ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
Revision: 1.207
Committed: Sun Apr 20 23:25:09 2008 UTC (16 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.206: +43 -61 lines
Log Message:
minor refactoring

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