ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
Revision: 1.342
Committed: Sun Apr 10 20:30:53 2011 UTC (13 years, 1 month ago) by sf-kernelpanic
Content type: text/plain
Branch: MAIN
Changes since 1.341: +4 -3 lines
Log Message:
object.C: don't merge "renamed" items

Before, it was possible to just pickup one item from a stack, rename
it and "taint" the stack with the new name by just dropping it.

With this patch the renamed item will not be merged into the stack.

Objects with the same "custom" name will still merge.

Another use case would be the separation of certain types of items which
are often found in dungeons, e.g. levitation boots. One could rename one
pair of levitation boots and use it whenever he needs to, and other
boots which would normally merge with it will form a new stack.

File Contents

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