ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
Revision: 1.163
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.162: +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

# User Rev Content
1 elmex 1.1 /*
2 root 1.163 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 pippijn 1.116 *
4 root 1.157 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2001,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.116 *
8 root 1.163 * 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 pippijn 1.116 *
13 root 1.163 * 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 pippijn 1.116 *
18 root 1.163 * 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 root 1.157 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 pippijn 1.116 */
23 elmex 1.1
24     /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
25     sub/add_weight will transcend the environment updating the carrying
26     variable. */
27     #include <global.h>
28 root 1.28 #include <stdio.h>
29     #include <sys/types.h>
30     #include <sys/uio.h>
31 elmex 1.1 #include <object.h>
32     #include <funcpoint.h>
33 root 1.146 #include <sproto.h>
34 elmex 1.1 #include <loader.h>
35 root 1.28
36 root 1.68 #include <bitset>
37    
38 elmex 1.1 int nrofallocobjects = 0;
39 root 1.39 static UUID uuid;
40     const uint64 UUID_SKIP = 1<<19;
41 elmex 1.1
42 root 1.108 objectvec objects;
43     activevec actives;
44 elmex 1.1
45 root 1.24 short freearr_x[SIZEOFFREE] = { 0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1,
46     0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
47     };
48     short freearr_y[SIZEOFFREE] = { 0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2,
49     -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3
50     };
51     int maxfree[SIZEOFFREE] = { 0, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45,
52     48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49
53     };
54     int freedir[SIZEOFFREE] = {
55     0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8,
56     1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
57     };
58 elmex 1.1
59 root 1.39 static void
60     write_uuid (void)
61     {
62     char filename1[MAX_BUF], filename2[MAX_BUF];
63    
64     sprintf (filename1, "%s/uuid", settings.localdir);
65     sprintf (filename2, "%s/uuid~", settings.localdir);
66    
67     FILE *fp;
68    
69     if (!(fp = fopen (filename2, "w")))
70     {
71     LOG (llevError, "ERROR: cannot open %s for writing, unable to write UUID!\n", filename2);
72     return;
73     }
74    
75     fprintf (fp, "<1,%llx>\n", (unsigned long long)uuid.seq + UUID_SKIP * 2);
76     fclose (fp);
77     rename (filename2, filename1);
78     }
79    
80     static void
81     read_uuid (void)
82     {
83     char filename[MAX_BUF];
84    
85     sprintf (filename, "%s/uuid", settings.localdir);
86    
87     FILE *fp;
88    
89     if (!(fp = fopen (filename, "r")))
90     {
91     if (errno == ENOENT)
92     {
93     LOG (llevInfo, "RESET uid to 1\n");
94     uuid.seq = 0;
95     write_uuid ();
96     return;
97     }
98    
99     LOG (llevError, "FATAL: cannot open %s for reading!\n", filename);
100     _exit (1);
101     }
102    
103     int version;
104     unsigned long long uid;
105     if (2 != fscanf (fp, "<%d,%llx>\n", &version, &uid) || version != 1)
106     {
107     LOG (llevError, "FATAL: error reading uid from %s!\n", filename);
108     _exit (1);
109     }
110    
111     uuid.seq = uid;
112     write_uuid ();
113 root 1.61 LOG (llevDebug, "read UID: %" PRId64 "\n", uid);
114 root 1.39 fclose (fp);
115     }
116    
117     UUID
118     gen_uuid ()
119     {
120     UUID uid;
121    
122     uid.seq = ++uuid.seq;
123    
124     if (!(uuid.seq & (UUID_SKIP - 1)))
125     write_uuid ();
126    
127     return uid;
128     }
129    
130     void
131     init_uuid ()
132     {
133     read_uuid ();
134     }
135    
136 elmex 1.1 /* Returns TRUE if every key_values in wants has a partner with the same value in has. */
137 root 1.24 static int
138     compare_ob_value_lists_one (const object *wants, const object *has)
139     {
140     key_value *wants_field;
141    
142     /* n-squared behaviour (see get_ob_key_link()), but I'm hoping both
143     * objects with lists are rare, and lists stay short. If not, use a
144     * different structure or at least keep the lists sorted...
145     */
146    
147     /* For each field in wants, */
148 root 1.86 for (wants_field = wants->key_values; wants_field; wants_field = wants_field->next)
149 root 1.24 {
150     key_value *has_field;
151    
152     /* Look for a field in has with the same key. */
153     has_field = get_ob_key_link (has, wants_field->key);
154    
155     if (has_field == NULL)
156     {
157     /* No field with that name. */
158     return FALSE;
159     }
160    
161     /* Found the matching field. */
162     if (has_field->value != wants_field->value)
163     {
164     /* Values don't match, so this half of the comparison is false. */
165     return FALSE;
166     }
167    
168     /* If we get here, we found a match. Now for the next field in wants. */
169 elmex 1.1 }
170 root 1.24
171     /* If we get here, every field in wants has a matching field in has. */
172     return TRUE;
173 elmex 1.1 }
174    
175     /* Returns TRUE if ob1 has the same key_values as ob2. */
176 root 1.24 static int
177     compare_ob_value_lists (const object *ob1, const object *ob2)
178     {
179     /* However, there may be fields in has which aren't partnered in wants,
180     * so we need to run the comparison *twice*. :(
181     */
182     return compare_ob_value_lists_one (ob1, ob2) && compare_ob_value_lists_one (ob2, ob1);
183 elmex 1.1 }
184    
185     /* Function examines the 2 objects given to it, and returns true if
186     * they can be merged together.
187     *
188     * Note that this function appears a lot longer than the macro it
189     * replaces - this is mostly for clarity - a decent compiler should hopefully
190     * reduce this to the same efficiency.
191     *
192 root 1.66 * Check nrof variable *before* calling can_merge()
193 elmex 1.1 *
194     * Improvements made with merge: Better checking on potion, and also
195     * check weight
196     */
197 root 1.66 bool object::can_merge_slow (object *ob1, object *ob2)
198 root 1.16 {
199     /* A couple quicksanity checks */
200 root 1.66 if (ob1 == ob2
201     || ob1->type != ob2->type
202     || ob1->speed != ob2->speed
203     || ob1->value != ob2->value
204     || ob1->name != ob2->name)
205 root 1.16 return 0;
206    
207 root 1.66 //TODO: this ain't working well, use nicer and correct overflow check
208 root 1.16 /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
209     * value could not be stored in a sint32 (which unfortunately sometimes is
210     * used to store nrof).
211     */
212     if (ob1->nrof + ob2->nrof >= 1UL << 31)
213     return 0;
214    
215     /* If the objects have been identified, set the BEEN_APPLIED flag.
216     * This is to the comparison of the flags below will be OK. We
217     * just can't ignore the been applied or identified flags, as they
218     * are not equal - just if it has been identified, the been_applied
219     * flags lose any meaning.
220     */
221     if (QUERY_FLAG (ob1, FLAG_IDENTIFIED))
222     SET_FLAG (ob1, FLAG_BEEN_APPLIED);
223    
224     if (QUERY_FLAG (ob2, FLAG_IDENTIFIED))
225     SET_FLAG (ob2, FLAG_BEEN_APPLIED);
226 elmex 1.1
227 root 1.80 if ((ob1->flag ^ ob2->flag).reset (FLAG_INV_LOCKED).reset (FLAG_CLIENT_SENT).any ()
228 root 1.68 || ob1->arch != ob2->arch
229     || ob1->name != ob2->name
230     || ob1->title != ob2->title
231     || ob1->msg != ob2->msg
232     || ob1->weight != ob2->weight
233     || memcmp (&ob1->resist, &ob2->resist, sizeof (ob1->resist))
234     || memcmp (&ob1->stats , &ob2->stats , sizeof (ob1->stats) )
235     || ob1->attacktype != ob2->attacktype
236     || ob1->magic != ob2->magic
237     || ob1->slaying != ob2->slaying
238     || ob1->skill != ob2->skill
239     || ob1->value != ob2->value
240     || ob1->animation_id != ob2->animation_id
241     || ob1->client_type != ob2->client_type
242     || ob1->materialname != ob2->materialname
243     || ob1->lore != ob2->lore
244     || ob1->subtype != ob2->subtype
245     || ob1->move_type != ob2->move_type
246     || ob1->move_block != ob2->move_block
247     || ob1->move_allow != ob2->move_allow
248     || ob1->move_on != ob2->move_on
249     || ob1->move_off != ob2->move_off
250     || ob1->move_slow != ob2->move_slow
251     || ob1->move_slow_penalty != ob2->move_slow_penalty)
252 root 1.16 return 0;
253    
254     /* This is really a spellbook check - really, we should
255     * check all objects in the inventory.
256     */
257     if (ob1->inv || ob2->inv)
258     {
259     /* if one object has inventory but the other doesn't, not equiv */
260     if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
261 root 1.24 return 0;
262 root 1.16
263     /* Now check to see if the two inventory objects could merge */
264 root 1.66 if (!object::can_merge (ob1->inv, ob2->inv))
265 root 1.24 return 0;
266 root 1.16
267     /* inventory ok - still need to check rest of this object to see
268     * if it is valid.
269     */
270     }
271 elmex 1.1
272 root 1.16 /* Don't merge objects that are applied. With the new 'body' code,
273     * it is possible for most any character to have more than one of
274     * some items equipped, and we don't want those to merge.
275     */
276     if (QUERY_FLAG (ob1, FLAG_APPLIED) || QUERY_FLAG (ob2, FLAG_APPLIED))
277     return 0;
278 elmex 1.1
279 root 1.16 /* Note sure why the following is the case - either the object has to
280     * be animated or have a very low speed. Is this an attempted monster
281     * check?
282     */
283 elmex 1.97 if (!QUERY_FLAG (ob1, FLAG_ANIMATE) && ob1->has_active_speed ())
284 root 1.16 return 0;
285 elmex 1.1
286 root 1.16 switch (ob1->type)
287     {
288 root 1.29 case SCROLL:
289     if (ob1->level != ob2->level)
290     return 0;
291     break;
292 root 1.16 }
293 elmex 1.1
294 root 1.16 if (ob1->key_values != NULL || ob2->key_values != NULL)
295     {
296     /* At least one of these has key_values. */
297     if ((ob1->key_values == NULL) != (ob2->key_values == NULL))
298 root 1.24 /* One has fields, but the other one doesn't. */
299     return 0;
300 root 1.16 else if (!compare_ob_value_lists (ob1, ob2))
301 root 1.24 return 0;
302 elmex 1.1 }
303 root 1.16
304     //TODO: generate an event or call into perl for additional checks
305     if (ob1->self || ob2->self)
306     {
307     ob1->optimise ();
308     ob2->optimise ();
309    
310     if (ob1->self || ob2->self)
311 root 1.24 return 0;
312 elmex 1.1 }
313    
314 root 1.16 /* Everything passes, must be OK. */
315     return 1;
316 elmex 1.1 }
317 root 1.24
318 elmex 1.1 /*
319     * sum_weight() is a recursive function which calculates the weight
320     * an object is carrying. It goes through in figures out how much
321     * containers are carrying, and sums it up.
322     */
323 root 1.28 long
324 root 1.24 sum_weight (object *op)
325     {
326 root 1.28 long sum;
327 elmex 1.1 object *inv;
328 root 1.24
329 root 1.142 for (sum = 0, inv = op->inv; inv; inv = inv->below)
330 root 1.24 {
331     if (inv->inv)
332     sum_weight (inv);
333 root 1.142
334 root 1.24 sum += inv->carrying + inv->weight * (inv->nrof ? inv->nrof : 1);
335     }
336 root 1.37
337 elmex 1.1 if (op->type == CONTAINER && op->stats.Str)
338 root 1.24 sum = (sum * (100 - op->stats.Str)) / 100;
339 root 1.37
340 root 1.24 if (op->carrying != sum)
341 elmex 1.1 op->carrying = sum;
342 root 1.37
343 elmex 1.1 return sum;
344     }
345    
346     /**
347     * Return the outermost environment object for a given object.
348     */
349    
350 root 1.24 object *
351     object_get_env_recursive (object *op)
352     {
353     while (op->env != NULL)
354     op = op->env;
355     return op;
356 elmex 1.1 }
357    
358     /*
359     * Used by: Crossedit: dump. Server DM commands: dumpbelow, dump.
360 root 1.11 * Some error messages.
361 elmex 1.1 * The result of the dump is stored in the static global errmsg array.
362     */
363 root 1.53 char *
364 root 1.24 dump_object (object *op)
365     {
366 root 1.53 if (!op)
367     return strdup ("[NULLOBJ]");
368 elmex 1.1
369 root 1.53 object_freezer freezer;
370 root 1.133 op->write (freezer);
371 root 1.53 return freezer.as_string ();
372 elmex 1.1 }
373    
374     /*
375     * get_nearest_part(multi-object, object 2) returns the part of the
376     * multi-object 1 which is closest to the second object.
377     * If it's not a multi-object, it is returned.
378     */
379    
380 root 1.24 object *
381     get_nearest_part (object *op, const object *pl)
382     {
383     object *tmp, *closest;
384     int last_dist, i;
385    
386     if (op->more == NULL)
387 elmex 1.1 return op;
388 root 1.24 for (last_dist = distance (op, pl), closest = op, tmp = op->more; tmp != NULL; tmp = tmp->more)
389     if ((i = distance (tmp, pl)) < last_dist)
390     closest = tmp, last_dist = i;
391 elmex 1.1 return closest;
392     }
393    
394     /*
395     * Returns the object which has the count-variable equal to the argument.
396     */
397 root 1.24 object *
398     find_object (tag_t i)
399     {
400 root 1.112 for_all_objects (op)
401     if (op->count == i)
402     return op;
403    
404     return 0;
405 elmex 1.1 }
406    
407     /*
408     * Returns the first object which has a name equal to the argument.
409     * Used only by the patch command, but not all that useful.
410     * Enables features like "patch <name-of-other-player> food 999"
411     */
412 root 1.24 object *
413     find_object_name (const char *str)
414     {
415 root 1.35 shstr_cmp str_ (str);
416 elmex 1.1 object *op;
417 root 1.24
418 root 1.108 for_all_objects (op)
419 root 1.35 if (op->name == str_)
420 elmex 1.1 break;
421 root 1.11
422 elmex 1.1 return op;
423     }
424    
425 root 1.24 void
426     free_all_object_data ()
427 root 1.14 {
428     LOG (llevDebug, "%d allocated objects\n", nrofallocobjects);
429 elmex 1.1 }
430    
431     /*
432     * Sets the owner and sets the skill and exp pointers to owner's current
433     * skill and experience objects.
434     */
435 root 1.24 void
436 root 1.30 object::set_owner (object *owner)
437 elmex 1.1 {
438 root 1.30 if (!owner)
439 root 1.24 return;
440    
441     /* next line added to allow objects which own objects */
442     /* Add a check for ownercounts in here, as I got into an endless loop
443     * with the fireball owning a poison cloud which then owned the
444     * fireball. I believe that was caused by one of the objects getting
445     * freed and then another object replacing it. Since the ownercounts
446     * didn't match, this check is valid and I believe that cause is valid.
447     */
448 root 1.30 while (owner->owner)
449 root 1.24 owner = owner->owner;
450 elmex 1.1
451 root 1.30 this->owner = owner;
452 elmex 1.1 }
453    
454 root 1.148 int
455     object::slottype () const
456     {
457     if (type == SKILL)
458     {
459     if (IS_COMBAT_SKILL (subtype)) return slot_combat;
460     if (IS_RANGED_SKILL (subtype)) return slot_ranged;
461     }
462     else
463     {
464     if (slot [body_combat].info) return slot_combat;
465     if (slot [body_range ].info) return slot_ranged;
466     }
467    
468     return slot_none;
469     }
470    
471 root 1.147 bool
472     object::change_weapon (object *ob)
473 root 1.144 {
474     if (current_weapon == ob)
475 root 1.147 return true;
476 root 1.146
477 root 1.150 if (chosen_skill)
478     chosen_skill->flag [FLAG_APPLIED] = false;
479    
480 root 1.144 current_weapon = ob;
481 root 1.147 chosen_skill = !ob || ob->type == SKILL ? ob : find_skill_by_name (this, ob->skill);
482 root 1.146
483 root 1.150 if (chosen_skill)
484     chosen_skill->flag [FLAG_APPLIED] = true;
485    
486 root 1.144 update_stats ();
487 root 1.147
488     if (ob)
489     {
490     // now check wether any body locations became invalid, in which case
491     // we cannot apply the weapon at the moment.
492     for (int i = 0; i < NUM_BODY_LOCATIONS; ++i)
493     if (slot[i].used < 0)
494     {
495     current_weapon = chosen_skill = 0;
496     update_stats ();
497    
498     new_draw_info_format (NDI_UNIQUE, 0, this,
499 root 1.156 "You try to balance all your items at once, "
500     "but the %s is just too much for your body. "
501     "[You need to unapply some items first.]", &ob->name);
502 root 1.147 return false;
503     }
504    
505 root 1.148 //new_draw_info_format (NDI_UNIQUE, 0, this, "You switch to your %s.", &ob->name);
506 root 1.147 }
507     else
508 root 1.148 ;//new_draw_info_format (NDI_UNIQUE, 0, this, "You unwield your weapons.");
509 root 1.147
510 root 1.151 if (ob && !ob->flag [FLAG_APPLIED] && ob->type != SPELL)
511     {
512     LOG (llevError | logBacktrace, "%s changed to unapplied weapon %s",
513     &name, ob->debug_desc ());
514     return false;
515     }
516    
517 root 1.147 return true;
518 root 1.144 }
519    
520 elmex 1.1 /* Zero the key_values on op, decrementing the shared-string
521     * refcounts and freeing the links.
522     */
523 root 1.24 static void
524     free_key_values (object *op)
525 root 1.11 {
526 root 1.137 for (key_value *i = op->key_values; i; )
527 root 1.11 {
528     key_value *next = i->next;
529     delete i;
530 root 1.24
531 root 1.11 i = next;
532 elmex 1.1 }
533 root 1.24
534 root 1.11 op->key_values = 0;
535 elmex 1.1 }
536    
537 root 1.137 object &
538     object::operator =(const object &src)
539 root 1.11 {
540 root 1.137 bool is_freed = flag [FLAG_FREED];
541     bool is_removed = flag [FLAG_REMOVED];
542 root 1.59
543 root 1.137 *(object_copy *)this = src;
544 elmex 1.1
545 root 1.137 flag [FLAG_FREED] = is_freed;
546     flag [FLAG_REMOVED] = is_removed;
547 elmex 1.1
548 root 1.11 /* Copy over key_values, if any. */
549 root 1.137 if (src.key_values)
550 root 1.14 {
551 root 1.23 key_value *tail = 0;
552 root 1.137 key_values = 0;
553 elmex 1.1
554 root 1.137 for (key_value *i = src.key_values; i; i = i->next)
555 root 1.11 {
556     key_value *new_link = new key_value;
557 root 1.8
558 root 1.24 new_link->next = 0;
559     new_link->key = i->key;
560 root 1.11 new_link->value = i->value;
561    
562     /* Try and be clever here, too. */
563 root 1.137 if (!key_values)
564 root 1.11 {
565 root 1.137 key_values = new_link;
566 root 1.11 tail = new_link;
567 root 1.8 }
568 root 1.11 else
569     {
570     tail->next = new_link;
571     tail = new_link;
572     }
573 root 1.14 }
574     }
575 root 1.137 }
576    
577     /*
578     * copy_to first frees everything allocated by the dst object,
579     * and then copies the contents of itself into the second
580     * object, allocating what needs to be allocated. Basically, any
581     * data that is malloc'd needs to be re-malloc/copied. Otherwise,
582     * if the first object is freed, the pointers in the new object
583     * will point at garbage.
584     */
585     void
586     object::copy_to (object *dst)
587     {
588     *dst = *this;
589    
590     if (speed < 0)
591     dst->speed_left = speed_left - rndm ();
592 root 1.2
593 root 1.87 dst->set_speed (dst->speed);
594 elmex 1.1 }
595    
596 root 1.133 void
597     object::instantiate ()
598     {
599     if (!uuid.seq) // HACK
600     uuid = gen_uuid ();
601    
602     speed_left = -0.1f;
603     /* copy the body_info to the body_used - this is only really
604     * need for monsters, but doesn't hurt to do it for everything.
605     * by doing so, when a monster is created, it has good starting
606     * values for the body_used info, so when items are created
607     * for it, they can be properly equipped.
608     */
609 root 1.145 for (int i = NUM_BODY_LOCATIONS; i--; )
610     slot[i].used = slot[i].info;
611 root 1.133
612     attachable::instantiate ();
613     }
614    
615 root 1.65 object *
616     object::clone ()
617     {
618     object *neu = create ();
619     copy_to (neu);
620     return neu;
621     }
622    
623 elmex 1.1 /*
624     * If an object with the IS_TURNABLE() flag needs to be turned due
625     * to the closest player being on the other side, this function can
626     * be called to update the face variable, _and_ how it looks on the map.
627     */
628 root 1.24 void
629     update_turn_face (object *op)
630     {
631 root 1.96 if (!QUERY_FLAG (op, FLAG_IS_TURNABLE) || !op->arch)
632 root 1.24 return;
633 root 1.96
634 root 1.24 SET_ANIMATION (op, op->direction);
635     update_object (op, UP_OBJ_FACE);
636 elmex 1.1 }
637    
638     /*
639     * Updates the speed of an object. If the speed changes from 0 to another
640     * value, or vice versa, then add/remove the object from the active list.
641     * This function needs to be called whenever the speed of an object changes.
642     */
643 root 1.24 void
644 root 1.87 object::set_speed (float speed)
645 root 1.24 {
646 root 1.87 if (flag [FLAG_FREED] && speed)
647 root 1.24 {
648 root 1.87 LOG (llevError, "Object %s is freed but has speed.\n", &name);
649     speed = 0;
650 elmex 1.1 }
651 root 1.31
652 root 1.87 this->speed = speed;
653    
654 elmex 1.97 if (has_active_speed ())
655 root 1.98 activate ();
656 root 1.24 else
657 root 1.98 deactivate ();
658 elmex 1.1 }
659    
660     /*
661 root 1.75 * update_object() updates the the map.
662 elmex 1.1 * It takes into account invisible objects (and represent squares covered
663     * by invisible objects by whatever is below them (unless it's another
664     * invisible object, etc...)
665     * If the object being updated is beneath a player, the look-window
666     * of that player is updated (this might be a suboptimal way of
667     * updating that window, though, since update_object() is called _often_)
668     *
669     * action is a hint of what the caller believes need to be done.
670     * current action are:
671     * UP_OBJ_INSERT: op was inserted
672     * UP_OBJ_REMOVE: op was removed
673     * UP_OBJ_CHANGE: object has somehow changed. In this case, we always update
674     * as that is easier than trying to look at what may have changed.
675     * UP_OBJ_FACE: only the objects face has changed.
676     */
677 root 1.24 void
678     update_object (object *op, int action)
679     {
680     if (op == NULL)
681     {
682     /* this should never happen */
683     LOG (llevDebug, "update_object() called for NULL object.\n");
684     return;
685 elmex 1.1 }
686 root 1.24
687 root 1.75 if (op->env)
688 root 1.24 {
689     /* Animation is currently handled by client, so nothing
690     * to do in this case.
691     */
692     return;
693 elmex 1.1 }
694    
695 root 1.24 /* If the map is saving, don't do anything as everything is
696     * going to get freed anyways.
697     */
698     if (!op->map || op->map->in_memory == MAP_SAVING)
699     return;
700    
701     /* make sure the object is within map boundaries */
702 root 1.83 if (op->x < 0 || op->x >= op->map->width || op->y < 0 || op->y >= op->map->height)
703 root 1.24 {
704     LOG (llevError, "update_object() called for object out of map!\n");
705 elmex 1.1 #ifdef MANY_CORES
706 root 1.24 abort ();
707 elmex 1.1 #endif
708 root 1.24 return;
709 elmex 1.1 }
710    
711 root 1.76 mapspace &m = op->ms ();
712 elmex 1.1
713 root 1.99 if (!(m.flags_ & P_UPTODATE))
714 root 1.75 /* nop */;
715     else if (action == UP_OBJ_INSERT)
716     {
717     // this is likely overkill, TODO: revisit (schmorp)
718     if ((QUERY_FLAG (op, FLAG_BLOCKSVIEW) && !(m.flags_ & P_BLOCKSVIEW))
719     || (QUERY_FLAG (op, FLAG_NO_MAGIC) && !(m.flags_ & P_NO_MAGIC))
720     || (op->type == PLAYER && !(m.flags_ & P_PLAYER))
721     || (op->type == SAFE_GROUND && !(m.flags_ & P_SAFE))
722     || (QUERY_FLAG (op, FLAG_ALIVE) && !(m.flags_ & P_IS_ALIVE))
723     || (QUERY_FLAG (op, FLAG_DAMNED) && !(m.flags_ & P_NO_CLERIC))
724     || (m.move_on | op->move_on ) != m.move_on
725     || (m.move_off | op->move_off ) != m.move_off
726     || (m.move_slow | op->move_slow) != m.move_slow
727     /* This isn't perfect, but I don't expect a lot of objects to
728     * to have move_allow right now.
729     */
730     || ((m.move_block | op->move_block) & ~op->move_allow) != m.move_block
731     || 1) // the above is not strong enough a test to skip updating. los maybe? TODO (Schmorp)
732 root 1.99 m.flags_ = 0;
733 root 1.75 }
734     /* if the object is being removed, we can't make intelligent
735     * decisions, because remove_ob can't really pass the object
736     * that is being removed.
737     */
738 root 1.24 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE)
739 root 1.99 m.flags_ = 0;
740 root 1.24 else if (action == UP_OBJ_FACE)
741 root 1.29 /* Nothing to do for that case */ ;
742 root 1.24 else
743 root 1.27 LOG (llevError, "update_object called with invalid action: %d\n", action);
744 elmex 1.1
745 root 1.75 if (op->more)
746 root 1.24 update_object (op->more, action);
747 elmex 1.1 }
748    
749 root 1.21 object::object ()
750     {
751 root 1.22 SET_FLAG (this, FLAG_REMOVED);
752    
753     expmul = 1.0;
754     face = blank_face;
755     }
756    
757     object::~object ()
758     {
759 root 1.121 unlink ();
760 root 1.119
761 root 1.22 free_key_values (this);
762     }
763    
764 root 1.112 static int object_count;
765    
766 root 1.24 void object::link ()
767 root 1.22 {
768 root 1.112 assert (!index);//D
769 root 1.41 uuid = gen_uuid ();
770 root 1.112 count = ++object_count;
771 root 1.21
772 root 1.109 refcnt_inc ();
773 root 1.108 objects.insert (this);
774 root 1.21 }
775    
776 root 1.24 void object::unlink ()
777 root 1.21 {
778 root 1.121 if (!index)
779     return;
780    
781 root 1.108 objects.erase (this);
782 root 1.109 refcnt_dec ();
783 root 1.98 }
784    
785 root 1.96 void
786 root 1.98 object::activate ()
787 root 1.96 {
788 root 1.98 /* If already on active list, don't do anything */
789 root 1.108 if (active)
790 root 1.98 return;
791    
792 elmex 1.97 if (has_active_speed ())
793 root 1.108 actives.insert (this);
794 root 1.98 }
795 root 1.96
796 root 1.98 void
797     object::activate_recursive ()
798     {
799     activate ();
800    
801 root 1.104 for (object *op = inv; op; op = op->below)
802 root 1.98 op->activate_recursive ();
803 root 1.96 }
804    
805     /* This function removes object 'op' from the list of active
806     * objects.
807     * This should only be used for style maps or other such
808     * reference maps where you don't want an object that isn't
809     * in play chewing up cpu time getting processed.
810     * The reverse of this is to call update_ob_speed, which
811     * will do the right thing based on the speed of the object.
812     */
813     void
814 root 1.98 object::deactivate ()
815 root 1.96 {
816     /* If not on the active list, nothing needs to be done */
817 root 1.108 if (!active)
818 root 1.96 return;
819    
820 root 1.108 actives.erase (this);
821 root 1.98 }
822 root 1.96
823 root 1.98 void
824     object::deactivate_recursive ()
825     {
826 root 1.104 for (object *op = inv; op; op = op->below)
827 root 1.98 op->deactivate_recursive ();
828    
829     deactivate ();
830 root 1.96 }
831    
832 root 1.106 void
833     object::set_flag_inv (int flag, int value)
834     {
835     for (object *op = inv; op; op = op->below)
836     {
837     op->flag [flag] = value;
838     op->set_flag_inv (flag, value);
839     }
840     }
841    
842 root 1.89 /*
843     * Remove and free all objects in the inventory of the given object.
844     * object.c ?
845     */
846     void
847     object::destroy_inv (bool drop_to_ground)
848     {
849 root 1.94 // need to check first, because the checks below might segfault
850     // as we might be on an invalid mapspace and crossfire code
851     // is too buggy to ensure that the inventory is empty.
852     // corollary: if you create arrows etc. with stuff in tis inventory,
853     // cf will crash below with off-map x and y
854     if (!inv)
855     return;
856    
857 root 1.89 /* Only if the space blocks everything do we not process -
858     * if some form of movement is allowed, let objects
859     * drop on that space.
860     */
861 root 1.92 if (!drop_to_ground
862     || !map
863     || map->in_memory != MAP_IN_MEMORY
864 root 1.122 || map->nodrop
865 root 1.95 || ms ().move_block == MOVE_ALL)
866 root 1.89 {
867     while (inv)
868 root 1.92 {
869     inv->destroy_inv (drop_to_ground);
870     inv->destroy ();
871     }
872 root 1.89 }
873     else
874     { /* Put objects in inventory onto this space */
875     while (inv)
876     {
877     object *op = inv;
878    
879     if (op->flag [FLAG_STARTEQUIP]
880     || op->flag [FLAG_NO_DROP]
881     || op->type == RUNE
882     || op->type == TRAP
883 root 1.110 || op->flag [FLAG_IS_A_TEMPLATE]
884     || op->flag [FLAG_DESTROY_ON_DEATH])
885 root 1.89 op->destroy ();
886     else
887 root 1.93 map->insert (op, x, y);
888 root 1.89 }
889     }
890     }
891    
892 root 1.21 object *object::create ()
893     {
894 root 1.42 object *op = new object;
895 root 1.22 op->link ();
896     return op;
897 root 1.21 }
898 elmex 1.1
899 root 1.82 void
900     object::do_destroy ()
901 root 1.14 {
902 root 1.112 attachable::do_destroy ();
903    
904 root 1.82 if (flag [FLAG_IS_LINKED])
905     remove_button_link (this);
906 root 1.29
907 root 1.82 if (flag [FLAG_FRIENDLY])
908 root 1.140 remove_friendly_object (this);
909 root 1.32
910 root 1.82 if (!flag [FLAG_REMOVED])
911 root 1.63 remove ();
912 root 1.14
913 root 1.112 destroy_inv (true);
914 root 1.14
915 root 1.112 deactivate ();
916     unlink ();
917 root 1.92
918 root 1.82 flag [FLAG_FREED] = 1;
919 root 1.14
920 root 1.57 // hack to ensure that freed objects still have a valid map
921     {
922     static maptile *freed_map; // freed objects are moved here to avoid crashes
923    
924     if (!freed_map)
925     {
926     freed_map = new maptile;
927    
928     freed_map->name = "/internal/freed_objects_map";
929     freed_map->width = 3;
930     freed_map->height = 3;
931    
932 root 1.96 freed_map->alloc ();
933 root 1.103 freed_map->in_memory = MAP_IN_MEMORY;
934 root 1.57 }
935    
936     map = freed_map;
937     x = 1;
938     y = 1;
939     }
940    
941 root 1.88 if (more)
942     {
943     more->destroy ();
944     more = 0;
945     }
946 root 1.82
947 root 1.162 head = 0;
948    
949     // clear those pointers that likely might cause circular references
950     owner = 0;
951     enemy = 0;
952     attacked_by = 0;
953     current_weapon = 0;
954 root 1.82 }
955    
956     void
957     object::destroy (bool destroy_inventory)
958     {
959     if (destroyed ())
960     return;
961    
962     if (destroy_inventory)
963 root 1.89 destroy_inv (false);
964 root 1.22
965 root 1.82 attachable::destroy ();
966 elmex 1.1 }
967    
968     /*
969     * sub_weight() recursively (outwards) subtracts a number from the
970     * weight of an object (and what is carried by it's environment(s)).
971     */
972 root 1.24 void
973     sub_weight (object *op, signed long weight)
974     {
975     while (op != NULL)
976     {
977     if (op->type == CONTAINER)
978 root 1.45 weight = (signed long) (weight * (100 - op->stats.Str) / 100);
979    
980 root 1.24 op->carrying -= weight;
981     op = op->env;
982 elmex 1.1 }
983     }
984    
985 root 1.63 /* op->remove ():
986 elmex 1.1 * This function removes the object op from the linked list of objects
987     * which it is currently tied to. When this function is done, the
988     * object will have no environment. If the object previously had an
989     * environment, the x and y coordinates will be updated to
990     * the previous environment.
991     */
992 root 1.24 void
993 root 1.128 object::do_remove ()
994 root 1.24 {
995 root 1.45 object *tmp, *last = 0;
996     object *otmp;
997 root 1.26
998 root 1.59 if (QUERY_FLAG (this, FLAG_REMOVED))
999 root 1.29 return;
1000 root 1.24
1001 root 1.59 SET_FLAG (this, FLAG_REMOVED);
1002 root 1.82 INVOKE_OBJECT (REMOVE, this);
1003 root 1.26
1004 root 1.59 if (more)
1005     more->remove ();
1006 root 1.24
1007     /*
1008     * In this case, the object to be removed is in someones
1009     * inventory.
1010     */
1011 root 1.59 if (env)
1012 root 1.24 {
1013 root 1.59 if (nrof)
1014     sub_weight (env, weight * nrof);
1015 root 1.24 else
1016 root 1.59 sub_weight (env, weight + carrying);
1017 root 1.24
1018     /* NO_FIX_PLAYER is set when a great many changes are being
1019     * made to players inventory. If set, avoiding the call
1020     * to save cpu time.
1021     */
1022 root 1.74 if ((otmp = in_player ()) && otmp->contr && !QUERY_FLAG (otmp, FLAG_NO_FIX_PLAYER))
1023 root 1.78 otmp->update_stats ();
1024 root 1.24
1025 root 1.96 if (above)
1026 root 1.59 above->below = below;
1027 root 1.24 else
1028 root 1.59 env->inv = below;
1029 root 1.24
1030 root 1.96 if (below)
1031 root 1.59 below->above = above;
1032 root 1.24
1033     /* we set up values so that it could be inserted into
1034     * the map, but we don't actually do that - it is up
1035     * to the caller to decide what we want to do.
1036     */
1037 root 1.59 x = env->x, y = env->y;
1038     map = env->map;
1039     above = 0, below = 0;
1040     env = 0;
1041     }
1042     else if (map)
1043     {
1044 root 1.96 if (type == PLAYER)
1045     {
1046 root 1.130 // leaving a spot always closes any open container on the ground
1047     if (container && !container->env)
1048     // this causes spurious floorbox updates, but it ensures
1049     // that the CLOSE event is being sent.
1050     close_container ();
1051    
1052 root 1.96 --map->players;
1053 root 1.100 map->touch ();
1054 root 1.96 }
1055    
1056 root 1.98 map->dirty = true;
1057 root 1.117 mapspace &ms = this->ms ();
1058 elmex 1.1
1059 root 1.29 /* link the object above us */
1060 root 1.59 if (above)
1061     above->below = below;
1062 root 1.29 else
1063 root 1.117 ms.top = below; /* we were top, set new top */
1064 root 1.24
1065 root 1.29 /* Relink the object below us, if there is one */
1066 root 1.59 if (below)
1067     below->above = above;
1068 root 1.29 else
1069     {
1070     /* Nothing below, which means we need to relink map object for this space
1071     * use translated coordinates in case some oddness with map tiling is
1072     * evident
1073     */
1074 root 1.59 if (GET_MAP_OB (map, x, y) != this)
1075 root 1.117 LOG (llevError, "remove_ob: GET_MAP_OB does not return object to be removed even though it appears to be on the bottom? %s\n", debug_desc ());
1076 elmex 1.1
1077 root 1.117 ms.bot = above; /* goes on above it. */
1078 root 1.8 }
1079 root 1.26
1080 root 1.59 above = 0;
1081     below = 0;
1082 root 1.26
1083 root 1.59 if (map->in_memory == MAP_SAVING)
1084 root 1.29 return;
1085 elmex 1.1
1086 root 1.82 int check_walk_off = !flag [FLAG_NO_APPLY];
1087 elmex 1.1
1088 root 1.117 for (tmp = ms.bot; tmp; tmp = tmp->above)
1089 root 1.24 {
1090 root 1.29 /* No point updating the players look faces if he is the object
1091     * being removed.
1092 root 1.24 */
1093 root 1.29
1094 root 1.59 if (tmp->type == PLAYER && tmp != this)
1095 root 1.24 {
1096 root 1.29 /* If a container that the player is currently using somehow gets
1097     * removed (most likely destroyed), update the player view
1098     * appropriately.
1099     */
1100 root 1.59 if (tmp->container == this)
1101 root 1.29 {
1102 root 1.82 flag [FLAG_APPLIED] = 0;
1103 root 1.59 tmp->container = 0;
1104 root 1.29 }
1105    
1106 root 1.82 if (tmp->contr->ns)
1107     tmp->contr->ns->floorbox_update ();
1108 root 1.8 }
1109 root 1.26
1110 root 1.96 /* See if object moving off should effect something */
1111 root 1.50 if (check_walk_off
1112 root 1.59 && ((move_type & tmp->move_off)
1113     && (move_type & ~tmp->move_off & ~tmp->move_block) == 0))
1114 root 1.29 {
1115 elmex 1.72 move_apply (tmp, this, 0);
1116 root 1.24
1117 root 1.59 if (destroyed ())
1118 root 1.50 LOG (llevError, "BUG: remove_ob(): name %s, destroyed leaving object\n", tmp->debug_desc ());
1119 root 1.8 }
1120    
1121 root 1.29 last = tmp;
1122     }
1123 root 1.26
1124 root 1.96 /* last == NULL if there are no objects on this space */
1125     //TODO: this makes little sense, why only update the topmost object?
1126 root 1.59 if (!last)
1127 root 1.99 map->at (x, y).flags_ = 0;
1128 root 1.29 else
1129     update_object (last, UP_OBJ_REMOVE);
1130 root 1.26
1131 root 1.82 if (flag [FLAG_BLOCKSVIEW] || glow_radius)
1132 root 1.59 update_all_los (map, x, y);
1133 elmex 1.1 }
1134     }
1135    
1136     /*
1137     * merge_ob(op,top):
1138     *
1139     * This function goes through all objects below and including top, and
1140     * merges op to the first matching object.
1141     * If top is NULL, it is calculated.
1142     * Returns pointer to object if it succeded in the merge, otherwise NULL
1143     */
1144 root 1.24 object *
1145     merge_ob (object *op, object *top)
1146     {
1147     if (!op->nrof)
1148 elmex 1.1 return 0;
1149 root 1.29
1150 root 1.82 if (top)
1151     for (top = op; top && top->above; top = top->above)
1152     ;
1153 root 1.29
1154 root 1.82 for (; top; top = top->below)
1155 elmex 1.1 {
1156 root 1.24 if (top == op)
1157     continue;
1158 root 1.66
1159     if (object::can_merge (op, top))
1160 root 1.24 {
1161     top->nrof += op->nrof;
1162    
1163 elmex 1.1 /* CLEAR_FLAG(top,FLAG_STARTEQUIP);*/
1164 root 1.24 op->weight = 0; /* Don't want any adjustements now */
1165 root 1.64 op->destroy ();
1166 root 1.24 return top;
1167     }
1168 elmex 1.1 }
1169 root 1.29
1170 root 1.45 return 0;
1171 elmex 1.1 }
1172    
1173 root 1.138 void
1174     object::expand_tail ()
1175     {
1176     if (more)
1177     return;
1178    
1179     object *prev = this;
1180    
1181 root 1.160 for (archetype *at = (archetype *)arch->more; at; at = (archetype *)at->more)
1182 root 1.138 {
1183     object *op = arch_to_object (at);
1184    
1185     op->name = name;
1186     op->name_pl = name_pl;
1187     op->title = title;
1188    
1189     op->head = this;
1190     prev->more = op;
1191    
1192     prev = op;
1193     }
1194     }
1195    
1196 elmex 1.1 /*
1197 root 1.117 * same as insert_ob_in_map except it handles separate coordinates and does a clean
1198     * job preparing multi-part monsters.
1199 elmex 1.1 */
1200 root 1.24 object *
1201 root 1.49 insert_ob_in_map_at (object *op, maptile *m, object *originator, int flag, int x, int y)
1202 root 1.24 {
1203 root 1.93 for (object *tmp = op->head_ (); tmp; tmp = tmp->more)
1204 root 1.24 {
1205 root 1.159 tmp->x = x + tmp->arch->x;
1206     tmp->y = y + tmp->arch->y;
1207 elmex 1.1 }
1208 root 1.29
1209 root 1.24 return insert_ob_in_map (op, m, originator, flag);
1210 elmex 1.1 }
1211    
1212     /*
1213     * insert_ob_in_map (op, map, originator, flag):
1214     * This function inserts the object in the two-way linked list
1215     * which represents what is on a map.
1216     * The second argument specifies the map, and the x and y variables
1217     * in the object about to be inserted specifies the position.
1218     *
1219     * originator: Player, monster or other object that caused 'op' to be inserted
1220     * into 'map'. May be NULL.
1221     *
1222     * flag is a bitmask about special things to do (or not do) when this
1223     * function is called. see the object.h file for the INS_ values.
1224     * Passing 0 for flag gives proper default values, so flag really only needs
1225     * to be set if special handling is needed.
1226     *
1227     * Return value:
1228     * new object if 'op' was merged with other object
1229     * NULL if 'op' was destroyed
1230     * just 'op' otherwise
1231     */
1232 root 1.24 object *
1233 root 1.49 insert_ob_in_map (object *op, maptile *m, object *originator, int flag)
1234 elmex 1.1 {
1235 root 1.138 assert (!op->flag [FLAG_FREED]);
1236    
1237 root 1.155 object *top, *floor = NULL;
1238 elmex 1.1
1239 root 1.117 op->remove ();
1240    
1241 root 1.139 #if 0
1242 root 1.138 if (!m->active != !op->active)
1243     if (m->active)
1244     op->activate_recursive ();
1245     else
1246     op->deactivate_recursive ();
1247 root 1.139 #endif
1248 root 1.25
1249 root 1.24 if (out_of_map (m, op->x, op->y))
1250     {
1251 root 1.138 LOG (llevError, "Trying to insert object outside the map.\n%s\n", op->debug_desc ());
1252 elmex 1.1 #ifdef MANY_CORES
1253 root 1.24 /* Better to catch this here, as otherwise the next use of this object
1254     * is likely to cause a crash. Better to find out where it is getting
1255     * improperly inserted.
1256     */
1257     abort ();
1258 elmex 1.1 #endif
1259 root 1.24 return op;
1260 elmex 1.1 }
1261 root 1.25
1262 root 1.117 if (object *more = op->more)
1263 root 1.155 if (!insert_ob_in_map (more, m, originator, flag))
1264     return 0;
1265 root 1.25
1266 root 1.24 CLEAR_FLAG (op, FLAG_REMOVED);
1267 root 1.8
1268 root 1.24 /* Ideally, the caller figures this out. However, it complicates a lot
1269     * of areas of callers (eg, anything that uses find_free_spot would now
1270     * need extra work
1271     */
1272 root 1.117 if (!xy_normalise (m, op->x, op->y))
1273     return 0;
1274    
1275     op->map = m;
1276     mapspace &ms = op->ms ();
1277 root 1.24
1278     /* this has to be done after we translate the coordinates.
1279     */
1280     if (op->nrof && !(flag & INS_NO_MERGE))
1281 root 1.155 for (object *tmp = ms.bot; tmp; tmp = tmp->above)
1282 root 1.66 if (object::can_merge (op, tmp))
1283 root 1.25 {
1284     op->nrof += tmp->nrof;
1285 root 1.64 tmp->destroy ();
1286 root 1.25 }
1287 root 1.24
1288     CLEAR_FLAG (op, FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */
1289     CLEAR_FLAG (op, FLAG_INV_LOCKED);
1290 root 1.25
1291 root 1.24 if (!QUERY_FLAG (op, FLAG_ALIVE))
1292     CLEAR_FLAG (op, FLAG_NO_STEAL);
1293    
1294     if (flag & INS_BELOW_ORIGINATOR)
1295     {
1296     if (originator->map != op->map || originator->x != op->x || originator->y != op->y)
1297     {
1298     LOG (llevError, "insert_ob_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
1299     abort ();
1300     }
1301 root 1.25
1302 root 1.24 op->above = originator;
1303     op->below = originator->below;
1304 root 1.25
1305 root 1.24 if (op->below)
1306     op->below->above = op;
1307     else
1308 root 1.117 ms.bot = op;
1309 root 1.25
1310 root 1.24 /* since *below* originator, no need to update top */
1311     originator->below = op;
1312 elmex 1.1 }
1313 root 1.24 else
1314     {
1315 root 1.117 top = ms.bot;
1316    
1317 root 1.24 /* If there are other objects, then */
1318 root 1.117 if ((!(flag & INS_MAP_LOAD)) && top)
1319 root 1.24 {
1320 root 1.96 object *last = 0;
1321 root 1.24
1322     /*
1323     * If there are multiple objects on this space, we do some trickier handling.
1324     * We've already dealt with merging if appropriate.
1325     * Generally, we want to put the new object on top. But if
1326     * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
1327     * floor, we want to insert above that and no further.
1328     * Also, if there are spell objects on this space, we stop processing
1329     * once we get to them. This reduces the need to traverse over all of
1330     * them when adding another one - this saves quite a bit of cpu time
1331     * when lots of spells are cast in one area. Currently, it is presumed
1332     * that flying non pickable objects are spell objects.
1333     */
1334 root 1.117 for (top = ms.bot; top; top = top->above)
1335 root 1.24 {
1336     if (QUERY_FLAG (top, FLAG_IS_FLOOR) || QUERY_FLAG (top, FLAG_OVERLAY_FLOOR))
1337     floor = top;
1338 root 1.26
1339 root 1.24 if (QUERY_FLAG (top, FLAG_NO_PICK) && (top->move_type & (MOVE_FLY_LOW | MOVE_FLY_HIGH)) && !QUERY_FLAG (top, FLAG_IS_FLOOR))
1340     {
1341     /* We insert above top, so we want this object below this */
1342     top = top->below;
1343     break;
1344     }
1345 root 1.26
1346 root 1.24 last = top;
1347     }
1348 root 1.26
1349 root 1.24 /* Don't want top to be NULL, so set it to the last valid object */
1350     top = last;
1351 root 1.8
1352 root 1.24 /* We let update_position deal with figuring out what the space
1353     * looks like instead of lots of conditions here.
1354     * makes things faster, and effectively the same result.
1355     */
1356    
1357     /* Have object 'fall below' other objects that block view.
1358 root 1.135 * Unless those objects are exits.
1359 root 1.24 * If INS_ON_TOP is used, don't do this processing
1360     * Need to find the object that in fact blocks view, otherwise
1361     * stacking is a bit odd.
1362     */
1363 root 1.117 if (!(flag & INS_ON_TOP)
1364     && ms.flags () & P_BLOCKSVIEW
1365 root 1.135 && (op->face && !faces [op->face].visibility))
1366 root 1.24 {
1367     for (last = top; last != floor; last = last->below)
1368     if (QUERY_FLAG (last, FLAG_BLOCKSVIEW) && (last->type != EXIT))
1369     break;
1370 root 1.117
1371 root 1.24 /* Check to see if we found the object that blocks view,
1372     * and make sure we have a below pointer for it so that
1373     * we can get inserted below this one, which requires we
1374     * set top to the object below us.
1375     */
1376     if (last && last->below && last != floor)
1377     top = last->below;
1378 root 1.8 }
1379 root 1.24 } /* If objects on this space */
1380 root 1.25
1381 root 1.24 if (flag & INS_MAP_LOAD)
1382 root 1.117 top = ms.top;
1383 root 1.25
1384 root 1.24 if (flag & INS_ABOVE_FLOOR_ONLY)
1385     top = floor;
1386    
1387     /* Top is the object that our object (op) is going to get inserted above.
1388     */
1389    
1390     /* First object on this space */
1391     if (!top)
1392     {
1393 root 1.117 op->above = ms.bot;
1394 root 1.25
1395 root 1.24 if (op->above)
1396     op->above->below = op;
1397 root 1.25
1398 root 1.96 op->below = 0;
1399 root 1.117 ms.bot = op;
1400 root 1.24 }
1401     else
1402     { /* get inserted into the stack above top */
1403     op->above = top->above;
1404 root 1.25
1405 root 1.24 if (op->above)
1406     op->above->below = op;
1407 root 1.25
1408 root 1.24 op->below = top;
1409     top->above = op;
1410     }
1411 root 1.25
1412 root 1.96 if (!op->above)
1413 root 1.117 ms.top = op;
1414 root 1.24 } /* else not INS_BELOW_ORIGINATOR */
1415 root 1.8
1416 root 1.24 if (op->type == PLAYER)
1417 root 1.96 {
1418     op->contr->do_los = 1;
1419     ++op->map->players;
1420 root 1.100 op->map->touch ();
1421 root 1.96 }
1422 root 1.24
1423 root 1.98 op->map->dirty = true;
1424    
1425 root 1.24 /* If we have a floor, we know the player, if any, will be above
1426     * it, so save a few ticks and start from there.
1427     */
1428     if (!(flag & INS_MAP_LOAD))
1429 root 1.117 if (object *pl = ms.player ())
1430 root 1.82 if (pl->contr->ns)
1431     pl->contr->ns->floorbox_update ();
1432 root 1.24
1433     /* If this object glows, it may affect lighting conditions that are
1434     * visible to others on this map. But update_all_los is really
1435     * an inefficient way to do this, as it means los for all players
1436     * on the map will get recalculated. The players could very well
1437     * be far away from this change and not affected in any way -
1438     * this should get redone to only look for players within range,
1439 root 1.99 * or just updating the P_UPTODATE for spaces within this area
1440 root 1.24 * of effect may be sufficient.
1441     */
1442 root 1.84 if (op->map->darkness && (op->glow_radius != 0))
1443 root 1.24 update_all_los (op->map, op->x, op->y);
1444    
1445     /* updates flags (blocked, alive, no magic, etc) for this map space */
1446     update_object (op, UP_OBJ_INSERT);
1447    
1448 root 1.82 INVOKE_OBJECT (INSERT, op);
1449    
1450 root 1.24 /* Don't know if moving this to the end will break anything. However,
1451 root 1.70 * we want to have floorbox_update called before calling this.
1452 root 1.24 *
1453     * check_move_on() must be after this because code called from
1454     * check_move_on() depends on correct map flags (so functions like
1455     * blocked() and wall() work properly), and these flags are updated by
1456     * update_object().
1457     */
1458    
1459     /* if this is not the head or flag has been passed, don't check walk on status */
1460 root 1.155 if (!(flag & INS_NO_WALK_ON) && op->head_ () == op)
1461 root 1.24 {
1462     if (check_move_on (op, originator))
1463 root 1.82 return 0;
1464 elmex 1.1
1465 root 1.24 /* If we are a multi part object, lets work our way through the check
1466     * walk on's.
1467     */
1468 root 1.155 for (object *tmp = op->more; tmp; tmp = tmp->more)
1469 root 1.24 if (check_move_on (tmp, originator))
1470 root 1.82 return 0;
1471 elmex 1.1 }
1472 root 1.25
1473 root 1.24 return op;
1474 elmex 1.1 }
1475    
1476     /* this function inserts an object in the map, but if it
1477 root 1.75 * finds an object of its own type, it'll remove that one first.
1478     * op is the object to insert it under: supplies x and the map.
1479 elmex 1.1 */
1480 root 1.24 void
1481     replace_insert_ob_in_map (const char *arch_string, object *op)
1482     {
1483 root 1.75 object *tmp, *tmp1;
1484 elmex 1.1
1485 root 1.24 /* first search for itself and remove any old instances */
1486 elmex 1.1
1487 root 1.104 for (tmp = op->ms ().bot; tmp; tmp = tmp->above)
1488 root 1.158 if (!strcmp (tmp->arch->archname, arch_string)) /* same archetype */
1489 root 1.64 tmp->destroy ();
1490 elmex 1.1
1491 root 1.46 tmp1 = arch_to_object (archetype::find (arch_string));
1492 elmex 1.1
1493 root 1.24 tmp1->x = op->x;
1494     tmp1->y = op->y;
1495     insert_ob_in_map (tmp1, op->map, op, 0);
1496     }
1497 elmex 1.1
1498 root 1.93 object *
1499     object::insert_at (object *where, object *originator, int flags)
1500     {
1501 root 1.138 return where->map->insert (this, where->x, where->y, originator, flags);
1502 root 1.93 }
1503    
1504 elmex 1.1 /*
1505     * get_split_ob(ob,nr) splits up ob into two parts. The part which
1506     * is returned contains nr objects, and the remaining parts contains
1507     * the rest (or is removed and freed if that number is 0).
1508     * On failure, NULL is returned, and the reason put into the
1509     * global static errmsg array.
1510     */
1511 root 1.24 object *
1512     get_split_ob (object *orig_ob, uint32 nr)
1513     {
1514 root 1.64 object *newob;
1515     int is_removed = (QUERY_FLAG (orig_ob, FLAG_REMOVED) != 0);
1516 root 1.24
1517     if (orig_ob->nrof < nr)
1518     {
1519     sprintf (errmsg, "There are only %d %ss.", orig_ob->nrof ? orig_ob->nrof : 1, &orig_ob->name);
1520     return NULL;
1521     }
1522 root 1.29
1523 root 1.24 newob = object_create_clone (orig_ob);
1524 root 1.29
1525 root 1.24 if ((orig_ob->nrof -= nr) < 1)
1526 root 1.63 orig_ob->destroy (1);
1527 root 1.24 else if (!is_removed)
1528     {
1529     if (orig_ob->env != NULL)
1530     sub_weight (orig_ob->env, orig_ob->weight * nr);
1531     if (orig_ob->env == NULL && orig_ob->map->in_memory != MAP_IN_MEMORY)
1532     {
1533     strcpy (errmsg, "Tried to split object whose map is not in memory.");
1534     LOG (llevDebug, "Error, Tried to split object whose map is not in memory.\n");
1535     return NULL;
1536 root 1.8 }
1537 elmex 1.1 }
1538 root 1.29
1539 root 1.24 newob->nrof = nr;
1540 elmex 1.1
1541 root 1.24 return newob;
1542 elmex 1.1 }
1543    
1544     /*
1545     * decrease_ob_nr(object, number) decreases a specified number from
1546     * the amount of an object. If the amount reaches 0, the object
1547     * is subsequently removed and freed.
1548     *
1549     * Return value: 'op' if something is left, NULL if the amount reached 0
1550     */
1551 root 1.24 object *
1552     decrease_ob_nr (object *op, uint32 i)
1553 elmex 1.1 {
1554 root 1.29 object *tmp;
1555 elmex 1.1
1556 root 1.24 if (i == 0) /* objects with op->nrof require this check */
1557     return op;
1558    
1559     if (i > op->nrof)
1560     i = op->nrof;
1561    
1562     if (QUERY_FLAG (op, FLAG_REMOVED))
1563 root 1.29 op->nrof -= i;
1564 root 1.73 else if (op->env)
1565 root 1.24 {
1566     /* is this object in the players inventory, or sub container
1567     * therein?
1568     */
1569 root 1.74 tmp = op->in_player ();
1570 root 1.24 /* nope. Is this a container the player has opened?
1571     * If so, set tmp to that player.
1572     * IMO, searching through all the players will mostly
1573     * likely be quicker than following op->env to the map,
1574     * and then searching the map for a player.
1575     */
1576     if (!tmp)
1577 root 1.81 for_all_players (pl)
1578     if (pl->ob->container == op->env)
1579     {
1580     tmp = pl->ob;
1581     break;
1582     }
1583 elmex 1.1
1584 root 1.24 if (i < op->nrof)
1585     {
1586     sub_weight (op->env, op->weight * i);
1587     op->nrof -= i;
1588     if (tmp)
1589 root 1.73 esrv_send_item (tmp, op);
1590 root 1.24 }
1591     else
1592     {
1593 root 1.63 op->remove ();
1594 root 1.24 op->nrof = 0;
1595     if (tmp)
1596 root 1.73 esrv_del_item (tmp->contr, op->count);
1597 elmex 1.1 }
1598     }
1599 root 1.24 else
1600 elmex 1.1 {
1601 root 1.29 object *above = op->above;
1602 elmex 1.1
1603 root 1.24 if (i < op->nrof)
1604 root 1.29 op->nrof -= i;
1605 root 1.24 else
1606     {
1607 root 1.63 op->remove ();
1608 root 1.24 op->nrof = 0;
1609     }
1610 root 1.29
1611 root 1.24 /* Since we just removed op, op->above is null */
1612 root 1.73 for (tmp = above; tmp; tmp = tmp->above)
1613 root 1.24 if (tmp->type == PLAYER)
1614     {
1615     if (op->nrof)
1616     esrv_send_item (tmp, op);
1617     else
1618     esrv_del_item (tmp->contr, op->count);
1619     }
1620 elmex 1.1 }
1621    
1622 root 1.24 if (op->nrof)
1623 root 1.29 return op;
1624 root 1.24 else
1625     {
1626 root 1.64 op->destroy ();
1627 root 1.73 return 0;
1628 elmex 1.1 }
1629     }
1630    
1631     /*
1632     * add_weight(object, weight) adds the specified weight to an object,
1633     * and also updates how much the environment(s) is/are carrying.
1634     */
1635 root 1.24 void
1636     add_weight (object *op, signed long weight)
1637     {
1638     while (op != NULL)
1639     {
1640     if (op->type == CONTAINER)
1641 root 1.29 weight = (signed long) (weight * (100 - op->stats.Str) / 100);
1642    
1643 root 1.24 op->carrying += weight;
1644     op = op->env;
1645     }
1646 elmex 1.1 }
1647    
1648 root 1.24 object *
1649     insert_ob_in_ob (object *op, object *where)
1650     {
1651 root 1.59 if (!where)
1652 root 1.24 {
1653 root 1.53 char *dump = dump_object (op);
1654     LOG (llevError, "Trying to put object in NULL.\n%s\n", dump);
1655     free (dump);
1656 root 1.24 return op;
1657     }
1658 root 1.29
1659 root 1.154 if (where->head_ () != where)
1660 root 1.24 {
1661 root 1.153 LOG (llevError | logBacktrace, "Warning: Tried to insert object into wrong part of multipart object.\n");
1662 root 1.24 where = where->head;
1663     }
1664 root 1.29
1665 root 1.59 return where->insert (op);
1666     }
1667    
1668     /*
1669     * env->insert (op)
1670     * This function inserts the object op in the linked list
1671     * inside the object environment.
1672     *
1673     * The function returns now pointer to inserted item, and return value can
1674     * be != op, if items are merged. -Tero
1675     */
1676     object *
1677     object::insert (object *op)
1678     {
1679     object *tmp, *otmp;
1680    
1681     if (!QUERY_FLAG (op, FLAG_REMOVED))
1682     op->remove ();
1683    
1684 root 1.24 if (op->more)
1685     {
1686     LOG (llevError, "Tried to insert multipart object %s (%d)\n", &op->name, op->count);
1687     return op;
1688     }
1689 root 1.29
1690 root 1.24 CLEAR_FLAG (op, FLAG_OBJ_ORIGINAL);
1691     CLEAR_FLAG (op, FLAG_REMOVED);
1692     if (op->nrof)
1693     {
1694 root 1.59 for (tmp = inv; tmp != NULL; tmp = tmp->below)
1695 root 1.66 if (object::can_merge (tmp, op))
1696 root 1.24 {
1697     /* return the original object and remove inserted object
1698     (client needs the original object) */
1699     tmp->nrof += op->nrof;
1700     /* Weight handling gets pretty funky. Since we are adding to
1701     * tmp->nrof, we need to increase the weight.
1702     */
1703 root 1.59 add_weight (this, op->weight * op->nrof);
1704 root 1.24 SET_FLAG (op, FLAG_REMOVED);
1705 root 1.59 op->destroy (); /* free the inserted object */
1706 root 1.24 op = tmp;
1707 root 1.59 op->remove (); /* and fix old object's links */
1708 root 1.24 CLEAR_FLAG (op, FLAG_REMOVED);
1709     break;
1710     }
1711    
1712     /* I assume combined objects have no inventory
1713     * We add the weight - this object could have just been removed
1714     * (if it was possible to merge). calling remove_ob will subtract
1715     * the weight, so we need to add it in again, since we actually do
1716     * the linking below
1717     */
1718 root 1.59 add_weight (this, op->weight * op->nrof);
1719 root 1.24 }
1720     else
1721 root 1.59 add_weight (this, (op->weight + op->carrying));
1722 elmex 1.1
1723 root 1.74 otmp = this->in_player ();
1724 root 1.59 if (otmp && otmp->contr)
1725     if (!QUERY_FLAG (otmp, FLAG_NO_FIX_PLAYER))
1726 root 1.78 otmp->update_stats ();
1727 elmex 1.1
1728 root 1.74 op->map = 0;
1729 root 1.59 op->env = this;
1730 root 1.74 op->above = 0;
1731     op->below = 0;
1732 root 1.24 op->x = 0, op->y = 0;
1733 elmex 1.1
1734     /* reset the light list and los of the players on the map */
1735 root 1.59 if ((op->glow_radius != 0) && map)
1736 root 1.24 {
1737 elmex 1.1 #ifdef DEBUG_LIGHTS
1738 root 1.24 LOG (llevDebug, " insert_ob_in_ob(): got %s to insert in map/op\n", op->name);
1739     #endif /* DEBUG_LIGHTS */
1740 root 1.84 if (map->darkness)
1741 root 1.59 update_all_los (map, x, y);
1742 root 1.24 }
1743 elmex 1.1
1744     /* Client has no idea of ordering so lets not bother ordering it here.
1745     * It sure simplifies this function...
1746     */
1747 root 1.59 if (!inv)
1748     inv = op;
1749 root 1.24 else
1750     {
1751 root 1.59 op->below = inv;
1752 elmex 1.1 op->below->above = op;
1753 root 1.59 inv = op;
1754 root 1.24 }
1755 root 1.59
1756 root 1.82 INVOKE_OBJECT (INSERT, this);
1757    
1758 elmex 1.1 return op;
1759     }
1760    
1761     /*
1762     * Checks if any objects has a move_type that matches objects
1763     * that effect this object on this space. Call apply() to process
1764     * these events.
1765     *
1766     * Any speed-modification due to SLOW_MOVE() of other present objects
1767     * will affect the speed_left of the object.
1768     *
1769     * originator: Player, monster or other object that caused 'op' to be inserted
1770     * into 'map'. May be NULL.
1771     *
1772     * Return value: 1 if 'op' was destroyed, 0 otherwise.
1773     *
1774     * 4-21-95 added code to check if appropriate skill was readied - this will
1775     * permit faster movement by the player through this terrain. -b.t.
1776     *
1777     * MSW 2001-07-08: Check all objects on space, not just those below
1778     * object being inserted. insert_ob_in_map may not put new objects
1779     * on top.
1780     */
1781 root 1.24 int
1782     check_move_on (object *op, object *originator)
1783 elmex 1.1 {
1784 root 1.48 object *tmp;
1785 root 1.49 maptile *m = op->map;
1786 root 1.48 int x = op->x, y = op->y;
1787 root 1.26
1788 root 1.48 MoveType move_on, move_slow, move_block;
1789 root 1.24
1790     if (QUERY_FLAG (op, FLAG_NO_APPLY))
1791     return 0;
1792    
1793     move_on = GET_MAP_MOVE_ON (op->map, op->x, op->y);
1794     move_slow = GET_MAP_MOVE_SLOW (op->map, op->x, op->y);
1795     move_block = GET_MAP_MOVE_BLOCK (op->map, op->x, op->y);
1796    
1797     /* if nothing on this space will slow op down or be applied,
1798     * no need to do checking below. have to make sure move_type
1799     * is set, as lots of objects don't have it set - we treat that
1800     * as walking.
1801     */
1802     if (op->move_type && !(op->move_type & move_on) && !(op->move_type & move_slow))
1803     return 0;
1804 elmex 1.1
1805 root 1.24 /* This is basically inverse logic of that below - basically,
1806     * if the object can avoid the move on or slow move, they do so,
1807     * but can't do it if the alternate movement they are using is
1808     * blocked. Logic on this seems confusing, but does seem correct.
1809     */
1810     if ((op->move_type & ~move_on & ~move_block) != 0 && (op->move_type & ~move_slow & ~move_block) != 0)
1811     return 0;
1812    
1813     /* The objects have to be checked from top to bottom.
1814     * Hence, we first go to the top:
1815     */
1816    
1817 root 1.104 for (tmp = op->ms ().bot; tmp && tmp->above; tmp = tmp->above)
1818 root 1.24 {
1819     /* Trim the search when we find the first other spell effect
1820     * this helps performance so that if a space has 50 spell objects,
1821     * we don't need to check all of them.
1822     */
1823     if ((tmp->move_type & MOVE_FLY_LOW) && QUERY_FLAG (tmp, FLAG_NO_PICK))
1824     break;
1825     }
1826 root 1.26
1827     for (; tmp; tmp = tmp->below)
1828 root 1.24 {
1829     if (tmp == op)
1830     continue; /* Can't apply yourself */
1831 elmex 1.1
1832 root 1.24 /* Check to see if one of the movement types should be slowed down.
1833     * Second check makes sure that the movement types not being slowed
1834     * (~slow_move) is not blocked on this space - just because the
1835     * space doesn't slow down swimming (for example), if you can't actually
1836     * swim on that space, can't use it to avoid the penalty.
1837     */
1838     if (!QUERY_FLAG (op, FLAG_WIZPASS))
1839     {
1840     if ((!op->move_type && tmp->move_slow & MOVE_WALK) ||
1841     ((op->move_type & tmp->move_slow) && (op->move_type & ~tmp->move_slow & ~tmp->move_block) == 0))
1842     {
1843 elmex 1.1
1844 root 1.29 float
1845 root 1.120 diff = tmp->move_slow_penalty * fabs (op->speed);
1846 elmex 1.1
1847 root 1.24 if (op->type == PLAYER)
1848 root 1.26 if ((QUERY_FLAG (tmp, FLAG_IS_HILLY) && find_skill_by_number (op, SK_CLIMBING)) ||
1849     (QUERY_FLAG (tmp, FLAG_IS_WOODED) && find_skill_by_number (op, SK_WOODSMAN)))
1850     diff /= 4.0;
1851    
1852 root 1.24 op->speed_left -= diff;
1853 root 1.8 }
1854     }
1855 elmex 1.1
1856 root 1.24 /* Basically same logic as above, except now for actual apply. */
1857     if ((!op->move_type && tmp->move_on & MOVE_WALK) ||
1858     ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0))
1859     {
1860 elmex 1.72 move_apply (tmp, op, originator);
1861 root 1.24
1862 root 1.48 if (op->destroyed ())
1863 root 1.24 return 1;
1864    
1865     /* what the person/creature stepped onto has moved the object
1866     * someplace new. Don't process any further - if we did,
1867     * have a feeling strange problems would result.
1868     */
1869     if (op->map != m || op->x != x || op->y != y)
1870     return 0;
1871 root 1.8 }
1872 elmex 1.1 }
1873 root 1.26
1874 root 1.24 return 0;
1875 elmex 1.1 }
1876    
1877     /*
1878     * present_arch(arch, map, x, y) searches for any objects with
1879     * a matching archetype at the given map and coordinates.
1880     * The first matching object is returned, or NULL if none.
1881     */
1882 root 1.24 object *
1883 root 1.49 present_arch (const archetype *at, maptile *m, int x, int y)
1884 root 1.24 {
1885 root 1.104 if (!m || out_of_map (m, x, y))
1886 root 1.24 {
1887     LOG (llevError, "Present_arch called outside map.\n");
1888     return NULL;
1889     }
1890 root 1.84
1891 root 1.104 for (object *tmp = m->at (x, y).bot; tmp; tmp = tmp->above)
1892 root 1.24 if (tmp->arch == at)
1893 elmex 1.1 return tmp;
1894 root 1.84
1895 elmex 1.1 return NULL;
1896     }
1897    
1898     /*
1899     * present(type, map, x, y) searches for any objects with
1900     * a matching type variable at the given map and coordinates.
1901     * The first matching object is returned, or NULL if none.
1902     */
1903 root 1.24 object *
1904 root 1.49 present (unsigned char type, maptile *m, int x, int y)
1905 root 1.24 {
1906     if (out_of_map (m, x, y))
1907     {
1908     LOG (llevError, "Present called outside map.\n");
1909     return NULL;
1910     }
1911 root 1.84
1912 root 1.104 for (object *tmp = m->at (x, y).bot; tmp; tmp = tmp->above)
1913 root 1.24 if (tmp->type == type)
1914 elmex 1.1 return tmp;
1915 root 1.84
1916 elmex 1.1 return NULL;
1917     }
1918    
1919     /*
1920     * present_in_ob(type, object) searches for any objects with
1921     * a matching type variable in the inventory of the given object.
1922     * The first matching object is returned, or NULL if none.
1923     */
1924 root 1.24 object *
1925     present_in_ob (unsigned char type, const object *op)
1926     {
1927 root 1.84 for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below)
1928 root 1.24 if (tmp->type == type)
1929 elmex 1.1 return tmp;
1930 root 1.84
1931 elmex 1.1 return NULL;
1932     }
1933    
1934     /*
1935     * present_in_ob (type, str, object) searches for any objects with
1936     * a matching type & name variable in the inventory of the given object.
1937     * The first matching object is returned, or NULL if none.
1938     * This is mostly used by spell effect code, so that we only
1939     * have one spell effect at a time.
1940     * type can be used to narrow the search - if type is set,
1941     * the type must also match. -1 can be passed for the type,
1942     * in which case the type does not need to pass.
1943     * str is the string to match against. Note that we match against
1944     * the object name, not the archetype name. this is so that the
1945     * spell code can use one object type (force), but change it's name
1946     * to be unique.
1947     */
1948 root 1.24 object *
1949     present_in_ob_by_name (int type, const char *str, const object *op)
1950     {
1951 root 1.84 for (object *tmp = op->inv; tmp; tmp = tmp->below)
1952 root 1.82 if ((type == -1 || tmp->type == type) && (!strcmp (str, tmp->name)))
1953     return tmp;
1954 elmex 1.1
1955 root 1.82 return 0;
1956 elmex 1.1 }
1957    
1958     /*
1959     * present_arch_in_ob(archetype, object) searches for any objects with
1960     * a matching archetype in the inventory of the given object.
1961     * The first matching object is returned, or NULL if none.
1962     */
1963 root 1.24 object *
1964     present_arch_in_ob (const archetype *at, const object *op)
1965     {
1966 root 1.82 for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below)
1967 root 1.24 if (tmp->arch == at)
1968 elmex 1.1 return tmp;
1969 root 1.82
1970 elmex 1.1 return NULL;
1971     }
1972    
1973     /*
1974     * activate recursively a flag on an object inventory
1975     */
1976 root 1.24 void
1977     flag_inv (object *op, int flag)
1978     {
1979     if (op->inv)
1980 root 1.82 for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below)
1981 root 1.24 {
1982     SET_FLAG (tmp, flag);
1983     flag_inv (tmp, flag);
1984 elmex 1.1 }
1985 root 1.82 }
1986    
1987     /*
1988     * deactivate recursively a flag on an object inventory
1989     */
1990 root 1.24 void
1991     unflag_inv (object *op, int flag)
1992     {
1993     if (op->inv)
1994 root 1.82 for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below)
1995 root 1.24 {
1996     CLEAR_FLAG (tmp, flag);
1997     unflag_inv (tmp, flag);
1998 elmex 1.1 }
1999     }
2000    
2001     /*
2002     * find_free_spot(object, map, x, y, start, stop) will search for
2003     * a spot at the given map and coordinates which will be able to contain
2004     * the given object. start and stop specifies how many squares
2005     * to search (see the freearr_x/y[] definition).
2006     * It returns a random choice among the alternatives found.
2007     * start and stop are where to start relative to the free_arr array (1,9
2008     * does all 4 immediate directions). This returns the index into the
2009     * array of the free spot, -1 if no spot available (dir 0 = x,y)
2010     * Note - this only checks to see if there is space for the head of the
2011     * object - if it is a multispace object, this should be called for all
2012     * pieces.
2013     * Note2: This function does correctly handle tiled maps, but does not
2014     * inform the caller. However, insert_ob_in_map will update as
2015     * necessary, so the caller shouldn't need to do any special work.
2016     * Note - updated to take an object instead of archetype - this is necessary
2017     * because arch_blocked (now ob_blocked) needs to know the movement type
2018     * to know if the space in question will block the object. We can't use
2019     * the archetype because that isn't correct if the monster has been
2020     * customized, changed states, etc.
2021     */
2022 root 1.24 int
2023 root 1.49 find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop)
2024 root 1.24 {
2025 root 1.82 int index = 0, flag;
2026     int altern[SIZEOFFREE];
2027 root 1.24
2028 root 1.82 for (int i = start; i < stop; i++)
2029 root 1.24 {
2030     flag = ob_blocked (ob, m, x + freearr_x[i], y + freearr_y[i]);
2031     if (!flag)
2032 root 1.82 altern [index++] = i;
2033 root 1.24
2034     /* Basically, if we find a wall on a space, we cut down the search size.
2035     * In this way, we won't return spaces that are on another side of a wall.
2036     * This mostly work, but it cuts down the search size in all directions -
2037     * if the space being examined only has a wall to the north and empty
2038     * spaces in all the other directions, this will reduce the search space
2039     * to only the spaces immediately surrounding the target area, and
2040     * won't look 2 spaces south of the target space.
2041     */
2042 root 1.74 else if ((flag & P_NO_PASS) && maxfree[i] < stop)
2043 root 1.24 stop = maxfree[i];
2044 elmex 1.1 }
2045 root 1.74
2046 root 1.24 if (!index)
2047     return -1;
2048 root 1.74
2049 root 1.124 return altern [rndm (index)];
2050 elmex 1.1 }
2051    
2052     /*
2053 root 1.49 * find_first_free_spot(archetype, maptile, x, y) works like
2054 elmex 1.1 * find_free_spot(), but it will search max number of squares.
2055     * But it will return the first available spot, not a random choice.
2056     * Changed 0.93.2: Have it return -1 if there is no free spot available.
2057     */
2058 root 1.24 int
2059 root 1.49 find_first_free_spot (const object *ob, maptile *m, int x, int y)
2060 root 1.24 {
2061 root 1.82 for (int i = 0; i < SIZEOFFREE; i++)
2062     if (!ob_blocked (ob, m, x + freearr_x[i], y + freearr_y[i]))
2063     return i;
2064 root 1.24
2065     return -1;
2066 elmex 1.1 }
2067    
2068     /*
2069     * The function permute(arr, begin, end) randomly reorders the array
2070     * arr[begin..end-1].
2071 root 1.82 * now uses a fisher-yates shuffle, old permute was broken
2072 elmex 1.1 */
2073 root 1.24 static void
2074     permute (int *arr, int begin, int end)
2075 elmex 1.1 {
2076 root 1.82 arr += begin;
2077     end -= begin;
2078    
2079     while (--end)
2080 root 1.124 swap (arr [end], arr [rndm (end + 1)]);
2081 elmex 1.1 }
2082    
2083     /* new function to make monster searching more efficient, and effective!
2084     * This basically returns a randomized array (in the passed pointer) of
2085     * the spaces to find monsters. In this way, it won't always look for
2086     * monsters to the north first. However, the size of the array passed
2087     * covers all the spaces, so within that size, all the spaces within
2088     * the 3x3 area will be searched, just not in a predictable order.
2089     */
2090 root 1.24 void
2091     get_search_arr (int *search_arr)
2092 elmex 1.1 {
2093 root 1.82 int i;
2094 elmex 1.1
2095 root 1.24 for (i = 0; i < SIZEOFFREE; i++)
2096 root 1.82 search_arr[i] = i;
2097 elmex 1.1
2098 root 1.24 permute (search_arr, 1, SIZEOFFREE1 + 1);
2099     permute (search_arr, SIZEOFFREE1 + 1, SIZEOFFREE2 + 1);
2100     permute (search_arr, SIZEOFFREE2 + 1, SIZEOFFREE);
2101 elmex 1.1 }
2102    
2103     /*
2104     * find_dir(map, x, y, exclude) will search some close squares in the
2105     * given map at the given coordinates for live objects.
2106     * It will not considered the object given as exclude among possible
2107     * live objects.
2108     * It returns the direction toward the first/closest live object if finds
2109     * any, otherwise 0.
2110     * Perhaps incorrectly, but I'm making the assumption that exclude
2111     * is actually want is going to try and move there. We need this info
2112     * because we have to know what movement the thing looking to move
2113     * there is capable of.
2114     */
2115 root 1.24 int
2116 root 1.49 find_dir (maptile *m, int x, int y, object *exclude)
2117 root 1.24 {
2118 root 1.82 int i, max = SIZEOFFREE, mflags;
2119 root 1.29
2120     sint16 nx, ny;
2121 root 1.82 object *tmp;
2122     maptile *mp;
2123 root 1.29
2124     MoveType blocked, move_type;
2125 root 1.24
2126 root 1.155 if (exclude && exclude->head_ () != exclude)
2127 root 1.24 {
2128     exclude = exclude->head;
2129     move_type = exclude->move_type;
2130     }
2131     else
2132     {
2133     /* If we don't have anything, presume it can use all movement types. */
2134     move_type = MOVE_ALL;
2135     }
2136    
2137     for (i = 1; i < max; i++)
2138     {
2139     mp = m;
2140     nx = x + freearr_x[i];
2141     ny = y + freearr_y[i];
2142    
2143     mflags = get_map_flags (m, &mp, nx, ny, &nx, &ny);
2144 root 1.75
2145 root 1.24 if (mflags & P_OUT_OF_MAP)
2146 root 1.75 max = maxfree[i];
2147 root 1.24 else
2148     {
2149 root 1.82 mapspace &ms = mp->at (nx, ny);
2150    
2151     blocked = ms.move_block;
2152 root 1.24
2153     if ((move_type & blocked) == move_type)
2154 root 1.75 max = maxfree[i];
2155 root 1.24 else if (mflags & P_IS_ALIVE)
2156     {
2157 root 1.84 for (tmp = ms.bot; tmp; tmp = tmp->above)
2158 root 1.82 if ((tmp->flag [FLAG_MONSTER] || tmp->type == PLAYER)
2159 root 1.155 && (tmp != exclude || (tmp->head_ () != tmp && tmp->head_ () != exclude)))
2160 root 1.75 break;
2161    
2162 root 1.24 if (tmp)
2163 root 1.75 return freedir[i];
2164 root 1.8 }
2165     }
2166 elmex 1.1 }
2167 root 1.75
2168 root 1.24 return 0;
2169 elmex 1.1 }
2170    
2171     /*
2172     * distance(object 1, object 2) will return the square of the
2173     * distance between the two given objects.
2174     */
2175 root 1.24 int
2176     distance (const object *ob1, const object *ob2)
2177     {
2178 root 1.82 return (ob1->x - ob2->x) * (ob1->x - ob2->x) + (ob1->y - ob2->y) * (ob1->y - ob2->y);
2179 elmex 1.1 }
2180    
2181     /*
2182     * find_dir_2(delta-x,delta-y) will return a direction in which
2183     * an object which has subtracted the x and y coordinates of another
2184     * object, needs to travel toward it.
2185     */
2186 root 1.24 int
2187     find_dir_2 (int x, int y)
2188     {
2189 root 1.75 int q;
2190 elmex 1.1
2191 root 1.24 if (y)
2192     q = x * 100 / y;
2193 elmex 1.1 else if (x)
2194 root 1.24 q = -300 * x;
2195 elmex 1.1 else
2196     return 0;
2197    
2198 root 1.24 if (y > 0)
2199     {
2200     if (q < -242)
2201     return 3;
2202     if (q < -41)
2203     return 2;
2204     if (q < 41)
2205     return 1;
2206     if (q < 242)
2207     return 8;
2208     return 7;
2209     }
2210 elmex 1.1
2211     if (q < -242)
2212 root 1.24 return 7;
2213 elmex 1.1 if (q < -41)
2214 root 1.24 return 6;
2215 elmex 1.1 if (q < 41)
2216 root 1.24 return 5;
2217 elmex 1.1 if (q < 242)
2218 root 1.24 return 4;
2219 elmex 1.1
2220 root 1.24 return 3;
2221 elmex 1.1 }
2222    
2223     /*
2224     * dirdiff(dir1, dir2) returns how many 45-degrees differences there is
2225     * between two directions (which are expected to be absolute (see absdir())
2226     */
2227 root 1.24 int
2228     dirdiff (int dir1, int dir2)
2229     {
2230 root 1.82 int d;
2231 root 1.24
2232     d = abs (dir1 - dir2);
2233     if (d > 4)
2234 elmex 1.1 d = 8 - d;
2235 root 1.82
2236 elmex 1.1 return d;
2237     }
2238    
2239     /* peterm:
2240     * do LOS stuff for ball lightning. Go after the closest VISIBLE monster.
2241     * Basically, this is a table of directions, and what directions
2242     * one could go to go back to us. Eg, entry 15 below is 4, 14, 16.
2243     * This basically means that if direction is 15, then it could either go
2244     * direction 4, 14, or 16 to get back to where we are.
2245     * Moved from spell_util.c to object.c with the other related direction
2246     * functions.
2247     */
2248 root 1.82 int reduction_dir[SIZEOFFREE][3] = {
2249 root 1.24 {0, 0, 0}, /* 0 */
2250     {0, 0, 0}, /* 1 */
2251     {0, 0, 0}, /* 2 */
2252     {0, 0, 0}, /* 3 */
2253     {0, 0, 0}, /* 4 */
2254     {0, 0, 0}, /* 5 */
2255     {0, 0, 0}, /* 6 */
2256     {0, 0, 0}, /* 7 */
2257     {0, 0, 0}, /* 8 */
2258     {8, 1, 2}, /* 9 */
2259     {1, 2, -1}, /* 10 */
2260     {2, 10, 12}, /* 11 */
2261     {2, 3, -1}, /* 12 */
2262     {2, 3, 4}, /* 13 */
2263     {3, 4, -1}, /* 14 */
2264     {4, 14, 16}, /* 15 */
2265     {5, 4, -1}, /* 16 */
2266     {4, 5, 6}, /* 17 */
2267     {6, 5, -1}, /* 18 */
2268     {6, 20, 18}, /* 19 */
2269     {7, 6, -1}, /* 20 */
2270     {6, 7, 8}, /* 21 */
2271     {7, 8, -1}, /* 22 */
2272     {8, 22, 24}, /* 23 */
2273     {8, 1, -1}, /* 24 */
2274     {24, 9, 10}, /* 25 */
2275     {9, 10, -1}, /* 26 */
2276     {10, 11, -1}, /* 27 */
2277     {27, 11, 29}, /* 28 */
2278     {11, 12, -1}, /* 29 */
2279     {12, 13, -1}, /* 30 */
2280     {12, 13, 14}, /* 31 */
2281     {13, 14, -1}, /* 32 */
2282     {14, 15, -1}, /* 33 */
2283     {33, 15, 35}, /* 34 */
2284     {16, 15, -1}, /* 35 */
2285     {17, 16, -1}, /* 36 */
2286     {18, 17, 16}, /* 37 */
2287     {18, 17, -1}, /* 38 */
2288     {18, 19, -1}, /* 39 */
2289     {41, 19, 39}, /* 40 */
2290     {19, 20, -1}, /* 41 */
2291     {20, 21, -1}, /* 42 */
2292     {20, 21, 22}, /* 43 */
2293     {21, 22, -1}, /* 44 */
2294     {23, 22, -1}, /* 45 */
2295     {45, 47, 23}, /* 46 */
2296     {23, 24, -1}, /* 47 */
2297     {24, 9, -1}
2298     }; /* 48 */
2299 elmex 1.1
2300     /* Recursive routine to step back and see if we can
2301     * find a path to that monster that we found. If not,
2302     * we don't bother going toward it. Returns 1 if we
2303     * can see a direct way to get it
2304     * Modified to be map tile aware -.MSW
2305     */
2306 root 1.24 int
2307 root 1.49 can_see_monsterP (maptile *m, int x, int y, int dir)
2308 root 1.24 {
2309 root 1.29 sint16 dx, dy;
2310 root 1.75 int mflags;
2311 root 1.24
2312     if (dir < 0)
2313     return 0; /* exit condition: invalid direction */
2314    
2315     dx = x + freearr_x[dir];
2316     dy = y + freearr_y[dir];
2317    
2318     mflags = get_map_flags (m, &m, dx, dy, &dx, &dy);
2319    
2320     /* This functional arguably was incorrect before - it was
2321     * checking for P_WALL - that was basically seeing if
2322     * we could move to the monster - this is being more
2323     * literal on if we can see it. To know if we can actually
2324     * move to the monster, we'd need the monster passed in or
2325     * at least its move type.
2326     */
2327     if (mflags & (P_OUT_OF_MAP | P_BLOCKSVIEW))
2328     return 0;
2329    
2330     /* yes, can see. */
2331     if (dir < 9)
2332     return 1;
2333 root 1.75
2334     return can_see_monsterP (m, x, y, reduction_dir[dir][0])
2335     | can_see_monsterP (m, x, y, reduction_dir[dir][1])
2336     | can_see_monsterP (m, x, y, reduction_dir[dir][2]);
2337 root 1.24 }
2338    
2339 elmex 1.1 /*
2340     * can_pick(picker, item): finds out if an object is possible to be
2341     * picked up by the picker. Returnes 1 if it can be
2342     * picked up, otherwise 0.
2343     *
2344     * Cf 0.91.3 - don't let WIZ's pick up anything - will likely cause
2345     * core dumps if they do.
2346     *
2347     * Add a check so we can't pick up invisible objects (0.93.8)
2348     */
2349    
2350 root 1.24 int
2351     can_pick (const object *who, const object *item)
2352     {
2353     return /*QUERY_FLAG(who,FLAG_WIZ)|| */
2354     (item->weight > 0 && !QUERY_FLAG (item, FLAG_NO_PICK) &&
2355     !QUERY_FLAG (item, FLAG_ALIVE) && !item->invisible && (who->type == PLAYER || item->weight < who->weight / 3));
2356 elmex 1.1 }
2357    
2358     /*
2359     * create clone from object to another
2360     */
2361 root 1.24 object *
2362     object_create_clone (object *asrc)
2363     {
2364 root 1.155 object *dst = 0, *tmp, *src, *prev, *item;
2365 elmex 1.1
2366 root 1.24 if (!asrc)
2367 root 1.62 return 0;
2368    
2369 root 1.155 src = asrc->head_ ();
2370 root 1.24
2371 root 1.62 prev = 0;
2372 root 1.155 for (object *part = src; part; part = part->more)
2373 root 1.24 {
2374 root 1.65 tmp = part->clone ();
2375 root 1.24 tmp->x -= src->x;
2376     tmp->y -= src->y;
2377 root 1.62
2378 root 1.24 if (!part->head)
2379     {
2380     dst = tmp;
2381 root 1.62 tmp->head = 0;
2382 root 1.24 }
2383     else
2384 root 1.75 tmp->head = dst;
2385 root 1.62
2386     tmp->more = 0;
2387    
2388 root 1.24 if (prev)
2389     prev->more = tmp;
2390 root 1.62
2391 root 1.24 prev = tmp;
2392 elmex 1.1 }
2393 root 1.24
2394     for (item = src->inv; item; item = item->below)
2395 root 1.48 insert_ob_in_ob (object_create_clone (item), dst);
2396 elmex 1.1
2397 root 1.24 return dst;
2398 elmex 1.1 }
2399    
2400     /* This returns the first object in who's inventory that
2401     * has the same type and subtype match.
2402     * returns NULL if no match.
2403     */
2404 root 1.24 object *
2405     find_obj_by_type_subtype (const object *who, int type, int subtype)
2406 elmex 1.1 {
2407 root 1.82 for (object *tmp = who->inv; tmp; tmp = tmp->below)
2408 root 1.24 if (tmp->type == type && tmp->subtype == subtype)
2409     return tmp;
2410 elmex 1.1
2411 root 1.82 return 0;
2412 elmex 1.1 }
2413    
2414     /* If ob has a field named key, return the link from the list,
2415     * otherwise return NULL.
2416     *
2417     * key must be a passed in shared string - otherwise, this won't
2418     * do the desired thing.
2419     */
2420 root 1.24 key_value *
2421     get_ob_key_link (const object *ob, const char *key)
2422     {
2423 root 1.82 for (key_value *link = ob->key_values; link; link = link->next)
2424 root 1.48 if (link->key == key)
2425     return link;
2426 root 1.24
2427 root 1.82 return 0;
2428 root 1.24 }
2429 elmex 1.1
2430     /*
2431     * Returns the value of op has an extra_field for key, or NULL.
2432     *
2433     * The argument doesn't need to be a shared string.
2434     *
2435     * The returned string is shared.
2436     */
2437 root 1.24 const char *
2438     get_ob_key_value (const object *op, const char *const key)
2439     {
2440 root 1.35 key_value *link;
2441     shstr_cmp canonical_key (key);
2442 root 1.24
2443 root 1.35 if (!canonical_key)
2444 root 1.24 {
2445     /* 1. There being a field named key on any object
2446     * implies there'd be a shared string to find.
2447     * 2. Since there isn't, no object has this field.
2448     * 3. Therefore, *this* object doesn't have this field.
2449     */
2450 root 1.35 return 0;
2451 elmex 1.1 }
2452    
2453 root 1.24 /* This is copied from get_ob_key_link() above -
2454     * only 4 lines, and saves the function call overhead.
2455     */
2456 root 1.35 for (link = op->key_values; link; link = link->next)
2457     if (link->key == canonical_key)
2458     return link->value;
2459    
2460     return 0;
2461 elmex 1.1 }
2462    
2463     /*
2464     * Updates the canonical_key in op to value.
2465     *
2466     * canonical_key is a shared string (value doesn't have to be).
2467     *
2468     * Unless add_key is TRUE, it won't add fields, only change the value of existing
2469     * keys.
2470     *
2471     * Returns TRUE on success.
2472     */
2473 root 1.24 int
2474     set_ob_key_value_s (object *op, const shstr & canonical_key, const char *value, int add_key)
2475     {
2476 root 1.82 key_value *field = NULL, *last = NULL;
2477 root 1.24
2478     for (field = op->key_values; field != NULL; field = field->next)
2479     {
2480     if (field->key != canonical_key)
2481     {
2482     last = field;
2483     continue;
2484     }
2485    
2486     if (value)
2487     field->value = value;
2488     else
2489     {
2490     /* Basically, if the archetype has this key set,
2491     * we need to store the null value so when we save
2492     * it, we save the empty value so that when we load,
2493     * we get this value back again.
2494     */
2495 root 1.159 if (get_ob_key_link (op->arch, canonical_key))
2496 root 1.24 field->value = 0;
2497     else
2498     {
2499     if (last)
2500     last->next = field->next;
2501     else
2502     op->key_values = field->next;
2503    
2504 root 1.29 delete field;
2505 root 1.24 }
2506     }
2507     return TRUE;
2508     }
2509     /* IF we get here, key doesn't exist */
2510    
2511     /* No field, we'll have to add it. */
2512    
2513     if (!add_key)
2514 root 1.82 return FALSE;
2515    
2516 root 1.24 /* There isn't any good reason to store a null
2517     * value in the key/value list. If the archetype has
2518     * this key, then we should also have it, so shouldn't
2519     * be here. If user wants to store empty strings,
2520     * should pass in ""
2521     */
2522     if (value == NULL)
2523 elmex 1.1 return TRUE;
2524 root 1.24
2525     field = new key_value;
2526    
2527     field->key = canonical_key;
2528     field->value = value;
2529     /* Usual prepend-addition. */
2530     field->next = op->key_values;
2531     op->key_values = field;
2532    
2533     return TRUE;
2534 elmex 1.1 }
2535    
2536     /*
2537     * Updates the key in op to value.
2538     *
2539     * If add_key is FALSE, this will only update existing keys,
2540     * and not add new ones.
2541     * In general, should be little reason FALSE is ever passed in for add_key
2542     *
2543     * Returns TRUE on success.
2544     */
2545 root 1.24 int
2546     set_ob_key_value (object *op, const char *key, const char *value, int add_key)
2547 root 1.11 {
2548 root 1.29 shstr key_ (key);
2549 root 1.24
2550 root 1.11 return set_ob_key_value_s (op, key_, value, add_key);
2551 elmex 1.1 }
2552 root 1.31
2553 root 1.34 object::depth_iterator::depth_iterator (object *container)
2554     : iterator_base (container)
2555     {
2556     while (item->inv)
2557     item = item->inv;
2558     }
2559    
2560 root 1.31 void
2561 root 1.34 object::depth_iterator::next ()
2562 root 1.31 {
2563 root 1.34 if (item->below)
2564     {
2565     item = item->below;
2566    
2567     while (item->inv)
2568     item = item->inv;
2569     }
2570 root 1.31 else
2571 root 1.34 item = item->env;
2572 root 1.31 }
2573 root 1.34
2574 elmex 1.97 const char *
2575     object::flag_desc (char *desc, int len) const
2576     {
2577     char *p = desc;
2578     bool first = true;
2579    
2580 root 1.101 *p = 0;
2581    
2582 elmex 1.97 for (int i = 0; i < NUM_FLAGS; i++)
2583     {
2584     if (len <= 10) // magic constant!
2585     {
2586     snprintf (p, len, ",...");
2587     break;
2588     }
2589    
2590 root 1.101 if (flag [i])
2591 elmex 1.97 {
2592     int cnt = snprintf (p, len, "%s%d", first ? "" : ",", i);
2593     len -= cnt;
2594     p += cnt;
2595     first = false;
2596     }
2597     }
2598    
2599     return desc;
2600     }
2601    
2602 root 1.101 // return a suitable string describing an object in enough detail to find it
2603 root 1.36 const char *
2604     object::debug_desc (char *info) const
2605     {
2606 elmex 1.97 char flagdesc[512];
2607     char info2[256 * 4];
2608 root 1.36 char *p = info;
2609    
2610 elmex 1.127 p += snprintf (p, 512, "{cnt:%d,uuid:<1.%" PRIx64 ">,name:\"%s\"%s%s,flags:[%s],type:%d}",
2611 elmex 1.97 count, uuid.seq,
2612 root 1.36 &name,
2613 root 1.117 title ? "\",title:\"" : "",
2614 elmex 1.97 title ? (const char *)title : "",
2615     flag_desc (flagdesc, 512), type);
2616 root 1.36
2617     if (env)
2618     p += snprintf (p, 256, "(in %s)", env->debug_desc (info2));
2619    
2620     if (map)
2621 root 1.96 p += snprintf (p, 256, "(on %s@%d+%d)", &map->path, x, y);
2622 root 1.36
2623     return info;
2624     }
2625    
2626     const char *
2627     object::debug_desc () const
2628     {
2629 root 1.143 static char info[3][256 * 4];
2630     static int info_idx;
2631 root 1.36
2632 root 1.143 return debug_desc (info [++info_idx % 3]);
2633 root 1.114 }
2634    
2635 root 1.125 struct region *
2636     object::region () const
2637     {
2638     return map ? map->region (x, y)
2639     : region::default_region ();
2640     }
2641    
2642 root 1.129 const materialtype_t *
2643     object::dominant_material () const
2644     {
2645     if (materialtype_t *mat = name_to_material (materialname))
2646     return mat;
2647    
2648     // omfg this is slow, this has to be temporary :)
2649     shstr unknown ("unknown");
2650    
2651     return name_to_material (unknown);
2652     }
2653    
2654 root 1.130 void
2655     object::open_container (object *new_container)
2656     {
2657     if (container == new_container)
2658     return;
2659    
2660     if (object *old_container = container)
2661     {
2662     if (INVOKE_OBJECT (CLOSE, old_container, ARG_OBJECT (this)))
2663     return;
2664    
2665     #if 0
2666     // remove the "Close old_container" object.
2667     if (object *closer = old_container->inv)
2668     if (closer->type == CLOSE_CON)
2669     closer->destroy ();
2670     #endif
2671    
2672     old_container->flag [FLAG_APPLIED] = 0;
2673     container = 0;
2674    
2675     esrv_update_item (UPD_FLAGS, this, old_container);
2676     new_draw_info_format (NDI_UNIQUE, 0, this, "You close %s.", query_name (old_container));
2677     }
2678    
2679     if (new_container)
2680     {
2681     if (INVOKE_OBJECT (OPEN, new_container, ARG_OBJECT (this)))
2682     return;
2683    
2684     // TODO: this does not seem to serve any purpose anymore?
2685     #if 0
2686     // insert the "Close Container" object.
2687     if (archetype *closer = new_container->other_arch)
2688     {
2689     object *closer = arch_to_object (new_container->other_arch);
2690     closer->flag [FLAG_NO_MAP_SAVE] = 1;
2691     new_container->insert (closer);
2692     }
2693     #endif
2694    
2695 root 1.132 new_draw_info_format (NDI_UNIQUE, 0, this, "You open %s.", query_name (new_container));
2696    
2697 root 1.130 new_container->flag [FLAG_APPLIED] = 1;
2698     container = new_container;
2699    
2700     esrv_update_item (UPD_FLAGS, this, new_container);
2701 root 1.131 esrv_send_inventory (this, new_container);
2702 root 1.130 }
2703     }
2704    
2705