Crossfire Server, Trunk
CREMapInformationManager.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 <QtConcurrent/QtConcurrent>
14 
16 #include "CRESettings.h"
17 #include "MessageManager.h"
18 #include "MessageFile.h"
20 #include "scripts/ScriptFile.h"
21 #include "random_maps/RandomMap.h"
22 
23 #include "global.h"
24 #include "assets.h"
25 #include "AssetsManager.h"
26 
27 const char* eventNames[NR_EVENTS] = {
28  "EVENT_NONE",
29  "EVENT_APPLY",
30  "EVENT_ATTACKED",
31  "EVENT_DEATH",
32  "EVENT_DROP",
33  "EVENT_PICKUP",
34  "EVENT_SAY",
35  "EVENT_STOP",
36  "EVENT_TIME",
37  "EVENT_THROW",
38  "EVENT_TRIGGER",
39  "EVENT_CLOSE",
40  "EVENT_TIMER",
41  "EVENT_DESTROY",
42  "EVENT_BORN",
43  "EVENT_CLOCK",
44  "EVENT_CRASH",
45  "EVENT_PLAYER_DEATH",
46  "EVENT_GKILL",
47  "EVENT_LOGIN",
48  "EVENT_LOGOUT",
49  "EVENT_MAPENTER",
50  "EVENT_MAPLEAVE",
51  "EVENT_MAPRESET",
52  "EVENT_REMOVE",
53  "EVENT_SHOUT",
54  "EVENT_TELL",
55  "EVENT_MUZZLE",
56  "EVENT_KICK",
57  "EVENT_MAPUNLOAD",
58  "EVENT_MAPLOAD",
59  "EVENT_USER",
60  "EVENT_SELLING",
61  "EVENT_ATTACKS",
62  "EVENT_BOUGHT",
63  "EVENT_MAPREADY",
64 };
65 
66 CREMapInformationManager::CREMapInformationManager(QObject* parent, MessageManager* messageManager, ScriptFileManager* scriptManager) : QObject(parent)
67 {
68  Q_ASSERT(messageManager != NULL);
69  Q_ASSERT(scriptManager != NULL);
70  myMessageManager = messageManager;
71  myScriptManager = scriptManager;
72  connect(this, SIGNAL(addHook(const QString &, HookInformation *)), scriptManager, SLOT(addHook(const QString &, HookInformation *)));
73 }
74 
76 {
77  qDeleteAll(myInformation);
78 }
79 
81 {
82  return myWorker.isFinished();
83 }
84 
86 {
87  if (myWorker.isRunning())
88  return;
89 
90  myWorker = QtConcurrent::run(this, &CREMapInformationManager::browseMaps);
91 }
92 
93 void CREMapInformationManager::checkItem(const object* item, CREMapInformation* information, const object* env)
94 {
95  archetype *arch = find_archetype(item->arch->name);
96  if (arch != NULL) {
97  addArchetypeUse(arch->name, information);
98  information->addArchetype(arch->name);
99  if (item->face && item->face != arch->clone.face)
100  {
101  addFaceUse(item->face->name, information);
102  information->addFace(item->face->name);
103  }
104  if (item->animation && item->animation != arch->clone.animation)
105  {
106  addAnimationUse(item->animation->name, information);
107  information->addAnimation(item->animation->name);
108  }
109  }
110  checkEvent(item, information, env);
111 
112  if (item->type == EXIT || item->type == TELEPORTER || item->type == PLAYER_CHANGER) {
113  char ep[500];
114  const char *start;
115 
116  if (!item->slaying) {
117  ep[0] = '\0';
118  /*if (warn_no_path)
119  printf(" exit without any path at %d, %d on %s\n", item->x, item->y, info->path);*/
120  } else {
121  memset(ep, 0, 500);
122  if (strcmp(item->slaying, "/!"))
123  strcpy(ep, EXIT_PATH(item));
124  else {
125  if (!item->msg) {
126  //printf(" random map without message in %s at %d, %d\n", info->path, item->x, item->y);
127  } else {
128  /* Some maps have a 'exit_on_final_map' flag, ignore it. */
129  start = strstr(item->msg, "\nfinal_map ");
130  if (!start && strncmp(item->msg, "final_map", strlen("final_map")) == 0)
131  /* Message start is final_map, nice */
132  start = item->msg;
133  if (start) {
134  const char *end = strchr(start+1, '\n');
135 
136  start += strlen("final_map")+2;
137  strncpy(ep, start, end-start);
138  }
139 
140  information->addRandomMap(new RandomMap(information, env->x, env->y, item->msg));
141  }
142  }
143 
144  if (strlen(ep)) {
145  char exit_path[500], tmppath[MAX_BUF];
146  path_combine_and_normalize(env->map->path, ep, exit_path, 500);
147  create_pathname(exit_path, tmppath, MAX_BUF);
148  if (!QFileInfo(tmppath).exists()) {
149  printf(" map %s doesn't exist in map %s, at %d, %d.\n", ep, env->map->path, env->x, env->y);
150  } else {
151  QString exit = exit_path;
152  if (!myToProcess.contains(exit))
153  myToProcess.append(exit);
154 
156  Q_ASSERT(other);
157  other->addAccessedFrom(exit);
158  information->addExitTo(exit_path);
159 
160 #if 0
161  link = get_map_info(exit_path);
162  add_map(link, &info->exits_from);
163  add_map(info, &link->exits_to);
164 
165  if (do_regions_link) {
166  mapstruct *link = ready_map_name(exit_path, 0);
167 
168  if (link && link != m) {
169  /* no need to link a map with itself. Also, if the exit points to the same map, we don't
170  * want to reset it. */
171  add_region_link(m, link, item->arch->clone.name);
172  link->reset_time = 1;
173  link->in_memory = MAP_IN_MEMORY;
174  delete_map(link);
175  }
176  }
177 #endif
178  }
179  }
180  }
181  }
182 
184  information->setExperience(information->experience() + item->stats.exp);
185 
187  {
188  checkItem(inv, information, env);
189  } FOR_INV_FINISH();
190 }
191 
192 void CREMapInformationManager::process(const QString& path2)
193 {
194  /*
195  don't ask why, but the variable gets apparently destroyed on the myToProcess.append() when it reallocated values...
196  so keep a copy to avoid messes
197  */
198  QString path(path2);
199 
200  if (myCancelled)
201  return;
202 
203  emit browsingMap(path);
204 // qDebug() << "processing" << path;
206 
207  char tmppath[MAX_BUF];
208  create_pathname(path.toLatin1(), tmppath, MAX_BUF);
209  QFileInfo info(tmppath);
210 
211  if (!info.exists())
212  {
213 // qDebug() << "non existant map" << tmppath;
214  return;
215  }
216 
217  if (!information->mapTime().isNull() && information->mapTime() >= info.lastModified())
218  {
219  foreach(QString exit, information->exitsTo())
220  {
221  if (!myToProcess.contains(exit))
222  myToProcess.append(exit);
223  }
224 // qDebug() << "skipping " << tmppath;
225  return;
226  }
227 
228  /* remove scripts to avoid duplications */
229  myScriptManager->removeMap(information);
230 
232 // qDebug() << "processing" << path << information->mapTime() << info.lastModified();
233  information->setName(m->name);
234  information->setMapTime(info.lastModified());
235  if (m->region != NULL)
236  information->setRegion(m->region->name);
237  else
238  information->setRegion("wilderness");
239  information->setDifficulty(m->difficulty);
240  m->difficulty = 0;
242  m->difficulty = information->difficulty();
243  if (m->background_music)
244  information->setBackgroundMusic(m->background_music);
245 
246  information->setShopGreed(m->shopgreed);
247  if (m->shopitems != NULL)
248  {
249  for (int i = 0; i < m->shopitems[0].index; i++)
250  {
251  information->shopItems().insert(QString(m->shopitems[i].name == NULL ? "*" : m->shopitems[i].name), m->shopitems[i].strength);
252  }
253  }
254  if (m->shoprace != NULL)
255  information->setShopRace(m->shoprace);
256  information->setShopMin(m->shopmin);
257  information->setShopMax(m->shopmax);
258  information->setResetGroup(m->reset_group ? m->reset_group : QString());
259 
260  char exit_path[500];
261 
262  for (int x = 0; x < 4; x++)
263  if (m->tile_path[x] != NULL) {
264  path_combine_and_normalize(m->path, m->tile_path[x], exit_path, sizeof(exit_path));
265  create_pathname(exit_path, tmppath, MAX_BUF);
266  if (!QFileInfo(tmppath).exists()) {
267  printf(" map %s doesn't exist in map %s, for tile %d.\n", exit_path, m->path, x);
268  }
269 
270  QString exit = exit_path;
271  if (!myToProcess.contains(exit))
272  myToProcess.append(exit);
273 
275  Q_ASSERT(other);
276  other->addAccessedFrom(path);
277  information->addExitTo(exit_path);
278  }
279 
280  for (int x = MAP_WIDTH(m)-1; x >= 0; x--)
281  {
282  for (int y = MAP_HEIGHT(m)-1; y >= 0; y--)
283  {
284  FOR_MAP_PREPARE(m, x, y, item)
285  {
286  checkItem(item, information, item);
287  } FOR_MAP_FINISH();
288  }
289  }
290 
291  QMutexLocker lock(&myLock);
292  if (m->region == NULL)
293  qDebug() << "map without region" << m->name << m->path;
294  myExperience[m->region ? m->region->name : "(undefined)"] += information->experience();
295 
296  m->reset_time = 1;
297  m->in_memory = MAP_IN_MEMORY;
298  delete_map(m);
299 }
300 
302 {
303  qDeleteAll(myInformation);
304  myArchetypeUse.clear();
305 
306  loadCache();
307 
308  myCancelled = false;
309  myCurrentMap = 0;
310  myToProcess.clear();
311  myToProcess.append(QString(first_map_path));
312 
313  /* try to find race-specific start maps */
314  if (first_map_ext_path[0] != 0)
315  {
316  getManager()->archetypes()->each([this] (archetype *arch)
317  {
318  if (arch->clone.type == PLAYER)
319  {
320  char path[MAX_BUF], name[MAX_BUF];
321  snprintf(name, sizeof(name), "%s/%s", first_map_ext_path, arch->name);
322  create_pathname(name, path, sizeof(path));
323  if (QFileInfo(path).exists()) {
324  myToProcess.append(name);
325  }
326  }
327  });
328  }
329 
330  /* Add style maps */
331  recurseStyleDirectory("styles");
332 
333  while (myCurrentMap < myToProcess.size())
334  {
335  process(myToProcess[myCurrentMap]);
336  myCurrentMap++;
337  if (myCancelled)
338  break;
339  }
340 
341  storeCache();
342 
343  for (auto map : myInformation) {
344  emit mapAdded(map);
345  }
346 
347  emit finished();
348 
350  qDebug() << "experience repartition:";
351  foreach(QString region, myExperience.keys())
352  {
353  qDebug() << region << myExperience[region];
354  }
355 
356  qDebug() << myToProcess.size() << "maps processed";
357 }
358 
360 {
361  myCancelled = true;
362  myWorker.waitForFinished();
363 }
364 
365 QList<CREMapInformation*> CREMapInformationManager::allMaps()
366 {
367  QMutexLocker lock(&myLock);
368  return myInformation.values();
369 }
370 
372 {
373  QMutexLocker lock(&myLock);
374  return myArchetypeUse.values(arch->name);
375 }
376 
377 QList<CREMapInformation*> CREMapInformationManager::getFaceUse(const Face* face)
378 {
379  QMutexLocker lock(&myLock);
380  return myFaceUse.values(face->name);
381 }
382 
383 QList<CREMapInformation*> CREMapInformationManager::getAnimationUse(const Animations* animation)
384 {
385  QMutexLocker lock(&myLock);
386  return myAnimationUse.values(animation->name);
387 }
388 
390 {
391  QMutexLocker lock(&myLock);
392  return myQuestUse.values(quest->quest_code);
393 }
394 
396 {
397  Q_ASSERT(myInformation.isEmpty());
398 
400  QFile file(settings.mapCacheDirectory() + QDir::separator() + "maps_cache.xml");
401  file.open(QFile::ReadOnly);
402 
403  QXmlStreamReader reader(&file);
404  bool hasMaps = false;
405  CREMapInformation* map = NULL;
406 
407  while (!reader.atEnd())
408  {
409  reader.readNext();
410 
411  if (reader.isStartElement() && reader.name() == "maps")
412  {
413  int version = reader.attributes().value("version").toString().toInt();
414  if (version < 1)
415  return;
416  hasMaps = true;
417  continue;
418  }
419 
420  if (!hasMaps)
421  continue;
422 
423  if (reader.isStartElement() && reader.name() == "map")
424  {
425  map = new CREMapInformation();
426  continue;
427  }
428  if (reader.isStartElement() && reader.name() == "path")
429  {
430  QString path = reader.readElementText();
431  map->setPath(path);
432  Q_ASSERT(!myInformation.contains(path));
434  continue;
435  }
436  if (reader.isStartElement() && reader.name() == "name")
437  {
438  map->setName(reader.readElementText());
439  continue;
440  }
441  if (reader.isStartElement() && reader.name() == "lastModified")
442  {
443  QString date = reader.readElementText();
444  map->setMapTime(QDateTime::fromString(date, Qt::ISODate));
445  continue;
446  }
447  if (reader.isStartElement() && reader.name() == "difficulty")
448  {
449  map->setDifficulty(reader.readElementText().toInt());
450  }
451  if (reader.isStartElement() && reader.name() == "computedDifficulty")
452  {
453  map->setComputedDifficulty(reader.readElementText().toInt());
454  }
455  if (reader.isStartElement() && reader.name() == "experience")
456  {
457  map->setExperience(reader.readElementText().toLongLong());
458  }
459  if (reader.isStartElement() && reader.name() == "region")
460  {
461  map->setRegion(reader.readElementText());
462  }
463  if (reader.isStartElement() && reader.name() == "arch")
464  {
465  QString arch = reader.readElementText();
466  map->addArchetype(arch);
468  continue;
469  }
470  if (reader.isStartElement() && reader.name() == "face")
471  {
472  QString face = reader.readElementText();
473  map->addFace(face);
474  addFaceUse(face, map);
475  continue;
476  }
477  if (reader.isStartElement() && reader.name() == "animation")
478  {
479  QString anim = reader.readElementText();
480  map->addAnimation(anim);
482  continue;
483  }
484  if (reader.isStartElement() && reader.name() == "exitTo")
485  {
486  QString path = reader.readElementText();
487  map->addExitTo(path);
488  continue;
489  }
490  if (reader.isStartElement() && reader.name() == "accessedFrom")
491  {
492  QString path = reader.readElementText();
493  map->addAccessedFrom(path);
494  continue;
495  }
496  if (reader.isStartElement() && reader.name() == "messageFile")
497  {
498  QString file = reader.readElementText();
499  map->addMessage(file);
501  if (message != NULL)
502  message->maps().append(map);
503  continue;
504  }
505  if (reader.isStartElement() && reader.name() == "quest")
506  {
507  QString code = reader.readElementText();
508  map->addQuest(code);
509  addQuestUse(code, map);
510  continue;
511  }
512  if (reader.isStartElement() && reader.name() == "shopItem")
513  {
514  QString item = reader.attributes().value("name").toString();
515  int strength = reader.readElementText().toInt();
516  map->shopItems()[item] = strength;
517  }
518  if (reader.isStartElement() && reader.name() == "shopGreed")
519  {
520  double greed = reader.readElementText().toDouble();
521  map->setShopGreed(greed);
522  }
523  if (reader.isStartElement() && reader.name() == "shopRace")
524  {
525  map->setShopRace(reader.readElementText());
526  }
527  if (reader.isStartElement() && reader.name() == "shopMin")
528  {
529  quint64 min = reader.readElementText().toULongLong();
530  map->setShopMin(min);
531  }
532  if (reader.isStartElement() && reader.name() == "shopMax")
533  {
534  quint64 max = reader.readElementText().toULongLong();
535  map->setShopMax(max);
536  }
537  if (reader.isStartElement() && reader.name() == "script")
538  {
539  int x = reader.attributes().value("x").toString().toInt();
540  int y = reader.attributes().value("x").toString().toInt();
541  QString item = reader.attributes().value("itemName").toString();
542  QString plugin = reader.attributes().value("pluginName").toString();
543  QString event = reader.attributes().value("eventName").toString();
544  QString script = reader.readElementText();
545  emit addHook(script, new HookInformation(map, x, y, item, plugin, event));
546  }
547  if (reader.isStartElement() && reader.name() == "random_map")
548  {
549  int x = reader.attributes().value("x").toString().toInt();
550  int y = reader.attributes().value("y").toString().toInt();
551  QString params = reader.attributes().value("params").toString();
552  map->addRandomMap(new RandomMap(map, x, y, params.toLatin1().constData()));
553  }
554  if (reader.isStartElement() && reader.name() == "background_music")
555  {
556  map->setBackgroundMusic(reader.readElementText());
557  continue;
558  }
559  if (reader.isStartElement() && reader.name() == "reset_group")
560  {
561  map->setResetGroup(reader.readElementText());
562  continue;
563  }
564 
565  if (reader.isEndElement() && reader.name() == "map")
566  {
567  map = NULL;
568  continue;
569  }
570  }
571 
572 // qDebug() << "loaded maps from cache:" << myInformation.size();
573 }
574 
576 {
578  QFile file(settings.mapCacheDirectory() + QDir::separator() + "maps_cache.xml");
579  file.open(QFile::WriteOnly | QFile::Truncate);
580 
581  QXmlStreamWriter writer(&file);
582 
583  writer.setAutoFormatting(true);
584  writer.writeStartDocument();
585 
586  writer.writeStartElement("maps");
587  writer.writeAttribute("version", "1");
588 
589  QList<CREMapInformation*> maps = myInformation.values();
590  foreach(CREMapInformation* map, maps)
591  {
592  writer.writeStartElement("map");
593  writer.writeTextElement("path", map->path());
594  writer.writeTextElement("name", map->name());
595  writer.writeTextElement("lastModified", map->mapTime().toString(Qt::ISODate));
596  writer.writeTextElement("difficulty", QString::number(map->difficulty()));
597  writer.writeTextElement("computedDifficulty", QString::number(map->computedDifficulty()));
598  writer.writeTextElement("experience", QString::number(map->experience()));
599  writer.writeTextElement("region", map->region());
600  foreach(QString arch, map->archetypes())
601  {
602  writer.writeTextElement("arch", arch);
603  }
604  foreach(QString face, map->faces())
605  {
606  writer.writeTextElement("face", face);
607  }
608  foreach(QString anim, map->animations())
609  {
610  writer.writeTextElement("animation", anim);
611  }
612  foreach(QString path, map->exitsTo())
613  {
614  writer.writeTextElement("exitTo", path);
615  }
616  foreach(QString path, map->accessedFrom())
617  {
618  writer.writeTextElement("accessedFrom", path);
619  }
620  foreach(QString file, map->messages())
621  {
622  writer.writeTextElement("messageFile", file);
623  }
624  foreach(QString code, map->quests())
625  {
626  writer.writeTextElement("quest", code);
627  }
628  foreach(QString item, map->shopItems().keys())
629  {
630  writer.writeStartElement("shopItem");
631  writer.writeAttribute("name", item);
632  writer.writeCharacters(QString::number(map->shopItems()[item]));
633  writer.writeEndElement();
634  }
635  if (map->shopGreed() != 0)
636  {
637  writer.writeTextElement("shopGreed", QString::number(map->shopGreed()));
638  }
639  if (!map->shopRace().isEmpty())
640  {
641  writer.writeTextElement("shopRace", map->shopRace());
642  }
643  if (map->shopMin() != 0)
644  {
645  writer.writeTextElement("shopMin", QString::number(map->shopMin()));
646  }
647  if (map->shopMax() != 0)
648  {
649  writer.writeTextElement("shopMax", QString::number(map->shopMax()));
650  }
651 
652  QList<ScriptFile*> scripts = myScriptManager->scriptsForMap(map);
653  foreach(ScriptFile* script, scripts)
654  {
655  foreach(const HookInformation* hook, script->hooks())
656  {
657  if (hook->map() == map)
658  {
659  writer.writeStartElement("script");
660  writer.writeAttribute("x", QString::number(hook->x()));
661  writer.writeAttribute("y", QString::number(hook->y()));
662  writer.writeAttribute("itemName", hook->itemName());
663  writer.writeAttribute("pluginName", hook->pluginName());
664  writer.writeAttribute("eventName", hook->eventName());
665  writer.writeCharacters(script->path());
666  writer.writeEndElement();
667  }
668  }
669  }
670 
671  foreach(RandomMap* random, map->randomMaps())
672  {
673  writer.writeStartElement("random_map");
674  writer.writeAttribute("x", QString::number(random->x()));
675  writer.writeAttribute("y", QString::number(random->y()));
677  char* params = stringbuffer_finish(sb);
678  writer.writeAttribute("params", params);
679  free(params);
680  writer.writeEndElement();
681  }
682 
683  if (!map->backgroundMusic().isEmpty())
684  {
685  writer.writeTextElement("background_music", map->backgroundMusic());
686  }
687  if (!map->resetGroup().isEmpty())
688  {
689  writer.writeTextElement("reset_group", map->resetGroup());
690  }
691 
692  writer.writeEndElement();
693  }
694 
695  writer.writeEndElement();
696 
697  writer.writeEndDocument();
698 }
699 
701 {
702  if (!myInformation.contains(path))
703  {
704  CREMapInformation* information = new CREMapInformation(path);
705  myInformation[path] = information;
706  }
707  return myInformation[path];
708 }
709 
711 {
712  QMutexLocker lock(&myLock);
713  if (!myArchetypeUse.values(name).contains(map))
714  myArchetypeUse.insert(name, map);
715 }
716 
718 {
719  QMutexLocker lock(&myLock);
720  if (!myFaceUse.values(name).contains(map))
721  myFaceUse.insert(name, map);
722 }
723 
725 {
726  QMutexLocker lock(&myLock);
727  if (!myAnimationUse.values(name).contains(map))
728  myAnimationUse.insert(name, map);
729 }
730 
732  QMutexLocker lock(&myLock);
733  if (!myQuestUse.values(name).contains(map))
734  myQuestUse.insert(name, map);
735 }
736 
737 
739 {
740  const QString slaying = "/python/dialog/npc_dialog.py";
741  const QString python = "Python";
742 
743  if (item->type != EVENT_CONNECTOR)
744  return;
745 
746  if (item->subtype > 0 && item->subtype < NR_EVENTS)
747  {
748  emit addHook(item->slaying, new HookInformation(map, env->x, env->y, env->name, item->title, eventNames[item->subtype]));
749  }
750 
751  if (python != item->title)
752  return;
753 
754  if (item->subtype == EVENT_SAY && slaying == item->slaying)
755  {
756  //qDebug() << "message event in" << map->path() << item->name;
757  QString path = item->name;
758  if (!path.startsWith('/'))
759  path = '/' + path;
760 
762  if (message != NULL)
763  {
764  if (!message->maps().contains(map))
765  message->maps().append(map);
766  map->addMessage(path);
767  } else
768  qDebug() << "missing message file" << path << "in" << map->path();
769  }
770 
771  if (QString(item->slaying).startsWith("/python/quests/"))
772  {
773  //qDebug() << "quest-related Python stuff";
774  QStringList split = QString(item->name).split(' ', QString::SkipEmptyParts);
775  if (split.length() > 1)
776  {
777  //qDebug() << "definitely quest" << split[0];
778  map->addQuest(split[0]);
779  addQuestUse(split[0], map);
780  }
781  }
782 }
783 
784 QList<CREMapInformation*> CREMapInformationManager::getMapsForRegion(const QString& region)
785 {
786  QList<CREMapInformation*> list;
787 
788  foreach(CREMapInformation* map, myInformation.values())
789  {
790  if (map->region() == region)
791  list.append(map);
792  }
793 
794  return list;
795 }
796 
798 {
800  Q_ASSERT(myWorker.isFinished());
801  QFile::remove(settings.mapCacheDirectory() + QDir::separator() + "maps_cache.xml");
802 }
803 
805 {
806  QList<RandomMap*> maps;
807  foreach(CREMapInformation* map, myInformation.values())
808  {
809  maps.append(map->randomMaps());
810  }
811  return maps;
812 }
813 
815 {
816  char full[MAX_BUF];
817  create_pathname(from.toLatin1(), full, sizeof(full));
818 
819  QDir dir(full);
820  QFileInfoList items = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot, QDir::DirsFirst);
821  foreach(QFileInfo info, items)
822  {
823  QString relative(from + QDir::separator() + info.baseName());
824  if (info.isDir())
825  {
826  recurseStyleDirectory(relative);
827  }
828  else
829  {
830  myToProcess.append(relative);
831  }
832  }
833 }
add_map
static void add_map(struct_map_info *info, struct_map_list *list)
Definition: mapper.cpp:1169
MessageFile.h
HookInformation::eventName
QString eventName() const
Definition: ScriptFile.cpp:106
CREMapInformationManager::allMaps
QList< CREMapInformation * > allMaps()
Definition: CREMapInformationManager.cpp:365
PLAYER
@ PLAYER
Definition: object.h:112
global.h
RandomMap::parameters
const RMParms * parameters() const
Definition: RandomMap.cpp:39
settings
struct Settings settings
Definition: init.cpp:139
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
CREMapInformationManager::addFaceUse
void addFaceUse(const QString &name, CREMapInformation *map)
Definition: CREMapInformationManager.cpp:717
version
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 version
Definition: arch-handbook.txt:212
CREMapInformationManager::myExperience
QHash< QString, qint64 > myExperience
Definition: CREMapInformationManager.h:67
MAP_NO_DIFFICULTY
#define MAP_NO_DIFFICULTY
Definition: map.h:94
EVENT_CONNECTOR
@ EVENT_CONNECTOR
Definition: object.h:232
HookInformation::pluginName
QString pluginName() const
Definition: ScriptFile.cpp:101
NR_EVENTS
#define NR_EVENTS
Definition: events.h:59
python_init.scripts
scripts
Definition: python_init.py:11
CREMapInformationManager::~CREMapInformationManager
virtual ~CREMapInformationManager()
Definition: CREMapInformationManager.cpp:75
diamondslots.x
x
Definition: diamondslots.py:15
CREMapInformationManager::addArchetypeUse
void addArchetypeUse(const QString &name, CREMapInformation *map)
Definition: CREMapInformationManager.cpp:710
ready_map_name
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.cpp:1759
first_map_path
char first_map_path[MAX_BUF]
Definition: init.cpp:120
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
CREMapInformation::mapTime
const QDateTime & mapTime() const
Definition: CREMapInformation.cpp:125
CREMapInformationManager::storeCache
void storeCache()
Definition: CREMapInformationManager.cpp:575
CREMapInformation::setShopRace
void setShopRace(const QString &race)
Definition: CREMapInformation.cpp:243
RandomMap::y
int y() const
Definition: RandomMap.cpp:34
send.date
date
Definition: send.py:29
CREMapInformationManager::myScriptManager
ScriptFileManager * myScriptManager
Definition: CREMapInformationManager.h:56
first_map_ext_path
char first_map_ext_path[MAX_BUF]
Definition: init.cpp:121
CREMapInformation::addRandomMap
void addRandomMap(RandomMap *map)
Definition: CREMapInformation.cpp:273
HookInformation::y
int y() const
Definition: ScriptFile.cpp:91
CREMapInformationManager::start
void start()
Definition: CREMapInformationManager.cpp:85
CRESettings.h
get_map_info
static struct_map_info * get_map_info(const char *path)
Definition: mapper.cpp:1262
CREMapInformation::difficulty
int difficulty
Definition: CREMapInformation.h:33
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:439
CREMapInformationManager::myInformation
QHash< QString, CREMapInformation * > myInformation
Definition: CREMapInformationManager.h:57
guildoracle.list
list
Definition: guildoracle.py:87
CREMapInformationManager::getMapsForRegion
QList< CREMapInformation * > getMapsForRegion(const QString &region)
Definition: CREMapInformationManager.cpp:784
CREMapInformation::setDifficulty
void setDifficulty(int difficulty)
Definition: CREMapInformation.cpp:162
RandomMap.h
commongive.inv
inv
Definition: commongive.py:29
CREMapInformation::shopItems
QHash< QString, int > & shopItems()
Definition: CREMapInformation.cpp:218
mad_mage_user.file
file
Definition: mad_mage_user.py:15
HookInformation::x
int x() const
Definition: ScriptFile.cpp:86
CREMapInformationManager::getArchetypeUse
QList< CREMapInformation * > getArchetypeUse(const archetype *arch)
Definition: CREMapInformationManager.cpp:371
CREMapInformation::setResetGroup
void setResetGroup(const QString &resetGroup)
Definition: CREMapInformation.cpp:89
ScriptFileManager.h
EVENT_SAY
#define EVENT_SAY
Definition: events.h:29
ScriptFileManager
Definition: ScriptFileManager.h:26
CREMapInformation::exitsTo
QStringList exitsTo() const
Definition: CREMapInformation.cpp:135
CREMapInformationManager::myArchetypeUse
QMultiHash< QString, CREMapInformation * > myArchetypeUse
Definition: CREMapInformationManager.h:58
CREMapInformationManager::browseFinished
bool browseFinished() const
Definition: CREMapInformationManager.cpp:80
AssetsManager.h
HookInformation
Definition: ScriptFile.h:25
ScriptFile.h
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
CREMapInformationManager::process
void process(const QString &path)
Definition: CREMapInformationManager.cpp:192
CREMapInformationManager::myLock
QMutex myLock
Definition: CREMapInformationManager.h:66
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
CREMapInformation::setComputedDifficulty
void setComputedDifficulty(int computed)
Definition: CREMapInformation.cpp:172
MAP_STYLE
#define MAP_STYLE
Definition: map.h:95
CREMapInformationManager::myCurrentMap
int myCurrentMap
Definition: CREMapInformationManager.h:63
Animations::name
sstring name
Definition: face.h:26
CREMapInformation::setShopGreed
void setShopGreed(double greed)
Definition: CREMapInformation.cpp:233
m
static event_registration m
Definition: citylife.cpp:425
quest
Definition: quest.py:1
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:127
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
CREMapInformation::setShopMax
void setShopMax(quint64 max)
Definition: CREMapInformation.cpp:263
disinfect.map
map
Definition: disinfect.py:4
CREMapInformationManager::myQuestUse
QMultiHash< QString, CREMapInformation * > myQuestUse
Definition: CREMapInformationManager.h:61
RandomMap
Definition: RandomMap.h:24
ScriptFileManager::scriptsForMap
QList< ScriptFile * > scriptsForMap(CREMapInformation *map)
Definition: ScriptFileManager.cpp:26
CREMapInformation::setRegion
void setRegion(const QString &region)
Definition: CREMapInformation.cpp:191
ScriptFile
Definition: ScriptFile.h:48
path_combine_and_normalize
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Definition: path.cpp:172
CREMapInformationManager::clearCache
void clearCache()
Definition: CREMapInformationManager.cpp:797
CREMapInformationManager::CREMapInformationManager
CREMapInformationManager(QObject *parent, MessageManager *messageManager, ScriptFileManager *scriptManager)
Definition: CREMapInformationManager.cpp:66
Face::name
sstring name
Definition: face.h:19
CREMapInformation::experience
qint64 experience
Definition: CREMapInformation.h:35
CREMapInformationManager::getOrCreateMapInformation
CREMapInformation * getOrCreateMapInformation(const QString &path)
Definition: CREMapInformationManager.cpp:700
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
script
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 script
Definition: README.txt:19
CREMapInformationManager::randomMaps
QList< RandomMap * > randomMaps()
Definition: CREMapInformationManager.cpp:804
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
MessageManager::findMessage
MessageFile * findMessage(const QString &path)
Definition: MessageManager.cpp:61
CREMapInformation::setShopMin
void setShopMin(quint64 min)
Definition: CREMapInformation.cpp:253
python
Definition: python.py:1
CREMapInformationManager::myToProcess
QStringList myToProcess
Definition: CREMapInformationManager.h:62
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
AssetsManager::archetypes
Archetypes * archetypes()
Definition: AssetsManager.h:44
CREMapInformationManager::myMessageManager
MessageManager * myMessageManager
Definition: CREMapInformationManager.h:55
say.max
dictionary max
Definition: say.py:148
CREMapInformation::addAccessedFrom
void addAccessedFrom(const QString &path)
Definition: CREMapInformation.cpp:151
archetype
Definition: object.h:474
doors_galore.process
def process()
Definition: doors_galore.py:72
animate.anim
string anim
Definition: animate.py:20
delete_map
void delete_map(mapstruct *m)
Definition: map.cpp:1696
CREMapInformationManager::loadCache
void loadCache()
Definition: CREMapInformationManager.cpp:395
CRESettings
Definition: CRESettings.h:21
CREMapInformationManager::checkEvent
void checkEvent(const object *item, CREMapInformation *map, const object *env)
Definition: CREMapInformationManager.cpp:738
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:74
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2170
MAX_BUF
#define MAX_BUF
Definition: define.h:35
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
CREMapInformation::addAnimation
void addAnimation(const QString &anim)
Definition: CREMapInformation.cpp:120
CREMapInformationManager::myCancelled
bool myCancelled
Definition: CREMapInformationManager.h:65
CREMapInformation::addExitTo
void addExitTo(const QString &path)
Definition: CREMapInformation.cpp:140
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
EXIT
@ EXIT
Definition: object.h:186
HookInformation::map
const CREMapInformation * map() const
Definition: ScriptFile.cpp:81
region
Definition: map.h:273
CREMapInformation
Definition: CREMapInformation.h:27
HookInformation::itemName
QString itemName() const
Definition: ScriptFile.cpp:96
add_region_link
static void add_region_link(mapstruct *source, mapstruct *dest)
Definition: mapper.cpp:1358
CREMapInformationManager::myWorker
QFuture< void > myWorker
Definition: CREMapInformationManager.h:64
CREMapInformation::addFace
void addFace(const QString &face)
Definition: CREMapInformation.cpp:110
AssetsCollection::each
void each(std::function< void(T *)> op)
Definition: AssetsCollection.h:158
CREMapInformation::setName
void setName(const QString &name)
Definition: CREMapInformation.cpp:69
CREMapInformationManager.h
item
Definition: item.py:1
eventNames
const char * eventNames[NR_EVENTS]
Definition: CREMapInformationManager.cpp:27
PLAYER_CHANGER
@ PLAYER_CHANGER
Definition: object.h:167
mapstruct
Definition: map.h:314
CREMapInformationManager::checkItem
void checkItem(const object *item, CREMapInformation *information, const object *env)
Definition: CREMapInformationManager.cpp:93
create_pathname
char * create_pathname(const char *name, char *buf, size_t size)
Definition: map.cpp:103
CREMapInformation::addArchetype
void addArchetype(const QString &archetype)
Definition: CREMapInformation.cpp:99
CREMapInformationManager::getMapsForQuest
QList< CREMapInformation * > getMapsForQuest(const quest_definition *quest)
Definition: CREMapInformationManager.cpp:389
quest_definition
Definition: quest.h:37
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
MessageFile
Definition: MessageFile.h:68
mapstruct::in_memory
uint32_t in_memory
Definition: map.h:335
roll-o-matic.params
params
Definition: roll-o-matic.py:193
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)
diamondslots.y
y
Definition: diamondslots.py:16
assets.h
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:76
do_regions_link
static bool do_regions_link
Definition: mapper.cpp:381
CREMapInformation::setExperience
void setExperience(qint64 experience)
Definition: CREMapInformation.cpp:182
Face
Definition: face.h:14
CREMapInformationManager::cancel
void cancel()
Definition: CREMapInformationManager.cpp:359
CREMapInformationManager::browsingMap
void browsingMap(const QString &path)
MessageManager
Definition: MessageManager.h:25
animate.event
event
DIALOGCHECK MINARGS 1 MAXARGS 2
Definition: animate.py:17
CREMapInformationManager::browseMaps
void browseMaps()
Definition: CREMapInformationManager.cpp:301
CREMapInformationManager::myFaceUse
QMultiHash< QString, CREMapInformation * > myFaceUse
Definition: CREMapInformationManager.h:59
code
Crossfire Architecture the general intention is to enhance the enjoyability and playability of CF In this code
Definition: arch-handbook.txt:14
calculate_difficulty
int calculate_difficulty(mapstruct *m)
Definition: map.cpp:1885
CREMapInformationManager::myAnimationUse
QMultiHash< QString, CREMapInformation * > myAnimationUse
Definition: CREMapInformationManager.h:60
Animations
Definition: face.h:25
split
static std::vector< std::string > split(const std::string &field, const std::string &by)
Definition: mapper.cpp:2608
mapstruct::reset_time
uint32_t reset_time
Definition: map.h:321
say.item
dictionary item
Definition: say.py:149
connect
Definition: connect.py:1
CREMapInformation::setMapTime
void setMapTime(const QDateTime &date)
Definition: CREMapInformation.cpp:130
CREMapInformationManager::getFaceUse
QList< CREMapInformation * > getFaceUse(const Face *face)
Definition: CREMapInformationManager.cpp:377
StringBuffer
Definition: stringbuffer.cpp:25
plugin
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 plugin
Definition: plugins.txt:15
RandomMap::x
int x() const
Definition: RandomMap.cpp:29
CREMapInformationManager::getAnimationUse
QList< CREMapInformation * > getAnimationUse(const Animations *anim)
Definition: CREMapInformationManager.cpp:383
mapfile_load
mapstruct * mapfile_load(const char *map, int flags)
Definition: map.cpp:1216
CREMapInformationManager::recurseStyleDirectory
void recurseStyleDirectory(const QString &from)
Definition: CREMapInformationManager.cpp:814
TELEPORTER
@ TELEPORTER
Definition: object.h:146
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
CREMapInformation::setBackgroundMusic
void setBackgroundMusic(const QString &music)
Definition: CREMapInformation.cpp:79
write_map_parameters_to_string
StringBuffer * write_map_parameters_to_string(const RMParms *RP)
Definition: random_map.cpp:749
CREMapInformationManager::addHook
void addHook(const QString &file, HookInformation *hook)
CREMapInformationManager::addAnimationUse
void addAnimationUse(const QString &name, CREMapInformation *map)
Definition: CREMapInformationManager.cpp:724
CREMapInformationManager::addQuestUse
void addQuestUse(const QString &name, CREMapInformation *map)
Definition: CREMapInformationManager.cpp:731
MessageManager.h
ScriptFileManager::removeMap
void removeMap(CREMapInformation *map)
Definition: ScriptFileManager.cpp:50