ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
Revision: 1.142
Committed: Mon Apr 30 04:25:29 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.141: +2 -7 lines
Log Message:
This is the first rough cut of the skill use system (use the STABLE tag).

Details will likely change, and combat skills do not work very well, but
it works quite well.

Players no longer have a shoottype or range slots, instead, each player
has these members:

   combat_skill/combat_ob  the currently selected skill (and weapon)
                           for direct attacks.
   ranged_skill/ranged_ob  the currently selected ranged skill (and
                           bow/spell/item)
   golem                   the currently-controlled golem, if any.

File Contents

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