ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
Revision: 1.204
Committed: Fri Apr 11 17:01:52 2008 UTC (16 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.203: +12 -5 lines
Log Message:
beeing too clever for ones own good is not good

File Contents

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