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  step->conditions.push_back(cond);
64  LOG(llevDebug, "condition added for step %d of quest %s, looking for quest %s between steps %d and %d\n",
65  step->step, quest->quest_code, cond->quest_code, cond->minstep, cond->maxstep);
66  continue;
67  }
68  if (in == QUESTFILE_STEPDESC) {
69  if (strcmp(read, "end_description") == 0) {
70  char *message;
71 
72  in = QUESTFILE_STEP;
73 
75  buf = NULL;
76 
77  step->step_description = (*message != '\0') ? add_string(message + 1) : NULL; // Skip initial newline
78  free(message);
79 
80  continue;
81  }
82 
85  continue;
86  }
87 
88  if (in == QUESTFILE_STEP) {
89  if (strcmp(read, "end_step") == 0) {
90  step = NULL;
91  in = QUESTFILE_QUEST;
92  continue;
93  }
94  if (strcmp(read, "finishes_quest") == 0) {
95  step->is_completion_step = 1;
96  continue;
97  }
98  if (strcmp(read, "description") == 0) {
100  in = QUESTFILE_STEPDESC;
101  continue;
102  }
103  if (strcmp(read, "setwhen") == 0) {
104  in = QUESTFILE_STEPCOND;
105  continue;
106  }
107  LOG(llevError, "quests: invalid line %s in definition of quest %s in %s:%zu!\n",
108  read, quest->quest_code, filename.c_str(), bufferreader_current_line(reader));
109  continue;
110  }
111 
112  if (in == QUESTFILE_QUESTDESC) {
113  if (strcmp(read, "end_description") == 0) {
114  in = QUESTFILE_QUEST;
115 
117  buf = NULL;
118 
119  quest->quest_description = (*message != '\0') ? add_string(message + 1) : NULL; // Remove initial newline
120  free(message);
121 
122  continue;
123  }
126  continue;
127  }
128 
129  if (in == QUESTFILE_COMMENT) {
130  // Quest comment is ignored here, only used in eg CRE.
131  if (strcmp(read, "end_comment") == 0) {
132  in = QUESTFILE_QUEST;
133  auto comment = stringbuffer_finish(buf);
134  buf = nullptr;
135  quest->quest_comment = (*comment != '\0') ? add_string(comment + 1) : NULL; // Skip initial newline
136  free(comment);
137  continue;
138  }
141  continue;
142  }
143 
144  if (in == QUESTFILE_QUEST) {
145  if (strcmp(read, "end_quest") == 0) {
146  quests->define(quest->quest_code, quest);
147  if (tracker) {
149  }
150  quest = NULL;
151  in = QUESTFILE_NEXTQUEST;
152  continue;
153  }
154 
155  if (strcmp(read, "description") == 0) {
156  in = QUESTFILE_QUESTDESC;
157  buf = stringbuffer_new();
158  continue;
159  }
160 
161  if (strncmp(read, "title ", 6) == 0) {
162  quest->quest_title = add_string(read + 6);
163  continue;
164  }
165 
166  if (sscanf(read, "step %d", &i)) {
167  step = quest_create_step();
168  step->step = i;
169  quest->steps.push_back(step);
170  in = QUESTFILE_STEP;
171  continue;
172  }
173 
174  if (sscanf(read, "restart %d", &i)) {
175  quest->quest_restart = i;
176  continue;
177  }
178  if (strncmp(read, "parent ", 7) == 0) {
179  quest->parent = quests->get(read + 7);
180  continue;
181  }
182 
183  if (strncmp(read, "face ", 5) == 0) {
184  quest->face = faces->get(read + 5);
185  continue;
186  }
187 
188  if (strncmp(read, "comment", 7) == 0) {
189  in = QUESTFILE_COMMENT;
190  buf = stringbuffer_new();
191  continue;
192  }
193 
194  if (sscanf(read, "is_system %d", &i)) {
195  quest->quest_is_system = (i ? true : false);
196  continue;
197  }
198  }
199 
200  if (read[0] == '#')
201  continue;
202 
203  if (strncmp(read, "quest ", 6) == 0) {
204  if (quest) {
205  LOG(llevError, "'quest' while in quest '%s' in file %s\n", quest->quest_code, filename.c_str());
206  }
207  quest = quest_create(read + 6);
208  /* Set a default face, which will be overwritten if a face is defined. */
209  quest->face = faces->get("quest_generic.111");
210  in = QUESTFILE_QUEST;
211  continue;
212  }
213 
214  if (strcmp(read, "") == 0)
215  continue;
216 
217  LOG(llevError, "quest: invalid file format for %s, I don't know what to do with the line %s\n", filename.c_str(), read);
218  }
219 
220  if (in != 0) {
221  LOG(llevError, "quest: quest definition file %s read in, ends with state %d\n", filename.c_str(), in);
222 
223  /* The buffer may not have been freed. */
224  if (buf != NULL) {
226  }
227  }
228 }
quest_condition::quest_code
sstring quest_code
Definition: quest.h:21
bufferreader_current_line
size_t bufferreader_current_line(BufferReader *br)
Definition: bufferreader.cpp:140
llevError
@ llevError
Definition: logger.h:11
quest_create_step
quest_step_definition * quest_create_step(void)
Definition: Quests.cpp:49
quest_condition::maxstep
int maxstep
Definition: quest.h:24
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:58
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
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
quest_step_definition::step
int step
Definition: quest.h:30
QuestLoader::quests
Quests * quests
Definition: QuestLoader.h:36
npc_dialog.filename
filename
Definition: npc_dialog.py:99
buf
StringBuffer * buf
Definition: readable.cpp:1565
quest_step_definition
Definition: quest.h:29
quest
Definition: quest.py:1
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
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:26
quest_step_definition::is_completion_step
int is_completion_step
Definition: quest.h:32
Quests
Definition: Quests.h:19
AssetsCollection::define
T * define(const Key &name, T *asset)
Definition: AssetsCollection.h:120
QUESTFILE_QUEST
#define QUESTFILE_QUEST
Definition: QuestLoader.cpp:26
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
AssetsTracker::assetDefined
virtual void assetDefined(const archetype *asset, const std::string &filename)
Definition: AssetsTracker.h:34
AssetsCollection.h
Quests.h
AssetsCollection::get
T * get(const Key &name)
Definition: AssetsCollection.h:89
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.cpp:95
Faces
Definition: Faces.h:19
StringBuffer
Definition: stringbuffer.cpp:25
quest_condition::minstep
int minstep
Definition: quest.h:22
diamondslots.message
string message
Definition: diamondslots.py:57
QUESTFILE_NEXTQUEST
#define QUESTFILE_NEXTQUEST
Definition: QuestLoader.cpp:25
QuestLoader.h
quest_condition
Definition: quest.h:20
QUESTFILE_STEP
#define QUESTFILE_STEP
Definition: QuestLoader.cpp:28
quest_definition
Definition: quest.h:37
assets.h
dragon_attune.faces
dictionary faces
Definition: dragon_attune.py:31
quest_step_definition::conditions
std::vector< quest_condition * > conditions
Definition: quest.h:33
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:31
QUESTFILE_COMMENT
#define QUESTFILE_COMMENT
Definition: QuestLoader.cpp:31
quests
static struct_quest ** quests
Definition: mapper.cpp:892
quest_create
quest_definition * quest_create(const char *name)
Definition: Quests.cpp:63
quest_condition_from_string
int quest_condition_from_string(quest_condition *condition, const char *buffer)
Definition: Quests.cpp:100
BufferReader
Definition: bufferreader.cpp:21
llevDebug
@ llevDebug
Definition: logger.h:13
quest_create_condition
quest_condition * quest_create_condition(void)
Definition: Quests.cpp:56
bufferreader_next_line
char * bufferreader_next_line(BufferReader *br)
Definition: bufferreader.cpp:102