ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/object.C
Revision: 1.163
Committed: Sun Jul 1 05:00:17 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.162: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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