ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
Revision: 1.203
Committed: Fri Apr 11 13:59:05 2008 UTC (16 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.202: +40 -37 lines
Log Message:
*** empty log message ***

File Contents

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