Crossfire Server, Trunk  R20513
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 
10 {
11 }
12 
14 {
15  qDeleteAll(myQuests);
16  qDeleteAll(myFiles);
17 }
18 
20 {
21  loadQuestFile("world.quests");
22  foreach(Quest* quest, myQuests)
23  quest->setModified(false);
24  qDebug() << "found quests:" << myQuests.size();
25 }
26 
27 void QuestManager::loadQuestFile(const QString& filename)
28 {
29  int i, in = 0; /* 0: quest file, 1: one quest, 2: quest description, 3: quest step, 4: step description, 5: setwhen */
30  Quest *quest = NULL;
31  char includefile[MAX_BUF];
32  QuestStep *step = NULL;
33  char final[MAX_BUF], read[MAX_BUF];
34  FILE *file;
35  StringBuffer *buf;
36 
37  snprintf(final, sizeof(final), "%s/%s/%s", settings.datadir, settings.mapdir, qPrintable(filename));
38  file = fopen(final, "r");
39  if (!file) {
40  LOG(llevError, "Can't open %s for reading quests", qPrintable(filename));
41  return;
42  }
43 
44  while (fgets(read, sizeof(read), file) != NULL) {
45  if (in == 5) {
46  if (strcmp(read, "end_setwhen\n") == 0) {
47  in = 3;
48  continue;
49  }
50 
51  read[strlen(read) - 1] = '\0';
52  step->setWhen().append(read);
53 
54  continue;
55  }
56  if (in == 4) {
57  if (strcmp(read, "end_description\n") == 0) {
58  char *message;
59 
60  in = 3;
61 
62  message = stringbuffer_finish(buf);
63  buf = NULL;
64 
65  step->setDescription(message);
66  free(message);
67 
68  continue;
69  }
70 
71  stringbuffer_append_string(buf, read);
72  continue;
73  }
74 
75  if (in == 3) {
76  if (strcmp(read, "end_step\n") == 0) {
77  step = NULL;
78  in = 1;
79  continue;
80  }
81  if (strcmp(read, "finishes_quest\n") == 0) {
82  step->setCompletion(true);
83  continue;
84  }
85  if (strcmp(read, "description\n") == 0) {
86  buf = stringbuffer_new();
87  in = 4;
88  continue;
89  }
90  if (strcmp(read, "setwhen\n") == 0) {
91  in = 5;
92  continue;
93  }
94  LOG(llevError, "quests: invalid line %s in definition of quest %s in file %s!\n",
95  read, qPrintable(quest->code()), qPrintable(filename));
96  continue;
97  }
98 
99  if (in == 2) {
100  if (strcmp(read, "end_description\n") == 0) {
101  char *message;
102 
103  in = 1;
104 
105  message = stringbuffer_finish(buf);
106  buf = NULL;
107 
108  quest->setDescription(message);
109  free(message);
110 
111  continue;
112  }
113  stringbuffer_append_string(buf, read);
114  continue;
115  }
116 
117  if (in == 1) {
118  if (strcmp(read, "end_quest\n") == 0) {
119  quest = NULL;
120  in = 0;
121  continue;
122  }
123 
124  if (strcmp(read, "description\n") == 0) {
125  in = 2;
126  buf = stringbuffer_new();
127  continue;
128  }
129 
130  if (strncmp(read, "title ", 6) == 0) {
131  read[strlen(read) - 1] = '\0';
132  quest->setTitle(read + 6);
133  continue;
134  }
135 
136  if (sscanf(read, "step %d\n", &i)) {
137  step = new QuestStep();
138  step->setStep(i);
139  quest->steps().append(step);
140  in = 3;
141  continue;
142  }
143 
144  if (sscanf(read, "restart %d\n", &i)) {
145  quest->setRestart(i != 0);
146  continue;
147  }
148 
149  if (strncmp(read, "face ", 5) == 0) {
150  read[strlen(read) - 1] = '\0';
151  quest->setFace(read + 5);
152  continue;
153  }
154  }
155 
156  if (read[0] == '#')
157  continue;
158 
159  if (strncmp(read, "quest ", 6) == 0) {
160  quest = new Quest();
161  addQuest(filename, quest);
162  read[strlen(read) - 1] = '\0';
163  quest->setCode(read + 6);
164  if (getByCode(quest->code()) != NULL) {
165  LOG(llevError, "Quest %s is listed in file %s, but this quest has already been defined\n", read + 6, qPrintable(filename));
166  }
167  myQuests.append(quest);
168  in = 1;
169  continue;
170  }
171  if (sscanf(read, "include %s\n", includefile)) {
172  char inc_path[HUGE_BUF], p[HUGE_BUF];
173  snprintf(p, sizeof(p), qPrintable(filename));
174  path_combine_and_normalize(p, includefile, inc_path, sizeof(inc_path));
175  loadQuestFile(inc_path);
176  myIncludes[filename].append(includefile);
177  continue;
178  }
179  if (strncmp(read, "parent ", 7) == 0) {
180  read[strlen(read) - 1] = '\0';
181  Quest* parent = findByCode(read + 7);
182  if (parent == NULL)
183  LOG(llevError, "Quest %s was defined before its parent %s", qPrintable(quest->code()), read + 7);
184  else
185  quest->setParent(parent);
186  continue;
187  }
188 
189  if (strcmp(read, "\n") == 0)
190  continue;
191 
192  LOG(llevError, "quest: invalid file format for %s, I don't know what to do with the line %s\n", final, read);
193  }
194 }
195 
196 Quest* QuestManager::getByCode(const QString& code)
197 {
198  foreach(Quest* quest, myQuests)
199  {
200  if (quest->code() == code)
201  return quest;
202  }
203  return NULL;
204 }
205 
206 QList<const Quest*> QuestManager::quests() const
207 {
208  QList<const Quest*> quests;
209  foreach(const Quest* quest, myQuests)
210  quests.append(quest);
211  return quests;
212 }
213 
214 QList<Quest*>& QuestManager::quests()
215 {
216  return myQuests;
217 }
218 
219 void QuestManager::addQuest(const QString& filename, Quest* quest)
220 {
221  if (!myFiles.contains(filename))
222  myFiles[filename] = new QList<Quest*>();
223  myFiles[filename]->append(quest);
224 }
225 
227 {
228  foreach(const QString& filename, myFiles.keys())
229  saveQuestFile(filename);
230 }
231 
232 void QuestManager::saveQuestFile(const QString& filename)
233 {
234  QList<Quest*>* list = myFiles[filename];
235  bool modified = false;
236  foreach(Quest* quest, *list)
237  {
238  if (quest->isModified())
239  {
240  modified = true;
241  break;
242  }
243  }
244 
245  if (!modified)
246  return;
247 
248  QString path = QString("%1/%2/%3").arg(settings.datadir, settings.mapdir, filename);
249  QFile file(path);
250  if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
251  {
252  qDebug() << "save error quest file" << filename << path;
254  return;
255  }
256 
257  qDebug() << "saving quests" << filename;
258 
259  QTextStream stream(&file);
260 
261  QStringList includes = myIncludes[filename];
262  if (includes.size() > 0)
263  {
264  foreach(QString include, includes)
265  stream << "include " << include << "\n";
266  stream << "\n\n";
267  }
268 
269  foreach(Quest* quest, *list)
270  {
271  stream << "quest " << quest->code() << "\n";
272  if (!quest->title().isEmpty())
273  stream << "title " << quest->title() << "\n";
274  if (!quest->face().isEmpty())
275  stream << "face " << quest->face() << "\n";
276  if (!quest->description().isEmpty())
277  {
278  stream << "description\n" << quest->description();
279  if (!quest->description().endsWith("\n"))
280  stream << "\n";
281  stream << "end_description\n";
282  }
283  if (quest->parent() != NULL)
284  stream << "parent " << quest->parent()->code() << "\n";
285  if (quest->canRestart())
286  stream << "restart 1\n";
287 
288  foreach(QuestStep* step, quest->steps())
289  {
290  stream << "step " << step->step() << "\n";
291  if (step->isCompletion())
292  stream << "finishes_quest\n";
293  if (!step->description().isEmpty())
294  {
295  stream << "description\n" << step->description();
296  if (!step->description().endsWith("\n"))
297  stream << "\n";
298  stream << "end_description\n";
299  }
300  if (step->setWhen().size() > 0)
301  {
302  stream << "setwhen\n";
303  foreach(QString when, step->setWhen())
304  {
305  stream << when << "\n";
306  }
307  stream << "end_setwhen\n";
308  }
309  stream << "end_step\n";
310 
311  }
312 
313  stream << "end_quest\n\n";
314  }
315 }
316 
317 QStringList QuestManager::getFiles() const
318 {
319  return myFiles.keys();
320 }
321 
322 QString QuestManager::getQuestFile(Quest* quest) const
323 {
324  foreach(QString file, myFiles.keys())
325  {
326  if (myFiles[file]->contains(quest))
327  return file;
328  }
329  return QString();
330 }
331 
332 void QuestManager::setQuestFile(Quest* quest, const QString& file)
333 {
334  if (file.isEmpty())
335  return;
336 
337  Q_ASSERT(getQuestFile(quest).isEmpty());
338  addQuest(file, quest);
339 }
340 
341 Quest* QuestManager::findByCode(const QString& code)
342 {
343  foreach(Quest* quest, myQuests)
344  {
345  if (quest->code() == code)
346  return quest;
347  }
348  return NULL;
349 }
Error, serious thing.
Definition: logger.h:11
void setRestart(bool restart)
Definition: Quest.cpp:130
const QStringList & setWhen() const
Definition: Quest.cpp:39
const Quest * parent() const
Definition: Quest.cpp:166
Definition: Quest.h:32
QList< const QuestStep * > steps() const
Definition: Quest.cpp:138
const QString & code() const
Definition: Quest.cpp:63
QString getQuestFile(Quest *quest) const
void setTitle(const QString &title)
Definition: Quest.cpp:81
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.c:57
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
void setStep(int step)
Definition: Quest.cpp:14
const QString & face() const
Definition: Quest.cpp:89
void loadQuestFile(const QString &filename)
const QString & description() const
Definition: Quest.cpp:112
Global type definitions and header inclusions.
void loadQuests()
const QString & title() const
Definition: Quest.cpp:76
Quest * findByCode(const QString &code)
QHash< QString, QList< Quest * > * > myFiles
Definition: QuestManager.h:26
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.c:95
void setDescription(const QString &description)
Definition: Quest.cpp:117
void setQuestFile(Quest *quest, const QString &file)
#define snprintf
Definition: win32.h:46
QHash< QString, QStringList > myIncludes
Definition: QuestManager.h:27
bool isModified() const
Definition: Quest.cpp:151
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Combines the 2 paths.
Definition: path.c:172
Definition: Quest.h:9
void setCompletion(bool completion)
Definition: Quest.cpp:34
virtual ~QuestManager()
bool canRestart() const
Definition: Quest.cpp:125
void setCode(const QString &code)
Definition: Quest.cpp:68
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
void saveQuestFile(const QString &filename)
void addQuest(const QString &filename, Quest *quest)
int step() const
Definition: Quest.cpp:9
void setParent(Quest *parent)
Definition: Quest.cpp:171
const char * datadir
Read only data files.
Definition: global.h:244
const QString & description() const
Definition: Quest.cpp:19
QList< Quest * > myQuests
Definition: QuestManager.h:25
QList< const Quest * > quests() const
const char * mapdir
Where the map files are.
Definition: global.h:247
struct Settings settings
Server settings.
Definition: init.c:40
bool isCompletion() const
Definition: Quest.cpp:29
QStringList getFiles() const
void setDescription(const QString &description)
Definition: Quest.cpp:24
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.c:25
void setModified(bool modified)
Definition: Quest.cpp:155
void setFace(const QString &face)
Definition: Quest.cpp:94
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.c:76
Quest * getByCode(const QString &code)