Crossfire Server, Trunk
QuestLoader.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 2021 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 "QuestLoader.h"
14 #include "AssetsCollection.h"
15 #include "Quests.h"
16 #include "assets.h"
17 #include "AssetsManager.h"
18 
25 #define QUESTFILE_NEXTQUEST 0
26 #define QUESTFILE_QUEST 1
27 #define QUESTFILE_QUESTDESC 2
28 #define QUESTFILE_STEP 3
29 #define QUESTFILE_STEPDESC 4
30 #define QUESTFILE_STEPCOND 5
31 #define QUESTFILE_COMMENT 6
33 
35 }
36 
37 void QuestLoader::load(BufferReader *reader, const std::string &filename) {
38  int i, in = QUESTFILE_NEXTQUEST;
39  quest_definition *quest = NULL;
40  quest_condition *cond = NULL;
41  quest_step_definition *step = NULL;
42  char *read;
43  StringBuffer *buf = NULL;
44 
45  while ((read = bufferreader_next_line(reader)) != NULL) {
46  if (in == QUESTFILE_STEPCOND) {
47  if (strcmp(read, "end_setwhen") == 0) {
48  in = QUESTFILE_STEP;
49  continue;
50  }
51  /*
52  * We are reading in a list of conditions for the 'setwhen' block for a quest step
53  * There will be one entry per line, containing the quest, and the steps that it applies to.
54  */
55 
56  cond = quest_create_condition();
57  if (!quest_condition_from_string(cond, read)) {
58  LOG(llevError, "Invalid line '%s' in setwhen block for quest %s=n", read, quest->quest_code);
59  free(cond);
60  continue;
61  }
62 
63  if (step->conditions) {
64  auto c = step->conditions;
65  while (c->next) {
66  c = c->next;
67  }
68  c->next = cond;
69  } else {
70  step->conditions = cond;
71  }
72  LOG(llevDebug, "condition added for step %d of quest %s, looking for quest %s between steps %d and %d\n",
73  step->step, quest->quest_code, cond->quest_code, cond->minstep, cond->maxstep);
74  continue;
75  }
76  if (in == QUESTFILE_STEPDESC) {
77  if (strcmp(read, "end_description") == 0) {
78  char *message;
79 
80  in = QUESTFILE_STEP;
81 
83  buf = NULL;
84 
85  step->step_description = (*message != '\0') ? add_string(message + 1) : NULL; // Skip initial newline
86  free(message);
87 
88  continue;
89  }
90 
93  continue;
94  }
95 
96  if (in == QUESTFILE_STEP) {
97  if (strcmp(read, "end_step") == 0) {
98  step = NULL;
99  in = QUESTFILE_QUEST;
100  continue;
101  }
102  if (strcmp(read, "finishes_quest") == 0) {
103  step->is_completion_step = 1;
104  continue;
105  }
106  if (strcmp(read, "description") == 0) {
107  buf = stringbuffer_new();
108  in = QUESTFILE_STEPDESC;
109  continue;
110  }
111  if (strcmp(read, "setwhen") == 0) {
112  in = QUESTFILE_STEPCOND;
113  continue;
114  }
115  LOG(llevError, "quests: invalid line %s in definition of quest %s in %s:%d!\n",
116  read, quest->quest_code, filename.c_str(), bufferreader_current_line(reader));
117  continue;
118  }
119 
120  if (in == QUESTFILE_QUESTDESC) {
121  if (strcmp(read, "end_description") == 0) {
122  in = QUESTFILE_QUEST;
123 
125  buf = NULL;
126 
127  quest->quest_description = (*message != '\0') ? add_string(message + 1) : NULL; // Remove initial newline
128  free(message);
129 
130  continue;
131  }
134  continue;
135  }
136 
137  if (in == QUESTFILE_COMMENT) {
138  // Quest comment is ignored here, only used in eg CRE.
139  if (strcmp(read, "end_comment") == 0) {
140  in = QUESTFILE_QUEST;
141  auto comment = stringbuffer_finish(buf);
142  buf = nullptr;
143  quest->quest_comment = (*comment != '\0') ? add_string(comment + 1) : NULL; // Skip initial newline
144  free(comment);
145  continue;
146  }
149  continue;
150  }
151 
152  if (in == QUESTFILE_QUEST) {
153  if (strcmp(read, "end_quest") == 0) {
154  quests->define(quest->quest_code, quest);
155  if (tracker) {
157  }
158  quest = NULL;
159  in = QUESTFILE_NEXTQUEST;
160  continue;
161  }
162 
163  if (strcmp(read, "description") == 0) {
164  in = QUESTFILE_QUESTDESC;
165  buf = stringbuffer_new();
166  continue;
167  }
168 
169  if (strncmp(read, "title ", 6) == 0) {
170  quest->quest_title = add_string(read + 6);
171  continue;
172  }
173 
174  if (sscanf(read, "step %d", &i)) {
175  step = quest_create_step();
176  step->step = i;
177  if (quest->steps) {
178  auto l = quest->steps;
179  while (l->next) {
180  l = l->next;
181  }
182  l->next = step;
183  } else {
184  quest->steps = step;
185  }
186  in = QUESTFILE_STEP;
187  continue;
188  }
189 
190  if (sscanf(read, "restart %d", &i)) {
191  quest->quest_restart = i;
192  continue;
193  }
194  if (strncmp(read, "parent ", 7) == 0) {
195  quest->parent = quests->get(read + 7);
196  continue;
197  }
198 
199  if (strncmp(read, "face ", 5) == 0) {
200  quest->face = faces->get(read + 5);
201  continue;
202  }
203 
204  if (strncmp(read, "comment", 7) == 0) {
205  in = QUESTFILE_COMMENT;
206  buf = stringbuffer_new();
207  continue;
208  }
209 
210  if (sscanf(read, "is_system %d", &i)) {
211  quest->quest_is_system = (i ? true : false);
212  continue;
213  }
214  }
215 
216  if (read[0] == '#')
217  continue;
218 
219  if (strncmp(read, "quest ", 6) == 0) {
220  if (quest) {
221  LOG(llevError, "'quest' while in quest '%s' in file %s\n", quest->quest_code, filename.c_str());
222  }
223  quest = quest_create(read + 6);
224  /* Set a default face, which will be overwritten if a face is defined. */
225  quest->face = faces->get("quest_generic.111");
226  in = QUESTFILE_QUEST;
227  continue;
228  }
229 
230  if (strcmp(read, "") == 0)
231  continue;
232 
233  LOG(llevError, "quest: invalid file format for %s, I don't know what to do with the line %s\n", filename.c_str(), read);
234  }
235 
236  if (in != 0) {
237  LOG(llevError, "quest: quest definition file %s read in, ends with state %d\n", filename.c_str(), in);
238 
239  /* The buffer may not have been freed. */
240  if (buf != NULL) {
242  }
243  }
244 }
banquet.l
l
Definition: banquet.py:164
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
quest_condition::quest_code
sstring quest_code
Definition: quest.h:24
llevError
@ llevError
Definition: logger.h:11
quest_create_step
quest_step_definition * quest_create_step(void)
Definition: Quests.cpp:47
quest_condition::maxstep
int maxstep
Definition: quest.h:27
QuestLoader::tracker
AssetsTracker * tracker
Definition: QuestLoader.h:38
QUESTFILE_STEPDESC
#define QUESTFILE_STEPDESC
Definition: QuestLoader.cpp:29
QuestLoader::faces
Faces * faces
Definition: QuestLoader.h:37
AssetsManager.h
QUESTFILE_QUESTDESC
#define QUESTFILE_QUESTDESC
Definition: QuestLoader.cpp:27
c
static event_registration c
Definition: citylife.cpp:427
bufferreader_next_line
char * bufferreader_next_line(BufferReader *br)
Definition: bufferreader.c:102
bufferreader_current_line
size_t bufferreader_current_line(BufferReader *br)
Definition: bufferreader.c:140
quest_step_definition::step
int step
Definition: quest.h:34
QuestLoader::quests
Quests * quests
Definition: QuestLoader.h:36
npc_dialog.filename
filename
Definition: npc_dialog.py:99
quest_step_definition
Definition: quest.h:33
quest
Definition: quest.py:1
QuestLoader::QuestLoader
QuestLoader(Quests *quests, Faces *faces, AssetsTracker *tracker)
Definition: QuestLoader.cpp:34
QUESTFILE_STEPCOND
#define QUESTFILE_STEPCOND
Definition: QuestLoader.cpp:30
AssetsTracker
Definition: AssetsTracker.h:28
quest_step_definition::is_completion_step
int is_completion_step
Definition: quest.h:36
Quests
Definition: Quests.h:21
AssetsCollection::define
T * define(const Key &name, T *asset)
Definition: AssetsCollection.h:97
QUESTFILE_QUEST
#define QUESTFILE_QUEST
Definition: QuestLoader.cpp:26
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:95
AssetsTracker::assetDefined
virtual void assetDefined(const archetype *asset, const std::string &filename)
Definition: AssetsTracker.h:36
AssetsCollection.h
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
Quests.h
AssetsCollection::get
T * get(const Key &name)
Definition: AssetsCollection.h:66
Faces
Definition: Faces.h:21
StringBuffer
Definition: stringbuffer.c:25
quest_condition::minstep
int minstep
Definition: quest.h:25
diamondslots.message
string message
Definition: diamondslots.py:57
QUESTFILE_NEXTQUEST
#define QUESTFILE_NEXTQUEST
Definition: QuestLoader.cpp:25
QuestLoader.h
quest_step_definition::conditions
quest_condition * conditions
Definition: quest.h:38
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
quest_condition
Definition: quest.h:23
QUESTFILE_STEP
#define QUESTFILE_STEP
Definition: QuestLoader.cpp:28
quest_definition
Definition: quest.h:42
assets.h
buf
StringBuffer * buf
Definition: readable.c:1610
dragon_attune.faces
dictionary faces
Definition: dragon_attune.py:31
QuestLoader::load
virtual void load(BufferReader *reader, const std::string &filename) override
Definition: QuestLoader.cpp:37
quest_step_definition::step_description
sstring step_description
Definition: quest.h:35
QUESTFILE_COMMENT
#define QUESTFILE_COMMENT
Definition: QuestLoader.cpp:31
quests
static struct_quest ** quests
Definition: mapper.cpp:916
quest_create
quest_definition * quest_create(const char *name)
Definition: Quests.cpp:61
quest_condition_from_string
int quest_condition_from_string(quest_condition *condition, const char *buffer)
Definition: Quests.cpp:104
BufferReader
Definition: bufferreader.c:21
llevDebug
@ llevDebug
Definition: logger.h:13
quest_create_condition
quest_condition * quest_create_condition(void)
Definition: Quests.cpp:54