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