ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
Revision: 1.142
Committed: Mon Apr 30 04:25:29 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.141: +2 -7 lines
Log Message:
This is the first rough cut of the skill use system (use the STABLE tag).

Details will likely change, and combat skills do not work very well, but
it works quite well.

Players no longer have a shoottype or range slots, instead, each player
has these members:

   combat_skill/combat_ob  the currently selected skill (and weapon)
                           for direct attacks.
   ranged_skill/ranged_ob  the currently selected ranged skill (and
                           bow/spell/item)
   golem                   the currently-controlled golem, if any.

File Contents

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