ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/arch.C
Revision: 1.56
Committed: Wed Apr 18 07:59:55 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.55: +2 -0 lines
Log Message:
commented out inherit functionality in the server fort he time being, it is just too beatiful to remove and might come in handy when we put archetypes in maps (which would be trivial to implement by now)

File Contents

# User Rev Content
1 elmex 1.1 /*
2 pippijn 1.37 * CrossFire, A Multiplayer game for X-windows
3     *
4     * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5     * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
6     * Copyright (C) 1992 Frank Tore Johansen
7     *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     *
22     * The authors can be reached via e-mail at <crossfire@schmorp.de>
23     */
24 elmex 1.1
25 root 1.12 #include <cassert>
26    
27 elmex 1.1 #include <global.h>
28     #include <funcpoint.h>
29     #include <loader.h>
30    
31 root 1.38 #include <tr1/functional>
32     #include <tr1/unordered_map>
33 elmex 1.1
34     /* The naming of these functions is really poor - they are all
35     * pretty much named '.._arch_...', but they may more may not
36     * return archetypes. Some make the arch_to_object call, and thus
37     * return an object. Perhaps those should be called 'archob' functions
38     * to denote they return an object derived from the archetype.
39     * MSW 2003-04-29
40     */
41    
42 root 1.46 bool loading_arch; // ugly flag to object laoder etc. to suppress/request special processing
43    
44 root 1.12 // the hashtable
45 root 1.18 typedef std::tr1::unordered_map
46     <
47 root 1.38 const char *,
48 root 1.26 arch_ptr,
49 root 1.38 str_hash,
50     str_equal,
51     slice_allocator< std::pair<const char *const, arch_ptr> >
52 root 1.18 > HT;
53    
54 root 1.38 static HT ht (5000);
55 root 1.46 static std::vector<archetype *> archetypes;
56 root 1.12
57 elmex 1.1 /**
58     * GROS - This function retrieves an archetype given the name that appears
59     * during the game (for example, "writing pen" instead of "stylus").
60     * It does not use the hashtable system, but browse the whole archlist each time.
61     * I suggest not to use it unless you really need it because of performance issue.
62     * It is currently used by scripting extensions (create-object).
63     * Params:
64     * - name: the name we're searching for (ex: "writing pen");
65     * Return value:
66     * - the archetype found or null if nothing was found.
67     */
68 root 1.12 archetype *
69     find_archetype_by_object_name (const char *name)
70     {
71 root 1.39 shstr_cmp name_cmp (name);
72 elmex 1.1
73 root 1.39 for (archetype *at = first_archetype; at; at = at->next)
74     if (at->clone.name == name_cmp)
75     return at;
76 elmex 1.1
77 root 1.39 return 0;
78 elmex 1.1 }
79    
80     /**
81     * This function retrieves an archetype by type and name that appears during
82     * the game. It is basically the same as find_archetype_by_object_name()
83     * except that it considers only items of the given type.
84     */
85 root 1.12 archetype *
86     find_archetype_by_object_type_name (int type, const char *name)
87     {
88 root 1.39 shstr_cmp name_cmp (name);
89 elmex 1.1
90 root 1.39 for (archetype *at = first_archetype; at; at = at->next)
91     if (at->clone.name == name_cmp && at->clone.type == type)
92     return at;
93 elmex 1.1
94 root 1.39 return 0;
95 elmex 1.1 }
96    
97     /* This is a lot like the above function. Instead, we are trying to match
98     * the arch->skill values. type is the type of object to match
99     * against (eg, to only match against skills or only skill objects for example).
100     * If type is -1, ew don't match on type.
101     */
102 root 1.12 object *
103     get_archetype_by_skill_name (const char *skill, int type)
104     {
105 root 1.39 shstr_cmp skill_cmp (skill);
106 elmex 1.1
107 root 1.39 for (archetype *at = first_archetype; at; at = at->next)
108     if (at->clone.skill == skill_cmp && (type == -1 || type == at->clone.type))
109     return arch_to_object (at);
110 root 1.35
111     return 0;
112 elmex 1.1 }
113    
114     /* similiar to above - this returns the first archetype
115     * that matches both the type and subtype. type and subtype
116     * can be -1 to say ignore, but in this case, the match it does
117     * may not be very useful. This function is most useful when
118     * subtypes are known to be unique for a particular type
119     * (eg, skills)
120     */
121 root 1.12 archetype *
122     get_archetype_by_type_subtype (int type, int subtype)
123     {
124 root 1.39 for (archetype *at = first_archetype; at; at = at->next)
125     if ((type == -1 || type == at->clone.type) && (subtype == -1 || subtype == at->clone.subtype))
126     return at;
127 elmex 1.1
128 root 1.39 return 0;
129 elmex 1.1 }
130    
131     /**
132     * GROS - this returns a new object given the name that appears during the game
133     * (for example, "writing pen" instead of "stylus").
134     * Params:
135     * - name: The name we're searching for (ex: "writing pen");
136     * Return value:
137     * - a corresponding object if found; a singularity object if not found.
138     * Note by MSW - it appears that it takes the full name and keeps
139     * shortening it until it finds a match. I re-wrote this so that it
140     * doesn't malloc it each time - not that this function is used much,
141     * but it otherwise had a big memory leak.
142     */
143 root 1.12 object *
144     get_archetype_by_object_name (const char *name)
145     {
146 root 1.17 char tmpname[MAX_BUF];
147     int i;
148    
149     assign (tmpname, name);
150 root 1.12
151     for (i = strlen (tmpname); i > 0; i--)
152     {
153     tmpname[i] = 0;
154 root 1.17
155 root 1.39 if (archetype *at = find_archetype_by_object_name (tmpname))
156 root 1.20 return arch_to_object (at);
157 elmex 1.1 }
158 root 1.17
159 root 1.12 return create_singularity (name);
160 elmex 1.1 }
161    
162     /* This is a subset of the parse_id command. Basically, name can be
163     * a string seperated lists of things to match, with certain keywords.
164     * pl is the player (only needed to set count properly)
165     * op is the item we are trying to match. Calling function takes care
166     * of what action might need to be done and if it is valid
167     * (pickup, drop, etc.) Return NONZERO if we have a match. A higher
168     * value means a better match. 0 means no match.
169     *
170     * Brief outline of the procedure:
171     * We take apart the name variable into the individual components.
172     * cases for 'all' and unpaid are pretty obvious.
173     * Next, we check for a count (either specified in name, or in the
174     * player object.)
175     * If count is 1, make a quick check on the name.
176     * IF count is >1, we need to make plural name. Return if match.
177     * Last, make a check on the full name.
178     */
179 root 1.12 int
180 root 1.15 item_matched_string (object *pl, object *op, const char *name)
181 elmex 1.1 {
182 root 1.22 char *cp, local_name[MAX_BUF];
183     int count, retval = 0;
184 root 1.15
185 root 1.40 assign (local_name, name); /* strtok is destructive to name */
186 root 1.12
187     for (cp = strtok (local_name, ","); cp; cp = strtok (NULL, ","))
188     {
189     while (cp[0] == ' ')
190     ++cp; /* get rid of spaces */
191    
192     /* LOG(llevDebug,"Trying to match %s\n", cp); */
193     /* All is a very generic match - low match value */
194     if (!strcmp (cp, "all"))
195     return 1;
196    
197     /* unpaid is a little more specific */
198     if (!strcmp (cp, "unpaid") && QUERY_FLAG (op, FLAG_UNPAID))
199     return 2;
200     if (!strcmp (cp, "cursed") && QUERY_FLAG (op, FLAG_KNOWN_CURSED) && (QUERY_FLAG (op, FLAG_CURSED) || QUERY_FLAG (op, FLAG_DAMNED)))
201     return 2;
202    
203     if (!strcmp (cp, "unlocked") && !QUERY_FLAG (op, FLAG_INV_LOCKED))
204     return 2;
205    
206     /* Allow for things like '100 arrows' */
207     if ((count = atoi (cp)) != 0)
208     {
209     cp = strchr (cp, ' ');
210     while (cp && cp[0] == ' ')
211     ++cp; /* get rid of spaces */
212     }
213     else
214     {
215     if (pl->type == PLAYER)
216     count = pl->contr->count;
217     else
218     count = 0;
219     }
220    
221     if (!cp || cp[0] == '\0' || count < 0)
222     return 0;
223    
224    
225     /* The code here should go from highest retval to lowest. That
226     * is because of the 'else' handling - we don't want to match on
227     * something and set a low retval, even though it may match a higher retcal
228     * later. So keep it in descending order here, so we try for the best
229     * match first, and work downward.
230     */
231     if (!strcasecmp (cp, query_name (op)))
232     retval = 20;
233     else if (!strcasecmp (cp, query_short_name (op)))
234     retval = 18;
235     else if (!strcasecmp (cp, query_base_name (op, 0)))
236     retval = 16;
237     else if (!strcasecmp (cp, query_base_name (op, 1)))
238     retval = 16;
239     else if (op->custom_name && !strcasecmp (cp, op->custom_name))
240     retval = 15;
241     else if (!strncasecmp (cp, query_base_name (op, 0), strlen (cp)))
242     retval = 14;
243     else if (!strncasecmp (cp, query_base_name (op, 1), strlen (cp)))
244     retval = 14;
245     /* Do substring checks, so things like 'Str+1' will match.
246     * retval of these should perhaps be lower - they are lower
247     * then the specific strcasecmp aboves, but still higher than
248     * some other match criteria.
249     */
250     else if (strstr (query_base_name (op, 1), cp))
251     retval = 12;
252     else if (strstr (query_base_name (op, 0), cp))
253     retval = 12;
254     else if (strstr (query_short_name (op), cp))
255     retval = 12;
256     /* Check against plural/non plural based on count. */
257     else if (count > 1 && !strcasecmp (cp, op->name_pl))
258 root 1.23 retval = 6;
259 root 1.12 else if (count == 1 && !strcasecmp (op->name, cp))
260 root 1.23 retval = 6;
261 root 1.12 /* base name matched - not bad */
262     else if (strcasecmp (cp, op->name) == 0 && !count)
263     retval = 4;
264     /* Check for partial custom name, but give a real low priority */
265     else if (op->custom_name && strstr (op->custom_name, cp))
266     retval = 3;
267    
268     if (retval)
269     {
270     if (pl->type == PLAYER)
271     pl->contr->count = count;
272 root 1.23
273 root 1.12 return retval;
274 root 1.7 }
275 elmex 1.1 }
276 root 1.23
277 root 1.12 return 0;
278 elmex 1.1 }
279    
280 root 1.46 archetype::archetype ()
281 root 1.12 {
282 root 1.46 clone.arch = this;
283 root 1.12
284 root 1.46 CLEAR_FLAG (&clone, FLAG_FREED); /* This shouldn't matter, since copy_to */
285     SET_FLAG (&clone, FLAG_REMOVED); /* doesn't copy these flags... */
286     }
287 root 1.12
288 root 1.46 archetype::~archetype ()
289     {
290     //TODO: nuke ->more's
291 elmex 1.1 }
292    
293 root 1.46 static void
294     unlink (archetype *at)
295 elmex 1.1 {
296 root 1.46 if (at->head)
297     at = at->head;
298 elmex 1.1
299 root 1.46 // destroy this archetype's link, making singletons out of its parts
300     while (at)
301 root 1.12 {
302 root 1.46 archetype *more = at->more;
303     at->clone.destroy_inv ();
304     at->head = at->more = 0;
305     at = more;
306 elmex 1.1 }
307     }
308    
309 root 1.46 // dire hack, need to rationalise
310     void
311     overwrite (archetype *at, object *op)
312 root 1.12 {
313 root 1.46 at->clone = *op;
314     at->clone.arch = at;
315 root 1.55
316 root 1.49 at->clone.inv = op->inv; op->inv = 0;
317    
318     op->destroy ();
319 elmex 1.1 }
320    
321 root 1.53 archetype *
322     archetype::read (object_thawer &f)
323 root 1.12 {
324 root 1.43 assert (f.kw == KW_object);
325    
326 root 1.53 loading_arch = true; // hack to tell parse_kv et al. to behave
327    
328 root 1.49 typedef std::pair<archetype *, object *> part;
329     std::vector<part> parts;
330 root 1.12
331 root 1.52 coroapi::cede_to_tick_every (100);
332    
333 root 1.49 for (;;)
334 root 1.43 {
335 root 1.54 object *op = object::create ();
336 root 1.49 archetype *at = get (f.get_str ());
337 root 1.54 f.get (op->name);
338     f.next ();
339 root 1.49
340 root 1.56 #if 0
341 root 1.55 if (f.kw == KW_inherit)
342     {
343     if (archetype *at = find (f.get_str ()))
344     *op = at->clone;
345     else
346     LOG (llevError, "archetype '%s' tries to inherit from non-existent archetype '%s'.\n",
347     &at->name, f.get_str ());
348    
349     f.next ();
350     }
351 root 1.56 #endif
352 root 1.55
353 root 1.49 if (!op->parse_kv (f))
354     goto fail;
355    
356     parts.push_back (std::make_pair (at, op));
357 root 1.12
358 root 1.49 if (f.kw != KW_more)
359     break;
360 root 1.46
361 root 1.43 f.next ();
362 root 1.54
363     if (f.kw != KW_object)
364     {
365     f.parse_error ("more object");
366     goto fail;
367     }
368 root 1.49 }
369 root 1.43
370 root 1.49 {
371     archetype *head = parts.front ().first;
372 root 1.12
373 root 1.49 // check that all archetypes belong to the same object or are heads
374 root 1.51 for (auto (p, parts.begin ()); p != parts.end (); ++p)
375 root 1.49 {
376     archetype *at = p->first;
377    
378     if (at->head != head && at->head)
379     {
380     LOG (llevError, "%s: unable to overwrite foreign non-head archetype with non-head archetype\n", &at->name);
381     goto fail;
382     }
383    
384     if (at->next && at != head)
385     {
386     LOG (llevError, "%s: unable to overwrite foreign head archetype with non-head archetype\n", &at->name);
387     goto fail;
388     }
389     }
390    
391     // sever chain of existing head object
392     for (archetype *more, *at = head; at; at = more)
393     {
394     more = at->more;
395    
396     at->head = 0;
397     at->more = 0;
398     }
399    
400     // replace/update head
401     overwrite (head, parts.front ().second);
402     head->tail_x = 0;
403     head->tail_y = 0;
404    
405     // link into list of heads, if not already there
406 root 1.50 if (!head->linked)
407 root 1.49 {
408 root 1.50 head->linked = true;
409 root 1.49 head->next = first_archetype;
410     first_archetype = head;
411     }
412    
413     // reassemble new chain
414     archetype *prev = head;
415 root 1.51 for (auto (p, parts.begin () + 1); p != parts.end (); ++p)
416 root 1.49 {
417     archetype *at = p->first;
418     overwrite (at, p->second);
419    
420     if (at->clone.x > head->tail_x) head->tail_x = at->clone.x;
421     if (at->clone.y > head->tail_y) head->tail_y = at->clone.y;
422    
423     at->head = head;
424     at->clone.head = &head->clone;
425     prev->more = at;
426     prev->clone.more = &at->clone;
427    
428     prev = at;
429     }
430 root 1.53
431     loading_arch = false;
432     return head;
433 root 1.49 }
434 root 1.43
435 root 1.49 fail:
436 root 1.51 for (auto (p, parts.begin ()); p != parts.end (); ++p)
437 root 1.49 p->second->destroy (true);
438 root 1.43
439 root 1.53 loading_arch = false;
440     return 0;
441 root 1.43 }
442    
443     /*
444 root 1.53 * Initialize global archtype pointers:
445 root 1.43 */
446 root 1.53 void
447     init_archetype_pointers ()
448 root 1.43 {
449 root 1.53 ring_arch = archetype::find ("ring");
450     amulet_arch = archetype::find ("amulet");
451     staff_arch = archetype::find ("staff");
452     crown_arch = archetype::find ("crown");
453 root 1.48 empty_archetype = archetype::find ("empty_archetype");
454 elmex 1.1 }
455    
456     /*
457     * Creates and returns a new object which is a copy of the given archetype.
458     * This function returns NULL on failure.
459     */
460 root 1.12 object *
461 root 1.15 arch_to_object (archetype *at)
462 root 1.12 {
463 root 1.43 if (!at)
464 root 1.12 {
465 root 1.53 LOG (llevError, "Couldn't find archetype.\n");
466     return 0;
467 root 1.12 }
468 root 1.15
469 root 1.43 object *op = at->clone.clone ();
470 root 1.15 op->arch = at;
471 root 1.2 op->instantiate ();
472 root 1.53
473 elmex 1.1 return op;
474     }
475    
476     /*
477     * Creates an object. This function is called by get_archetype()
478     * if it fails to find the appropriate archetype.
479     * Thus get_archetype() will be guaranteed to always return
480     * an object, and never NULL.
481     */
482 root 1.12 object *
483     create_singularity (const char *name)
484     {
485 root 1.22 object *op;
486 root 1.20 char buf[MAX_BUF];
487 root 1.15
488 root 1.12 sprintf (buf, "%s (%s)", ARCH_SINGULARITY, name);
489 root 1.29 op = object::create ();
490 root 1.10 op->name = op->name_pl = buf;
491 root 1.12 SET_FLAG (op, FLAG_NO_PICK);
492 elmex 1.1 return op;
493     }
494    
495     /*
496     * Finds which archetype matches the given name, and returns a new
497     * object containing a copy of the archetype.
498     */
499 root 1.12 object *
500     get_archetype (const char *name)
501     {
502 root 1.20 archetype *at = archetype::find (name);
503 root 1.15
504 root 1.20 if (!at)
505 root 1.12 return create_singularity (name);
506 root 1.15
507 root 1.12 return arch_to_object (at);
508 elmex 1.1 }
509    
510     /*
511     * Finds, using the hashtable, which archetype matches the given name.
512     * returns a pointer to the found archetype, otherwise NULL.
513     */
514 root 1.12 archetype *
515 root 1.20 archetype::find (const char *name)
516 root 1.12 {
517     if (!name)
518     return 0;
519    
520 root 1.51 auto (i, ht.find (name));
521 root 1.12
522     if (i == ht.end ())
523     return 0;
524     else
525     return i->second;
526 elmex 1.1 }
527    
528 root 1.46 archetype *
529     archetype::get (const char *name)
530     {
531     archetype *at = find (name);
532    
533     if (!at)
534     {
535     archetypes.push_back (at = new archetype);
536     at->name = name;
537     at->hash_add ();
538     }
539    
540     return at;
541     }
542    
543 elmex 1.1 /*
544     * Adds an archetype to the hashtable.
545     */
546 root 1.26 void
547     archetype::hash_add ()
548     {
549 root 1.38 ht.insert (std::make_pair (name, this));
550 root 1.26 }
551 elmex 1.1
552 root 1.26 void
553     archetype::hash_del ()
554 root 1.12 {
555 root 1.38 ht.erase (name);
556 elmex 1.1 }
557    
558     /*
559     * Returns the first archetype using the given type.
560     * Used in treasure-generation.
561     */
562 root 1.12 archetype *
563     type_to_archetype (int type)
564     {
565 root 1.46 for (archetype *at = first_archetype; at; at = at->more == 0 ? at->next : at->more)
566 root 1.12 if (at->clone.type == type)
567 elmex 1.1 return at;
568 root 1.20
569     return 0;
570 elmex 1.1 }
571    
572     /*
573     * Returns a new object copied from the first archetype matching
574     * the given type.
575     * Used in treasure-generation.
576     */
577 root 1.12 object *
578     clone_arch (int type)
579     {
580 root 1.20 archetype *at;
581 elmex 1.1
582 root 1.12 if ((at = type_to_archetype (type)) == NULL)
583     {
584     LOG (llevError, "Can't clone archetype %d\n", type);
585 root 1.30 return 0;
586 root 1.12 }
587 root 1.20
588 root 1.30 object *op = at->clone.clone ();
589 root 1.3 op->instantiate ();
590 elmex 1.1 return op;
591     }
592    
593     /*
594     * member: make instance from class
595     */
596    
597 root 1.12 object *
598 root 1.15 object_create_arch (archetype *at)
599 elmex 1.1 {
600 root 1.20 object *op, *prev = 0, *head = 0;
601 elmex 1.1
602 root 1.12 while (at)
603     {
604     op = arch_to_object (at);
605     op->x = at->clone.x;
606     op->y = at->clone.y;
607 root 1.20
608 root 1.12 if (head)
609     op->head = head, prev->more = op;
610 root 1.20
611 root 1.12 if (!head)
612     head = op;
613 root 1.20
614 root 1.12 prev = op;
615     at = at->more;
616 elmex 1.1 }
617 root 1.20
618 root 1.12 return (head);
619 elmex 1.1 }
620