Crossfire Server, Trunk
QuestManager.cpp
Go to the documentation of this file.
1 #include "QuestManager.h"
2 #include "CREMainWindow.h"
3 #include "Quest.h"
4 
5 extern "C" {
6 #include <global.h>
7 }
8 
9 #include "assets.h"
10 #include "AssetsManager.h"
11 
13 {
14 }
15 
17 {
18  qDeleteAll(myQuests);
19  qDeleteAll(myFiles);
20 }
21 
23 {
24  loadQuestFile("world.quests");
25  foreach(Quest* quest, myQuests)
26  quest->setModified(false);
27  qDebug() << "found quests:" << myQuests.size();
28 }
29 
31 {
32  int i, in = 0; /* 0: quest file, 1: one quest, 2: quest description, 3: quest step, 4: step description, 5: setwhen */
33  Quest *quest = NULL;
34  char includefile[MAX_BUF];
35  QuestStep *step = NULL;
36  char final[MAX_BUF], read[MAX_BUF];
37  FILE *file;
39  QString comment;
40 
41  snprintf(final, sizeof(final), "%s/%s/%s", settings.datadir, settings.mapdir, qPrintable(filename));
42  file = fopen(final, "r");
43  if (!file) {
44  LOG(llevError, "Can't open %s for reading quests", qPrintable(filename));
45  return;
46  }
47 
48  while (fgets(read, sizeof(read), file) != NULL) {
49  if (in == 6) {
50  if (strcmp(read, "end_comment\n") == 0) {
51  quest->setComment(comment.trimmed());
52  in = 1;
53  continue;
54  }
55  comment.append(read);
56  continue;
57  }
58  if (in == 5) {
59  if (strcmp(read, "end_setwhen\n") == 0) {
60  in = 3;
61  continue;
62  }
63 
64  read[strlen(read) - 1] = '\0';
65  step->setWhen().append(read);
66 
67  continue;
68  }
69  if (in == 4) {
70  if (strcmp(read, "end_description\n") == 0) {
71  char *message;
72 
73  in = 3;
74 
76  buf = NULL;
77 
78  step->setDescription(message);
79  free(message);
80 
81  continue;
82  }
83 
85  continue;
86  }
87 
88  if (in == 3) {
89  if (strcmp(read, "end_step\n") == 0) {
90  step = NULL;
91  in = 1;
92  continue;
93  }
94  if (strcmp(read, "finishes_quest\n") == 0) {
95  step->setCompletion(true);
96  continue;
97  }
98  if (strcmp(read, "description\n") == 0) {
100  in = 4;
101  continue;
102  }
103  if (strcmp(read, "setwhen\n") == 0) {
104  in = 5;
105  continue;
106  }
107  LOG(llevError, "quests: invalid line %s in definition of quest %s in file %s!\n",
108  read, qPrintable(quest->code()), qPrintable(filename));
109  continue;
110  }
111 
112  if (in == 2) {
113  if (strcmp(read, "end_description\n") == 0) {
114  char *message;
115 
116  in = 1;
117 
119  buf = NULL;
120 
121  quest->setDescription(message);
122  free(message);
123 
124  continue;
125  }
127  continue;
128  }
129 
130  if (in == 1) {
131  if (strcmp(read, "end_quest\n") == 0) {
132  quest = NULL;
133  in = 0;
134  continue;
135  }
136 
137  if (strcmp(read, "description\n") == 0) {
138  in = 2;
139  buf = stringbuffer_new();
140  continue;
141  }
142 
143  if (strncmp(read, "title ", 6) == 0) {
144  read[strlen(read) - 1] = '\0';
145  quest->setTitle(read + 6);
146  continue;
147  }
148 
149  if (sscanf(read, "step %d\n", &i)) {
150  step = new QuestStep();
151  step->setStep(i);
152  quest->steps().append(step);
153  in = 3;
154  continue;
155  }
156 
157  if (sscanf(read, "restart %d\n", &i)) {
158  quest->setRestart(i != 0);
159  continue;
160  }
161 
162  if (strncmp(read, "face ", 5) == 0) {
163  read[strlen(read) - 1] = '\0';
164  quest->setFace(getManager()->faces()->find(read + 5));
165  continue;
166  }
167 
168  if (strcmp(read, "comment\n") == 0) {
169  in = 6;
170  comment = "";
171  continue;
172  }
173 
174  if (sscanf(read, "is_system %d\n", &i)) {
175  quest->setSystem(i ? true : false);
176  continue;
177  }
178  }
179 
180  if (read[0] == '#')
181  continue;
182 
183  if (strncmp(read, "quest ", 6) == 0) {
184  quest = new Quest();
186  read[strlen(read) - 1] = '\0';
187  quest->setCode(read + 6);
188  if (getByCode(quest->code()) != NULL) {
189  LOG(llevError, "Quest %s is listed in file %s, but this quest has already been defined\n", read + 6, qPrintable(filename));
190  }
191  myQuests.append(quest);
192  in = 1;
193  continue;
194  }
195  if (sscanf(read, "include %s\n", includefile)) {
196  char inc_path[HUGE_BUF], p[HUGE_BUF];
197  snprintf(p, sizeof(p), qPrintable(filename));
198  path_combine_and_normalize(p, includefile, inc_path, sizeof(inc_path));
199  loadQuestFile(inc_path);
200  myIncludes[filename].append(includefile);
201  continue;
202  }
203  if (strncmp(read, "parent ", 7) == 0) {
204  read[strlen(read) - 1] = '\0';
205  Quest* parent = findByCode(read + 7);
206  if (parent == NULL)
207  LOG(llevError, "Quest %s was defined before its parent %s", qPrintable(quest->code()), read + 7);
208  else
209  quest->setParent(parent);
210  continue;
211  }
212 
213  if (strcmp(read, "\n") == 0)
214  continue;
215 
216  LOG(llevError, "quest: invalid file format for %s, I don't know what to do with the line %s\n", final, read);
217  }
218 
219  fclose(file);
220 }
221 
222 Quest* QuestManager::getByCode(const QString& code)
223 {
224  foreach(Quest* quest, myQuests)
225  {
226  if (quest->code() == code)
227  return quest;
228  }
229  return NULL;
230 }
231 
232 QList<const Quest*> QuestManager::quests() const
233 {
234  QList<const Quest*> quests;
235  foreach(const Quest* quest, myQuests)
236  quests.append(quest);
237  return quests;
238 }
239 
240 QList<Quest*>& QuestManager::quests()
241 {
242  return myQuests;
243 }
244 
246 {
247  if (!myFiles.contains(filename))
248  myFiles[filename] = new QList<Quest*>();
249  myFiles[filename]->append(quest);
250 }
251 
253 {
254  foreach(const QString& filename, myFiles.keys())
256 }
257 
259 {
260  QList<Quest*>* list = myFiles[filename];
261  bool modified = false;
262  foreach(Quest* quest, *list)
263  {
264  if (quest->isModified())
265  {
266  modified = true;
267  break;
268  }
269  }
270 
271  if (!modified)
272  return;
273 
274  QString path = QString("%1/%2/%3").arg(settings.datadir, settings.mapdir, filename);
275  QFile file(path);
276  if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
277  {
278  qDebug() << "save error quest file" << filename << path;
280  return;
281  }
282 
283  qDebug() << "saving quests" << filename;
284 
285  QTextStream stream(&file);
286 
287  QStringList includes = myIncludes[filename];
288  if (includes.size() > 0)
289  {
290  foreach(QString include, includes)
291  stream << "include " << include << "\n";
292  stream << "\n\n";
293  }
294 
295  foreach(Quest* quest, *list)
296  {
297  stream << "quest " << quest->code() << "\n";
298  if (!quest->title().isEmpty())
299  stream << "title " << quest->title() << "\n";
300  if (quest->face() != nullptr)
301  stream << "face " << quest->face()->name << "\n";
302  if (!quest->description().isEmpty())
303  {
304  stream << "description\n" << quest->description();
305  if (!quest->description().endsWith("\n"))
306  stream << "\n";
307  stream << "end_description\n";
308  }
309  if (quest->parent() != NULL)
310  stream << "parent " << quest->parent()->code() << "\n";
311  if (quest->canRestart())
312  stream << "restart 1\n";
313  if (quest->isSystem())
314  stream << "is_system 1\n";
315 
316  if (!quest->comment().isEmpty())
317  {
318  QString c(quest->comment());
319  c.replace("end_comment", "end comment");
320  stream << "comment\n";
321  stream << c;
322  if (!c.endsWith("\n"))
323  stream << "\n";
324  stream << "end_comment\n";
325  }
326 
327  foreach(QuestStep* step, quest->steps())
328  {
329  stream << "step " << step->step() << "\n";
330  if (step->isCompletion())
331  stream << "finishes_quest\n";
332  if (!step->description().isEmpty())
333  {
334  stream << "description\n" << step->description();
335  if (!step->description().endsWith("\n"))
336  stream << "\n";
337  stream << "end_description\n";
338  }
339  if (step->setWhen().size() > 0)
340  {
341  stream << "setwhen\n";
342  foreach(QString when, step->setWhen())
343  {
344  stream << when << "\n";
345  }
346  stream << "end_setwhen\n";
347  }
348  stream << "end_step\n";
349 
350  }
351 
352  stream << "end_quest\n\n";
353  }
354 }
355 
356 QStringList QuestManager::getFiles() const
357 {
358  return myFiles.keys();
359 }
360 
362 {
363  foreach(QString file, myFiles.keys())
364  {
365  if (myFiles[file]->contains(quest))
366  return file;
367  }
368  return QString();
369 }
370 
372 {
373  if (file.isEmpty())
374  return;
375 
376  Q_ASSERT(getQuestFile(quest).isEmpty());
377  addQuest(file, quest);
378 }
379 
380 Quest* QuestManager::findByCode(const QString& code)
381 {
382  foreach(Quest* quest, myQuests)
383  {
384  if (quest->code() == code)
385  return quest;
386  }
387  return NULL;
388 }
Settings::mapdir
const char * mapdir
Definition: global.h:246
global.h
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
llevError
@ llevError
Definition: logger.h:11
AssetsManager.h
QuestManager::addQuest
void addQuest(const QString &filename, Quest *quest)
Definition: QuestManager.cpp:245
c
static event_registration c
Definition: citylife.cpp:410
Settings::datadir
const char * datadir
Definition: global.h:243
guildoracle.list
list
Definition: guildoracle.py:87
python_event.path
path
Definition: python_event.py:11
mad_mage_user.file
file
Definition: mad_mage_user.py:15
QuestStep::description
const QString & description() const
Definition: Quest.cpp:19
path_combine_and_normalize
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Definition: path.c:172
QuestStep::setCompletion
void setCompletion(bool completion)
Definition: Quest.cpp:34
npc_dialog.filename
filename
Definition: npc_dialog.py:99
QuestManager.h
getManager
AssetsManager * getManager()
Definition: assets.cpp:317
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
QuestManager::myIncludes
QHash< QString, QStringList > myIncludes
Definition: QuestManager.h:27
QuestStep::setStep
void setStep(int step)
Definition: Quest.cpp:14
settings
struct Settings settings
Definition: init.c:39
quest
Definition: quest.py:1
QuestStep::setWhen
const QStringList & setWhen() const
Definition: Quest.cpp:39
QuestStep::step
int step() const
Definition: Quest.cpp:9
QuestManager::loadQuests
void loadQuests()
Definition: QuestManager.cpp:22
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:95
QuestManager::saveQuests
void saveQuests()
Definition: QuestManager.cpp:252
QuestManager::~QuestManager
virtual ~QuestManager()
Definition: QuestManager.cpp:16
QuestStep::isCompletion
bool isCompletion() const
Definition: Quest.cpp:29
QuestManager::loadQuestFile
void loadQuestFile(const QString &filename)
Definition: QuestManager.cpp:30
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
MAX_BUF
#define MAX_BUF
Definition: define.h:35
Quest
Definition: Quest.h:34
QuestManager::QuestManager
QuestManager()
Definition: QuestManager.cpp:12
QuestManager::getByCode
Quest * getByCode(const QString &code)
Definition: QuestManager.cpp:222
StringBuffer
Definition: stringbuffer.c:25
diamondslots.message
string message
Definition: diamondslots.py:57
QuestManager::quests
QList< const Quest * > quests() const
Definition: QuestManager.cpp:232
QuestManager::setQuestFile
void setQuestFile(Quest *quest, const QString &file)
Definition: QuestManager.cpp:371
Quest.h
QuestStep
Definition: Quest.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
assets.h
buf
StringBuffer * buf
Definition: readable.c:1606
dragon_attune.faces
dictionary faces
Definition: dragon_attune.py:31
QuestStep::setDescription
void setDescription(const QString &description)
Definition: Quest.cpp:24
QuestManager::myFiles
QHash< QString, QList< Quest * > * > myFiles
Definition: QuestManager.h:26
CREMainWindow.h
QuestManager::getQuestFile
QString getQuestFile(Quest *quest) const
Definition: QuestManager.cpp:361
QuestManager::saveQuestFile
void saveQuestFile(const QString &filename)
Definition: QuestManager.cpp:258
QuestManager::myQuests
QList< Quest * > myQuests
Definition: QuestManager.h:25
QuestManager::getFiles
QStringList getFiles() const
Definition: QuestManager.cpp:356
QuestManager::findByCode
Quest * findByCode(const QString &code)
Definition: QuestManager.cpp:380