1 |
/* |
/* |
2 |
$Id$ |
$Id$ |
3 |
|
|
4 |
Copyright (C) 2004 Kai Sterker <kaisterker@linuxgames.com> |
Copyright (C) 2004/2005 Kai Sterker <kaisterker@linuxgames.com> |
5 |
Part of the Adonthell Project http://adonthell.linuxgames.com |
Part of the Adonthell Project http://adonthell.linuxgames.com |
6 |
|
|
7 |
Adonthell is free software; you can redistribute it and/or modify |
Adonthell is free software; you can redistribute it and/or modify |
31 |
#include "base/base.h" |
#include "base/base.h" |
32 |
#include "base/diskio.h" |
#include "base/diskio.h" |
33 |
#include "python/python.h" |
#include "python/python.h" |
34 |
|
#include "event/manager.h" |
35 |
|
#include "rpg/quest_event.h" |
36 |
|
|
37 |
using rpg::quest; |
using rpg::quest; |
38 |
using rpg::quest_part; |
using rpg::quest_part; |
39 |
|
using rpg::quest_event; |
40 |
|
|
41 |
// ctor |
// ctor |
42 |
quest_part::quest_part (const std::string & id) |
quest_part::quest_part (const std::string & id, quest_part *parent) |
43 |
{ |
{ |
44 |
Id = id; |
Id = id; |
45 |
Code = ""; |
Code = ""; |
46 |
Entry = NULL; |
Parent = parent; |
|
Parent = NULL; |
|
47 |
Started = false; |
Started = false; |
48 |
Completed = false; |
Completed = false; |
49 |
|
EntryOnStart = NULL; |
50 |
|
EntryOnCompl = NULL; |
51 |
|
|
52 |
|
if (Parent != NULL) |
53 |
|
Parent->add_child (this); |
54 |
} |
} |
55 |
|
|
56 |
// dtor |
// dtor |
59 |
std::map<std::string, quest_part*>::iterator q; |
std::map<std::string, quest_part*>::iterator q; |
60 |
for (q = Children.begin (); q != Children.end (); q++) |
for (q = Children.begin (); q != Children.end (); q++) |
61 |
delete (*q).second; |
delete (*q).second; |
62 |
|
|
63 |
|
delete EntryOnStart; |
64 |
|
delete EntryOnCompl; |
65 |
} |
} |
66 |
|
|
67 |
// set a step to completed |
// set a step to completed |
70 |
// only steps can be completed that way |
// only steps can be completed that way |
71 |
if (!Children.empty ()) return false; |
if (!Children.empty ()) return false; |
72 |
|
|
73 |
Completed = true; |
// set state to started and completed |
74 |
Started = true; |
update (); |
|
|
|
|
// update parent, if it has one |
|
|
if (Parent != NULL) Parent->update (); |
|
75 |
|
|
76 |
return true; |
return true; |
77 |
} |
} |
89 |
return NULL; |
return NULL; |
90 |
} |
} |
91 |
|
|
92 |
|
// add a quest to list of quests |
93 |
|
void quest_part::add_child (quest_part *part) |
94 |
|
{ |
95 |
|
std::map<std::string, quest_part*>::iterator q; |
96 |
|
if ((q = Children.find (part->id ())) != Children.end ()) |
97 |
|
{ |
98 |
|
delete (*q).second; |
99 |
|
(*q).second = part; |
100 |
|
} |
101 |
|
else Children[part->id ()] = part; |
102 |
|
} |
103 |
|
|
104 |
|
|
105 |
// update state of a quest part from state of its children |
// update state of a quest part from state of its children |
106 |
void quest_part::update () |
void quest_part::update () |
107 |
{ |
{ |
139 |
if (Completed == true) changed = true; |
if (Completed == true) changed = true; |
140 |
} |
} |
141 |
|
|
142 |
// if state changed, update parent too |
if (changed) |
143 |
if (Parent != NULL && changed) Parent->update (); |
{ |
144 |
|
// fire quest event |
145 |
|
quest_event evt (full_name(), this); |
146 |
|
events::manager::raise_event (&evt); |
147 |
|
|
148 |
|
// if state changed, update parent too |
149 |
|
if (Parent != NULL) Parent->update (); |
150 |
|
} |
151 |
} |
} |
152 |
|
|
153 |
// calculate the state of completion with given code |
// calculate the state of completion with given code |
154 |
bool quest_part::evaluate () |
bool quest_part::evaluate () |
155 |
{ |
{ |
156 |
std::string code = "", token = 0; |
std::string code = "", token = ""; |
157 |
std::map<std::string, quest_part*>::iterator child; |
std::map<std::string, quest_part*>::iterator child; |
158 |
|
|
159 |
// prepare code for evaluation, replacing all references to quest parts with |
// prepare code for evaluation, replacing all references to quest parts with |
160 |
// their state of completion |
// their state of completion |
161 |
for (std::string::const_iterator i = Code.begin (); i != Code.end (); i++) |
for (const char *cptr = Code.c_str(); *cptr != '\0'; cptr++) |
162 |
{ |
{ |
163 |
if (!isalnum (*i)) |
if (!isalnum (*cptr) && *cptr != '_') |
164 |
{ |
{ |
165 |
// check if we have just read a new token |
// check if we have just read a new token |
166 |
if (token != "") |
if (token != "") |
167 |
{ |
{ |
168 |
// check if the token we read is a quest_part |
// check if the token we read is a quest_part |
169 |
if ((child = Children.find (token)) != Children.end ()) |
if ((child = Children.find (token)) != Children.end ()) |
170 |
// if so, add it's state of completion to the code |
// if so, add its state of completion to the code |
171 |
code += (*child).second->is_completed () ? '1' : '0'; |
code += (*child).second->is_completed () ? '1' : '0'; |
172 |
else |
else |
173 |
// otherwise assume the token is part of the code |
// otherwise assume the token is part of the code |
176 |
// reset token |
// reset token |
177 |
token = ""; |
token = ""; |
178 |
} |
} |
179 |
code += *i; |
code += *cptr; |
180 |
} |
} |
181 |
else token += *i; |
else token += *cptr; |
182 |
} |
} |
183 |
|
|
184 |
// now try to evaluate our code snippet |
// now try to evaluate our code snippet |
196 |
return completed; |
return completed; |
197 |
} |
} |
198 |
|
|
199 |
|
|
200 |
|
// get full name of this quest part |
201 |
|
std::string quest_part::full_name () const |
202 |
|
{ |
203 |
|
if (Parent != NULL) return Parent->full_name() + std::string(".") + Id; |
204 |
|
return Id; |
205 |
|
} |
206 |
|
|
207 |
// save quest_part |
// save quest_part |
208 |
void quest_part::put_state (base::flat & out) const |
void quest_part::put_state (base::flat & out) const |
209 |
{ |
{ |
210 |
base::flat record; |
base::flat record; |
211 |
|
|
212 |
|
// id needs be saved here only for quest root |
213 |
|
if (Parent == NULL) record.put_string ("qid", Id); |
214 |
|
|
215 |
// save attributes |
// save attributes |
|
record.put_string ("qid", Id); |
|
216 |
record.put_bool ("qst", Started); |
record.put_bool ("qst", Started); |
217 |
record.put_bool ("qcp", Completed); |
record.put_bool ("qcp", Completed); |
218 |
record.put_string ("qcd", Code); |
record.put_string ("qcd", Code); |
219 |
|
|
220 |
// save associated log entry |
// save associated log entries |
221 |
record.put_bool ("qhe", Entry != NULL); |
record.put_bool ("qse", EntryOnStart != NULL); |
222 |
if (Entry) Entry->put_state (record); |
if (EntryOnStart) EntryOnStart->put_state (record); |
223 |
|
record.put_bool ("qce", EntryOnCompl != NULL); |
224 |
|
if (EntryOnCompl) EntryOnCompl->put_state (record); |
225 |
|
|
226 |
// save child quest parts |
// save child quest parts |
227 |
std::map<std::string, quest_part*>::const_iterator i; |
std::map<std::string, quest_part*>::const_iterator i; |
228 |
record.put_uint16 ("qnc", Children.size ()); |
record.put_uint16 ("qnc", Children.size ()); |
229 |
for (i = Children.begin (); i != Children.end (); i++) |
for (i = Children.begin (); i != Children.end (); i++) |
230 |
|
{ |
231 |
|
record.put_string ("qid", (*i).second->id ()); |
232 |
(*i).second->put_state (record); |
(*i).second->put_state (record); |
233 |
|
} |
234 |
|
|
235 |
// save this quest part to stream |
// save this quest part to stream |
236 |
out.put_flat ("q", record); |
out.put_flat ("q", record); |
237 |
} |
} |
242 |
base::flat record = in.get_flat ("q"); |
base::flat record = in.get_flat ("q"); |
243 |
if (!in.success ()) return false; |
if (!in.success ()) return false; |
244 |
|
|
245 |
|
// id needs to be loaded only for quest root |
246 |
|
if (Parent == NULL) Id = record.get_string ("qid"); |
247 |
|
|
248 |
// get attributes |
// get attributes |
|
Id = record.get_string ("qid"); |
|
249 |
Started = record.get_bool ("qst"); |
Started = record.get_bool ("qst"); |
250 |
Completed = record.get_bool ("qcp"); |
Completed = record.get_bool ("qcp"); |
251 |
Code = record.get_string ("qcd"); |
Code = record.get_string ("qcd"); |
252 |
|
|
253 |
// get log entry, if any |
// get log entry for quest start, if any |
254 |
if (record.get_bool ("qhe") == true) |
if (record.get_bool ("qse") == true) |
255 |
{ |
{ |
256 |
Entry = new rpg::log_entry ("", "", ""); |
EntryOnStart = new rpg::log_entry ("", "", ""); |
257 |
Entry->get_state (record); |
EntryOnStart->get_state (record); |
258 |
|
} |
259 |
|
|
260 |
|
// get log entries for quest completion, if any |
261 |
|
if (record.get_bool ("qce") == true) |
262 |
|
{ |
263 |
|
EntryOnCompl = new rpg::log_entry ("", "", ""); |
264 |
|
EntryOnCompl->get_state (record); |
265 |
} |
} |
266 |
|
|
267 |
// get children, if any |
// get children, if any |
268 |
quest_part *part; |
quest_part *part; |
269 |
for (u_int16 i = record.get_uint16 ("qhc"); i > 0; i--) |
for (u_int16 i = record.get_uint16 ("qnc"); i > 0; i--) |
270 |
{ |
{ |
271 |
part = new quest_part (""); |
string id = record.get_string ("qid"); |
272 |
|
|
273 |
|
part = new quest_part (id, this); |
274 |
part->get_state (record); |
part->get_state (record); |
|
part->Parent = this; |
|
|
Children[part->Id] = part; |
|
275 |
} |
} |
276 |
|
|
277 |
return record.success (); |
return record.success (); |
288 |
delete (*q).second; |
delete (*q).second; |
289 |
} |
} |
290 |
|
|
291 |
// check wether a given quest (step) has been started |
// check whether a given quest (step) has been started |
292 |
bool quest::is_started (const std::string & id) |
bool quest::is_started (const std::string & id) |
293 |
{ |
{ |
294 |
const quest_part *part = get_part (id); |
const quest_part *part = get_part (id); |
296 |
return false; |
return false; |
297 |
} |
} |
298 |
|
|
299 |
// check wether a given quest (step) has been completed |
// check whether a given quest (step) has been completed |
300 |
bool quest::is_completed (const std::string & id) |
bool quest::is_completed (const std::string & id) |
301 |
{ |
{ |
302 |
const quest_part *part = get_part (id); |
const quest_part *part = get_part (id); |
304 |
return false; |
return false; |
305 |
} |
} |
306 |
|
|
307 |
// check wether a given quest (step) is in progress |
// check whether a given quest (step) is in progress |
308 |
bool quest::in_progress (const std::string & id) |
bool quest::in_progress (const std::string & id) |
309 |
{ |
{ |
310 |
const quest_part *part = get_part (id); |
const quest_part *part = get_part (id); |
353 |
{ |
{ |
354 |
// open file |
// open file |
355 |
base::igzstream in; |
base::igzstream in; |
356 |
if (!base::Paths.open (in, QUEST_DATA)); |
if (!base::Paths.open (in, QUEST_DATA)) |
357 |
{ |
{ |
358 |
fprintf (stderr, "*** quest::put_state: cannot open '" QUEST_DATA "' for reading!\n"); |
fprintf (stderr, "*** quest::get_state: cannot open '" QUEST_DATA "' for reading!\n"); |
359 |
return false; |
return false; |
360 |
} |
} |
361 |
|
|
375 |
|
|
376 |
for (int i = 0; i < size; i++) |
for (int i = 0; i < size; i++) |
377 |
{ |
{ |
378 |
part = new quest_part (""); |
part = new quest_part ("", NULL); |
379 |
if (part->get_state (in)) add (part); |
if (part->get_state (in)) add (part); |
380 |
} |
} |
381 |
|
|
405 |
if ((q = Quests.find (*i)) != Quests.end ()) |
if ((q = Quests.find (*i)) != Quests.end ()) |
406 |
part = (*q).second; |
part = (*q).second; |
407 |
else |
else |
408 |
fprintf (stderr, "*** quest::get_part: quest '%s' no found!\n", (*i).c_str ()); |
fprintf (stderr, "*** quest::get_part: quest '%s' not found!\n", (*i).c_str ()); |
409 |
|
|
410 |
for (i = i++; i != result.end () && part != NULL; i++) |
for (i++; i != result.end () && part != NULL; i++) |
411 |
part = part->child (*i); |
part = part->child (*i); |
412 |
|
|
413 |
return part; |
return part; |