ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
Revision: 1.336
Committed: Wed Apr 28 11:19:09 2010 UTC (14 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.335: +8 -3 lines
Log Message:
re-appl<y no-auto-exit hack :(

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