Crossfire Server, Trunk  R213250
object.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
20  object_sub/add_weight will transcend the environment updating the carrying
21  variable. */
22 
23 #include "global.h"
24 
25 #include <assert.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #ifndef WIN32 /* ---win32 exclude headers */
32 #include <sys/types.h>
33 #include <sys/uio.h>
34 #endif /* win32 */
35 
36 #include "loader.h"
37 #include "object.h"
38 #include "skills.h"
39 #include "sproto.h"
40 #include "stringbuffer.h"
41 
42 static int compare_ob_value_lists_one(const object *, const object *);
43 static int compare_ob_value_lists(const object *, const object *);
44 static void expand_objects(void);
45 static void permute(int *, int, int);
46 static int object_set_value_s(object *, const char *, const char *, int);
47 static void object_increase_nrof(object *op, uint32_t i);
48 
49 #ifdef MEMORY_DEBUG
50 int nroffreeobjects = 0;
51 int nrofallocobjects = 0;
52 #undef OBJ_EXPAND
53 #define OBJ_EXPAND 1
54 #else
55 static object objarray[STARTMAX];
58 #endif
59 
60 object *objects;
61 static object *free_objects;
62 object *active_objects;
66  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,
67  0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
68 };
69 
72  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,
73  -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3
74 };
75 
78  0, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45,
79  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
80 };
81 
84  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,
85  1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
86 };
87 
93 void init_objects(void) {
94  /* Initialize all objects: */
95  objects = NULL;
96  active_objects = NULL;
97 
98 #ifdef MEMORY_DEBUG
99  free_objects = NULL;
100 #else
101  free_objects = objarray;
102  objarray[0].prev = NULL,
103  objarray[0].next = &objarray[1],
104  SET_FLAG(&objarray[0], FLAG_REMOVED);
105  SET_FLAG(&objarray[0], FLAG_FREED);
106  for (int i = 1; i < STARTMAX-1; i++) {
107  objarray[i].next = &objarray[i+1];
108  objarray[i].prev = &objarray[i-1];
109  SET_FLAG(&objarray[i], FLAG_REMOVED);
110  SET_FLAG(&objarray[i], FLAG_FREED);
111  }
112  objarray[STARTMAX-1].next = NULL;
113  objarray[STARTMAX-1].prev = &objarray[STARTMAX-2];
114  SET_FLAG(&objarray[STARTMAX-1], FLAG_REMOVED);
115  SET_FLAG(&objarray[STARTMAX-1], FLAG_FREED);
116 #endif
117 }
118 
129 static int compare_ob_value_lists_one(const object *wants, const object *has) {
130  key_value *wants_field;
131 
132  /* n-squared behaviour (see object_get_key_value()), but I'm hoping both
133  * objects with lists are rare, and lists stay short. If not, use a
134  * different structure or at least keep the lists sorted...
135  */
136 
137  /* For each field in wants, */
138  for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) {
139  key_value *has_field;
140 
141  /* Look for a field in has with the same key. */
142  has_field = object_get_key_value(has, wants_field->key);
143 
144  if (has_field == NULL) {
145  /* No field with that name. */
146  return FALSE;
147  }
148 
149  /* Found the matching field. */
150  if (has_field->value != wants_field->value) {
151  /* Values don't match, so this half of the comparison is false. */
152  return FALSE;
153  }
154 
155  /* If we get here, we found a match. Now for the next field in wants. */
156  }
157 
158  /* If we get here, every field in wants has a matching field in has. */
159  return TRUE;
160 }
161 
170 static int compare_ob_value_lists(const object *ob1, const object *ob2) {
171  /* However, there may be fields in has which aren't partnered in wants,
172  * so we need to run the comparison *twice*. :(
173  */
174  return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1);
175 }
176 
202 int object_can_merge(object *ob1, object *ob2) {
203  /* A couple quicksanity checks */
204  if (ob1 == ob2 || ob1->type != ob2->type)
205  return 0;
206 
207  if (ob1->speed != ob2->speed)
208  return 0;
209  /* Note sure why the following is the case - either the object has to
210  * be animated or have a very low speed. Is this an attempted monster
211  * check?
212  */
213  /*TODO is this check really needed?*/
214  if (!QUERY_FLAG(ob1, FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
215  return 0;
216 
217  /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
218  * value could not be stored in a int32_t (which unfortunately sometimes is
219  * used to store nrof).
220  */
221  if (ob1->nrof+ob2->nrof >= 1UL<<31)
222  return 0;
223 
224  /* This is really a spellbook check - really, we should
225  * check all objects in the inventory.
226  */
227  /*TODO is this check really needed?*/
228  if (ob1->inv || ob2->inv) {
229  /* if one object has inventory but the other doesn't, not equiv */
230  if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
231  return 0;
232 
233  /* Now check to see if the two inventory objects could merge */
234  if (!object_can_merge(ob1->inv, ob2->inv))
235  return 0;
236 
237  /* inventory ok - still need to check rest of this object to see
238  * if it is valid.
239  */
240  }
241 
242  /* If the objects have been identified, set the BEEN_APPLIED flag.
243  * This is to the comparison of the flags below will be OK. We
244  * just can't ignore the been applied or identified flags, as they
245  * are not equal - just if it has been identified, the been_applied
246  * flags lose any meaning.
247  */
248 
249  /*TODO is this hack on BEEN_APPLIED really needed? */
250  if (QUERY_FLAG(ob1, FLAG_IDENTIFIED))
252 
253  if (QUERY_FLAG(ob2, FLAG_IDENTIFIED))
255 
256 
257  /* Note: FLAG_INV_LOCKED is ignored for merging purposes */
258  if ((ob1->arch != ob2->arch)
259  || (ob1->flags[0] != ob2->flags[0])
260  || (ob1->flags[1] != ob2->flags[1])
261  || (ob1->flags[2] != ob2->flags[2])
262  || ((ob1->flags[3]&~0x84) != (ob2->flags[3]&~0x84)) /* ignore CLIENT_SENT and FLAG_OBJ_ORIGINAL */
263  || (ob1->name != ob2->name)
264  || (ob1->title != ob2->title)
265  || (ob1->msg != ob2->msg)
266  || (ob1->weight != ob2->weight)
267  || (ob1->item_power != ob2->item_power)
268  || (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist)) != 0)
269  || (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats)) != 0)
270  || (ob1->attacktype != ob2->attacktype)
271  || (ob1->magic != ob2->magic)
272  || (ob1->slaying != ob2->slaying)
273  || (ob1->skill != ob2->skill)
274  || (ob1->value != ob2->value)
275  || (ob1->animation_id != ob2->animation_id)
276  || (ob1->client_type != ob2->client_type)
277  || (ob1->materialname != ob2->materialname)
278  || (ob1->lore != ob2->lore)
279  || (ob1->subtype != ob2->subtype)
280  || (ob1->move_type != ob2->move_type)
281  || (ob1->move_block != ob2->move_block)
282  || (ob1->move_allow != ob2->move_allow)
283  || (ob1->move_on != ob2->move_on)
284  || (ob1->move_off != ob2->move_off)
285  || (ob1->move_slow != ob2->move_slow)
286  || (ob1->move_slow_penalty != ob2->move_slow_penalty)
287  || (ob1->map_layer != ob2->map_layer))
288  return 0;
289 
290  /* Don't merge objects that are applied. With the new 'body' code,
291  * it is possible for most any character to have more than one of
292  * some items equipped, and we don't want those to merge.
293  */
294  if (QUERY_FLAG(ob1, FLAG_APPLIED) || QUERY_FLAG(ob2, FLAG_APPLIED))
295  return 0;
296 
297  if (ob1->key_values != NULL || ob2->key_values != NULL) {
298  /* At least one of these has key_values. */
299  if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
300  /* One has fields, but the other one doesn't. */
301  return 0;
302  } else {
303  return compare_ob_value_lists(ob1, ob2);
304  }
305  }
306 
307  /*TODO should this really be limited to scrolls?*/
308  switch (ob1->type) {
309  case SCROLL:
310  if (ob1->level != ob2->level)
311  return 0;
312  break;
313  }
314 
315  /* Don't merge items with differing custom names. */
316  if (ob1->custom_name != ob2->custom_name)
317  return 0;
318 
319  /* Everything passes, must be OK. */
320  return 1;
321 }
322 
341 /* TODO should check call this this are made a place where we really need reevaluaton of whole tree */
342 signed long object_sum_weight(object *op) {
343  signed long sum;
344 
345  sum = 0;
346  FOR_INV_PREPARE(op, inv) {
347  if (inv->inv)
348  object_sum_weight(inv);
349  sum += inv->carrying+inv->weight*NROF(inv);
350  } FOR_INV_FINISH();
351  if (op->type == CONTAINER && op->stats.Str)
352  sum = (sum*(100-op->stats.Str))/100;
353  op->carrying = sum;
354  return sum;
355 }
356 
364 object *object_get_env_recursive(object *op) {
365  while (op->env != NULL)
366  op = op->env;
367  return op;
368 }
369 
384 object *object_get_player_container(object *op) {
385  for (; op != NULL && op->type != PLAYER; op = op->env)
386  /*TODO this is patching the structure on the flight as side effect. Shoudln't be needed in clean code */
387  if (op->env == op)
388  op->env = NULL;
389  return op;
390 }
391 
401 static const object *object_get_owner_const(const object *op) {
402  if (op->owner == NULL)
403  return NULL;
404 
405  if (!QUERY_FLAG(op->owner, FLAG_FREED)
406  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
407  && op->owner->count == op->ownercount)
408  return op->owner;
409 
410  LOG(llevError, "Warning, no owner found\n");
411  return NULL;
412 }
413 
425 void object_dump(const object *op, StringBuffer *sb) {
426  if (op == NULL) {
427  stringbuffer_append_string(sb, "[NULL pointer]");
428  return;
429  }
430 
431  /* object *tmp;*/
432 
433  if (op->arch != NULL) {
434  const object *owner;
435 
436  stringbuffer_append_string(sb, "arch ");
437  stringbuffer_append_string(sb, op->arch->name ? op->arch->name : "(null)");
438  stringbuffer_append_string(sb, "\n");
439 
440  if (op->artifact != NULL) {
441  stringbuffer_append_string(sb, "artifact ");
443  stringbuffer_append_string(sb, "\n");
444  }
445 
446  get_ob_diff(sb, op, &empty_archetype->clone);
447  if (op->more) {
448  stringbuffer_append_printf(sb, "more %u\n", op->more->count);
449  }
450  if (op->head) {
451  stringbuffer_append_printf(sb, "head %u\n", op->head->count);
452  }
453  if (op->env) {
454  stringbuffer_append_printf(sb, "env %u\n", op->env->count);
455  }
456  if (op->inv) {
457  stringbuffer_append_printf(sb, "inv %u\n", op->inv->count);
458  }
459  owner = object_get_owner_const(op);
460  if (owner != NULL) {
461  stringbuffer_append_printf(sb, "owner %u\n", owner->count);
462  }
463  stringbuffer_append_string(sb, "end\n");
464  } else {
465  stringbuffer_append_string(sb, "Object ");
466  stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
467  stringbuffer_append_string(sb, "\nend\n");
468  }
469 }
470 
481 void object_dump_all(void) {
482  object *op;
483 
484  for (op = objects; op != NULL; op = op->next) {
485  StringBuffer *sb;
486  char *diff;
487 
488  sb = stringbuffer_new();
489  object_dump(op, sb);
490  diff = stringbuffer_finish(sb);
491  LOG(llevDebug, "Object %u\n:%s\n", op->count, diff);
492  free(diff);
493  }
494 }
495 
508  object *op;
509 
510  for (op = objects; op != NULL; op = op->next)
511  if (op->count == i)
512  break;
513  return op;
514 }
515 
530 object *object_find_by_name_global(const char *str) {
531  const char *name = add_string(str);
532  object *op;
533 
534  for (op = objects; op != NULL; op = op->next)
535  if (op->name == name)
536  break;
537  free_string(name);
538  return op;
539 }
540 
554 #ifdef MEMORY_DEBUG
555  object *op, *next;
556 
557  for (op = free_objects; op != NULL; ) {
558  next = op->next;
559  free(op);
561  nroffreeobjects--;
562  op = next;
563  }
564  free_objects = NULL;
565 
566  for (op = objects; op != NULL; ) {
567  next = op->next;
568  if (!QUERY_FLAG(op, FLAG_FREED)) {
569  LOG(llevDebug, "non freed object: %s\n", op->name);
570  }
571  op = next;
572  }
573 #endif
574 
575  LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX);
576 }
577 
590 object *object_get_owner(object *op) {
591  if (op->owner == NULL)
592  return NULL;
593 
594  if (!QUERY_FLAG(op->owner, FLAG_FREED)
595  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
596  && op->owner->count == op->ownercount)
597  return op->owner;
598 
599  object_clear_owner(op);
600  return NULL;
601 }
602 
612 void object_clear_owner(object *op) {
613  if (!op)
614  return;
615 
616  op->owner = NULL;
617  op->ownercount = 0;
618 }
619 
632 void object_set_owner(object *op, object *owner) {
633  /* Assign temp to something, so it can't accidentally be NULL */
634  object *tmp = owner;
635  if (op == NULL)
636  return;
637  if (owner == NULL) {
638  object_clear_owner(op);
639  return;
640  }
641 
642  /* next line added to allow objects which own objects */
643  /* Add a check for ownercounts in here, as I got into an endless loop
644  * with the fireball owning a poison cloud which then owned the
645  * fireball. I believe that was caused by one of the objects getting
646  * freed and then another object replacing it. Since the ownercounts
647  * didn't match, this check is valid and I believe that cause is valid.
648  */
649  /*
650  * if owner is NULL, function will have already returned,
651  * so loop should still function as before.
652  */
653  while (tmp) {
654  tmp = object_get_owner(owner);
655  if (tmp)
656  owner = tmp;
657  }
658 
659  /* must not cause owner cycles */
660  assert(op != owner);
661 
662  if (op->owner != NULL)
663  object_clear_owner(op);
664 
665  op->owner = owner;
666  op->ownercount = owner->count;
667 }
668 
688 void object_copy_owner(object *op, object *clone) {
689  object *owner = object_get_owner(clone);
690  if (owner == NULL) {
691  /* players don't have owners - they own themselves. Update
692  * as appropriate.
693  */
694  /*TODO owner=self is dangerous and should be avoided*/
695  if (clone->type != PLAYER)
696  return;
697  owner = clone;
698  }
699  object_set_owner(op, owner);
700 }
701 
710 void object_set_enemy(object *op, object *enemy) {
711  if (op->enemy == enemy) {
712  return;
713  }
714 
715 #if 0
716  if (op->type != PLAYER) {
717  LOG(llevDebug, "object_set_enemy: %s(%lu)->enemy=%s(%lu)\n", op->name, op->count, enemy == NULL ? "NONE" : enemy->name, enemy == NULL ? 0 : enemy->count);
718  }
719 #endif
720  op->enemy = enemy;
721 }
722 
735 void object_reset(object *op) {
736  op->name = NULL;
737  op->name_pl = NULL;
738  op->title = NULL;
739  op->race = NULL;
740  op->slaying = NULL;
741  op->skill = NULL;
742  op->msg = NULL;
743  op->materialname = NULL;
744  op->lore = NULL;
745  object_clear(op);
746 }
747 
758 void object_free_key_values(object *op) {
759  key_value *i;
760  key_value *next = NULL;
761 
762  if (op->key_values == NULL)
763  return;
764 
765  for (i = op->key_values; i != NULL; i = next) {
766  /* Store next *first*. */
767  next = i->next;
768 
769  if (i->key)
771  if (i->value)
773  i->next = NULL;
774  free(i);
775  }
776 
777  op->key_values = NULL;
778 }
779 
790 void object_clear(object *op) {
791  /*TODO this comment must be investigated*/
792  /* redo this to be simpler/more efficient. Was also seeing
793  * crashes in the old code. Move this to the top - am
794  * seeing periodic crashes in this code, and would like to have
795  * as much info available as possible (eg, object name).
796  */
799 
800  /* the memset will clear all these values for us, but we need
801  * to reduce the refcount on them.
802  */
803  if (op->name != NULL)
805  if (op->name_pl != NULL)
807  if (op->title != NULL)
809  if (op->race != NULL)
811  if (op->slaying != NULL)
813  if (op->skill != NULL)
815  if (op->msg != NULL)
816  FREE_AND_CLEAR_STR(op->msg);
817  if (op->lore != NULL)
819  if (op->materialname != NULL)
821  if (op->discrete_damage != NULL)
823 
824  /* Remove object from friendly list if needed. */
825  if (QUERY_FLAG(op, FLAG_FRIENDLY))
827 
828  memset((void *)((char *)op+offsetof(object, name)), 0, sizeof(object)-offsetof(object, name));
829  /* Below here, we clear things that are not done by the memset,
830  * or set default values that are not zero.
831  */
832  /* This is more or less true */
833  SET_FLAG(op, FLAG_REMOVED);
834 
835 
836  op->contr = NULL;
837  op->below = NULL;
838  op->above = NULL;
839  op->inv = NULL;
840  op->container = NULL;
841  op->env = NULL;
842  op->more = NULL;
843  op->head = NULL;
844  op->map = NULL;
845  op->active_next = NULL;
846  op->active_prev = NULL;
847  /* What is not cleared is next, prev, and count */
848 
849  op->expmul = 1.0;
850  op->face = blank_face;
851  op->attacked_by_count = -1;
853  op->casting_time = -1;
854 }
855 
869 void object_copy(const object *src_ob, object *dest_ob) {
870  int is_freed = QUERY_FLAG(dest_ob, FLAG_FREED), is_removed = QUERY_FLAG(dest_ob, FLAG_REMOVED);
871 
872  /* Decrement the refcounts, but don't bother zeroing the fields;
873  they'll be overwritten by memcpy. */
874  if (dest_ob->artifact != NULL)
875  free_string(dest_ob->artifact);
876  if (dest_ob->name != NULL)
877  free_string(dest_ob->name);
878  if (dest_ob->name_pl != NULL)
879  free_string(dest_ob->name_pl);
880  if (dest_ob->anim_suffix != NULL)
881  free_string(dest_ob->anim_suffix);
882  if (dest_ob->title != NULL)
883  free_string(dest_ob->title);
884  if (dest_ob->race != NULL)
885  free_string(dest_ob->race);
886  if (dest_ob->slaying != NULL)
887  free_string(dest_ob->slaying);
888  if (dest_ob->skill != NULL)
889  free_string(dest_ob->skill);
890  if (dest_ob->msg != NULL)
891  free_string(dest_ob->msg);
892  if (dest_ob->lore != NULL)
893  free_string(dest_ob->lore);
894  if (dest_ob->materialname != NULL)
895  free_string(dest_ob->materialname);
896  if (dest_ob->custom_name != NULL)
897  free_string(dest_ob->custom_name);
898  if (dest_ob->discrete_damage != NULL)
900  if (dest_ob->spell_tags != NULL)
901  FREE_AND_CLEAR(dest_ob->spell_tags);
902 
903  /* Basically, same code as from object_clear() */
904 
905  object_free_key_values(dest_ob);
906  free_dialog_information(dest_ob);
907 
908  /* Copy all attributes below name (name included). */
909  (void)memcpy((void *)((char *)dest_ob+offsetof(object, name)),
910  (void *)((char *)src_ob+offsetof(object, name)),
911  sizeof(object)-offsetof(object, name));
912 
913  if (is_freed)
914  SET_FLAG(dest_ob, FLAG_FREED);
915  if (is_removed)
916  SET_FLAG(dest_ob, FLAG_REMOVED);
917  if (dest_ob->artifact != NULL)
918  add_refcount(dest_ob->artifact);
919  if (dest_ob->name != NULL)
920  add_refcount(dest_ob->name);
921  if (dest_ob->name_pl != NULL)
922  add_refcount(dest_ob->name_pl);
923  if (dest_ob->anim_suffix != NULL)
924  add_refcount(dest_ob->anim_suffix);
925  if (dest_ob->title != NULL)
926  add_refcount(dest_ob->title);
927  if (dest_ob->race != NULL)
928  add_refcount(dest_ob->race);
929  if (dest_ob->slaying != NULL)
930  add_refcount(dest_ob->slaying);
931  if (dest_ob->skill != NULL)
932  add_refcount(dest_ob->skill);
933  if (dest_ob->lore != NULL)
934  add_refcount(dest_ob->lore);
935  if (dest_ob->msg != NULL)
936  add_refcount(dest_ob->msg);
937  if (dest_ob->custom_name != NULL)
938  add_refcount(dest_ob->custom_name);
939  if (dest_ob->materialname != NULL)
940  add_refcount(dest_ob->materialname);
941  if (dest_ob->discrete_damage != NULL) {
942  dest_ob->discrete_damage = malloc(sizeof(int16_t)*NROFATTACKS);
943  memcpy(dest_ob->discrete_damage, src_ob->discrete_damage, sizeof(int16_t)*NROFATTACKS);
944  }
945 
946  if (dest_ob->spell_tags != NULL) {
947  dest_ob->spell_tags = malloc(sizeof(tag_t)*SPELL_TAG_SIZE);
948  memcpy(dest_ob->spell_tags, src_ob->spell_tags, sizeof(tag_t)*SPELL_TAG_SIZE);
949  }
950 
951  /* If archetype is a temporary one, we need to update reference count, because
952  * that archetype will be freed by object_free_drop_inventory() when the last object is removed.
953  */
954  if (dest_ob->arch->reference_count > 0)
955  dest_ob->arch->reference_count++;
956 
957  if (src_ob->speed < 0)
958  dest_ob->speed_left = src_ob->speed_left-RANDOM()%200/100.0;
959 
960  /* Copy over key_values, if any. */
961  if (src_ob->key_values != NULL) {
962  key_value *tail = NULL;
963  key_value *i;
964 
965  dest_ob->key_values = NULL;
966 
967  for (i = src_ob->key_values; i != NULL; i = i->next) {
968  key_value *new_link = malloc(sizeof(key_value));
969 
970  new_link->next = NULL;
971  new_link->key = add_refcount(i->key);
972  if (i->value)
973  new_link->value = add_refcount(i->value);
974  else
975  new_link->value = NULL;
976 
977  /* Try and be clever here, too. */
978  if (dest_ob->key_values == NULL) {
979  dest_ob->key_values = new_link;
980  tail = new_link;
981  } else {
982  tail->next = new_link;
983  tail = new_link;
984  }
985  }
986  }
987 
988  /* This way, dialog information will be parsed again when/if needed. */
989  CLEAR_FLAG(dest_ob, FLAG_DIALOG_PARSED);
990 
991  object_update_speed(dest_ob);
992 }
993 
1006 void object_copy_with_inv(const object *src_ob, object *dest_ob) {
1007  object_copy(src_ob, dest_ob);
1008  FOR_INV_PREPARE(src_ob, walk) {
1009  object *tmp;
1010 
1011  tmp = object_new();
1012  object_copy_with_inv(walk, tmp);
1013  object_insert_in_ob(tmp, dest_ob);
1014  } FOR_INV_FINISH();
1015 }
1016 
1024 static void expand_objects(void) {
1025  int i;
1026  object *new;
1027 
1028  new = (object *)CALLOC(OBJ_EXPAND, sizeof(object));
1029 
1030  if (new == NULL)
1032  free_objects = new;
1033  new[0].prev = NULL;
1034  new[0].next = &new[1],
1035  SET_FLAG(&new[0], FLAG_REMOVED);
1036  SET_FLAG(&new[0], FLAG_FREED);
1037 
1038  for (i = 1; i < OBJ_EXPAND-1; i++) {
1039  new[i].next = &new[i+1],
1040  new[i].prev = &new[i-1],
1041  SET_FLAG(&new[i], FLAG_REMOVED);
1042  SET_FLAG(&new[i], FLAG_FREED);
1043  }
1044  new[OBJ_EXPAND-1].prev = &new[OBJ_EXPAND-2],
1045  new[OBJ_EXPAND-1].next = NULL,
1046  SET_FLAG(&new[OBJ_EXPAND-1], FLAG_REMOVED);
1047  SET_FLAG(&new[OBJ_EXPAND-1], FLAG_FREED);
1048 
1051 }
1052 
1068 object *object_new(void) {
1069  object *op;
1070 #ifdef MEMORY_DEBUG
1071  /* FIXME: However this doesn't work since object_free() sometimes add
1072  * objects back to the free_objects linked list, and some functions mess
1073  * with the object after return of object_free(). This is bad and should be
1074  * fixed. But it would need fairly extensive changes and a lot of debugging.
1075  */
1076  op = calloc(1, sizeof(object));
1077  if (op == NULL)
1079 #else
1080  if (free_objects == NULL) {
1081  expand_objects();
1082  }
1083  op = free_objects;
1084  if (!QUERY_FLAG(op, FLAG_FREED)) {
1085  LOG(llevError, "Fatal: Getting busy object.\n");
1086 #ifdef MANY_CORES
1087  abort();
1088 #endif
1089  }
1090  free_objects = op->next;
1091  if (free_objects != NULL)
1092  free_objects->prev = NULL;
1093  nroffreeobjects--;
1094 #endif
1095  op->count = ++ob_count;
1096  op->name = NULL;
1097  op->name_pl = NULL;
1098  op->title = NULL;
1099  op->race = NULL;
1100  op->slaying = NULL;
1101  op->skill = NULL;
1102  op->lore = NULL;
1103  op->msg = NULL;
1104  op->materialname = NULL;
1105  op->next = objects;
1106  op->prev = NULL;
1107  op->active_next = NULL;
1108  op->active_prev = NULL;
1109  op->discrete_damage = NULL;
1110  op->spell_tags = NULL;
1111  if (objects != NULL)
1112  objects->prev = op;
1113  objects = op;
1114  object_clear(op);
1115  SET_FLAG(op, FLAG_REMOVED);
1116  return op;
1117 }
1118 
1130 void object_update_turn_face(object *op) {
1131  if (op->animation_id == 0 || !QUERY_FLAG(op, FLAG_IS_TURNABLE))
1132  return;
1133  animate_object(op, op->direction);
1134 }
1135 
1150 void object_update_speed(object *op) {
1151  /* FIXME what the hell is this crappy hack?*/
1152  extern int arch_init;
1153 
1154  /* No reason putting the archetypes objects on the speed list,
1155  * since they never really need to be updated.
1156  */
1157 
1158  if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
1159  LOG(llevError, "Object %s is freed but has speed.\n", op->name);
1160 #ifdef MANY_CORES
1161  abort();
1162 #else
1163  op->speed = 0;
1164 #endif
1165  }
1166  if (arch_init) {
1167  return;
1168  }
1169  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
1170  /* If already on active list, don't do anything */
1171  /* TODO this check can probably be simplified a lot */
1172  if (op->active_next || op->active_prev || op == active_objects)
1173  return;
1174 
1175  /* process_events() expects us to insert the object at the beginning
1176  * of the list. */
1178  if (op->active_next != NULL)
1179  op->active_next->active_prev = op;
1180  active_objects = op;
1181  } else {
1182  /* If not on the active list, nothing needs to be done */
1183  if (!op->active_next && !op->active_prev && op != active_objects)
1184  return;
1185 
1186  if (op->active_prev == NULL) {
1187  active_objects = op->active_next;
1188  if (op->active_next != NULL)
1189  op->active_next->active_prev = NULL;
1190  } else {
1191  op->active_prev->active_next = op->active_next;
1192  if (op->active_next)
1193  op->active_next->active_prev = op->active_prev;
1194  }
1195  op->active_next = NULL;
1196  op->active_prev = NULL;
1197  }
1198 }
1199 
1216  /* If not on the active list, nothing needs to be done */
1217  if (!op->active_next && !op->active_prev && op != active_objects)
1218  return;
1219 
1220  if (op->active_prev == NULL) {
1221  active_objects = op->active_next;
1222  if (op->active_next != NULL)
1223  op->active_next->active_prev = NULL;
1224  } else {
1225  op->active_prev->active_next = op->active_next;
1226  if (op->active_next)
1227  op->active_next->active_prev = op->active_prev;
1228  }
1229  op->active_next = NULL;
1230  op->active_prev = NULL;
1231 }
1232 
1260 void object_update(object *op, int action) {
1261  int update_now = 0, flags;
1262  MoveType move_on, move_off, move_block, move_slow;
1263  object *pl;
1264 
1265  if (op == NULL) {
1266  /* this should never happen */
1267  LOG(llevDebug, "object_update() called for NULL object.\n");
1268  return;
1269  }
1270 
1271  if (op->env != NULL) {
1272  /* Animation is currently handled by client, so nothing
1273  * to do in this case.
1274  */
1275  return;
1276  }
1277 
1278  /* If the map is saving, don't do anything as everything is
1279  * going to get freed anyways.
1280  */
1281  if (!op->map || op->map->in_memory == MAP_SAVING)
1282  return;
1283 
1284  /* make sure the object is within map boundaries */
1285  if (op->x < 0 || op->x >= MAP_WIDTH(op->map)
1286  || op->y < 0 || op->y >= MAP_HEIGHT(op->map)) {
1287  LOG(llevError, "object_update() called for object out of map!\n");
1288 #ifdef MANY_CORES
1289  abort();
1290 #endif
1291  return;
1292  }
1293 
1294  flags = GET_MAP_FLAGS(op->map, op->x, op->y);
1295  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NEED_UPDATE);
1296  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
1297  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
1298  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
1299  move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y);
1300 
1301  if (action == UP_OBJ_INSERT) {
1303  update_now = 1;
1304 
1305  if (QUERY_FLAG(op, FLAG_NO_MAGIC) && !(flags&P_NO_MAGIC))
1306  update_now = 1;
1307 
1308  if (QUERY_FLAG(op, FLAG_DAMNED) && !(flags&P_NO_CLERIC))
1309  update_now = 1;
1310 
1311  if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags&P_IS_ALIVE))
1312  update_now = 1;
1313 
1314  if ((move_on|op->move_on) != move_on)
1315  update_now = 1;
1316  if ((move_off|op->move_off) != move_off)
1317  update_now = 1;
1318  /* This isn't perfect, but I don't expect a lot of objects to
1319  * to have move_allow right now.
1320  */
1321  if (((move_block|op->move_block)&~op->move_allow) != move_block)
1322  update_now = 1;
1323  if ((move_slow|op->move_slow) != move_slow)
1324  update_now = 1;
1325 
1326  if (op->type == PLAYER)
1327  update_now = 1;
1328  /* if the object is being removed, we can't make intelligent
1329  * decisions, because object_remove() can't really pass the object
1330  * that is being removed.
1331  */
1332  } else if (action == UP_OBJ_REMOVE) {
1333  update_now = 1;
1334  } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) {
1335  /* In addition to sending info to client, need to update space
1336  * information.
1337  */
1338  if (action == UP_OBJ_CHANGE)
1339  update_now = 1;
1340 
1341  /* There is a player on this space - we may need to send an
1342  * update to the client.
1343  * If this object is supposed to be animated by the client,
1344  * nothing to do here - let the client animate it.
1345  * We can't use FLAG_ANIMATE, as that is basically set for
1346  * all objects with multiple faces, regardless if they are animated.
1347  * (levers have it set for example).
1348  */
1349  if (flags&P_PLAYER
1352  pl = GET_MAP_PLAYER(op->map, op->x, op->y);
1353 
1354  /* If update_look is set, we're going to send this entire space
1355  * to the client, so no reason to send face information now.
1356  */
1357  if (!pl->contr->socket.update_look) {
1358  esrv_update_item(UPD_FACE, pl, op);
1359  }
1360  }
1361  } else {
1362  LOG(llevError, "object_update called with invalid action: %d\n", action);
1363  }
1364 
1365  if (update_now) {
1366  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NO_ERROR|P_NEED_UPDATE);
1367  update_position(op->map, op->x, op->y);
1368  }
1369 
1370  if (op->more != NULL)
1371  object_update(op->more, action);
1372 }
1373 
1389 void object_free_drop_inventory(object *ob) {
1390  object_free(ob, 0);
1391 }
1392 
1409 void object_free(object *ob, int flags) {
1410  if (!QUERY_FLAG(ob, FLAG_REMOVED)) {
1411  StringBuffer *sb;
1412  char *diff;
1413 
1414  LOG(llevDebug, "Free object called with non removed object\n");
1415  sb = stringbuffer_new();
1416  object_dump(ob, sb);
1417  diff = stringbuffer_finish(sb);
1418  LOG(llevError, "%s", diff);
1419  free(diff);
1420 #ifdef MANY_CORES
1421  abort();
1422 #endif
1423  }
1424  if (QUERY_FLAG(ob, FLAG_FRIENDLY)) {
1425  LOG(llevMonster, "Warning: tried to free friendly object.\n");
1427  }
1428  if (QUERY_FLAG(ob, FLAG_FREED)) {
1429  StringBuffer *sb;
1430  char *diff;
1431 
1432  sb = stringbuffer_new();
1433  object_dump(ob, sb);
1434  diff = stringbuffer_finish(sb);
1435  LOG(llevError, "Trying to free freed object.\n%s\n", diff);
1436  free(diff);
1437  return;
1438  }
1439 
1440  if ((flags & FREE_OBJ_NO_DESTROY_CALLBACK) == 0) {
1441  /* Handle for plugin destroy event */
1442  execute_event(ob, EVENT_DESTROY, NULL, NULL, NULL, SCRIPT_FIX_NOTHING);
1443  }
1444 
1445  if (ob->inv) {
1446  /* Only if the space blocks everything do we not process -
1447  * if some form of movemnt is allowed, let objects
1448  * drop on that space.
1449  */
1450  if ((flags & FREE_OBJ_FREE_INVENTORY) != 0
1451  || ob->map == NULL
1452  || ob->map->in_memory != MAP_IN_MEMORY
1453  || (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL)) {
1454  FOR_INV_PREPARE(ob, op) {
1455  object_remove(op);
1456  object_free(op, flags);
1457  } FOR_INV_FINISH();
1458  } else { /* Put objects in inventory onto this space */
1459  FOR_INV_PREPARE(ob, op) {
1460  object_remove(op);
1461  /* No drop means no drop, including its inventory */
1462  if (QUERY_FLAG(op, FLAG_NO_DROP))
1463  object_free(op, FREE_OBJ_FREE_INVENTORY);
1464  else if (QUERY_FLAG(op, FLAG_STARTEQUIP)
1465  || QUERY_FLAG(op, FLAG_NO_DROP)
1466  || op->type == RUNE
1467  || op->type == TRAP
1470  else {
1471  object *part;
1472 
1473  /* If it's a multi-tile object, scatter dropped items randomly */
1474  if (ob->more) {
1475  int partcount = 0;
1476  /* Get the number of non-head parts */
1477  for (part = ob; part; part = part->more) {
1478  partcount++;
1479  }
1480  /* Select a random part */
1481  partcount = RANDOM()%partcount;
1482  for (part = ob; partcount > 0; partcount--) {
1483  part = part->more;
1484  }
1485  } else {
1486  part = ob;
1487  }
1488 
1489  if (QUERY_FLAG(op, FLAG_ALIVE)) {
1490  object_insert_to_free_spot_or_free(op, part->map, part->x, part->y, 0, SIZEOFFREE, NULL);
1491  } else {
1492  int f = 0;
1493  if (flags & FREE_OBJ_DROP_ABOVE_FLOOR)
1495  object_insert_in_map_at(op, part->map, NULL, f, part->x, part->y); /* Insert in same map as the envir */
1496  }
1497  }
1498  } FOR_INV_FINISH();
1499  }
1500  }
1501 
1502  if (ob->more != NULL) {
1503  object_free(ob->more, flags);
1504  ob->more = NULL;
1505  }
1506 
1507  /* Remove object from the active list */
1508  ob->speed = 0;
1509  object_update_speed(ob);
1510 
1511  SET_FLAG(ob, FLAG_FREED);
1512  ob->count = 0;
1513 
1514  /* Remove this object from the list of used objects */
1515  if (ob->prev == NULL) {
1516  objects = ob->next;
1517  if (objects != NULL)
1518  objects->prev = NULL;
1519  } else {
1520  ob->prev->next = ob->next;
1521  if (ob->next != NULL)
1522  ob->next->prev = ob->prev;
1523  }
1524 
1525  if (ob->artifact != NULL) FREE_AND_CLEAR_STR(ob->artifact);
1526  if (ob->name != NULL) FREE_AND_CLEAR_STR(ob->name);
1527  if (ob->name_pl != NULL) FREE_AND_CLEAR_STR(ob->name_pl);
1528  if (ob->title != NULL) FREE_AND_CLEAR_STR(ob->title);
1529  if (ob->race != NULL) FREE_AND_CLEAR_STR(ob->race);
1530  if (ob->slaying != NULL) FREE_AND_CLEAR_STR(ob->slaying);
1531  if (ob->skill != NULL) FREE_AND_CLEAR_STR(ob->skill);
1532  if (ob->lore != NULL) FREE_AND_CLEAR_STR(ob->lore);
1533  if (ob->msg != NULL) FREE_AND_CLEAR_STR(ob->msg);
1534  if (ob->materialname != NULL) FREE_AND_CLEAR_STR(ob->materialname);
1535  if (ob->discrete_damage != NULL) FREE_AND_CLEAR(ob->discrete_damage);
1536  if (ob->spell_tags) FREE_AND_CLEAR(ob->spell_tags);
1537 
1538  /* Why aren't events freed? */
1540 
1542 
1543  /* Test whether archetype is a temporary one, and if so look whether it should be trashed. */
1544  if (ob->arch && ob->arch->reference_count > 0) {
1545  if (--ob->arch->reference_count == 0) {
1546  free_arch(ob->arch);
1547  }
1548  }
1549 
1550 #ifdef MEMORY_DEBUG
1551  free(ob);
1552 #else
1553  /* Now link it with the free_objects list: */
1554  ob->prev = NULL;
1555  ob->next = free_objects;
1556  if (free_objects != NULL)
1557  free_objects->prev = ob;
1558  free_objects = ob;
1559  nroffreeobjects++;
1560 #endif
1561 }
1562 
1573  int i = 0;
1574  object *tmp = free_objects;
1575 
1576  while (tmp != NULL)
1577  tmp = tmp->next,
1578  i++;
1579  return i;
1580 }
1581 
1592  int i = 0;
1593  object *tmp = objects;
1594 
1595  while (tmp != NULL)
1596  tmp = tmp->next,
1597  i++;
1598  return i;
1599 }
1600 
1611  int i = 0;
1612  object *tmp = active_objects;
1613 
1614  while (tmp != NULL)
1615  tmp = tmp->active_next,
1616  i++;
1617  return i;
1618 }
1619 
1637 void object_sub_weight(object *op, signed long weight) {
1638  while (op != NULL) {
1639  if (op->type == CONTAINER) {
1640  weight = (signed long)(weight*(100-op->stats.Str)/100);
1641  }
1642  op->carrying -= weight;
1643  op = op->env;
1644  }
1645 }
1646 
1666 void object_remove(object *op) {
1667  object *last = NULL;
1668  object *otmp;
1669  tag_t tag;
1670  int check_walk_off;
1671  mapstruct *m;
1672  int16_t x, y;
1673 
1674  if (QUERY_FLAG(op, FLAG_REMOVED)) {
1675  StringBuffer *sb;
1676  char *diff;
1677 
1678  sb = stringbuffer_new();
1679  object_dump(op, sb);
1680  diff = stringbuffer_finish(sb);
1681  LOG(llevError, "Trying to remove removed object.\n%s\n", diff);
1682  free(diff);
1683  abort();
1684  }
1685  if (op->more != NULL)
1686  object_remove(op->more);
1687 
1688  SET_FLAG(op, FLAG_REMOVED);
1689 
1690  /*
1691  * In this case, the object to be removed is in someones
1692  * inventory.
1693  */
1694  /* TODO try to call a generic inventory weight adjusting function like object_sub_weight */
1695  if (op->env != NULL) {
1696  player *pl = NULL;
1697 
1698  if (op->nrof)
1699  object_sub_weight(op->env, op->weight*op->nrof);
1700  else
1701  object_sub_weight(op->env, op->weight+op->carrying);
1702 
1703  /* Update in two cases: item is in a player, or in a container the player is looking into. */
1704  if (op->env->contr != NULL && op->head == NULL) {
1705  pl = op->env->contr;
1706  } else if (op->env->type == CONTAINER && QUERY_FLAG(op->env, FLAG_APPLIED)) {
1707 
1708  if (op->env->env && op->env->env->contr)
1709  /* Container is in player's inventory. */
1710  pl = op->env->env->contr;
1711  else if (op->env->map) {
1712  /* Container on map, look above for player. */
1713  object *above = op->env->above;
1714 
1715  while (above && !above->contr)
1716  above = above->above;
1717  if (above)
1718  pl = above->contr;
1719  }
1720  }
1721 
1722  /* NO_FIX_PLAYER is set when a great many changes are being
1723  * made to players inventory. If set, avoiding the call
1724  * to save cpu time.
1725  */
1726  otmp = object_get_player_container(op->env);
1727  if (otmp != NULL
1728  && otmp->contr
1729  && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
1730  fix_object(otmp);
1731 
1732  if (op->above != NULL)
1733  op->above->below = op->below;
1734  else
1735  op->env->inv = op->below;
1736 
1737  if (op->below != NULL)
1738  op->below->above = op->above;
1739 
1740  /* we set up values so that it could be inserted into
1741  * the map, but we don't actually do that - it is up
1742  * to the caller to decide what we want to do.
1743  */
1744  op->x = op->env->x;
1745  op->y = op->env->y;
1746  op->ox = op->x;
1747  op->oy = op->y;
1748  op->map = op->env->map;
1749  op->above = NULL;
1750  op->below = NULL;
1751  /* send the delitem before resetting env, so container's contents be may
1752  * refreshed */
1753  if (LOOK_OBJ(op) && pl != NULL)
1754  esrv_del_item(pl, op);
1755  op->env = NULL;
1756  return;
1757  }
1758 
1759  /* If we get here, we are removing it from a map */
1760  if (op->map == NULL)
1761  return;
1762 
1763  if (op->contr != NULL && !op->contr->hidden)
1764  op->map->players--;
1765 
1766  x = op->x;
1767  y = op->y;
1768  m = get_map_from_coord(op->map, &x, &y);
1769 
1770  if (!m) {
1771  LOG(llevError, "object_remove called when object was on map but appears to not be within valid coordinates? %s (%d,%d)\n", op->map->path, op->x, op->y);
1772  abort();
1773  }
1774  if (op->map != m) {
1775  LOG(llevError, "object_remove: Object not really on map it claimed to be on? %s != %s, %d,%d != %d,%d\n", op->map->path, m->path, op->x, op->y, x, y);
1776  }
1777 
1778  /* link the object above us */
1779  if (op->above)
1780  op->above->below = op->below;
1781  else
1782  SET_MAP_TOP(m, x, y, op->below); /* we were top, set new top */
1783 
1784  /* Relink the object below us, if there is one */
1785  if (op->below) {
1786  op->below->above = op->above;
1787  } else {
1788  /* Nothing below, which means we need to relink map object for this space
1789  * use translated coordinates in case some oddness with map tiling is
1790  * evident
1791  */
1792  /*TODO is this check really needed?*/
1793  if (GET_MAP_OB(m, x, y) != op) {
1794  StringBuffer *sb;
1795  char *diff;
1796 
1797  sb = stringbuffer_new();
1798  object_dump(op, sb);
1799  diff = stringbuffer_finish(sb);
1800  LOG(llevError, "object_remove: GET_MAP_OB on %s does not return object to be removed even though it appears to be on the bottom?\n%s\n", m->path, diff);
1801  free(diff);
1802 
1803  sb = stringbuffer_new();
1804  object_dump(GET_MAP_OB(m, x, y), sb);
1805  diff = stringbuffer_finish(sb);
1806  LOG(llevError, "%s\n", diff);
1807  free(diff);
1808  }
1809  SET_MAP_OB(m, x, y, op->above); /* goes on above it. */
1810  }
1811  op->above = NULL;
1812  op->below = NULL;
1813 
1814  if (op->map->in_memory == MAP_SAVING)
1815  return;
1816 
1817  tag = op->count;
1818  check_walk_off = !QUERY_FLAG(op, FLAG_NO_APPLY);
1819  FOR_MAP_PREPARE(m, x, y, tmp) {
1820  /* No point updating the players look faces if he is the object
1821  * being removed.
1822  */
1823 
1824  if (tmp->type == PLAYER && tmp != op) {
1825  /* If a container that the player is currently using somehow gets
1826  * removed (most likely destroyed), update the player view
1827  * appropriately.
1828  */
1829  if (tmp->container == op) {
1830  CLEAR_FLAG(op, FLAG_APPLIED);
1831  tmp->container = NULL;
1832  }
1833  tmp->contr->socket.update_look = 1;
1834  }
1835  /* See if player moving off should effect something */
1836  if (check_walk_off
1837  && ((op->move_type&tmp->move_off) && (op->move_type&~tmp->move_off&~tmp->move_block) == 0)) {
1838  ob_move_on(tmp, op, NULL);
1839  if (object_was_destroyed(op, tag)) {
1840  LOG(llevError, "BUG: object_remove(): name %s, archname %s destroyed leaving object\n", tmp->name, tmp->arch->name);
1841  }
1842  }
1843 
1844  /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
1845  if (tmp->above == tmp)
1846  tmp->above = NULL;
1847  last = tmp;
1848  } FOR_MAP_FINISH();
1849  /* last == NULL or there are no objects on this space */
1850  if (last == NULL) {
1851  /* set P_NEED_UPDATE, otherwise update_position will complain. In theory,
1852  * we could preserve the flags (GET_MAP_FLAGS), but update_position figures
1853  * those out anyways, and if there are any flags set right now, they won't
1854  * be correct anyways.
1855  */
1856  SET_MAP_FLAGS(op->map, op->x, op->y, P_NEED_UPDATE);
1857  update_position(op->map, op->x, op->y);
1858  } else
1860 
1861  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) || (op->glow_radius != 0))
1862  update_all_los(op->map, op->x, op->y);
1863 }
1864 
1881 object *object_merge(object *op, object *top) {
1882  if (!op->nrof)
1883  return NULL;
1884 
1885  if (top == NULL)
1886  for (top = op; top != NULL && top->above != NULL; top = top->above)
1887  ;
1889  if (top == op)
1890  continue;
1891  if (object_can_merge(op, top)) {
1892  object_increase_nrof(top, op->nrof);
1893  /*
1894  * Previous behavior set weight to zero here.
1895  * This, however, caused the object_sub_weight
1896  * call in object_remove to subtract zero weight
1897  * when removing the object. Thus, until inventory
1898  * weight is next recalculated, the object merged
1899  * into another pile added weight in object_increase_nrof
1900  * but did not remove the weight from the original
1901  * instance of itself in object_remove, essentially
1902  * counting for double weight for several minutes.
1903  *
1904  * SilverNexus 2014-05-27
1905  */
1906  object_remove(op);
1908  return top;
1909  }
1911  return NULL;
1912 }
1913 
1933 object *object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y) {
1934  object *tmp;
1935 
1936  op = HEAD(op);
1937  for (tmp = op; tmp; tmp = tmp->more) {
1938  tmp->x = x+tmp->arch->clone.x;
1939  tmp->y = y+tmp->arch->clone.y;
1940  tmp->map = m;
1941  }
1942  return object_insert_in_map(op, m, originator, flag);
1943 }
1944 
1965 void object_merge_spell(object *op, int16_t x, int16_t y) {
1966  int i;
1967 
1968  /* We try to do some merging of spell objects - if something has same owner,
1969  * is same type of spell, and going in the same direction, it is somewhat
1970  * mergable.
1971  *
1972  * If the spell object has an other_arch, don't merge - when the spell
1973  * does something, like explodes, it will use this other_arch, and
1974  * if we merge, there is no easy way to make the correct values be
1975  * set on this new object (values should be doubled, tripled, etc.)
1976  *
1977  * We also care about speed - only process objects that will not be
1978  * active this tick. Without this, the results are incorrect - think
1979  * of a case where tmp would normally get processed this tick, but
1980  * get merges with op, which does not get processed.
1981  */
1982  FOR_MAP_PREPARE(op->map, x, y, tmp) {
1983  if (op->type == tmp->type
1984  && op->subtype == tmp->subtype
1985  && op->direction == tmp->direction
1986  && op->owner == tmp->owner && op->ownercount == tmp->ownercount
1987  && op->range == tmp->range
1988  && op->stats.wc == tmp->stats.wc
1989  && op->level == tmp->level
1990  && op->attacktype == tmp->attacktype
1991  && op->speed == tmp->speed
1992  && !tmp->other_arch
1993  && (tmp->speed_left+tmp->speed) < 0.0
1994  && op != tmp) {
1995  /* Quick test - if one or the other objects already have hash tables
1996  * set up, and that hash bucket contains a value that doesn't
1997  * match what we want to set it up, we won't be able to merge.
1998  * Note that these two if statements are the same, except
1999  * for which object they are checking against. They could
2000  * be merged, but the line wrapping would be large enough
2001  * that IMO it would become difficult to read the different clauses
2002  * so its cleaner just to do 2 statements - MSW
2003  */
2004  if (op->spell_tags
2005  && !OB_SPELL_TAG_MATCH(op, (tag_t)tmp->stats.maxhp)
2006  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0)
2007  continue;
2008 
2009  if (tmp->spell_tags
2010  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)op->stats.maxhp)
2011  && OB_SPELL_TAG_HASH(tmp, op->stats.maxhp) != 0)
2012  continue;
2013 
2014  /* If we merge, the data from tmp->spell_tags gets copied into op.
2015  * so we need to make sure that slot isn't filled up.
2016  */
2017  if (tmp->spell_tags
2018  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)tmp->stats.maxhp)
2019  && OB_SPELL_TAG_HASH(tmp, tmp->stats.maxhp) != 0)
2020  continue;
2021 
2022  /* If both objects have spell_tags, we need to see if there are conflicting
2023  * values - if there are, we won't be able to merge then.
2024  */
2025  if (tmp->spell_tags && op->spell_tags) {
2026  int need_copy = 0;
2027 
2028  for (i = 0; i < SPELL_TAG_SIZE; i++) {
2029  /* If the two tag values in the hash are set, but are
2030  * not set to the same value, then these objects
2031  * can not be merged.
2032  */
2033  if (op->spell_tags[i] && tmp->spell_tags[i]
2034  && op->spell_tags[i] != tmp->spell_tags[i]) {
2036  break;
2037  }
2038  /* If one tag is set and the other is not, that is
2039  * fine, but we have to note that we need to copy
2040  * the data in that case.
2041  */
2042  if ((!op->spell_tags[i] && tmp->spell_tags[i])
2043  || (op->spell_tags[i] && !tmp->spell_tags[i])) {
2044  need_copy = 1;
2045  }
2046  }
2047  /* If we did not get through entire array, it means
2048  * we got a conflicting hash, and so we won't be
2049  * able to merge these - just continue processing
2050  * object on this space.
2051  */
2052  if (i <= SPELL_TAG_SIZE)
2053  continue;
2054 
2055  /* Ok - everything checked out - we should be able to
2056  * merge tmp in op. So lets copy the tag data if
2057  * needed. Note that this is a selective copy, as
2058  * we don't want to clear values that may be set in op.
2059  */
2060  if (need_copy) {
2061  for (i = 0; i < SPELL_TAG_SIZE; i++)
2062  if (!op->spell_tags[i]
2063  && tmp->spell_tags[i]
2064  && tmp->spell_tags[i] != (tag_t)op->stats.maxhp)
2065  op->spell_tags[i] = tmp->spell_tags[i];
2066  }
2067  FREE_AND_CLEAR(tmp->spell_tags);
2068  }
2069 
2070  /* if tmp has a spell_tags table, copy it to op and free tmps */
2071  if (tmp->spell_tags && !op->spell_tags) {
2072  op->spell_tags = tmp->spell_tags;
2073  tmp->spell_tags = NULL;
2074 
2075  /* We don't need to keep a copy of our maxhp value
2076  * in the copied over value
2077  */
2078  if (OB_SPELL_TAG_MATCH(op, (tag_t)op->stats.maxhp))
2079  OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0;
2080  }
2081 
2082  /* For spells to work correctly, we need to record what spell
2083  * tags we've merged in with this effect. This is used
2084  * in ok_to_put_more() to see if a spell effect is already on
2085  * the space.
2086  */
2087  if (op->stats.maxhp != tmp->stats.maxhp) {
2088 #ifdef OBJECT_DEBUG
2089  /* This if statement should never happen - the logic above should
2090  * have prevented it. It is a problem, because by now its possible
2091  * we've destroyed the spell_tags in tmp, so we can't really
2092  * just bail out.
2093  */
2094 
2095  if (op->spell_tags
2096  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0
2097  && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)) {
2098  LOG(llevError, "object_insert_in_map: Got non matching spell tags: %d != %d\n", OB_SPELL_TAG_HASH(op, tmp->stats.maxhp), tmp->stats.maxhp);
2099  }
2100 #endif
2101  if (!op->spell_tags)
2102  op->spell_tags = calloc(SPELL_TAG_SIZE, sizeof(tag_t));
2103 
2104  OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) = tmp->stats.maxhp;
2105  }
2106 
2108  op->speed_left = MAX(op->speed_left, tmp->speed_left);
2109 
2110  if (tmp->duration != op->duration) {
2111  /* We need to use tmp_dam here because otherwise the
2112  * calculations can overflow the size of stats.dam.
2113  */
2114  int tmp_dam = tmp->stats.dam*(tmp->duration+1)+
2115  op->stats.dam*(op->duration+1);
2116 
2117  op->duration = MAX(op->duration, tmp->duration);
2118  tmp_dam /= op->duration+1;
2119  op->stats.dam = tmp_dam+1;
2120  } else {
2121  /* in this case, duration is the same, so simply adding
2122  * up damage works.
2123  */
2124  op->stats.dam += tmp->stats.dam;
2125  }
2126 
2127  object_remove(tmp);
2129  }
2130  } FOR_MAP_FINISH();
2131 }
2132 
2133 static object *find_insert_pos(object *op, const int flag) {
2134  object *floor = NULL;
2135  /*
2136  * If there are multiple objects on this space, we do some trickier handling.
2137  * We've already dealt with merging if appropriate.
2138  * Generally, we want to put the new object on top. But if
2139  * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
2140  * floor, we want to insert above that and no further.
2141  * Also, if there are spell objects on this space, we stop processing
2142  * once we get to them. This reduces the need to traverse over all of
2143  * them when adding another one - this saves quite a bit of cpu time
2144  * when lots of spells are cast in one area. Currently, it is presumed
2145  * that flying non pickable objects are spell objects.
2146  */
2147  if (flag&INS_ON_TOP) {
2148  return GET_MAP_TOP(op->map, op->x, op->y);
2149  }
2150  object *last = NULL;
2151  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2152  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)
2153  || QUERY_FLAG(tmp, FLAG_OVERLAY_FLOOR))
2154  floor = tmp;
2155 
2156  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
2157  && (tmp->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH))
2158  && !QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2159  /* We insert above tmp, so we want this object below this */
2160  break;
2161  }
2162  last = tmp;
2163  } FOR_MAP_FINISH();
2164  if (flag&INS_ABOVE_FLOOR_ONLY)
2165  return floor;
2166  return last;
2167 }
2168 
2200 object *object_insert_in_map(object *op, mapstruct *m, object *originator, int flag) {
2201  object *tmp, *top, *floor = NULL;
2202  int16_t x, y;
2203 
2204  if (QUERY_FLAG(op, FLAG_FREED)) {
2205  LOG(llevError, "Trying to insert freed object!\n");
2206  return NULL;
2207  }
2208  if (m == NULL) {
2209  StringBuffer *sb;
2210  char *diff;
2211 
2212  sb = stringbuffer_new();
2213  object_dump(op, sb);
2214  diff = stringbuffer_finish(sb);
2215  LOG(llevError, "Trying to insert in null-map!\n%s\n", diff);
2216  free(diff);
2217  return op;
2218  }
2219  if (out_of_map(m, op->x, op->y)) {
2220  StringBuffer *sb;
2221  char *diff;
2222 
2223  sb = stringbuffer_new();
2224  object_dump(op, sb);
2225  diff = stringbuffer_finish(sb);
2226  LOG(llevError, "Trying to insert object outside the map.\n%s\n", diff);
2227  free(diff);
2228 #ifdef MANY_CORES
2229  /* Better to catch this here, as otherwise the next use of this object
2230  * is likely to cause a crash. Better to find out where it is getting
2231  * improperly inserted.
2232  */
2233  abort();
2234 #endif
2235  return op;
2236  }
2237  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2238  StringBuffer *sb;
2239  char *diff;
2240 
2241  sb = stringbuffer_new();
2242  object_dump(op, sb);
2243  diff = stringbuffer_finish(sb);
2244  LOG(llevError, "Trying to insert (map) inserted object.\n%s\n", diff);
2245  free(diff);
2246  return op;
2247  }
2248  if (op->more != NULL) {
2249  /* The part may be on a different map. */
2250 
2251  object *more = op->more;
2252 
2253  /* We really need the caller to normalize coordinates - if
2254  * we set the map, that doesn't work if the location is within
2255  * a map and this is straddling an edge. So only if coordinate
2256  * is clear wrong do we normalize it.
2257  */
2258  if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
2259  /* Debugging information so you can see the last coordinates this object had */
2260  more->ox = more->x;
2261  more->oy = more->y;
2262  more->map = get_map_from_coord(more->map, &more->x, &more->y);
2263  } else if (!more->map) {
2264  /* For backwards compatibility - when not dealing with tiled maps,
2265  * more->map should always point to the parent.
2266  */
2267  more->map = m;
2268  }
2269 
2270  if (object_insert_in_map(more, more->map, originator, flag) == NULL) {
2271  if (!op->head)
2272  LOG(llevError, "BUG: object_insert_in_map(): inserting op->more killed op\n");
2273  return NULL;
2274  }
2275  }
2276  CLEAR_FLAG(op, FLAG_REMOVED);
2277 
2278  /* Debugging information so you can see the last coordinates this object had */
2279  op->ox = op->x;
2280  op->oy = op->y;
2281  x = op->x;
2282  y = op->y;
2283  op->map = get_map_from_coord(m, &x, &y);
2284 
2285  /* this has to be done after we translate the coordinates. */
2286  if (op->nrof
2287  && !(flag&INS_NO_MERGE)
2288  && op->type != SPELL_EFFECT) {
2289  FOR_MAP_PREPARE(op->map, x, y, tmp) {
2290  if (object_can_merge(op, tmp)) {
2291  op->nrof += tmp->nrof;
2292  object_remove(tmp);
2294  }
2295  } FOR_MAP_FINISH();
2296  } else if (op->type == SPELL_EFFECT
2297  && !op->range
2298  && !op->other_arch
2299  && (op->speed_left+op->speed) < 0.0) {
2300  object_merge_spell(op, x, y);
2301  }
2302 
2303  /* Ideally, the caller figures this out. However, it complicates a lot
2304  * of areas of callers (eg, anything that uses object_find_free_spot() would now
2305  * need extra work
2306  */
2307  if (op->map != m) {
2308  /* coordinates should not change unless map also changes */
2309  op->x = x;
2310  op->y = y;
2311  }
2312 
2313  if (op->type != LAMP)
2314  /* lamps use the FLAG_APPLIED to keep the light/unlit status, so don't reset it.
2315  Other objects just get unapplied, since the container "drops" them. */
2316  CLEAR_FLAG(op, FLAG_APPLIED);
2318  if (!QUERY_FLAG(op, FLAG_ALIVE))
2320 
2321  /* In many places, a player is passed as the originator, which
2322  * is fine. However, if the player is on a transport, they are not
2323  * actually on the map, so we can't use them for the linked pointers,
2324  * nor should the walk on function below use them either.
2325  */
2326  if (originator && originator->contr && originator->contr->transport)
2327  originator = originator->contr->transport;
2328 
2329  if (flag&INS_BELOW_ORIGINATOR) {
2330  if (originator->map != op->map
2331  || originator->x != op->x
2332  || originator->y != op->y) {
2333  LOG(llevError, "object_insert_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
2334  abort();
2335  }
2336  op->above = originator;
2337  op->below = originator->below;
2338  if (op->below)
2339  op->below->above = op;
2340  else
2341  SET_MAP_OB(op->map, op->x, op->y, op);
2342  /* since *below *originator, no need to update top */
2343  originator->below = op;
2344  } else {
2345  /* Top is the object that our object (op) is going to get inserted above. */
2346  top = find_insert_pos(op, flag);
2347 
2348  /* First object on this space */
2349  if (!top) {
2350  op->above = GET_MAP_OB(op->map, op->x, op->y);
2351  if (op->above)
2352  op->above->below = op;
2353  op->below = NULL;
2354  SET_MAP_OB(op->map, op->x, op->y, op);
2355  } else { /* get inserted into the stack above top */
2356  op->above = top->above;
2357  if (op->above)
2358  op->above->below = op;
2359  op->below = top;
2360  top->above = op;
2361  }
2362  if (op->above == NULL)
2363  SET_MAP_TOP(op->map, op->x, op->y, op);
2364  } /* else not INS_BELOW_ORIGINATOR */
2365 
2366  if (!(flag&INS_MAP_LOAD)) {
2367  if (op->type == PLAYER)
2368  op->contr->do_los = 1;
2369 
2370  /* If we have a floor, we know the player, if any, will be above
2371  * it, so save a few ticks and start from there.
2372  */
2373  tmp = floor ? floor : GET_MAP_OB(op->map, op->x, op->y);
2375  if (tmp->type == PLAYER)
2376  tmp->contr->socket.update_look = 1;
2378 
2379  /* If this object glows, it may affect lighting conditions that are
2380  * visible to others on this map. But update_all_los is really
2381  * an inefficient way to do this, as it means los for all players
2382  * on the map will get recalculated. The players could very well
2383  * be far away from this change and not affected in any way -
2384  * this should get redone to only look for players within range,
2385  * or just updating the P_NEED_UPDATE for spaces within this area
2386  * of effect may be sufficient.
2387  */
2388  if (MAP_DARKNESS(op->map) && (op->glow_radius != 0))
2389  update_all_los(op->map, op->x, op->y);
2390 
2391  if (op->contr && !op->contr->hidden)
2392  op->map->players++;
2393  }
2394 
2395  /* updates flags (blocked, alive, no magic, etc) for this map space */
2397 
2398  /* Don't know if moving this to the end will break anything. However,
2399  * we want to have update_look set above before calling this.
2400  *
2401  * object_check_move_on() must be after this because code called from
2402  * object_check_move_on() depends on correct map flags (so functions like
2403  * blocked() and wall() work properly), and these flags are updated by
2404  * object_update().
2405  */
2406 
2407  /* if this is not the head or flag has been passed, don't check walk on status */
2408 
2409  if (!(flag&INS_NO_WALK_ON) && !op->head) {
2410  if (object_check_move_on(op, originator))
2411  return NULL;
2412 
2413  /* If we are a multi part object, lets work our way through the check
2414  * walk on's.
2415  */
2416  for (tmp = op->more; tmp != NULL; tmp = tmp->more)
2417  if (object_check_move_on(tmp, originator))
2418  return NULL;
2419  }
2420  return op;
2421 }
2422 
2435 void object_replace_insert_in_map(const char *arch_string, object *op) {
2436  object *tmp1;
2437  archetype *at;
2438 
2439  /* first search for itself and remove any old instances */
2440  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2441  if (!strcmp(tmp->arch->name, arch_string)) { /* same archetype */
2442  object_remove(tmp);
2444  }
2445  } FOR_MAP_FINISH();
2446 
2447  at = find_archetype(arch_string);
2448  if (at == NULL) {
2449  return;
2450  }
2451  tmp1 = arch_to_object(at);
2452  object_insert_in_map_at(tmp1, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
2453 }
2454 
2478 object *object_split(object *orig_ob, uint32_t nr, char *err, size_t size) {
2479  object *newob;
2480 
2481  if (MAX(1, orig_ob->nrof) < nr) {
2482  /* If err is set, the caller knows that nr can be wrong (player trying to drop items), thus don't log that. */
2483  if (err)
2484  snprintf(err, size, "There are only %u %ss.", NROF(orig_ob), orig_ob->name);
2485  else
2486  LOG(llevDebug, "There are only %u %ss.\n", NROF(orig_ob), orig_ob->name);
2487  return NULL;
2488  }
2489  newob = object_create_clone(orig_ob);
2490  if (orig_ob->nrof == 0) {
2491  if (!QUERY_FLAG(orig_ob, FLAG_REMOVED)) {
2492  object_remove(orig_ob);
2493  }
2495  } else {
2496  newob->nrof = nr;
2497  object_decrease_nrof(orig_ob, nr);
2498  }
2499 
2500  return newob;
2501 }
2502 
2520 object *object_decrease_nrof(object *op, uint32_t i) {
2521  object *tmp;
2522 
2523  if (i == 0) /* objects with op->nrof require this check */
2524  return op;
2525 
2526  if (i > op->nrof)
2527  i = op->nrof;
2528 
2529  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2530  op->nrof -= i;
2531  } else if (op->env != NULL) {
2532  if (i < op->nrof) {
2533  player *pl;
2534  /* is this object in the players inventory, or sub container
2535  * therein?
2536  */
2537  tmp = object_get_player_container(op->env);
2538  /* nope. Is this a container the player has opened?
2539  * If so, set tmp to that player.
2540  * IMO, searching through all the players will mostly
2541  * likely be quicker than following op->env to the map,
2542  * and then searching the map for a player.
2543  */
2544  if (!tmp) {
2545  for (pl = first_player; pl; pl = pl->next)
2546  if (pl->ob->container == op->env)
2547  break;
2548  if (pl)
2549  tmp = pl->ob;
2550  else
2551  tmp = NULL;
2552  }
2553 
2554  /* Because of weight reduction by container and integer arithmetic,
2555  * there is no guarantee the rounded weight of combined items will be
2556  * the same as the sum of rounded weights.
2557  * Therefore just remove the current weight, and add the new.
2558  * Same adjustment done in object_increase_nrof().
2559  */
2560  object_sub_weight(op->env, op->weight * op->nrof);
2561  op->nrof -= i;
2562  object_add_weight(op->env, op->weight * op->nrof);
2563  if (tmp) {
2564  esrv_update_item(UPD_NROF, tmp, op);
2565  esrv_update_item(UPD_WEIGHT, tmp, op->env);
2566  fix_object(tmp);
2567  }
2568  } else {
2569  object_remove(op);
2570  op->nrof = 0;
2571  }
2572  } else {
2573  /* On a map. */
2574  if (i < op->nrof) {
2575  op->nrof -= i;
2576 
2577  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2578  if (pl->contr) {
2579  pl->contr->socket.update_look = 1;
2580  break;
2581  }
2582  FOR_MAP_FINISH();
2583  } else {
2584  object_remove(op);
2585  op->nrof = 0;
2586  }
2587  }
2588 
2589  if (op->nrof) {
2590  return op;
2591  } else {
2593  return NULL;
2594  }
2595 }
2596 
2607 static void object_increase_nrof(object *op, uint32_t i) {
2608  object *tmp;
2609 
2610  if (i == 0) /* objects with op->nrof require this check */
2611  return;
2612 
2613  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2614  op->nrof += i;
2615  } else if (op->env != NULL) {
2616  player *pl;
2617  /* is this object in the players inventory, or sub container
2618  * therein?
2619  */
2620  tmp = object_get_player_container(op->env);
2621  /* nope. Is this a container the player has opened?
2622  * If so, set tmp to that player.
2623  * IMO, searching through all the players will mostly
2624  * likely be quicker than following op->env to the map,
2625  * and then searching the map for a player.
2626  */
2627  if (!tmp) {
2628  for (pl = first_player; pl; pl = pl->next)
2629  if (pl->ob->container == op->env)
2630  break;
2631  if (pl)
2632  tmp = pl->ob;
2633  else
2634  tmp = NULL;
2635  }
2636 
2637  /* Because of weight reduction by container and integer arithmetic,
2638  * there is no guarantee the rounded weight of combined items will be
2639  * the same as the sum of rounded weights.
2640  * Therefore just remove the current weight, and add the new.
2641  * Same adjustment done in object_decrease_nrof().
2642  */
2643  object_sub_weight(op->env, op->weight * op->nrof);
2644  op->nrof += i;
2645  object_add_weight(op->env, op->weight * op->nrof);
2646  if (tmp) {
2647  esrv_update_item(UPD_NROF, tmp, op);
2648  // Why don't we need to update weight of op->env here?
2649  }
2650  } else {
2651  /* On a map. */
2652  op->nrof += i;
2653 
2654  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2655  if (pl->contr) {
2656  pl->contr->socket.update_look = 1;
2657  break;
2658  }
2659  FOR_MAP_FINISH();
2660  }
2661 }
2662 
2680 void object_add_weight(object *op, signed long weight) {
2681  while (op != NULL) {
2682  if (op->type == CONTAINER) {
2683  weight = (signed long)(weight*(100-op->stats.Str)/100);
2684  }
2685  op->carrying += weight;
2686  op = op->env;
2687  }
2688 }
2689 
2707 object *object_insert_in_ob(object *op, object *where) {
2708  object *otmp;
2709 
2710  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2711  StringBuffer *sb;
2712  char *diff;
2713 
2714  sb = stringbuffer_new();
2715  object_dump(op, sb);
2716  diff = stringbuffer_finish(sb);
2717  LOG(llevError, "Trying to insert (ob) inserted object.\n%s\n", diff);
2718  free(diff);
2719  return op;
2720  }
2721 
2722  if (where == NULL) {
2723  StringBuffer *sb;
2724  char *diff;
2725 
2726  sb = stringbuffer_new();
2727  object_dump(op, sb);
2728  diff = stringbuffer_finish(sb);
2729  LOG(llevError, "Trying to put object in NULL.\n%s\n", diff);
2730  free(diff);
2731  return op;
2732  }
2733  if (where->head) {
2734  LOG(llevDebug, "Warning: Tried to insert object wrong part of multipart object.\n");
2735  }
2736  where = HEAD(where);
2737  if (op->more) {
2738  LOG(llevError, "Tried to insert multipart object %s (%u)\n", op->name, op->count);
2739  return op;
2740  }
2742  CLEAR_FLAG(op, FLAG_REMOVED);
2743  if (op->nrof) {
2744  FOR_INV_PREPARE(where, tmp)
2745  if (object_can_merge(tmp, op)) {
2746  /* return the original object and remove inserted object
2747  * (client needs the original object) */
2748  object_increase_nrof(tmp, op->nrof);
2749  SET_FLAG(op, FLAG_REMOVED);
2750  object_free(op, FREE_OBJ_FREE_INVENTORY | FREE_OBJ_NO_DESTROY_CALLBACK); /* free the inserted object */
2751  return tmp;
2752  }
2753  FOR_INV_FINISH();
2754 
2755  /* the item couldn't merge. */
2756  object_add_weight(where, op->weight*op->nrof);
2757  } else
2758  object_add_weight(where, op->weight+op->carrying);
2759 
2760  op->map = NULL;
2761  op->env = where;
2762  op->above = NULL;
2763  op->below = NULL;
2764  op->x = 0,
2765  op->y = 0;
2766  op->ox = 0,
2767  op->oy = 0;
2768 
2769  /* Client has no idea of ordering so lets not bother ordering it here.
2770  * It sure simplifies this function...
2771  */
2772  if (where->inv == NULL)
2773  where->inv = op;
2774  else {
2775  op->below = where->inv;
2776  op->below->above = op;
2777  where->inv = op;
2778  }
2779 
2780  /* Update in 2 cases: object goes into player's inventory, or object goes into container the player
2781  * is looking into. */
2782  if (where->contr != NULL)
2783  esrv_send_item(where, op);
2784  else if (where->type == CONTAINER && QUERY_FLAG(where, FLAG_APPLIED)) {
2785  object *pl = NULL;
2786 
2787  if (op->env->env && op->env->env->contr)
2788  /* Container is in player's inventory. */
2789  pl = op->env->env;
2790  else if (op->env->map) {
2791  /* Container on map, look above for player. */
2792  FOR_ABOVE_PREPARE(op->env, above)
2793  if (above->contr) {
2794  pl = above;
2795  break;
2796  }
2797  FOR_ABOVE_FINISH();
2798  }
2799  if (pl)
2800  esrv_send_item(pl, op);
2801  }
2802 
2803  otmp = object_get_player_container(where);
2804  if (otmp && otmp->contr != NULL) {
2805  if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER)
2806  && (QUERY_FLAG(op, FLAG_APPLIED) || op->type == SKILL || op->glow_radius != 0))
2807  /* fix_object will only consider applied items, or skills, or items with a glow radius.
2808  thus no need to call it if our object hasn't that. */
2809  fix_object(otmp);
2810  }
2811 
2812  /* reset the light list and los of the players on the map */
2813  if (op->glow_radius != 0 && where->map) {
2814 #ifdef DEBUG_LIGHTS
2815  LOG(llevDebug, " object_insert_in_ob(): got %s to insert in map/op\n", op->name);
2816 #endif /* DEBUG_LIGHTS */
2817  if (MAP_DARKNESS(where->map)) {
2818  SET_MAP_FLAGS(where->map, where->x, where->y, P_NEED_UPDATE);
2819  update_position(where->map, where->x, where->y);
2820  update_all_los(where->map, where->x, where->y);
2821  }
2822  }
2823 
2824  return op;
2825 }
2826 
2852 int object_check_move_on(object *op, object *originator) {
2853  object *tmp;
2854  tag_t tag;
2855  mapstruct *m = op->map;
2856  int x = op->x, y = op->y;
2857  MoveType move_on, move_slow, move_block;
2858 
2859  if (QUERY_FLAG(op, FLAG_NO_APPLY))
2860  return 0;
2861 
2862  tag = op->count;
2863 
2864  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
2865  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
2866  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
2867 
2868  /* if nothing on this space will slow op down or be applied,
2869  * no need to do checking below. have to make sure move_type
2870  * is set, as lots of objects don't have it set - we treat that
2871  * as walking.
2872  */
2873  if (op->move_type
2874  && !(op->move_type&move_on)
2875  && !(op->move_type&move_slow))
2876  return 0;
2877 
2878  /* This is basically inverse logic of that below - basically,
2879  * if the object can avoid the move on or slow move, they do so,
2880  * but can't do it if the alternate movement they are using is
2881  * blocked. Logic on this seems confusing, but does seem correct.
2882  */
2883  if ((op->move_type&~move_on&~move_block) != 0
2884  && (op->move_type&~move_slow&~move_block) != 0)
2885  return 0;
2886 
2887  /* The objects have to be checked from top to bottom.
2888  * Hence, we first go to the top:
2889  */
2890 
2891  tmp = GET_MAP_OB(op->map, op->x, op->y);
2893  if (tmp->above == NULL)
2894  break;
2895  /* Trim the search when we find the first other spell effect
2896  * this helps performance so that if a space has 50 spell objects,
2897  * we don't need to check all of them.
2898  */
2899  if ((tmp->move_type&MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK))
2900  break;
2903  if (tmp == op)
2904  continue; /* Can't apply yourself */
2905 
2906  /* Check to see if one of the movement types should be slowed down.
2907  * Second check makes sure that the movement types not being slowed
2908  * (~slow_move) is not blocked on this space - just because the
2909  * space doesn't slow down swimming (for example), if you can't actually
2910  * swim on that space, can't use it to avoid the penalty.
2911  */
2912  if (!QUERY_FLAG(op, FLAG_WIZPASS)) {
2913  if ((!op->move_type && tmp->move_slow&MOVE_WALK)
2914  || ((op->move_type&tmp->move_slow) && (op->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
2915  float diff;
2916 
2917  diff = tmp->move_slow_penalty*FABS(op->speed);
2918  if (op->type == PLAYER) {
2921  diff /= 4.0;
2922  }
2923  }
2924  op->speed_left -= diff;
2925  }
2926  }
2927 
2928  /* Basically same logic as above, except now for actual apply. */
2929  if ((!op->move_type && tmp->move_on&MOVE_WALK)
2930  || ((op->move_type&tmp->move_on) && (op->move_type&~tmp->move_on&~tmp->move_block) == 0)) {
2931  ob_move_on(tmp, op, originator);
2932  if (object_was_destroyed(op, tag))
2933  return 1;
2934 
2935  /* what the person/creature stepped onto has moved the object
2936  * someplace new. Don't process any further - if we did,
2937  * have a feeling strange problems would result.
2938  */
2939  if (op->map != m || op->x != x || op->y != y)
2940  return 0;
2941  }
2943  return 0;
2944 }
2945 
2961 object *map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at) {
2962  if (m == NULL || OUT_OF_REAL_MAP(m, x, y)) {
2963  LOG(llevError, "Present_arch called outside map.\n");
2964  return NULL;
2965  }
2966 
2967  FOR_MAP_PREPARE(m, x, y, tmp)
2968  if (tmp->arch == at)
2969  return tmp;
2970  FOR_MAP_FINISH();
2971 
2972  return NULL;
2973 }
2974 
2991 object *map_find_by_type(mapstruct *m, int x, int y, uint8_t type) {
2992  if (OUT_OF_REAL_MAP(m, x, y)) {
2993  return NULL;
2994  }
2995 
2996  FOR_MAP_PREPARE(m, x, y, tmp)
2997  if (tmp->type == type)
2998  return tmp;
2999  FOR_MAP_FINISH();
3000 
3001  return NULL;
3002 }
3003 
3017 object *object_present_in_ob(uint8_t type, const object *op) {
3018  object *tmp;
3019 
3020  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3021  if (tmp->type == type)
3022  return tmp;
3023 
3024  return NULL;
3025 }
3026 
3055 object *object_present_in_ob_by_name(int type, const char *str, const object *op) {
3056  object *tmp;
3057 
3058  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3059  if ((type == -1 || tmp->type == type) && !strcmp(str, tmp->name))
3060  return tmp;
3061  }
3062  return NULL;
3063 }
3064 
3077 object *arch_present_in_ob(const archetype *at, const object *op) {
3078  object *tmp;
3079 
3080  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3081  if (tmp->arch == at)
3082  return tmp;
3083  return NULL;
3084 }
3085 
3097 void object_set_flag_inv(object*op, int flag) {
3098  object *tmp;
3099 
3100  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3101  SET_FLAG(tmp, flag);
3102  object_set_flag_inv(tmp, flag);
3103  }
3104 }
3105 
3117 void object_unset_flag_inv(object*op, int flag) {
3118  object *tmp;
3119 
3120  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3121  CLEAR_FLAG(tmp, flag);
3122  object_unset_flag_inv(tmp, flag);
3123  }
3124 }
3125 
3138 void object_set_cheat(object *op) {
3139  SET_FLAG(op, FLAG_WAS_WIZ);
3141 }
3142 
3163 int object_find_multi_free_spot_around(const object *ob, const object *gen, int16_t *hx, int16_t *hy) {
3164  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3165  int freecount = 0;
3166 
3167  ob = HEAD(ob);
3168 
3169  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3170  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3171  /*
3172  * sx and sy are now the coords of the bottom right corner of ob relative to the head.
3173  * genx and geny are now the coords of the bottom right corner of gen relative to the head.
3174  * sx2 and sy2 are now the coords of the head of ob relative to the top left corner.
3175  * genx2 and geny2 are now the coords of the head of gen relative to the top left corner.
3176  */
3177 
3178  sx++;
3179  sy++;
3180  genx++;
3181  geny++;
3182  /*
3183  * sx, sy, genx, and geny, are now the size of the object, excluding parts left and above
3184  * the head.
3185  */
3186 
3187  ix = gen->x-sx-genx2;
3188  iy = gen->y-sy-geny2;
3189  sx += genx+sx2;
3190  sy += geny+sy2;
3191  /*
3192  * ix and iy are the map coords of the top left square where the head of ob could possibly
3193  * be placed. sx and sy are now the size of the square to search for placement of the head
3194  * relative to ix and iy.
3195  */
3196 
3197  /*
3198  * Loop around the square of possible positions for the head of ob object:
3199  */
3200  for (i = 0; i < (sx+sx+sy+sy); i++) {
3201  if (i <= sx) {
3202  nx = i+ix;
3203  ny = iy;
3204  } else if (i <= sx+sy) {
3205  nx = ix+sx;
3206  ny = iy+i-sx;
3207  } else if (i <= sx+sy+sx) {
3208  nx = ix+sx-(i-(sx+sy));
3209  ny = iy+sy;
3210  } else {
3211  nx = ix;
3212  ny = iy+sy-(i-(sx+sy+sx));
3213  }
3214  /* Check if the spot is free. */
3215  flag = ob_blocked(ob, gen->map, nx, ny);
3216  if (!flag) {
3217  freecount++;
3218  }
3219  }
3220  /* If no free spaces, return. */
3221  if (!freecount)
3222  return -1;
3223 
3224  /* Choose a random valid position */
3225  freecount = RANDOM()%freecount;
3226  for (i = 0; i < sx+sx+sy+sy; i++) {
3227  if (i <= sx) {
3228  nx = i+ix;
3229  ny = iy;
3230  } else if (i <= sx+sy) {
3231  nx = ix+sx;
3232  ny = iy+i-sx;
3233  } else if (i <= sx+sy+sx) {
3234  nx = ix+sx-(i-(sx+sy));
3235  ny = iy+sy;
3236  } else {
3237  nx = ix;
3238  ny = iy+sy-(i-(sx+sy+sx));
3239  }
3240 
3241  /* Make sure it's within map. */
3242  if (nx < 0 || nx >= MAP_WIDTH(gen->map)
3243  || ny < 0 || ny >= MAP_HEIGHT(gen->map))
3244  continue;
3245 
3246  /* Check if the spot is free.*/
3247  flag = ob_blocked(ob, gen->map, nx, ny);
3248  if (!flag) {
3249  freecount--;
3250  if (freecount <= 0) {
3251  *hx = nx;
3252  *hy = ny;
3253  return 0;
3254  }
3255  }
3256  }
3257  return -1;
3258 }
3259 
3282 int object_find_multi_free_spot_within_radius(const object *ob, const object *gen, int *hx, int *hy) {
3283  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3284  int8_t x, y, radius;
3285  int freecount = 0, freecountstop = 0;
3286  const char *value;
3287  int8_t *x_array;
3288  int8_t *y_array;
3289 
3290  /* If radius is not set, default to 1 */
3291  value = object_get_value(gen, "generator_radius");
3292  if (value) {
3293  radius = (int8_t)strtol(value, NULL, 10);
3294  if (radius < 1) {
3295  radius = 1;
3296  }
3297  } else {
3298  radius = 1;
3299  }
3300 
3301  ob = HEAD(ob);
3302 
3303  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3304  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3305  /*
3306  * sx and sy are now the coords of the bottom right corner
3307  * of ob relative to the head.
3308  * genx and geny are now the coords of the bottom right corner
3309  * of gen relative to the head.
3310  * sx2 and sy2 are now the coords of the head of ob relative
3311  * to the top left corner.
3312  * genx2 and geny2 are now the coords of the head of gen relative
3313  * to the top left corner.
3314  */
3315 
3316  sx++;
3317  sy++;
3318  genx++;
3319  geny++;
3320  /*
3321  * sx, sy, genx, and geny, are now the size of the object,
3322  * excluding parts left and above the head.
3323  */
3324 
3325  ix = gen->x-sx-genx2-radius+1;
3326  iy = gen->y-sy-geny2-radius+1;
3327  sx += genx+sx2+radius*2-1;
3328  sy += geny+sy2+radius*2-1;
3329 
3330  /*
3331  * ix and iy are the map coords of the top left square where
3332  * the head of ob could possibly be placed. sx and sy are now
3333  * the size of the square to search for placement of the head
3334  * relative to ix and iy.
3335  */
3336 
3337  /* Create arrays large enough to hold free space coordinates */
3338  x_array = malloc(sx*sy*sizeof(int8_t));
3339  y_array = malloc(sx*sy*sizeof(int8_t));
3340 
3341  /*
3342  * Loop through the area of possible positions for the head of ob object:
3343  */
3344  for (x = 0; x < sx; x++) {
3345  for (y = 0; y < sy; y++) {
3346  nx = ix+x;
3347  ny = iy+y;
3348 
3349 
3350  /* Make sure it's within map. */
3351  if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) {
3352  continue;
3353  }
3354 
3355  /* Check if the spot is free. */
3356  flag = ob_blocked(ob, gen->map, nx, ny);
3357  if (!flag) {
3358  x_array[freecount] = nx;
3359  y_array[freecount] = ny;
3360  freecount++;
3361  }
3362  }
3363  }
3364  /* If no free spaces, return. */
3365  if (!freecount) {
3366  free(x_array);
3367  free(y_array);
3368  return -1;
3369  }
3370 
3371  /* Choose a random valid position */
3372  freecountstop = RANDOM()%freecount;
3373  for (i = 0; i < freecount; i++) {
3374  nx = x_array[i];
3375  ny = y_array[i];
3376 
3377  /* Check if the spot is free.*/
3378  flag = ob_blocked(ob, gen->map, nx, ny);
3379  if (!flag) {
3380  freecountstop--;
3381  if (freecountstop <= 0) {
3382  *hx = nx;
3383  *hy = ny;
3384  free(x_array);
3385  free(y_array);
3386  return 0;
3387  }
3388  }
3389  }
3390  free(x_array);
3391  free(y_array);
3392  return -1;
3393 }
3394 
3431 int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop) {
3432  int i, index = 0, flag;
3433  static int altern[SIZEOFFREE];
3434 
3435  for (i = start; i < stop; i++) {
3436  flag = ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]);
3437  if (!flag)
3438  altern[index++] = i;
3439 
3440  /* Basically, if we find a wall on a space, we cut down the search size.
3441  * In this way, we won't return spaces that are on another side of a wall.
3442  * This mostly work, but it cuts down the search size in all directions -
3443  * if the space being examined only has a wall to the north and empty
3444  * spaces in all the other directions, this will reduce the search space
3445  * to only the spaces immediately surrounding the target area, and
3446  * won't look 2 spaces south of the target space.
3447  */
3448  else if ((flag&AB_NO_PASS) && maxfree[i] < stop)
3449  stop = maxfree[i];
3450  }
3451  if (!index)
3452  return -1;
3453  return altern[RANDOM()%index];
3454 }
3455 
3474 int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y) {
3475  int i;
3476 
3477  for (i = 0; i < SIZEOFFREE; i++) {
3478  if (!ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]))
3479  return i;
3480  }
3481  return -1;
3482 }
3483 
3493 static void permute(int *arr, int begin, int end) {
3494  int i, j, tmp, len;
3495 
3496  len = end-begin;
3497  for (i = begin; i < end; i++) {
3498  j = begin+RANDOM()%len;
3499 
3500  tmp = arr[i];
3501  arr[i] = arr[j];
3502  arr[j] = tmp;
3503  }
3504 }
3505 
3517 void get_search_arr(int *search_arr) {
3518  int i;
3519 
3520  for (i = 0; i < SIZEOFFREE; i++) {
3521  search_arr[i] = i;
3522  }
3523 
3524  permute(search_arr, 1, SIZEOFFREE1+1);
3525  permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1);
3526  permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE);
3527 }
3528 
3550 int map_find_dir(mapstruct *m, int x, int y, object *exclude) {
3551  int i, max = SIZEOFFREE, mflags;
3552  int16_t nx, ny;
3553  mapstruct *mp;
3554  MoveType blocked, move_type;
3555 
3556  if (exclude && exclude->head) {
3557  exclude = exclude->head;
3558  move_type = exclude->move_type;
3559  } else {
3560  /* If we don't have anything, presume it can use all movement types. */
3561  move_type = MOVE_ALL;
3562  }
3563 
3564  for (i = 1; i < max; i++) {
3565  mp = m;
3566  nx = x+freearr_x[i];
3567  ny = y+freearr_y[i];
3568 
3569  mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny);
3570  if (mflags&P_OUT_OF_MAP) {
3571  max = maxfree[i];
3572  } else {
3573  blocked = GET_MAP_MOVE_BLOCK(mp, nx, ny);
3574 
3575  if ((move_type&blocked) == move_type) {
3576  max = maxfree[i];
3577  } else if (mflags&P_IS_ALIVE) {
3578  FOR_MAP_PREPARE(mp, nx, ny, tmp) {
3579  if ((QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type == PLAYER)
3580  && (tmp != exclude || (tmp->head && tmp->head != exclude))) {
3581  return freedir[i];
3582  }
3583  } FOR_MAP_FINISH();
3584  }
3585  }
3586  }
3587  return 0;
3588 }
3589 
3600 int object_distance(const object *ob1, const object *ob2) {
3601  int i;
3602 
3603  i = (ob1->x-ob2->x)*(ob1->x-ob2->x)+
3604  (ob1->y-ob2->y)*(ob1->y-ob2->y);
3605  return i;
3606 }
3607 
3616 int find_dir_2(int x, int y) {
3617  int q;
3618 
3619  if (!y)
3620  q = -300*x;
3621  else
3622  q = x*100/y;
3623  if (y > 0) {
3624  if (q < -242)
3625  return 3;
3626  if (q < -41)
3627  return 2;
3628  if (q < 41)
3629  return 1;
3630  if (q < 242)
3631  return 8;
3632  return 7;
3633  }
3634  if (q < -242)
3635  return 7;
3636  if (q < -41)
3637  return 6;
3638  if (q < 41)
3639  return 5;
3640  if (q < 242)
3641  return 4;
3642  return 3;
3643 }
3644 
3653 int absdir(int d) {
3654  // Shortcut for modulus that work becuase we have a power of 2
3655  d &= 7;
3656  // 0 needs to be 8
3657  if (!d)
3658  d = 8;
3659  return d;
3660 }
3661 
3671 int dirdiff(int dir1, int dir2) {
3672  int d;
3673 
3674  d = abs(dir1-dir2);
3675  if (d > 4)
3676  d = 8-d;
3677  return d;
3678 }
3679 
3691 static const int reduction_dir[SIZEOFFREE][3] = {
3692  { 0, 0, 0 }, /* 0 */
3693  { 0, 0, 0 }, /* 1 */
3694  { 0, 0, 0 }, /* 2 */
3695  { 0, 0, 0 }, /* 3 */
3696  { 0, 0, 0 }, /* 4 */
3697  { 0, 0, 0 }, /* 5 */
3698  { 0, 0, 0 }, /* 6 */
3699  { 0, 0, 0 }, /* 7 */
3700  { 0, 0, 0 }, /* 8 */
3701  { 8, 1, 2 }, /* 9 */
3702  { 1, 2, -1 }, /* 10 */
3703  { 2, 10, 12 }, /* 11 */
3704  { 2, 3, -1 }, /* 12 */
3705  { 2, 3, 4 }, /* 13 */
3706  { 3, 4, -1 }, /* 14 */
3707  { 4, 14, 16 }, /* 15 */
3708  { 5, 4, -1 }, /* 16 */
3709  { 4, 5, 6 }, /* 17 */
3710  { 6, 5, -1 }, /* 18 */
3711  { 6, 20, 18 }, /* 19 */
3712  { 7, 6, -1 }, /* 20 */
3713  { 6, 7, 8 }, /* 21 */
3714  { 7, 8, -1 }, /* 22 */
3715  { 8, 22, 24 }, /* 23 */
3716  { 8, 1, -1 }, /* 24 */
3717  { 24, 9, 10 }, /* 25 */
3718  { 9, 10, -1 }, /* 26 */
3719  { 10, 11, -1 }, /* 27 */
3720  { 27, 11, 29 }, /* 28 */
3721  { 11, 12, -1 }, /* 29 */
3722  { 12, 13, -1 }, /* 30 */
3723  { 12, 13, 14 }, /* 31 */
3724  { 13, 14, -1 }, /* 32 */
3725  { 14, 15, -1 }, /* 33 */
3726  { 33, 15, 35 }, /* 34 */
3727  { 16, 15, -1 }, /* 35 */
3728  { 17, 16, -1 }, /* 36 */
3729  { 18, 17, 16 }, /* 37 */
3730  { 18, 17, -1 }, /* 38 */
3731  { 18, 19, -1 }, /* 39 */
3732  { 41, 19, 39 }, /* 40 */
3733  { 19, 20, -1 }, /* 41 */
3734  { 20, 21, -1 }, /* 42 */
3735  { 20, 21, 22 }, /* 43 */
3736  { 21, 22, -1 }, /* 44 */
3737  { 23, 22, -1 }, /* 45 */
3738  { 45, 47, 23 }, /* 46 */
3739  { 23, 24, -1 }, /* 47 */
3740  { 24, 9, -1 } /* 48 */
3741 };
3742 
3761 int can_see_monsterP(mapstruct *m, int x, int y, int dir) {
3762  int16_t dx, dy;
3763  int mflags;
3764 
3765  if (dir < 0)
3766  return 0; /* exit condition: invalid direction */
3767 
3768  dx = x+freearr_x[dir];
3769  dy = y+freearr_y[dir];
3770 
3771  mflags = get_map_flags(m, &m, dx, dy, &dx, &dy);
3772 
3773  /* This functional arguably was incorrect before - it was
3774  * checking for P_WALL - that was basically seeing if
3775  * we could move to the monster - this is being more
3776  * literal on if we can see it. To know if we can actually
3777  * move to the monster, we'd need the monster passed in or
3778  * at least its move type.
3779  */
3780  if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
3781  return 0;
3782 
3783  /* yes, can see. */
3784  if (dir < 9)
3785  return 1;
3786  return can_see_monsterP(m, x, y, reduction_dir[dir][0])|
3787  can_see_monsterP(m, x, y, reduction_dir[dir][1])|
3788  can_see_monsterP(m, x, y, reduction_dir[dir][2]);
3789 }
3790 
3809 int object_can_pick(const object *who, const object *item) {
3810  /* I re-wrote this as a series of if statements
3811  * instead of a nested return (foo & bar && yaz)
3812  * - I think this is much more readable,
3813  * and likely compiler effectively optimizes it the
3814  * same.
3815  */
3816  if (item->weight <= 0)
3817  return 0;
3818  if (QUERY_FLAG(item, FLAG_NO_PICK))
3819  return 0;
3820  if (QUERY_FLAG(item, FLAG_ALIVE))
3821  return 0;
3822  if (item->invisible)
3823  return 0;
3824  if (item->type == TRANSPORT && item->contr != NULL) {
3825  return 0;
3826  }
3827 
3828  /* Weight limit for monsters */
3829  if (who->type != PLAYER && ((uint32_t)(who->weight+who->carrying+item->weight)) > get_weight_limit(who->stats.Str))
3830  return 0;
3831 
3832  /* Can not pick up multipart objects */
3833  if (item->head || item->more)
3834  return 0;
3835 
3836  /* Everything passes, so OK to pick up */
3837  return 1;
3838 }
3839 
3851 object *object_create_clone(object *asrc) {
3852  object *dst = NULL, *tmp, *src, *part, *prev;
3853 
3854  if (!asrc)
3855  return NULL;
3856  src = HEAD(asrc);
3857 
3858  prev = NULL;
3859  for (part = src; part; part = part->more) {
3860  tmp = object_new();
3861  object_copy(part, tmp);
3862  /*
3863  * Need to reset the weight, since object_insert_in_ob() later will
3864  * recompute this field.
3865  */
3866  tmp->carrying = tmp->arch->clone.carrying;
3867  tmp->x -= src->x;
3868  tmp->y -= src->y;
3869  if (!part->head) {
3870  dst = tmp;
3871  tmp->head = NULL;
3872  } else {
3873  tmp->head = dst;
3874  }
3875  tmp->more = NULL;
3876  if (prev)
3877  prev->more = tmp;
3878  prev = tmp;
3879  }
3880  /*** copy inventory ***/
3881  FOR_INV_PREPARE(src, item)
3882  (void)object_insert_in_ob(object_create_clone(item), dst);
3883  FOR_INV_FINISH();
3884 
3885  return dst;
3886 }
3887 
3898 object *object_find_by_name(const object *who, const char *name) {
3899  const char *name_shared = add_string(name);
3900  object *tmp;
3901 
3902  for (tmp = who->inv; tmp; tmp = tmp->below)
3903  if (tmp->name == name_shared)
3904  break;
3905  free_string(name_shared);
3906  return tmp;
3907 }
3908 
3922 object *object_find_by_type(const object *who, int type) {
3923  object *tmp;
3924 
3925  for (tmp = who->inv; tmp; tmp = tmp->below)
3926  if (tmp->type == type)
3927  return tmp;
3928 
3929  return NULL;
3930 }
3931 
3947 object *object_find_by_type2(const object *who, int type1, int type2) {
3948  object *tmp;
3949 
3950  for (tmp = who->inv; tmp; tmp = tmp->below)
3951  if (tmp->type == type1 || tmp->type == type2)
3952  return tmp;
3953 
3954  return NULL;
3955 }
3956 
3970 object *object_find_by_tag(const object *who, tag_t tag) {
3971  object *tmp;
3972 
3973  for (tmp = who->inv; tmp; tmp = tmp->below)
3974  if (tmp->count == tag)
3975  return tmp;
3976 
3977  return NULL;
3978 }
3979 
3993 object *object_find_by_type_applied(const object *who, int type) {
3994  object *tmp;
3995 
3996  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
3997  if (tmp->type == type && QUERY_FLAG(tmp, FLAG_APPLIED))
3998  return tmp;
3999 
4000  return NULL;
4001 }
4002 
4018 object *object_find_by_type_and_name(const object *who, int type, const char *name) {
4019  object *tmp;
4020 
4021  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4022  if (tmp->type == type && strcmp(tmp->name, name) == 0)
4023  return tmp;
4024 
4025  return NULL;
4026 }
4027 
4043 object *object_find_by_type_and_race(const object *who, int type, const char *race) {
4044  object *tmp;
4045 
4046  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4047  if (tmp->type == type && strcmp(tmp->race, race) == 0)
4048  return tmp;
4049 
4050  return NULL;
4051 }
4052 
4068 object *object_find_by_type_and_slaying(const object *who, int type, const char *slaying) {
4069  object *tmp;
4070 
4071  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4072  if (tmp->type == type && tmp->slaying != NULL && strcmp(tmp->slaying, slaying) == 0)
4073  return tmp;
4074 
4075  return NULL;
4076 }
4077 
4093 object *object_find_by_type_and_skill(const object *who, int type, const char *skill) {
4094  object *tmp;
4095 
4096  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4097  if (tmp->type == type && tmp->skill != NULL && strcmp(tmp->skill, skill) == 0)
4098  return tmp;
4099 
4100  return NULL;
4101 }
4102 
4116 object *object_find_by_flag(const object *who, int flag) {
4117  object *tmp;
4118 
4119  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4120  if (QUERY_FLAG(tmp, flag))
4121  return tmp;
4122 
4123  return NULL;
4124 }
4125 
4139 object *object_find_by_flag_applied(const object *who, int flag) {
4140  object *tmp;
4141 
4142  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4143  if (QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, flag))
4144  return tmp;
4145 
4146  return NULL;
4147 }
4148 
4162 object *object_find_by_arch_name(const object *who, const char *name) {
4163  object *tmp;
4164 
4165  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4166  if (strcmp(tmp->arch->name, name) == 0)
4167  return tmp;
4168 
4169  return NULL;
4170 }
4171 
4187 object *object_find_by_type_and_arch_name(const object *who, int type, const char *name) {
4188  object *tmp;
4189 
4190  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4191  if (tmp->type == type && strcmp(tmp->arch->name, name) == 0)
4192  return tmp;
4193 
4194  return NULL;
4195 }
4196 
4214 object *object_find_by_type_subtype(const object *who, int type, int subtype) {
4215  object *tmp;
4216 
4217  for (tmp = who->inv; tmp; tmp = tmp->below)
4218  if (tmp->type == type && tmp->subtype == subtype)
4219  return tmp;
4220 
4221  return NULL;
4222 }
4223 
4237 key_value *object_get_key_value(const object *ob, const char *key) {
4238  key_value *link;
4239 
4240  for (link = ob->key_values; link != NULL; link = link->next) {
4241  if (link->key == key) {
4242  return link;
4243  }
4244  }
4245 
4246  return NULL;
4247 }
4248 
4265 const char *object_get_value(const object *op, const char *const key) {
4266  key_value *link;
4267  const char *canonical_key;
4268 
4269  canonical_key = find_string(key);
4270 
4271  if (canonical_key == NULL) {
4272  /* 1. There being a field named key on any object
4273  * implies there'd be a shared string to find.
4274  * 2. Since there isn't, no object has this field.
4275  * 3. Therefore, *this *object doesn't have this field.
4276  */
4277  return NULL;
4278  }
4279 
4280  /* This is copied from object_get_key_value() above -
4281  * only 4 lines, and saves the function call overhead.
4282  */
4283  for (link = op->key_values; link != NULL; link = link->next) {
4284  if (link->key == canonical_key) {
4285  return link->value;
4286  }
4287  }
4288  return NULL;
4289 }
4290 
4308 static int object_set_value_s(object *op, const char *canonical_key, const char *value, int add_key) {
4309  key_value *field = NULL, *last = NULL;
4310 
4311  for (field = op->key_values; field != NULL; field = field->next) {
4312  if (field->key != canonical_key) {
4313  last = field;
4314  continue;
4315  }
4316 
4317  if (field->value)
4318  FREE_AND_CLEAR_STR(field->value);
4319  if (value)
4320  field->value = add_string(value);
4321  else {
4322  /* Basically, if the archetype has this key set,
4323  * we need to store the null value so when we save
4324  * it, we save the empty value so that when we load,
4325  * we get this value back again.
4326  */
4327  if (object_get_key_value(&op->arch->clone, canonical_key))
4328  field->value = NULL;
4329  else {
4330  /* Delete this link */
4331  if (field->key)
4332  FREE_AND_CLEAR_STR(field->key);
4333  if (field->value)
4334  FREE_AND_CLEAR_STR(field->value);
4335  if (last)
4336  last->next = field->next;
4337  else
4338  op->key_values = field->next;
4339  free(field);
4340  }
4341  }
4342  return TRUE;
4343  }
4344  /* IF we get here, key doesn't exist */
4345 
4346  /* No field, we'll have to add it. */
4347 
4348  if (!add_key) {
4349  return FALSE;
4350  }
4351  /* There isn't any good reason to store a null
4352  * value in the key/value list. If the archetype has
4353  * this key, then we should also have it, so shouldn't
4354  * be here. If user wants to store empty strings,
4355  * should pass in ""
4356  */
4357  if (value == NULL)
4358  return TRUE;
4359 
4360  field = malloc(sizeof(key_value));
4361 
4362  field->key = add_refcount(canonical_key);
4363  field->value = add_string(value);
4364  /* Usual prepend-addition. */
4365  field->next = op->key_values;
4366  op->key_values = field;
4367 
4368  return TRUE;
4369 }
4370 
4394 int object_set_value(object *op, const char *key, const char *value, int add_key) {
4395  const char *canonical_key = NULL;
4396  int floating_ref = FALSE;
4397  int ret;
4398 
4399  /* HACK This mess is to make sure set_ob_value() passes a shared string
4400  * to object_get_key_value(), without leaving a leaked refcount.
4401  */
4402 
4403  canonical_key = find_string(key);
4404  if (canonical_key == NULL) {
4405  canonical_key = add_string(key);
4406  floating_ref = TRUE;
4407  }
4408 
4409  ret = object_set_value_s(op, canonical_key, value, add_key);
4410 
4411  if (floating_ref) {
4412  free_string(canonical_key);
4413  }
4414 
4415  return ret;
4416 }
4417 
4472 int object_matches_string(object *pl, object *op, const char *name) {
4473  char *cp, local_name[MAX_BUF], name_op[MAX_BUF], name_short[HUGE_BUF], bname_s[MAX_BUF], bname_p[MAX_BUF];
4474  int count, retval = 0;
4475  /* strtok is destructive to name */
4476  safe_strncpy(local_name, name, sizeof(local_name));
4477 
4478  for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) {
4479  while (cp[0] == ' ')
4480  ++cp; /* get rid of spaces */
4481 
4482  /* LOG(llevDebug, "Trying to match %s\n", cp);*/
4483  /* All is a very generic match - low match value */
4484  if (!strcmp(cp, "all"))
4485  return 1;
4486 
4487  /* unpaid is a little more specific */
4488  if (!strcmp(cp, "unpaid") && QUERY_FLAG(op, FLAG_UNPAID))
4489  return 2;
4490  if (!strcmp(cp, "cursed")
4492  && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)))
4493  return 2;
4494 
4495  if (!strcmp(cp, "unlocked") && !QUERY_FLAG(op, FLAG_INV_LOCKED))
4496  return 2;
4497 
4498  /* Allow for things like '100 arrows' */
4499  count = atoi(cp);
4500  if (count != 0) {
4501  cp = strchr(cp, ' ');
4502  while (cp && cp[0] == ' ')
4503  ++cp; /* get rid of spaces */
4504  } else {
4505  if (pl->type == PLAYER)
4506  count = pl->contr->count;
4507  else
4508  count = 0;
4509  }
4510 
4511  if (!cp || cp[0] == '\0' || count < 0)
4512  return 0;
4513 
4514  /* The code here should go from highest retval to lowest. That
4515  * is because of the 'else' handling - we don't want to match on
4516  * something and set a low retval, even though it may match a higher retcal
4517  * later. So keep it in descending order here, so we try for the best
4518  * match first, and work downward.
4519  */
4520  query_name(op, name_op, MAX_BUF);
4521  query_short_name(op, name_short, HUGE_BUF);
4522  query_base_name(op, 0, bname_s, MAX_BUF);
4523  query_base_name(op, 1, bname_p, MAX_BUF);
4524 
4525  if (!strcasecmp(cp, name_op))
4526  retval = 20;
4527  else if (!strcasecmp(cp, name_short))
4528  retval = 18;
4529  else if (!strcasecmp(cp, bname_s))
4530  retval = 16;
4531  else if (!strcasecmp(cp, bname_p))
4532  retval = 16;
4533  else if (op->custom_name && !strcasecmp(cp, op->custom_name))
4534  retval = 15;
4535  else if (!strncasecmp(cp, bname_s, strlen(cp)))
4536  retval = 14;
4537  else if (!strncasecmp(cp, bname_p, strlen(cp)))
4538  retval = 14;
4539  /* Do substring checks, so things like 'Str+1' will match.
4540  * retval of these should perhaps be lower - they are lower
4541  * then the specific strcasecmp aboves, but still higher than
4542  * some other match criteria.
4543  */
4544  else if (strstr(bname_p, cp))
4545  retval = 12;
4546  else if (strstr(bname_s, cp))
4547  retval = 12;
4548  else if (strstr(name_short, cp))
4549  retval = 12;
4550  /* Check against plural/non plural based on count. */
4551  else if (count > 1 && !strcasecmp(cp, op->name_pl)) {
4552  retval = 6;
4553  } else if (count == 1 && !strcasecmp(op->name, cp)) {
4554  retval = 6;
4555  }
4556  /* base name matched - not bad */
4557  else if (strcasecmp(cp, op->name) == 0 && !count)
4558  retval = 4;
4559  /* Check for partial custom name, but give a real low priority */
4560  else if (op->custom_name && strstr(op->custom_name, cp))
4561  retval = 3;
4562 
4563  if (retval) {
4564  if (pl->type == PLAYER)
4565  pl->contr->count = count;
4566  return retval;
4567  }
4568  }
4569  return 0;
4570 }
4571 
4583 void object_fix_multipart(object *tmp) {
4584  archetype *at;
4585  object *op, *last;
4586 
4587  if (!tmp->map) {
4588  LOG(llevError, "object_fix_multipart: not on a map!\n");
4589  return;
4590  }
4591 
4592  /* already multipart - don't do anything more */
4593  if (tmp->head || tmp->more)
4594  return;
4595 
4596  /* If there is nothing more to this object, this for loop
4597  * won't do anything.
4598  */
4599  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
4600  op = arch_to_object(at);
4601 
4602  /* update x,y coordinates */
4603  op->x += tmp->x;
4604  op->y += tmp->y;
4605  op->head = tmp;
4606  op->map = tmp->map;
4607  last->more = op;
4608  if (tmp->name != op->name) {
4609  if (op->name)
4610  free_string(op->name);
4611  op->name = add_string(tmp->name);
4612  }
4613  if (tmp->title != op->title) {
4614  if (op->title)
4615  free_string(op->title);
4616  op->title = add_string(tmp->title);
4617  }
4618  /* we could link all the parts onto tmp, and then just
4619  * call object_insert_in_map once, but the effect is the same,
4620  * as object_insert_in_map will call itself with each part, and
4621  * the coding is simpler to just to it here with each part.
4622  */
4624  } /* for at = tmp->arch->more */
4625 }
4626 
4645 void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy) {
4646  archetype *part;
4647  int maxx = 0, maxy = 0, minx = 0, miny = 0;
4648 
4649  ob = HEAD(ob);
4650  *sx = 1;
4651  *sy = 1;
4652  if (ob->arch->more) {
4653  for (part = ob->arch; part; part = part->more) {
4654  if (part->clone.x > maxx)
4655  maxx = part->clone.x;
4656  if (part->clone.y > maxy)
4657  maxy = part->clone.y;
4658  if (part->clone.x < minx)
4659  minx = part->clone.x;
4660  if (part->clone.y < miny)
4661  miny = part->clone.y;
4662  }
4663  }
4664  if (sx)
4665  *sx = maxx;
4666  if (sy)
4667  *sy = maxy;
4668  if (hx)
4669  *hx = -minx;
4670  if (hy)
4671  *hy = -miny;
4672 }
4673 
4694 void object_insert_to_free_spot_or_free(object *op, mapstruct *map, int x, int y, int start, int stop, object *originator) {
4695  int pos;
4696 
4697  pos = object_find_free_spot(op, map, x, y, start, stop);
4698  if (pos == -1) {
4700  return;
4701  }
4702 
4703  object_insert_in_map_at(op, map, originator, 0, x+freearr_x[pos], y+freearr_y[pos]);
4704 }
4705 
4714 void object_set_msg(object *op, const char *msg) {
4715  if (op->msg != NULL) {
4716  free_string(op->msg);
4717  }
4718 
4719  if (msg != NULL) {
4720  // If the message does not have a trailing newline, add one.
4721  if (*msg != '\0' && strchr(msg, '\0')[-1] != '\n') {
4723  stringbuffer_append_string(sb, msg);
4724  stringbuffer_append_string(sb, "\n");
4725  op->msg = stringbuffer_finish_shared(sb);
4726  } else {
4727  op->msg = add_string(msg);
4728  }
4729  } else {
4730  op->msg = NULL;
4731  }
4732 }
4733 
4735 const char *const move_name[] = {
4736  "walk",
4737  "fly_low",
4738  "fly_high",
4739  "swim",
4740  "boat",
4741  NULL
4742 };
4743 
4744 /* This array equates the FLAG_ values with the V_ values. Use -1 to
4745  * put gaps in the array that should not be processed.
4746  * The order matches the order of the define values in 'define.h'.
4747  */
4754 static const char *const flag_names[NUM_FLAGS+1] = {
4755  "alive", "wiz", NULL, NULL, "was_wiz", "applied", "unpaid",
4756  "can_use_shield", "no_pick", "client_anim_sync", "client_anim_random", /* 10 */
4757  "is_animated", NULL /* FLAG_DIALOG_PARSED, not saved */,
4758  NULL /* flying */, "monster", "friendly", "generator",
4759  "is_thrown", "auto_apply", "treasure", "player sold", /* 20 */
4760  "see_invisible", "can_roll", "overlay_floor",
4761  "is_turnable", NULL /* walk_off */, NULL /* fly_on */,
4762  NULL /*fly_off*/, "is_used_up", "identified", "reflecting", /* 30 */
4763  "changing", "splitting", "hitback", "startequip",
4764  "blocksview", "undead", "scared", "unaggressive",
4765  "reflect_missile", "reflect_spell", /* 40 */
4766  "no_magic", "no_fix_player", "is_lightable", "tear_down",
4767  "run_away", NULL /*pass_thru */, NULL /*can_pass_thru*/,
4768  NULL /*"pick_up"*/, "unique", "no_drop", /* 50 */
4769  NULL /* wizcast*/, "can_cast_spell", "can_use_scroll", "can_use_range",
4770  "can_use_bow", "can_use_armour", "can_use_weapon",
4771  "can_use_ring", "has_ready_range", "has_ready_bow", /* 60 */
4772  "xrays", NULL, "is_floor", "lifesave", "no_strength", "sleep",
4773  "stand_still", "random_movement", "only_attack", "confused", /* 70 */
4774  "stealth", NULL, NULL, "cursed", "damned",
4775  "see_anywhere", "known_magical", "known_cursed",
4776  "can_use_skill", "been_applied", /* 80 */
4777  "has_ready_scroll", NULL, NULL,
4778  NULL, "make_invisible", "inv_locked", "is_wooded",
4779  "is_hilly", "has_ready_skill", "has_ready_weapon", /* 90 */
4780  "no_skill_ident", "is_blind", "can_see_in_dark", "is_cauldron",
4781  NULL, "no_steal", "one_hit", NULL, "berserk", "neutral", /* 100 */
4782  "no_attack", "no_damage", NULL, NULL, "activate_on_push",
4783  "activate_on_release", "is_water", "use_content_on_gen", NULL, "is_buildable", /* 110 */
4784  NULL, "blessed", "known_blessed"
4785 };
4786 
4796 {
4797  static char retbuf[MAX_BUF], retbuf_all[MAX_BUF];
4798  int i, all_count = 0, count;
4799 
4800  strcpy(retbuf, "");
4801  strcpy(retbuf_all, " all");
4802 
4803  /* Quick check, and probably fairly common */
4804  if (mt == MOVE_ALL) {
4805  stringbuffer_append_string(sb, "all");
4806  return;
4807  }
4808  if (mt == 0) {
4809  stringbuffer_append_string(sb, "0");
4810  return;
4811  }
4812 
4813  /* We basically slide the bits down. Why look at MOVE_ALL?
4814  * because we may want to return a string like 'all -swim',
4815  * and if we just looked at mt, we couldn't get that.
4816  */
4817  for (i = MOVE_ALL, count = 0; i != 0; i >>= 1, count++) {
4818  if (mt&(1<<count)) {
4819  strcat(retbuf, " ");
4820  strcat(retbuf, move_name[count]);
4821  } else {
4822  strcat(retbuf_all, " -");
4823  strcat(retbuf_all, move_name[count]);
4824  all_count++;
4825  }
4826  }
4827  /* Basically, if there is a single negation, return it, eg
4828  * 'all -swim'. But more than that, just return the
4829  * enumerated values. It doesn't make sense to return
4830  * 'all -walk -fly_low' - it is shorter to return 'fly_high swim'
4831  */
4832  if (all_count <= 1)
4833  stringbuffer_append_string(sb, retbuf_all+1);
4834  else
4835  stringbuffer_append_string(sb, retbuf+1);
4836 }
4837 
4839 static inline void ADD_STRINGLINE_ENTRY(StringBuffer *sb, const char *name, const char *value) {
4840  stringbuffer_append_string(sb, name);
4841  stringbuffer_append_string(sb, value);
4842  stringbuffer_append_string(sb, "\n");
4843 }
4844 
4846 static inline void FAST_SAVE_LONG(StringBuffer *sb, const char *name, const long value) {
4847  stringbuffer_append_printf(sb, "%s%ld\n", name, (long int)value);
4848 }
4849 
4851 static inline void FAST_SAVE_DOUBLE(StringBuffer *sb, const char *name, const double value) {
4852  stringbuffer_append_printf(sb, "%s%f\n", name, value);
4853 }
4854 
4868 void get_ob_diff(StringBuffer *sb, const object *op, const object *op2) {
4869  static char buf2[64];
4870  int tmp;
4871  int i;
4872  key_value *my_field;
4873  key_value *arch_field;
4874 
4875  /* This saves the key/value lists. We do it first so that any
4876  * keys that match field names will be overwritten by the loader.
4877  */
4878  for (my_field = op->key_values; my_field != NULL; my_field = my_field->next) {
4879  /* Find the field in the opposing member. */
4880  arch_field = object_get_key_value(op2, my_field->key);
4881 
4882  /* If there's no partnering field, or it's got a different value, save our field. */
4883  if (arch_field == NULL || my_field->value != arch_field->value) {
4884  stringbuffer_append_string(sb, my_field->key);
4885  stringbuffer_append_string(sb, " ");
4886  /* If this is null, then saving it as a space should
4887  * cause it to be null again.
4888  */
4889  if (my_field->value)
4890  stringbuffer_append_string(sb, my_field->value);
4891  stringbuffer_append_string(sb, "\n");
4892  }
4893  }
4894  /* We don't need to worry about the arch's extra fields - they
4895  * will get taken care of the object_copy() function.
4896  */
4897 
4898  if (op->name && op->name != op2->name) {
4899  ADD_STRINGLINE_ENTRY(sb, "name ", op->name);
4900  }
4901  if (op->name_pl && op->name_pl != op2->name_pl) {
4902  ADD_STRINGLINE_ENTRY(sb, "name_pl ", op->name_pl);
4903  }
4904  if (op->anim_suffix && op->anim_suffix != op2->anim_suffix) {
4905  ADD_STRINGLINE_ENTRY(sb, "anim_suffix ", op->anim_suffix);
4906  }
4907  if (op->custom_name && op->custom_name != op2->custom_name) {
4908  ADD_STRINGLINE_ENTRY(sb, "custom_name ", op->custom_name);
4909  }
4910  if (op->title && op->title != op2->title) {
4911  ADD_STRINGLINE_ENTRY(sb, "title ", op->title);
4912  }
4913  if (op->race && op->race != op2->race) {
4914  ADD_STRINGLINE_ENTRY(sb, "race ", op->race);
4915  }
4916  if (op->slaying && op->slaying != op2->slaying) {
4917  ADD_STRINGLINE_ENTRY(sb, "slaying ", op->slaying);
4918  }
4919  if (op->skill && op->skill != op2->skill) {
4920  ADD_STRINGLINE_ENTRY(sb, "skill ", op->skill);
4921  }
4922  if (op->msg && op->msg != op2->msg) {
4923  stringbuffer_append_string(sb, "msg\n");
4925  stringbuffer_append_string(sb, "endmsg\n");
4926  }
4927  if (op->lore && op->lore != op2->lore) {
4928  stringbuffer_append_string(sb, "lore\n");
4930  stringbuffer_append_string(sb, "endlore\n");
4931  }
4932  if (op->other_arch != op2->other_arch && op->other_arch != NULL && op->other_arch->name) {
4933  ADD_STRINGLINE_ENTRY(sb, "other_arch ", op->other_arch->name);
4934  }
4935  if (op->face != op2->face) {
4936  ADD_STRINGLINE_ENTRY(sb, "face ", op->face->name);
4937  }
4938 
4939  if (op->animation_id != op2->animation_id) {
4940  if (op->animation_id) {
4941  ADD_STRINGLINE_ENTRY(sb, "animation ", animations[GET_ANIM_ID(op)].name);
4942  if (!QUERY_FLAG (op, FLAG_ANIMATE)) {
4943  stringbuffer_append_string(sb, "is_animated 0\n");
4944  }
4945  } else {
4946  stringbuffer_append_string(sb, "animation NONE\n");
4947  }
4948  }
4949  if (op->stats.Str != op2->stats.Str)
4950  FAST_SAVE_LONG(sb, "Str ", op->stats.Str);
4951  if (op->stats.Dex != op2->stats.Dex)
4952  FAST_SAVE_LONG(sb, "Dex ", op->stats.Dex);
4953  if (op->stats.Con != op2->stats.Con)
4954  FAST_SAVE_LONG(sb, "Con ", op->stats.Con);
4955  if (op->stats.Wis != op2->stats.Wis)
4956  FAST_SAVE_LONG(sb, "Wis ", op->stats.Wis);
4957  if (op->stats.Pow != op2->stats.Pow)
4958  FAST_SAVE_LONG(sb, "Pow ", op->stats.Pow);
4959  if (op->stats.Cha != op2->stats.Cha)
4960  FAST_SAVE_LONG(sb, "Cha ", op->stats.Cha);
4961  if (op->stats.Int != op2->stats.Int)
4962  FAST_SAVE_LONG(sb, "Int ", op->stats.Int);
4963  if (op->stats.hp != op2->stats.hp)
4964  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
4965  if (op->stats.maxhp != op2->stats.maxhp)
4966  FAST_SAVE_LONG(sb, "maxhp ", op->stats.maxhp);
4967  if (op->stats.sp != op2->stats.sp)
4968  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
4969  if (op->stats.maxsp != op2->stats.maxsp)
4970  FAST_SAVE_LONG(sb, "maxsp ", op->stats.maxsp);
4971  if (op->stats.grace != op2->stats.grace)
4972  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
4973  if (op->stats.maxgrace != op2->stats.maxgrace)
4974  FAST_SAVE_LONG(sb, "maxgrace ", op->stats.maxgrace);
4975 
4976  if (op->stats.exp != op2->stats.exp) {
4977  snprintf(buf2, sizeof(buf2), "%"FMT64, op->stats.exp);
4978  ADD_STRINGLINE_ENTRY(sb, "exp ", buf2);
4979  }
4980 
4981  if (op->total_exp != op2->total_exp) {
4982  snprintf(buf2, sizeof(buf2), "%"FMT64, op->total_exp);
4983  ADD_STRINGLINE_ENTRY(sb, "total_exp ", buf2);
4984  }
4985 
4986  if (op->expmul != op2->expmul)
4987  FAST_SAVE_DOUBLE(sb, "expmul ", op->expmul);
4988  if (op->stats.food != op2->stats.food)
4989  FAST_SAVE_LONG(sb, "food ", op->stats.food);
4990  if (op->stats.dam != op2->stats.dam)
4991  FAST_SAVE_LONG(sb, "dam ", op->stats.dam);
4992  if (op->stats.luck != op2->stats.luck)
4993  FAST_SAVE_LONG(sb, "luck ", op->stats.luck);
4994  if (op->stats.wc != op2->stats.wc)
4995  FAST_SAVE_LONG(sb, "wc ", op->stats.wc);
4996  if (op->stats.ac != op2->stats.ac)
4997  FAST_SAVE_LONG(sb, "ac ", op->stats.ac);
4998  if (op->x != op2->x)
4999  FAST_SAVE_LONG(sb, "x ", op->x);
5000  if (op->y != op2->y)
5001  FAST_SAVE_LONG(sb, "y ", op->y);
5002  if (op->speed != op2->speed) {
5003  FAST_SAVE_DOUBLE(sb, "speed ", op->speed);
5004  }
5005  if (op->speed > 0 && op->speed_left != op2->speed_left) {
5006  FAST_SAVE_DOUBLE(sb, "speed_left ", op->speed_left);
5007  }
5008  if (op->weapon_speed != op2->weapon_speed) {
5009  FAST_SAVE_DOUBLE(sb, "weapon_speed ", op->weapon_speed);
5010  }
5011  if (op->weapon_speed > 0 && op->weapon_speed_left != op2->weapon_speed_left) {
5012  FAST_SAVE_DOUBLE(sb, "weapon_speed_left ", op->weapon_speed_left);
5013  }
5014  if (op->move_status != op2->move_status)
5015  FAST_SAVE_LONG(sb, "move_state ", op->move_status);
5016  if (op->attack_movement != op2->attack_movement)
5017  FAST_SAVE_LONG(sb, "attack_movement ", op->attack_movement);
5018  if (op->nrof != op2->nrof)
5019  FAST_SAVE_LONG(sb, "nrof ", op->nrof);
5020  if (op->level != op2->level)
5021  FAST_SAVE_LONG(sb, "level ", op->level);
5022  if (op->direction != op2->direction)
5023  FAST_SAVE_LONG(sb, "direction ", op->direction);
5024  if (op->type != op2->type)
5025  FAST_SAVE_LONG(sb, "type ", op->type);
5026  if (op->subtype != op2->subtype)
5027  FAST_SAVE_LONG(sb, "subtype ", op->subtype);
5028  if (op->attacktype != op2->attacktype)
5029  FAST_SAVE_LONG(sb, "attacktype ", op->attacktype);
5030 
5031  for (tmp = 0; tmp < NROFATTACKS; tmp++) {
5032  if (op->resist[tmp] != op2->resist[tmp]) {
5033  stringbuffer_append_string(sb, "resist_");
5034  FAST_SAVE_LONG(sb, resist_save[tmp], op->resist[tmp]);
5035  }
5036  }
5037 
5038  if (op->path_attuned != op2->path_attuned)
5039  FAST_SAVE_LONG(sb, "path_attuned ", op->path_attuned);
5040  if (op->path_repelled != op2->path_repelled)
5041  FAST_SAVE_LONG(sb, "path_repelled ", op->path_repelled);
5042  if (op->path_denied != op2->path_denied)
5043  FAST_SAVE_LONG(sb, "path_denied ", op->path_denied);
5044  if (op->material != op2->material)
5045  FAST_SAVE_LONG(sb, "material ", op->material);
5046  if (op->materialname && op->materialname != op2->materialname) {
5047  ADD_STRINGLINE_ENTRY(sb, "materialname ", op->materialname);
5048  }
5049  if (op->value != op2->value)
5050  FAST_SAVE_LONG(sb, "value ", op->value);
5051  if (op->carrying != op2->carrying)
5052  FAST_SAVE_LONG(sb, "carrying ", op->carrying);
5053  if (op->weight != op2->weight)
5054  FAST_SAVE_LONG(sb, "weight ", op->weight);
5055  if (op->invisible != op2->invisible)
5056  FAST_SAVE_LONG(sb, "invisible ", op->invisible);
5057  if (op->state != op2->state)
5058  FAST_SAVE_LONG(sb, "state ", op->state);
5059  if (op->magic != op2->magic)
5060  FAST_SAVE_LONG(sb, "magic ", op->magic);
5061  if (op->last_heal != op2->last_heal)
5062  FAST_SAVE_LONG(sb, "last_heal ", op->last_heal);
5063  if (op->last_sp != op2->last_sp)
5064  FAST_SAVE_LONG(sb, "last_sp ", op->last_sp);
5065  if (op->last_grace != op2->last_grace)
5066  FAST_SAVE_LONG(sb, "last_grace ", op->last_grace);
5067  if (op->last_eat != op2->last_eat)
5068  FAST_SAVE_LONG(sb, "last_eat ", op->last_eat);
5069  if (QUERY_FLAG(op, FLAG_IS_LINKED) && (tmp = get_button_value(op)))
5070  FAST_SAVE_LONG(sb, "connected ", tmp);
5071  if (op->glow_radius != op2->glow_radius)
5072  FAST_SAVE_LONG(sb, "glow_radius ", op->glow_radius);
5073  if (op->randomitems != op2->randomitems) {
5074  ADD_STRINGLINE_ENTRY(sb, "randomitems ", op->randomitems ? op->randomitems->name : "none");
5075  }
5076 
5077  if (op->run_away != op2->run_away)
5078  FAST_SAVE_LONG(sb, "run_away ", op->run_away);
5079  if (op->pick_up != op2->pick_up)
5080  FAST_SAVE_LONG(sb, "pick_up ", op->pick_up);
5081  if (op->weight_limit != op2->weight_limit)
5082  FAST_SAVE_LONG(sb, "container ", op->weight_limit);
5083  if (op->will_apply != op2->will_apply)
5084  FAST_SAVE_LONG(sb, "will_apply ", op->will_apply);
5085  if (op->smoothlevel != op2->smoothlevel)
5086  FAST_SAVE_LONG(sb, "smoothlevel ", op->smoothlevel);
5087 
5088  if (op->map_layer != op2->map_layer)
5089  ADD_STRINGLINE_ENTRY(sb, "map_layer ", map_layer_name[op->map_layer]);
5090 
5091  if (op->weapontype && op->weapontype != op2->weapontype) {
5092  FAST_SAVE_LONG(sb, "weapontype ", op->weapontype);
5093  }
5094  if (op->client_type && op->client_type != op2->client_type) {
5095  FAST_SAVE_LONG(sb, "client_type ", op->client_type);
5096  }
5097 
5098  if (op->item_power != op2->item_power) {
5099  FAST_SAVE_LONG(sb, "item_power ", op->item_power);
5100  }
5101 
5102  if (op->duration != op2->duration)
5103  FAST_SAVE_LONG(sb, "duration ", op->duration);
5104 
5105  if (op->range != op2->range)
5106  FAST_SAVE_LONG(sb, "range ", op->range);
5107 
5108  if (op->range_modifier != op2->range_modifier)
5109  FAST_SAVE_LONG(sb, "range_modifier ", op->range_modifier);
5110 
5111  if (op->duration_modifier != op2->duration_modifier)
5112  FAST_SAVE_LONG(sb, "duration_modifier ", op->duration_modifier);
5113 
5114  if (op->dam_modifier != op2->dam_modifier)
5115  FAST_SAVE_LONG(sb, "dam_modifier ", op->dam_modifier);
5116 
5117  if (op->gen_sp_armour != op2->gen_sp_armour) {
5118  FAST_SAVE_LONG(sb, "gen_sp_armour ", op->gen_sp_armour);
5119  }
5120 
5121  /* I've kept the old int move type saving code commented out.
5122  * In an ideal world, we'd know if we want to do a quick
5123  * save (say to a temp map, where we don't care about strings),
5124  * or a slower save/dm dump, where printing out strings is handy.
5125  */
5126  if (op->move_type != op2->move_type) {
5127  /*FAST_SAVE_LONG(sb, "move_type ", op->move_type)*/
5128  stringbuffer_append_string(sb, "move_type ");
5130  stringbuffer_append_string(sb, "\n");
5131  }
5132  if (op->move_block != op2->move_block) {
5133  /*FAST_SAVE_LONG(sb, "move_block ", op->move_block)*/
5134  stringbuffer_append_string(sb, "move_block ");
5136  stringbuffer_append_string(sb, "\n");
5137  }
5138  if (op->move_allow != op2->move_allow) {
5139  /*FAST_SAVE_LONG(sb, "move_allow ", op->move_allow);*/
5140  stringbuffer_append_string(sb, "move_allow ");
5142  stringbuffer_append_string(sb, "\n");
5143  }
5144  if (op->move_on != op2->move_on) {
5145  /*FAST_SAVE_LONG(sb, "move_on ", op->move_on);*/
5146  stringbuffer_append_string(sb, "move_on ");
5147  get_string_move_type(sb, op->move_on);
5148  stringbuffer_append_string(sb, "\n");
5149  }
5150  if (op->move_off != op2->move_off) {
5151  /*FAST_SAVE_LONG(sb, "move_off ", op->move_off);*/
5152  stringbuffer_append_string(sb, "move_off ");
5153  get_string_move_type(sb, op->move_off);
5154  stringbuffer_append_string(sb, "\n");
5155  }
5156  if (op->move_slow != op2->move_slow) {
5157  /*FAST_SAVE_LONG(sb, "move_slow ", op->move_slow);*/
5158  stringbuffer_append_string(sb, "move_slow ");
5160  stringbuffer_append_string(sb, "\n");
5161  }
5162 
5163  if (op->move_slow_penalty != op2->move_slow_penalty) {
5164  FAST_SAVE_DOUBLE(sb, "move_slow_penalty ", op->move_slow_penalty);
5165  }
5166 
5167  if (!COMPARE_FLAGS(op, op2)) {
5168  for (tmp = 0; tmp <= NUM_FLAGS; tmp++) {
5169  if (flag_names[tmp] && (QUERY_FLAG(op, tmp) != QUERY_FLAG(op2, tmp))) {
5170  ADD_STRINGLINE_ENTRY(sb, flag_names[tmp], QUERY_FLAG(op, tmp) ? " 1" : " 0");
5171  }
5172  }
5173  }
5174 
5175  /* Save body locations */
5176  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
5177  if (op->body_info[i] != op2->body_info[i]) {
5178  stringbuffer_append_string(sb, body_locations[i].save_name);
5179  FAST_SAVE_LONG(sb, " ", op->body_info[i]);
5180  }
5181  }
5182 
5183  /* Save discrete damage if applicable
5184  * Note that given how the discrete_damage allocation is done, there can't be any case where
5185  * op->discrete_damage == NULL && op2->discrete_damage != NULL.
5186  */
5187  if (op->discrete_damage) {
5188  for (i = 0; i < NROFATTACKS; i++) {
5189  if (op2->discrete_damage == NULL || op2->discrete_damage[i] != op->discrete_damage[i]) {
5190  stringbuffer_append_string(sb, "damage_");
5191  FAST_SAVE_LONG(sb, resist_save[i], op->discrete_damage[i]);
5192  }
5193  }
5194  }
5195 }
5196 
5201 void save_object_in_sb(StringBuffer *sb, const object *op, const int flag) {
5202  archetype *at = op->arch;
5203  if (at == NULL)
5204  at = empty_archetype;
5205 
5206  stringbuffer_append_printf(sb, "arch %s\n", at->name);
5207 
5208  if (op->arch->reference_count > 0) {
5209  /* The object is a custom item/monster, so we handle its save differently.
5210  * We compare the custom archetype to the "original" one, then only save hp/gr/sp
5211  * which are the only values we can't recompute later - all others are modified by items in inventory.
5212  * Note that hp/gr/sp will appear twice in save, but last value will take precedence.
5213  */
5214  archetype *original = find_archetype(op->arch->name);
5215  if (!original) {
5216  LOG(llevError, "could not find original archetype %s for custom monster!\n", op->arch->name);
5217  abort();
5218  }
5219  get_ob_diff(sb, &op->arch->clone, &original->clone);
5220  if (op->stats.hp != op->arch->clone.stats.hp)
5221  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5222  if (op->stats.sp != op->arch->clone.stats.sp)
5223  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5224  if (op->stats.grace != op->arch->clone.stats.grace)
5225  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5226  if (op->x != op->arch->clone.x)
5227  FAST_SAVE_LONG(sb, "x ", op->x);
5228  if (op->y != op->arch->clone.y)
5229  FAST_SAVE_LONG(sb, "y ", op->y);
5230  } else if (op->artifact != NULL) {
5231  /* if op is an artifact, then find the "standard" artifact to use that for the diff */
5232  object *base;
5233  const artifact *artifact;
5234 
5235  artifact = find_artifact(op, op->artifact);
5236  if (artifact == NULL) {
5237  LOG(llevError, "could not find artifact %s [%d] to save data\n", op->artifact, op->type);
5238  get_ob_diff(sb, op, &at->clone);
5239  } else {
5240  stringbuffer_append_printf(sb, "artifact %s\n", op->artifact);
5241  base = arch_to_object(at);
5242  give_artifact_abilities(base, artifact->item);
5243  get_ob_diff(sb, op, base);
5245  }
5246  } else {
5247  get_ob_diff(sb, op, &at->clone);
5248  }
5249 
5250  /* Eneq(@csd.uu.se): Added this to allow containers being saved with contents*/
5251  FOR_INV_PREPARE(op, tmp)
5252  save_object_in_sb(sb, tmp, flag);
5253  FOR_INV_FINISH();
5254 
5255  stringbuffer_append_string(sb, "end\n");
5256 }
5257 
5270 int save_object(FILE *fp, object *op, int flag) {
5271  /* Even if the object does have an owner, it would seem that we should
5272  * still save it.
5273  */
5274  if (object_get_owner(op) != NULL || fp == NULL)
5275  return SAVE_ERROR_OK;
5276 
5277  /* If it is unpaid and we don't want to save those, just return. */
5278  if (!(flag&SAVE_FLAG_SAVE_UNPAID) && (QUERY_FLAG(op, FLAG_UNPAID))) {
5279  return SAVE_ERROR_OK;
5280  }
5281 
5282  /* If the object has no_save set, just return */
5283  if (QUERY_FLAG(op, FLAG_NO_SAVE))
5284  return SAVE_ERROR_OK;
5285 
5287  save_object_in_sb(sb, op, flag);
5288  char *cp = stringbuffer_finish(sb);
5289  if (fputs(cp, fp) == EOF) {
5290  free(cp);
5291  return SAVE_ERROR_WRITE;
5292  } else {
5293  free(cp);
5294  return SAVE_ERROR_OK;
5295  }
5296 }
float weapon_speed_left
Definition: object.h:331
static int compare_ob_value_lists(const object *, const object *)
Definition: object.c:170
int object_distance(const object *ob1, const object *ob2)
Definition: object.c:3600
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.c:4018
#define FLAG_NO_MAGIC
Definition: define.h:276
char path[HUGE_BUF]
Definition: map.h:365
int find_dir_2(int x, int y)
Definition: object.c:3616
#define SET_MAP_OB(M, X, Y, tmp)
Definition: map.h:177
int reference_count
Definition: object.h:475
#define FLAG_NO_DROP
Definition: define.h:289
int8_t Int
Definition: living.h:36
#define NUM_BODY_LOCATIONS
Definition: object.h:13
Definition: player.h:92
archetype * find_archetype(const char *name)
Definition: arch.c:695
#define FLAG_DAMNED
Definition: define.h:318
#define FLAG_IS_FLOOR
Definition: define.h:303
#define FLAG_UNPAID
Definition: define.h:236
int8_t ac
Definition: living.h:38
struct _key_value * next
Definition: object.h:43
#define MOVE_WALK
Definition: define.h:407
int32_t weight_limit
Definition: object.h:367
#define UP_OBJ_FACE
Definition: object.h:519
tag_t ownercount
Definition: object.h:382
#define FLAG_IS_LINKED
Definition: define.h:316
MoveType move_type
Definition: object.h:426
#define INS_BELOW_ORIGINATOR
Definition: object.h:572
#define GET_MAP_MOVE_OFF(M, X, Y)
Definition: map.h:207
void object_free(object *ob, int flags)
Definition: object.c:1409
uint8_t dam_modifier
Definition: object.h:409
MoveType move_on
Definition: object.h:429
EXTERN long ob_count
Definition: global.h:154
#define P_PLAYER
Definition: map.h:236
#define SAVE_ERROR_OK
Definition: map.h:143
struct Statistics statistics
Definition: init.c:98
const char * race
Definition: object.h:318
#define P_NEED_UPDATE
Definition: map.h:239
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Definition: define.h:776
uint16_t attack_movement
Definition: object.h:393
#define OBJ_EXPAND
Definition: config.h:524
void esrv_send_item(object *pl, object *op)
Definition: main.c:340
tag_t attacked_by_count
Definition: object.h:385
#define SET_FLAG(xyz, p)
Definition: define.h:223
sstring add_refcount(sstring str)
Definition: shstr.c:210
void object_clear_owner(object *op)
Definition: object.c:612
MoveType move_allow
Definition: object.h:428
void object_sub_weight(object *op, signed long weight)
Definition: object.c:1637
object * object_find_by_type_applied(const object *who, int type)
Definition: object.c:3993
#define FABS(x)
Definition: define.h:22
unsigned char uint8_t
Definition: win32.h:161
Definition: object.h:221
void object_free_all_data(void)
Definition: object.c:553
void object_copy_owner(object *op, object *clone)
Definition: object.c:688
uint16_t animation_id
Definition: object.h:418
uint16_t material
Definition: object.h:348
tag_t * spell_tags
Definition: object.h:438
sstring artifact
Definition: object.h:314
object * object_find_by_type(const object *who, int type)
Definition: object.c:3922
uint64_t spell_merges
Definition: global.h:352
#define EVENT_DESTROY
Definition: plugin.h:77
object * object_get_env_recursive(object *op)
Definition: object.c:364
struct obj * container
Definition: object.h:291
#define FLAG_FRIENDLY
Definition: define.h:246
void object_copy_with_inv(const object *src_ob, object *dest_ob)
Definition: object.c:1006
sstring stringbuffer_finish_shared(StringBuffer *sb)
Definition: stringbuffer.c:85
#define P_NO_MAGIC
Definition: map.h:227
int16_t players
Definition: map.h:344
void fatal(enum fatal_error err)
Definition: utils.c:597
static object * find_insert_pos(object *op, const int flag)
Definition: object.c:2133
static void get_string_move_type(StringBuffer *sb, MoveType mt)
Definition: object.c:4795
int8_t range
Definition: object.h:407
void init_objects(void)
Definition: object.c:93
#define FLAG_NO_FIX_PLAYER
Definition: define.h:277
#define LOOK_OBJ(ob)
Definition: object.h:507
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
uint32_t in_memory
Definition: map.h:345
void get_search_arr(int *search_arr)
Definition: object.c:3517
unsigned char MoveType
Definition: define.h:432
int32_t last_heal
Definition: object.h:358
int16_t maxgrace
Definition: living.h:45
void free_string(sstring str)
Definition: shstr.c:280
#define UP_OBJ_INSERT
Definition: object.h:516
signed long object_sum_weight(object *op)
Definition: object.c:342
static void FAST_SAVE_LONG(StringBuffer *sb, const char *name, const long value)
Definition: object.c:4846
#define HUGE_BUF
Definition: define.h:37
void object_fix_multipart(object *tmp)
Definition: object.c:4583
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.c:2387
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.c:343
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4265
struct treasureliststruct * randomitems
Definition: object.h:387
static uint32_t NROF(const object *const ob)
Definition: object.h:612
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:720
#define MAP_HEIGHT(m)
Definition: map.h:80
object clone
Definition: object.h:472
int16_t duration
Definition: object.h:405
socket_struct socket
Definition: player.h:94
int16_t invisible
Definition: object.h:361
short freearr_x[SIZEOFFREE]
Definition: object.c:65
int object_find_multi_free_spot_within_radius(const object *ob, const object *gen, int *hx, int *hy)
Definition: object.c:3282
uint8_t duration_modifier
Definition: object.h:406
Definition: object.h:240
int object_count_active(void)
Definition: object.c:1610
const char * key
Definition: object.h:41
struct obj * prev
Definition: object.h:278
const char * slaying
Definition: object.h:319
object * object_find_by_flag(const object *who, int flag)
Definition: object.c:4116
int32_t last_sp
Definition: object.h:359
int object_check_move_on(object *op, object *originator)
Definition: object.c:2852
uint8_t subtype
Definition: object.h:340
int64_t exp
Definition: living.h:47
#define FREE_OBJ_NO_DESTROY_CALLBACK
Definition: object.h:533
int arch_init
Definition: arch.c:41
struct obj * above
Definition: object.h:288
void object_dump_all(void)
Definition: object.c:481
double expmul
Definition: object.h:397
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Definition: object.c:4068
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:217
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
#define TRUE
Definition: compat.h:10
int freedir[SIZEOFFREE]
Definition: object.c:83
object * arch_present_in_ob(const archetype *at, const object *op)
Definition: object.c:3077
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
Definition: item.c:54
#define FALSE
Definition: compat.h:11
void remove_friendly_object(object *op)
Definition: friend.c:56
uint32_t path_attuned
Definition: object.h:344
#define MAX(x, y)
Definition: compat.h:20
void object_update(object *op, int action)
Definition: object.c:1260
int16_t sp
Definition: living.h:42
uint32_t get_weight_limit(int stat)
Definition: living.c:2355
int object_can_merge(object *ob1, object *ob2)
Definition: object.c:202
uint8_t smoothlevel
Definition: object.h:423
uint32_t path_repelled
Definition: object.h:345
#define safe_strncpy
Definition: compat.h:23
uint32_t hidden
Definition: player.h:132
void free_dialog_information(object *op)
Definition: dialog.c:32
struct obj * enemy
Definition: object.h:383
struct archt * other_arch
Definition: object.h:415
int absdir(int d)
Definition: object.c:3653
object * object_find_by_name(const object *who, const char *name)
Definition: object.c:3898
Definition: object.h:467
uint8_t casting_time
Definition: global.h:272
uint64_t spell_hash_full
Definition: global.h:353
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:791
int16_t maxsp
Definition: living.h:43
int8_t Con
Definition: living.h:36
#define FLAG_REMOVED
Definition: define.h:232
int16_t hp
Definition: living.h:40
#define CALLOC(x, y)
Definition: compat.h:27
int nrofallocobjects
Definition: object.c:57
short freearr_y[SIZEOFFREE]
Definition: object.c:71
object * active_objects
Definition: object.c:62
static const int reduction_dir[SIZEOFFREE][3]
Definition: object.c:3691
#define SAVE_ERROR_WRITE
Definition: map.h:146
void object_set_flag_inv(object *op, int flag)
Definition: object.c:3097
#define MOVE_ALL
Definition: define.h:413
void esrv_del_item(player *pl, object *ob)
Definition: main.c:356
int object_find_multi_free_spot_around(const object *ob, const object *gen, int16_t *hx, int16_t *hy)
Definition: object.c:3163
int64_t total_exp
Definition: object.h:371
void object_set_owner(object *op, object *owner)
Definition: object.c:632
int16_t * discrete_damage
Definition: object.h:437
#define SAVE_FLAG_SAVE_UNPAID
Definition: map.h:110
Definition: object.h:241
const char * lore
Definition: object.h:323
#define MAP_IN_MEMORY
Definition: map.h:130
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.c:4394
uint32_t update_look
Definition: newserver.h:104
void object_free_drop_inventory(object *ob)
Definition: object.c:1389
const char * name
Definition: face.h:20
const char * title
Definition: object.h:317
int16_t y
Definition: object.h:326
key_value * object_get_key_value(const object *ob, const char *key)
Definition: object.c:4237
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1933
int16_t maxhp
Definition: living.h:41
sstring find_string(const char *str)
Definition: shstr.c:236
void object_replace_insert_in_map(const char *arch_string, object *op)
Definition: object.c:2435
int dirdiff(int dir1, int dir2)
Definition: object.c:3671
void object_update_turn_face(object *op)
Definition: object.c:1130
#define FREE_OBJ_FREE_INVENTORY
Definition: object.h:532
void object_dump(const object *op, StringBuffer *sb)
Definition: object.c:425
#define FLAG_CLIENT_ANIM_RANDOM
Definition: define.h:241
EXTERN archetype * empty_archetype
Definition: global.h:149
uint32_t path_denied
Definition: object.h:346
int maxfree[SIZEOFFREE]
Definition: object.c:77
#define STARTMAX
Definition: config.h:523
#define FLAG_ALIVE
Definition: define.h:230
object * object_new(void)
Definition: object.c:1068
const char * name_pl
Definition: object.h:315
#define FLAG_OBJ_ORIGINAL
Definition: define.h:365
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:95
object * object_find_by_tag_global(tag_t i)
Definition: object.c:507
#define FOR_OB_AND_ABOVE_FINISH()
Definition: define.h:780
int object_can_pick(const object *who, const object *item)
Definition: object.c:3809
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2707
float speed_left
Definition: object.h:329
#define MAP_DARKNESS(m)
Definition: map.h:75
#define INS_ON_TOP
Definition: object.h:571
#define FLAG_NO_STEAL
Definition: define.h:343
signed short int16_t
Definition: win32.h:160
int16_t ox
Definition: object.h:327
const char * materialname
Definition: object.h:347
int32_t weight
Definition: object.h:366
#define MOVE_FLY_LOW
Definition: define.h:408
const char * anim_suffix
Definition: object.h:316
#define FOR_ABOVE_FINISH()
Definition: define.h:731
void update_all_los(const mapstruct *map, int x, int y)
Definition: los.c:536
uint8_t range_modifier
Definition: object.h:408
int8_t Wis
Definition: living.h:36
uint32_t flags[4]
Definition: object.h:417
struct mapdef * map
Definition: object.h:297
void free_arch(archetype *at)
Definition: arch.c:265
#define snprintf
Definition: win32.h:46
struct obj * active_prev
Definition: object.h:283
#define FLAG_NO_SAVE
Definition: define.h:244
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.c:497
const char *const move_name[]
Definition: object.c:4735
const artifact * find_artifact(const object *op, const char *name)
Definition: artifact.c:657
#define FLAG_CLIENT_ANIM_SYNC
Definition: define.h:240
object * transport
Definition: player.h:195
#define FLAG_IDENTIFIED
Definition: define.h:261
#define FOR_INV_FINISH()
Definition: define.h:714
object * object_find_by_flag_applied(const object *who, int flag)
Definition: object.c:4139
void object_remove_from_active_list(object *op)
Definition: object.c:1215
#define FMT64
Definition: compat.h:12
void update_position(mapstruct *m, int x, int y)
Definition: map.c:2137
int16_t dam
Definition: living.h:46
int object_count_free(void)
Definition: object.c:1572
int32_t carrying
Definition: object.h:368
object * objects
Definition: object.c:60
#define FLAG_BLOCKSVIEW
Definition: define.h:269
struct artifactstruct artifact
static const char *const flag_names[NUM_FLAGS+1]
Definition: object.c:4754
const char * name
Definition: object.h:311
struct obj * env
Definition: object.h:293
static void FAST_SAVE_DOUBLE(StringBuffer *sb, const char *name, const double value)
Definition: object.c:4851
#define FOR_ABOVE_PREPARE(op_, it_)
Definition: define.h:724
int8_t gen_sp_armour
Definition: object.h:364
#define OB_SPELL_TAG_MATCH(op, count)
Definition: object.h:93
int save_object(FILE *fp, object *op, int flag)
Definition: object.c:5270
uint8_t state
Definition: object.h:350
struct obj * below
Definition: object.h:287
struct archt * more
Definition: object.h:471
#define INS_NO_WALK_ON
Definition: object.h:570
object * object_present_in_ob(uint8_t type, const object *op)
Definition: object.c:3017
#define offsetof(type, member)
Definition: shstr.h:37
#define FLAG_IS_A_TEMPLATE
Definition: define.h:375
int16_t last_grace
Definition: object.h:360
void object_reset(object *op)
Definition: object.c:735
#define GET_MAP_TOP(M, X, Y)
Definition: map.h:174
int8_t direction
Definition: object.h:335
object * object_create_clone(object *asrc)
Definition: object.c:3851
#define NUM_FLAGS
Definition: define.h:385
uint32_t nrof
Definition: object.h:333
int8_t Cha
Definition: living.h:36
#define GET_MAP_MOVE_ON(M, X, Y)
Definition: map.h:202
#define FLAG_OVERLAY_FLOOR
Definition: define.h:255
#define SIZEOFFREE
Definition: define.h:154
#define P_OUT_OF_MAP
Definition: map.h:251
MoveType move_off
Definition: object.h:430
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:192
object * object_find_by_name_global(const char *str)
Definition: object.c:530
EXTERN Animations * animations
Definition: global.h:163
struct pl * contr
Definition: object.h:276
int8_t item_power
Definition: object.h:363
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:2200
void object_clear(object *op)
Definition: object.c:790
int16_t oy
Definition: object.h:327
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:206
#define MAP_SAVING
Definition: map.h:133
#define UPD_WEIGHT
Definition: newclient.h:291
uint32_t tag_t
Definition: object.h:12
static void ADD_STRINGLINE_ENTRY(StringBuffer *sb, const char *name, const char *value)
Definition: object.c:4839
object * object_find_by_type_and_race(const object *who, int type, const char *race)
Definition: object.c:4043
int8_t luck
Definition: living.h:39
float speed
Definition: object.h:328
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define HEAD(op)
Definition: object.h:594
#define INS_ABOVE_FLOOR_ONLY
Definition: object.h:569
#define FLAG_BEEN_APPLIED
Definition: define.h:324
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Definition: object.c:4645
#define MAX_BUF
Definition: define.h:35
static object * free_objects
Definition: object.c:61
struct obj * active_next
Definition: object.h:279
static void expand_objects(void)
Definition: object.c:1024
void give_artifact_abilities(object *op, const object *artifact)
Definition: artifact.c:203
method_ret ob_move_on(object *op, object *victim, object *originator)
Definition: ob_methods.c:111
int16_t x
Definition: object.h:326
int strncasecmp(const char *s1, const char *s2, int n)
Definition: porting.c:224
const char *const map_layer_name[MAP_LAYERS]
Definition: map.c:54
int nroffreeobjects
Definition: object.c:56
MoveType move_slow
Definition: object.h:431
const char * skill
Definition: object.h:321
int32_t last_eat
Definition: object.h:357
Definition: object.h:201
int8_t wc
Definition: living.h:37
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
Definition: object.c:3474
void object_insert_to_free_spot_or_free(object *op, mapstruct *map, int x, int y, int start, int stop, object *originator)
Definition: object.c:4694
static const flag_definition flags[]
#define FOR_MAP_FINISH()
Definition: define.h:767
key_value * key_values
Definition: object.h:435
struct obj * next
Definition: object.h:277
int8_t Str
Definition: living.h:36
#define COMPARE_FLAGS(p, q)
Definition: define.h:226
void animate_object(object *op, int dir)
Definition: anim.c:213
#define FLAG_NO_APPLY
Definition: define.h:302
int16_t resist[NROFATTACKS]
Definition: object.h:342
#define FLAG_KNOWN_CURSED
Definition: define.h:321
object * ob
Definition: player.h:158
object * object_find_by_tag(const object *who, tag_t tag)
Definition: object.c:3970
#define GET_MAP_FLAGS(M, X, Y)
Definition: map.h:161
#define FLAG_IS_HILLY
Definition: define.h:333
#define SPELL_TAG_SIZE
Definition: object.h:81
#define FLAG_CURSED
Definition: define.h:317
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Definition: object.c:4214
#define SET_MAP_FLAGS(M, X, Y, C)
Definition: map.h:163
#define FLAG_ANIMATE
Definition: define.h:242
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:374
const char * name
Definition: treasure.h:83
object * object_find_by_type_and_skill(const object *who, int type, const char *skill)
Definition: object.c:4093
uint32_t attacktype
Definition: object.h:343
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2478
uint8_t map_layer
Definition: object.h:424
#define INS_NO_MERGE
Definition: object.h:568
object * object_decrease_nrof(object *op, uint32_t i)
Definition: object.c:2520
void save_object_in_sb(StringBuffer *sb, const object *op, const int flag)
Definition: object.c:5201
#define UP_OBJ_CHANGE
Definition: object.h:518
struct obj * owner
Definition: object.h:379
#define RANDOM()
Definition: define.h:681
int16_t grace
Definition: living.h:44
#define UPD_NROF
Definition: newclient.h:296
signed char int8_t
Definition: win32.h:158
Definition: object.h:143
#define GET_MAP_PLAYER(M, X, Y)
Definition: map.h:168
New_Face * blank_face
Definition: image.c:39
const char * custom_name
Definition: object.h:434
#define UP_OBJ_REMOVE
Definition: object.h:517
int get_button_value(const object *button)
Definition: button.c:754
tag_t count
Definition: object.h:299
living stats
Definition: object.h:369
uint16_t client_type
Definition: object.h:341
int8_t Dex
Definition: living.h:36
struct archt * arch
Definition: object.h:414
#define AB_NO_PASS
Definition: map.h:235
#define UPD_FACE
Definition: newclient.h:292
#define MAP_WIDTH(m)
Definition: map.h:78
uint8_t will_apply
Definition: object.h:394
uint8_t type
Definition: object.h:339
uint32_t do_los
Definition: player.h:126
struct Settings settings
Definition: init.c:39
void object_set_enemy(object *op, object *enemy)
Definition: object.c:710
uint32_t weapontype
Definition: object.h:373
#define FLAG_APPLIED
Definition: define.h:235
#define NROFATTACKS
Definition: attack.h:17
object * object_merge(object *op, object *top)
Definition: object.c:1881
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:548
object * object_get_player_container(object *op)
Definition: object.c:384
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2313
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: main.c:365
static object objarray[STARTMAX]
Definition: object.c:55
#define SIZEOFFREE2
Definition: define.h:153
#define OB_SPELL_TAG_HASH(op, count)
Definition: object.h:87
int object_count_used(void)
Definition: object.c:1591
static const object * object_get_owner_const(const object *op)
Definition: object.c:401
const char * msg
Definition: object.h:322
const char * value
Definition: object.h:42
static void permute(int *, int, int)
Definition: object.c:3493
int16_t casting_time
Definition: object.h:404
void object_unset_flag_inv(object *op, int flag)
Definition: object.c:3117
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.c:4472
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:787
#define FLAG_STARTEQUIP
Definition: define.h:268
void object_merge_spell(object *op, int16_t x, int16_t y)
Definition: object.c:1965
int map_find_dir(mapstruct *m, int x, int y, object *exclude)
Definition: object.c:3550
#define GET_ANIM_ID(ob)
Definition: global.h:171
sstring add_string(const char *str)
Definition: shstr.c:124
EXTERN player * first_player
Definition: global.h:117
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.c:104
struct pl * next
Definition: player.h:93
#define MIN_ACTIVE_SPEED
Definition: define.h:676
void object_add_weight(object *op, signed long weight)
Definition: object.c:2680
#define GET_MAP_OB(M, X, Y)
Definition: map.h:172
int strcasecmp(const char *s1, const char *s2)
Definition: porting.c:256
int8_t glow_radius
Definition: object.h:365
#define FLAG_MONSTER
Definition: define.h:245
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.c:869
int8_t Pow
Definition: living.h:36
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:310
struct obj * inv
Definition: object.h:290
void object_set_cheat(object *op)
Definition: object.c:3138
#define SIZEOFFREE1
Definition: define.h:152
struct obj * head
Definition: object.h:296
#define MOVE_FLY_HIGH
Definition: define.h:409
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
static void object_increase_nrof(object *op, uint32_t i)
Definition: object.c:2607
EXTERN const char *const resist_save[NROFATTACKS]
Definition: attack.h:139
#define SET_MAP_TOP(M, X, Y, tmp)
Definition: map.h:179
#define FLAG_WAS_WIZ
Definition: define.h:234
uint8_t pick_up
Definition: object.h:362
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:760
#define FREE_OBJ_DROP_ABOVE_FLOOR
Definition: object.h:534
MoveType move_block
Definition: object.h:427
uint8_t run_away
Definition: object.h:386
#define GET_MAP_MOVE_SLOW(M, X, Y)
Definition: map.h:197
#define P_BLOCKSVIEW
Definition: map.h:226
void object_set_msg(object *op, const char *msg)
Definition: object.c:4714
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
Definition: object.c:3761
int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
Definition: object.c:3431
#define FLAG_DIALOG_PARSED
Definition: define.h:243
#define P_NO_ERROR
Definition: map.h:240
float move_slow_penalty
Definition: object.h:432
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:623
object * item
Definition: artifact.h:15
object * find_skill_by_number(object *who, int skillno)
Definition: main.c:352
object * map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at)
Definition: object.c:2961
Definition: map.h:325
#define P_IS_ALIVE
Definition: map.h:237
void get_ob_diff(StringBuffer *sb, const object *op, const object *op2)
Definition: object.c:4868
const New_Face * face
Definition: object.h:332
#define FREE_AND_CLEAR(xyz)
Definition: global.h:201
#define FLAG_IS_WOODED
Definition: define.h:331
#define FLAG_NO_PICK
Definition: define.h:239
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
Definition: object.c:4187
#define FLAG_WIZPASS
Definition: define.h:315
int32_t move_status
Definition: object.h:392
void object_free_key_values(object *op)
Definition: object.c:758
int16_t level
Definition: object.h:352
#define FLAG_INV_LOCKED
Definition: define.h:330
void fix_object(object *op)
Definition: living.c:1120
float weapon_speed
Definition: object.h:330
struct obj * more
Definition: object.h:295
object * arch_to_object(archetype *at)
Definition: arch.c:571
void object_update_speed(object *op)
Definition: object.c:1150
#define SCRIPT_FIX_NOTHING
Definition: global.h:368
int32_t value
Definition: object.h:351
object * object_get_owner(object *op)
Definition: object.c:590
int8_t magic
Definition: object.h:349
const char * name
Definition: object.h:468
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
#define P_NO_CLERIC
Definition: map.h:238
object * object_find_by_arch_name(const object *who, const char *name)
Definition: object.c:4162
object * object_present_in_ob_by_name(int type, const char *str, const object *op)
Definition: object.c:3055
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:707
void object_remove(object *op)
Definition: object.c:1666
object * map_find_by_type(mapstruct *m, int x, int y, uint8_t type)
Definition: object.c:2991
static int compare_ob_value_lists_one(const object *, const object *)
Definition: object.c:129
#define INS_MAP_LOAD
Definition: object.h:573
object * object_find_by_type2(const object *who, int type1, int type2)
Definition: object.c:3947
int32_t food
Definition: living.h:48
#define FLAG_FREED
Definition: define.h:233
uint32_t count
Definition: player.h:109
static int object_set_value_s(object *, const char *, const char *, int)
Definition: object.c:4308
#define FLAG_IS_TURNABLE
Definition: define.h:256