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

# Content
1 /*
2 * 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
25 #include <cassert>
26
27 #include <global.h>
28 #include <funcpoint.h>
29 #include <loader.h>
30
31 #include <tr1/functional>
32 #include <tr1/unordered_map>
33
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 bool loading_arch; // ugly flag to object laoder etc. to suppress/request special processing
43
44 // the hashtable
45 typedef std::tr1::unordered_map
46 <
47 const char *,
48 arch_ptr,
49 str_hash,
50 str_equal,
51 slice_allocator< std::pair<const char *const, arch_ptr> >
52 > HT;
53
54 static HT ht (5000);
55 static std::vector<archetype *> archetypes;
56
57 /**
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 archetype *
69 find_archetype_by_object_name (const char *name)
70 {
71 shstr_cmp name_cmp (name);
72
73 for (archetype *at = first_archetype; at; at = at->next)
74 if (at->clone.name == name_cmp)
75 return at;
76
77 return 0;
78 }
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 archetype *
86 find_archetype_by_object_type_name (int type, const char *name)
87 {
88 shstr_cmp name_cmp (name);
89
90 for (archetype *at = first_archetype; at; at = at->next)
91 if (at->clone.name == name_cmp && at->clone.type == type)
92 return at;
93
94 return 0;
95 }
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 object *
103 get_archetype_by_skill_name (const char *skill, int type)
104 {
105 shstr_cmp skill_cmp (skill);
106
107 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
111 return 0;
112 }
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 archetype *
122 get_archetype_by_type_subtype (int type, int subtype)
123 {
124 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
128 return 0;
129 }
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 object *
144 get_archetype_by_object_name (const char *name)
145 {
146 char tmpname[MAX_BUF];
147 int i;
148
149 assign (tmpname, name);
150
151 for (i = strlen (tmpname); i > 0; i--)
152 {
153 tmpname[i] = 0;
154
155 if (archetype *at = find_archetype_by_object_name (tmpname))
156 return arch_to_object (at);
157 }
158
159 return create_singularity (name);
160 }
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 int
180 item_matched_string (object *pl, object *op, const char *name)
181 {
182 char *cp, local_name[MAX_BUF];
183 int count, retval = 0;
184
185 assign (local_name, name); /* strtok is destructive to name */
186
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 retval = 6;
259 else if (count == 1 && !strcasecmp (op->name, cp))
260 retval = 6;
261 /* 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
273 return retval;
274 }
275 }
276
277 return 0;
278 }
279
280 archetype::archetype ()
281 {
282 clone.arch = this;
283
284 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
288 archetype::~archetype ()
289 {
290 //TODO: nuke ->more's
291 }
292
293 static void
294 unlink (archetype *at)
295 {
296 if (at->head)
297 at = at->head;
298
299 // destroy this archetype's link, making singletons out of its parts
300 while (at)
301 {
302 archetype *more = at->more;
303 at->clone.destroy_inv ();
304 at->head = at->more = 0;
305 at = more;
306 }
307 }
308
309 // dire hack, need to rationalise
310 void
311 overwrite (archetype *at, object *op)
312 {
313 at->clone = *op;
314 at->clone.arch = at;
315
316 at->clone.inv = op->inv; op->inv = 0;
317
318 op->destroy ();
319 }
320
321 archetype *
322 archetype::read (object_thawer &f)
323 {
324 assert (f.kw == KW_object);
325
326 loading_arch = true; // hack to tell parse_kv et al. to behave
327
328 typedef std::pair<archetype *, object *> part;
329 std::vector<part> parts;
330
331 coroapi::cede_to_tick_every (100);
332
333 for (;;)
334 {
335 object *op = object::create ();
336 archetype *at = get (f.get_str ());
337 f.get (op->name);
338 f.next ();
339
340 #if 0
341 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 #endif
352
353 if (!op->parse_kv (f))
354 goto fail;
355
356 parts.push_back (std::make_pair (at, op));
357
358 if (f.kw != KW_more)
359 break;
360
361 f.next ();
362
363 if (f.kw != KW_object)
364 {
365 f.parse_error ("more object");
366 goto fail;
367 }
368 }
369
370 {
371 archetype *head = parts.front ().first;
372
373 // check that all archetypes belong to the same object or are heads
374 for (auto (p, parts.begin ()); p != parts.end (); ++p)
375 {
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 if (!head->linked)
407 {
408 head->linked = true;
409 head->next = first_archetype;
410 first_archetype = head;
411 }
412
413 // reassemble new chain
414 archetype *prev = head;
415 for (auto (p, parts.begin () + 1); p != parts.end (); ++p)
416 {
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
431 loading_arch = false;
432 return head;
433 }
434
435 fail:
436 for (auto (p, parts.begin ()); p != parts.end (); ++p)
437 p->second->destroy (true);
438
439 loading_arch = false;
440 return 0;
441 }
442
443 /*
444 * Initialize global archtype pointers:
445 */
446 void
447 init_archetype_pointers ()
448 {
449 ring_arch = archetype::find ("ring");
450 amulet_arch = archetype::find ("amulet");
451 staff_arch = archetype::find ("staff");
452 crown_arch = archetype::find ("crown");
453 empty_archetype = archetype::find ("empty_archetype");
454 }
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 object *
461 arch_to_object (archetype *at)
462 {
463 if (!at)
464 {
465 LOG (llevError, "Couldn't find archetype.\n");
466 return 0;
467 }
468
469 object *op = at->clone.clone ();
470 op->arch = at;
471 op->instantiate ();
472
473 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 object *
483 create_singularity (const char *name)
484 {
485 object *op;
486 char buf[MAX_BUF];
487
488 sprintf (buf, "%s (%s)", ARCH_SINGULARITY, name);
489 op = object::create ();
490 op->name = op->name_pl = buf;
491 SET_FLAG (op, FLAG_NO_PICK);
492 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 object *
500 get_archetype (const char *name)
501 {
502 archetype *at = archetype::find (name);
503
504 if (!at)
505 return create_singularity (name);
506
507 return arch_to_object (at);
508 }
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 archetype *
515 archetype::find (const char *name)
516 {
517 if (!name)
518 return 0;
519
520 auto (i, ht.find (name));
521
522 if (i == ht.end ())
523 return 0;
524 else
525 return i->second;
526 }
527
528 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 /*
544 * Adds an archetype to the hashtable.
545 */
546 void
547 archetype::hash_add ()
548 {
549 ht.insert (std::make_pair (name, this));
550 }
551
552 void
553 archetype::hash_del ()
554 {
555 ht.erase (name);
556 }
557
558 /*
559 * Returns the first archetype using the given type.
560 * Used in treasure-generation.
561 */
562 archetype *
563 type_to_archetype (int type)
564 {
565 for (archetype *at = first_archetype; at; at = at->more == 0 ? at->next : at->more)
566 if (at->clone.type == type)
567 return at;
568
569 return 0;
570 }
571
572 /*
573 * Returns a new object copied from the first archetype matching
574 * the given type.
575 * Used in treasure-generation.
576 */
577 object *
578 clone_arch (int type)
579 {
580 archetype *at;
581
582 if ((at = type_to_archetype (type)) == NULL)
583 {
584 LOG (llevError, "Can't clone archetype %d\n", type);
585 return 0;
586 }
587
588 object *op = at->clone.clone ();
589 op->instantiate ();
590 return op;
591 }
592
593 /*
594 * member: make instance from class
595 */
596
597 object *
598 object_create_arch (archetype *at)
599 {
600 object *op, *prev = 0, *head = 0;
601
602 while (at)
603 {
604 op = arch_to_object (at);
605 op->x = at->clone.x;
606 op->y = at->clone.y;
607
608 if (head)
609 op->head = head, prev->more = op;
610
611 if (!head)
612 head = op;
613
614 prev = op;
615 at = at->more;
616 }
617
618 return (head);
619 }
620