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 template <typename F>
152 QAction *CREMainWindow::createAction(const QString &title, const QString &statusTip, F functor, bool waitMaps) {
153  auto action = createAction(title, statusTip);
154  if (waitMaps) {
155  connect(action, &QAction::triggered, [this, functor] {
156  if (!myMapManager->browseFinished()) {
157  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
158  QProgressDialog prog(this);
159  prog.setLabelText(tr("Waiting for maps browing to finish..."));
160  prog.setWindowModality(Qt::ApplicationModal);
161  prog.setRange(0, 0);
162  prog.setVisible(true);
163  prog.setValue(0);
164  while (!myMapManager->browseFinished())
165  {
166  if (prog.wasCanceled()) {
167  QApplication::restoreOverrideCursor();
168  return;
169  }
170  QApplication::processEvents();
171  QThread::msleep(1);
172  }
173  QApplication::restoreOverrideCursor();
174  }
175  functor();
176  });
177  } else {
178  connect(action, &QAction::triggered, functor);
179  }
180  return action;
181 }
182 
183 QAction *CREMainWindow::createAction(const QString &title, const QString &statusTip) {
184  auto action = new QAction(title, this);
185  action->setStatusTip(statusTip);
186  return action;
187 }
188 
190 {
191  mySaveFormulae = new QAction(tr("Formulae"), this);
192  mySaveFormulae->setEnabled(false);
193  connect(mySaveFormulae, SIGNAL(triggered()), this, SLOT(onSaveFormulae()));
194 
195  myClearMapCache = new QAction(tr("Clear map cache"), this);
196  myClearMapCache->setStatusTip(tr("Force a refresh of all map information at next start."));
197  connect(myClearMapCache, SIGNAL(triggered()), this, SLOT(onClearCache()));
198  /* can't clear map cache while collecting information */
199  myClearMapCache->setEnabled(false);
200 
201  myToolFacesetUseFallback = new QAction(tr("Use set fallback for missing faces"), this);
202  connect(myToolFacesetUseFallback, SIGNAL(triggered()), this, SLOT(onToolFacesetUseFallback()));
203  myToolFacesetUseFallback->setCheckable(true);
204  myToolFacesetUseFallback->setChecked(true);
205 }
206 
208 {
209  myOpenMenu = menuBar()->addMenu(tr("&Open"));
210 
211  auto add = [this] (int index, const QString &name, const QString &tip) {
212  QAction* action = new QAction(name, this);
213  action->setStatusTip(tip);
214  action->setData(static_cast<int>(index));
215  connect(action, &QAction::triggered, [this, index] () { doResourceWindow(index); });
216  myOpenMenu->addAction(action);
217  };
218  add(-1, tr("Assets"), tr("Display all defined assets, except the experience table."));
219  for (int asset = 0; asset < myAssets->childrenCount(); asset++) {
220  add(asset, myAssets->child(asset)->displayName(), myAssets->child(asset)->property(AssetWrapper::tipProperty).toString());
221  }
222 
223  myOpenMenu->addAction(createAction(tr("Experience"), tr("Display the experience table."), [this] { onOpenExperience(); }));
224 
225  myOpenMenu->addSeparator();
226  QAction* exit = myOpenMenu->addAction(tr("&Exit"));
227  exit->setStatusTip(tr("Close the application."));
228  connect(exit, SIGNAL(triggered()), this, SLOT(close()));
229 
230  mySaveMenu = menuBar()->addMenu(tr("&Save"));
231  mySaveMenu->addAction(mySaveFormulae);
232  mySaveMenu->addAction(createAction(tr("Quests"), tr("Save all modified quests to disk."), [this] { onSaveQuests(); }));
233  mySaveMenu->addAction(createAction(tr("Dialogs"), tr("Save all modified NPC dialogs."), [this] { onSaveMessages(); }));
234  mySaveMenu->addAction(createAction(tr("Archetypes"), tr("Save all modified archetypes."), [this] { myResourcesManager->saveArchetypes(); }));
235  mySaveMenu->addAction(createAction(tr("Treasures"), tr("Save all modified treasures."), [this] { myResourcesManager->saveTreasures(); }));
236  mySaveMenu->addAction(createAction(tr("General messages"), tr("Save all modified general messages."), [this] { myResourcesManager->saveGeneralMessages(); }));
237  mySaveMenu->addAction(createAction(tr("Artifacts"), tr("Save all modified artifacts."), [this] { myResourcesManager->saveArtifacts(); }));
238 
239  QMenu* reportMenu = menuBar()->addMenu(tr("&Reports"));
240  reportMenu->addAction(createAction(tr("Faces and animations report"), tr("Show faces and animations which are used by multiple archetypes, or not used."), [this] { onReportDuplicate(); }));
241  reportMenu->addAction(createAction(tr("Spell damage"), tr("Display damage by level for some spells."), [this] () { onReportSpellDamage(); }, true));
242  reportMenu->addAction(createAction(tr("Alchemy"), tr("Display alchemy formulae, in a table."), [this] { onReportAlchemy(); }));
243  reportMenu->addAction(createAction(tr("Alchemy graph"), tr("Export alchemy relationship as a DOT file."), [this] { onReportAlchemyGraph(); }));
244  reportMenu->addAction(createAction(tr("Spells"), tr("Display all spells, in a table."), [this] { onReportSpells(); }));
245  reportMenu->addAction(createAction(tr("Player vs monsters"), tr("Compute statistics related to player vs monster combat."), [=] { onReportPlayer(); }, true));
246  reportMenu->addAction(createAction(tr("Summoned pets statistics"), tr("Display wc, hp, speed and other statistics for summoned pets."), [=] { onReportSummon(); }));
247  reportMenu->addAction(createAction(tr("Shop specialization"), tr("Display the list of shops and their specialization for items."), [=] { onReportShops(); }, true));
248  reportMenu->addAction(createAction(tr("Quest solved by players"), tr("Display quests the players have solved."), [=] { onReportQuests(); }, true));
249  reportMenu->addAction(createAction(tr("Materials"), tr("Display all materials with their properties."), [this] { onReportMaterials(); }));
250  reportMenu->addAction(createAction(tr("Unused archetypes"), tr("Display all archetypes which seem unused."), [=] { onReportArchetypes(); }, true));
251  reportMenu->addAction(createAction(tr("Licenses checks"), tr("Check for licenses inconsistencies."), [this] { onReportLicenses(); }));
252  reportMenu->addAction(createAction(tr("Map reset groups"), tr("List map reset groups."), [this] { onReportResetGroups(); }, true));
253 
254  myToolsMenu = menuBar()->addMenu(tr("&Tools"));
255  myToolsMenu->addAction(createAction(tr("Edit monsters"), tr("Edit monsters in a table."), [this] { onToolEditMonsters(); }));
256  auto resist = createAction(tr("Monster resistances overview"), tr("Display an overview of resistances of monsters"));
257  connect(resist, &QAction::triggered, [&] {
258  MonsterResistances dlg(this);
259  dlg.exec();
260  });
261  myToolsMenu->addAction(resist);
262  myToolsMenu->addAction(createAction(tr("Generate smooth face base"), tr("Generate the basic smoothed picture for a face."), [this] { onToolSmooth(); }));
263  myToolsMenu->addAction(createAction(tr("Generate HP bar"), tr("Generate faces for a HP bar."), [this] { onToolBarMaker(); }));
264  myToolsMenu->addAction(createAction(tr("Combat simulator"), tr("Simulate fighting between two objects."), [this] { onToolCombatSimulator(); }));
265  myToolsMenu->addAction(createAction(tr("Generate face variants"), tr("Generate faces by changing colors of existing faces."), [this] { onToolFaceMaker(); }));
266  myToolsMenu->addAction(myClearMapCache);
267  myToolsMenu->addAction(createAction(tr("Reload assets"), tr("Reload all assets from the data directory."), [this] { onToolReloadAssets(); }));
268  myToolsMenu->addAction(createAction(tr("Sounds"), tr("Display defined sounds and associated files."), [this] { onToolSounds(); }));
269 
270  CRESettings set;
271 
272  myWindows = menuBar()->addMenu(tr("&Windows"));
273  connect(myWindows, SIGNAL(aboutToShow()), this, SLOT(onWindowsShowing()));
274  auto store = createAction(tr("Restore windows positions at launch"), tr("If enabled then opened windows are automatically opened again when the application starts"));
275  store->setCheckable(true);
276  store->setChecked(set.storeWindowsState());
277  myWindows->addAction(store);
278  connect(store, &QAction::triggered, [store] {
279  CRESettings set;
280  set.setStoreWindowState(store->isChecked());
281  } );
282 
283  myWindows->addAction(createAction(tr("Close current window"), tr("Close the currently focused window"), [this] { myArea->closeActiveSubWindow(); }));
284  myWindows->addAction(createAction(tr("Close all windows"), tr("Close all opened windows"), [=] { myArea->closeAllSubWindows(); }));
285  myWindows->addAction(createAction(tr("Tile windows"), tr("Tile all windows"), [=] { myArea->tileSubWindows(); }));
286  myWindows->addAction(createAction(tr("Cascade windows"), tr("Cascade all windows"), [=] { myArea->cascadeSubWindows(); }));
287 
288  auto sep = new QAction(this);
289  sep->setSeparator(true);
290  myWindows->addAction(sep);
291 
292  auto helpMenu = menuBar()->addMenu(tr("&Help"));
293  auto help = createAction(tr("Help"), tr("CRE Help"), [=] { myHelpManager->displayHelp(); });
294  help->setShortcut(Qt::Key_F1);
295  helpMenu->addAction(help);
296 
297  helpMenu->addAction(createAction(tr("About"), tr("About CRE"), [=] () { QMessageBox::about(this, tr("About CRE"), tr("Crossfire Resource Editor")); }));
298 
300  auto show = createAction(tr("Show changes after updating"), tr("If checked, then show latest changes at first startup after an update"));
301  show->setCheckable(true);
302  show->setChecked(settings.showChanges());
303  helpMenu->addAction(show);
304  connect(show, &QAction::triggered, [&] (bool checked) {
306  settings.setShowChanges(checked);
307  });
308 
309  helpMenu->addAction(createAction(tr("Changes"), tr("Display CRE changes"), [=] () { myChanges->setVisible(true); }));
310 }
311 
312 void CREMainWindow::doResourceWindow(int assets, const QByteArray& position)
313 {
314  QModelIndex root;
315  if (assets != -1) {
316  root = myModel->index(assets, 0, QModelIndex());
317  }
318 
320  resources->setAttribute(Qt::WA_DeleteOnClose);
321  connect(this, SIGNAL(updateFilters()), resources, SLOT(updateFilters()));
322  connect(resources, SIGNAL(filtersModified()), this, SLOT(onFiltersModified()));
323  connect(this, SIGNAL(updateReports()), resources, SLOT(updateReports()));
324  connect(resources, SIGNAL(reportsModified()), this, SLOT(onReportsModified()));
325  auto widget = myArea->addSubWindow(resources);
326  widget->setAttribute(Qt::WA_DeleteOnClose);
327  if (position.isEmpty()) {
328  if (myArea->subWindowList().size() == 1) {
329  widget->setWindowState(Qt::WindowMaximized);
330  }
331  } else {
332  widget->restoreGeometry(position);
333  }
334  resources->show();
335 }
336 
337 void CREMainWindow::onOpenExperience(const QByteArray& position)
338 {
339  QWidget* experience = new CREExperienceWindow();
340  auto widget = myArea->addSubWindow(experience);
341  if (!position.isEmpty()) {
342  widget->restoreGeometry(position);
343  }
344  experience->show();
345 }
346 
348 {
350  const QString select = settings.facesetToDisplay();
351  const bool use = settings.facesetUseFallback();
352 
353  QMenu *fs = myToolsMenu->addMenu(tr("Facesets"));
354  myFacesetsGroup = new QActionGroup(this);
355  connect(myFacesetsGroup, SIGNAL(triggered(QAction*)), this, SLOT(onToolFaceset(QAction*)));
356  getManager()->facesets()->each([&fs, &select, this] (face_sets *f)
357  {
358  QAction *a = new QAction(f->fullname, fs);
359  a->setCheckable(true);
360  a->setData(f->prefix);
361  fs->addAction(a);
362  myFacesetsGroup->addAction(a);
363  if (select == f->prefix)
364  a->setChecked(true);
365  });
366  fs->addSeparator();
367  fs->addAction(myToolFacesetUseFallback);
368  myToolFacesetUseFallback->setChecked(use);
369 }
370 
372 {
373 }
374 
376 {
378 }
379 
381 {
383 }
384 
385 void CREMainWindow::browsingMap(const QString& path)
386 {
387  myMapBrowseStatus->setText(tr("Browsing map %1").arg(path));
388 }
389 
391 {
392  statusBar()->showMessage(tr("Finished browsing maps."), 5000);
393  myMapBrowseStatus->setVisible(false);
394  myClearMapCache->setEnabled(true);
395 }
396 
398 {
399  emit updateFilters();
400 }
401 
403 {
404  emit updateReports();
405 }
406 
414 {
415  QHash<QString, QStringList> faces, anims;
416 
417  // browse all archetypes
418  getManager()->archetypes()->each([&faces, &anims] (const auto arch)
419  {
420  if (arch->head)
421  {
422  return;
423  }
424  // 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)
425  if (arch->clone.animation == NULL)
426  {
427  if (arch->clone.face) {
428  faces[QString::fromLatin1(arch->clone.face->name)].append(QString(arch->name) + " (arch)");
429  sstring key = object_get_value(&arch->clone, "identified_face");
430  if (key)
431  {
432  faces[QString(key)].append(QString(arch->name) + " (arch)");
433  }
434  }
435  }
436  else
437  {
438  anims[arch->clone.animation->name].append(QString(arch->name) + " (arch)");
439  sstring key = object_get_value(&arch->clone, "identified_animation");
440  if (key)
441  {
442  anims[QString(key)].append(QString(arch->name) + " (arch)");
443  }
444  }
445  });
446 
447  // list faces in animations
448  getManager()->animations()->each([&faces] (const auto anim)
449  {
450  QStringList done;
451  for (int i = 0; i < anim->num_animations; i++)
452  {
453  // don't list animation twice if they use the same face
454  if (!done.contains(QString::fromLatin1(anim->faces[i]->name)))
455  {
456  faces[QString::fromLatin1(anim->faces[i]->name)].append(QString(anim->name) + " (animation)");
457  done.append(QString::fromLatin1(anim->faces[i]->name));
458  }
459  }
460  });
461 
462  // list faces and animations for artifacts
464  for (list = first_artifactlist; list != NULL; list = list->next)
465  {
466  for (auto art : list->items)
467  {
468  if (art->item->animation == 0)
469  {
470  if (art->item->face) {
471  faces[QString::fromLatin1(art->item->face->name)].append(QString(art->item->name) + " (art)");
472  sstring key = object_get_value(art->item, "identified_face");
473  if (key)
474  {
475  faces[QString(key)].append(QString(art->item->name) + " (art)");
476  }
477  }
478  }
479  else
480  {
481  anims[art->item->animation->name].append(QString(art->item->name) + " (art)");
482  sstring key = object_get_value(art->item, "identified_animation");
483  if (key)
484  {
485  anims[QString(key)].append(QString(art->item->name) + " (arch)");
486  }
487  }
488  }
489  }
490 
491  getManager()->quests()->each([&] (auto quest) {
492  if (quest->face != nullptr)
493  {
494  faces[quest->face->name].append(QString(quest->quest_code) + " (quest)");
495  }
496  });
497 
499  {
500  if (message->face != nullptr)
501  {
502  faces[message->face->name].append(QString(message->identifier) + " (message)");
503  }
504  });
505 
506  for (const auto map : myMapManager->allMaps())
507  {
508  for (const auto face : map->faces())
509  {
510  faces[face].append(QString(map->path()) + " (map)");
511  }
512  for (const auto animation : map->animations())
513  {
514  anims[animation].append(map->path() + " (map)");
515  }
516  }
517 
518  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>");
519 
520  QStringList keys = faces.keys();
521  keys.sort();
522  foreach(QString name, keys)
523  {
524  if (faces[name].size() <= 1 || name.compare("blank.111") == 0)
525  continue;
526 
527  faces[name].sort();
528  report += "<li>" + name + ": ";
529  report += faces[name].join(", ");
530  report += "</li>";
531  }
532 
533  report += "</ul>";
534 
535  report += "<h1>Unused faces:</h1><ul>";
536  getManager()->faces()->each([&faces, &report] (const auto face)
537  {
538  if (faces[face->name].size() > 0)
539  return;
540  report += QString("<li>") + face->name + "</li>";
541  });
542  report += "</ul>";
543 
544  report += "<h1>Animations used multiple times:</h1><ul>";
545  keys = anims.keys();
546  keys.sort();
547  foreach(QString name, keys)
548  {
549  if (anims[name].size() <= 1)
550  continue;
551 
552  anims[name].sort();
553  report += "<li>" + name + ": ";
554  report += anims[name].join(", ");
555  report += "</li>";
556  }
557  report += "</ul>";
558 
559  report += "<h1>Unused animations:</h1><ul>";
560  getManager()->animations()->each([&anims, &report] (const auto anim)
561  {
562  if (anims[anim->name].size() > 0 || !strcmp(anim->name, "###none"))
563  return;
564  report += QString("<li>") + anim->name + "</li>";
565  });
566  report += "</ul>";
567 
568  // Find faces used for an object having an animation not including this face
569  report += "<h1>Objects having a face not part of their animation:</h1><ul>";
570 
572  // if there is an animation, don't consider the face, since it's part of the animation anyway (hopefully)
573  if (arch->clone.animation == NULL || arch->clone.face == NULL) {
574  return;
575  }
576  bool included = false;
577  for (int f = 0; f < arch->clone.animation->num_animations && !included; f++) {
578  if (arch->clone.animation->faces[f] == arch->clone.face) {
579  included = true;
580  }
581  }
582  if (!included) {
583  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);
584  }
585  });
586 
587  CREReportDisplay show(report, "Faces and animations report");
588  show.exec();
589 }
590 
592 {
593  QStringList spell;
594  QList<QStringList> damage;
595 
596  object* caster = create_archetype("orc");
597 
598  getManager()->archetypes()->each([&caster, &spell, &damage] (archetype *arch)
599  {
600  if (arch->clone.type == SPELL && arch->clone.subtype == SP_BULLET && arch->clone.skill && strcmp(arch->clone.skill, "praying") == 0)
601  {
602  spell.append(arch->clone.name);
603  QStringList dam;
604  for (int l = 0; l < settings.max_level; l++)
605  {
606  caster->level = l;
607  int dm = arch->clone.stats.dam + SP_level_dam_adjust(caster, &arch->clone);
608  int cost = SP_level_spellpoint_cost(caster, &arch->clone, SPELL_GRACE);
609  dam.append(tr("%1 [%2]").arg(dm).arg(cost));
610  }
611  damage.append(dam);
612  }
613  });
614 
616 
617  QString report("<table><thead><tr><th>level</th>");
618 
619  for (int i = 0; i < spell.size(); i++)
620  {
621  report += "<th>" + spell[i] + "</th>";
622  }
623 
624  report += "</tr></thead><tbody>";
625 
626  for (int l = 0; l < settings.max_level; l++)
627  {
628  report += "<tr><td>" + QString::number(l) + "</td>";
629  for (int s = 0; s < spell.size(); s++)
630  report += "<td>" + damage[s][l] + "</td>";
631  report += "</tr>";
632  }
633 
634  report += "</tbody></table>";
635 
636  CREReportDisplay show(report, "Spell damage");
637  show.exec();
638 }
639 
640 static QString alchemyTable(const QString& skill, QStringList& noChance, std::vector<std::pair<QString, int>> &allIngredients)
641 {
642  int count = 0;
643 
644  QHash<int, QStringList> recipes;
645 
646  const recipelist* list;
647  const recipe* recipe;
648 
649  for (int ing = 1; ; ing++)
650  {
651  list = get_formulalist(ing);
652  if (!list)
653  break;
654 
655  for (recipe = list->items; recipe; recipe = recipe->next)
656  {
657  if (skill == recipe->skill)
658  {
659  if (recipe->arch_names == 0)
660  // hu?
661  continue;
662 
664  if (arch == NULL) {
665  continue;
666  }
667 
668  QString name;
669  if (strcmp(recipe->title, "NONE") == 0)
670  {
671  if (arch->clone.title == NULL)
672  name = arch->clone.name;
673  else
674  name = QString("%1 %2").arg(arch->clone.name, arch->clone.title);
675  }
676  else
677  {
678  name = QString("%1 of %2").arg(arch->clone.name, recipe->title);
679  }
680 
681  QStringList ingredients;
682  for (const linked_char* ingred = recipe->ingred; ingred != NULL; ingred = ingred->next)
683  {
684  ingredients.append(ingred->name);
685  const char* name = ingred->name;
686  if (isdigit(ingred->name[0])) {
687  name = strchr(ingred->name, ' ') + 1;
688  }
689  auto ing = std::find_if(allIngredients.begin(), allIngredients.end(), [&] (auto i) { return i.first == name; } );
690  if (ing != allIngredients.end()) {
691  (*ing).second++;
692  } else {
693  allIngredients.push_back(std::make_pair(name, 1));;
694  }
695  }
696 
697  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(", ")));
698  count++;
699 
700  if (recipe->chance == 0) {
701  noChance.append(name);
702  }
703  }
704  }
705  }
706 
707  if (count == 0)
708  return QString();
709 
710  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);
711  report += "</tr></thead><tbody>";
712 
713  QList<int> difficulties = recipes.keys();
714  qSort(difficulties);
715  foreach(int difficulty, difficulties)
716  {
717  QStringList line = recipes[difficulty];
718  qSort(line);
719  report += line.join("\n");
720  }
721 
722  report += "</tbody></table>";
723 
724  return report;
725 }
726 
727 static void doIngredients(const std::vector<std::pair<QString, int>> &allIngredients, const QString &criteria, QString &report) {
728  report += QString("<h1>All items used as ingredients (%1)</h1>").arg(criteria);
729  report += "<ul>";
730  for (auto ing : allIngredients) {
731  report += QString("<li>%1 (%2 recipes)</li>").arg(ing.first).arg(ing.second);
732  }
733  report += "</ul>";
734 }
735 
737 {
738  QStringList skills;
739 
740  getManager()->archetypes()->each([&skills] (const auto arch)
741  {
742  if (arch->clone.type == SKILL)
743  skills.append(arch->clone.name);
744  });
745  skills.sort();
746 
747  QString report("<h1>Alchemy formulae</h1>");
748  QStringList noChance;
749  std::vector<std::pair<QString, int>> allIngredients;
750 
751  foreach(const QString skill, skills)
752  {
753  report += alchemyTable(skill, noChance, allIngredients);
754  }
755 
756  qSort(noChance);
757  report += tr("<h1>Formulae with chance of 0</h1>");
758  report += "<table><th>";
759  foreach(const QString& name, noChance) {
760  report += "<tr><td>" + name + "</td></tr>";
761  }
762  report += "</th></table>";
763 
764  std::sort(allIngredients.begin(), allIngredients.end(), [] (auto i1, auto i2) {
765  return i1.first.toLower() < i2.first.toLower();
766  });
767  doIngredients(allIngredients, "alphabetical order", report);
768 
769  std::sort(allIngredients.begin(), allIngredients.end(), [] (auto i1, auto i2) {
770  if (i1.second == i2.second) {
771  return i1.first.toLower() < i2.first.toLower();
772  }
773  return i1.second > i2.second;
774  });
775  doIngredients(allIngredients, "count of uses", report);
776 
777  CREReportDisplay show(report, "Alchemy formulae");
778  show.exec();
779 }
780 
782 {
783  QString output = QFileDialog::getSaveFileName(this, tr("Destination file"), "", tr("Dot files (*.dot);;All files (*.*)"));
784  if (output.isEmpty()) {
785  return;
786  }
787 
788  QFile file(output);
789  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
790  QMessageBox::critical(this, "Write error", tr("Unable to write to %1").arg(output));
791  return;
792  }
793  QTextStream out(&file);
794 
795  out << "digraph alchemy {\n";
796 
797  QVector<const recipe*> recipes;
798  QHash<const recipe*, QString> names;
799  QHash<QString, QVector<const recipe*> > products;
800 
801  for (int ing = 1; ; ing++)
802  {
803  const recipelist* list = get_formulalist(ing);
804  if (!list)
805  break;
806 
807  for (const recipe* recipe = list->items; recipe; recipe = recipe->next)
808  {
809  QString product("???");
810  for (size_t idx = 0; idx < recipe->arch_names; idx++) {
811  auto arch = getManager()->archetypes()->find(recipe->arch_name[idx]);
812  if (!arch) {
813  continue;
814  }
815  if (recipe->title && strcmp(recipe->title, "NONE")) {
816  product = tr("%1 of %2").arg(arch->clone.name, recipe->title);
817  } else {
818  product = arch->clone.name;
819  }
820  products[product].append(recipe);
821  }
822  names[recipe] = product;
823  recipes.append(recipe);
824  }
825  }
826 
827  QHash<const recipe*, bool> added;
828 
829  foreach (const recipe* rec, recipes) {
830  for (linked_char* ing = rec->ingred; ing; ing = ing->next) {
831  const char* name = ing->name;
832  if (isdigit(name[0]) && strchr(name, ' ')) {
833  name = strchr(name, ' ') + 1;
834  }
835  QHash<QString, QVector<const recipe*> >::iterator item = products.find(name);
836  if (item != products.end()) {
837  if (!added[rec]) {
838  out << tr("alchemy_%1 [label=\"%2\"]\n").arg(recipes.indexOf(rec)).arg(names[rec]);
839  added[rec] = true;
840  }
841  for (auto r = item->begin(); r != item->end(); r++) {
842  if (!added[*r]) {
843  out << tr("alchemy_%1 [label=\"%2\"]\n").arg(recipes.indexOf(*r)).arg(names[*r]);
844  added[*r] = true;
845  }
846  out << tr("alchemy_%1 -> alchemy_%2\n").arg(recipes.indexOf(*r)).arg(recipes.indexOf(rec));
847  }
848  }
849  }
850  }
851 
852  int ignored = 0;
853  foreach (const recipe* rec, recipes) {
854  if (!added[rec]) {
855  ignored++;
856  }
857  }
858  out << "graph [labelloc=\"b\" labeljust=\"c\" label=\"Alchemy graph, formulae producing ingredients of other formulae";
859  if (ignored) {
860  out << tr(" (%1 formulae not displayed)").arg(ignored);
861  }
862  out << "\"]\n";
863 
864  out << "}\n";
865 }
866 
867 static QString spellsTable(const QString& skill)
868 {
869  bool one = false;
870 
871  QString report = QString("<h2>%1</h2><table><thead><tr><th>Spell</th><th>Level</th>").arg(skill);
872  report += "</tr></thead><tbody>";
873 
874  QHash<int, QStringList> spells;
875 
876  getManager()->archetypes()->each([&skill, &spells, &one] (const archetype *spell) {
877  if (spell->clone.type == SPELL && spell->clone.skill == skill)
878  {
879  spells[spell->clone.level].append(QString("<tr><td>%1</td><td>%2</td></tr>").arg(spell->clone.name).arg(spell->clone.level));
880  one = true;
881  }
882  });
883 
884  if (!one)
885  return QString();
886 
887  QList<int> levels = spells.keys();
888  qSort(levels);
889  foreach(int level, levels)
890  {
891  spells[level].sort();
892  report += spells[level].join("\n");
893  }
894 
895  report += "</tbody></table>";
896 
897  return report;
898 }
899 
901 {
902  QStringList skills;
903 
904  getManager()->archetypes()->each([&skills] (const archetype *arch)
905  {
906  if (arch->clone.type == SKILL)
907  skills.append(arch->clone.name);
908  });
909 
910  skills.sort();
911 
912  QString report("<h1>Spell list</h1>");
913 
914  foreach(const QString skill, skills)
915  {
917  }
918 
919  CREReportDisplay show(report, "Spell list");
920  show.exec();
921 }
922 
933 {
934  int limit = 50, result = 1;
935  player pl;
936  socket_struct sock;
937  memset(&pl, 0, sizeof(player));
938  memset(&sock, 0, sizeof(sock));
939  strncpy(pl.savebed_map, "/HallOfSelection", MAX_BUF);
940  pl.bed_x = 5;
941  pl.bed_y = 5;
942  pl.socket = &sock;
943  std::unique_ptr<uint8_t[]> faces(new uint8_t[get_faces_count()]);
944  sock.faces_sent = faces.get();
945 
946  archetype *dwarf_player_arch = find_archetype("dwarf_player");
947  if (dwarf_player_arch == NULL) {
948  return 0;
949  }
950  object* obfirst = object_create_arch(dwarf_player_arch);
951  obfirst->level = level;
952  obfirst->contr = &pl;
953  pl.ob = obfirst;
954  object* obskill = object_create_arch(skill);
955  obskill->level = level;
956  SET_FLAG(obskill, FLAG_APPLIED);
957  object_insert_in_ob(obskill, obfirst);
958  archetype *skill_arch = find_archetype((skill->clone.subtype == SK_TWO_HANDED_WEAPON) ? "sword_3" : "sword");
959  if (skill_arch == NULL) {
960  return 0;
961  }
962  object* sword = object_create_arch(skill_arch);
963  SET_FLAG(sword, FLAG_APPLIED);
964  object_insert_in_ob(sword, obfirst);
965  fix_object(obfirst);
966  obfirst->stats.hp = obfirst->stats.maxhp;
967 
968  object* obsecond = object_create_arch(monster);
969  tag_t tagfirst = obfirst->count;
970  tag_t tagsecond = obsecond->count;
971 
972  // make a big map so large monsters are ok in map
973  mapstruct* test_map = get_empty_map(50, 50);
974 
975  obfirst = object_insert_in_map_at(obfirst, test_map, NULL, 0, 0, 0);
976  obsecond = object_insert_in_map_at(obsecond, test_map, NULL, 0, 1 + monster->tail_x, monster->tail_y);
977 
978  if (!obsecond || object_was_destroyed(obsecond, tagsecond))
979  {
980  qDebug() << "second removed??";
981  }
982 
983  while (limit-- > 0 && obfirst->stats.hp >= 0 && obsecond->stats.hp >= 0)
984  {
985  if (obfirst->weapon_speed_left > 0) {
986  --obfirst->weapon_speed_left;
987  do_some_living(obfirst);
988 
989  move_player(obfirst, 3);
990  if (object_was_destroyed(obsecond, tagsecond))
991  break;
992 
993  /* the player may have been killed (acid for instance), so check here */
994  if (object_was_destroyed(obfirst, tagfirst) || (obfirst->map != test_map))
995  {
996  result = 0;
997  break;
998  }
999  }
1000 
1001  if (obsecond->speed_left > 0) {
1002  --obsecond->speed_left;
1003  monster_do_living(obsecond);
1004 
1005  attack_ob(obfirst, obsecond);
1006  /* when player is killed, she is teleported to bed of reality -> check map */
1007  if (object_was_destroyed(obfirst, tagfirst) || (obfirst->map != test_map))
1008  {
1009  result = 0;
1010  break;
1011  }
1012  }
1013 
1014  obfirst->weapon_speed_left += obfirst->weapon_speed;
1015  if (obfirst->weapon_speed_left > 1.0)
1016  obfirst->weapon_speed_left = 1.0;
1017  if (obsecond->speed_left <= 0)
1018  obsecond->speed_left += FABS(obsecond->speed);
1019  }
1020 
1021  if (!object_was_destroyed(obfirst, tagfirst))
1022  {
1023  object_remove(obfirst);
1025  }
1026  if (!object_was_destroyed(obsecond, tagsecond))
1027  {
1028  object_remove(obsecond);
1030  }
1032 
1033  return result;
1034 }
1035 
1047 {
1048  int victory = 0;
1049  while (count-- > 0)
1050  victory += monsterFight(monster, skill, level);
1051 
1052  return victory;
1053 }
1054 
1065 {
1066  qDebug() << "monsterFight:" << monster->clone.name << skill->clone.name;
1067  int ret, min = settings.max_level + 1, half = settings.max_level + 1, count = 5, level;
1068  int first = 1, max = settings.max_level;
1069 
1070  while (first != max)
1071  {
1072  level = (max + first) / 2;
1073  if (level < first)
1074  level = first;
1075  if (first > max)
1076  first = max;
1077 
1078  ret = monsterFight(monster, skill, level, count);
1079  if (ret > 0)
1080  {
1081  if (level < min)
1082  min = level;
1083  if (ret > (count / 2) && (level < half))
1084  half = level;
1085 
1086  max = level;
1087  }
1088  else
1089  {
1090  if (first == level)
1091  break;
1092  first = level;
1093  }
1094  }
1095 
1096  //qDebug() << " result:" << min << half;
1097 
1098  // if player was killed, then HallOfSelection was loaded, so clean it now.
1099  // This speeds up various checks, like in free_all_objects().
1100  mapstruct* hos = has_been_loaded("/HallOfSelection");
1101  if (hos)
1102  {
1103  hos->reset_time = 1;
1104  hos->in_memory = MAP_IN_MEMORY;
1105  delete_map(hos);
1106  }
1107  /*
1108  extern int nroffreeobjects;
1109  extern int nrofallocobjects;
1110  qDebug() << "free: " << nroffreeobjects << ", all: " << nrofallocobjects;
1111  */
1112 
1113  if (min == settings.max_level + 1)
1114  return "<td colspan=\"2\">-</td>";
1115  return "<td>" + QString::number(min) + "</td><td>" + ((half != 0) ? QString::number(half) : "") + "</td>";
1116 }
1117 
1124 static QString monsterTable(archetype* monster, QList<archetype*> skills)
1125 {
1126  QString line = "<tr>";
1127 
1128  line += "<td>" + QString(monster->clone.name) + "</td>";
1129  line += "<td>" + QString::number(monster->clone.level) + "</td>";
1130  line += "<td>" + QString::number(monster->clone.speed) + "</td>";
1131  line += "<td>" + QString::number(monster->clone.stats.wc) + "</td>";
1132  line += "<td>" + QString::number(monster->clone.stats.dam) + "</td>";
1133  line += "<td>" + QString::number(monster->clone.stats.ac) + "</td>";
1134  line += "<td>" + QString::number(monster->clone.stats.hp) + "</td>";
1135  line += "<td>" + QString::number(monster->clone.stats.Con) + "</td>";
1136 
1137  foreach(archetype* skill, skills)
1138  {
1140  }
1141  line += "</tr>\n";
1142 
1143  return line;
1144 }
1145 
1151 {
1152  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1153 
1154  QStringList names;
1155  QMap<QString, archetype*> monsters;
1156  QList<archetype*> skills;
1157 
1159  {
1160  if (QUERY_FLAG(&arch->clone, FLAG_MONSTER) && arch->clone.stats.hp > 0 && arch->head == NULL)
1161  {
1162  QString name(QString(arch->clone.name).toLower());
1163  if (monsters.contains(name))
1164  {
1165  int suffix = 1;
1166  do
1167  {
1168  name = QString(arch->clone.name).toLower() + "_" + QString::number(suffix);
1169  suffix++;
1170  } while (monsters.contains(name));
1171  }
1172 
1173  monsters[name] = arch;
1174  }
1175  if (arch->clone.type == SKILL && IS_COMBAT_SKILL(arch->clone.subtype))
1176  {
1177  if (strcmp(arch->name, "skill_missile_weapon") == 0 || strcmp(arch->name, "skill_throwing") == 0)
1178  return;
1179  skills.append(arch);
1180  }
1181  });
1182 
1183  names = monsters.keys();
1184  names.sort();
1185 
1186  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;
1187  report += "<table border=\"1\"><tbody>\n";
1188  report += "<tr>";
1189  report += "<th rowspan=\"2\">Monster</th>";
1190  report += "<th rowspan=\"2\">level</th>";
1191  report += "<th rowspan=\"2\">speed</th>";
1192  report += "<th rowspan=\"2\">wc</th>";
1193  report += "<th rowspan=\"2\">dam</th>";
1194  report += "<th rowspan=\"2\">ac</th>";
1195  report += "<th rowspan=\"2\">hp</th>";
1196  report += "<th rowspan=\"2\">regen</th>";
1197 
1198  line = "<tr>";
1199  foreach(archetype* skill, skills)
1200  {
1201  report += "<th colspan=\"2\">" + QString(skill->clone.name) + "</th>";
1202  line += "<th>fv</th><th>hv</th>";
1203  }
1204  report += "</tr>\n" + line + "</tr>\n";
1205 
1206  int limit = 500;
1207  foreach(const QString name, names)
1208  {
1210  if (limit-- <= 0)
1211  break;
1212  }
1213 
1214  report += "</tbody></table>\n";
1215 
1216  CREReportDisplay show(report, "Player vs monsters (hand to hand)");
1217  QApplication::restoreOverrideCursor();
1218  show.exec();
1219 }
1220 
1221 static QString reportSummon(const archetype* summon, const object* other, QString name)
1222 {
1223  QString report;
1224  int level, wc_adj = 0;
1225 
1226  const object* spell = &summon->clone;
1227  sstring rate = object_get_value(spell, "wc_increase_rate");
1228  if (rate != NULL) {
1229  wc_adj = atoi(rate);
1230  }
1231 
1232  // hp, dam, speed, wc
1233 
1234  QString ac("<tr><td>ac</td>");
1235  QString hp("<tr><td>hp</td>");
1236  QString dam("<tr><td>dam</td>");
1237  QString speed("<tr><td>speed</td>");
1238  QString wc("<tr><td>wc</td>");
1239  int ihp, idam, iwc, diff;
1240  float fspeed;
1241 
1242  for (level = 1; level < 120; level += 10)
1243  {
1244  if (level < spell->level)
1245  {
1246  ac += "<td></td>";
1247  hp += "<td></td>";
1248  dam += "<td></td>";
1249  speed += "<td></td>";
1250  wc += "<td></td>";
1251  continue;
1252  }
1253 
1254  diff = level - spell->level;
1255 
1256  ihp = other->stats.hp + spell->duration + (spell->duration_modifier != 0 ? (diff / spell->duration_modifier) : 0);
1257  idam = (spell->stats.dam ? spell->stats.dam : other->stats.dam) + (spell->dam_modifier != 0 ? (diff / spell->dam_modifier) : 0);
1258  fspeed = MIN(1.0, FABS(other->speed) + .02 * (spell->range_modifier != 0 ? (diff / spell->range_modifier) : 0));
1259  iwc = other->stats.wc;
1260  if (wc_adj > 0)
1261  iwc -= (diff / wc_adj);
1262 
1263  ac += "<td>" + QString::number(other->stats.ac) + "</td>";
1264  hp += "<td>" + QString::number(ihp) + "</td>";
1265  dam += "<td>" + QString::number(idam) + "</td>";
1266  speed += "<td>" + QString::number(fspeed) + "</td>";
1267  wc += "<td>" + QString::number(iwc) + "</td>";
1268  }
1269 
1270  report += "<tr><td colspan=\"13\"><strong>" + name + "</strong></td></tr>\n";
1271 
1272  report += ac + "</tr>\n" + hp + "</tr>\n" + dam + "</tr>\n" + speed + "</tr>\n" + wc + "</tr>\n\n";
1273 
1274  return report;
1275 }
1276 
1278 {
1279  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1280 
1281  int level;
1282 
1283  QString report(tr("<h1>Summoned pet statistics</h1>\n")), line;
1284  report += "<table border=\"1\">\n<thead>\n";
1285  report += "<tr>";
1286  report += "<th rowspan=\"2\">Spell</th>";
1287  report += "<th colspan=\"12\">Level</th>";
1288  report += "</tr>\n";
1289  report += "<tr>";
1290 
1291  for (level = 1; level < 120; level += 10)
1292  {
1293  report += "<th>" + QString::number(level) + "</th>";
1294  }
1295  report += "</tr>\n</thead>\n<tbody>\n";
1296 
1297  QMap<QString, QString> spells;
1298 
1299  getManager()->archetypes()->each([&spells] (archetype *summon)
1300  {
1301  if (summon->clone.type != SPELL || summon->clone.subtype != SP_SUMMON_GOLEM)
1302  return;
1303  if (summon->clone.other_arch != NULL)
1304  {
1305  spells[summon->clone.name] = reportSummon(summon, &summon->clone.other_arch->clone, QString(summon->clone.name));
1306  return;
1307  }
1308 
1309  // god-based summoning
1310  getManager()->archetypes()->each([&summon, &spells] (archetype *god)
1311  {
1312  if (god->clone.type != GOD)
1313  return;
1314 
1315  QString name(QString(summon->clone.name) + " (" + QString(god->name) + ")");
1316  archetype* holy = determine_holy_arch(&god->clone, summon->clone.race);
1317  if (holy == NULL)
1318  return;
1319 
1320  spells[name] = reportSummon(summon, &holy->clone, name);
1321  });
1322  });
1323 
1324  QStringList keys = spells.keys();
1325  keys.sort();
1326  foreach(QString key, keys)
1327  {
1328  report += spells[key];
1329  }
1330 
1331  report += "</tbody>\n</table>\n";
1332 
1333  CREReportDisplay show(report, "Summoned pet statistics");
1334  QApplication::restoreOverrideCursor();
1335  show.exec();
1336 }
1337 
1338 static QString buildShopReport(const QString& title, const QStringList& types, const QList<CREMapInformation*>& maps, QStringList& items)
1339 {
1340  QString report("<h2>" + title + "</h2>");
1341  report += "<table border=\"1\">\n<thead>\n";
1342  report += "<tr>";
1343  report += "<th>Shop</th>";
1344  report += "<th>Greed</th>";
1345  report += "<th>Race</th>";
1346  report += "<th>Min</th>";
1347  report += "<th>Max</th>";
1348  foreach (QString item, types)
1349  {
1350  report += "<th>" + item + "</th>";
1351  items.removeAll(item);
1352  }
1353  report += "</tr>\n</thead><tbody>";
1354 
1355  foreach(const CREMapInformation* map, maps)
1356  {
1357  QString line;
1358  bool keep = false;
1359 
1360  if (map->shopItems().size() == 0)
1361  continue;
1362 
1363  line += "<tr>";
1364 
1365  line += "<td>" + map->name() + " " + map->path() + "</td>";
1366  line += "<td>" + QString::number(map->shopGreed()) + "</td>";
1367  line += "<td>" + map->shopRace() + "</td>";
1368  line += "<td>" + (map->shopMin() != 0 ? QString::number(map->shopMin()) : "") + "</td>";
1369  line += "<td>" + (map->shopMax() != 0 ? QString::number(map->shopMax()) : "") + "</td>";
1370 
1371  foreach(const QString item, types)
1372  {
1373  if (map->shopItems()[item] == 0)
1374  {
1375  if (map->shopItems()["*"] == 0)
1376  line += "<td></td>";
1377  else
1378  line += "<td>" + QString::number(map->shopItems()["*"]) + "</td>";
1379  continue;
1380  }
1381  keep = true;
1382  line += "<td>" + QString::number(map->shopItems()[item]) + "</td>";
1383  }
1384 
1385  line += "</tr>";
1386  if (keep)
1387  report += line;
1388  }
1389 
1390  report += "</tbody></table>";
1391  return report;
1392 }
1393 
1395 {
1396  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1397 
1398  QString report(tr("<h1>Shop information</h1>\n"));
1399 
1400  QList<CREMapInformation*> maps = myMapManager->allMaps();
1401  QStringList items;
1402  foreach(const CREMapInformation* map, maps)
1403  {
1404  QStringList add = map->shopItems().keys();
1405  foreach(const QString item, add)
1406  {
1407  if (!items.contains(item))
1408  items.append(item);
1409  }
1410  }
1411  qSort(items);
1412 
1413  QStringList part;
1414 
1415  part << "weapon" << "weapon improver" << "bow" << "arrow";
1416  report += buildShopReport("Weapons", part, maps, items);
1417 
1418  part.clear();
1419  part << "armour" << "armour improver" << "boots" << "bracers" << "cloak" << "girdle" << "gloves" << "helmet" << "shield";
1420  report += buildShopReport("Armour", part, maps, items);
1421 
1422  part.clear();
1423  part << "amulet" << "potion" << "power_crystal" << "ring" << "rod" << "scroll" << "skillscroll" << "spellbook" << "wand";
1424  report += buildShopReport("Magical", part, maps, items);
1425 
1426  part.clear();
1427  part << "container" << "food" << "key" << "lamp" << "skill tool" << "special key";
1428  report += buildShopReport("Equipment", part, maps, items);
1429 
1430  if (!items.isEmpty())
1431  {
1432 
1433  part = items;
1434  report += buildShopReport("Others", part, maps, items);
1435  }
1436 
1437  CREReportDisplay show(report, "Shop information");
1438  QApplication::restoreOverrideCursor();
1439  show.exec();
1440 }
1441 
1442 void readDirectory(const QString& path, QHash<QString, QHash<QString, bool> >& states)
1443 {
1444  QDir dir(path);
1445  QStringList subdirs = dir.entryList(QStringList("*"), QDir::Dirs | QDir::NoDotAndDotDot);
1446  foreach(QString subdir, subdirs)
1447  {
1448  readDirectory(path + QDir::separator() + subdir, states);
1449  }
1450 
1451  QStringList quests = dir.entryList(QStringList("*.quest"), QDir::Files);
1452  foreach(QString file, quests)
1453  {
1454  qDebug() << "read quest:" << path << file;
1455  QString name = file.left(file.length() - 6);
1456  QFile read(path + QDir::separator() + file);
1457  read.open(QFile::ReadOnly);
1458  QTextStream stream(&read);
1459  QString line, code;
1460  bool completed;
1461  while (!(line = stream.readLine(0)).isNull())
1462  {
1463  if (line.startsWith("quest "))
1464  {
1465  code = line.mid(6);
1466  completed = false;
1467  continue;
1468  }
1469  if (code.isEmpty())
1470  continue;
1471  if (line == "end_quest")
1472  {
1473  states[code][name] = completed;
1474  code.clear();
1475  continue;
1476  }
1477  if (line.startsWith("state "))
1478  continue;
1479  if (line == "completed 1")
1480  completed = true;
1481  }
1482  }
1483 }
1484 
1486 {
1487  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1488 
1489  QHash<QString, QHash<QString, bool> > states;
1490  QString directory(settings.localdir);
1491  directory += QDir::separator();
1492  directory += settings.playerdir;
1493  readDirectory(directory, states);
1494 
1495  QStringList codes;
1496  getManager()->quests()->each([&] (const auto quest) {
1497  codes.append(quest->quest_code);
1498  });
1499 
1500  QString report("<html><body>\n<h1>Quests</h1>\n");
1501 
1502  QStringList keys = states.keys();
1503  keys.sort();
1504 
1505  foreach(QString key, keys)
1506  {
1507  codes.removeAll(key);
1508  const auto quest = getManager()->quests()->get(key.toStdString());
1509  report += "<h2>Quest: " + (quest != NULL ? quest->quest_title : (key + " ???")) + "</h2>\n";
1510  report += "<p>";
1511  QHash<QString, bool> done = states[key];
1512  QStringList players = done.keys();
1513  players.sort();
1514  int completed = 0;
1515  QString sep;
1516  foreach(QString player, players)
1517  {
1518  report += sep;
1519  sep = ", ";
1520  if (done[player])
1521  {
1522  completed++;
1523  report += "<strong>" + player + "</strong>";
1524  }
1525  else
1526  {
1527  report += player;
1528  }
1529  }
1530  report += "</p>\n";
1531  report += "<p>" + tr("%1 completed out of %2 (%3%)").arg(completed).arg(players.size()).arg(completed * 100 / players.size()) + "</p>\n";
1532  }
1533 
1534  if (codes.length() > 0)
1535  {
1536  codes.sort();
1537  QString sep;
1538  report += "<h2>Quests never done</h2>\n<p>\n";
1539  foreach(QString code, codes)
1540  {
1541  report += sep;
1542  sep = ", ";
1543  const auto quest = getManager()->quests()->find(code.toStdString());
1544  report += (quest != NULL ? quest->quest_title : (code + " ???"));
1545  }
1546  report += "</p>\n";
1547  }
1548 
1549  report += "</body>\n</html>\n";
1550 
1551  CREReportDisplay show(report, "Quests report");
1552  QApplication::restoreOverrideCursor();
1553  show.exec();
1554 }
1555 
1557 {
1558  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1559 
1560  QString report;
1561  report += "<html>";
1562 
1563  report += "<h1>Materials</h1>";
1564  report += "<table><tr><th>Name</th><th>Description</th></tr>";
1565  for (const auto &mat : materials) {
1566  report += tr("<tr><td>%1</td><td>%2</td></tr>").arg(mat->name, mat->description);
1567  }
1568  report += "</table>";
1569 
1570  for (int s = 0; s < 2; s++) {
1571  QString name(s == 0 ? "Saves" : "Resistances");
1572  report += tr("<h1>%1</h1>").arg(name);
1573  report += tr("<tr><th rowspan='2'>Name</th><th colspan='%1'>%2</th></tr>").arg(NROFATTACKS).arg(name);
1574  report += "<tr>";
1575  for (int r = 0; r < NROFATTACKS; r++) {
1576  report += "<th>" + QString(attacktype_desc[r]) + "</th>";
1577  }
1578  report += "</tr>";
1579 
1580  for (auto const &mat : materials) {
1581  report += tr("<tr><td>%1</td>").arg(mat->name);
1582  for (int r = 0; r < NROFATTACKS; r++) {
1583  int8_t val = (s == 0 ? mat->save[r] : mat->mod[r]);
1584  report += tr("<td>%1</td>").arg(val == 0 ? QString() : QString::number(val));
1585  }
1586  report += "</tr>";
1587  }
1588  report += "</table>";
1589  }
1590 
1591  report += "</html>";
1592 
1593  CREReportDisplay show(report, "Materials report");
1594  QApplication::restoreOverrideCursor();
1595  show.exec();
1596 }
1597 
1599 {
1600  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1601 
1602  QString report;
1603  report += "<html>";
1604 
1605  report += "<h1>Apparently unused archetypes</h1>";
1606  report += "<h3>Warning: this list contains skills, items on style maps, and other things which are actually used.</h3>";
1607  report += "<table>";
1608  report += "<tr><th>Image</th><th>Archetype name</th><th>Item name</th><th>Type</th></tr>";
1609 
1610  getManager()->archetypes()->each([this, &report] (const archetype* arch)
1611  {
1612  if (arch->head || arch->clone.type == PLAYER || arch->clone.type == MAP || arch->clone.type == EVENT_CONNECTOR)
1613  return;
1614  if (strstr(arch->name, "hpbar") != nullptr)
1615  return;
1616 
1617  bool used = false;
1619  (ArchetypeUse, const archetype*, const treasurelist*, const CREMapInformation*, const recipe*) -> bool
1620  {
1621  used = true;
1622  return false;
1623  });
1624 
1625  if (!used)
1626  {
1627  QImage image(CREPixmap::getIcon(arch->clone.face->number).pixmap(32,32).toImage());
1628  QByteArray byteArray;
1629  QBuffer buffer(&byteArray);
1630  image.save(&buffer, "PNG");
1631  QString iconBase64 = QString::fromLatin1(byteArray.toBase64().data());
1632  auto td = get_typedata(arch->clone.type);
1633  report += tr("<tr><td><img src='data:image/png;base64,%1'></td><td>%2</td><td>%3</td><td>%4</td></tr>")
1634  .arg(iconBase64, arch->name, arch->clone.name, td ? td->name : tr("unknown: %1").arg(arch->clone.type));
1635  }
1636  });
1637 
1638  report += "</table>";
1639  report += "</html>";
1640 
1641  CREReportDisplay show(report, "Unused archetypes report");
1642  QApplication::restoreOverrideCursor();
1643  show.exec();
1644 }
1645 
1647 {
1648  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1649 
1650  QString report;
1651  report += "<html>";
1652 
1653  auto all = myResourcesManager->licenseManager()->getAll();
1654  std::set<std::string> faces, facesets, fields;
1655 
1656  for (auto item : all)
1657  {
1658  faces.insert(item.first);
1659  for (auto fs : item.second)
1660  {
1661  facesets.insert(fs.first);
1662  for (auto items : fs.second)
1663  {
1664  fields.insert(items.first);
1665  }
1666  }
1667  }
1668 
1669  getManager()->facesets()->each([&facesets] (const face_sets *fs)
1670  {
1671  facesets.erase(fs->prefix);
1672  });
1673  getManager()->faces()->each([&faces] (const Face *face)
1674  {
1676  });
1677 
1678  if (facesets.empty())
1679  {
1680  report += "<h1>No invalid faceset</h1>\n";
1681  }
1682  else
1683  {
1684  report += "<h1>Invalid faceset found</h1>\n";
1685  report += "<p>The faceset of the license file doesn't match any defined facesets.</p>";
1686  report += "<ul>\n";
1687  for (auto fs : facesets)
1688  {
1689  report += "<li>" + QString(fs.c_str()) + "</li>\n";
1690  }
1691  report += "</ul>\n";
1692  }
1693 
1694  if (faces.empty())
1695  {
1696  report += "<h1>No invalid face name</h1>\n";
1697  }
1698  else
1699  {
1700  report += "<h1>Invalid face names found</h1>\n";
1701  report += "<p>The face name from the license file doesn't match any defined face.</p>";
1702  report += "<ul>\n";
1703  for (auto f : faces)
1704  {
1705  report += "<li>" + QString(f.c_str()) + "</li>\n";
1706  }
1707  report += "</ul>\n";
1708  }
1709 
1710  report += "<h1>All fields used in license descriptions</h1>\n";
1711  report += "<ul>\n";
1712  for (auto f : fields)
1713  {
1714  report += "<li>" + QString(f.c_str()) + "</li>\n";
1715  }
1716  report += "</ul>\n";
1717 
1718  report += "</html>";
1719  CREReportDisplay show(report, "Licenses checks");
1720  QApplication::restoreOverrideCursor();
1721  show.exec();
1722 }
1723 
1725 {
1726  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1727 
1728  QString report;
1729  report += "<html>";
1730 
1732  auto groupCmp = [] (const std::string &left, const std::string &right) { return left < right; };
1733  auto mapCmp = [] (const CREMapInformation *left, const CREMapInformation *right)
1734  {
1735  int name = left->name().compare(right->name());
1736  if (name != 0)
1737  {
1738  return name < 0;
1739  }
1740  return left->path().compare(right->path()) < 0;
1741  };
1742  std::map<std::string, std::vector<CREMapInformation *>, decltype(groupCmp)> groups(groupCmp);
1743 
1744  for (auto map : maps)
1745  {
1746  if (!map->resetGroup().isEmpty())
1747  {
1748  groups[map->resetGroup().toStdString()].push_back(map);
1749  }
1750  }
1751 
1752  if (groups.empty())
1753  {
1754  report += "<h1>No reset group defined</h1>\n";
1755  }
1756  else
1757  {
1758  for (auto group : groups)
1759  {
1760  report += "<h1>" + QString(group.first.c_str()) + " (" + QString::number(group.second.size()) + " maps)</h1>\n";
1761  report += "<ul>\n";
1762  std::sort(group.second.begin(), group.second.end(), mapCmp);
1763  for (auto map : group.second)
1764  {
1765  report += tr("<li>%1 (%2)</li>").arg(map->name(), map->path());
1766  }
1767  report += "</ul>\n";
1768  }
1769  }
1770 
1771  report += "</html>";
1772  CREReportDisplay show(report, "Map reset groups");
1773  QApplication::restoreOverrideCursor();
1774  show.exec();
1775 }
1776 
1778 {
1780  edit.exec();
1781 }
1782 
1784 {
1785  CRESmoothFaceMaker smooth;
1786  smooth.exec();
1787 }
1788 
1790 {
1791  CRECombatSimulator simulator;
1792  simulator.exec();
1793 }
1794 
1796 {
1797  CREHPBarMaker maker;
1798  maker.exec();
1799 }
1800 
1802 {
1803  FaceMakerDialog maker(this, myResourcesManager);
1804  maker.exec();
1805 }
1806 
1808 {
1809  QMessageBox confirm;
1810  confirm.setWindowTitle(tr("Crossfire Resource Editor"));
1811  confirm.setText(tr("Really clear map cache?"));
1812  confirm.setInformativeText(tr("This will force cache rebuild at next application start."));
1813  confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1814  confirm.setDefaultButton(QMessageBox::No);
1815  confirm.setIcon(QMessageBox::Question);
1816  if (confirm.exec() == QMessageBox::Yes)
1817  {
1819  }
1820 }
1821 
1823 {
1824  CREPixmap::setFaceset(action->data().toString());
1825 }
1826 
1828 {
1830 }
1831 
1833 {
1834  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1838  QApplication::restoreOverrideCursor();
1839  QMessageBox::information(this, "Reload complete", "Assets reload complete, you may need to change the selected item to see updated versions.");
1840 }
1841 
1843 {
1845  QString dir = QFileDialog::getExistingDirectory(this, tr("Please select the 'sounds' directory"), settings.soundsDirectory());
1846  if (dir.isEmpty())
1847  return;
1848  settings.setSoundsDirectory(dir);
1849  SoundsDialog dlg(dir, this);
1850  dlg.exec();
1851 }
1852 
1854  auto windows = myArea->subWindowList();
1855  bool hasWindows = !windows.empty();
1856 
1857  while (myWindows->actions().size() > 6) {
1858  myWindows->removeAction(myWindows->actions()[6]);
1859  }
1860  for (auto a : myWindows->actions()) {
1861  if (a->isSeparator()) {
1862  a->setVisible(hasWindows);
1863  } else if (a != myWindows->actions()[0]) {
1864  a->setEnabled(hasWindows);
1865  }
1866  }
1867 
1868  for (int i = 0; i < windows.size(); ++i) {
1869  QMdiSubWindow *mdiSubWindow = windows.at(i);
1870 
1871  QString title(mdiSubWindow->widget()->windowTitle());
1872  if (i < 9) {
1873  title = tr("&%1 %2").arg(i + 1).arg(title);
1874  } else {
1875  title = tr("%1 %2").arg(i + 1).arg(title);
1876  }
1877  QAction *action = myWindows->addAction(title, mdiSubWindow, [this, mdiSubWindow] () {
1878  myArea->setActiveSubWindow(mdiSubWindow);
1879  });
1880  action->setCheckable(true);
1881  action ->setChecked(mdiSubWindow == myArea->activeSubWindow());
1882  }
1883 }
1884 
1886  auto reg = get_region_by_name(map->region().toLocal8Bit().data());
1887  map->setDisplayParent(myResourcesManager->wrap(reg, myAssets->regions()));
1888  for (auto rm : map->randomMaps()) {
1889  rm->setDisplayParent(myAssets->randomMaps());
1890  }
1891 }
spells
the faster the spell may be cast there are several other common only the caster may be affected by the spell The most common spell range is that of touch This denotes that the caster much touch the recipient of the spell in order to release the spell or wall For cone spells
Definition: spell-info.txt:46
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:70
ResourcesManager::archetypeUse
static void archetypeUse(const archetype *item, CREMapInformationManager *store, AssetUseCallback callback)
Definition: ResourcesManager.cpp:138
AssetsManager::messages
Messages * messages()
Definition: AssetsManager.h:59
CREMainWindow::onReportAlchemy
void onReportAlchemy()
Definition: CREMainWindow.cpp:736
CREMainWindow::onReportArchetypes
void onReportArchetypes()
Definition: CREMainWindow.cpp:1598
skills
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters as well as how often the character can attack this affects the prices when buying and selling items if this drops the player will start losing hit points wd Cleric or Dwarf sm Elf wd Fireborn ft Human ra Mage C Monk se Ninja hi Priest C Quetzalcoatl mw Swashbuckler si Thief st Viking ba Warrior or Wizard C Wraith C Class Prof Str Dex Con Wis Cha Int Pow Net Skills Enclosed are codes used for the skills above The ones in and fighting should all be pretty self explanatory For the other skills
Definition: stats.txt:126
CREMapInformationManager::allMaps
QList< CREMapInformation * > allMaps()
Definition: CREMapInformationManager.cpp:365
ResourcesManager::licenseManager
LicenseManager * licenseManager()
Definition: ResourcesManager.h:152
object::weapon_speed_left
float weapon_speed_left
Definition: object.h:340
PLAYER
@ PLAYER
Definition: object.h:112
CREMainWindow::onReportPlayer
void onReportPlayer()
Definition: CREMainWindow.cpp:1150
global.h
make_face_from_files.anims
list anims
Definition: make_face_from_files.py:59
monsterTable
static QString monsterTable(archetype *monster, QList< archetype * > skills)
Definition: CREMainWindow.cpp:1124
line
Install Bug reporting Credits so make sure you have version or later There are files involved in the automatic convert convertall and filelist py GuildList has the list of guilds for the server GuildLocations is what is used by the install script for setting up the maps It has columns in the first is the name of the no spaces The second is the region of the the third is the destination folder for the the fourth is the exit the fifth and sixth are the x and y coords within the exit the seventh eighth and ninth are the exit location for the storage hall If field seven is then it uses the same exit map as for the guild hall itself filelist py has a list of which files to process for each guild hall convert py takes all the files in filelist py and customises them to the specific guild then outputs them into a in the same order that they are listed in GuildLocations convertall py reads the lines from GuildLocations and runs line by line
Definition: README.txt:12
settings
struct Settings settings
Definition: init.cpp:139
Files
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map Files
Definition: README.txt:17
spellsTable
static QString spellsTable(const QString &skill)
Definition: CREMainWindow.cpp:867
banquet.l
l
Definition: banquet.py:164
MAP
@ MAP
Definition: object.h:130
get_formulalist
recipelist * get_formulalist(int i)
Definition: recipe.cpp:98
living::maxhp
int16_t maxhp
Definition: living.h:41
LicenseManager::reset
void reset()
Definition: LicenseManager.h:52
CREMainWindow::myMessageManager
MessageManager * myMessageManager
Definition: CREMainWindow.h:70
LicenseManager.h
AssetWrapper::tipProperty
static const char * tipProperty
Definition: AssetWrapper.h:34
LicenseManager::licenseNameFromFaceName
static std::string licenseNameFromFaceName(const std::string &face)
Definition: LicenseManager.cpp:83
FABS
#define FABS(x)
Definition: define.h:22
EVENT_CONNECTOR
@ EVENT_CONNECTOR
Definition: object.h:232
get_empty_map
mapstruct * get_empty_map(int sizex, int sizey)
Definition: map.cpp:842
CREPixmap::setUseFacesetFallback
static void setUseFacesetFallback(bool use)
Definition: CREPixmap.cpp:52
CREMainWindow::onReportSpellDamage
void onReportSpellDamage()
Definition: CREMainWindow.cpp:591
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
CREMainWindow::onReportSpells
void onReportSpells()
Definition: CREMainWindow.cpp:900
test_map
mapstruct * test_map
Definition: comet_perf.cpp:74
get_region_by_name
region * get_region_by_name(const char *region_name)
Definition: region.cpp:46
player
Definition: player.h:105
CREMainWindow::onSaveFormulae
void onSaveFormulae()
Definition: CREMainWindow.cpp:371
AssetsCollection::get
T * get(const Key &name)
Definition: AssetsCollection.h:89
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
CREMainWindow::onToolSmooth
void onToolSmooth()
Definition: CREMainWindow.cpp:1783
recipe::arch_names
size_t arch_names
Definition: recipe.h:12
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
AllAssets::randomMaps
AssetWrapper * randomMaps()
Definition: AllAssets.h:35
has_been_loaded
mapstruct * has_been_loaded(const char *name)
Definition: map.cpp:78
socket_struct
Definition: newserver.h:89
CREMainWindow::onToolBarMaker
void onToolBarMaker()
Definition: CREMainWindow.cpp:1795
ChangesDock.h
CREMapInformationManager::start
void start()
Definition: CREMapInformationManager.cpp:85
CREMainWindow::fillFacesets
void fillFacesets()
Definition: CREMainWindow.cpp:347
CRESettings.h
object::speed
float speed
Definition: object.h:337
CREMainWindow::myOpenMenu
QMenu * myOpenMenu
Definition: CREMainWindow.h:59
cleanup
void cleanup(void)
Definition: server.cpp:1259
AllAssets
Definition: AllAssets.h:23
guildoracle.list
list
Definition: guildoracle.py:87
object::speed_left
float speed_left
Definition: object.h:338
CREExperienceWindow
Definition: CREExperienceWindow.h:18
report.report
def report(pl)
Definition: report.py:6
object::map
struct mapstruct * map
Definition: object.h:305
Settings::localdir
const char * localdir
Definition: global.h:249
fields
non standard information is not specified or uptime fields
Definition: arch-handbook.txt:204
RandomMap.h
root
static char root[500]
Definition: mapper.cpp:304
doIngredients
static void doIngredients(const std::vector< std::pair< QString, int >> &allIngredients, const QString &criteria, QString &report)
Definition: CREMainWindow.cpp:727
mad_mage_user.file
file
Definition: mad_mage_user.py:15
alchemyTable
static QString alchemyTable(const QString &skill, QStringList &noChance, std::vector< std::pair< QString, int >> &allIngredients)
Definition: CREMainWindow.cpp:640
MIN
#define MIN(x, y)
Definition: compat.h:21
readDirectory
void readDirectory(const QString &path, QHash< QString, QHash< QString, bool > > &states)
Definition: CREMainWindow.cpp:1442
move_player
int move_player(object *op, int dir)
Definition: player.cpp:2948
CREMainWindow::onReportAlchemyGraph
void onReportAlchemyGraph()
Definition: CREMainWindow.cpp:781
hall_of_fame.keys
keys
Definition: hall_of_fame.py:43
ChangesDock
Definition: ChangesDock.h:24
SKILL
@ SKILL
Definition: object.h:148
CREHPBarMaker.h
MessageManager::saveMessages
void saveMessages()
Definition: MessageManager.cpp:43
AssetModel.h
object::count
tag_t count
Definition: object.h:307
monster_do_living
void monster_do_living(object *op)
Definition: monster.cpp:721
CREMainWindow::myHelpManager
HelpManager * myHelpManager
Definition: CREMainWindow.h:74
archetypes
other than new code I created new archetypes
Definition: arch-handbook.txt:18
fix_object
void fix_object(object *op)
Definition: living.cpp:1125
CREMapInformationManager
Definition: CREMapInformationManager.h:27
EditMonstersDialog.h
ScriptFileManager.h
recipe::arch_name
char ** arch_name
Definition: recipe.h:13
monster
the faster the spell may be cast there are several other common only the caster may be affected by the spell The most common spell range is that of touch This denotes that the caster much touch the recipient of the spell in order to release the spell monster
Definition: spell-info.txt:45
ScriptFileManager
Definition: ScriptFileManager.h:26
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
CREMainWindow::myResourcesManager
ResourcesManager * myResourcesManager
Definition: CREMainWindow.h:71
curse_on_apply.ac
ac
Definition: curse_on_apply.py:4
CREMainWindow::myFacesetsGroup
QActionGroup * myFacesetsGroup
Definition: CREMainWindow.h:64
CREMainWindow::myWindows
QMenu * myWindows
Definition: CREMainWindow.h:67
CREMapInformationManager::browseFinished
bool browseFinished() const
Definition: CREMapInformationManager.cpp:80
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:4337
AssetsManager.h
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:361
FaceMakerDialog.h
CREMainWindow::onOpenExperience
void onOpenExperience(const QByteArray &position=QByteArray())
Definition: CREMainWindow.cpp:337
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2848
face_sets::prefix
char * prefix
Definition: image.h:19
ResourcesManager::saveQuests
void saveQuests()
Definition: ResourcesManager.cpp:226
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
linked_char
Definition: global.h:96
AllAssets::child
virtual AssetWrapper * child(int index)
Definition: AllAssets.h:31
quest
Definition: quest.py:1
CREMapInformation::name
QString name
Definition: CREMapInformation.h:32
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:127
CREMainWindow::myScriptManager
ScriptFileManager * myScriptManager
Definition: CREMainWindow.h:72
CREMainWindow::myMapBrowseStatus
QLabel * myMapBrowseStatus
Definition: CREMainWindow.h:68
GeneralMessage
Definition: book.h:44
AssetsManager::quests
Quests * quests()
Definition: AssetsManager.h:71
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
object::contr
struct player * contr
Definition: object.h:284
HelpManager
Definition: HelpManager.h:23
SP_BULLET
#define SP_BULLET
Definition: spells.h:79
disinfect.map
map
Definition: disinfect.py:4
FaceMakerDialog
Definition: FaceMakerDialog.h:26
CREMainWindow::onToolEditMonsters
void onToolEditMonsters()
Definition: CREMainWindow.cpp:1777
CREPixmap::setFaceset
static void setFaceset(const QString &prefix)
Definition: CREPixmap.cpp:44
object::subtype
uint8_t subtype
Definition: object.h:349
damage
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be and may attack the nearest of your enemies Others can be in that they follow you around and help you in your quest to kill enemies and find treasure SPECIAL ITEMS There are many special items which can be found in of these the most important may be the signs all a player must do is apply the handle In the case of the player must move items over the button to hold it down Some of the larger buttons may need very large items to be moved onto before they can be activated Gates and locked but be for you could fall down into a pit full of ghosts or dragons and not be able to get back out Break away sometimes it may be worth a player s time to test the walls of a map for secret doors Fire such as missile weapons and spells you will notice them going up in smoke ! So be careful not to destroy valuable items Spellbooks sometimes a player can learn the other times they cannot There are many different types of books and scrolls out there Improve item have lower higher damage
Definition: survival-guide.txt:100
SK_TWO_HANDED_WEAPON
@ SK_TWO_HANDED_WEAPON
Definition: skills.h:56
ResourcesManager::saveTreasures
void saveTreasures()
Definition: ResourcesManager.cpp:234
recipelist
Definition: recipe.h:37
MonsterResistances
Definition: MonsterResistances.h:24
rotate-tower.result
bool result
Definition: rotate-tower.py:13
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:327
CREMainWindow::onClearCache
void onClearCache()
Definition: CREMainWindow.cpp:1807
object::weapon_speed
float weapon_speed
Definition: object.h:339
output
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs rules Media tags are made of with inside them the name of tag and optional parameters for the tag Unlike html or there is no notion of opening and closing tag A client not able to understand a tag is supposed to ignore it when server is communicating with and old client that does not understand a a specific extended it will issue a classical message output
Definition: media-tags.txt:36
levels
int64_t * levels
Definition: exp.cpp:26
treasurelist
Definition: treasure.h:85
CREMainWindow::onToolFaceset
void onToolFaceset(QAction *action)
Definition: CREMainWindow.cpp:1822
CREMainWindow::onWindowsShowing
void onWindowsShowing()
Definition: CREMainWindow.cpp:1853
monsters
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long but due to updates or the length of time the server instance has been up may be much shorter MN US< br > link< br >< a href="http: text_comment=Latest SVN 1.x branch, Eden Prairie, MN US archbase=Standard mapbase=Standard codebase=Standard num_players=3 in_bytes=142050710 out_bytes=-1550812829 uptime=909914 version=1.11.0 sc_version=1027 cs_version=1023 last_update=1214541369 END_SERVER_DATA ---- Multigod -------- This is a brief description of the MULTIGOD hack. It is preserved here for mostly historical reasons. Introduction ~~~~~~~~~~~~ The intention of this code is to enhance the enjoy-ability and playability of clerical characters in the new skills/exp scheme. This is done by giving players gods to worship who in turn effect clerical magic and powers. Included in this patch are several new spells which (hopefully) will allow the priest characters a better chance to gain xp at higher levels. Notably, the "holy orb" and "holy word" spells have been revamped. When MULTIPLE_GODS flag is defined in include/config.h, this code is enabled. This code (described below) encompasses 3 main parts: an array of gods that players/NPCs may worship, new clerical spells which rely on the worshiped god's attrib- utes in Gods[] array and, altars/praying--the interface between a worshiper and their god. b.t. thomas@astro.psu.edu Implementation Details ~~~~~~~~~~~~~~~~~~~~~~ This code is flexible and easy to configure (just edit the god archetypes). Part of the reason for creating this code was to allow server maintainers to develop their own "mythos". From my personal point of view, I hate having the old "Christian" aligned mythos, but if that's what you like, you can replicate it with this code too (see below). Properties of the Gods ~~~~~~~~~~~~~~~~~~~~~~ Here is a fuller description of Gods archetype values. ---- name - name of the god (required) other_arch - archetype that will be used for the summon holy servant spell. title - diametrically opposed god, leave blank if none exists attacktype - favored attack of this god, used in spells of summon avatar, holy word. Recipients of "holy possession" get this too. immune - Avatars/holy servants/recipient of "holy possession" gets this. protected - all of the above AND recipient of god's blessing and the priest of this god gets this. vulnerable - Avatar/servant/recipient of gods curse/priest of this god get this. path_attuned - priest of this god and recipient of "bless" gets this path_repelled - priest and recipient of "curse" gets this path_denied - priest and recipient of "curse" gets this slaying - comma delimited list of the races of creatures that are aligned with the god. "summon cult monsters" uses. this list to find creatures. Summon avatar/call servant code assigns this value to prevent them from attacking aligned races. Value is blank if no race(s) exists. race - comma delimited list of the races of creatures "holy word", "holy possession" spells will effect. Value entry is blank if no such race(s) exists. hp,dam,ac,wc - base stats for the summoned avatar. ---- IF MORE_PRIEST_GIFTS is defined (in gods.c) then ADDITIONAL gifts/limitations will be assigned to the priest: Flags ^^^^^ Now, the following flags, in addition to being used by the god (if planted on a map) are assigned to the worshiping priest: can_use_weapon, can_use_armour, is_undead, is_blind, reflect_missile, reflect_spell, make_invisible, stealth, can_see_in_dark, xrays NOTE: if can_use_armour/can_use_weapon flags are NOT present, then the priest will be forbidden the use of these items. Stats ^^^^^ The following stats are used: ---- luck - how lucky the god (and the priest) are. last_eat - how fast priest digestion is last_hp - how fast priest healing is last_sp - how fast priest mana regeneration is last_grace - how fast priest grace regeneration is ---- Designing New Gods ~~~~~~~~~~~~~~~~~~ To examine the gods properties, use the '-m8' flag (ie 'crossfire -m8'). Note some of the big differences here in terms of spell_paths, races, etc. Most of these entries were designed with roughly polar opposite gods. For designing new gods. You should make sure that worshiping a god will be "unique" in some way. But playbalance first! You must consider the balance between the following: . spellpaths . priest gifts . priest limitations . special spells . attacktypes . summoned monster lists . properties of the avatar and holy servant. Here are some hard and fast rules for designing gods: - Decide how the cleric will get experience. The god should be either a 'summoning', 'turning' *or* a 'wounding' god. If summoning/turning, make sure the aligned_race/enemy_race list(s) has enough creatures to summon/slay at low, medium and high levels. DONT give a god attuned to wounding AND turning||summoning (in fact, at minimum, one of these 3 paths should be repelled/denied). - make sure the summoned avatar is stronger than the servant (!) - examine the avatar/servant stats. If set inproperly, you will give wimpy/super values. For example, Avatars/servants with less than 50 hp (and a high ac/no armour) will vanish quickly. Shoot for stats like: ---- type | A V E R A G E S T A T S | hp | ac | wc | arm | dam | speed ----------|----------------------------------- servant | 50 | 5 | 5 | 20 | 5 | 0.15 avatar | 350 | -5 | -1 | 50 | 50 | 0.25 ---- Its difficult to give measurements on how to trade these off. To help guide your choices try to conserve the value of speed*dam and (armour+1)*hp. * avoid giving the potent attacktypes of death, weaponmagic and paralysis. * gods have a vulnerability for every immunity. Not all attacktypes are the same. Immunity to physical, magic and common attacktypes (like fire/cold/electric) are very potent. Similarly, vuln to these is a big negative. * SPELL paths. Carefull treatment is needed here. Give a path_denied/ or a couple path_repelled for every path_attuned. BUT note: not all paths are of equal use. (ex path_abjuration has a very large list of spells). The main clerical paths are restoration, abjuration, protection, turning, wounding and summoning. For balance, make 3-4 of these repelled/denied and 1 or 2 attuned. Be sure to check out the special spells list (below). Attuned paths like DEATH, WOUNDING and (especially) PROTECTION are very potent. Allow for some balance else where if you assign (one!) of these as a path_attuned. * If using the MORE_PRIEST_GIFTS define: priest limitations of no weapons and no armour are very negative, be sure to compensate with more than an attunded path. Of course, you may break these 'rules' to create your god. When you do that, you had better make up for the bonus elsewhere! Otherwise, you will create a 'mega-god' whose worship (by the player priests) will unbalance the game. Designing a good god takes a bit of work. Special Spells ~~~~~~~~~~~~~~ Here is a possibly *incomplete* list of the special spells that a god may grant use to a worshiper. Check the file spellist.h for the 0 bookchance clerical spells to find all of these. (This list was complete on 10/96). ---- INFO perceive self PROTECTION defense; immuntity to cold, fire, electricity, poison, slow, paralysis, draining, attack, and magic RESTORE remove damnation; reincarnation; raise dead; resurrection; regeneration WOUNDING cause critical wounds; retributive strike LIGHT daylight; nightfall DEATH face of death; finger of death SUMMONING insect plague CREATE wall of thorns ---- Ideas ~~~~~ * Allow sacrifices. This is an excellent way to give a cleric xp. Need to create enemy_race creatures w/ bodyparts we can sacrifice, and designate a pointer in Gods to the appropriate array of stuff we can sacrifice for xp. Experience ---------- Obsolete file kept for historical reasons. Introduction ~~~~~~~~~~~~ This patch represents a "developer 's" version of the exp/skills system. While I have now achieved all of the objectives in sections "B" and "C" of the coding proposal (see README.PROPOSAL) and have play-tested as much of the code as possible, I am sure some big bugs must remain. (One for sure is that exp gained when using rod/horn/wand is wrong.) Below this section I outline 1) coding philosophy, 2) gross description of how the code impinges/interacts within older code. 3) designer's notes on the changes to the code. Comments on any area of this coding would be appreciated. Personally, I would like to see the Pow stat and a 2-type system of magic come into being. After all of you check out the code, I would like to discuss enhancements/bug fixes/implementation. For instance, is it too hard to figure out how to use the code! Sometime tomorrow exp2.tar.gz will be available in pub/thomas on ftp.astro.psu.edu. b.t. Code Philosophy ^^^^^^^^^^^^^^^ To move CF over to a new skills-based experience system. In this implementation several kinds of experience will exist. Players will gain experience in each kind of experience (or category) based on their actions in the game. The sum of all the various categories of experience equals the player "score", from which dam, wc, and hp are determined. All experience gaining actions will be through the use of certain skills -- so called "associated skills". Associated skills are each related to 1 kind of experience. Thus, for example, "stealing" is a skill associated with "agility" experience. There exists also "miscellaneous" skills which allow the use of a unique skill, but which are not related to any kind of experience and whose use does not generate experience points. In this implementation, skills and objects are both treated as objects in the inventory of the user. Experience "objects" each represent one kind of experience and are always invisible. Skills objects each represent one kind of skill available in the game. Skills objects may either be invisible or have an associated bitmap (in which case they are "tools"). All experience gaining actions will be through the use of certain skills -- called "associated skills". Associated skills are each related to 1 kind of experience. Thus, for example, "stealing" is a skill associated with "agility" experience. Both Players and NPC's may only use skills which are in their inventories. NPC's do not use experience objects. A breakdown of the properties of skills and exp objects objects is as follows: ---- Object Property NPC use? ------ ----------------------------------- ------- Experience Each represents a different kind of NO experience in the game. The object in the player inventory keeps track of player experience in that category. Always is invisible. Skill- Represents a skill the player may YES associated perform. May be either invisible or visible as a "tool". Successful use of this skill generates experience. Experience is allocated to appropriate experience object. Skill- Same as above, *but* this skill is not YES miscell. related to any experience category, and use of this skill generates *no* experience. ---- Linking of associated skills to experience categories is done during initialization of the code (in init()) based on the shared stats of both. How skills and experience categories are named and linked may be changed by editing the skills/experience object archetypes. Implementation Details ~~~~~~~~~~~~~~~~~~~~~~ The most important thing is that I moved most of the code into the server/skills.c and server/skill_util.c files. The skills code is loosely implemented along the lines of the spell code. This is to say that: . skills use (do_skill) is called from fire(). . there is a skills[] table similar to spells[]. . server files skills.c and skill_util.c parallel spell_effect.c and spell_util.c in respective functionallity. Particular notes about the implementation are outlined below. Defines ^^^^^^^ #define MAX_EXP_CAT be > I had to make use of several global parameters These etc FLAG_IS_HILLY needed by the mountaineer skill Should be set on all mountainous terrain FLAG_READY_WEAPON Code needs this for both players and monsters
Definition: arch-handbook.txt:558
archetype::clone
object clone
Definition: object.h:478
CREMapInformationManager::clearCache
void clearCache()
Definition: CREMapInformationManager.cpp:797
ResourcesManager::wrap
ArchetypeWrapper * wrap(archetype *arch, AssetWrapper *parent)
Definition: ResourcesManager.h:131
CREMainWindow::mySaveFormulae
QAction * mySaveFormulae
Definition: CREMainWindow.h:62
Face::name
sstring name
Definition: face.h:19
speed
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters speed
Definition: stats.txt:23
AssetsCollection::find
T * find(const Key &name)
Definition: AssetsCollection.h:108
AssetWrapper::setDisplayParent
void setDisplayParent(AssetWrapper *parent)
Definition: AssetWrapper.h:47
CREMainWindow.h
done
int done
Definition: readable.cpp:1553
convert.action
action
Definition: convert.py:25
monsterFight
static int monsterFight(archetype *monster, archetype *skill, int level)
Definition: CREMainWindow.cpp:932
CRESmoothFaceMaker.h
ResourcesManager
Definition: ResourcesManager.h:80
SoundsDialog.h
object::type
uint8_t type
Definition: object.h:348
message
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your message
Definition: survival-guide.txt:34
CREMainWindow::myModel
AssetModel * myModel
Definition: CREMainWindow.h:53
living::dam
int16_t dam
Definition: living.h:46
object_create_arch
object * object_create_arch(archetype *at)
Definition: arch.cpp:298
maps
this information may not reflect the current implementation This brief document is meant to describe the operation of the crossfire as well as the form of the data The metaserver listens on port for tcp and on port for udp packets The server sends updates to the metaserver via udp The metaserver only does basic checking on the data that server sends It trusts the server for the ip name it provides The metaserver does add the ip address and also tracks the idle time(time since last packet received). The client gets its information from the metaserver through connecting by means of tcp. The client should retrieve http the body s content type is text plain The current metaserver implementation is in Perl But the metaserver could be in any language perl is fast enough for the amount of data that is being exchanged The response includes zero or more server entries Each entry begins with the line START_SERVER_DATA and ends with the line END_SERVER_DATA Between these lines key value pairs("key=value") may be present. The entries are sent in arbitrary order. A client should apply some ordering when displaying the entries to the user. TODO b additional information outside BEGIN_SERVER_DATA END_SERVER_DATA maps
Definition: arch-handbook.txt:189
spell
with a maximum of six This is not so if you are wearing plate you receive no benefit Armour is additive with all the supplementry forms of which means that it lasts until the next semi permanent spell effect is cast upon the character spell
Definition: tome-of-magic.txt:44
linked_char::next
struct linked_char * next
Definition: global.h:98
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1587
title
Definition: readable.cpp:108
artifactlist
Definition: artifact.h:24
AssetsManager::archetypes
Archetypes * archetypes()
Definition: AssetsManager.h:44
F
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters as well as how often the character can attack this affects the prices when buying and selling items if this drops the player will start losing hit points wd Cleric F
Definition: stats.txt:90
CREMainWindow::onToolCombatSimulator
void onToolCombatSimulator()
Definition: CREMainWindow.cpp:1789
CREMainWindow::myChanges
ChangesDock * myChanges
Definition: CREMainWindow.h:73
CREMainWindow::CREMainWindow
CREMainWindow(const QString &helpRoot)
Definition: CREMainWindow.cpp:50
disinfect.count
int count
Definition: disinfect.py:7
say.max
dictionary max
Definition: say.py:148
ResourcesManager::saveGeneralMessages
void saveGeneralMessages()
Definition: ResourcesManager.cpp:261
CREExperienceWindow.h
tag_t
uint32_t tag_t
Definition: object.h:14
archetype
Definition: object.h:474
CREMainWindow::mapAdded
void mapAdded(CREMapInformation *map)
Definition: CREMainWindow.cpp:1885
Settings::playerdir
const char * playerdir
Definition: global.h:250
sproto.h
CREMainWindow::onToolFacesetUseFallback
void onToolFacesetUseFallback()
Definition: CREMainWindow.cpp:1827
LicenseManager::getAll
std::map< std::string, LicenseItems > getAll() const
Definition: LicenseManager.h:47
animate.anim
string anim
Definition: animate.py:20
IS_COMBAT_SKILL
#define IS_COMBAT_SKILL(num)
Definition: skills.h:91
delete_map
void delete_map(mapstruct *m)
Definition: map.cpp:1696
ResourcesManager::load
void load()
Definition: ResourcesManager.cpp:57
object::race
sstring race
Definition: object.h:326
AssetsManager::facesets
Facesets * facesets()
Definition: AssetsManager.h:65
ResourcesManager::saveArchetypes
void saveArchetypes()
Definition: ResourcesManager.cpp:218
ArchetypeUse
ArchetypeUse
Definition: ResourcesManager.h:66
CRESettings
Definition: CRESettings.h:21
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:2095
object::other_arch
struct archetype * other_arch
Definition: object.h:423
ASSETS_ALL
#define ASSETS_ALL
Definition: assets.h:32
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
reportSummon
static QString reportSummon(const archetype *summon, const object *other, QString name)
Definition: CREMainWindow.cpp:1221
MonsterResistances.h
CREMainWindow::onReportSummon
void onReportSummon()
Definition: CREMainWindow.cpp:1277
recipe::ingred_count
int ingred_count
Definition: recipe.h:23
MAX_BUF
#define MAX_BUF
Definition: define.h:35
codes
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters as well as how often the character can attack this affects the prices when buying and selling items if this drops the player will start losing hit points wd Cleric or Dwarf sm Elf wd Fireborn ft Human ra Mage C Monk se Ninja hi Priest C Quetzalcoatl mw Swashbuckler si Thief st Viking ba Warrior or Wizard C Wraith C Class Prof Str Dex Con Wis Cha Int Pow Net Skills Enclosed are codes used for the skills above The ones in and fighting should all be pretty self explanatory For the other a brief description is for a more detailed look at the skills doc file Skill codes
Definition: stats.txt:132
CREMainWindow::onReportShops
void onReportShops()
Definition: CREMainWindow.cpp:1394
HelpManager::displayHelp
void displayHelp()
Definition: HelpManager.cpp:50
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:278
path
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
CREMainWindow::onToolReloadAssets
void onToolReloadAssets()
Definition: CREMainWindow.cpp:1832
living::wc
int8_t wc
Definition: living.h:37
names
const char *const names[]
Definition: AssetOriginAndCreationDialog.cpp:24
CREMainWindow::onToolSounds
void onToolSounds()
Definition: CREMainWindow.cpp:1842
recipe
Definition: recipe.h:10
ResourcesManager.h
CRESettings::storeWindowsState
bool storeWindowsState() const
Definition: CRESettings.cpp:120
ResourcesManager::getMapInformationManager
CREMapInformationManager * getMapInformationManager()
Definition: ResourcesManager.h:91
ResourcesManager::hasPendingChanges
bool hasPendingChanges() const
Definition: ResourcesManager.h:121
make_face_from_files.out
out
Definition: make_face_from_files.py:81
CREPixmap::clearFaceCache
static void clearFaceCache()
Definition: CREPixmap.cpp:60
CREMainWindow::onReportResetGroups
void onReportResetGroups()
Definition: CREMainWindow.cpp:1724
CREMapInformation
Definition: CREMapInformation.h:27
CREMainWindow::onFiltersModified
void onFiltersModified()
Definition: CREMainWindow.cpp:397
CREMainWindow::browsingFinished
void browsingFinished()
Definition: CREMainWindow.cpp:390
AssetWrapper::displayName
QString displayName
Definition: AssetWrapper.h:29
object::name
sstring name
Definition: object.h:319
attacktype_desc
const char *const attacktype_desc[NROFATTACKS]
Definition: init.cpp:40
CREPixmap.h
CRESettings::setStoreWindowState
void setStoreWindowState(bool store)
Definition: CRESettings.cpp:124
report
Definition: report.py:1
Settings::max_level
int16_t max_level
Definition: global.h:302
AssetsCollection::each
void each(std::function< void(T *)> op)
Definition: AssetsCollection.h:158
CREMainWindow::browsingMap
void browsingMap(const QString &path)
Definition: CREMainWindow.cpp:385
players
std::vector< archetype * > players
Definition: player.cpp:493
CREMapInformationManager.h
powerbroker.confirm
def confirm(text, action)
Definition: powerbroker.py:97
ResourcesManager::saveArtifacts
void saveArtifacts()
Definition: ResourcesManager.cpp:265
CREPixmap::init
static void init()
Definition: CREPixmap.cpp:32
recipe::chance
int chance
Definition: recipe.h:14
item
Definition: item.py:1
CREResourcesWindow.h
CREMainWindow::doResourceWindow
void doResourceWindow(int assets, const QByteArray &position=QByteArray())
Definition: CREMainWindow.cpp:312
mapstruct
Definition: map.h:314
sstring
const typedef char * sstring
Definition: sstring.h:2
CREMainWindow::createAction
QAction * createAction(const QString &title, const QString &statusTip, F functor, bool waitMaps=false)
Definition: CREMainWindow.cpp:152
AssetsManager::faces
Faces * faces()
Definition: AssetsManager.h:39
types
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data types
Definition: protocol.txt:36
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
mapstruct::in_memory
uint32_t in_memory
Definition: map.h:335
CREMainWindow::myToolFacesetUseFallback
QAction * myToolFacesetUseFallback
Definition: CREMainWindow.h:65
help
static void help(void)
Definition: init.cpp:1132
CREMainWindow::myClearMapCache
QAction * myClearMapCache
Definition: CREMainWindow.h:66
recipe::diff
int diff
Definition: recipe.h:16
CREHPBarMaker
Definition: CREHPBarMaker.h:22
CREMainWindow::onReportDuplicate
void onReportDuplicate()
Definition: CREMainWindow.cpp:413
CREMainWindow::updateReports
void updateReports()
exit
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map or objects if you want to use the optional Python based Guild Storage hall The first three are on the main the next two are in the guild_hq and the final one is in hallofjoining Withe the Storage three objects are found on the main floor and the last two are in the basement It s not that but you will need a map editor You find the object that has the click edit and change the line script options(which currently is "GUILD_TEMPALTE") to the guild you wish to use. And make sure you use the same one for all of them or it won 't work. Here 's a quick HOWTO for using the map editor to make these changes edit the mainfloor map exit(x15, y29 - set to/Edit/This/Exit/Path in the template) back to the world map as well. If you are using the Storage Hall map(storage_hall)
MessageManager::loadMessages
void loadMessages()
Definition: MessageManager.cpp:34
assets.h
npc_dialog.index
int index
Definition: npc_dialog.py:102
CREMainWindow::onSaveQuests
void onSaveQuests()
Definition: CREMainWindow.cpp:375
living::ac
int8_t ac
Definition: living.h:38
CREMainWindow::myArea
QMdiArea * myArea
Definition: CREMainWindow.h:52
dragon_attune.faces
dictionary faces
Definition: dragon_attune.py:31
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
player
the faster the spell may be cast there are several other common only the caster may be affected by the spell The most common spell range is that of touch This denotes that the caster much touch the recipient of the spell in order to release the spell or wall For cone it usually denotes that the range depends on some such as the caster s Wisdom level If this is the it will be stated in the long spell description or the standard duration for the spell expires Only one protection or change player attribute spell may be in effect on a player at any one time If another such spell is cast upon a player
Definition: spell-info.txt:68
level
int level
Definition: readable.cpp:1550
first_artifactlist
artifactlist * first_artifactlist
Definition: init.cpp:109
CREMainWindow::onReportQuests
void onReportQuests()
Definition: CREMainWindow.cpp:1485
castle_read.key
key
Definition: castle_read.py:64
CREReportDisplay.h
Face
Definition: face.h:14
CREMainWindow::createActions
void createActions()
Definition: CREMainWindow.cpp:189
Settings::datadir
const char * datadir
Definition: global.h:248
CRECombatSimulator.h
CREMainWindow::myAssets
AllAssets * myAssets
Definition: CREMainWindow.h:54
CREMainWindow::onReportLicenses
void onReportLicenses()
Definition: CREMainWindow.cpp:1646
CRECombatSimulator
Definition: CRECombatSimulator.h:27
skill
skill
Definition: arch-handbook.txt:585
first
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at first
Definition: protocol.txt:20
object_remove
void object_remove(object *op)
Definition: object.cpp:1828
CREMapInformationManager::cancel
void cancel()
Definition: CREMapInformationManager.cpp:359
a
Magical Runes Runes are magical inscriptions on the dungeon which cast a spell or detonate when something steps on them Flying objects don t detonate runes Beware ! Runes are invisible most of the time They are only visible occasionally ! There are several runes which are there are some special runes which may only be called with the invoke and people may apply it to read it Maybe useful for mazes ! This rune will not nor is it ordinarily invisible Partial Visibility of they ll be visible only part of the time They have a(your level/2) chance of being visible in any given round
MessageManager
Definition: MessageManager.h:25
animate.event
event
DIALOGCHECK MINARGS 1 MAXARGS 2
Definition: animate.py:17
AssetModel
Definition: AssetModel.h:29
recipe::ingred
linked_char * ingred
Definition: recipe.h:22
CREResourcesWindow
Definition: CREResourcesWindow.h:31
CREMainWindow::closeEvent
void closeEvent(QCloseEvent *event)
Definition: CREMainWindow.cpp:112
CREMainWindow::myMapManager
CREMapInformationManager * myMapManager
Definition: CREMainWindow.h:69
face_sets::fullname
char * fullname
Definition: image.h:20
do_some_living
void do_some_living(object *op)
Definition: player.cpp:3272
SP_SUMMON_GOLEM
#define SP_SUMMON_GOLEM
Definition: spells.h:86
FREE_OBJ_FREE_INVENTORY
#define FREE_OBJ_FREE_INVENTORY
Definition: object.h:535
code
Crossfire Architecture the general intention is to enhance the enjoyability and playability of CF In this code
Definition: arch-handbook.txt:14
CREMapInformation::path
QString path
Definition: CREMapInformation.h:31
AllAssets::regions
AssetWrapper * regions()
Definition: AllAssets.h:34
archetype::name
sstring name
Definition: object.h:475
recipe::next
recipe * next
Definition: recipe.h:24
AllAssets::childrenCount
virtual int childrenCount() const
Definition: AllAssets.h:30
assets_collect
void assets_collect(const char *datadir, int what)
Definition: assets.cpp:113
mapstruct::reset_time
uint32_t reset_time
Definition: map.h:321
recipe::skill
sstring skill
Definition: recipe.h:26
say.item
dictionary item
Definition: say.py:149
object::stats
living stats
Definition: object.h:378
attack_ob
int attack_ob(object *op, object *hitter)
Definition: attack.cpp:937
CREPixmap::getIcon
static QIcon getIcon(uint16_t faceNumber)
Definition: CREPixmap.cpp:65
connect
Definition: connect.py:1
AllAssets.h
get_faces_count
size_t get_faces_count()
Definition: assets.cpp:293
CRESmoothFaceMaker
Definition: CRESmoothFaceMaker.h:23
CREMainWindow::createMenus
void createMenus()
Definition: CREMainWindow.cpp:207
AssetsManager::animations
AllAnimations * animations()
Definition: AssetsManager.h:49
face_sets
Definition: image.h:17
SoundsDialog
Definition: SoundsDialog.h:18
SPELL
@ SPELL
Definition: object.h:219
CREMainWindow::onSaveMessages
void onSaveMessages()
Definition: CREMainWindow.cpp:380
CREMainWindow::mySaveMenu
QMenu * mySaveMenu
Definition: CREMainWindow.h:60
quests
static struct_quest ** quests
Definition: mapper.cpp:894
EditMonstersDialog
Definition: EditMonstersDialog.h:24
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
CREMainWindow::myToolsMenu
QMenu * myToolsMenu
Definition: CREMainWindow.h:63
if
if(!(yy_init))
Definition: loader.c:2626
living::hp
int16_t hp
Definition: living.h:40
ResourcesManager::setMapInformationManager
void setMapInformationManager(CREMapInformationManager *mapInformationManager)
Definition: ResourcesManager.h:88
ring_occidental_mages.r
r
Definition: ring_occidental_mages.py:6
HelpManager.h
GOD
@ GOD
Definition: object.h:153
AssetModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const override
Definition: AssetModel.cpp:30
CREReportDisplay
Definition: CREReportDisplay.h:19
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
determine_holy_arch
archetype * determine_holy_arch(const object *god, const char *type)
Definition: gods.cpp:675
CREMainWindow::onReportMaterials
void onReportMaterials()
Definition: CREMainWindow.cpp:1556
CREMainWindow::onReportsModified
void onReportsModified()
Definition: CREMainWindow.cpp:402
buildShopReport
static QString buildShopReport(const QString &title, const QStringList &types, const QList< CREMapInformation * > &maps, QStringList &items)
Definition: CREMainWindow.cpp:1338
CREMainWindow::updateFilters
void updateFilters()
recipe::title
sstring title
Definition: recipe.h:11
CREMainWindow::onToolFaceMaker
void onToolFaceMaker()
Definition: CREMainWindow.cpp:1801
MessageManager.h
level
Definition: level.py:1