ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/quest.C
Revision: 1.2
Committed: Sun Sep 3 22:45:55 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +1 -1 lines
State: FILE REMOVED
Log Message:
string scanning (e.g. for patch) is not implemented ATM but should be easy
to add with an alternative constructor for object_thawer.

Rewrote flex scanner to be simpler, faster and more modularised.

Initial speedup: 16%

(ah well)

File Contents

# Content
1 /*
2 * static char *rcsid_quest_c =
3 * "$Id: quest.C,v 1.1 2006-08-13 17:16:00 elmex Exp $";
4 */
5
6 /*
7 CrossFire, A Multiplayer game for X-windows
8
9 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26 The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28
29 /*
30 This file handles quest-related functions.
31 Quests are stored in specific items of type QUEST.
32 */
33
34 #include <global.h>
35 #include <commands.h>
36 #ifndef __CEXTRACT__
37 #include <sproto.h>
38 #endif
39 #include <ctype.h>
40 #include "quest.h"
41
42 #define QUEST_NAME( op ) op->name_pl
43 #define TASK_NAME( op ) op->custom_name
44
45 #if 0
46 int quest_is_same_quest( const char* slaying1, const char* slaying2 )
47 {
48 char *start1, *start2, *end1, *end2;
49
50 /* Sanity check */
51 if ( !slaying1 )
52 {
53 LOG( llevError, "quest_is_same_quest: slaying1 invalid.\n" );
54 return 0;
55 }
56 if ( !slaying2 )
57 {
58 LOG( llevError, "quest_is_same_quest: slaying2 invalid.\n" );
59 return 0;
60 }
61
62 start1 = strchr( slaying1, ' ' );
63 start2 = strchr( slaying2, ' ' );
64 end1 = strrchr( slaying1, ' ' );
65 end2 = strrchr( slaying2, ' ' );
66 if ( end1 - start1 != end2 - start2 )
67 return 0;
68 if ( strncmp( start1, start2, end1 - start1 ) )
69 return 0;
70 return 1;
71 }
72 #endif
73
74 int quest_is_quest_marker( const object* marker, int task )
75 {
76 if ( marker->type != QUEST )
77 return 0;
78 if ( task && !TASK_NAME(marker) )
79 return 0;
80 if ( !task && TASK_NAME(marker) )
81 return 0;
82 return 1;
83 }
84
85 int quest_is_in_progress( const object* marker, int task )
86 {
87 if ( marker->subtype != QUEST_IN_PROGRESS )
88 return 0;
89 return 1;
90 }
91
92 int quest_is_completed( const object* marker, int task )
93 {
94 if ( marker->type != QUEST )
95 return 0;
96 if ( task && ( !marker->subtype != QUEST_DONE_TASK ) )
97 return 0;
98 if ( !task && ( marker->subtype != QUEST_DONE_QUEST ) )
99 return 0;
100 return 1;
101 }
102
103 #if 0
104 static int quest_has_start( object* marker, object* pl )
105 {
106 const char* start;
107 const char* end;
108 object* item;
109 start = marker->slaying + strlen( QUEST_START );
110 end = strrchr( start, ' ' );
111 if ( !end )
112 {
113 LOG( llevError, "quest_has_start: invalid marker slaying %s\n", marker->slaying );
114 return 0;
115 }
116
117 for ( item = pl->inv; item; item = item->below )
118 {
119 if ( item->type == FORCE
120 && item->slaying
121 && ( quest_is_quest_marker( item ) )
122 && ( quest_is_same_quest( marker->slaying, item->slaying ) )
123 && ( quest_is_start( item->slaying ) ) )
124 return 1;
125 }
126
127 return 0;
128 }
129
130 static int quest_has_end( object* marker, object* pl )
131 {
132 const char* start;
133 const char* end;
134 object* item;
135 start = marker->slaying + strlen( QUEST_START );
136 end = strrchr( start, ' ' );
137 if ( !end )
138 {
139 LOG( llevError, "quest_has_end: invalid marker slaying %s\n", marker->slaying );
140 return 0;
141 }
142
143 for ( item = pl->inv; item; item = item->below )
144 {
145 if ( item->type == FORCE
146 && item->slaying
147 && ( quest_is_quest_marker( item ) )
148 && ( quest_is_same_quest( marker->slaying, item->slaying ) )
149 && ( quest_is_end( item->slaying ) ) )
150 return 1;
151 }
152
153 return 0;
154 }
155
156 /**
157 * Checks if the marker is a quest one, and if so if compatible with the player's current quests.
158 **/
159 int quest_marker_compatible( object* marker, object* pl )
160 {
161 if ( !quest_is_quest_marker( marker ) )
162 return 1;
163
164 if ( quest_is_start( marker->slaying ) )
165 {
166 if ( quest_has_end( marker, pl ) )
167 /* Can't restart a quest */
168 return 0;
169 if ( quest_has_start( marker, pl ) )
170 /* Can't restart a quest already started */
171 return 0;
172 return 1;
173 }
174 else if ( quest_is_end( marker->slaying ) )
175 {
176 if ( !quest_has_start( marker, pl ) )
177 return 0;
178 if ( quest_has_end( marker, pl ) )
179 return 0;
180 return 1;
181 }
182
183 /* Neither a start or end, seek a start */
184 if ( quest_has_start( marker, pl ) )
185 return 1;
186
187 /* No start, or an end => can't */
188 return 0;
189 }
190
191 /**
192 * Clears other quest markers if required.
193 **/
194 void quest_clear_markers( object* marker, object* pl )
195 {
196 object *item;
197 object *next;
198 if ( !quest_is_end( marker->slaying ) )
199 return;
200
201 next = NULL;
202 for ( item = pl->inv; item; item = next )
203 {
204 next = item->below;
205 if ( quest_is_quest_marker( item ) && quest_is_same_quest( marker->slaying, item->slaying ) )
206 remove_ob( item );
207 }
208 }
209
210 /**
211 * Checks message against quest marker. Returns:
212 * * message if message not linked to quest
213 * * NULL if message linked to quest and player isn't at right step.
214 * * first char of real message, line after the 'quest xxx xxx' line.
215 **/
216 const char* quest_message_check( const char* message, object* pl )
217 {
218 const char *end1, *end2, *nl;
219 char buf[ MAX_BUF ];
220 object *item;
221 if ( !message || strncmp( message, QUEST_MARKER, strlen( QUEST_MARKER ) ) )
222 return message;
223
224 if ( nl = strchr( message, '\n' ) )
225 {
226 strncpy( buf, message, MIN( nl - message, MAX_BUF ) );
227 buf[ MIN( nl - message, MAX_BUF ) ] = '\0';
228 nl++;
229 }
230 else
231 {
232 strncpy( buf, message, MAX_BUF );
233 buf[ strlen( message ) ] = '\0';
234 nl = "";
235 }
236
237 for ( item = pl->inv; item; item = item->below )
238 {
239 if ( quest_is_quest_marker( item )
240 && quest_is_same_quest( item->slaying, buf ) )
241 {
242 end1 = strrchr( item->slaying, ' ' );
243 end2 = strrchr( buf, ' ' );
244 if ( !strcmp( end1, end2 ) )
245 return nl;
246 }
247 }
248 return NULL;
249 }
250 #endif
251
252 const char* quest_get_name( const object* marker )
253 {
254 if ( marker->type != QUEST )
255 return NULL;
256 if ( TASK_NAME(marker) )
257 return TASK_NAME(marker);
258 return QUEST_NAME(marker);
259 }
260
261 object* quest_get_player_quest( const object* pl, const char* name, const char* name_pl )
262 {
263 object* quest;
264 for ( quest = pl->inv; quest; quest = quest->below )
265 if ( quest->type == QUEST &&
266 QUEST_NAME(quest) == name && TASK_NAME(quest) == name_pl )
267 return quest;
268
269 return NULL;
270 }
271
272 object* quest_get_override( const object* ob, const object* pl )
273 {
274 object *in_ob, *in_pl;
275 if ( !ob->inv )
276 return NULL;
277 for ( in_ob = ob->inv; in_ob; in_ob = in_ob->below )
278 {
279 if ( in_ob->type == QUEST && in_ob->subtype == QUEST_OVERRIDE )
280 {
281 in_pl = quest_get_player_quest( pl, QUEST_NAME(in_ob), TASK_NAME(in_ob) );
282 if ( in_pl )
283 return in_ob;
284 }
285 }
286 return NULL;
287 }
288
289 const char* quest_get_override_slaying( const object* ob, const object* pl )
290 {
291 object* quest;
292 quest = quest_get_override( ob, pl );
293 if ( quest )
294 return quest->slaying;
295 return ob->slaying;
296 }
297
298 const char* quest_get_override_msg( const object* ob, const object* pl )
299 {
300 object* quest;
301 quest = quest_get_override( ob, pl );
302 if ( quest )
303 return quest->msg;
304 return ob->msg;
305 }
306 /*
307 static int quest_objects_match( object* first, object* second )
308 {
309 if ( !first || !second )
310 return 0;
311 if ( first->name != second->name )
312 return 0;
313 if ( first->name_pl && first->name_pl != second->name_pl )
314 return 0;
315 return 1;
316 }
317 */
318 static void quest_remove_marker(object* item, const char* name, const char* name_pl, int type)
319 {
320 object* test;
321 for ( test = item->inv; test; test = test->below )
322 {
323 if ( ( test->type == QUEST ) && ( test->subtype == type ) && ( QUEST_NAME(test) == name ) && ( !name_pl || TASK_NAME(test) == name_pl ) )
324 {
325 remove_ob(test);
326 return;
327 }
328 }
329 }
330
331 void quest_apply_items( object* wrapper, player* pl )
332 {
333 object* item;
334 object* qm;
335 for ( item = wrapper->inv; item; item = item->below )
336 {
337 if ( item->type == QUEST )
338 {
339 switch ( item->subtype )
340 {
341 case QUEST_START_QUEST:
342 if ( quest_get_player_quest( pl->ob, QUEST_NAME(item), NULL ) )
343 return;
344 qm = get_archetype("quest_in_progress");
345 FREE_AND_COPY(QUEST_NAME(qm), QUEST_NAME(item));
346 if ( item->lore )
347 {
348 FREE_AND_COPY(qm->lore, item->lore);
349 new_draw_info(NDI_UNIQUE, 0, pl->ob, item->lore);
350 }
351 insert_ob_in_ob(qm, pl->ob);
352 break;
353 case QUEST_END_QUEST:
354 if ( !quest_get_player_quest( pl->ob, QUEST_NAME(item), NULL ) )
355 return;
356 qm = get_archetype("quest_done_quest");
357 FREE_AND_COPY(QUEST_NAME(qm), QUEST_NAME(item));
358 if ( item->lore )
359 {
360 FREE_AND_COPY(qm->lore, item->lore);
361 new_draw_info(NDI_UNIQUE, 0, pl->ob, item->lore);
362 }
363 quest_remove_marker(pl->ob, QUEST_NAME(item), NULL, QUEST_IN_PROGRESS);
364 insert_ob_in_ob(qm, pl->ob);
365 break;
366 case QUEST_START_TASK:
367 if ( quest_get_player_quest( pl->ob, QUEST_NAME(item), TASK_NAME(item) ) )
368 return;
369 qm = get_archetype("quest_in_progress");
370 FREE_AND_COPY(QUEST_NAME(qm), QUEST_NAME(item));
371 FREE_AND_COPY(TASK_NAME(qm), TASK_NAME(item));
372 if ( item->lore )
373 {
374 FREE_AND_COPY(qm->lore, item->lore);
375 new_draw_info(NDI_UNIQUE, 0, pl->ob, item->lore);
376 }
377 insert_ob_in_ob(qm, pl->ob);
378 break;
379 case QUEST_END_TASK:
380 if ( !quest_get_player_quest( pl->ob, QUEST_NAME(item), TASK_NAME(item) ) )
381 return;
382 qm = get_archetype("quest_done_task");
383 FREE_AND_COPY(QUEST_NAME(qm), QUEST_NAME(item));
384 FREE_AND_COPY(TASK_NAME(qm), TASK_NAME(item));
385 if ( item->lore )
386 {
387 FREE_AND_COPY(qm->lore, item->lore);
388 new_draw_info(NDI_UNIQUE, 0, pl->ob, item->lore);
389 }
390 quest_remove_marker(pl->ob, QUEST_NAME(item), TASK_NAME(item), QUEST_IN_PROGRESS);
391 insert_ob_in_ob(qm, pl->ob);
392 break;
393 }
394 }
395 }
396 }
397
398 /**
399 * Returns 0 if no matching quest, 1 if anything matched.
400 **/
401 int quest_on_activate( object* ob, player*pl )
402 {
403 object* in_item;
404
405 for ( in_item = ob->inv; in_item; in_item = in_item->below )
406 {
407 if ( ( in_item->type == QUEST ) && ( in_item->subtype == QUEST_ON_ACTIVATE ) )
408 {
409 quest_apply_items( in_item, pl );
410 return 1;
411 }
412 }
413 return 0;
414 }
415
416 /**
417 * NS :not started
418 * S :started
419 * D :done
420 * SD :started or done
421 * Q :quest
422 * T :task
423 **/
424 #define QCT_QNS 1
425 #define QCT_QS 2
426 #define QCT_QS_TNS 3
427 #define QCT_QS_TS 4
428 #define QCT_QS_TD 5
429 #define QCT_QS_TSD 6
430 #define QCT_QSD 7
431 #define QCT_QD 8
432
433 int quest_is_override_compatible(const object *marker, const object* pl)
434 {
435 object* test;
436 if ( marker->type != QUEST || marker->subtype != QUEST_OVERRIDE )
437 return 0;
438 switch ( marker->stats.hp )
439 {
440 case QCT_QNS:
441 if ( quest_get_player_quest( pl, QUEST_NAME(marker), NULL ) == NULL )
442 return 1;
443 return 0;
444 case QCT_QS:
445 test = quest_get_player_quest( pl, QUEST_NAME(marker), NULL );
446 if ( !test )
447 return 0;
448 if ( quest_is_completed( test, 0 ) )
449 return 0;
450 return 1;
451 case QCT_QS_TNS:
452 test = quest_get_player_quest( pl, QUEST_NAME(marker), TASK_NAME(marker) );
453 if ( !test )
454 if ( quest_get_player_quest( pl, QUEST_NAME(marker), NULL ) )
455 return 1;
456 return 0;
457 case QCT_QS_TS:
458 test = quest_get_player_quest( pl, QUEST_NAME(marker), TASK_NAME(marker) );
459 if ( !test )
460 return 0;
461 if ( quest_is_completed( test, 1 ) )
462 return 0;
463 return 1;
464 case QCT_QS_TD:
465 test = quest_get_player_quest( pl, QUEST_NAME(marker), TASK_NAME(marker) );
466 if ( !test )
467 return 0;
468 if ( quest_is_completed( test, 1 ) )
469 return 1;
470 return 0;
471 case QCT_QS_TSD:
472 test = quest_get_player_quest( pl, QUEST_NAME(marker), TASK_NAME(marker) );
473 if ( !test )
474 return 0;
475 return 1;
476 case QCT_QSD:
477 test = quest_get_player_quest( pl, QUEST_NAME(marker), NULL );
478 if ( !test )
479 return 0;
480 return 1;
481 case QCT_QD:
482 test = quest_get_player_quest( pl, QUEST_NAME(marker), NULL );
483 if ( !test || !quest_is_completed( test, 0 ) )
484 return 0;
485 return 1;
486 };
487 return 1;
488 }