ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/quest.c
Revision: 1.1.1.2 (vendor branch)
Committed: Wed Feb 22 18:01:22 2006 UTC (18 years, 3 months ago) by elmex
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_03_15, LAST_C_VERSION, UPSTREAM_2006_02_22, difficulty_fix_merge_060810_2300
Branch point for: difficulty_fix
Changes since 1.1.1.1: +10 -10 lines
Log Message:
cvs -z7 -d:ext:elmex@cvs.schmorp.de:/schmorpforge import cf.schmorp.de UPSTREAM UPSTREAM_2006_02_22

File Contents

# User Rev Content
1 root 1.1 /*
2     * static char *rcsid_quest_c =
3 elmex 1.1.1.2 * "$Id: quest.c,v 1.6 2006/02/09 00:48:36 akirschbaum Exp $";
4 root 1.1 */
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 elmex 1.1.1.2 int quest_is_quest_marker( const object* marker, int task )
75 root 1.1 {
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 elmex 1.1.1.2 int quest_is_in_progress( const object* marker, int task )
86 root 1.1 {
87     if ( marker->subtype != QUEST_IN_PROGRESS )
88     return 0;
89     return 1;
90     }
91    
92 elmex 1.1.1.2 int quest_is_completed( const object* marker, int task )
93 root 1.1 {
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 elmex 1.1.1.2 const char* quest_get_name( const object* marker )
253 root 1.1 {
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 elmex 1.1.1.2 object* quest_get_player_quest( const object* pl, const char* name, const char* name_pl )
262 root 1.1 {
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 elmex 1.1.1.2 object* quest_get_override( const object* ob, const object* pl )
273 root 1.1 {
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 elmex 1.1.1.2 const char* quest_get_override_slaying( const object* ob, const object* pl )
290 root 1.1 {
291     object* quest;
292     quest = quest_get_override( ob, pl );
293     if ( quest )
294     return quest->slaying;
295     return ob->slaying;
296     }
297    
298 elmex 1.1.1.2 const char* quest_get_override_msg( const object* ob, const object* pl )
299 root 1.1 {
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 elmex 1.1.1.2 int quest_is_override_compatible(const object *marker, const object* pl)
434 root 1.1 {
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     }