Crossfire Server  1.75.0
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 
34 QuestLoader::QuestLoader(Quests *quests, Faces *faces, AssetsTracker *tracker) : quests(quests), faces(faces), tracker(tracker) {
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 
74  message = stringbuffer_finish(buf);
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 
83  stringbuffer_append_string(buf, "\n");
84  stringbuffer_append_string(buf, read);
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) {
99  buf = stringbuffer_new();
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 
116  auto message = stringbuffer_finish(buf);
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  }
124  stringbuffer_append_string(buf, "\n");
125  stringbuffer_append_string(buf, read);
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  }
139  stringbuffer_append_string(buf, "\n");
140  stringbuffer_append_string(buf, read);
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) {
148  tracker->assetDefined(quest, filename);
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) {
225  stringbuffer_finish(buf);
226  }
227  }
228 }
Error, serious thing.
Definition: logger.h:11
int maxstep
The latest step that triggers the condition, to match, the stages must be between minstep and maxstep...
Definition: quest.h:24
sstring step_description
Step description to show player.
Definition: quest.h:31
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Faces * faces
Definition: QuestLoader.h:37
Definition of an in-game quest.
Definition: quest.h:37
T * get(const Key &name)
Get a named asset.
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
sstring quest_code
The quest that triggers the condition.
Definition: quest.h:21
Quests * quests
Definition: QuestLoader.h:36
std::vector< quest_step_definition * > steps
Quest steps.
Definition: quest.h:46
sstring quest_comment
Quest comment, not visible to players.
Definition: quest.h:41
#define QUESTFILE_STEP
In a quest step.
Definition: QuestLoader.cpp:28
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
One step of a quest.
Definition: quest.h:29
QuestLoader(Quests *quests, Faces *faces, AssetsTracker *tracker)
Definition: QuestLoader.cpp:34
size_t bufferreader_current_line(BufferReader *br)
Return the index of the last line returned by bufferreader_next_line().
Definition: Quests.h:19
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
AssetsTracker * tracker
Definition: QuestLoader.h:38
quest_definition * quest_create(const char *name)
Definition: Quests.cpp:63
#define QUESTFILE_COMMENT
In a quest comment.
Definition: QuestLoader.cpp:31
int quest_condition_from_string(quest_condition *condition, const char *buffer)
Parse a single step condition.
Definition: Quests.cpp:100
One condition to automatically move to a quest step.
Definition: quest.h:20
quest_condition * quest_create_condition(void)
Allocate a quest_condition, will call fatal() if out of memory.
Definition: Quests.cpp:56
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
bool quest_is_system
If set then the quest isn&#39;t counted or listed.
Definition: quest.h:45
Base class to be informed of where an asset is defined.
Definition: AssetsTracker.h:24
quest_step_definition * quest_create_step(void)
Allocate a quest_step_definition, will call fatal() if out of memory.
Definition: Quests.cpp:49
sstring quest_code
Quest internal code.
Definition: quest.h:38
std::vector< quest_condition * > conditions
The conditions that must be satisfied to trigger the step.
Definition: quest.h:33
#define QUESTFILE_QUEST
In a quest definition.
Definition: QuestLoader.cpp:26
sstring quest_title
Quest title for player.
Definition: quest.h:39
#define QUESTFILE_QUESTDESC
In a quest description.
Definition: QuestLoader.cpp:27
struct quest_definition * parent
Parent for this quest, NULL if it is a &#39;top-level&#39; quest.
Definition: quest.h:47
const Face * face
Face associated with this quest.
Definition: quest.h:43
int minstep
The earliest step in the quest that triggers the condition, -1 means finished, 0 means not started...
Definition: quest.h:22
int is_completion_step
Whether this step completes the quest (1) or not (0)
Definition: quest.h:32
virtual void assetDefined(const archetype *asset, const std::string &filename)
Function called when an asset is defined in a file.
Definition: AssetsTracker.h:32
#define QUESTFILE_NEXTQUEST
Waiting for next quest definition.
Definition: QuestLoader.cpp:25
#define QUESTFILE_STEPCOND
In a quest step conditions.
Definition: QuestLoader.cpp:30
Only for debugging purposes.
Definition: logger.h:13
int quest_restart
If non zero, can be restarted.
Definition: quest.h:42
C function wrappers to interact with assets.
int step
Step identifier.
Definition: quest.h:30
StringBuffer * buf
Definition: readable.cpp:1563
char * bufferreader_next_line(BufferReader *br)
Return the next line in the buffer, as separated by a newline.
virtual void load(BufferReader *reader, const std::string &filename) override
Load assets from the specified reader.
Definition: QuestLoader.cpp:37
A buffer that will be expanded as content is added to it.
sstring quest_description
Quest longer description.
Definition: quest.h:40
Definition: Faces.h:19
static struct_quest ** quests
All quests in the game.
Definition: mapper.cpp:943
#define QUESTFILE_STEPDESC
In a quest step description.
Definition: QuestLoader.cpp:29
T * define(const Key &name, T *asset)
Define an asset, erasing an existing one.