Crossfire Server, Trunk  R20513
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 object objarray[STARTMAX];
58 #endif
59 
60 object *objects;
61 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 
98 static int compare_ob_value_lists_one(const object *wants, const object *has) {
99  key_value *wants_field;
100 
101  /* n-squared behaviour (see object_get_key_value()), but I'm hoping both
102  * objects with lists are rare, and lists stay short. If not, use a
103  * different structure or at least keep the lists sorted...
104  */
105 
106  /* For each field in wants, */
107  for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) {
108  key_value *has_field;
109 
110  /* Look for a field in has with the same key. */
111  has_field = object_get_key_value(has, wants_field->key);
112 
113  if (has_field == NULL) {
114  /* No field with that name. */
115  return FALSE;
116  }
117 
118  /* Found the matching field. */
119  if (has_field->value != wants_field->value) {
120  /* Values don't match, so this half of the comparison is false. */
121  return FALSE;
122  }
123 
124  /* If we get here, we found a match. Now for the next field in wants. */
125  }
126 
127  /* If we get here, every field in wants has a matching field in has. */
128  return TRUE;
129 }
130 
139 static int compare_ob_value_lists(const object *ob1, const object *ob2) {
140  /* However, there may be fields in has which aren't partnered in wants,
141  * so we need to run the comparison *twice*. :(
142  */
143  return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1);
144 }
145 
171 int object_can_merge(object *ob1, object *ob2) {
172  /* A couple quicksanity checks */
173  if (ob1 == ob2 || ob1->type != ob2->type)
174  return 0;
175 
176  if (ob1->speed != ob2->speed)
177  return 0;
178  /* Note sure why the following is the case - either the object has to
179  * be animated or have a very low speed. Is this an attempted monster
180  * check?
181  */
182  /*TODO is this check really needed?*/
183  if (!QUERY_FLAG(ob1, FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
184  return 0;
185 
186  /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
187  * value could not be stored in a int32_t (which unfortunately sometimes is
188  * used to store nrof).
189  */
190  if (ob1->nrof+ob2->nrof >= 1UL<<31)
191  return 0;
192 
193  /* This is really a spellbook check - really, we should
194  * check all objects in the inventory.
195  */
196  /*TODO is this check really needed?*/
197  if (ob1->inv || ob2->inv) {
198  /* if one object has inventory but the other doesn't, not equiv */
199  if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
200  return 0;
201 
202  /* Now check to see if the two inventory objects could merge */
203  if (!object_can_merge(ob1->inv, ob2->inv))
204  return 0;
205 
206  /* inventory ok - still need to check rest of this object to see
207  * if it is valid.
208  */
209  }
210 
211  /* If the objects have been identified, set the BEEN_APPLIED flag.
212  * This is to the comparison of the flags below will be OK. We
213  * just can't ignore the been applied or identified flags, as they
214  * are not equal - just if it has been identified, the been_applied
215  * flags lose any meaning.
216  */
217 
218  /*TODO is this hack on BEEN_APPLIED really needed? */
219  if (QUERY_FLAG(ob1, FLAG_IDENTIFIED))
221 
222  if (QUERY_FLAG(ob2, FLAG_IDENTIFIED))
224 
225 
226  /* Note: FLAG_INV_LOCKED is ignored for merging purposes */
227  if ((ob1->arch != ob2->arch)
228  || (ob1->flags[0] != ob2->flags[0])
229  || (ob1->flags[1] != ob2->flags[1])
230  || (ob1->flags[2] != ob2->flags[2])
231  || ((ob1->flags[3]&~0x84) != (ob2->flags[3]&~0x84)) /* ignore CLIENT_SENT and FLAG_OBJ_ORIGINAL */
232  || (ob1->name != ob2->name)
233  || (ob1->title != ob2->title)
234  || (ob1->msg != ob2->msg)
235  || (ob1->weight != ob2->weight)
236  || (ob1->item_power != ob2->item_power)
237  || (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist)) != 0)
238  || (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats)) != 0)
239  || (ob1->attacktype != ob2->attacktype)
240  || (ob1->magic != ob2->magic)
241  || (ob1->slaying != ob2->slaying)
242  || (ob1->skill != ob2->skill)
243  || (ob1->value != ob2->value)
244  || (ob1->animation_id != ob2->animation_id)
245  || (ob1->client_type != ob2->client_type)
246  || (ob1->materialname != ob2->materialname)
247  || (ob1->lore != ob2->lore)
248  || (ob1->subtype != ob2->subtype)
249  || (ob1->move_type != ob2->move_type)
250  || (ob1->move_block != ob2->move_block)
251  || (ob1->move_allow != ob2->move_allow)
252  || (ob1->move_on != ob2->move_on)
253  || (ob1->move_off != ob2->move_off)
254  || (ob1->move_slow != ob2->move_slow)
255  || (ob1->move_slow_penalty != ob2->move_slow_penalty)
256  || (ob1->map_layer != ob2->map_layer))
257  return 0;
258 
259  /* Don't merge objects that are applied. With the new 'body' code,
260  * it is possible for most any character to have more than one of
261  * some items equipped, and we don't want those to merge.
262  */
263  if (QUERY_FLAG(ob1, FLAG_APPLIED) || QUERY_FLAG(ob2, FLAG_APPLIED))
264  return 0;
265 
266  if (ob1->key_values != NULL || ob2->key_values != NULL) {
267  /* At least one of these has key_values. */
268  if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
269  /* One has fields, but the other one doesn't. */
270  return 0;
271  } else {
272  return compare_ob_value_lists(ob1, ob2);
273  }
274  }
275 
276  /*TODO should this really be limited to scrolls?*/
277  switch (ob1->type) {
278  case SCROLL:
279  if (ob1->level != ob2->level)
280  return 0;
281  break;
282  }
283 
284  /* Don't merge items with differing custom names. */
285  if (ob1->custom_name != ob2->custom_name)
286  return 0;
287 
288  /* Everything passes, must be OK. */
289  return 1;
290 }
291 
310 /* TODO should check call this this are made a place where we really need reevaluaton of whole tree */
311 signed long object_sum_weight(object *op) {
312  signed long sum;
313 
314  sum = 0;
315  FOR_INV_PREPARE(op, inv) {
316  if (inv->inv)
317  object_sum_weight(inv);
318  sum += inv->carrying+inv->weight*(inv->nrof ? inv->nrof : 1);
319  } FOR_INV_FINISH();
320  if (op->type == CONTAINER && op->stats.Str)
321  sum = (sum*(100-op->stats.Str))/100;
322  op->carrying = sum;
323  return sum;
324 }
325 
333 object *object_get_env_recursive(object *op) {
334  while (op->env != NULL)
335  op = op->env;
336  return op;
337 }
338 
353 object *object_get_player_container(object *op) {
354  for (; op != NULL && op->type != PLAYER; op = op->env)
355  /*TODO this is patching the structure on the flight as side effect. Shoudln't be needed in clean code */
356  if (op->env == op)
357  op->env = NULL;
358  return op;
359 }
360 
370 static const object *object_get_owner_const(const object *op) {
371  if (op->owner == NULL)
372  return NULL;
373 
374  if (!QUERY_FLAG(op->owner, FLAG_FREED)
375  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
376  && op->owner->count == op->ownercount)
377  return op->owner;
378 
379  LOG(llevError, "Warning, no owner found\n");
380  return NULL;
381 }
382 
394 void object_dump(const object *op, StringBuffer *sb) {
395  if (op == NULL) {
396  stringbuffer_append_string(sb, "[NULL pointer]");
397  return;
398  }
399 
400  /* object *tmp;*/
401 
402  if (op->arch != NULL) {
403  const object *owner;
404 
405  stringbuffer_append_string(sb, "arch ");
406  stringbuffer_append_string(sb, op->arch->name ? op->arch->name : "(null)");
407  stringbuffer_append_string(sb, "\n");
408 
409  if (op->artifact != NULL) {
410  stringbuffer_append_string(sb, "artifact ");
412  stringbuffer_append_string(sb, "\n");
413  }
414 
415  get_ob_diff(sb, op, &empty_archetype->clone);
416  if (op->more) {
417  stringbuffer_append_printf(sb, "more %u\n", op->more->count);
418  }
419  if (op->head) {
420  stringbuffer_append_printf(sb, "head %u\n", op->head->count);
421  }
422  if (op->env) {
423  stringbuffer_append_printf(sb, "env %u\n", op->env->count);
424  }
425  if (op->inv) {
426  stringbuffer_append_printf(sb, "inv %u\n", op->inv->count);
427  }
428  owner = object_get_owner_const(op);
429  if (owner != NULL) {
430  stringbuffer_append_printf(sb, "owner %u\n", owner->count);
431  }
432  stringbuffer_append_string(sb, "end\n");
433  } else {
434  stringbuffer_append_string(sb, "Object ");
435  stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
436  stringbuffer_append_string(sb, "\nend\n");
437  }
438 }
439 
450 void object_dump_all(void) {
451  object *op;
452 
453  for (op = objects; op != NULL; op = op->next) {
454  StringBuffer *sb;
455  char *diff;
456 
457  sb = stringbuffer_new();
458  object_dump(op, sb);
459  diff = stringbuffer_finish(sb);
460  LOG(llevDebug, "Object %u\n:%s\n", op->count, diff);
461  free(diff);
462  }
463 }
464 
477  object *op;
478 
479  for (op = objects; op != NULL; op = op->next)
480  if (op->count == i)
481  break;
482  return op;
483 }
484 
499 object *object_find_by_name_global(const char *str) {
500  const char *name = add_string(str);
501  object *op;
502 
503  for (op = objects; op != NULL; op = op->next)
504  if (op->name == name)
505  break;
506  free_string(name);
507  return op;
508 }
509 
523 #ifdef MEMORY_DEBUG
524  object *op, *next;
525 
526  for (op = free_objects; op != NULL; ) {
527  next = op->next;
528  free(op);
530  nroffreeobjects--;
531  op = next;
532  }
533  free_objects = NULL;
534 
535  for (op = objects; op != NULL; ) {
536  next = op->next;
537  if (!QUERY_FLAG(op, FLAG_FREED)) {
538  LOG(llevDebug, "non freed object: %s\n", op->name);
539  }
540  op = next;
541  }
542 #endif
543 
544  LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX);
545 }
546 
559 object *object_get_owner(object *op) {
560  if (op->owner == NULL)
561  return NULL;
562 
563  if (!QUERY_FLAG(op->owner, FLAG_FREED)
564  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
565  && op->owner->count == op->ownercount)
566  return op->owner;
567 
568  object_clear_owner(op);
569  return NULL;
570 }
571 
581 void object_clear_owner(object *op) {
582  if (!op)
583  return;
584 
585  op->owner = NULL;
586  op->ownercount = 0;
587 }
588 
601 void object_set_owner(object *op, object *owner) {
602  /* Assign temp to something, so it can't accidentally be NULL */
603  object *tmp = owner;
604  if (op == NULL)
605  return;
606  if (owner == NULL) {
607  object_clear_owner(op);
608  return;
609  }
610 
611  /* next line added to allow objects which own objects */
612  /* Add a check for ownercounts in here, as I got into an endless loop
613  * with the fireball owning a poison cloud which then owned the
614  * fireball. I believe that was caused by one of the objects getting
615  * freed and then another object replacing it. Since the ownercounts
616  * didn't match, this check is valid and I believe that cause is valid.
617  */
618  /*
619  * if owner is NULL, function will have already returned,
620  * so loop should still function as before.
621  */
622  while (tmp) {
623  tmp = object_get_owner(owner);
624  if (tmp)
625  owner = tmp;
626  }
627 
628  /* must not cause owner cycles */
629  assert(op != owner);
630 
631  if (op->owner != NULL)
632  object_clear_owner(op);
633 
634  op->owner = owner;
635  op->ownercount = owner->count;
636 }
637 
657 void object_copy_owner(object *op, object *clone) {
658  object *owner = object_get_owner(clone);
659  if (owner == NULL) {
660  /* players don't have owners - they own themselves. Update
661  * as appropriate.
662  */
663  /*TODO owner=self is dangerous and should be avoided*/
664  if (clone->type != PLAYER)
665  return;
666  owner = clone;
667  }
668  object_set_owner(op, owner);
669 }
670 
679 void object_set_enemy(object *op, object *enemy) {
680  if (op->enemy == enemy) {
681  return;
682  }
683 
684 #if 0
685  if (op->type != PLAYER) {
686  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);
687  }
688 #endif
689  op->enemy = enemy;
690 }
691 
704 void object_reset(object *op) {
705  op->name = NULL;
706  op->name_pl = NULL;
707  op->title = NULL;
708  op->race = NULL;
709  op->slaying = NULL;
710  op->skill = NULL;
711  op->msg = NULL;
712  op->materialname = NULL;
713  op->lore = NULL;
714  object_clear(op);
715 }
716 
727 void object_free_key_values(object *op) {
728  key_value *i;
729  key_value *next = NULL;
730 
731  if (op->key_values == NULL)
732  return;
733 
734  for (i = op->key_values; i != NULL; i = next) {
735  /* Store next *first*. */
736  next = i->next;
737 
738  if (i->key)
740  if (i->value)
742  i->next = NULL;
743  free(i);
744  }
745 
746  op->key_values = NULL;
747 }
748 
759 void object_clear(object *op) {
760  /*TODO this comment must be investigated*/
761  /* redo this to be simpler/more efficient. Was also seeing
762  * crashes in the old code. Move this to the top - am
763  * seeing periodic crashes in this code, and would like to have
764  * as much info available as possible (eg, object name).
765  */
768 
769  /* the memset will clear all these values for us, but we need
770  * to reduce the refcount on them.
771  */
772  if (op->name != NULL)
774  if (op->name_pl != NULL)
776  if (op->title != NULL)
778  if (op->race != NULL)
780  if (op->slaying != NULL)
782  if (op->skill != NULL)
784  if (op->msg != NULL)
785  FREE_AND_CLEAR_STR(op->msg);
786  if (op->lore != NULL)
788  if (op->materialname != NULL)
790  if (op->discrete_damage != NULL)
792 
793  /* Remove object from friendly list if needed. */
794  if (QUERY_FLAG(op, FLAG_FRIENDLY))
796 
797  memset((void *)((char *)op+offsetof(object, name)), 0, sizeof(object)-offsetof(object, name));
798  /* Below here, we clear things that are not done by the memset,
799  * or set default values that are not zero.
800  */
801  /* This is more or less true */
802  SET_FLAG(op, FLAG_REMOVED);
803 
804 
805  op->contr = NULL;
806  op->below = NULL;
807  op->above = NULL;
808  op->inv = NULL;
809  op->container = NULL;
810  op->env = NULL;
811  op->more = NULL;
812  op->head = NULL;
813  op->map = NULL;
814  op->active_next = NULL;
815  op->active_prev = NULL;
816  /* What is not cleared is next, prev, and count */
817 
818  op->expmul = 1.0;
819  op->face = blank_face;
820  op->attacked_by_count = -1;
822  op->casting_time = -1;
823 }
824 
838 void object_copy(const object *src_ob, object *dest_ob) {
839  int is_freed = QUERY_FLAG(dest_ob, FLAG_FREED), is_removed = QUERY_FLAG(dest_ob, FLAG_REMOVED);
840 
841  /* Decrement the refcounts, but don't bother zeroing the fields;
842  they'll be overwritten by memcpy. */
843  if (dest_ob->artifact != NULL)
844  free_string(dest_ob->artifact);
845  if (dest_ob->name != NULL)
846  free_string(dest_ob->name);
847  if (dest_ob->name_pl != NULL)
848  free_string(dest_ob->name_pl);
849  if (dest_ob->anim_suffix != NULL)
850  free_string(dest_ob->anim_suffix);
851  if (dest_ob->title != NULL)
852  free_string(dest_ob->title);
853  if (dest_ob->race != NULL)
854  free_string(dest_ob->race);
855  if (dest_ob->slaying != NULL)
856  free_string(dest_ob->slaying);
857  if (dest_ob->skill != NULL)
858  free_string(dest_ob->skill);
859  if (dest_ob->msg != NULL)
860  free_string(dest_ob->msg);
861  if (dest_ob->lore != NULL)
862  free_string(dest_ob->lore);
863  if (dest_ob->materialname != NULL)
864  free_string(dest_ob->materialname);
865  if (dest_ob->custom_name != NULL)
866  free_string(dest_ob->custom_name);
867  if (dest_ob->discrete_damage != NULL)
869  if (dest_ob->spell_tags != NULL)
870  FREE_AND_CLEAR(dest_ob->spell_tags);
871 
872  /* Basically, same code as from object_clear() */
873 
874  object_free_key_values(dest_ob);
875  free_dialog_information(dest_ob);
876 
877  /* Copy all attributes below name (name included). */
878  (void)memcpy((void *)((char *)dest_ob+offsetof(object, name)),
879  (void *)((char *)src_ob+offsetof(object, name)),
880  sizeof(object)-offsetof(object, name));
881 
882  if (is_freed)
883  SET_FLAG(dest_ob, FLAG_FREED);
884  if (is_removed)
885  SET_FLAG(dest_ob, FLAG_REMOVED);
886  if (dest_ob->artifact != NULL)
887  add_refcount(dest_ob->artifact);
888  if (dest_ob->name != NULL)
889  add_refcount(dest_ob->name);
890  if (dest_ob->name_pl != NULL)
891  add_refcount(dest_ob->name_pl);
892  if (dest_ob->anim_suffix != NULL)
893  add_refcount(dest_ob->anim_suffix);
894  if (dest_ob->title != NULL)
895  add_refcount(dest_ob->title);
896  if (dest_ob->race != NULL)
897  add_refcount(dest_ob->race);
898  if (dest_ob->slaying != NULL)
899  add_refcount(dest_ob->slaying);
900  if (dest_ob->skill != NULL)
901  add_refcount(dest_ob->skill);
902  if (dest_ob->lore != NULL)
903  add_refcount(dest_ob->lore);
904  if (dest_ob->msg != NULL)
905  add_refcount(dest_ob->msg);
906  if (dest_ob->custom_name != NULL)
907  add_refcount(dest_ob->custom_name);
908  if (dest_ob->materialname != NULL)
909  add_refcount(dest_ob->materialname);
910  if (dest_ob->discrete_damage != NULL) {
911  dest_ob->discrete_damage = malloc(sizeof(int16_t)*NROFATTACKS);
912  memcpy(dest_ob->discrete_damage, src_ob->discrete_damage, sizeof(int16_t)*NROFATTACKS);
913  }
914 
915  if (dest_ob->spell_tags != NULL) {
916  dest_ob->spell_tags = malloc(sizeof(tag_t)*SPELL_TAG_SIZE);
917  memcpy(dest_ob->spell_tags, src_ob->spell_tags, sizeof(tag_t)*SPELL_TAG_SIZE);
918  }
919 
920  /* If archetype is a temporary one, we need to update reference count, because
921  * that archetype will be freed by object_free_drop_inventory() when the last object is removed.
922  */
923  if (dest_ob->arch->reference_count > 0)
924  dest_ob->arch->reference_count++;
925 
926  if (src_ob->speed < 0)
927  dest_ob->speed_left = src_ob->speed_left-RANDOM()%200/100.0;
928 
929  /* Copy over key_values, if any. */
930  if (src_ob->key_values != NULL) {
931  key_value *tail = NULL;
932  key_value *i;
933 
934  dest_ob->key_values = NULL;
935 
936  for (i = src_ob->key_values; i != NULL; i = i->next) {
937  key_value *new_link = malloc(sizeof(key_value));
938 
939  new_link->next = NULL;
940  new_link->key = add_refcount(i->key);
941  if (i->value)
942  new_link->value = add_refcount(i->value);
943  else
944  new_link->value = NULL;
945 
946  /* Try and be clever here, too. */
947  if (dest_ob->key_values == NULL) {
948  dest_ob->key_values = new_link;
949  tail = new_link;
950  } else {
951  tail->next = new_link;
952  tail = new_link;
953  }
954  }
955  }
956 
957  /* This way, dialog information will be parsed again when/if needed. */
958  CLEAR_FLAG(dest_ob, FLAG_DIALOG_PARSED);
959 
960  object_update_speed(dest_ob);
961 }
962 
975 void object_copy_with_inv(const object *src_ob, object *dest_ob) {
976  object_copy(src_ob, dest_ob);
977  FOR_INV_PREPARE(src_ob, walk) {
978  object *tmp;
979 
980  tmp = object_new();
981  object_copy_with_inv(walk, tmp);
982  object_insert_in_ob(tmp, dest_ob);
983  } FOR_INV_FINISH();
984 }
985 
993 static void expand_objects(void) {
994  int i;
995  object *new;
996 
997  new = (object *)CALLOC(OBJ_EXPAND, sizeof(object));
998 
999  if (new == NULL)
1001  free_objects = new;
1002  new[0].prev = NULL;
1003  new[0].next = &new[1],
1004  SET_FLAG(&new[0], FLAG_REMOVED);
1005  SET_FLAG(&new[0], FLAG_FREED);
1006 
1007  for (i = 1; i < OBJ_EXPAND-1; i++) {
1008  new[i].next = &new[i+1],
1009  new[i].prev = &new[i-1],
1010  SET_FLAG(&new[i], FLAG_REMOVED);
1011  SET_FLAG(&new[i], FLAG_FREED);
1012  }
1013  new[OBJ_EXPAND-1].prev = &new[OBJ_EXPAND-2],
1014  new[OBJ_EXPAND-1].next = NULL,
1015  SET_FLAG(&new[OBJ_EXPAND-1], FLAG_REMOVED);
1016  SET_FLAG(&new[OBJ_EXPAND-1], FLAG_FREED);
1017 
1020 }
1021 
1037 object *object_new(void) {
1038  object *op;
1039 
1040  if (free_objects == NULL) {
1041  expand_objects();
1042  }
1043  op = free_objects;
1044 #ifdef MEMORY_DEBUG
1045  /* The idea is hopefully by doing a realloc, the memory
1046  * debugging program will now use the current stack trace to
1047  * report leaks.
1048  */
1049  /* FIXME: However this doesn't work since object_free2() sometimes add
1050  * objects back to the free_objects linked list, and some functions mess
1051  * with the object after return of object_free2(). This is bad and should be
1052  * fixed. But it would need fairly extensive changes and a lot of debugging.
1053  * So until that is fixed, skip realloc() here unless MEMORY_DEBUG is set to
1054  * a value greater than 1. We do this in order at least make MEMORY_DEBUG
1055  * slightly useful.
1056  */
1057 #if MEMORY_DEBUG > 1
1058  op = realloc(op, sizeof(object));
1059 #endif
1060  SET_FLAG(op, FLAG_REMOVED);
1061  SET_FLAG(op, FLAG_FREED);
1062 #endif
1063 
1064  if (!QUERY_FLAG(op, FLAG_FREED)) {
1065  LOG(llevError, "Fatal: Getting busy object.\n");
1066 #ifdef MANY_CORES
1067  abort();
1068 #endif
1069  }
1070  free_objects = op->next;
1071  if (free_objects != NULL)
1072  free_objects->prev = NULL;
1073  op->count = ++ob_count;
1074  op->name = NULL;
1075  op->name_pl = NULL;
1076  op->title = NULL;
1077  op->race = NULL;
1078  op->slaying = NULL;
1079  op->skill = NULL;
1080  op->lore = NULL;
1081  op->msg = NULL;
1082  op->materialname = NULL;
1083  op->next = objects;
1084  op->prev = NULL;
1085  op->active_next = NULL;
1086  op->active_prev = NULL;
1087  op->discrete_damage = NULL;
1088  op->spell_tags = NULL;
1089  if (objects != NULL)
1090  objects->prev = op;
1091  objects = op;
1092  object_clear(op);
1093  SET_FLAG(op, FLAG_REMOVED);
1094  nroffreeobjects--;
1095  return op;
1096 }
1097 
1109 void object_update_turn_face(object *op) {
1110  if (op->animation_id == 0 || !QUERY_FLAG(op, FLAG_IS_TURNABLE))
1111  return;
1112  animate_object(op, op->direction);
1113 }
1114 
1129 void object_update_speed(object *op) {
1130  /* FIXME what the hell is this crappy hack?*/
1131  extern int arch_init;
1132 
1133  /* No reason putting the archetypes objects on the speed list,
1134  * since they never really need to be updated.
1135  */
1136 
1137  if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
1138  LOG(llevError, "Object %s is freed but has speed.\n", op->name);
1139 #ifdef MANY_CORES
1140  abort();
1141 #else
1142  op->speed = 0;
1143 #endif
1144  }
1145  if (arch_init) {
1146  return;
1147  }
1148  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
1149  /* If already on active list, don't do anything */
1150  /* TODO this check can probably be simplified a lot */
1151  if (op->active_next || op->active_prev || op == active_objects)
1152  return;
1153 
1154  /* process_events() expects us to insert the object at the beginning
1155  * of the list. */
1157  if (op->active_next != NULL)
1158  op->active_next->active_prev = op;
1159  active_objects = op;
1160  } else {
1161  /* If not on the active list, nothing needs to be done */
1162  if (!op->active_next && !op->active_prev && op != active_objects)
1163  return;
1164 
1165  if (op->active_prev == NULL) {
1166  active_objects = op->active_next;
1167  if (op->active_next != NULL)
1168  op->active_next->active_prev = NULL;
1169  } else {
1170  op->active_prev->active_next = op->active_next;
1171  if (op->active_next)
1172  op->active_next->active_prev = op->active_prev;
1173  }
1174  op->active_next = NULL;
1175  op->active_prev = NULL;
1176  }
1177 }
1178 
1195  /* If not on the active list, nothing needs to be done */
1196  if (!op->active_next && !op->active_prev && op != active_objects)
1197  return;
1198 
1199  if (op->active_prev == NULL) {
1200  active_objects = op->active_next;
1201  if (op->active_next != NULL)
1202  op->active_next->active_prev = NULL;
1203  } else {
1204  op->active_prev->active_next = op->active_next;
1205  if (op->active_next)
1206  op->active_next->active_prev = op->active_prev;
1207  }
1208  op->active_next = NULL;
1209  op->active_prev = NULL;
1210 }
1211 
1239 void object_update(object *op, int action) {
1240  int update_now = 0, flags;
1241  MoveType move_on, move_off, move_block, move_slow;
1242  object *pl;
1243 
1244  if (op == NULL) {
1245  /* this should never happen */
1246  LOG(llevDebug, "object_update() called for NULL object.\n");
1247  return;
1248  }
1249 
1250  if (op->env != NULL) {
1251  /* Animation is currently handled by client, so nothing
1252  * to do in this case.
1253  */
1254  return;
1255  }
1256 
1257  /* If the map is saving, don't do anything as everything is
1258  * going to get freed anyways.
1259  */
1260  if (!op->map || op->map->in_memory == MAP_SAVING)
1261  return;
1262 
1263  /* make sure the object is within map boundaries */
1264  if (op->x < 0 || op->x >= MAP_WIDTH(op->map)
1265  || op->y < 0 || op->y >= MAP_HEIGHT(op->map)) {
1266  LOG(llevError, "object_update() called for object out of map!\n");
1267 #ifdef MANY_CORES
1268  abort();
1269 #endif
1270  return;
1271  }
1272 
1273  flags = GET_MAP_FLAGS(op->map, op->x, op->y);
1274  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NEED_UPDATE);
1275  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
1276  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
1277  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
1278  move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y);
1279 
1280  if (action == UP_OBJ_INSERT) {
1282  update_now = 1;
1283 
1284  if (QUERY_FLAG(op, FLAG_NO_MAGIC) && !(flags&P_NO_MAGIC))
1285  update_now = 1;
1286 
1287  if (QUERY_FLAG(op, FLAG_DAMNED) && !(flags&P_NO_CLERIC))
1288  update_now = 1;
1289 
1290  if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags&P_IS_ALIVE))
1291  update_now = 1;
1292 
1293  if ((move_on|op->move_on) != move_on)
1294  update_now = 1;
1295  if ((move_off|op->move_off) != move_off)
1296  update_now = 1;
1297  /* This isn't perfect, but I don't expect a lot of objects to
1298  * to have move_allow right now.
1299  */
1300  if (((move_block|op->move_block)&~op->move_allow) != move_block)
1301  update_now = 1;
1302  if ((move_slow|op->move_slow) != move_slow)
1303  update_now = 1;
1304 
1305  if (op->type == PLAYER)
1306  update_now = 1;
1307  /* if the object is being removed, we can't make intelligent
1308  * decisions, because object_remove() can't really pass the object
1309  * that is being removed.
1310  */
1311  } else if (action == UP_OBJ_REMOVE) {
1312  update_now = 1;
1313  } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) {
1314  /* In addition to sending info to client, need to update space
1315  * information.
1316  */
1317  if (action == UP_OBJ_CHANGE)
1318  update_now = 1;
1319 
1320  /* There is a player on this space - we may need to send an
1321  * update to the client.
1322  * If this object is supposed to be animated by the client,
1323  * nothing to do here - let the client animate it.
1324  * We can't use FLAG_ANIMATE, as that is basically set for
1325  * all objects with multiple faces, regardless if they are animated.
1326  * (levers have it set for example).
1327  */
1328  if (flags&P_PLAYER
1331  pl = GET_MAP_PLAYER(op->map, op->x, op->y);
1332 
1333  /* If update_look is set, we're going to send this entire space
1334  * to the client, so no reason to send face information now.
1335  */
1336  if (!pl->contr->socket.update_look) {
1337  esrv_update_item(UPD_FACE, pl, op);
1338  }
1339  }
1340  } else {
1341  LOG(llevError, "object_update called with invalid action: %d\n", action);
1342  }
1343 
1344  if (update_now) {
1345  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NO_ERROR|P_NEED_UPDATE);
1346  update_position(op->map, op->x, op->y);
1347  }
1348 
1349  if (op->more != NULL)
1350  object_update(op->more, action);
1351 }
1352 
1368 void object_free_drop_inventory(object *ob) {
1369  object_free2(ob, 0);
1370 }
1371 
1391 void object_free2(object *ob, int flags) {
1392  if (!QUERY_FLAG(ob, FLAG_REMOVED)) {
1393  StringBuffer *sb;
1394  char *diff;
1395 
1396  LOG(llevDebug, "Free object called with non removed object\n");
1397  sb = stringbuffer_new();
1398  object_dump(ob, sb);
1399  diff = stringbuffer_finish(sb);
1400  LOG(llevError, "%s", diff);
1401  free(diff);
1402 #ifdef MANY_CORES
1403  abort();
1404 #endif
1405  }
1406  if (QUERY_FLAG(ob, FLAG_FRIENDLY)) {
1407  LOG(llevMonster, "Warning: tried to free friendly object.\n");
1409  }
1410  if (QUERY_FLAG(ob, FLAG_FREED)) {
1411  StringBuffer *sb;
1412  char *diff;
1413 
1414  sb = stringbuffer_new();
1415  object_dump(ob, sb);
1416  diff = stringbuffer_finish(sb);
1417  LOG(llevError, "Trying to free freed object.\n%s\n", diff);
1418  free(diff);
1419  return;
1420  }
1421 
1422  if ((flags & FREE_OBJ_NO_DESTROY_CALLBACK) == 0) {
1423  /* Handle for plugin destroy event */
1424  execute_event(ob, EVENT_DESTROY, NULL, NULL, NULL, SCRIPT_FIX_NOTHING);
1425  }
1426 
1427  if (ob->inv) {
1428  /* Only if the space blocks everything do we not process -
1429  * if some form of movemnt is allowed, let objects
1430  * drop on that space.
1431  */
1432  if ((flags & FREE_OBJ_FREE_INVENTORY) != 0
1433  || ob->map == NULL
1434  || ob->map->in_memory != MAP_IN_MEMORY
1435  || (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL)) {
1436  FOR_INV_PREPARE(ob, op) {
1437  object_remove(op);
1438  object_free2(op, flags);
1439  } FOR_INV_FINISH();
1440  } else { /* Put objects in inventory onto this space */
1441  FOR_INV_PREPARE(ob, op) {
1442  object_remove(op);
1443  /* No drop means no drop, including its inventory */
1444  if (QUERY_FLAG(op, FLAG_NO_DROP))
1445  object_free2(op, FREE_OBJ_FREE_INVENTORY);
1446  else if (QUERY_FLAG(op, FLAG_STARTEQUIP)
1447  || QUERY_FLAG(op, FLAG_NO_DROP)
1448  || op->type == RUNE
1449  || op->type == TRAP
1452  else {
1453  object *part;
1454 
1455  /* If it's a multi-tile object, scatter dropped items randomly */
1456  if (ob->more) {
1457  int partcount = 0;
1458  /* Get the number of non-head parts */
1459  for (part = ob; part; part = part->more) {
1460  partcount++;
1461  }
1462  /* Select a random part */
1463  partcount = RANDOM()%partcount;
1464  for (part = ob; partcount > 0; partcount--) {
1465  part = part->more;
1466  }
1467  } else {
1468  part = ob;
1469  }
1470 
1471  if (QUERY_FLAG(op, FLAG_ALIVE)) {
1472  object_insert_to_free_spot_or_free(op, part->map, part->x, part->y, 0, SIZEOFFREE, NULL);
1473  } else {
1474  int f = 0;
1475  if (flags & FREE_OBJ_DROP_ABOVE_FLOOR)
1477  object_insert_in_map_at(op, part->map, NULL, f, part->x, part->y); /* Insert in same map as the envir */
1478  }
1479  }
1480  } FOR_INV_FINISH();
1481  }
1482  }
1483 
1484  if (ob->more != NULL) {
1485  object_free2(ob->more, flags);
1486  ob->more = NULL;
1487  }
1488 
1489  /* Remove object from the active list */
1490  ob->speed = 0;
1491  object_update_speed(ob);
1492 
1493  SET_FLAG(ob, FLAG_FREED);
1494  ob->count = 0;
1495 
1496  /* Remove this object from the list of used objects */
1497  if (ob->prev == NULL) {
1498  objects = ob->next;
1499  if (objects != NULL)
1500  objects->prev = NULL;
1501  } else {
1502  ob->prev->next = ob->next;
1503  if (ob->next != NULL)
1504  ob->next->prev = ob->prev;
1505  }
1506 
1507  if (ob->artifact != NULL) FREE_AND_CLEAR_STR(ob->artifact);
1508  if (ob->name != NULL) FREE_AND_CLEAR_STR(ob->name);
1509  if (ob->name_pl != NULL) FREE_AND_CLEAR_STR(ob->name_pl);
1510  if (ob->title != NULL) FREE_AND_CLEAR_STR(ob->title);
1511  if (ob->race != NULL) FREE_AND_CLEAR_STR(ob->race);
1512  if (ob->slaying != NULL) FREE_AND_CLEAR_STR(ob->slaying);
1513  if (ob->skill != NULL) FREE_AND_CLEAR_STR(ob->skill);
1514  if (ob->lore != NULL) FREE_AND_CLEAR_STR(ob->lore);
1515  if (ob->msg != NULL) FREE_AND_CLEAR_STR(ob->msg);
1516  if (ob->materialname != NULL) FREE_AND_CLEAR_STR(ob->materialname);
1517  if (ob->discrete_damage != NULL) FREE_AND_CLEAR(ob->discrete_damage);
1518  if (ob->spell_tags) FREE_AND_CLEAR(ob->spell_tags);
1519 
1520  /* Why aren't events freed? */
1522 
1524 
1525  /* Test whether archetype is a temporary one, and if so look whether it should be trashed. */
1526  if (ob->arch && ob->arch->reference_count > 0) {
1527  if (--ob->arch->reference_count == 0) {
1528  free_arch(ob->arch);
1529  }
1530  }
1531 
1532 #if defined(MEMORY_DEBUG) && (MEMORY_DEBUG > 2)
1533  /* memset() to clear it then set flags and finally free it. This will
1534  * help detect bad use after return.
1535  */
1536  memset(ob, 0, sizeof(object));
1537  SET_FLAG(ob, FLAG_REMOVED);
1538  SET_FLAG(ob, FLAG_FREED);
1539  free(ob);
1540 #else
1541  /* Now link it with the free_objects list: */
1542  ob->prev = NULL;
1543  ob->next = free_objects;
1544  if (free_objects != NULL)
1545  free_objects->prev = ob;
1546  free_objects = ob;
1547  nroffreeobjects++;
1548 #endif
1549 }
1550 
1561  int i = 0;
1562  object *tmp = free_objects;
1563 
1564  while (tmp != NULL)
1565  tmp = tmp->next,
1566  i++;
1567  return i;
1568 }
1569 
1580  int i = 0;
1581  object *tmp = objects;
1582 
1583  while (tmp != NULL)
1584  tmp = tmp->next,
1585  i++;
1586  return i;
1587 }
1588 
1599  int i = 0;
1600  object *tmp = active_objects;
1601 
1602  while (tmp != NULL)
1603  tmp = tmp->active_next,
1604  i++;
1605  return i;
1606 }
1607 
1625 void object_sub_weight(object *op, signed long weight) {
1626  while (op != NULL) {
1627  if (op->type == CONTAINER) {
1628  weight = (signed long)(weight*(100-op->stats.Str)/100);
1629  }
1630  op->carrying -= weight;
1631  op = op->env;
1632  }
1633 }
1634 
1654 void object_remove(object *op) {
1655  object *last = NULL;
1656  object *otmp;
1657  tag_t tag;
1658  int check_walk_off;
1659  mapstruct *m;
1660  int16_t x, y;
1661 
1662  if (QUERY_FLAG(op, FLAG_REMOVED)) {
1663  StringBuffer *sb;
1664  char *diff;
1665 
1666  sb = stringbuffer_new();
1667  object_dump(op, sb);
1668  diff = stringbuffer_finish(sb);
1669  LOG(llevError, "Trying to remove removed object.\n%s\n", diff);
1670  free(diff);
1671  abort();
1672  }
1673  if (op->more != NULL)
1674  object_remove(op->more);
1675 
1676  SET_FLAG(op, FLAG_REMOVED);
1677 
1678  /*
1679  * In this case, the object to be removed is in someones
1680  * inventory.
1681  */
1682  /* TODO try to call a generic inventory weight adjusting function like object_sub_weight */
1683  if (op->env != NULL) {
1684  player *pl = NULL;
1685 
1686  if (op->nrof)
1687  object_sub_weight(op->env, op->weight*op->nrof);
1688  else
1689  object_sub_weight(op->env, op->weight+op->carrying);
1690 
1691  /* Update in two cases: item is in a player, or in a container the player is looking into. */
1692  if (op->env->contr != NULL && op->head == NULL) {
1693  pl = op->env->contr;
1694  } else if (op->env->type == CONTAINER && QUERY_FLAG(op->env, FLAG_APPLIED)) {
1695 
1696  if (op->env->env && op->env->env->contr)
1697  /* Container is in player's inventory. */
1698  pl = op->env->env->contr;
1699  else if (op->env->map) {
1700  /* Container on map, look above for player. */
1701  object *above = op->env->above;
1702 
1703  while (above && !above->contr)
1704  above = above->above;
1705  if (above)
1706  pl = above->contr;
1707  }
1708  }
1709 
1710  /* NO_FIX_PLAYER is set when a great many changes are being
1711  * made to players inventory. If set, avoiding the call
1712  * to save cpu time.
1713  */
1714  otmp = object_get_player_container(op->env);
1715  if (otmp != NULL
1716  && otmp->contr
1717  && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
1718  fix_object(otmp);
1719 
1720  if (op->above != NULL)
1721  op->above->below = op->below;
1722  else
1723  op->env->inv = op->below;
1724 
1725  if (op->below != NULL)
1726  op->below->above = op->above;
1727 
1728  /* we set up values so that it could be inserted into
1729  * the map, but we don't actually do that - it is up
1730  * to the caller to decide what we want to do.
1731  */
1732  op->x = op->env->x;
1733  op->y = op->env->y;
1734  op->ox = op->x;
1735  op->oy = op->y;
1736  op->map = op->env->map;
1737  op->above = NULL;
1738  op->below = NULL;
1739  /* send the delitem before resetting env, so container's contents be may
1740  * refreshed */
1741  if (LOOK_OBJ(op) && pl != NULL)
1742  esrv_del_item(pl, op);
1743  op->env = NULL;
1744  return;
1745  }
1746 
1747  /* If we get here, we are removing it from a map */
1748  if (op->map == NULL)
1749  return;
1750 
1751  if (op->contr != NULL && !op->contr->hidden)
1752  op->map->players--;
1753 
1754  x = op->x;
1755  y = op->y;
1756  m = get_map_from_coord(op->map, &x, &y);
1757 
1758  if (!m) {
1759  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);
1760  abort();
1761  }
1762  if (op->map != m) {
1763  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);
1764  }
1765 
1766  /* link the object above us */
1767  if (op->above)
1768  op->above->below = op->below;
1769  else
1770  SET_MAP_TOP(m, x, y, op->below); /* we were top, set new top */
1771 
1772  /* Relink the object below us, if there is one */
1773  if (op->below) {
1774  op->below->above = op->above;
1775  } else {
1776  /* Nothing below, which means we need to relink map object for this space
1777  * use translated coordinates in case some oddness with map tiling is
1778  * evident
1779  */
1780  /*TODO is this check really needed?*/
1781  if (GET_MAP_OB(m, x, y) != op) {
1782  StringBuffer *sb;
1783  char *diff;
1784 
1785  sb = stringbuffer_new();
1786  object_dump(op, sb);
1787  diff = stringbuffer_finish(sb);
1788  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);
1789  free(diff);
1790 
1791  sb = stringbuffer_new();
1792  object_dump(GET_MAP_OB(m, x, y), sb);
1793  diff = stringbuffer_finish(sb);
1794  LOG(llevError, "%s\n", diff);
1795  free(diff);
1796  }
1797  SET_MAP_OB(m, x, y, op->above); /* goes on above it. */
1798  }
1799  op->above = NULL;
1800  op->below = NULL;
1801 
1802  if (op->map->in_memory == MAP_SAVING)
1803  return;
1804 
1805  tag = op->count;
1806  check_walk_off = !QUERY_FLAG(op, FLAG_NO_APPLY);
1807  FOR_MAP_PREPARE(m, x, y, tmp) {
1808  /* No point updating the players look faces if he is the object
1809  * being removed.
1810  */
1811 
1812  if (tmp->type == PLAYER && tmp != op) {
1813  /* If a container that the player is currently using somehow gets
1814  * removed (most likely destroyed), update the player view
1815  * appropriately.
1816  */
1817  if (tmp->container == op) {
1818  CLEAR_FLAG(op, FLAG_APPLIED);
1819  tmp->container = NULL;
1820  }
1821  tmp->contr->socket.update_look = 1;
1822  }
1823  /* See if player moving off should effect something */
1824  if (check_walk_off
1825  && ((op->move_type&tmp->move_off) && (op->move_type&~tmp->move_off&~tmp->move_block) == 0)) {
1826  ob_move_on(tmp, op, NULL);
1827  if (object_was_destroyed(op, tag)) {
1828  LOG(llevError, "BUG: object_remove(): name %s, archname %s destroyed leaving object\n", tmp->name, tmp->arch->name);
1829  }
1830  }
1831 
1832  /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
1833  if (tmp->above == tmp)
1834  tmp->above = NULL;
1835  last = tmp;
1836  } FOR_MAP_FINISH();
1837  /* last == NULL or there are no objects on this space */
1838  if (last == NULL) {
1839  /* set P_NEED_UPDATE, otherwise update_position will complain. In theory,
1840  * we could preserve the flags (GET_MAP_FLAGS), but update_position figures
1841  * those out anyways, and if there are any flags set right now, they won't
1842  * be correct anyways.
1843  */
1844  SET_MAP_FLAGS(op->map, op->x, op->y, P_NEED_UPDATE);
1845  update_position(op->map, op->x, op->y);
1846  } else
1848 
1849  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) || (op->glow_radius != 0))
1850  update_all_los(op->map, op->x, op->y);
1851 }
1852 
1869 object *object_merge(object *op, object *top) {
1870  if (!op->nrof)
1871  return NULL;
1872 
1873  if (top == NULL)
1874  for (top = op; top != NULL && top->above != NULL; top = top->above)
1875  ;
1877  if (top == op)
1878  continue;
1879  if (object_can_merge(op, top)) {
1880  object_increase_nrof(top, op->nrof);
1881  /*
1882  * Previous behavior set weight to zero here.
1883  * This, however, caused the object_sub_weight
1884  * call in object_remove to subtract zero weight
1885  * when removing the object. Thus, until inventory
1886  * weight is next recalculated, the object merged
1887  * into another pile added weight in object_increase_nrof
1888  * but did not remove the weight from the original
1889  * instance of itself in object_remove, essentially
1890  * counting for double weight for several minutes.
1891  *
1892  * SilverNexus 2014-05-27
1893  */
1894  object_remove(op);
1896  return top;
1897  }
1899  return NULL;
1900 }
1901 
1921 object *object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y) {
1922  object *tmp;
1923 
1924  op = HEAD(op);
1925  for (tmp = op; tmp; tmp = tmp->more) {
1926  tmp->x = x+tmp->arch->clone.x;
1927  tmp->y = y+tmp->arch->clone.y;
1928  tmp->map = m;
1929  }
1930  return object_insert_in_map(op, m, originator, flag);
1931 }
1932 
1953 void object_merge_spell(object *op, int16_t x, int16_t y) {
1954  int i;
1955 
1956  /* We try to do some merging of spell objects - if something has same owner,
1957  * is same type of spell, and going in the same direction, it is somewhat
1958  * mergable.
1959  *
1960  * If the spell object has an other_arch, don't merge - when the spell
1961  * does something, like explodes, it will use this other_arch, and
1962  * if we merge, there is no easy way to make the correct values be
1963  * set on this new object (values should be doubled, tripled, etc.)
1964  *
1965  * We also care about speed - only process objects that will not be
1966  * active this tick. Without this, the results are incorrect - think
1967  * of a case where tmp would normally get processed this tick, but
1968  * get merges with op, which does not get processed.
1969  */
1970  FOR_MAP_PREPARE(op->map, x, y, tmp) {
1971  if (op->type == tmp->type
1972  && op->subtype == tmp->subtype
1973  && op->direction == tmp->direction
1974  && op->owner == tmp->owner && op->ownercount == tmp->ownercount
1975  && op->range == tmp->range
1976  && op->stats.wc == tmp->stats.wc
1977  && op->level == tmp->level
1978  && op->attacktype == tmp->attacktype
1979  && op->speed == tmp->speed
1980  && !tmp->other_arch
1981  && (tmp->speed_left+tmp->speed) < 0.0
1982  && op != tmp) {
1983  /* Quick test - if one or the other objects already have hash tables
1984  * set up, and that hash bucket contains a value that doesn't
1985  * match what we want to set it up, we won't be able to merge.
1986  * Note that these two if statements are the same, except
1987  * for which object they are checking against. They could
1988  * be merged, but the line wrapping would be large enough
1989  * that IMO it would become difficult to read the different clauses
1990  * so its cleaner just to do 2 statements - MSW
1991  */
1992  if (op->spell_tags
1993  && !OB_SPELL_TAG_MATCH(op, (tag_t)tmp->stats.maxhp)
1994  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0)
1995  continue;
1996 
1997  if (tmp->spell_tags
1998  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)op->stats.maxhp)
1999  && OB_SPELL_TAG_HASH(tmp, op->stats.maxhp) != 0)
2000  continue;
2001 
2002  /* If we merge, the data from tmp->spell_tags gets copied into op.
2003  * so we need to make sure that slot isn't filled up.
2004  */
2005  if (tmp->spell_tags
2006  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)tmp->stats.maxhp)
2007  && OB_SPELL_TAG_HASH(tmp, tmp->stats.maxhp) != 0)
2008  continue;
2009 
2010  /* If both objects have spell_tags, we need to see if there are conflicting
2011  * values - if there are, we won't be able to merge then.
2012  */
2013  if (tmp->spell_tags && op->spell_tags) {
2014  int need_copy = 0;
2015 
2016  for (i = 0; i < SPELL_TAG_SIZE; i++) {
2017  /* If the two tag values in the hash are set, but are
2018  * not set to the same value, then these objects
2019  * can not be merged.
2020  */
2021  if (op->spell_tags[i] && tmp->spell_tags[i]
2022  && op->spell_tags[i] != tmp->spell_tags[i]) {
2024  break;
2025  }
2026  /* If one tag is set and the other is not, that is
2027  * fine, but we have to note that we need to copy
2028  * the data in that case.
2029  */
2030  if ((!op->spell_tags[i] && tmp->spell_tags[i])
2031  || (op->spell_tags[i] && !tmp->spell_tags[i])) {
2032  need_copy = 1;
2033  }
2034  }
2035  /* If we did not get through entire array, it means
2036  * we got a conflicting hash, and so we won't be
2037  * able to merge these - just continue processing
2038  * object on this space.
2039  */
2040  if (i <= SPELL_TAG_SIZE)
2041  continue;
2042 
2043  /* Ok - everything checked out - we should be able to
2044  * merge tmp in op. So lets copy the tag data if
2045  * needed. Note that this is a selective copy, as
2046  * we don't want to clear values that may be set in op.
2047  */
2048  if (need_copy) {
2049  for (i = 0; i < SPELL_TAG_SIZE; i++)
2050  if (!op->spell_tags[i]
2051  && tmp->spell_tags[i]
2052  && tmp->spell_tags[i] != (tag_t)op->stats.maxhp)
2053  op->spell_tags[i] = tmp->spell_tags[i];
2054  }
2055  FREE_AND_CLEAR(tmp->spell_tags);
2056  }
2057 
2058  /* if tmp has a spell_tags table, copy it to op and free tmps */
2059  if (tmp->spell_tags && !op->spell_tags) {
2060  op->spell_tags = tmp->spell_tags;
2061  tmp->spell_tags = NULL;
2062 
2063  /* We don't need to keep a copy of our maxhp value
2064  * in the copied over value
2065  */
2066  if (OB_SPELL_TAG_MATCH(op, (tag_t)op->stats.maxhp))
2067  OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0;
2068  }
2069 
2070  /* For spells to work correctly, we need to record what spell
2071  * tags we've merged in with this effect. This is used
2072  * in ok_to_put_more() to see if a spell effect is already on
2073  * the space.
2074  */
2075  if (op->stats.maxhp != tmp->stats.maxhp) {
2076 #ifdef OBJECT_DEBUG
2077  /* This if statement should never happen - the logic above should
2078  * have prevented it. It is a problem, because by now its possible
2079  * we've destroyed the spell_tags in tmp, so we can't really
2080  * just bail out.
2081  */
2082 
2083  if (op->spell_tags
2084  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0
2085  && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)) {
2086  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);
2087  }
2088 #endif
2089  if (!op->spell_tags)
2090  op->spell_tags = calloc(SPELL_TAG_SIZE, sizeof(tag_t));
2091 
2092  OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) = tmp->stats.maxhp;
2093  }
2094 
2096  op->speed_left = MAX(op->speed_left, tmp->speed_left);
2097 
2098  if (tmp->duration != op->duration) {
2099  /* We need to use tmp_dam here because otherwise the
2100  * calculations can overflow the size of stats.dam.
2101  */
2102  int tmp_dam = tmp->stats.dam*(tmp->duration+1)+
2103  op->stats.dam*(op->duration+1);
2104 
2105  op->duration = MAX(op->duration, tmp->duration);
2106  tmp_dam /= op->duration+1;
2107  op->stats.dam = tmp_dam+1;
2108  } else {
2109  /* in this case, duration is the same, so simply adding
2110  * up damage works.
2111  */
2112  op->stats.dam += tmp->stats.dam;
2113  }
2114 
2115  object_remove(tmp);
2117  }
2118  } FOR_MAP_FINISH();
2119 }
2120 
2152 object *object_insert_in_map(object *op, mapstruct *m, object *originator, int flag) {
2153  object *tmp, *top, *floor = NULL;
2154  int16_t x, y;
2155 
2156  if (QUERY_FLAG(op, FLAG_FREED)) {
2157  LOG(llevError, "Trying to insert freed object!\n");
2158  return NULL;
2159  }
2160  if (m == NULL) {
2161  StringBuffer *sb;
2162  char *diff;
2163 
2164  sb = stringbuffer_new();
2165  object_dump(op, sb);
2166  diff = stringbuffer_finish(sb);
2167  LOG(llevError, "Trying to insert in null-map!\n%s\n", diff);
2168  free(diff);
2169  return op;
2170  }
2171  if (out_of_map(m, op->x, op->y)) {
2172  StringBuffer *sb;
2173  char *diff;
2174 
2175  sb = stringbuffer_new();
2176  object_dump(op, sb);
2177  diff = stringbuffer_finish(sb);
2178  LOG(llevError, "Trying to insert object outside the map.\n%s\n", diff);
2179  free(diff);
2180 #ifdef MANY_CORES
2181  /* Better to catch this here, as otherwise the next use of this object
2182  * is likely to cause a crash. Better to find out where it is getting
2183  * improperly inserted.
2184  */
2185  abort();
2186 #endif
2187  return op;
2188  }
2189  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2190  StringBuffer *sb;
2191  char *diff;
2192 
2193  sb = stringbuffer_new();
2194  object_dump(op, sb);
2195  diff = stringbuffer_finish(sb);
2196  LOG(llevError, "Trying to insert (map) inserted object.\n%s\n", diff);
2197  free(diff);
2198  return op;
2199  }
2200  if (op->more != NULL) {
2201  /* The part may be on a different map. */
2202 
2203  object *more = op->more;
2204 
2205  /* We really need the caller to normalize coordinates - if
2206  * we set the map, that doesn't work if the location is within
2207  * a map and this is straddling an edge. So only if coordinate
2208  * is clear wrong do we normalize it.
2209  */
2210  if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
2211  /* Debugging information so you can see the last coordinates this object had */
2212  more->ox = more->x;
2213  more->oy = more->y;
2214  more->map = get_map_from_coord(more->map, &more->x, &more->y);
2215  } else if (!more->map) {
2216  /* For backwards compatibility - when not dealing with tiled maps,
2217  * more->map should always point to the parent.
2218  */
2219  more->map = m;
2220  }
2221 
2222  if (object_insert_in_map(more, more->map, originator, flag) == NULL) {
2223  if (!op->head)
2224  LOG(llevError, "BUG: object_insert_in_map(): inserting op->more killed op\n");
2225  return NULL;
2226  }
2227  }
2228  CLEAR_FLAG(op, FLAG_REMOVED);
2229 
2230  /* Debugging information so you can see the last coordinates this object had */
2231  op->ox = op->x;
2232  op->oy = op->y;
2233  x = op->x;
2234  y = op->y;
2235  op->map = get_map_from_coord(m, &x, &y);
2236 
2237  /* this has to be done after we translate the coordinates. */
2238  if (op->nrof
2239  && !(flag&INS_NO_MERGE)
2240  && op->type != SPELL_EFFECT) {
2241  FOR_MAP_PREPARE(op->map, x, y, tmp) {
2242  if (object_can_merge(op, tmp)) {
2243  op->nrof += tmp->nrof;
2244  object_remove(tmp);
2246  }
2247  } FOR_MAP_FINISH();
2248  } else if (op->type == SPELL_EFFECT
2249  && !op->range
2250  && !op->other_arch
2251  && (op->speed_left+op->speed) < 0.0) {
2252  object_merge_spell(op, x, y);
2253  }
2254 
2255  /* Ideally, the caller figures this out. However, it complicates a lot
2256  * of areas of callers (eg, anything that uses object_find_free_spot() would now
2257  * need extra work
2258  */
2259  if (op->map != m) {
2260  /* coordinates should not change unless map also changes */
2261  op->x = x;
2262  op->y = y;
2263  }
2264 
2265  if (op->type != LAMP)
2266  /* lamps use the FLAG_APPLIED to keep the light/unlit status, so don't reset it.
2267  Other objects just get unapplied, since the container "drops" them. */
2268  CLEAR_FLAG(op, FLAG_APPLIED);
2270  if (!QUERY_FLAG(op, FLAG_ALIVE))
2272 
2273  /* In many places, a player is passed as the originator, which
2274  * is fine. However, if the player is on a transport, they are not
2275  * actually on the map, so we can't use them for the linked pointers,
2276  * nor should the walk on function below use them either.
2277  */
2278  if (originator && originator->contr && originator->contr->transport)
2279  originator = originator->contr->transport;
2280 
2281  if (flag&INS_BELOW_ORIGINATOR) {
2282  if (originator->map != op->map
2283  || originator->x != op->x
2284  || originator->y != op->y) {
2285  LOG(llevError, "object_insert_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
2286  abort();
2287  }
2288  op->above = originator;
2289  op->below = originator->below;
2290  if (op->below)
2291  op->below->above = op;
2292  else
2293  SET_MAP_OB(op->map, op->x, op->y, op);
2294  /* since *below *originator, no need to update top */
2295  originator->below = op;
2296  } else {
2297  /* If there are other objects, then */
2298  /* This test is incorrect i think, as ins_above_floor_only needs the floor variable
2299  if ((!(flag&INS_MAP_LOAD)) && ((top = GET_MAP_OB(op->map, op->x, op->y)) != NULL)) {
2300  */
2301  object *last;
2302 
2303  /*
2304  * If there are multiple objects on this space, we do some trickier handling.
2305  * We've already dealt with merging if appropriate.
2306  * Generally, we want to put the new object on top. But if
2307  * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
2308  * floor, we want to insert above that and no further.
2309  * Also, if there are spell objects on this space, we stop processing
2310  * once we get to them. This reduces the need to traverse over all of
2311  * them when adding another one - this saves quite a bit of cpu time
2312  * when lots of spells are cast in one area. Currently, it is presumed
2313  * that flying non pickable objects are spell objects.
2314  */
2315  last = NULL;
2316  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2317  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)
2318  || QUERY_FLAG(tmp, FLAG_OVERLAY_FLOOR))
2319  floor = tmp;
2320 
2321  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
2323  && !QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2324  /* We insert above tmp, so we want this object below this */
2325  break;
2326  }
2327  last = tmp;
2328  } FOR_MAP_FINISH();
2329  top = last;
2330 
2331  if (flag&INS_MAP_LOAD)
2332  top = GET_MAP_TOP(op->map, op->x, op->y);
2333  if (flag&INS_ABOVE_FLOOR_ONLY)
2334  top = floor;
2335 
2336  /* Top is the object that our object (op) is going to get inserted above. */
2337 
2338  /* First object on this space */
2339  if (!top) {
2340  op->above = GET_MAP_OB(op->map, op->x, op->y);
2341  if (op->above)
2342  op->above->below = op;
2343  op->below = NULL;
2344  SET_MAP_OB(op->map, op->x, op->y, op);
2345  } else { /* get inserted into the stack above top */
2346  op->above = top->above;
2347  if (op->above)
2348  op->above->below = op;
2349  op->below = top;
2350  top->above = op;
2351  }
2352  if (op->above == NULL)
2353  SET_MAP_TOP(op->map, op->x, op->y, op);
2354  } /* else not INS_BELOW_ORIGINATOR */
2355 
2356  if (op->type == PLAYER)
2357  op->contr->do_los = 1;
2358 
2359  /* If we have a floor, we know the player, if any, will be above
2360  * it, so save a few ticks and start from there.
2361  */
2362  if (!(flag&INS_MAP_LOAD)) {
2363  tmp = floor ? floor : GET_MAP_OB(op->map, op->x, op->y);
2365  if (tmp->type == PLAYER)
2366  tmp->contr->socket.update_look = 1;
2368  }
2369 
2370  /* If this object glows, it may affect lighting conditions that are
2371  * visible to others on this map. But update_all_los is really
2372  * an inefficient way to do this, as it means los for all players
2373  * on the map will get recalculated. The players could very well
2374  * be far away from this change and not affected in any way -
2375  * this should get redone to only look for players within range,
2376  * or just updating the P_NEED_UPDATE for spaces within this area
2377  * of effect may be sufficient.
2378  */
2379  if (MAP_DARKNESS(op->map) && (op->glow_radius != 0))
2380  update_all_los(op->map, op->x, op->y);
2381 
2382  /* updates flags (blocked, alive, no magic, etc) for this map space */
2384 
2385  if (op->contr && !op->contr->hidden)
2386  op->map->players++;
2387 
2388  /* Don't know if moving this to the end will break anything. However,
2389  * we want to have update_look set above before calling this.
2390  *
2391  * object_check_move_on() must be after this because code called from
2392  * object_check_move_on() depends on correct map flags (so functions like
2393  * blocked() and wall() work properly), and these flags are updated by
2394  * object_update().
2395  */
2396 
2397  /* if this is not the head or flag has been passed, don't check walk on status */
2398 
2399  if (!(flag&INS_NO_WALK_ON) && !op->head) {
2400  if (object_check_move_on(op, originator))
2401  return NULL;
2402 
2403  /* If we are a multi part object, lets work our way through the check
2404  * walk on's.
2405  */
2406  for (tmp = op->more; tmp != NULL; tmp = tmp->more)
2407  if (object_check_move_on(tmp, originator))
2408  return NULL;
2409  }
2410  return op;
2411 }
2412 
2425 void object_replace_insert_in_map(const char *arch_string, object *op) {
2426  object *tmp1;
2427 
2428  /* first search for itself and remove any old instances */
2429  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2430  if (!strcmp(tmp->arch->name, arch_string)) { /* same archetype */
2431  object_remove(tmp);
2433  }
2434  } FOR_MAP_FINISH();
2435 
2436  tmp1 = arch_to_object(find_archetype(arch_string));
2437  object_insert_in_map_at(tmp1, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
2438 }
2439 
2463 object *object_split(object *orig_ob, uint32_t nr, char *err, size_t size) {
2464  object *newob;
2465 
2466  if (MAX(1, orig_ob->nrof) < nr) {
2467  /* If err is set, the caller knows that nr can be wrong (player trying to drop items), thus don't log that. */
2468  if (err)
2469  snprintf(err, size, "There are only %u %ss.", orig_ob->nrof ? orig_ob->nrof : 1, orig_ob->name);
2470  else
2471  LOG(llevDebug, "There are only %u %ss.\n", orig_ob->nrof ? orig_ob->nrof : 1, orig_ob->name);
2472  return NULL;
2473  }
2474  newob = object_create_clone(orig_ob);
2475  if (orig_ob->nrof == 0) {
2476  if (!QUERY_FLAG(orig_ob, FLAG_REMOVED)) {
2477  object_remove(orig_ob);
2478  }
2480  } else {
2481  newob->nrof = nr;
2482  object_decrease_nrof(orig_ob, nr);
2483  }
2484 
2485  return newob;
2486 }
2487 
2505 object *object_decrease_nrof(object *op, uint32_t i) {
2506  object *tmp;
2507 
2508  if (i == 0) /* objects with op->nrof require this check */
2509  return op;
2510 
2511  if (i > op->nrof)
2512  i = op->nrof;
2513 
2514  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2515  op->nrof -= i;
2516  } else if (op->env != NULL) {
2517  if (i < op->nrof) {
2518  player *pl;
2519  /* is this object in the players inventory, or sub container
2520  * therein?
2521  */
2522  tmp = object_get_player_container(op->env);
2523  /* nope. Is this a container the player has opened?
2524  * If so, set tmp to that player.
2525  * IMO, searching through all the players will mostly
2526  * likely be quicker than following op->env to the map,
2527  * and then searching the map for a player.
2528  */
2529  if (!tmp) {
2530  for (pl = first_player; pl; pl = pl->next)
2531  if (pl->ob->container == op->env)
2532  break;
2533  if (pl)
2534  tmp = pl->ob;
2535  else
2536  tmp = NULL;
2537  }
2538 
2539  /* Because of weight reduction by container and integer arithmetic,
2540  * there is no guarantee the rounded weight of combined items will be
2541  * the same as the sum of rounded weights.
2542  * Therefore just remove the current weight, and add the new.
2543  * Same adjustment done in object_increase_nrof().
2544  */
2545  object_sub_weight(op->env, op->weight * op->nrof);
2546  op->nrof -= i;
2547  object_add_weight(op->env, op->weight * op->nrof);
2548  if (tmp) {
2549  esrv_update_item(UPD_NROF, tmp, op);
2550  fix_object(tmp);
2551  }
2552  } else {
2553  object_remove(op);
2554  op->nrof = 0;
2555  }
2556  } else {
2557  /* On a map. */
2558  if (i < op->nrof) {
2559  op->nrof -= i;
2560 
2561  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2562  if (pl->contr) {
2563  pl->contr->socket.update_look = 1;
2564  break;
2565  }
2566  FOR_MAP_FINISH();
2567  } else {
2568  object_remove(op);
2569  op->nrof = 0;
2570  }
2571  }
2572 
2573  if (op->nrof) {
2574  return op;
2575  } else {
2577  return NULL;
2578  }
2579 }
2580 
2591 static void object_increase_nrof(object *op, uint32_t i) {
2592  object *tmp;
2593 
2594  if (i == 0) /* objects with op->nrof require this check */
2595  return;
2596 
2597  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2598  op->nrof += i;
2599  } else if (op->env != NULL) {
2600  player *pl;
2601  /* is this object in the players inventory, or sub container
2602  * therein?
2603  */
2604  tmp = object_get_player_container(op->env);
2605  /* nope. Is this a container the player has opened?
2606  * If so, set tmp to that player.
2607  * IMO, searching through all the players will mostly
2608  * likely be quicker than following op->env to the map,
2609  * and then searching the map for a player.
2610  */
2611  if (!tmp) {
2612  for (pl = first_player; pl; pl = pl->next)
2613  if (pl->ob->container == op->env)
2614  break;
2615  if (pl)
2616  tmp = pl->ob;
2617  else
2618  tmp = NULL;
2619  }
2620 
2621  /* Because of weight reduction by container and integer arithmetic,
2622  * there is no guarantee the rounded weight of combined items will be
2623  * the same as the sum of rounded weights.
2624  * Therefore just remove the current weight, and add the new.
2625  * Same adjustment done in object_decrease_nrof().
2626  */
2627  object_sub_weight(op->env, op->weight * op->nrof);
2628  op->nrof += i;
2629  object_add_weight(op->env, op->weight * op->nrof);
2630  if (tmp) {
2631  esrv_update_item(UPD_NROF, tmp, op);
2632  }
2633  } else {
2634  /* On a map. */
2635  op->nrof += i;
2636 
2637  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2638  if (pl->contr) {
2639  pl->contr->socket.update_look = 1;
2640  break;
2641  }
2642  FOR_MAP_FINISH();
2643  }
2644 }
2645 
2663 void object_add_weight(object *op, signed long weight) {
2664  while (op != NULL) {
2665  if (op->type == CONTAINER) {
2666  weight = (signed long)(weight*(100-op->stats.Str)/100);
2667  }
2668  op->carrying += weight;
2669  op = op->env;
2670  }
2671 }
2672 
2690 object *object_insert_in_ob(object *op, object *where) {
2691  object *otmp;
2692 
2693  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2694  StringBuffer *sb;
2695  char *diff;
2696 
2697  sb = stringbuffer_new();
2698  object_dump(op, sb);
2699  diff = stringbuffer_finish(sb);
2700  LOG(llevError, "Trying to insert (ob) inserted object.\n%s\n", diff);
2701  free(diff);
2702  return op;
2703  }
2704 
2705  if (where == NULL) {
2706  StringBuffer *sb;
2707  char *diff;
2708 
2709  sb = stringbuffer_new();
2710  object_dump(op, sb);
2711  diff = stringbuffer_finish(sb);
2712  LOG(llevError, "Trying to put object in NULL.\n%s\n", diff);
2713  free(diff);
2714  return op;
2715  }
2716  if (where->head) {
2717  LOG(llevDebug, "Warning: Tried to insert object wrong part of multipart object.\n");
2718  }
2719  where = HEAD(where);
2720  if (op->more) {
2721  LOG(llevError, "Tried to insert multipart object %s (%u)\n", op->name, op->count);
2722  return op;
2723  }
2725  CLEAR_FLAG(op, FLAG_REMOVED);
2726  if (op->nrof) {
2727  FOR_INV_PREPARE(where, tmp)
2728  if (object_can_merge(tmp, op)) {
2729  /* return the original object and remove inserted object
2730  * (client needs the original object) */
2731  object_increase_nrof(tmp, op->nrof);
2732  SET_FLAG(op, FLAG_REMOVED);
2733  object_free2(op, FREE_OBJ_FREE_INVENTORY | FREE_OBJ_NO_DESTROY_CALLBACK); /* free the inserted object */
2734  return tmp;
2735  }
2736  FOR_INV_FINISH();
2737 
2738  /* the item couldn't merge. */
2739  object_add_weight(where, op->weight*op->nrof);
2740  } else
2741  object_add_weight(where, op->weight+op->carrying);
2742 
2743  op->map = NULL;
2744  op->env = where;
2745  op->above = NULL;
2746  op->below = NULL;
2747  op->x = 0,
2748  op->y = 0;
2749  op->ox = 0,
2750  op->oy = 0;
2751 
2752  /* Client has no idea of ordering so lets not bother ordering it here.
2753  * It sure simplifies this function...
2754  */
2755  if (where->inv == NULL)
2756  where->inv = op;
2757  else {
2758  op->below = where->inv;
2759  op->below->above = op;
2760  where->inv = op;
2761  }
2762 
2763  /* Update in 2 cases: object goes into player's inventory, or object goes into container the player
2764  * is looking into. */
2765  if (where->contr != NULL)
2766  esrv_send_item(where, op);
2767  else if (where->type == CONTAINER && QUERY_FLAG(where, FLAG_APPLIED)) {
2768  object *pl = NULL;
2769 
2770  if (op->env->env && op->env->env->contr)
2771  /* Container is in player's inventory. */
2772  pl = op->env->env;
2773  else if (op->env->map) {
2774  /* Container on map, look above for player. */
2775  FOR_ABOVE_PREPARE(op->env, above)
2776  if (above->contr) {
2777  pl = above;
2778  break;
2779  }
2780  FOR_ABOVE_FINISH();
2781  }
2782  if (pl)
2783  esrv_send_item(pl, op);
2784  }
2785 
2786  otmp = object_get_player_container(where);
2787  if (otmp && otmp->contr != NULL) {
2788  if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER)
2789  && (QUERY_FLAG(op, FLAG_APPLIED) || op->type == SKILL || op->glow_radius != 0))
2790  /* fix_object will only consider applied items, or skills, or items with a glow radius.
2791  thus no need to call it if our object hasn't that. */
2792  fix_object(otmp);
2793  }
2794 
2795  /* reset the light list and los of the players on the map */
2796  if (op->glow_radius != 0 && where->map) {
2797 #ifdef DEBUG_LIGHTS
2798  LOG(llevDebug, " object_insert_in_ob(): got %s to insert in map/op\n", op->name);
2799 #endif /* DEBUG_LIGHTS */
2800  if (MAP_DARKNESS(where->map)) {
2801  SET_MAP_FLAGS(where->map, where->x, where->y, P_NEED_UPDATE);
2802  update_position(where->map, where->x, where->y);
2803  update_all_los(where->map, where->x, where->y);
2804  }
2805  }
2806 
2807  return op;
2808 }
2809 
2835 int object_check_move_on(object *op, object *originator) {
2836  object *tmp;
2837  tag_t tag;
2838  mapstruct *m = op->map;
2839  int x = op->x, y = op->y;
2840  MoveType move_on, move_slow, move_block;
2841 
2842  if (QUERY_FLAG(op, FLAG_NO_APPLY))
2843  return 0;
2844 
2845  tag = op->count;
2846 
2847  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
2848  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
2849  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
2850 
2851  /* if nothing on this space will slow op down or be applied,
2852  * no need to do checking below. have to make sure move_type
2853  * is set, as lots of objects don't have it set - we treat that
2854  * as walking.
2855  */
2856  if (op->move_type
2857  && !(op->move_type&move_on)
2858  && !(op->move_type&move_slow))
2859  return 0;
2860 
2861  /* This is basically inverse logic of that below - basically,
2862  * if the object can avoid the move on or slow move, they do so,
2863  * but can't do it if the alternate movement they are using is
2864  * blocked. Logic on this seems confusing, but does seem correct.
2865  */
2866  if ((op->move_type&~move_on&~move_block) != 0
2867  && (op->move_type&~move_slow&~move_block) != 0)
2868  return 0;
2869 
2870  /* The objects have to be checked from top to bottom.
2871  * Hence, we first go to the top:
2872  */
2873 
2874  tmp = GET_MAP_OB(op->map, op->x, op->y);
2876  if (tmp->above == NULL)
2877  break;
2878  /* Trim the search when we find the first other spell effect
2879  * this helps performance so that if a space has 50 spell objects,
2880  * we don't need to check all of them.
2881  */
2882  if ((tmp->move_type&MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK))
2883  break;
2886  if (tmp == op)
2887  continue; /* Can't apply yourself */
2888 
2889  /* Check to see if one of the movement types should be slowed down.
2890  * Second check makes sure that the movement types not being slowed
2891  * (~slow_move) is not blocked on this space - just because the
2892  * space doesn't slow down swimming (for example), if you can't actually
2893  * swim on that space, can't use it to avoid the penalty.
2894  */
2895  if (!QUERY_FLAG(op, FLAG_WIZPASS)) {
2896  if ((!op->move_type && tmp->move_slow&MOVE_WALK)
2897  || ((op->move_type&tmp->move_slow) && (op->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
2898  float diff;
2899 
2900  diff = tmp->move_slow_penalty*FABS(op->speed);
2901  if (op->type == PLAYER) {
2904  diff /= 4.0;
2905  }
2906  }
2907  op->speed_left -= diff;
2908  }
2909  }
2910 
2911  /* Basically same logic as above, except now for actual apply. */
2912  if ((!op->move_type && tmp->move_on&MOVE_WALK)
2913  || ((op->move_type&tmp->move_on) && (op->move_type&~tmp->move_on&~tmp->move_block) == 0)) {
2914  ob_move_on(tmp, op, originator);
2915  if (object_was_destroyed(op, tag))
2916  return 1;
2917 
2918  /* what the person/creature stepped onto has moved the object
2919  * someplace new. Don't process any further - if we did,
2920  * have a feeling strange problems would result.
2921  */
2922  if (op->map != m || op->x != x || op->y != y)
2923  return 0;
2924  }
2926  return 0;
2927 }
2928 
2944 object *map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at) {
2945  if (m == NULL || out_of_map(m, x, y)) {
2946  LOG(llevError, "Present_arch called outside map.\n");
2947  return NULL;
2948  }
2949 
2950  FOR_MAP_PREPARE(m, x, y, tmp)
2951  if (tmp->arch == at)
2952  return tmp;
2953  FOR_MAP_FINISH();
2954 
2955  return NULL;
2956 }
2957 
2974 object *map_find_by_type(mapstruct *m, int x, int y, uint8_t type) {
2975  if (out_of_map(m, x, y)) {
2976  LOG(llevError, "Present called outside map.\n");
2977  return NULL;
2978  }
2979 
2980  FOR_MAP_PREPARE(m, x, y, tmp)
2981  if (tmp->type == type)
2982  return tmp;
2983  FOR_MAP_FINISH();
2984 
2985  return NULL;
2986 }
2987 
3001 object *object_present_in_ob(uint8_t type, const object *op) {
3002  object *tmp;
3003 
3004  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3005  if (tmp->type == type)
3006  return tmp;
3007 
3008  return NULL;
3009 }
3010 
3039 object *object_present_in_ob_by_name(int type, const char *str, const object *op) {
3040  object *tmp;
3041 
3042  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3043  if ((type == -1 || tmp->type == type) && !strcmp(str, tmp->name))
3044  return tmp;
3045  }
3046  return NULL;
3047 }
3048 
3061 object *arch_present_in_ob(const archetype *at, const object *op) {
3062  object *tmp;
3063 
3064  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3065  if (tmp->arch == at)
3066  return tmp;
3067  return NULL;
3068 }
3069 
3081 void object_set_flag_inv(object*op, int flag) {
3082  object *tmp;
3083 
3084  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3085  SET_FLAG(tmp, flag);
3086  object_set_flag_inv(tmp, flag);
3087  }
3088 }
3089 
3101 void object_unset_flag_inv(object*op, int flag) {
3102  object *tmp;
3103 
3104  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3105  CLEAR_FLAG(tmp, flag);
3106  object_unset_flag_inv(tmp, flag);
3107  }
3108 }
3109 
3122 void object_set_cheat(object *op) {
3123  SET_FLAG(op, FLAG_WAS_WIZ);
3125 }
3126 
3147 int object_find_multi_free_spot_around(const object *ob, const object *gen, int *hx, int *hy) {
3148  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3149  int freecount = 0;
3150 
3151  ob = HEAD(ob);
3152 
3153  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3154  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3155  /*
3156  * sx and sy are now the coords of the bottom right corner of ob relative to the head.
3157  * genx and geny are now the coords of the bottom right corner of gen relative to the head.
3158  * sx2 and sy2 are now the coords of the head of ob relative to the top left corner.
3159  * genx2 and geny2 are now the coords of the head of gen relative to the top left corner.
3160  */
3161 
3162  sx++;
3163  sy++;
3164  genx++;
3165  geny++;
3166  /*
3167  * sx, sy, genx, and geny, are now the size of the object, excluding parts left and above
3168  * the head.
3169  */
3170 
3171  ix = gen->x-sx-genx2;
3172  iy = gen->y-sy-geny2;
3173  sx += genx+sx2;
3174  sy += geny+sy2;
3175  /*
3176  * ix and iy are the map coords of the top left square where the head of ob could possibly
3177  * be placed. sx and sy are now the size of the square to search for placement of the head
3178  * relative to ix and iy.
3179  */
3180 
3181  /*
3182  * Loop around the square of possible positions for the head of ob object:
3183  */
3184  for (i = 0; i < (sx+sx+sy+sy); i++) {
3185  if (i <= sx) {
3186  nx = i+ix;
3187  ny = iy;
3188  } else if (i <= sx+sy) {
3189  nx = ix+sx;
3190  ny = iy+i-sx;
3191  } else if (i <= sx+sy+sx) {
3192  nx = ix+sx-(i-(sx+sy));
3193  ny = iy+sy;
3194  } else {
3195  nx = ix;
3196  ny = iy+sy-(i-(sx+sy+sx));
3197  }
3198  /* Check if the spot is free. */
3199  flag = ob_blocked(ob, gen->map, nx, ny);
3200  if (!flag) {
3201  freecount++;
3202  }
3203  }
3204  /* If no free spaces, return. */
3205  if (!freecount)
3206  return -1;
3207 
3208  /* Choose a random valid position */
3209  freecount = RANDOM()%freecount;
3210  for (i = 0; i < sx+sx+sy+sy; i++) {
3211  if (i <= sx) {
3212  nx = i+ix;
3213  ny = iy;
3214  } else if (i <= sx+sy) {
3215  nx = ix+sx;
3216  ny = iy+i-sx;
3217  } else if (i <= sx+sy+sx) {
3218  nx = ix+sx-(i-(sx+sy));
3219  ny = iy+sy;
3220  } else {
3221  nx = ix;
3222  ny = iy+sy-(i-(sx+sy+sx));
3223  }
3224 
3225  /* Make sure it's within map. */
3226  if (nx < 0 || nx >= MAP_WIDTH(gen->map)
3227  || ny < 0 || ny >= MAP_HEIGHT(gen->map))
3228  continue;
3229 
3230  /* Check if the spot is free.*/
3231  flag = ob_blocked(ob, gen->map, nx, ny);
3232  if (!flag) {
3233  freecount--;
3234  if (freecount <= 0) {
3235  *hx = nx;
3236  *hy = ny;
3237  return 0;
3238  }
3239  }
3240  }
3241  return -1;
3242 }
3243 
3266 int object_find_multi_free_spot_within_radius(const object *ob, const object *gen, int *hx, int *hy) {
3267  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3268  int8_t x, y, radius;
3269  int freecount = 0, freecountstop = 0;
3270  const char *value;
3271  int8_t *x_array;
3272  int8_t *y_array;
3273 
3274  /* If radius is not set, default to 1 */
3275  value = object_get_value(gen, "generator_radius");
3276  if (value) {
3277  radius = (int8_t)strtol(value, NULL, 10);
3278  if (radius < 1) {
3279  radius = 1;
3280  }
3281  } else {
3282  radius = 1;
3283  }
3284 
3285  ob = HEAD(ob);
3286 
3287  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3288  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3289  /*
3290  * sx and sy are now the coords of the bottom right corner
3291  * of ob relative to the head.
3292  * genx and geny are now the coords of the bottom right corner
3293  * of gen relative to the head.
3294  * sx2 and sy2 are now the coords of the head of ob relative
3295  * to the top left corner.
3296  * genx2 and geny2 are now the coords of the head of gen relative
3297  * to the top left corner.
3298  */
3299 
3300  sx++;
3301  sy++;
3302  genx++;
3303  geny++;
3304  /*
3305  * sx, sy, genx, and geny, are now the size of the object,
3306  * excluding parts left and above the head.
3307  */
3308 
3309  ix = gen->x-sx-genx2-radius+1;
3310  iy = gen->y-sy-geny2-radius+1;
3311  sx += genx+sx2+radius*2-1;
3312  sy += geny+sy2+radius*2-1;
3313 
3314  /*
3315  * ix and iy are the map coords of the top left square where
3316  * the head of ob could possibly be placed. sx and sy are now
3317  * the size of the square to search for placement of the head
3318  * relative to ix and iy.
3319  */
3320 
3321  /* Create arrays large enough to hold free space coordinates */
3322  x_array = malloc(sx*sy*sizeof(int8_t));
3323  y_array = malloc(sx*sy*sizeof(int8_t));
3324 
3325  /*
3326  * Loop through the area of possible positions for the head of ob object:
3327  */
3328  for (x = 0; x < sx; x++) {
3329  for (y = 0; y < sy; y++) {
3330  nx = ix+x;
3331  ny = iy+y;
3332 
3333 
3334  /* Make sure it's within map. */
3335  if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) {
3336  continue;
3337  }
3338 
3339  /* Check if the spot is free. */
3340  flag = ob_blocked(ob, gen->map, nx, ny);
3341  if (!flag) {
3342  x_array[freecount] = nx;
3343  y_array[freecount] = ny;
3344  freecount++;
3345  }
3346  }
3347  }
3348  /* If no free spaces, return. */
3349  if (!freecount) {
3350  free(x_array);
3351  free(y_array);
3352  return -1;
3353  }
3354 
3355  /* Choose a random valid position */
3356  freecountstop = RANDOM()%freecount;
3357  for (i = 0; i < freecount; i++) {
3358  nx = x_array[i];
3359  ny = y_array[i];
3360 
3361  /* Check if the spot is free.*/
3362  flag = ob_blocked(ob, gen->map, nx, ny);
3363  if (!flag) {
3364  freecountstop--;
3365  if (freecountstop <= 0) {
3366  *hx = nx;
3367  *hy = ny;
3368  free(x_array);
3369  free(y_array);
3370  return 0;
3371  }
3372  }
3373  }
3374  free(x_array);
3375  free(y_array);
3376  return -1;
3377 }
3378 
3415 int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop) {
3416  int i, index = 0, flag;
3417  static int altern[SIZEOFFREE];
3418 
3419  for (i = start; i < stop; i++) {
3420  flag = ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]);
3421  if (!flag)
3422  altern[index++] = i;
3423 
3424  /* Basically, if we find a wall on a space, we cut down the search size.
3425  * In this way, we won't return spaces that are on another side of a wall.
3426  * This mostly work, but it cuts down the search size in all directions -
3427  * if the space being examined only has a wall to the north and empty
3428  * spaces in all the other directions, this will reduce the search space
3429  * to only the spaces immediately surrounding the target area, and
3430  * won't look 2 spaces south of the target space.
3431  */
3432  else if ((flag&AB_NO_PASS) && maxfree[i] < stop)
3433  stop = maxfree[i];
3434  }
3435  if (!index)
3436  return -1;
3437  return altern[RANDOM()%index];
3438 }
3439 
3458 int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y) {
3459  int i;
3460 
3461  for (i = 0; i < SIZEOFFREE; i++) {
3462  if (!ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]))
3463  return i;
3464  }
3465  return -1;
3466 }
3467 
3477 static void permute(int *arr, int begin, int end) {
3478  int i, j, tmp, len;
3479 
3480  len = end-begin;
3481  for (i = begin; i < end; i++) {
3482  j = begin+RANDOM()%len;
3483 
3484  tmp = arr[i];
3485  arr[i] = arr[j];
3486  arr[j] = tmp;
3487  }
3488 }
3489 
3501 void get_search_arr(int *search_arr) {
3502  int i;
3503 
3504  for (i = 0; i < SIZEOFFREE; i++) {
3505  search_arr[i] = i;
3506  }
3507 
3508  permute(search_arr, 1, SIZEOFFREE1+1);
3509  permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1);
3510  permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE);
3511 }
3512 
3534 int map_find_dir(mapstruct *m, int x, int y, object *exclude) {
3535  int i, max = SIZEOFFREE, mflags;
3536  int16_t nx, ny;
3537  mapstruct *mp;
3538  MoveType blocked, move_type;
3539 
3540  if (exclude && exclude->head) {
3541  exclude = exclude->head;
3542  move_type = exclude->move_type;
3543  } else {
3544  /* If we don't have anything, presume it can use all movement types. */
3545  move_type = MOVE_ALL;
3546  }
3547 
3548  for (i = 1; i < max; i++) {
3549  mp = m;
3550  nx = x+freearr_x[i];
3551  ny = y+freearr_y[i];
3552 
3553  mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny);
3554  if (mflags&P_OUT_OF_MAP) {
3555  max = maxfree[i];
3556  } else {
3557  blocked = GET_MAP_MOVE_BLOCK(mp, nx, ny);
3558 
3559  if ((move_type&blocked) == move_type) {
3560  max = maxfree[i];
3561  } else if (mflags&P_IS_ALIVE) {
3562  FOR_MAP_PREPARE(mp, nx, ny, tmp) {
3563  if ((QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type == PLAYER)
3564  && (tmp != exclude || (tmp->head && tmp->head != exclude))) {
3565  return freedir[i];
3566  }
3567  } FOR_MAP_FINISH();
3568  }
3569  }
3570  }
3571  return 0;
3572 }
3573 
3584 int object_distance(const object *ob1, const object *ob2) {
3585  int i;
3586 
3587  i = (ob1->x-ob2->x)*(ob1->x-ob2->x)+
3588  (ob1->y-ob2->y)*(ob1->y-ob2->y);
3589  return i;
3590 }
3591 
3600 int find_dir_2(int x, int y) {
3601  int q;
3602 
3603  if (!y)
3604  q = -300*x;
3605  else
3606  q = x*100/y;
3607  if (y > 0) {
3608  if (q < -242)
3609  return 3;
3610  if (q < -41)
3611  return 2;
3612  if (q < 41)
3613  return 1;
3614  if (q < 242)
3615  return 8;
3616  return 7;
3617  }
3618  if (q < -242)
3619  return 7;
3620  if (q < -41)
3621  return 6;
3622  if (q < 41)
3623  return 5;
3624  if (q < 242)
3625  return 4;
3626  return 3;
3627 }
3628 
3637 int absdir(int d) {
3638  // Shortcut for modulus that work becuase we have a power of 2
3639  d &= 7;
3640  // 0 needs to be 8
3641  if (!d)
3642  d = 8;
3643  return d;
3644 }
3645 
3655 int dirdiff(int dir1, int dir2) {
3656  int d;
3657 
3658  d = abs(dir1-dir2);
3659  if (d > 4)
3660  d = 8-d;
3661  return d;
3662 }
3663 
3675 static const int reduction_dir[SIZEOFFREE][3] = {
3676  { 0, 0, 0 }, /* 0 */
3677  { 0, 0, 0 }, /* 1 */
3678  { 0, 0, 0 }, /* 2 */
3679  { 0, 0, 0 }, /* 3 */
3680  { 0, 0, 0 }, /* 4 */
3681  { 0, 0, 0 }, /* 5 */
3682  { 0, 0, 0 }, /* 6 */
3683  { 0, 0, 0 }, /* 7 */
3684  { 0, 0, 0 }, /* 8 */
3685  { 8, 1, 2 }, /* 9 */
3686  { 1, 2, -1 }, /* 10 */
3687  { 2, 10, 12 }, /* 11 */
3688  { 2, 3, -1 }, /* 12 */
3689  { 2, 3, 4 }, /* 13 */
3690  { 3, 4, -1 }, /* 14 */
3691  { 4, 14, 16 }, /* 15 */
3692  { 5, 4, -1 }, /* 16 */
3693  { 4, 5, 6 }, /* 17 */
3694  { 6, 5, -1 }, /* 18 */
3695  { 6, 20, 18 }, /* 19 */
3696  { 7, 6, -1 }, /* 20 */
3697  { 6, 7, 8 }, /* 21 */
3698  { 7, 8, -1 }, /* 22 */
3699  { 8, 22, 24 }, /* 23 */
3700  { 8, 1, -1 }, /* 24 */
3701  { 24, 9, 10 }, /* 25 */
3702  { 9, 10, -1 }, /* 26 */
3703  { 10, 11, -1 }, /* 27 */
3704  { 27, 11, 29 }, /* 28 */
3705  { 11, 12, -1 }, /* 29 */
3706  { 12, 13, -1 }, /* 30 */
3707  { 12, 13, 14 }, /* 31 */
3708  { 13, 14, -1 }, /* 32 */
3709  { 14, 15, -1 }, /* 33 */
3710  { 33, 15, 35 }, /* 34 */
3711  { 16, 15, -1 }, /* 35 */
3712  { 17, 16, -1 }, /* 36 */
3713  { 18, 17, 16 }, /* 37 */
3714  { 18, 17, -1 }, /* 38 */
3715  { 18, 19, -1 }, /* 39 */
3716  { 41, 19, 39 }, /* 40 */
3717  { 19, 20, -1 }, /* 41 */
3718  { 20, 21, -1 }, /* 42 */
3719  { 20, 21, 22 }, /* 43 */
3720  { 21, 22, -1 }, /* 44 */
3721  { 23, 22, -1 }, /* 45 */
3722  { 45, 47, 23 }, /* 46 */
3723  { 23, 24, -1 }, /* 47 */
3724  { 24, 9, -1 } /* 48 */
3725 };
3726 
3745 int can_see_monsterP(mapstruct *m, int x, int y, int dir) {
3746  int16_t dx, dy;
3747  int mflags;
3748 
3749  if (dir < 0)
3750  return 0; /* exit condition: invalid direction */
3751 
3752  dx = x+freearr_x[dir];
3753  dy = y+freearr_y[dir];
3754 
3755  mflags = get_map_flags(m, &m, dx, dy, &dx, &dy);
3756 
3757  /* This functional arguably was incorrect before - it was
3758  * checking for P_WALL - that was basically seeing if
3759  * we could move to the monster - this is being more
3760  * literal on if we can see it. To know if we can actually
3761  * move to the monster, we'd need the monster passed in or
3762  * at least its move type.
3763  */
3764  if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
3765  return 0;
3766 
3767  /* yes, can see. */
3768  if (dir < 9)
3769  return 1;
3770  return can_see_monsterP(m, x, y, reduction_dir[dir][0])|
3771  can_see_monsterP(m, x, y, reduction_dir[dir][1])|
3772  can_see_monsterP(m, x, y, reduction_dir[dir][2]);
3773 }
3774 
3793 int object_can_pick(const object *who, const object *item) {
3794  /* I re-wrote this as a series of if statements
3795  * instead of a nested return (foo & bar && yaz)
3796  * - I think this is much more readable,
3797  * and likely compiler effectively optimizes it the
3798  * same.
3799  */
3800  if (item->weight <= 0)
3801  return 0;
3802  if (QUERY_FLAG(item, FLAG_NO_PICK))
3803  return 0;
3804  if (QUERY_FLAG(item, FLAG_ALIVE))
3805  return 0;
3806  if (item->invisible)
3807  return 0;
3808 
3809  /* Weight limit for monsters */
3810  if (who->type != PLAYER && ((uint32_t)(who->weight+who->carrying+item->weight)) > get_weight_limit(who->stats.Str))
3811  return 0;
3812 
3813  /* Can not pick up multipart objects */
3814  if (item->head || item->more)
3815  return 0;
3816 
3817  /* Everything passes, so OK to pick up */
3818  return 1;
3819 }
3820 
3832 object *object_create_clone(object *asrc) {
3833  object *dst = NULL, *tmp, *src, *part, *prev;
3834 
3835  if (!asrc)
3836  return NULL;
3837  src = HEAD(asrc);
3838 
3839  prev = NULL;
3840  for (part = src; part; part = part->more) {
3841  tmp = object_new();
3842  object_copy(part, tmp);
3843  /*
3844  * Need to reset the weight, since object_insert_in_ob() later will
3845  * recompute this field.
3846  */
3847  tmp->carrying = tmp->arch->clone.carrying;
3848  tmp->x -= src->x;
3849  tmp->y -= src->y;
3850  if (!part->head) {
3851  dst = tmp;
3852  tmp->head = NULL;
3853  } else {
3854  tmp->head = dst;
3855  }
3856  tmp->more = NULL;
3857  if (prev)
3858  prev->more = tmp;
3859  prev = tmp;
3860  }
3861  /*** copy inventory ***/
3862  FOR_INV_PREPARE(src, item)
3863  (void)object_insert_in_ob(object_create_clone(item), dst);
3864  FOR_INV_FINISH();
3865 
3866  return dst;
3867 }
3868 
3879 object *object_find_by_name(const object *who, const char *name) {
3880  const char *name_shared = add_string(name);
3881  object *tmp;
3882 
3883  for (tmp = who->inv; tmp; tmp = tmp->below)
3884  if (tmp->name == name_shared)
3885  break;
3886  free_string(name_shared);
3887  return tmp;
3888 }
3889 
3903 object *object_find_by_type(const object *who, int type) {
3904  object *tmp;
3905 
3906  for (tmp = who->inv; tmp; tmp = tmp->below)
3907  if (tmp->type == type)
3908  return tmp;
3909 
3910  return NULL;
3911 }
3912 
3928 object *object_find_by_type2(const object *who, int type1, int type2) {
3929  object *tmp;
3930 
3931  for (tmp = who->inv; tmp; tmp = tmp->below)
3932  if (tmp->type == type1 || tmp->type == type2)
3933  return tmp;
3934 
3935  return NULL;
3936 }
3937 
3951 object *object_find_by_tag(const object *who, tag_t tag) {
3952  object *tmp;
3953 
3954  for (tmp = who->inv; tmp; tmp = tmp->below)
3955  if (tmp->count == tag)
3956  return tmp;
3957 
3958  return NULL;
3959 }
3960 
3974 object *object_find_by_type_applied(const object *who, int type) {
3975  object *tmp;
3976 
3977  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
3978  if (tmp->type == type && QUERY_FLAG(tmp, FLAG_APPLIED))
3979  return tmp;
3980 
3981  return NULL;
3982 }
3983 
3999 object *object_find_by_type_and_name(const object *who, int type, const char *name) {
4000  object *tmp;
4001 
4002  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4003  if (tmp->type == type && strcmp(tmp->name, name) == 0)
4004  return tmp;
4005 
4006  return NULL;
4007 }
4008 
4024 object *object_find_by_type_and_race(const object *who, int type, const char *race) {
4025  object *tmp;
4026 
4027  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4028  if (tmp->type == type && strcmp(tmp->race, race) == 0)
4029  return tmp;
4030 
4031  return NULL;
4032 }
4033 
4049 object *object_find_by_type_and_slaying(const object *who, int type, const char *slaying) {
4050  object *tmp;
4051 
4052  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4053  if (tmp->type == type && tmp->slaying != NULL && strcmp(tmp->slaying, slaying) == 0)
4054  return tmp;
4055 
4056  return NULL;
4057 }
4058 
4074 object *object_find_by_type_and_skill(const object *who, int type, const char *skill) {
4075  object *tmp;
4076 
4077  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4078  if (tmp->type == SKILL && tmp->skill != NULL && strcmp(tmp->skill, skill) == 0)
4079  return tmp;
4080 
4081  return NULL;
4082 }
4083 
4097 object *object_find_by_flag(const object *who, int flag) {
4098  object *tmp;
4099 
4100  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4101  if (QUERY_FLAG(tmp, flag))
4102  return tmp;
4103 
4104  return NULL;
4105 }
4106 
4120 object *object_find_by_flag_applied(const object *who, int flag) {
4121  object *tmp;
4122 
4123  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4124  if (QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, flag))
4125  return tmp;
4126 
4127  return NULL;
4128 }
4129 
4143 object *object_find_by_arch_name(const object *who, const char *name) {
4144  object *tmp;
4145 
4146  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4147  if (strcmp(tmp->arch->name, name) == 0)
4148  return tmp;
4149 
4150  return NULL;
4151 }
4152 
4168 object *object_find_by_type_and_arch_name(const object *who, int type, const char *name) {
4169  object *tmp;
4170 
4171  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4172  if (tmp->type == type && strcmp(tmp->arch->name, name) == 0)
4173  return tmp;
4174 
4175  return NULL;
4176 }
4177 
4195 object *object_find_by_type_subtype(const object *who, int type, int subtype) {
4196  object *tmp;
4197 
4198  for (tmp = who->inv; tmp; tmp = tmp->below)
4199  if (tmp->type == type && tmp->subtype == subtype)
4200  return tmp;
4201 
4202  return NULL;
4203 }
4204 
4218 key_value *object_get_key_value(const object *ob, const char *key) {
4219  key_value *link;
4220 
4221  for (link = ob->key_values; link != NULL; link = link->next) {
4222  if (link->key == key) {
4223  return link;
4224  }
4225  }
4226 
4227  return NULL;
4228 }
4229 
4246 const char *object_get_value(const object *op, const char *const key) {
4247  key_value *link;
4248  const char *canonical_key;
4249 
4250  canonical_key = find_string(key);
4251 
4252  if (canonical_key == NULL) {
4253  /* 1. There being a field named key on any object
4254  * implies there'd be a shared string to find.
4255  * 2. Since there isn't, no object has this field.
4256  * 3. Therefore, *this *object doesn't have this field.
4257  */
4258  return NULL;
4259  }
4260 
4261  /* This is copied from object_get_key_value() above -
4262  * only 4 lines, and saves the function call overhead.
4263  */
4264  for (link = op->key_values; link != NULL; link = link->next) {
4265  if (link->key == canonical_key) {
4266  return link->value;
4267  }
4268  }
4269  return NULL;
4270 }
4271 
4289 static int object_set_value_s(object *op, const char *canonical_key, const char *value, int add_key) {
4290  key_value *field = NULL, *last = NULL;
4291 
4292  for (field = op->key_values; field != NULL; field = field->next) {
4293  if (field->key != canonical_key) {
4294  last = field;
4295  continue;
4296  }
4297 
4298  if (field->value)
4299  FREE_AND_CLEAR_STR(field->value);
4300  if (value)
4301  field->value = add_string(value);
4302  else {
4303  /* Basically, if the archetype has this key set,
4304  * we need to store the null value so when we save
4305  * it, we save the empty value so that when we load,
4306  * we get this value back again.
4307  */
4308  if (object_get_key_value(&op->arch->clone, canonical_key))
4309  field->value = NULL;
4310  else {
4311  /* Delete this link */
4312  if (field->key)
4313  FREE_AND_CLEAR_STR(field->key);
4314  if (field->value)
4315  FREE_AND_CLEAR_STR(field->value);
4316  if (last)
4317  last->next = field->next;
4318  else
4319  op->key_values = field->next;
4320  free(field);
4321  }
4322  }
4323  return TRUE;
4324  }
4325  /* IF we get here, key doesn't exist */
4326 
4327  /* No field, we'll have to add it. */
4328 
4329  if (!add_key) {
4330  return FALSE;
4331  }
4332  /* There isn't any good reason to store a null
4333  * value in the key/value list. If the archetype has
4334  * this key, then we should also have it, so shouldn't
4335  * be here. If user wants to store empty strings,
4336  * should pass in ""
4337  */
4338  if (value == NULL)
4339  return TRUE;
4340 
4341  field = malloc(sizeof(key_value));
4342 
4343  field->key = add_refcount(canonical_key);
4344  field->value = add_string(value);
4345  /* Usual prepend-addition. */
4346  field->next = op->key_values;
4347  op->key_values = field;
4348 
4349  return TRUE;
4350 }
4351 
4375 int object_set_value(object *op, const char *key, const char *value, int add_key) {
4376  const char *canonical_key = NULL;
4377  int floating_ref = FALSE;
4378  int ret;
4379 
4380  /* HACK This mess is to make sure set_ob_value() passes a shared string
4381  * to object_get_key_value(), without leaving a leaked refcount.
4382  */
4383 
4384  canonical_key = find_string(key);
4385  if (canonical_key == NULL) {
4386  canonical_key = add_string(key);
4387  floating_ref = TRUE;
4388  }
4389 
4390  ret = object_set_value_s(op, canonical_key, value, add_key);
4391 
4392  if (floating_ref) {
4393  free_string(canonical_key);
4394  }
4395 
4396  return ret;
4397 }
4398 
4453 int object_matches_string(object *pl, object *op, const char *name) {
4454  char *cp, local_name[MAX_BUF], name_op[MAX_BUF], name_short[HUGE_BUF], bname_s[MAX_BUF], bname_p[MAX_BUF];
4455  int count, retval = 0;
4456  /* strtok is destructive to name */
4457  safe_strncpy(local_name, name, sizeof(local_name));
4458 
4459  for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) {
4460  while (cp[0] == ' ')
4461  ++cp; /* get rid of spaces */
4462 
4463  /* LOG(llevDebug, "Trying to match %s\n", cp);*/
4464  /* All is a very generic match - low match value */
4465  if (!strcmp(cp, "all"))
4466  return 1;
4467 
4468  /* unpaid is a little more specific */
4469  if (!strcmp(cp, "unpaid") && QUERY_FLAG(op, FLAG_UNPAID))
4470  return 2;
4471  if (!strcmp(cp, "cursed")
4473  && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)))
4474  return 2;
4475 
4476  if (!strcmp(cp, "unlocked") && !QUERY_FLAG(op, FLAG_INV_LOCKED))
4477  return 2;
4478 
4479  /* Allow for things like '100 arrows' */
4480  count = atoi(cp);
4481  if (count != 0) {
4482  cp = strchr(cp, ' ');
4483  while (cp && cp[0] == ' ')
4484  ++cp; /* get rid of spaces */
4485  } else {
4486  if (pl->type == PLAYER)
4487  count = pl->contr->count;
4488  else
4489  count = 0;
4490  }
4491 
4492  if (!cp || cp[0] == '\0' || count < 0)
4493  return 0;
4494 
4495  /* The code here should go from highest retval to lowest. That
4496  * is because of the 'else' handling - we don't want to match on
4497  * something and set a low retval, even though it may match a higher retcal
4498  * later. So keep it in descending order here, so we try for the best
4499  * match first, and work downward.
4500  */
4501  query_name(op, name_op, MAX_BUF);
4502  query_short_name(op, name_short, HUGE_BUF);
4503  query_base_name(op, 0, bname_s, MAX_BUF);
4504  query_base_name(op, 1, bname_p, MAX_BUF);
4505 
4506  if (!strcasecmp(cp, name_op))
4507  retval = 20;
4508  else if (!strcasecmp(cp, name_short))
4509  retval = 18;
4510  else if (!strcasecmp(cp, bname_s))
4511  retval = 16;
4512  else if (!strcasecmp(cp, bname_p))
4513  retval = 16;
4514  else if (op->custom_name && !strcasecmp(cp, op->custom_name))
4515  retval = 15;
4516  else if (!strncasecmp(cp, bname_s, strlen(cp)))
4517  retval = 14;
4518  else if (!strncasecmp(cp, bname_p, strlen(cp)))
4519  retval = 14;
4520  /* Do substring checks, so things like 'Str+1' will match.
4521  * retval of these should perhaps be lower - they are lower
4522  * then the specific strcasecmp aboves, but still higher than
4523  * some other match criteria.
4524  */
4525  else if (strstr(bname_p, cp))
4526  retval = 12;
4527  else if (strstr(bname_s, cp))
4528  retval = 12;
4529  else if (strstr(name_short, cp))
4530  retval = 12;
4531  /* Check against plural/non plural based on count. */
4532  else if (count > 1 && !strcasecmp(cp, op->name_pl)) {
4533  retval = 6;
4534  } else if (count == 1 && !strcasecmp(op->name, cp)) {
4535  retval = 6;
4536  }
4537  /* base name matched - not bad */
4538  else if (strcasecmp(cp, op->name) == 0 && !count)
4539  retval = 4;
4540  /* Check for partial custom name, but give a real low priority */
4541  else if (op->custom_name && strstr(op->custom_name, cp))
4542  retval = 3;
4543 
4544  if (retval) {
4545  if (pl->type == PLAYER)
4546  pl->contr->count = count;
4547  return retval;
4548  }
4549  }
4550  return 0;
4551 }
4552 
4564 void object_fix_multipart(object *tmp) {
4565  archetype *at;
4566  object *op, *last;
4567 
4568  if (!tmp->map) {
4569  LOG(llevError, "object_fix_multipart: not on a map!\n");
4570  return;
4571  }
4572 
4573  /* already multipart - don't do anything more */
4574  if (tmp->head || tmp->more)
4575  return;
4576 
4577  /* If there is nothing more to this object, this for loop
4578  * won't do anything.
4579  */
4580  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
4581  op = arch_to_object(at);
4582 
4583  /* update x,y coordinates */
4584  op->x += tmp->x;
4585  op->y += tmp->y;
4586  op->head = tmp;
4587  op->map = tmp->map;
4588  last->more = op;
4589  if (tmp->name != op->name) {
4590  if (op->name)
4591  free_string(op->name);
4592  op->name = add_string(tmp->name);
4593  }
4594  if (tmp->title != op->title) {
4595  if (op->title)
4596  free_string(op->title);
4597  op->title = add_string(tmp->title);
4598  }
4599  /* we could link all the parts onto tmp, and then just
4600  * call object_insert_in_map once, but the effect is the same,
4601  * as object_insert_in_map will call itself with each part, and
4602  * the coding is simpler to just to it here with each part.
4603  */
4605  } /* for at = tmp->arch->more */
4606 }
4607 
4626 void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy) {
4627  archetype *part;
4628  int maxx = 0, maxy = 0, minx = 0, miny = 0;
4629 
4630  ob = HEAD(ob);
4631  *sx = 1;
4632  *sy = 1;
4633  if (ob->arch->more) {
4634  for (part = ob->arch; part; part = part->more) {
4635  if (part->clone.x > maxx)
4636  maxx = part->clone.x;
4637  if (part->clone.y > maxy)
4638  maxy = part->clone.y;
4639  if (part->clone.x < minx)
4640  minx = part->clone.x;
4641  if (part->clone.y < miny)
4642  miny = part->clone.y;
4643  }
4644  }
4645  if (sx)
4646  *sx = maxx;
4647  if (sy)
4648  *sy = maxy;
4649  if (hx)
4650  *hx = -minx;
4651  if (hy)
4652  *hy = -miny;
4653 }
4654 
4675 void object_insert_to_free_spot_or_free(object *op, mapstruct *map, int x, int y, int start, int stop, object *originator) {
4676  int pos;
4677 
4678  pos = object_find_free_spot(op, map, x, y, start, stop);
4679  if (pos == -1) {
4681  return;
4682  }
4683 
4684  object_insert_in_map_at(op, map, originator, 0, x+freearr_x[pos], y+freearr_y[pos]);
4685 }
4686 
4695 void object_set_msg(object *op, const char *msg) {
4696  if (op->msg != NULL) {
4697  free_string(op->msg);
4698  }
4699 
4700  if (msg != NULL) {
4701  // If the message does not have a trailing newline, add one.
4702  if (*msg != '\0' && strchr(msg, '\0')[-1] != '\n') {
4704  stringbuffer_append_string(sb, msg);
4705  stringbuffer_append_string(sb, "\n");
4706  op->msg = stringbuffer_finish_shared(sb);
4707  } else {
4708  op->msg = add_string(msg);
4709  }
4710  } else {
4711  op->msg = NULL;
4712  }
4713 }
4714 
4716 const char *const move_name[] = {
4717  "walk",
4718  "fly_low",
4719  "fly_high",
4720  "swim",
4721  "boat",
4722  NULL
4723 };
4724 
4725 /* This array equates the FLAG_ values with the V_ values. Use -1 to
4726  * put gaps in the array that should not be processed.
4727  * The order matches the order of the define values in 'define.h'.
4728  */
4735 static const char *const flag_names[NUM_FLAGS+1] = {
4736  "alive", "wiz", NULL, NULL, "was_wiz", "applied", "unpaid",
4737  "can_use_shield", "no_pick", "client_anim_sync", "client_anim_random", /* 10 */
4738  "is_animated", NULL /* FLAG_DIALOG_PARSED, not saved */,
4739  NULL /* flying */, "monster", "friendly", "generator",
4740  "is_thrown", "auto_apply", "treasure", "player sold", /* 20 */
4741  "see_invisible", "can_roll", "overlay_floor",
4742  "is_turnable", NULL /* walk_off */, NULL /* fly_on */,
4743  NULL /*fly_off*/, "is_used_up", "identified", "reflecting", /* 30 */
4744  "changing", "splitting", "hitback", "startequip",
4745  "blocksview", "undead", "scared", "unaggressive",
4746  "reflect_missile", "reflect_spell", /* 40 */
4747  "no_magic", "no_fix_player", "is_lightable", "tear_down",
4748  "run_away", NULL /*pass_thru */, NULL /*can_pass_thru*/,
4749  NULL /*"pick_up"*/, "unique", "no_drop", /* 50 */
4750  NULL /* wizcast*/, "can_cast_spell", "can_use_scroll", "can_use_range",
4751  "can_use_bow", "can_use_armour", "can_use_weapon",
4752  "can_use_ring", "has_ready_range", "has_ready_bow", /* 60 */
4753  "xrays", NULL, "is_floor", "lifesave", "no_strength", "sleep",
4754  "stand_still", "random_movement", "only_attack", "confused", /* 70 */
4755  "stealth", NULL, NULL, "cursed", "damned",
4756  "see_anywhere", "known_magical", "known_cursed",
4757  "can_use_skill", "been_applied", /* 80 */
4758  "has_ready_scroll", NULL, NULL,
4759  NULL, "make_invisible", "inv_locked", "is_wooded",
4760  "is_hilly", "has_ready_skill", "has_ready_weapon", /* 90 */
4761  "no_skill_ident", "is_blind", "can_see_in_dark", "is_cauldron",
4762  NULL, "no_steal", "one_hit", NULL, "berserk", "neutral", /* 100 */
4763  "no_attack", "no_damage", NULL, NULL, "activate_on_push",
4764  "activate_on_release", "is_water", "use_content_on_gen", NULL, "is_buildable", /* 110 */
4765  NULL, "blessed", "known_blessed"
4766 };
4767 
4777 {
4778  static char retbuf[MAX_BUF], retbuf_all[MAX_BUF];
4779  int i, all_count = 0, count;
4780 
4781  strcpy(retbuf, "");
4782  strcpy(retbuf_all, " all");
4783 
4784  /* Quick check, and probably fairly common */
4785  if (mt == MOVE_ALL) {
4786  stringbuffer_append_string(sb, "all");
4787  return;
4788  }
4789  if (mt == 0) {
4790  stringbuffer_append_string(sb, "0");
4791  return;
4792  }
4793 
4794  /* We basically slide the bits down. Why look at MOVE_ALL?
4795  * because we may want to return a string like 'all -swim',
4796  * and if we just looked at mt, we couldn't get that.
4797  */
4798  for (i = MOVE_ALL, count = 0; i != 0; i >>= 1, count++) {
4799  if (mt&(1<<count)) {
4800  strcat(retbuf, " ");
4801  strcat(retbuf, move_name[count]);
4802  } else {
4803  strcat(retbuf_all, " -");
4804  strcat(retbuf_all, move_name[count]);
4805  all_count++;
4806  }
4807  }
4808  /* Basically, if there is a single negation, return it, eg
4809  * 'all -swim'. But more than that, just return the
4810  * enumerated values. It doesn't make sense to return
4811  * 'all -walk -fly_low' - it is shorter to return 'fly_high swim'
4812  */
4813  if (all_count <= 1)
4814  stringbuffer_append_string(sb, retbuf_all+1);
4815  else
4816  stringbuffer_append_string(sb, retbuf+1);
4817 }
4818 
4820 #define ADD_STRINGLINE_ENTRY(sb__, entryname__, entryvalue__) do {\
4821  stringbuffer_append_string(sb__, entryname__);\
4822  stringbuffer_append_string(sb__, entryvalue__);\
4823  stringbuffer_append_string(sb__, "\n");\
4824  } while (0)
4825 
4826 #define FAST_SAVE_LONG(sb__, entryname__, entryvalue__) \
4827  stringbuffer_append_printf(sb__, "%s%ld\n", entryname__, (long int)entryvalue__)
4828 
4829 #define FAST_SAVE_DOUBLE(sb__, entryname__, entryvalue__) \
4830  stringbuffer_append_printf(sb__, "%s%f\n", entryname__, entryvalue__)
4831 
4845 void get_ob_diff(StringBuffer *sb, const object *op, const object *op2) {
4846  static char buf2[64];
4847  int tmp;
4848  int i;
4849  key_value *my_field;
4850  key_value *arch_field;
4851 
4852  /* This saves the key/value lists. We do it first so that any
4853  * keys that match field names will be overwritten by the loader.
4854  */
4855  for (my_field = op->key_values; my_field != NULL; my_field = my_field->next) {
4856  /* Find the field in the opposing member. */
4857  arch_field = object_get_key_value(op2, my_field->key);
4858 
4859  /* If there's no partnering field, or it's got a different value, save our field. */
4860  if (arch_field == NULL || my_field->value != arch_field->value) {
4861  stringbuffer_append_string(sb, my_field->key);
4862  stringbuffer_append_string(sb, " ");
4863  /* If this is null, then saving it as a space should
4864  * cause it to be null again.
4865  */
4866  if (my_field->value)
4867  stringbuffer_append_string(sb, my_field->value);
4868  stringbuffer_append_string(sb, "\n");
4869  }
4870  }
4871  /* We don't need to worry about the arch's extra fields - they
4872  * will get taken care of the object_copy() function.
4873  */
4874 
4875  if (op->name && op->name != op2->name) {
4876  ADD_STRINGLINE_ENTRY(sb, "name ", op->name);
4877  }
4878  if (op->name_pl && op->name_pl != op2->name_pl) {
4879  ADD_STRINGLINE_ENTRY(sb, "name_pl ", op->name_pl);
4880  }
4881  if (op->anim_suffix && op->anim_suffix != op2->anim_suffix) {
4882  ADD_STRINGLINE_ENTRY(sb, "anim_suffix ", op->anim_suffix);
4883  }
4884  if (op->custom_name && op->custom_name != op2->custom_name) {
4885  ADD_STRINGLINE_ENTRY(sb, "custom_name ", op->custom_name);
4886  }
4887  if (op->title && op->title != op2->title) {
4888  ADD_STRINGLINE_ENTRY(sb, "title ", op->title);
4889  }
4890  if (op->race && op->race != op2->race) {
4891  ADD_STRINGLINE_ENTRY(sb, "race ", op->race);
4892  }
4893  if (op->slaying && op->slaying != op2->slaying) {
4894  ADD_STRINGLINE_ENTRY(sb, "slaying ", op->slaying);
4895  }
4896  if (op->skill && op->skill != op2->skill) {
4897  ADD_STRINGLINE_ENTRY(sb, "skill ", op->skill);
4898  }
4899  if (op->msg && op->msg != op2->msg) {
4900  stringbuffer_append_string(sb, "msg\n");
4902  stringbuffer_append_string(sb, "endmsg\n");
4903  }
4904  if (op->lore && op->lore != op2->lore) {
4905  stringbuffer_append_string(sb, "lore\n");
4907  stringbuffer_append_string(sb, "endlore\n");
4908  }
4909  if (op->other_arch != op2->other_arch && op->other_arch != NULL && op->other_arch->name) {
4910  ADD_STRINGLINE_ENTRY(sb, "other_arch ", op->other_arch->name);
4911  }
4912  if (op->face != op2->face) {
4913  ADD_STRINGLINE_ENTRY(sb, "face ", op->face->name);
4914  }
4915 
4916  if (op->animation_id != op2->animation_id) {
4917  if (op->animation_id) {
4918  ADD_STRINGLINE_ENTRY(sb, "animation ", animations[GET_ANIM_ID(op)].name);
4919  if (!QUERY_FLAG (op, FLAG_ANIMATE)) {
4920  stringbuffer_append_string(sb, "is_animated 0\n");
4921  }
4922  } else {
4923  stringbuffer_append_string(sb, "animation NONE\n");
4924  }
4925  }
4926  if (op->stats.Str != op2->stats.Str)
4927  FAST_SAVE_LONG(sb, "Str ", op->stats.Str);
4928  if (op->stats.Dex != op2->stats.Dex)
4929  FAST_SAVE_LONG(sb, "Dex ", op->stats.Dex);
4930  if (op->stats.Con != op2->stats.Con)
4931  FAST_SAVE_LONG(sb, "Con ", op->stats.Con);
4932  if (op->stats.Wis != op2->stats.Wis)
4933  FAST_SAVE_LONG(sb, "Wis ", op->stats.Wis);
4934  if (op->stats.Pow != op2->stats.Pow)
4935  FAST_SAVE_LONG(sb, "Pow ", op->stats.Pow);
4936  if (op->stats.Cha != op2->stats.Cha)
4937  FAST_SAVE_LONG(sb, "Cha ", op->stats.Cha);
4938  if (op->stats.Int != op2->stats.Int)
4939  FAST_SAVE_LONG(sb, "Int ", op->stats.Int);
4940  if (op->stats.hp != op2->stats.hp)
4941  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
4942  if (op->stats.maxhp != op2->stats.maxhp)
4943  FAST_SAVE_LONG(sb, "maxhp ", op->stats.maxhp);
4944  if (op->stats.sp != op2->stats.sp)
4945  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
4946  if (op->stats.maxsp != op2->stats.maxsp)
4947  FAST_SAVE_LONG(sb, "maxsp ", op->stats.maxsp);
4948  if (op->stats.grace != op2->stats.grace)
4949  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
4950  if (op->stats.maxgrace != op2->stats.maxgrace)
4951  FAST_SAVE_LONG(sb, "maxgrace ", op->stats.maxgrace);
4952 
4953  if (op->stats.exp != op2->stats.exp) {
4954  snprintf(buf2, sizeof(buf2), "%"FMT64, op->stats.exp);
4955  ADD_STRINGLINE_ENTRY(sb, "exp ", buf2);
4956  }
4957 
4958  if (op->perm_exp != op2->perm_exp) {
4959  snprintf(buf2, sizeof(buf2), "%"FMT64, op->perm_exp);
4960  ADD_STRINGLINE_ENTRY(sb, "perm_exp ", buf2);
4961  }
4962 
4963  if (op->expmul != op2->expmul)
4964  FAST_SAVE_DOUBLE(sb, "expmul ", op->expmul);
4965  if (op->stats.food != op2->stats.food)
4966  FAST_SAVE_LONG(sb, "food ", op->stats.food);
4967  if (op->stats.dam != op2->stats.dam)
4968  FAST_SAVE_LONG(sb, "dam ", op->stats.dam);
4969  if (op->stats.luck != op2->stats.luck)
4970  FAST_SAVE_LONG(sb, "luck ", op->stats.luck);
4971  if (op->stats.wc != op2->stats.wc)
4972  FAST_SAVE_LONG(sb, "wc ", op->stats.wc);
4973  if (op->stats.ac != op2->stats.ac)
4974  FAST_SAVE_LONG(sb, "ac ", op->stats.ac);
4975  if (op->x != op2->x)
4976  FAST_SAVE_LONG(sb, "x ", op->x);
4977  if (op->y != op2->y)
4978  FAST_SAVE_LONG(sb, "y ", op->y);
4979  if (op->speed != op2->speed) {
4980  FAST_SAVE_DOUBLE(sb, "speed ", op->speed);
4981  }
4982  if (op->speed > 0 && op->speed_left != op2->speed_left) {
4983  FAST_SAVE_DOUBLE(sb, "speed_left ", op->speed_left);
4984  }
4985  if (op->weapon_speed != op2->weapon_speed) {
4986  FAST_SAVE_DOUBLE(sb, "weapon_speed ", op->weapon_speed);
4987  }
4988  if (op->weapon_speed > 0 && op->weapon_speed_left != op2->weapon_speed_left) {
4989  FAST_SAVE_DOUBLE(sb, "weapon_speed_left ", op->weapon_speed_left);
4990  }
4991  if (op->move_status != op2->move_status)
4992  FAST_SAVE_LONG(sb, "move_state ", op->move_status);
4993  if (op->attack_movement != op2->attack_movement)
4994  FAST_SAVE_LONG(sb, "attack_movement ", op->attack_movement);
4995  if (op->nrof != op2->nrof)
4996  FAST_SAVE_LONG(sb, "nrof ", op->nrof);
4997  if (op->level != op2->level)
4998  FAST_SAVE_LONG(sb, "level ", op->level);
4999  if (op->direction != op2->direction)
5000  FAST_SAVE_LONG(sb, "direction ", op->direction);
5001  if (op->type != op2->type)
5002  FAST_SAVE_LONG(sb, "type ", op->type);
5003  if (op->subtype != op2->subtype)
5004  FAST_SAVE_LONG(sb, "subtype ", op->subtype);
5005  if (op->attacktype != op2->attacktype)
5006  FAST_SAVE_LONG(sb, "attacktype ", op->attacktype);
5007 
5008  for (tmp = 0; tmp < NROFATTACKS; tmp++) {
5009  if (op->resist[tmp] != op2->resist[tmp]) {
5010  stringbuffer_append_string(sb, "resist_");
5011  FAST_SAVE_LONG(sb, resist_save[tmp], op->resist[tmp]);
5012  }
5013  }
5014 
5015  if (op->path_attuned != op2->path_attuned)
5016  FAST_SAVE_LONG(sb, "path_attuned ", op->path_attuned);
5017  if (op->path_repelled != op2->path_repelled)
5018  FAST_SAVE_LONG(sb, "path_repelled ", op->path_repelled);
5019  if (op->path_denied != op2->path_denied)
5020  FAST_SAVE_LONG(sb, "path_denied ", op->path_denied);
5021  if (op->material != op2->material)
5022  FAST_SAVE_LONG(sb, "material ", op->material);
5023  if (op->materialname && op->materialname != op2->materialname) {
5024  ADD_STRINGLINE_ENTRY(sb, "materialname ", op->materialname);
5025  }
5026  if (op->value != op2->value)
5027  FAST_SAVE_LONG(sb, "value ", op->value);
5028  if (op->carrying != op2->carrying)
5029  FAST_SAVE_LONG(sb, "carrying ", op->carrying);
5030  if (op->weight != op2->weight)
5031  FAST_SAVE_LONG(sb, "weight ", op->weight);
5032  if (op->invisible != op2->invisible)
5033  FAST_SAVE_LONG(sb, "invisible ", op->invisible);
5034  if (op->state != op2->state)
5035  FAST_SAVE_LONG(sb, "state ", op->state);
5036  if (op->magic != op2->magic)
5037  FAST_SAVE_LONG(sb, "magic ", op->magic);
5038  if (op->last_heal != op2->last_heal)
5039  FAST_SAVE_LONG(sb, "last_heal ", op->last_heal);
5040  if (op->last_sp != op2->last_sp)
5041  FAST_SAVE_LONG(sb, "last_sp ", op->last_sp);
5042  if (op->last_grace != op2->last_grace)
5043  FAST_SAVE_LONG(sb, "last_grace ", op->last_grace);
5044  if (op->last_eat != op2->last_eat)
5045  FAST_SAVE_LONG(sb, "last_eat ", op->last_eat);
5046  if (QUERY_FLAG(op, FLAG_IS_LINKED) && (tmp = get_button_value(op)))
5047  FAST_SAVE_LONG(sb, "connected ", tmp);
5048  if (op->glow_radius != op2->glow_radius)
5049  FAST_SAVE_LONG(sb, "glow_radius ", op->glow_radius);
5050  if (op->randomitems != op2->randomitems) {
5051  ADD_STRINGLINE_ENTRY(sb, "randomitems ", op->randomitems ? op->randomitems->name : "none");
5052  }
5053 
5054  if (op->run_away != op2->run_away)
5055  FAST_SAVE_LONG(sb, "run_away ", op->run_away);
5056  if (op->pick_up != op2->pick_up)
5057  FAST_SAVE_LONG(sb, "pick_up ", op->pick_up);
5058  if (op->weight_limit != op2->weight_limit)
5059  FAST_SAVE_LONG(sb, "container ", op->weight_limit);
5060  if (op->will_apply != op2->will_apply)
5061  FAST_SAVE_LONG(sb, "will_apply ", op->will_apply);
5062  if (op->smoothlevel != op2->smoothlevel)
5063  FAST_SAVE_LONG(sb, "smoothlevel ", op->smoothlevel);
5064 
5065  if (op->map_layer != op2->map_layer)
5066  ADD_STRINGLINE_ENTRY(sb, "map_layer ", map_layer_name[op->map_layer]);
5067 
5068  if (op->weapontype && op->weapontype != op2->weapontype) {
5069  FAST_SAVE_LONG(sb, "weapontype ", op->weapontype);
5070  }
5071  if (op->client_type && op->client_type != op2->client_type) {
5072  FAST_SAVE_LONG(sb, "client_type ", op->client_type);
5073  }
5074 
5075  if (op->item_power != op2->item_power) {
5076  FAST_SAVE_LONG(sb, "item_power ", op->item_power);
5077  }
5078 
5079  if (op->duration != op2->duration)
5080  FAST_SAVE_LONG(sb, "duration ", op->duration);
5081 
5082  if (op->range != op2->range)
5083  FAST_SAVE_LONG(sb, "range ", op->range);
5084 
5085  if (op->range_modifier != op2->range_modifier)
5086  FAST_SAVE_LONG(sb, "range_modifier ", op->range_modifier);
5087 
5088  if (op->duration_modifier != op2->duration_modifier)
5089  FAST_SAVE_LONG(sb, "duration_modifier ", op->duration_modifier);
5090 
5091  if (op->dam_modifier != op2->dam_modifier)
5092  FAST_SAVE_LONG(sb, "dam_modifier ", op->dam_modifier);
5093 
5094  if (op->gen_sp_armour != op2->gen_sp_armour) {
5095  FAST_SAVE_LONG(sb, "gen_sp_armour ", op->gen_sp_armour);
5096  }
5097 
5098  /* I've kept the old int move type saving code commented out.
5099  * In an ideal world, we'd know if we want to do a quick
5100  * save (say to a temp map, where we don't care about strings),
5101  * or a slower save/dm dump, where printing out strings is handy.
5102  */
5103  if (op->move_type != op2->move_type) {
5104  /*FAST_SAVE_LONG(sb, "move_type ", op->move_type)*/
5105  stringbuffer_append_string(sb, "move_type ");
5107  stringbuffer_append_string(sb, "\n");
5108  }
5109  if (op->move_block != op2->move_block) {
5110  /*FAST_SAVE_LONG(sb, "move_block ", op->move_block)*/
5111  stringbuffer_append_string(sb, "move_block ");
5113  stringbuffer_append_string(sb, "\n");
5114  }
5115  if (op->move_allow != op2->move_allow) {
5116  /*FAST_SAVE_LONG(sb, "move_allow ", op->move_allow);*/
5117  stringbuffer_append_string(sb, "move_allow ");
5119  stringbuffer_append_string(sb, "\n");
5120  }
5121  if (op->move_on != op2->move_on) {
5122  /*FAST_SAVE_LONG(sb, "move_on ", op->move_on);*/
5123  stringbuffer_append_string(sb, "move_on ");
5124  get_string_move_type(sb, op->move_on);
5125  stringbuffer_append_string(sb, "\n");
5126  }
5127  if (op->move_off != op2->move_off) {
5128  /*FAST_SAVE_LONG(sb, "move_off ", op->move_off);*/
5129  stringbuffer_append_string(sb, "move_off ");
5130  get_string_move_type(sb, op->move_off);
5131  stringbuffer_append_string(sb, "\n");
5132  }
5133  if (op->move_slow != op2->move_slow) {
5134  /*FAST_SAVE_LONG(sb, "move_slow ", op->move_slow);*/
5135  stringbuffer_append_string(sb, "move_slow ");
5137  stringbuffer_append_string(sb, "\n");
5138  }
5139 
5140  if (op->move_slow_penalty != op2->move_slow_penalty) {
5141  FAST_SAVE_DOUBLE(sb, "move_slow_penalty ", op->move_slow_penalty);
5142  }
5143 
5144  if (!COMPARE_FLAGS(op, op2)) {
5145  for (tmp = 0; tmp <= NUM_FLAGS; tmp++) {
5146  if (flag_names[tmp] && (QUERY_FLAG(op, tmp) != QUERY_FLAG(op2, tmp))) {
5147  ADD_STRINGLINE_ENTRY(sb, flag_names[tmp], QUERY_FLAG(op, tmp) ? " 1" : " 0");
5148  }
5149  }
5150  }
5151 
5152  /* Save body locations */
5153  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
5154  if (op->body_info[i] != op2->body_info[i]) {
5155  stringbuffer_append_string(sb, body_locations[i].save_name);
5156  FAST_SAVE_LONG(sb, " ", op->body_info[i]);
5157  }
5158  }
5159 
5160  /* Save discrete damage if applicable
5161  * Note that given how the discrete_damage allocation is done, there can't be any case where
5162  * op->discrete_damage == NULL && op2->discrete_damage != NULL.
5163  */
5164  if (op->discrete_damage) {
5165  for (i = 0; i < NROFATTACKS; i++) {
5166  if (op2->discrete_damage == NULL || op2->discrete_damage[i] != op->discrete_damage[i]) {
5167  stringbuffer_append_string(sb, "damage_");
5168  FAST_SAVE_LONG(sb, resist_save[i], op->discrete_damage[i]);
5169  }
5170  }
5171  }
5172 }
5173 
5186 int save_object(FILE *fp, object *op, int flag) {
5187  archetype *at;
5188  char *cp;
5189  int res;
5190  StringBuffer *sb;
5191 
5192  /* Even if the object does have an owner, it would seem that we should
5193  * still save it.
5194  */
5195  if (object_get_owner(op) != NULL || fp == NULL)
5196  return SAVE_ERROR_OK;
5197 
5198  /* If it is unpaid and we don't want to save those, just return. */
5199  if (!(flag&SAVE_FLAG_SAVE_UNPAID) && (QUERY_FLAG(op, FLAG_UNPAID))) {
5200  return SAVE_ERROR_OK;
5201  }
5202 
5203  /* If the object has no_save set, just return */
5204  if (QUERY_FLAG(op, FLAG_NO_SAVE))
5205  return SAVE_ERROR_OK;
5206 
5207  if ((at = op->arch) == NULL)
5208  at = empty_archetype;
5209  if (fprintf(fp, "arch %s\n", at->name) < 0)
5210  return SAVE_ERROR_WRITE;
5211 
5212  sb = stringbuffer_new();
5213 
5214  if (op->arch->reference_count > 0) {
5215  /* The object is a custom item/monster, so we handle its save differently.
5216  * We compare the custom archetype to the "original" one, then only save hp/gr/sp
5217  * which are the only values we can't recompute later - all others are modified by items in inventory.
5218  * Note that hp/gr/sp will appear twice in save, but last value will take precedence.
5219  */
5220  archetype *original = find_archetype(op->arch->name);
5221  if (!original) {
5222  LOG(llevError, "could not find original archetype %s for custom monster!\n", op->arch->name);
5223  abort();
5224  }
5225  get_ob_diff(sb, &op->arch->clone, &original->clone);
5226  if (op->stats.hp != op->arch->clone.stats.hp)
5227  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5228  if (op->stats.sp != op->arch->clone.stats.sp)
5229  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5230  if (op->stats.grace != op->arch->clone.stats.grace)
5231  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5232  if (op->x != op->arch->clone.x)
5233  FAST_SAVE_LONG(sb, "x ", op->x);
5234  if (op->y != op->arch->clone.y)
5235  FAST_SAVE_LONG(sb, "y ", op->y);
5236  }
5237  else {
5238  /* if op is an artifact, then find the "standard" artifact to use that for the diff */
5239  if (op->artifact != NULL) {
5240  object *base;
5241  const artifact *artifact;
5242 
5243  artifact = find_artifact(op, op->artifact);
5244  if (artifact == NULL) {
5245  LOG(llevError, "could not find artifact %s [%d] to save data\n", op->artifact, op->type);
5246  get_ob_diff(sb, op, &at->clone);
5247  } else {
5248  stringbuffer_append_printf(sb, "artifact %s\n", op->artifact);
5249  base = arch_to_object(at);
5250  give_artifact_abilities(base, artifact->item);
5251  get_ob_diff(sb, op, base);
5253  }
5254  } else {
5255  get_ob_diff(sb, op, &at->clone);
5256  }
5257  }
5258 
5259  cp = stringbuffer_finish(sb);
5260  if (fputs(cp, fp) == EOF) {
5261  free(cp);
5262  return SAVE_ERROR_WRITE;
5263  }
5264  free(cp);
5265 
5266  /* Eneq(@csd.uu.se): Added this to allow containers being saved with contents*/
5267 
5268  FOR_INV_PREPARE(op, tmp)
5269  if ((res = save_object(fp, tmp, flag)) != 0)
5270  return res;
5271  FOR_INV_FINISH();
5272 
5273  if (fprintf(fp, "end\n") < 0)
5274  return SAVE_ERROR_WRITE;
5275 
5276  return SAVE_ERROR_OK;
5277 }
float weapon_speed_left
How much speed is left to spend this round.
Definition: object.h:331
Error, serious thing.
Definition: logger.h:11
int object_distance(const object *ob1, const object *ob2)
Return the square of the distance between the two given objects.
Definition: object.c:3584
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Find object in inventory by type and name.
Definition: object.c:3999
#define FLAG_NO_MAGIC
Spells (some) can&#39;t pass this object.
Definition: define.h:276
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:365
int find_dir_2(int x, int y)
Computes a direction which you should travel to move of x and y.
Definition: object.c:3600
#define SET_MAP_OB(M, X, Y, tmp)
Sets the bottom object on a map.
Definition: map.h:177
int reference_count
How many times this temporary archetype is used.
Definition: object.h:473
#define FLAG_NO_DROP
Object can&#39;t be dropped.
Definition: define.h:289
int8_t Int
Definition: living.h:35
#define NUM_BODY_LOCATIONS
Number of body locations.
Definition: object.h:13
One player.
Definition: player.h:92
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
#define ADD_STRINGLINE_ENTRY(sb__, entryname__, entryvalue__)
Adds a line to the buffer.
Definition: object.c:4820
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:318
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:303
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:236
int8_t ac
Armour Class, how hard to hit, the lower the better.
Definition: living.h:37
struct _key_value * next
Next key in the list.
Definition: object.h:43
#define MOVE_WALK
Object walks.
Definition: define.h:407
int32_t weight_limit
Weight-limit of object.
Definition: object.h:366
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:519
tag_t ownercount
What count the owner had (in case owner has been freed)
Definition: object.h:380
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:316
MoveType move_type
Type of movement this object uses.
Definition: object.h:424
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:572
#define GET_MAP_MOVE_OFF(M, X, Y)
Gets the move_off state of a square.
Definition: map.h:207
uint8_t dam_modifier
How going up in level affects damage.
Definition: object.h:407
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:427
EXTERN long ob_count
Definition: global.h:156
#define P_PLAYER
There is a player on this space.
Definition: map.h:236
#define SAVE_ERROR_OK
No error.
Definition: map.h:143
struct Statistics statistics
Merged spell statistics.
Definition: init.c:113
const char * race
Human, goblin, dragon, etc.
Definition: object.h:318
#define P_NEED_UPDATE
This space is out of date.
Definition: map.h:239
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Constructs a loop iterating over an object and all objects above it in the same pile.
Definition: define.h:774
uint16_t attack_movement
What kind of attack movement.
Definition: object.h:391
#define OBJ_EXPAND
How big steps to use when expanding array.
Definition: config.h:574
void esrv_send_item(object *pl, object *op)
Sends item&#39;s info to player.
Definition: main.c:339
tag_t attacked_by_count
The tag of attacker, so we can be sure.
Definition: object.h:383
#define SET_FLAG(xyz, p)
Definition: define.h:223
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.c:210
void object_clear_owner(object *op)
Clears the owner of specified object.
Definition: object.c:581
MoveType move_allow
What movement types explicitly allowed.
Definition: object.h:426
void object_sub_weight(object *op, signed long weight)
Recursively (outwards) subtracts a number from the weight of an object (and what is carried by it&#39;s e...
Definition: object.c:1625
object * object_find_by_type_applied(const object *who, int type)
Find applied object in inventory.
Definition: object.c:3974
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
unsigned char uint8_t
Definition: win32.h:161
See Scroll.
Definition: object.h:221
void object_free_all_data(void)
Destroys all allocated objects.
Definition: object.c:522
void object_copy_owner(object *op, object *clone)
Set the owner to clone&#39;s current owner and set the skill and experience objects to clone&#39;s objects (t...
Definition: object.c:657
uint16_t animation_id
An index into the animation array.
Definition: object.h:416
uint16_t material
What materials this object consist of.
Definition: object.h:347
tag_t * spell_tags
Tags used for spell effect merging.
Definition: object.h:436
sstring artifact
If set, the item is the artifact with this name and the matching type.
Definition: object.h:314
object * object_find_by_type(const object *who, int type)
Find object in inventory.
Definition: object.c:3903
uint64_t spell_merges
Number of spell merges done.
Definition: global.h:346
#define EVENT_DESTROY
Object destroyed (includes map reset/swapout)
Definition: plugin.h:77
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.c:333
struct obj * container
Current container being used.
Definition: object.h:291
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:246
void object_copy_with_inv(const object *src_ob, object *dest_ob)
copy an object with an inventory...
Definition: object.c:975
sstring stringbuffer_finish_shared(StringBuffer *sb)
Deallocate the string buffer instance and return the string as a shared string.
Definition: stringbuffer.c:85
#define P_NO_MAGIC
Spells (some) can&#39;t pass this object.
Definition: map.h:227
int16_t players
How many players are on this level right now.
Definition: map.h:344
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.c:596
static void get_string_move_type(StringBuffer *sb, MoveType mt)
This returns a string of the integer movement type.
Definition: object.c:4776
int8_t range
Range of the spell.
Definition: object.h:405
Climbing.
Definition: skills.h:39
#define FLAG_NO_FIX_PLAYER
fix_object() won&#39;t be called
Definition: define.h:277
#define LOOK_OBJ(ob)
This returns TRUE if the object is something that should be displayed in the look window...
Definition: object.h:507
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.c:57
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:345
void get_search_arr(int *search_arr)
New function to make monster searching more efficient, and effective! This basically returns a random...
Definition: object.c:3501
unsigned char MoveType
Typdef here to define type large enough to hold bitmask of all movement types.
Definition: define.h:432
int32_t last_heal
Last healed.
Definition: object.h:357
int16_t maxgrace
Maximum grace.
Definition: living.h:44
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
#define UP_OBJ_INSERT
Object was inserted.
Definition: object.h:516
signed long object_sum_weight(object *op)
object_sum_weight() is a recursive function which calculates the weight an object is carrying...
Definition: object.c:311
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
void object_fix_multipart(object *tmp)
Ensures specified object has its more parts correctly inserted in map.
Definition: object.c:4564
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.c:2366
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.c:342
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
struct treasureliststruct * randomitems
Items to be generated.
Definition: object.h:385
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.c:722
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:80
object clone
An object from which to do object_copy()
Definition: object.h:470
int16_t duration
How long the spell lasts.
Definition: object.h:403
socket_struct socket
Socket information for this player.
Definition: player.h:94
int16_t invisible
How much longer the object will be invis.
Definition: object.h:360
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.c:65
int object_find_multi_free_spot_within_radius(const object *ob, const object *gen, int *hx, int *hy)
Sets hx and hy to the coords to insert a possibly multi-tile ob at, within radius of generator...
Definition: object.c:3266
uint8_t duration_modifier
how level modifies duration
Definition: object.h:404
See Rune.
Definition: object.h:240
int object_count_active(void)
Objects statistics.
Definition: object.c:1598
const char * key
Name of the key.
Definition: object.h:41
struct obj * prev
Pointer to the previous object in the free/used list.
Definition: object.h:278
const char * slaying
Which race to do double damage to.
Definition: object.h:319
object * object_find_by_flag(const object *who, int flag)
Find object in inventory by flag.
Definition: object.c:4097
int32_t last_sp
As last_heal, but for spell points.
Definition: object.h:358
int object_check_move_on(object *op, object *originator)
Checks if any objects has a move_type that matches objects that effect this object on this space...
Definition: object.c:2835
uint8_t subtype
Subtype of object.
Definition: object.h:339
int64_t exp
Experience.
Definition: living.h:46
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:533
int arch_init
True if doing arch initialization.
Definition: arch.c:41
struct obj * above
Pointer to the object stacked above this one.
Definition: object.h:288
void object_dump_all(void)
Dumps all objects to console.
Definition: object.c:450
double expmul
needed experience = (calc_exp*expmul) - means some races/classes can need less/more exp to gain level...
Definition: object.h:395
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Find object in inventory by type and slaying.
Definition: object.c:4049
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:217
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:68
#define TRUE
Definition: compat.h:10
int freedir[SIZEOFFREE]
Direction we&#39;re pointing on this spot.
Definition: object.c:83
object * arch_present_in_ob(const archetype *at, const object *op)
Searches for any objects with a matching archetype in the inventory of the given object.
Definition: object.c:3061
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
The ordering of this is actually doesn&#39;t make a difference However, for ease of use, new entries should go at the end so those people that debug the code that get used to something being in the location 4 don&#39;t get confused.
Definition: item.c:54
#define FALSE
Definition: compat.h:11
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.c:56
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:343
#define MAX(x, y)
Definition: compat.h:20
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.c:1239
int16_t sp
Spell points.
Definition: living.h:41
uint32_t get_weight_limit(int stat)
Definition: living.c:2255
int object_can_merge(object *ob1, object *ob2)
Examines the 2 objects given to it, and returns true if they can be merged together, including inventory.
Definition: object.c:171
uint8_t smoothlevel
how to smooth this square around
Definition: object.h:421
Global type definitions and header inclusions.
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:344
#define safe_strncpy
Definition: compat.h:23
uint32_t hidden
If True, player (DM) is hidden from view.
Definition: player.h:132
void free_dialog_information(object *op)
Frees obj::dialog_information.
Definition: dialog.c:32
struct obj * enemy
Monster/player to follow even if not closest.
Definition: object.h:381
struct archt * other_arch
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:413
#define FAST_SAVE_LONG(sb__, entryname__, entryvalue__)
Adds a long to the buffer.
Definition: object.c:4826
int absdir(int d)
Computes an absolute direction.
Definition: object.c:3637
object * object_find_by_name(const object *who, const char *name)
Finds an object in inventory name.
Definition: object.c:3879
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
uint8_t casting_time
It takes awhile to cast a spell.
Definition: global.h:268
uint64_t spell_hash_full
Number of times spell hash was full.
Definition: global.h:347
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:789
int16_t maxsp
Max spell points.
Definition: living.h:42
int8_t Con
Definition: living.h:35
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
int16_t hp
Hit Points.
Definition: living.h:39
#define CALLOC(x, y)
Definition: compat.h:27
int nrofallocobjects
How many OBs allocated (free + used)
Definition: object.c:57
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.c:71
Woodsman.
Definition: skills.h:40
object * active_objects
List of active objects that need to be processed.
Definition: object.c:62
static const int reduction_dir[SIZEOFFREE][3]
Basically, this is a table of directions, and what directions one could go to go back to us...
Definition: object.c:3675
#define SAVE_ERROR_WRITE
Write error.
Definition: map.h:146
void object_set_flag_inv(object *op, int flag)
Activate recursively a flag on an object&#39;s inventory.
Definition: object.c:3081
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:413
void esrv_del_item(player *pl, object *ob)
Tells the client to delete an item.
Definition: main.c:355
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner&#39;s current skill and experience objects...
Definition: object.c:601
int16_t * discrete_damage
damage values, based on each attacktype.
Definition: object.h:435
#define SAVE_FLAG_SAVE_UNPAID
If set, unpaid items will be saved.
Definition: map.h:110
See Trap.
Definition: object.h:241
const char * lore
Obscure information about this object, to get put into books and the like.
Definition: object.h:323
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:130
int object_set_value(object *op, const char *key, const char *value, int add_key)
Updates the key in op to value.
Definition: object.c:4375
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:115
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
const char * name
Face name, as used by archetypes and such.
Definition: face.h:20
const char * title
Of foo, etc.
Definition: object.h:317
int16_t y
Position in the map for this object.
Definition: object.h:326
key_value * object_get_key_value(const object *ob, const char *key)
Search for a field by key.
Definition: object.c:4218
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.c:1921
int16_t maxhp
Max hit points.
Definition: living.h:40
sstring find_string(const char *str)
Searches a string in the shared strings.
Definition: shstr.c:236
void object_replace_insert_in_map(const char *arch_string, object *op)
This function inserts an object of a specified archetype in the map, but if it finds objects of its o...
Definition: object.c:2425
int dirdiff(int dir1, int dir2)
Computes a direction difference.
Definition: object.c:3655
void object_update_turn_face(object *op)
If an object with the IS_TURNABLE() flag needs to be turned due to the closest player being on the ot...
Definition: object.c:1109
#define FREE_OBJ_FREE_INVENTORY
Free inventory objects; if not set, drop inventory.
Definition: object.h:532
void object_dump(const object *op, StringBuffer *sb)
Dumps an object.
Definition: object.c:394
#define FLAG_CLIENT_ANIM_RANDOM
Client animate this, randomized.
Definition: define.h:241
EXTERN archetype * empty_archetype
Nice to have fast access to it.
Definition: global.h:151
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:345
int maxfree[SIZEOFFREE]
Number of spots around a location, including that location (except for 0)
Definition: object.c:77
#define STARTMAX
How big array of objects to start with.
Definition: config.h:573
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it...
Definition: object.c:1037
const char * name_pl
The plural name of the object.
Definition: object.h:315
#define FLAG_OBJ_ORIGINAL
NEVER SET THIS.
Definition: define.h:365
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.c:95
object * object_find_by_tag_global(tag_t i)
Returns the object which has the count-variable equal to the argument.
Definition: object.c:476
#define FOR_OB_AND_ABOVE_FINISH()
Finishes FOR_OB_AND_ABOVE_PREPARE().
Definition: define.h:778
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.c:3793
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.c:2690
float speed_left
How much speed is left to spend this round.
Definition: object.h:329
#define MAP_DARKNESS(m)
Map darkness used to enforce the MAX_DARKNESS value.
Definition: map.h:75
#define FLAG_NO_STEAL
Item can&#39;t be stolen.
Definition: define.h:343
Defines for loader.l / loader.c.
signed short int16_t
Definition: win32.h:160
int16_t ox
Definition: object.h:327
const char * materialname
Specific material name.
Definition: object.h:346
int32_t weight
Attributes of the object.
Definition: object.h:365
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:408
const char * anim_suffix
Used to determine combined animations.
Definition: object.h:316
#define FOR_ABOVE_FINISH()
Finishes FOR_ABOVE_PREPARE().
Definition: define.h:729
void update_all_los(const mapstruct *map, int x, int y)
This function makes sure that update_los() will be called for all players on the given map within the...
Definition: los.c:532
uint8_t range_modifier
How going up in level affects range.
Definition: object.h:406
int8_t Wis
Definition: living.h:35
uint32_t flags[4]
Various flags.
Definition: object.h:415
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
void free_arch(archetype *at)
Frees archetype.
Definition: arch.c:263
#define snprintf
Definition: win32.h:46
struct obj * active_prev
Previous object in the &#39;active list This is used in process_events so that the entire object list doe...
Definition: object.h:283
#define FLAG_NO_SAVE
If set (through plugins), the object is not saved on maps.
Definition: define.h:244
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Returns true if the given object can&#39;t fit in the given spot.
Definition: map.c:489
const char *const move_name[]
Maps the MOVE_* values to names.
Definition: object.c:4716
const artifact * find_artifact(const object *op, const char *name)
Searches and returns a specific artifact, NULL if not found.
Definition: artifact.c:640
#define FLAG_CLIENT_ANIM_SYNC
Let client animate this, synchronized.
Definition: define.h:240
object * transport
Transport the player is in.
Definition: player.h:195
#define FLAG_IDENTIFIED
Player knows full info about item.
Definition: define.h:261
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
object * object_find_by_flag_applied(const object *who, int flag)
Find applied object in inventory by flag.
Definition: object.c:4120
void object_remove_from_active_list(object *op)
This function removes object &#39;op&#39; from the list of active objects.
Definition: object.c:1194
#define FMT64
Definition: compat.h:12
void update_position(mapstruct *m, int x, int y)
This function updates various attributes about a specific space on the map (what it looks like...
Definition: map.c:2119
int16_t dam
How much damage this object does when hitting.
Definition: living.h:45
int object_count_free(void)
Objects statistics.
Definition: object.c:1560
int32_t carrying
How much weight this object contains.
Definition: object.h:367
object * objects
Pointer to the list of used objects.
Definition: object.c:60
#define FLAG_BLOCKSVIEW
Object blocks view.
Definition: define.h:269
struct artifactstruct artifact
This is one artifact, ie one special item.
static const char *const flag_names[NUM_FLAGS+1]
This is a list of pointers that correspond to the FLAG_.
Definition: object.c:4735
const char * name
The name of the object, obviously...
Definition: object.h:311
struct obj * env
Pointer to the object which is the environment.
Definition: object.h:293
#define FOR_ABOVE_PREPARE(op_, it_)
Constructs a loop iterating over all objects above an object.
Definition: define.h:722
int64_t perm_exp
Permanent exp.
Definition: object.h:369
int8_t gen_sp_armour
Sp regen penalty this object has (was last_heal)
Definition: object.h:363
#define OB_SPELL_TAG_MATCH(op, count)
Check whether a tag matches in the tags.
Definition: object.h:93
static int compare_ob_value_lists_one(const object *, const object *)
Compares value lists.
Definition: object.c:98
int save_object(FILE *fp, object *op, int flag)
Dumps all variables in an object to a file.
Definition: object.c:5186
uint8_t state
How the object was last drawn (animation)
Definition: object.h:349
struct obj * below
Pointer to the object stacked below this one.
Definition: object.h:287
struct archt * more
Next part of a linked object.
Definition: object.h:469
#define INS_NO_WALK_ON
Don&#39;t call check_walk_on against the originator.
Definition: object.h:570
object * object_present_in_ob(uint8_t type, const object *op)
Searches for any objects with a matching type variable in the inventory of the given object...
Definition: object.c:3001
#define offsetof(type, member)
The offsetof macro is part of ANSI C, but many compilers lack it, for example "gcc -ansi"...
Definition: shstr.h:37
#define FLAG_IS_A_TEMPLATE
Object has no ingame life until instantiated.
Definition: define.h:375
int16_t last_grace
As last_sp, except for grace.
Definition: object.h:359
void object_reset(object *op)
Sets to 0 vital variables in an object.
Definition: object.c:704
#define GET_MAP_TOP(M, X, Y)
Gets the top object on a map.
Definition: map.h:174
int8_t direction
Means the object is moving that way.
Definition: object.h:334
object * object_create_clone(object *asrc)
Create clone from object to another.
Definition: object.c:3832
#define NUM_FLAGS
Should always be equal to the last defined flag.
Definition: define.h:385
uint32_t nrof
How many of the objects.
Definition: object.h:333
Each object (this also means archetypes!) could have a few of these "dangling" from it; this could al...
Definition: object.h:40
int8_t Cha
Definition: living.h:35
#define GET_MAP_MOVE_ON(M, X, Y)
Gets the move_on state of a square.
Definition: map.h:202
#define FLAG_OVERLAY_FLOOR
Object is an overlay floor.
Definition: define.h:255
#define SIZEOFFREE
Definition: define.h:154
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:251
MoveType move_off
Move types affected moving off this space.
Definition: object.h:428
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
object * object_find_by_name_global(const char *str)
Finds an object by name.
Definition: object.c:499
EXTERN Animations * animations
Definition: global.h:165
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
int8_t item_power
Power rating of the object.
Definition: object.h:362
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
This function inserts the object in the two-way linked list which represents what is on a map...
Definition: object.c:2152
void object_clear(object *op)
Frees everything allocated by an object, and also clears all variables and flags to default settings...
Definition: object.c:759
int16_t oy
For debugging: Where it was last inserted.
Definition: object.h:327
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:208
#define MAP_SAVING
Map being saved.
Definition: map.h:133
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:12
int object_find_multi_free_spot_around(const object *ob, const object *gen, int *hx, int *hy)
Sets hx and hy to the coords to insert a possibly multi-tile ob at, around gen.
Definition: object.c:3147
object * object_find_by_type_and_race(const object *who, int type, const char *race)
Find object in inventory by type and race.
Definition: object.c:4024
int8_t luck
Affects thaco and ac from time to time.
Definition: living.h:38
float speed
The overall speed of this object.
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)
Returns the head part of an object.
Definition: object.h:594
#define INS_ABOVE_FLOOR_ONLY
Put object immediatly above the floor.
Definition: object.h:569
#define FLAG_BEEN_APPLIED
The object has been applied.
Definition: define.h:324
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Computes the size of a multitile object.
Definition: object.c:4626
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
This is one artifact, ie one special item.
Definition: artifact.h:14
object * free_objects
Pointer to the list of unused objects.
Definition: object.c:61
struct obj * active_next
Next object in the &#39;active&#39; list This is used in process_events so that the entire object list does n...
Definition: object.h:279
static void expand_objects(void)
Allocates more objects for the list of unused objects.
Definition: object.c:993
void give_artifact_abilities(object *op, const object *artifact)
Fixes the given object, giving it the abilities and titles it should have due to the second artifact-...
Definition: artifact.c:203
Many many details.
Definition: logger.h:14
method_ret ob_move_on(object *op, object *victim, object *originator)
Makes an object move on top of another one.
Definition: ob_methods.c:105
int16_t x
Definition: object.h:326
int strncasecmp(const char *s1, const char *s2, int n)
Case-insensitive comparaison of strings.
Definition: porting.c:224
const char *const map_layer_name[MAP_LAYERS]
These correspond to the layer names in map.h - since some of the types can be on multiple layers...
Definition: map.c:46
int nroffreeobjects
How many OBs allocated and free (free)
Definition: object.c:56
MoveType move_slow
Movement types this slows down.
Definition: object.h:429
const char * skill
Name of the skill this object uses/grants.
Definition: object.h:321
int32_t last_eat
How long since we last ate.
Definition: object.h:356
Skill-related defines, including subtypes.
Lamp.
Definition: object.h:201
int8_t wc
Weapon Class, how skilled, the lower the better.
Definition: living.h:36
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
object_find_first_free_spot(archetype, mapstruct, x, y) works like object_find_free_spot(), but it will search max number of squares.
Definition: object.c:3458
See Container.
Definition: object.h:231
void object_insert_to_free_spot_or_free(object *op, mapstruct *map, int x, int y, int start, int stop, object *originator)
Inserts an object into its map.
Definition: object.c:4675
Implements a general string buffer: it builds a string by concatenating.
static const flag_definition flags[]
Flag mapping.
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
struct obj * next
Pointer to the next object in the free/used list.
Definition: object.h:277
key_value * key_values
Fields not explictly known by the loader.
Definition: object.h:433
int8_t Str
Definition: living.h:35
#define COMPARE_FLAGS(p, q)
Definition: define.h:226
void animate_object(object *op, int dir)
Updates the face-variable of an object.
Definition: anim.c:186
#define FLAG_NO_APPLY
Avoids step_on/fly_on to this object.
Definition: define.h:302
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:341
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:321
object * ob
The object representing the player.
Definition: player.h:158
object * object_find_by_tag(const object *who, tag_t tag)
Find object in inventory.
Definition: object.c:3951
#define GET_MAP_FLAGS(M, X, Y)
Gets map flags.
Definition: map.h:161
#define FLAG_IS_HILLY
Item is hilly/mountain terrain.
Definition: define.h:333
#define SPELL_TAG_SIZE
Defines default size of the *spell_tags pointer.
Definition: object.h:81
#define FLAG_CURSED
The object is cursed.
Definition: define.h:317
See Player.
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)
Find object in inventory.
Definition: object.c:4195
#define SET_MAP_FLAGS(M, X, Y, C)
Sets map flags.
Definition: map.h:163
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:242
Object structure, the core of Crossfire.
int8_t body_info[NUM_BODY_LOCATIONS]
Body info as loaded from the file.
Definition: object.h:372
const char * name
Usually monster-name/combination.
Definition: treasure.h:83
object * object_find_by_type_and_skill(const object *who, int type, const char *skill)
Find object in inventory by type and skill.
Definition: object.c:4074
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:342
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
object_split(ob,nr) splits up ob into two parts.
Definition: object.c:2463
uint8_t map_layer
What level to draw this on the map.
Definition: object.h:422
#define INS_NO_MERGE
Don&#39;t try to merge with other items.
Definition: object.h:568
object * object_decrease_nrof(object *op, uint32_t i)
Decreases a specified number from the amount of an object.
Definition: object.c:2505
#define UP_OBJ_CHANGE
Object changed.
Definition: object.h:518
struct obj * owner
Pointer to the object which controls this one.
Definition: object.h:377
#define RANDOM()
Definition: define.h:679
static int compare_ob_value_lists(const object *, const object *)
Compares two object lists.
Definition: object.c:139
int16_t grace
Grace.
Definition: living.h:43
#define UPD_NROF
Definition: newclient.h:296
signed char int8_t
Type definitions for fixed-size integer types.
Definition: win32.h:158
Also see SKILL_TOOL (74) below.
Definition: object.h:143
#define GET_MAP_PLAYER(M, X, Y)
Definition: map.h:168
New_Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.c:39
const char * custom_name
Custom name assigned by player.
Definition: object.h:432
#define UP_OBJ_REMOVE
Object was removed.
Definition: object.h:517
int get_button_value(const object *button)
Returns the first value linked to this button.
Definition: button.c:754
tag_t count
Unique object number for this object.
Definition: object.h:299
living stats
Str, Con, Dex, etc.
Definition: object.h:368
uint16_t client_type
Public type information.
Definition: object.h:340
int8_t Dex
Definition: living.h:35
struct archt * arch
Pointer to archetype.
Definition: object.h:412
#define AB_NO_PASS
Definition: map.h:235
#define UPD_FACE
Definition: newclient.h:292
#define MAP_WIDTH(m)
Map width.
Definition: map.h:78
Only for debugging purposes.
Definition: logger.h:13
uint8_t will_apply
See crossfire.doc and What monsters apply.
Definition: object.h:392
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:126
struct Settings settings
Server settings.
Definition: init.c:40
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.c:679
void object_free2(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1391
uint32_t weapontype
Type of weapon.
Definition: object.h:371
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
#define NROFATTACKS
Definition: attack.h:17
object * object_merge(object *op, object *top)
This function goes through all objects below and including top, and merges op to the first matching o...
Definition: object.c:1869
void query_short_name(const object *op, char *buf, size_t size)
query_short_name(object) is similar to query_name(), but doesn&#39;t contain any information about object...
Definition: item.c:547
object * object_get_player_container(object *op)
Finds the player carrying an object.
Definition: object.c:353
int out_of_map(mapstruct *m, int x, int y)
this returns TRUE if the coordinates (x,y) are out of map m.
Definition: map.c:2294
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: main.c:364
object objarray[STARTMAX]
All objects, allocated this way at first.
Definition: object.c:55
#define SIZEOFFREE2
Definition: define.h:153
#define OB_SPELL_TAG_HASH(op, count)
Get the hash on an object for a specified count.
Definition: object.h:87
int object_count_used(void)
Object statistics.
Definition: object.c:1579
static const object * object_get_owner_const(const object *op)
Returns the object which this object marks as being the owner, constant version.
Definition: object.c:370
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
const char * value
Key&#39;s value.
Definition: object.h:42
int16_t casting_time
Time left before spell goes off.
Definition: object.h:402
void object_unset_flag_inv(object *op, int flag)
Desactivate recursively a flag on an object inventory.
Definition: object.c:3101
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.c:4453
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:785
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:268
void object_merge_spell(object *op, int16_t x, int16_t y)
This sees if there are any objects on the space that can merge with op.
Definition: object.c:1953
int map_find_dir(mapstruct *m, int x, int y, object *exclude)
Search some close squares in the given map at the given coordinates for live objects.
Definition: object.c:3534
#define GET_ANIM_ID(ob)
Definition: global.h:173
static void permute(int *, int, int)
Randomly permutes an array.
Definition: object.c:3477
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
EXTERN player * first_player
First player.
Definition: global.h:117
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.c:104
struct pl * next
Pointer to next player, NULL if this is last.
Definition: player.h:93
#define MIN_ACTIVE_SPEED
Cut off point of when an object is put on the active list or not.
Definition: define.h:674
void object_add_weight(object *op, signed long weight)
object_add_weight(object, weight) adds the specified weight to an object, and also updates how much t...
Definition: object.c:2663
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:172
int strcasecmp(const char *s1, const char *s2)
Case-insensitive comparaison of strings.
Definition: porting.c:256
int8_t glow_radius
indicates the glow radius of the object
Definition: object.h:364
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.c:838
int8_t Pow
Definition: living.h:35
static int object_set_value_s(object *, const char *, const char *, int)
Updates or sets a key value.
Definition: object.c:4289
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.c:302
struct obj * inv
Pointer to the first object in the inventory.
Definition: object.h:290
void object_set_cheat(object *op)
object_set_cheat(object) sets the cheat flag (WAS_WIZ) in the object and in all it&#39;s inventory (recur...
Definition: object.c:3122
#define SIZEOFFREE1
Definition: define.h:152
struct obj * head
Points to the main object of a large body.
Definition: object.h:296
#define MOVE_FLY_HIGH
High flying object.
Definition: define.h:409
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
static void object_increase_nrof(object *op, uint32_t i)
Increase the count of an object.
Definition: object.c:2591
EXTERN const char *const resist_save[NROFATTACKS]
Definition: attack.h:139
#define SET_MAP_TOP(M, X, Y, tmp)
Sets the top object on a map.
Definition: map.h:179
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:234
uint8_t pick_up
See crossfire.doc.
Definition: object.h:361
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
#define FREE_OBJ_DROP_ABOVE_FLOOR
If FREE_OBJ_FREE_INVENTORY is not set, drop inventory just above ground instead on top...
Definition: object.h:534
MoveType move_block
What movement types this blocks.
Definition: object.h:425
uint8_t run_away
Monster runs away if it&#39;s hp goes below this percentage.
Definition: object.h:384
#define GET_MAP_MOVE_SLOW(M, X, Y)
Gets the slowing state of a square.
Definition: map.h:197
#define P_BLOCKSVIEW
This spot blocks the player&#39;s view.
Definition: map.h:226
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.c:4695
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
Recursive routine to see if we can find a path to a certain point.
Definition: object.c:3745
int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
object_find_free_spot(object, map, x, y, start, stop) will search for a spot at the given map and coo...
Definition: object.c:3415
#define FLAG_DIALOG_PARSED
Was the object::msg field parsed? Temporary flag not saved.
Definition: define.h:243
#define FAST_SAVE_DOUBLE(sb__, entryname__, entryvalue__)
Adds a double to the buffer.
Definition: object.c:4829
#define P_NO_ERROR
Purely temporary - if set, update_position does not complain if the flags are different.
Definition: map.h:240
float move_slow_penalty
How much this slows down the object.
Definition: object.h:430
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.c:25
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
object * item
Special values of the artifact.
Definition: artifact.h:15
object * find_skill_by_number(object *who, int skillno)
This returns the skill pointer of the given name (the one that accumulates exp, has the level...
Definition: main.c:351
object * map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at)
Searches for any objects with a matching archetype at the given map and coordinates.
Definition: object.c:2944
This is a game-map.
Definition: map.h:325
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
void get_ob_diff(StringBuffer *sb, const object *op, const object *op2)
Returns a pointer to a static string which contains all variables which are different in the two give...
Definition: object.c:4845
const New_Face * face
Face with colors.
Definition: object.h:332
#define FREE_AND_CLEAR(xyz)
Free the pointer and then set it to NULL.
Definition: global.h:203
#define FLAG_IS_WOODED
Item is wooded terrain.
Definition: define.h:331
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:239
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
Find object in inventory by type and archetype name.
Definition: object.c:4168
#define FLAG_WIZPASS
The wizard can go through walls.
Definition: define.h:315
int32_t move_status
What stage in attack mode.
Definition: object.h:390
void object_free_key_values(object *op)
Zero the key_values on op, decrementing the shared-string refcounts and freeing the links...
Definition: object.c:727
int16_t level
Level of creature or object.
Definition: object.h:351
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:330
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.c:1120
float weapon_speed
The overall speed of this object.
Definition: object.h:330
struct obj * more
Pointer to the rest of a large body of objects.
Definition: object.h:295
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.c:1129
#define SCRIPT_FIX_NOTHING
Definition: global.h:362
int32_t value
How much money it is worth (or contains)
Definition: object.h:350
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.c:559
int8_t magic
Any magical bonuses to this item.
Definition: object.h:348
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.c:76
#define P_NO_CLERIC
No clerical spells cast here.
Definition: map.h:238
object * object_find_by_arch_name(const object *who, const char *name)
Find object in inventory by archetype name.
Definition: object.c:4143
object * object_present_in_ob_by_name(int type, const char *str, const object *op)
Searches for any objects with a matching type & name variable in the inventory of the given object...
Definition: object.c:3039
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
object * map_find_by_type(mapstruct *m, int x, int y, uint8_t type)
Searches for any objects with a matching type variable at the given map and coordinates.
Definition: object.c:2974
#define INS_MAP_LOAD
Disable lots of checkings.
Definition: object.h:573
object * object_find_by_type2(const object *who, int type1, int type2)
Find object in inventory.
Definition: object.c:3928
int32_t food
How much food in stomach.
Definition: living.h:47
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
uint32_t count
Any numbers typed before a command.
Definition: player.h:109
#define FLAG_IS_TURNABLE
Object can change face with direction.
Definition: define.h:256