ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/arch.C
Revision: 1.68
Committed: Sun Jul 1 05:00:17 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.67: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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