Crossfire Server, Branches 1.12  R18729
object.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_object_c =
3  * "$Id: object.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2001 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28 
34 /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
35  sub/add_weight will transcend the environment updating the carrying
36  variable. */
37 
38 #include <stdlib.h>
39 #include <string.h>
40 #include <global.h>
41 #ifndef WIN32 /* ---win32 exclude headers */
42 #include <stdio.h>
43 #include <sys/types.h>
44 #include <sys/uio.h>
45 #endif /* win32 */
46 #include <object.h>
47 #include <skills.h>
48 #include <loader.h>
49 #include <sproto.h>
50 #include "stringbuffer.h"
51 
52 static int compare_ob_value_lists_one(const object *, const object *);
53 static int compare_ob_value_lists(const object *, const object *);
54 static void expand_objects(void);
55 static void permute(int *, int, int);
56 static int set_ob_key_value_s(object *, const char *, const char *, int);
57 static void increase_ob_nr(object *op, uint32 i);
58 
59 #ifdef MEMORY_DEBUG
60 int nroffreeobjects = 0;
61 int nrofallocobjects = 0;
62 #undef OBJ_EXPAND
63 #define OBJ_EXPAND 1
64 #else
65 object objarray[STARTMAX];
68 #endif
69 
70 object *objects;
71 object *free_objects;
72 object *active_objects;
76  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,
77  0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
78 };
79 
82  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,
83  -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3
84 };
85 
88  0, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45,
89  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
90 };
91 
94  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,
95  1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
96 };
97 
108 static int compare_ob_value_lists_one(const object *wants, const object *has) {
109  key_value *wants_field;
110 
111  /* n-squared behaviour (see get_ob_key_link()), but I'm hoping both
112  * objects with lists are rare, and lists stay short. If not, use a
113  * different structure or at least keep the lists sorted...
114  */
115 
116  /* For each field in wants, */
117  for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) {
118  key_value *has_field;
119 
120  /* Look for a field in has with the same key. */
121  has_field = get_ob_key_link(has, wants_field->key);
122 
123  if (has_field == NULL) {
124  /* No field with that name. */
125  return FALSE;
126  }
127 
128  /* Found the matching field. */
129  if (has_field->value != wants_field->value) {
130  /* Values don't match, so this half of the comparison is false. */
131  return FALSE;
132  }
133 
134  /* If we get here, we found a match. Now for the next field in wants. */
135  }
136 
137  /* If we get here, every field in wants has a matching field in has. */
138  return TRUE;
139 }
140 
149 static int compare_ob_value_lists(const object *ob1, const object *ob2) {
150  /* However, there may be fields in has which aren't partnered in wants,
151  * so we need to run the comparison *twice*. :(
152  */
153  return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1);
154 }
155 
178 int can_merge(object *ob1, object *ob2) {
179 
180  /* A couple quicksanity checks */
181  if ((ob1 == ob2) || (ob1->type != ob2->type))
182  return 0;
183 
184  if (ob1->speed != ob2->speed)
185  return 0;
186  /* Note sure why the following is the case - either the object has to
187  * be animated or have a very low speed. Is this an attempted monster
188  * check?
189  */
190  /*TODO is this check really needed?*/
191  if (!QUERY_FLAG(ob1, FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
192  return 0;
193 
194  /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
195  * value could not be stored in a sint32 (which unfortunately sometimes is
196  * used to store nrof).
197  */
198  if (ob1->nrof+ob2->nrof >= 1UL<<31)
199  return 0;
200 
201  /* This is really a spellbook check - really, we should
202  * check all objects in the inventory.
203  */
204  /*TODO is this check really needed?*/
205  if (ob1->inv || ob2->inv) {
206  /* if one object has inventory but the other doesn't, not equiv */
207  if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
208  return 0;
209 
210  /* Now check to see if the two inventory objects could merge */
211  if (!can_merge(ob1->inv, ob2->inv))
212  return 0;
213 
214  /* inventory ok - still need to check rest of this object to see
215  * if it is valid.
216  */
217  }
218 
219  /* If the objects have been identified, set the BEEN_APPLIED flag.
220  * This is to the comparison of the flags below will be OK. We
221  * just can't ignore the been applied or identified flags, as they
222  * are not equal - just if it has been identified, the been_applied
223  * flags lose any meaning.
224  */
225 
226  /*TODO is this hack on BEEN_APPLIED really needed? */
227  if (QUERY_FLAG(ob1, FLAG_IDENTIFIED))
229 
230  if (QUERY_FLAG(ob2, FLAG_IDENTIFIED))
232 
233 
234  /* Note: FLAG_INV_LOCKED is ignored for merging purposes */
235  if ((ob1->arch != ob2->arch)
236  || (ob1->flags[0] != ob2->flags[0])
237  || (ob1->flags[1] != ob2->flags[1])
238  || (ob1->flags[2] != ob2->flags[2])
239  || ((ob1->flags[3]&~0x4) != (ob2->flags[3]&~0x4)) /* ignore CLIENT_SENT */
240  || (ob1->name != ob2->name)
241  || (ob1->title != ob2->title)
242  || (ob1->msg != ob2->msg)
243  || (ob1->weight != ob2->weight)
244  || (ob1->item_power != ob2->item_power)
245  || (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist)) != 0)
246  || (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats)) != 0)
247  || (ob1->attacktype != ob2->attacktype)
248  || (ob1->magic != ob2->magic)
249  || (ob1->slaying != ob2->slaying)
250  || (ob1->skill != ob2->skill)
251  || (ob1->value != ob2->value)
252  || (ob1->animation_id != ob2->animation_id)
253  || (ob1->client_type != ob2->client_type)
254  || (ob1->materialname != ob2->materialname)
255  || (ob1->lore != ob2->lore)
256  || (ob1->subtype != ob2->subtype)
257  || (ob1->move_type != ob2->move_type)
258  || (ob1->move_block != ob2->move_block)
259  || (ob1->move_allow != ob2->move_allow)
260  || (ob1->move_on != ob2->move_on)
261  || (ob1->move_off != ob2->move_off)
262  || (ob1->move_slow != ob2->move_slow)
263  || (ob1->move_slow_penalty != ob2->move_slow_penalty)
264  || (ob1->map_layer != ob2->map_layer))
265  return 0;
266 
267  /* Don't merge objects that are applied. With the new 'body' code,
268  * it is possible for most any character to have more than one of
269  * some items equipped, and we don't want those to merge.
270  */
271  if (QUERY_FLAG(ob1, FLAG_APPLIED) || QUERY_FLAG(ob2, FLAG_APPLIED))
272  return 0;
273 
274  if (ob1->key_values != NULL || ob2->key_values != NULL) {
275  /* At least one of these has key_values. */
276  if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
277  /* One has fields, but the other one doesn't. */
278  return 0;
279  } else {
280  return compare_ob_value_lists(ob1, ob2);
281  }
282  }
283 
284  /*TODO should this really be limited to scrolls?*/
285  switch (ob1->type) {
286  case SCROLL:
287  if (ob1->level != ob2->level)
288  return 0;
289  break;
290 
291  }
292 
293  /* Don't merge items with differing custom names. */
294  if (ob1->custom_name != ob2->custom_name)
295  return 0;
296 
297  /* Everything passes, must be OK. */
298  return 1;
299 }
300 
316 /* TODO should check call this this are made a place where we really need reevaluaton of whole tree */
317 signed long sum_weight(object *op) {
318  signed long sum;
319  object *inv;
320 
321  for (sum = 0, inv = op->inv; inv != NULL; inv = inv->below) {
322  if (inv->inv)
323  sum_weight(inv);
324  sum += inv->carrying+inv->weight*(inv->nrof ? inv->nrof : 1);
325  }
326  if (op->type == CONTAINER && op->stats.Str)
327  sum = (sum*(100-op->stats.Str))/100;
328  op->carrying = sum;
329  return sum;
330 }
331 
339 object *object_get_env_recursive(object *op) {
340  while (op->env != NULL)
341  op = op->env;
342  return op;
343 }
344 
356 object *get_player_container(object *op) {
357  for (; op != NULL && op->type != PLAYER; op = op->env)
358  /*TODO this is patching the structure on the flight as side effect. Shoudln't be needed in clean code */
359  if (op->env == op)
360  op->env = NULL;
361  return op;
362 }
363 
372 void dump_object(object *op, StringBuffer *sb) {
373  if (op == NULL) {
374  stringbuffer_append_string(sb, "[NULL pointer]");
375  return;
376  }
377 
378  /* object *tmp;*/
379 
380  if (op->arch != NULL) {
381  stringbuffer_append_string(sb, "arch ");
382  stringbuffer_append_string(sb, op->arch->name ? op->arch->name : "(null)");
383  stringbuffer_append_string(sb, "\n");
384 
385  get_ob_diff(sb, op, &empty_archetype->clone);
386  if (op->more) {
387  stringbuffer_append_printf(sb, "more %u\n", op->more->count);
388  }
389  if (op->head) {
390  stringbuffer_append_printf(sb, "head %u\n", op->head->count);
391  }
392  if (op->env) {
393  stringbuffer_append_printf(sb, "env %u\n", op->env->count);
394  }
395  if (op->inv) {
396  stringbuffer_append_printf(sb, "inv %u\n", op->inv->count);
397  }
398  if (op->owner) {
399  stringbuffer_append_printf(sb, "owner %u\n", op->owner->count);
400  }
401  stringbuffer_append_string(sb, "end\n");
402  } else {
403  stringbuffer_append_string(sb, "Object ");
404  stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
405  stringbuffer_append_string(sb, "\nend\n");
406  }
407 }
408 
416 void dump_all_objects(void) {
417  object *op;
418 
419  for (op = objects; op != NULL; op = op->next) {
420  StringBuffer *sb;
421  char *diff;
422 
423  sb = stringbuffer_new();
424  dump_object(op, sb);
425  diff = stringbuffer_finish(sb);
426  LOG(llevDebug, "Object %d\n:%s\n", op->count, diff);
427  free(diff);
428  }
429 }
430 
439 object *find_object(tag_t i) {
440  object *op;
441 
442  for (op = objects; op != NULL; op = op->next)
443  if (op->count == i)
444  break;
445  return op;
446 }
447 
459 object *find_object_name(const char *str) {
460  const char *name = add_string(str);
461  object *op;
462 
463  for (op = objects; op != NULL; op = op->next)
464  if (op->name == name)
465  break;
466  free_string(name);
467  return op;
468 }
469 
480 #ifdef MEMORY_DEBUG
481  object *op, *next;
482 
483  for (op = free_objects; op != NULL; ) {
484  next = op->next;
485  free(op);
487  nroffreeobjects--;
488  op = next;
489  }
490 
491  for (op = objects; op != NULL; ) {
492  next = op->next;
493  if (!QUERY_FLAG(op, FLAG_FREED)) {
494  LOG(llevDebug, "non freed object: %s\n", op->name);
495  }
496  op = next;
497  }
498 #endif
499 
500  LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX);
501 }
502 
524 object *get_owner(object *op) {
525  if (op->owner == NULL)
526  return NULL;
527 
528  if (!QUERY_FLAG(op->owner, FLAG_FREED)
529  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
530  && op->owner->count == op->ownercount)
531  return op->owner;
532  LOG(llevError, "I had to clean an owner when in get_owner, this isn't my job.\n");
533  op->owner = NULL;
534  op->ownercount = 0;
535  return NULL;
536 }
537 
544 void clear_owner(object *op) {
545  if (!op)
546  return;
547 
548  op->owner = NULL;
549  op->ownercount = 0;
550 }
551 
564 void set_owner(object *op, object *owner) {
565  if (op == NULL)
566  return;
567  if (owner == NULL) {
568  clear_owner(op);
569  return;
570  }
571 
572  /* next line added to allow objects which own objects */
573  /* Add a check for ownercounts in here, as I got into an endless loop
574  * with the fireball owning a poison cloud which then owned the
575  * fireball. I believe that was caused by one of the objects getting
576  * freed and then another object replacing it. Since the ownercounts
577  * didn't match, this check is valid and I believe that cause is valid.
578  */
579  while (owner->owner
580  && owner != owner->owner
581  && owner->ownercount == owner->owner->count)
582  owner = owner->owner;
583 
584  /* IF the owner still has an owner, we did not resolve to a final owner.
585  * so lets not add to that.
586  */
587  if (owner->owner) {
588  LOG(llevError, "owner id %d could not be resolved to a parent owner in set_owner(). This is bad!"
589  "owner=%p owner->owner=%p owner->ownercount=%d owner->owner->count=%d\n",
590  owner->count, owner, owner->owner, owner->ownercount, owner->owner->count);
591  return;
592  }
593 
594  op->owner = owner;
595  op->ownercount = owner->count;
596 }
597 
614 void copy_owner(object *op, object *clone) {
615  object *owner = get_owner(clone);
616  if (owner == NULL) {
617  /* players don't have owners - they own themselves. Update
618  * as appropriate.
619  */
620  /*TODO owner=self is dangerous and should be avoided*/
621  if (clone->type == PLAYER)
622  owner = clone;
623  else
624  return;
625  }
626  set_owner(op, owner);
627 
628 }
629 
639 void reset_object(object *op) {
640  op->name = NULL;
641  op->name_pl = NULL;
642  op->title = NULL;
643  op->race = NULL;
644  op->slaying = NULL;
645  op->skill = NULL;
646  op->msg = NULL;
647  op->materialname = NULL;
648  op->lore = NULL;
649  clear_object(op);
650 }
651 
659 void free_key_values(object *op) {
660  key_value *i;
661  key_value *next = NULL;
662 
663  if (op->key_values == NULL)
664  return;
665 
666  for (i = op->key_values; i != NULL; i = next) {
667  /* Store next *first*. */
668  next = i->next;
669 
670  if (i->key)
672  if (i->value)
674  i->next = NULL;
675  free(i);
676  }
677 
678  op->key_values = NULL;
679 }
680 
688 void clear_object(object *op) {
689 
690  /*TODO this comment must be investigated*/
691  /* redo this to be simpler/more efficient. Was also seeing
692  * crashes in the old code. Move this to the top - am
693  * seeing periodic crashes in this code, and would like to have
694  * as much info available as possible (eg, object name).
695  */
696  free_key_values(op);
698 
699  /* the memset will clear all these values for us, but we need
700  * to reduce the refcount on them.
701  */
702  if (op->name != NULL) FREE_AND_CLEAR_STR(op->name);
703  if (op->name_pl != NULL) FREE_AND_CLEAR_STR(op->name_pl);
704  if (op->title != NULL) FREE_AND_CLEAR_STR(op->title);
705  if (op->race != NULL) FREE_AND_CLEAR_STR(op->race);
706  if (op->slaying != NULL) FREE_AND_CLEAR_STR(op->slaying);
707  if (op->skill != NULL) FREE_AND_CLEAR_STR(op->skill);
708  if (op->msg != NULL) FREE_AND_CLEAR_STR(op->msg);
709  if (op->lore != NULL) FREE_AND_CLEAR_STR(op->lore);
710  if (op->materialname != NULL) FREE_AND_CLEAR_STR(op->materialname);
711  if (op->discrete_damage != NULL) FREE_AND_CLEAR(op->discrete_damage);
712 
713  /* Remove object from friendly list if needed. */
714  if (QUERY_FLAG(op, FLAG_FRIENDLY))
716 
717  memset((void *)((char *)op+offsetof(object, name)), 0, sizeof(object)-offsetof(object, name));
718  /* Below here, we clear things that are not done by the memset,
719  * or set default values that are not zero.
720  */
721  /* This is more or less true */
722  SET_FLAG(op, FLAG_REMOVED);
723 
724 
725  op->contr = NULL;
726  op->below = NULL;
727  op->above = NULL;
728  op->inv = NULL;
729  op->container = NULL;
730  op->env = NULL;
731  op->more = NULL;
732  op->head = NULL;
733  op->map = NULL;
734  op->active_next = NULL;
735  op->active_prev = NULL;
736  /* What is not cleared is next, prev, and count */
737 
738  op->expmul = 1.0;
739  op->face = blank_face;
740  op->attacked_by_count = -1;
742  op->casting_time = -1;
743 }
744 
758 void copy_object(object *op2, object *op) {
759  int is_freed = QUERY_FLAG(op, FLAG_FREED), is_removed = QUERY_FLAG(op, FLAG_REMOVED);
760 
761  /* Decrement the refcounts, but don't bother zeroing the fields;
762  they'll be overwritten by memcpy. */
763  if (op->name != NULL) free_string(op->name);
764  if (op->name_pl != NULL) free_string(op->name_pl);
765  if (op->anim_suffix != NULL) free_string(op->anim_suffix);
766  if (op->title != NULL) free_string(op->title);
767  if (op->race != NULL) free_string(op->race);
768  if (op->slaying != NULL) free_string(op->slaying);
769  if (op->skill != NULL) free_string(op->skill);
770  if (op->msg != NULL) free_string(op->msg);
771  if (op->lore != NULL) free_string(op->lore);
772  if (op->materialname != NULL) free_string(op->materialname);
773  if (op->custom_name != NULL) free_string(op->custom_name);
774  if (op->discrete_damage != NULL) FREE_AND_CLEAR(op->discrete_damage);
775  if (op->spell_tags != NULL) FREE_AND_CLEAR(op->spell_tags);
776 
777  /* Basically, same code as from clear_object() */
778 
779  free_key_values(op);
781 
782  /* op is the destination, op2 is the source. */
783  (void)memcpy((void *)((char *)op+offsetof(object, name)),
784  (void *)((char *)op2+offsetof(object, name)),
785  sizeof(object)-offsetof(object, name));
786 
787  if (is_freed) SET_FLAG(op, FLAG_FREED);
788  if (is_removed) SET_FLAG(op, FLAG_REMOVED);
789  if (op->name != NULL) add_refcount(op->name);
790  if (op->name_pl != NULL) add_refcount(op->name_pl);
791  if (op->anim_suffix != NULL) add_refcount(op->anim_suffix);
792  if (op->title != NULL) add_refcount(op->title);
793  if (op->race != NULL) add_refcount(op->race);
794  if (op->slaying != NULL) add_refcount(op->slaying);
795  if (op->skill != NULL) add_refcount(op->skill);
796  if (op->lore != NULL) add_refcount(op->lore);
797  if (op->msg != NULL) add_refcount(op->msg);
798  if (op->custom_name != NULL) add_refcount(op->custom_name);
799  if (op->materialname != NULL) add_refcount(op->materialname);
800  if (op->discrete_damage != NULL) {
801  op->discrete_damage = malloc(sizeof(sint16)*NROFATTACKS);
802  memcpy(op->discrete_damage, op2->discrete_damage, sizeof(sint16)*NROFATTACKS);
803  }
804 
805  if (op->spell_tags != NULL) {
806  op->spell_tags = malloc(sizeof(tag_t)*SPELL_TAG_SIZE);
807  memcpy(op->spell_tags, op2->spell_tags, sizeof(tag_t)*SPELL_TAG_SIZE);
808  }
809 
810  /* If archetype is a temporary one, we need to update reference count, because
811  * that archetype will be freed by free_object when the last object is removed.
812  */
813  if (op->arch->reference_count > 0)
814  op->arch->reference_count++;
815 
816  if (op2->speed < 0)
817  op->speed_left = op2->speed_left-RANDOM()%200/100.0;
818 
819  /* Copy over key_values, if any. */
820  if (op2->key_values != NULL) {
821  key_value *tail = NULL;
822  key_value *i;
823 
824  op->key_values = NULL;
825 
826  for (i = op2->key_values; i != NULL; i = i->next) {
827  key_value *new_link = malloc(sizeof(key_value));
828 
829  new_link->next = NULL;
830  new_link->key = add_refcount(i->key);
831  if (i->value)
832  new_link->value = add_refcount(i->value);
833  else
834  new_link->value = NULL;
835 
836  /* Try and be clever here, too. */
837  if (op->key_values == NULL) {
838  op->key_values = new_link;
839  tail = new_link;
840  } else {
841  tail->next = new_link;
842  tail = new_link;
843  }
844  }
845  }
846 
847  /* This way, dialog information will be parsed again when/if needed. */
849 
850  update_ob_speed(op);
851 }
852 
862 void copy_object_with_inv(object *src_ob, object *dest_ob) {
863  object *walk, *tmp;
864  copy_object(src_ob, dest_ob);
865 
866  for (walk = src_ob->inv; walk != NULL; walk = walk->below) {
867  tmp = get_object();
868  copy_object(walk, tmp);
869  insert_ob_in_ob(tmp, dest_ob);
870  }
871 }
872 
880 static void expand_objects(void) {
881  int i;
882  object *new;
883 
884  new = (object *)CALLOC(OBJ_EXPAND, sizeof(object));
885 
886  if (new == NULL)
888  free_objects = new;
889  new[0].prev = NULL;
890  new[0].next = &new[1],
891  SET_FLAG(&(new[0]), FLAG_REMOVED);
892  SET_FLAG(&(new[0]), FLAG_FREED);
893 
894  for (i = 1; i < OBJ_EXPAND-1; i++) {
895  new[i].next = &new[i+1],
896  new[i].prev = &new[i-1],
897  SET_FLAG(&(new[i]), FLAG_REMOVED);
898  SET_FLAG(&(new[i]), FLAG_FREED);
899  }
900  new[OBJ_EXPAND-1].prev = &new[OBJ_EXPAND-2],
901  new[OBJ_EXPAND-1].next = NULL,
902  SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_REMOVED);
903  SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_FREED);
904 
907 }
908 
921 object *get_object(void) {
922  object *op;
923 
924  if (free_objects == NULL) {
925  expand_objects();
926  }
927  op = free_objects;
928 #ifdef MEMORY_DEBUG
929  /* The idea is hopefully by doing a realloc, the memory
930  * debugging program will now use the current stack trace to
931  * report leaks.
932  */
933  /* FIXME: However this doesn't work since free_object2() sometimes add
934  * objects back to the free_objects linked list, and some functions mess
935  * with the object after return of free_object2(). This is bad and should be
936  * fixed. But it would need fairly extensive changes and a lot of debugging.
937  * So until that is fixed, skip realloc() here unless MEMORY_DEBUG is set to
938  * a value greater than 1. We do this in order at least make MEMORY_DEBUG
939  * slightly useful.
940  */
941 #if MEMORY_DEBUG > 1
942  op = realloc(op, sizeof(object));
943 #endif
944  SET_FLAG(op, FLAG_REMOVED);
945  SET_FLAG(op, FLAG_FREED);
946 #endif
947 
948  if (!QUERY_FLAG(op, FLAG_FREED)) {
949  LOG(llevError, "Fatal: Getting busy object.\n");
950 #ifdef MANY_CORES
951  abort();
952 #endif
953  }
954  free_objects = op->next;
955  if (free_objects != NULL)
956  free_objects->prev = NULL;
957  op->count = ++ob_count;
958  op->name = NULL;
959  op->name_pl = NULL;
960  op->title = NULL;
961  op->race = NULL;
962  op->slaying = NULL;
963  op->skill = NULL;
964  op->lore = NULL;
965  op->msg = NULL;
966  op->materialname = NULL;
967  op->next = objects;
968  op->prev = NULL;
969  op->active_next = NULL;
970  op->active_prev = NULL;
971  op->discrete_damage = NULL;
972  op->spell_tags = NULL;
973  if (objects != NULL)
974  objects->prev = op;
975  objects = op;
976  clear_object(op);
977  SET_FLAG(op, FLAG_REMOVED);
978  nroffreeobjects--;
979  return op;
980 }
981 
990 void update_turn_face(object *op) {
991  if (!QUERY_FLAG(op, FLAG_IS_TURNABLE) || op->arch == NULL)
992  return;
993  SET_ANIMATION(op, op->direction);
995 }
996 
1008 void update_ob_speed(object *op) {
1009  /* FIXME what the hell is this crappy hack?*/
1010  extern int arch_init;
1011 
1012  /* No reason putting the archetypes objects on the speed list,
1013  * since they never really need to be updated.
1014  */
1015 
1016  if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
1017  LOG(llevError, "Object %s is freed but has speed.\n", op->name);
1018 #ifdef MANY_CORES
1019  abort();
1020 #else
1021  op->speed = 0;
1022 #endif
1023  }
1024  if (arch_init) {
1025  return;
1026  }
1027  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
1028  /* If already on active list, don't do anything */
1029  /* TODO this check can probably be simplified a lot */
1030  if (op->active_next || op->active_prev || op == active_objects)
1031  return;
1032 
1033  /* process_events() expects us to insert the object at the beginning
1034  * of the list. */
1036  if (op->active_next != NULL)
1037  op->active_next->active_prev = op;
1038  active_objects = op;
1039  } else {
1040  /* If not on the active list, nothing needs to be done */
1041  if (!op->active_next && !op->active_prev && op != active_objects)
1042  return;
1043 
1044  if (op->active_prev == NULL) {
1045  active_objects = op->active_next;
1046  if (op->active_next != NULL)
1047  op->active_next->active_prev = NULL;
1048  } else {
1049  op->active_prev->active_next = op->active_next;
1050  if (op->active_next)
1051  op->active_next->active_prev = op->active_prev;
1052  }
1053  op->active_next = NULL;
1054  op->active_prev = NULL;
1055  }
1056 }
1057 
1070 void remove_from_active_list(object *op) {
1071  /* If not on the active list, nothing needs to be done */
1072  if (!op->active_next && !op->active_prev && op != active_objects)
1073  return;
1074 
1075  if (op->active_prev == NULL) {
1076  active_objects = op->active_next;
1077  if (op->active_next != NULL)
1078  op->active_next->active_prev = NULL;
1079  } else {
1080  op->active_prev->active_next = op->active_next;
1081  if (op->active_next)
1082  op->active_next->active_prev = op->active_prev;
1083  }
1084  op->active_next = NULL;
1085  op->active_prev = NULL;
1086 }
1087 
1112 void update_object(object *op, int action) {
1113  int update_now = 0, flags;
1114  MoveType move_on, move_off, move_block, move_slow;
1115  object *pl;
1116 
1117  if (op == NULL) {
1118  /* this should never happen */
1119  LOG(llevDebug, "update_object() called for NULL object.\n");
1120  return;
1121  }
1122 
1123  if (op->env != NULL) {
1124  /* Animation is currently handled by client, so nothing
1125  * to do in this case.
1126  */
1127  return;
1128  }
1129 
1130  /* If the map is saving, don't do anything as everything is
1131  * going to get freed anyways.
1132  */
1133  if (!op->map || op->map->in_memory == MAP_SAVING)
1134  return;
1135 
1136  /* make sure the object is within map boundaries */
1137  if (op->x < 0 || op->x >= MAP_WIDTH(op->map)
1138  || op->y < 0 || op->y >= MAP_HEIGHT(op->map)) {
1139  LOG(llevError, "update_object() called for object out of map!\n");
1140 #ifdef MANY_CORES
1141  abort();
1142 #endif
1143  return;
1144  }
1145 
1146  flags = GET_MAP_FLAGS(op->map, op->x, op->y);
1147  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NEED_UPDATE);
1148  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
1149  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
1150  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
1151  move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y);
1152 
1153  if (action == UP_OBJ_INSERT) {
1155  update_now = 1;
1156 
1157  if (QUERY_FLAG(op, FLAG_NO_MAGIC) && !(flags&P_NO_MAGIC))
1158  update_now = 1;
1159 
1160  if (QUERY_FLAG(op, FLAG_DAMNED) && !(flags&P_NO_CLERIC))
1161  update_now = 1;
1162 
1163  if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags&P_IS_ALIVE))
1164  update_now = 1;
1165 
1166  if ((move_on|op->move_on) != move_on)
1167  update_now = 1;
1168  if ((move_off|op->move_off) != move_off)
1169  update_now = 1;
1170  /* This isn't perfect, but I don't expect a lot of objects to
1171  * to have move_allow right now.
1172  */
1173  if (((move_block|op->move_block)&~op->move_allow) != move_block)
1174  update_now = 1;
1175  if ((move_slow|op->move_slow) != move_slow)
1176  update_now = 1;
1177 
1178  if (op->type == PLAYER)
1179  update_now = 1;
1180  /* if the object is being removed, we can't make intelligent
1181  * decisions, because remove_ob can't really pass the object
1182  * that is being removed.
1183  */
1184  } else if (action == UP_OBJ_REMOVE) {
1185  update_now = 1;
1186  } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) {
1187  /* In addition to sending info to client, need to update space
1188  * information.
1189  */
1190  if (action == UP_OBJ_CHANGE)
1191  update_now = 1;
1192 
1193  /* There is a player on this space - we may need to send an
1194  * update to the client.
1195  * If this object is supposed to be animated by the client,
1196  * nothing to do here - let the client animate it.
1197  * We can't use FLAG_ANIMATE, as that is basically set for
1198  * all objects with multiple faces, regardless if they are animated.
1199  * (levers have it set for example).
1200  */
1201  if (flags&P_PLAYER
1204  pl = GET_MAP_PLAYER(op->map, op->x, op->y);
1205 
1206  /* If update_look is set, we're going to send this entire space
1207  * to the client, so no reason to send face information now.
1208  */
1209  if (!pl->contr->socket.update_look) {
1210  esrv_update_item(UPD_FACE, pl, op);
1211  }
1212  }
1213  } else {
1214  LOG(llevError, "update_object called with invalid action: %d\n", action);
1215  }
1216 
1217  if (update_now) {
1218  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NO_ERROR|P_NEED_UPDATE);
1219  update_position(op->map, op->x, op->y);
1220  }
1221 
1222  if (op->more != NULL)
1223  update_object(op->more, action);
1224 }
1225 
1238 void free_object(object *ob) {
1239  free_object2(ob, 0);
1240 }
1241 
1258 void free_object2(object *ob, int free_inventory) {
1259  object *tmp, *op;
1260 
1261  if (!QUERY_FLAG(ob, FLAG_REMOVED)) {
1262  StringBuffer *sb;
1263  char *diff;
1264 
1265  LOG(llevDebug, "Free object called with non removed object\n");
1266  sb = stringbuffer_new();
1267  dump_object(ob, sb);
1268  diff = stringbuffer_finish(sb);
1269  LOG(llevError, diff);
1270  free(diff);
1271 #ifdef MANY_CORES
1272  abort();
1273 #endif
1274  }
1275  if (QUERY_FLAG(ob, FLAG_FRIENDLY)) {
1276  LOG(llevMonster, "Warning: tried to free friendly object.\n");
1278  }
1279  if (QUERY_FLAG(ob, FLAG_FREED)) {
1280  StringBuffer *sb;
1281  char *diff;
1282 
1283  sb = stringbuffer_new();
1284  dump_object(ob, sb);
1285  diff = stringbuffer_finish(sb);
1286  LOG(llevError, "Trying to free freed object.\n%s\n", diff);
1287  free(diff);
1288  return;
1289  }
1290 
1291  /* Handle for plugin destroy event */
1292  execute_event(ob, EVENT_DESTROY, NULL, NULL, NULL, SCRIPT_FIX_NOTHING);
1293 
1294  if (ob->inv) {
1295  /* Only if the space blocks everything do we not process -
1296  * if some form of movemnt is allowed, let objects
1297  * drop on that space.
1298  */
1299  if (free_inventory
1300  || ob->map == NULL
1301  || ob->map->in_memory != MAP_IN_MEMORY
1302  || (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL)) {
1303  op = ob->inv;
1304  while (op != NULL) {
1305  tmp = op->below;
1306  remove_ob(op);
1307  free_object2(op, free_inventory);
1308  op = tmp;
1309  }
1310  } else { /* Put objects in inventory onto this space */
1311  op = ob->inv;
1312  while (op != NULL) {
1313  tmp = op->below;
1314  remove_ob(op);
1316  || op->type == RUNE
1317  || op->type == TRAP
1319  free_object(op);
1320  else {
1321  object *part;
1322 
1323  /* If it's a multi-tile object, scatter dropped items randomly */
1324  if (ob->more) {
1325  int partcount = 0;
1326  /* Get the number of non-head parts */
1327  for (part = ob; part; part = part->more) {
1328  partcount++;
1329  }
1330  /* Select a random part */
1331  partcount = RANDOM()%partcount;
1332  for (part = ob; partcount > 0; partcount--) {
1333  part = part->more;
1334  }
1335  } else {
1336  part = ob;
1337  }
1338 
1339  if (QUERY_FLAG(op, FLAG_ALIVE)) {
1340  int pos;
1341 
1342  pos = find_free_spot(op, part->map, part->x, part->y, 0, SIZEOFFREE);
1343  if (pos == -1)
1344  free_object(op);
1345  else {
1346  op->x = part->x+freearr_x[pos];
1347  op->y = part->y+freearr_y[pos];
1348  insert_ob_in_map(op, part->map, NULL, 0); /* Insert in same map as the envir */
1349  }
1350  } else {
1351  op->x = part->x;
1352  op->y = part->y;
1353  insert_ob_in_map(op, part->map, NULL, 0); /* Insert in same map as the envir */
1354  }
1355  }
1356  op = tmp;
1357  }
1358  }
1359  }
1360 
1361  if (ob->more != NULL) {
1362  free_object2(ob->more, free_inventory);
1363  ob->more = NULL;
1364  }
1365 
1366  /* Remove object from the active list */
1367  ob->speed = 0;
1368  update_ob_speed(ob);
1369 
1370  SET_FLAG(ob, FLAG_FREED);
1371  ob->count = 0;
1372 
1373  /* Remove this object from the list of used objects */
1374  if (ob->prev == NULL) {
1375  objects = ob->next;
1376  if (objects != NULL)
1377  objects->prev = NULL;
1378  } else {
1379  ob->prev->next = ob->next;
1380  if (ob->next != NULL)
1381  ob->next->prev = ob->prev;
1382  }
1383 
1384  if (ob->name != NULL) FREE_AND_CLEAR_STR(ob->name);
1385  if (ob->name_pl != NULL) FREE_AND_CLEAR_STR(ob->name_pl);
1386  if (ob->title != NULL) FREE_AND_CLEAR_STR(ob->title);
1387  if (ob->race != NULL) FREE_AND_CLEAR_STR(ob->race);
1388  if (ob->slaying != NULL) FREE_AND_CLEAR_STR(ob->slaying);
1389  if (ob->skill != NULL) FREE_AND_CLEAR_STR(ob->skill);
1390  if (ob->lore != NULL) FREE_AND_CLEAR_STR(ob->lore);
1391  if (ob->msg != NULL) FREE_AND_CLEAR_STR(ob->msg);
1392  if (ob->materialname != NULL) FREE_AND_CLEAR_STR(ob->materialname);
1393  if (ob->discrete_damage != NULL) FREE_AND_CLEAR(ob->discrete_damage);
1394  if (ob->spell_tags) FREE_AND_CLEAR(ob->spell_tags);
1395 
1396  /* Why aren't events freed? */
1397  free_key_values(ob);
1398 
1400 
1401  /* Test whether archetype is a temporary one, and if so look whether it should be trashed. */
1402  if (ob->arch && ob->arch->reference_count > 0) {
1403  if (--ob->arch->reference_count == 0) {
1404  free_arch(ob->arch);
1405  }
1406  }
1407 
1408 #if defined(MEMORY_DEBUG) && (MEMORY_DEBUG > 2)
1409  /* memset() to clear it then set flags and finally free it. This will
1410  * help detect bad use after return.
1411  */
1412  memset(ob, 0, sizeof(object));
1413  SET_FLAG(ob, FLAG_REMOVED);
1414  SET_FLAG(ob, FLAG_FREED);
1415  free(ob);
1416 #else
1417  /* Now link it with the free_objects list: */
1418  ob->prev = NULL;
1419  ob->next = free_objects;
1420  if (free_objects != NULL)
1421  free_objects->prev = ob;
1422  free_objects = ob;
1423  nroffreeobjects++;
1424 #endif
1425 }
1426 
1433 int count_free(void) {
1434  int i = 0;
1435  object *tmp = free_objects;
1436 
1437  while (tmp != NULL)
1438  tmp = tmp->next,
1439  i++;
1440  return i;
1441 }
1442 
1449 int count_used(void) {
1450  int i = 0;
1451  object *tmp = objects;
1452 
1453  while (tmp != NULL)
1454  tmp = tmp->next,
1455  i++;
1456  return i;
1457 }
1458 
1465 int count_active(void) {
1466  int i = 0;
1467  object *tmp = active_objects;
1468 
1469  while (tmp != NULL)
1470  tmp = tmp->active_next,
1471  i++;
1472  return i;
1473 }
1474 
1489 void sub_weight(object *op, signed long weight) {
1490  while (op != NULL) {
1491  if (op->type == CONTAINER) {
1492  weight = (signed long)(weight*(100-op->stats.Str)/100);
1493  }
1494  op->carrying -= weight;
1495  op = op->env;
1496  }
1497 }
1498 
1515 void remove_ob(object *op) {
1516  object *tmp, *last = NULL;
1517  object *otmp;
1518  tag_t tag;
1519  int check_walk_off;
1520  mapstruct *m;
1521  sint16 x, y;
1522 
1523  if (QUERY_FLAG(op, FLAG_REMOVED)) {
1524  StringBuffer *sb;
1525  char *diff;
1526 
1527  sb = stringbuffer_new();
1528  dump_object(op, sb);
1529  diff = stringbuffer_finish(sb);
1530  LOG(llevError, "Trying to remove removed object.\n%s\n", diff);
1531  free(diff);
1532  abort();
1533  }
1534  if (op->more != NULL)
1535  remove_ob(op->more);
1536 
1537  SET_FLAG(op, FLAG_REMOVED);
1538 
1539  /*
1540  * In this case, the object to be removed is in someones
1541  * inventory.
1542  */
1543  /* TODO try to call a generic inventory weight adjusting function like sub_weight */
1544  if (op->env != NULL) {
1545  if (op->nrof)
1546  sub_weight(op->env, op->weight*op->nrof);
1547  else
1548  sub_weight(op->env, op->weight+op->carrying);
1549 
1550  /* Update in two cases: item is in a player, or in a container the player is looking into. */
1551  if (op->env->contr != NULL && op->head == NULL) {
1552  if (LOOK_OBJ(op))
1553  esrv_del_item(op->env->contr, op->count);
1554  } else if (op->env->type == CONTAINER && QUERY_FLAG(op->env, FLAG_APPLIED)) {
1555  player *pl = NULL;
1556 
1557  if (op->env->env && op->env->env->contr)
1558  /* Container is in player's inventory. */
1559  pl = op->env->env->contr;
1560  else if (op->env->map) {
1561  /* Container on map, look above for player. */
1562  object *above = op->env->above;
1563 
1564  while (above && !above->contr)
1565  above = above->above;
1566  if (above)
1567  pl = above->contr;
1568  }
1569  if (pl && LOOK_OBJ(op))
1570  esrv_del_item(pl, op->count);
1571  }
1572 
1573  /* NO_FIX_PLAYER is set when a great many changes are being
1574  * made to players inventory. If set, avoiding the call
1575  * to save cpu time.
1576  */
1577  if ((otmp = get_player_container(op->env)) != NULL
1578  && otmp->contr
1579  && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
1580  fix_object(otmp);
1581 
1582  if (op->above != NULL)
1583  op->above->below = op->below;
1584  else
1585  op->env->inv = op->below;
1586 
1587  if (op->below != NULL)
1588  op->below->above = op->above;
1589 
1590  /* we set up values so that it could be inserted into
1591  * the map, but we don't actually do that - it is up
1592  * to the caller to decide what we want to do.
1593  */
1594  op->x = op->env->x;
1595  op->y = op->env->y;
1596  op->ox = op->x;
1597  op->oy = op->y;
1598  op->map = op->env->map;
1599  op->above = NULL;
1600  op->below = NULL;
1601  op->env = NULL;
1602  return;
1603  }
1604 
1605  /* If we get here, we are removing it from a map */
1606  if (op->map == NULL)
1607  return;
1608 
1609  if (op->contr != NULL && !op->contr->hidden)
1610  op->map->players--;
1611 
1612  x = op->x;
1613  y = op->y;
1614  m = get_map_from_coord(op->map, &x, &y);
1615 
1616  if (!m) {
1617  LOG(llevError, "remove_ob 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);
1618  abort();
1619  }
1620  if (op->map != m) {
1621  LOG(llevError, "remove_ob: 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);
1622  }
1623 
1624  /* link the object above us */
1625  if (op->above)
1626  op->above->below = op->below;
1627  else
1628  SET_MAP_TOP(m, x, y, op->below); /* we were top, set new top */
1629 
1630  /* Relink the object below us, if there is one */
1631  if (op->below) {
1632  op->below->above = op->above;
1633  } else {
1634  /* Nothing below, which means we need to relink map object for this space
1635  * use translated coordinates in case some oddness with map tiling is
1636  * evident
1637  */
1638  /*TODO is this check really needed?*/
1639  if (GET_MAP_OB(m, x, y) != op) {
1640  StringBuffer *sb;
1641  char *diff;
1642 
1643  sb = stringbuffer_new();
1644  dump_object(op, sb);
1645  diff = stringbuffer_finish(sb);
1646  LOG(llevError, "remove_ob: GET_MAP_OB does not return object to be removed even though it appears to be on the bottom?\n%s\n", diff);
1647  free(diff);
1648 
1649  sb = stringbuffer_new();
1650  dump_object(GET_MAP_OB(m, x, y), sb);
1651  diff = stringbuffer_finish(sb);
1652  LOG(llevError, "%s\n", diff);
1653  free(diff);
1654  }
1655  SET_MAP_OB(m, x, y, op->above); /* goes on above it. */
1656  }
1657  op->above = NULL;
1658  op->below = NULL;
1659 
1660  if (op->map->in_memory == MAP_SAVING)
1661  return;
1662 
1663  tag = op->count;
1664  check_walk_off = !QUERY_FLAG(op, FLAG_NO_APPLY);
1665  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) {
1666  /* No point updating the players look faces if he is the object
1667  * being removed.
1668  */
1669 
1670  if (tmp->type == PLAYER && tmp != op) {
1671  /* If a container that the player is currently using somehow gets
1672  * removed (most likely destroyed), update the player view
1673  * appropriately.
1674  */
1675  if (tmp->container == op) {
1676  CLEAR_FLAG(op, FLAG_APPLIED);
1677  tmp->container = NULL;
1678  }
1679  tmp->contr->socket.update_look = 1;
1680  }
1681  /* See if player moving off should effect something */
1682  if (check_walk_off
1683  && ((op->move_type&tmp->move_off) && (op->move_type&~tmp->move_off&~tmp->move_block) == 0)) {
1684  ob_move_on(tmp, op, NULL);
1685  if (was_destroyed(op, tag)) {
1686  LOG(llevError, "BUG: remove_ob(): name %s, archname %s destroyed leaving object\n", tmp->name, tmp->arch->name);
1687  }
1688  }
1689 
1690  /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
1691  if (tmp->above == tmp)
1692  tmp->above = NULL;
1693  last = tmp;
1694  }
1695  /* last == NULL or there are no objects on this space */
1696  if (last == NULL) {
1697  /* set P_NEED_UPDATE, otherwise update_position will complain. In theory,
1698  * we could preserve the flags (GET_MAP_FLAGS), but update_position figures
1699  * those out anyways, and if there are any flags set right now, they won't
1700  * be correct anyways.
1701  */
1702  SET_MAP_FLAGS(op->map, op->x, op->y, P_NEED_UPDATE);
1703  update_position(op->map, op->x, op->y);
1704  } else
1706 
1707  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW)|| (op->glow_radius != 0))
1708  update_all_los(op->map, op->x, op->y);
1709 }
1710 
1724 object *merge_ob(object *op, object *top) {
1725  if (!op->nrof)
1726  return NULL;
1727 
1728  if (top == NULL)
1729  for (top = op; top != NULL && top->above != NULL; top = top->above)
1730  ;
1731  for (; top != NULL; top = top->below) {
1732  if (top == op)
1733  continue;
1734  if (can_merge(op, top)) {
1735  increase_ob_nr(top, op->nrof);
1736  op->weight = 0; /* Don't want any adjustements now */
1737  remove_ob(op);
1738  free_object(op);
1739  return top;
1740  }
1741  }
1742  return NULL;
1743 }
1744 
1761 object *insert_ob_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y) {
1762  object *tmp;
1763 
1764  if (op->head)
1765  op = op->head;
1766  for (tmp = op; tmp; tmp = tmp->more) {
1767  tmp->x = x+tmp->arch->clone.x;
1768  tmp->y = y+tmp->arch->clone.y;
1769  if (op != tmp && !tmp->map)
1770  tmp->map = op->map ? op->map : m;
1771  }
1772  return insert_ob_in_map(op, m, originator, flag);
1773 }
1774 
1792 void merge_spell(object *op, sint16 x, sint16 y) {
1793  object *tmp, *above;
1794  int i;
1795 
1796  /* We try to do some merging of spell objects - if something has same owner,
1797  * is same type of spell, and going in the same direction, it is somewhat
1798  * mergable.
1799  *
1800  * If the spell object has an other_arch, don't merge - when the spell
1801  * does something, like explodes, it will use this other_arch, and
1802  * if we merge, there is no easy way to make the correct values be
1803  * set on this new object (values should be doubled, tripled, etc.)
1804  *
1805  * We also care about speed - only process objects that will not be
1806  * active this tick. Without this, the results are incorrect - think
1807  * of a case where tmp would normally get processed this tick, but
1808  * get merges with op, which does not get processed.
1809  */
1810  for (tmp = GET_MAP_OB(op->map, x, y); tmp != NULL; tmp = above) {
1811  above = tmp->above;
1812 
1813  if (op->type == tmp->type
1814  && op->subtype == tmp->subtype
1815  && op->direction == tmp->direction
1816  && op->owner == tmp->owner && op->ownercount == tmp->ownercount
1817  && op->range == tmp->range
1818  && op->stats.wc == tmp->stats.wc
1819  && op->level == tmp->level
1820  && op->attacktype == tmp->attacktype
1821  && op->speed == tmp->speed
1822  && !tmp->other_arch
1823  && (tmp->speed_left+tmp->speed) < 0.0
1824  && op != tmp) {
1825  /* Quick test - if one or the other objects already have hash tables
1826  * set up, and that hash bucket contains a value that doesn't
1827  * match what we want to set it up, we won't be able to merge.
1828  * Note that these two if statements are the same, except
1829  * for which object they are checking against. They could
1830  * be merged, but the line wrapping would be large enough
1831  * that IMO it would become difficult to read the different clauses
1832  * so its cleaner just to do 2 statements - MSW
1833  */
1834  if (op->spell_tags
1835  && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)
1836  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0)
1837  continue;
1838 
1839  if (tmp->spell_tags
1840  && !OB_SPELL_TAG_MATCH(tmp, op->stats.maxhp)
1841  && OB_SPELL_TAG_HASH(tmp, op->stats.maxhp) != 0)
1842  continue;
1843 
1844  /* If we merge, the data from tmp->spell_tags gets copied into op.
1845  * so we need to make sure that slot isn't filled up.
1846  */
1847  if (tmp->spell_tags
1848  && !OB_SPELL_TAG_MATCH(tmp, tmp->stats.maxhp)
1849  && OB_SPELL_TAG_HASH(tmp, tmp->stats.maxhp) != 0)
1850  continue;
1851 
1852  /* If both objects have spell_tags, we need to see if there are conflicting
1853  * values - if there are, we won't be able to merge then.
1854  */
1855  if (tmp->spell_tags && op->spell_tags) {
1856  int need_copy = 0;
1857 
1858  for (i = 0; i < SPELL_TAG_SIZE; i++) {
1859  /* If the two tag values in the hash are set, but are
1860  * not set to the same value, then these objects
1861  * can not be merged.
1862  */
1863  if (op->spell_tags[i] && tmp->spell_tags[i]
1864  && op->spell_tags[i] != tmp->spell_tags[i]) {
1866  break;
1867  }
1868  /* If one tag is set and the other is not, that is
1869  * fine, but we have to note that we need to copy
1870  * the data in that case.
1871  */
1872  if ((!op->spell_tags[i] && tmp->spell_tags[i])
1873  || (op->spell_tags[i] && !tmp->spell_tags[i])) {
1874  need_copy = 1;
1875  }
1876  }
1877  /* If we did not get through entire array, it means
1878  * we got a conflicting hash, and so we won't be
1879  * able to merge these - just continue processing
1880  * object on this space.
1881  */
1882  if (i <= SPELL_TAG_SIZE)
1883  continue;
1884 
1885  /* Ok - everything checked out - we should be able to
1886  * merge tmp in op. So lets copy the tag data if
1887  * needed. Note that this is a selective copy, as
1888  * we don't want to clear values that may be set in op.
1889  */
1890  if (need_copy) {
1891  for (i = 0; i < SPELL_TAG_SIZE; i++)
1892  if (!op->spell_tags[i]
1893  && tmp->spell_tags[i]
1894  && tmp->spell_tags[i] != op->stats.maxhp)
1895  op->spell_tags[i] = tmp->spell_tags[i];
1896  }
1897  FREE_AND_CLEAR(tmp->spell_tags);
1898  }
1899 
1900  /* if tmp has a spell_tags table, copy it to op and free tmps */
1901  if (tmp->spell_tags && !op->spell_tags) {
1902  op->spell_tags = tmp->spell_tags;
1903  tmp->spell_tags = NULL;
1904 
1905  /* We don't need to keep a copy of our maxhp value
1906  * in the copied over value
1907  */
1908  if (OB_SPELL_TAG_MATCH(op, op->stats.maxhp))
1909  OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0;
1910  }
1911 
1912  /* For spells to work correctly, we need to record what spell
1913  * tags we've merged in with this effect. This is used
1914  * in ok_to_put_more() to see if a spell effect is already on
1915  * the space.
1916  */
1917  if (op->stats.maxhp != tmp->stats.maxhp) {
1918 #ifdef OBJECT_DEBUG
1919  /* This if statement should never happen - the logic above should
1920  * have prevented it. It is a problem, because by now its possible
1921  * we've destroyed the spell_tags in tmp, so we can't really
1922  * just bail out.
1923  */
1924 
1925  if (op->spell_tags
1926  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0
1927  && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)) {
1928  LOG(llevError, "insert_ob_in_map: Got non matching spell tags: %d != %d\n", OB_SPELL_TAG_HASH(op, tmp->stats.maxhp), tmp->stats.maxhp);
1929  }
1930 #endif
1931  if (!op->spell_tags)
1932  op->spell_tags = calloc(1, SPELL_TAG_SIZE*sizeof(tag_t));
1933 
1934  OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) = tmp->stats.maxhp;
1935  }
1936 
1938  op->speed_left = MAX(op->speed_left, tmp->speed_left);
1939 
1940  if (tmp->duration != op->duration) {
1941  /* We need to use tmp_dam here because otherwise the
1942  * calculations can overflow the size of stats.dam.
1943  */
1944  int tmp_dam = tmp->stats.dam*(tmp->duration+1)+
1945  op->stats.dam*(op->duration+1);
1946 
1947  op->duration = MAX(op->duration, tmp->duration);
1948  tmp_dam /= (op->duration+1);
1949  op->stats.dam = tmp_dam+1;
1950  } else {
1951  /* in this case, duration is the same, so simply adding
1952  * up damage works.
1953  */
1954  op->stats.dam += tmp->stats.dam;
1955  }
1956 
1957  remove_ob(tmp);
1958  free_object(tmp);
1959  }
1960  }
1961 }
1962 
1992 object *insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag) {
1993  object *tmp, *top, *floor = NULL;
1994  sint16 x, y;
1995 
1996  if (QUERY_FLAG(op, FLAG_FREED)) {
1997  LOG(llevError, "Trying to insert freed object!\n");
1998  return NULL;
1999  }
2000  if (m == NULL) {
2001  StringBuffer *sb;
2002  char *diff;
2003 
2004  sb = stringbuffer_new();
2005  dump_object(op, sb);
2006  diff = stringbuffer_finish(sb);
2007  LOG(llevError, "Trying to insert in null-map!\n%s\n", diff);
2008  free(diff);
2009  return op;
2010  }
2011  if (out_of_map(m, op->x, op->y)) {
2012  StringBuffer *sb;
2013  char *diff;
2014 
2015  sb = stringbuffer_new();
2016  dump_object(op, sb);
2017  diff = stringbuffer_finish(sb);
2018  LOG(llevError, "Trying to insert object outside the map.\n%s\n", diff);
2019  free(diff);
2020 #ifdef MANY_CORES
2021  /* Better to catch this here, as otherwise the next use of this object
2022  * is likely to cause a crash. Better to find out where it is getting
2023  * improperly inserted.
2024  */
2025  abort();
2026 #endif
2027  return op;
2028  }
2029  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2030  StringBuffer *sb;
2031  char *diff;
2032 
2033  sb = stringbuffer_new();
2034  dump_object(op, sb);
2035  diff = stringbuffer_finish(sb);
2036  LOG(llevError, "Trying to insert (map) inserted object.\n%s\n", diff);
2037  free(diff);
2038  return op;
2039  }
2040  if (op->more != NULL) {
2041  /* The part may be on a different map. */
2042 
2043  object *more = op->more;
2044 
2045  /* We really need the caller to normalize coordinates - if
2046  * we set the map, that doesn't work if the location is within
2047  * a map and this is straddling an edge. So only if coordinate
2048  * is clear wrong do we normalize it.
2049  */
2050  if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
2051  /* Debugging information so you can see the last coordinates this object had */
2052  more->ox = more->x;
2053  more->oy = more->y;
2054  more->map = get_map_from_coord(m, &more->x, &more->y);
2055  } else if (!more->map) {
2056  /* For backwards compatibility - when not dealing with tiled maps,
2057  * more->map should always point to the parent.
2058  */
2059  more->map = m;
2060  }
2061 
2062  if (insert_ob_in_map(more, more->map, originator, flag) == NULL) {
2063  if (!op->head)
2064  LOG(llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n");
2065  return NULL;
2066  }
2067  }
2068  CLEAR_FLAG(op, FLAG_REMOVED);
2069 
2070  /* Debugging information so you can see the last coordinates this object had */
2071  op->ox = op->x;
2072  op->oy = op->y;
2073  x = op->x;
2074  y = op->y;
2075  op->map = get_map_from_coord(m, &x, &y);
2076 
2077  /* this has to be done after we translate the coordinates. */
2078  if (op->nrof
2079  && !(flag&INS_NO_MERGE)
2080  && op->type != SPELL_EFFECT) {
2081  for (tmp = GET_MAP_OB(op->map, x, y); tmp != NULL; tmp = tmp->above) {
2082  if (can_merge(op, tmp)) {
2083  op->nrof += tmp->nrof;
2084  remove_ob(tmp);
2085  free_object(tmp);
2086  }
2087  }
2088  } else if (op->type == SPELL_EFFECT
2089  && !op->range
2090  && !op->other_arch
2091  && (op->speed_left+op->speed) < 0.0) {
2092  merge_spell(op, x, y);
2093  }
2094 
2095  /* Ideally, the caller figures this out. However, it complicates a lot
2096  * of areas of callers (eg, anything that uses find_free_spot would now
2097  * need extra work
2098  */
2099  if (op->map != m) {
2100  /* coordinates should not change unless map also changes */
2101  op->x = x;
2102  op->y = y;
2103  }
2104 
2105  if (op->type != LAMP)
2106  /* lamps use the FLAG_APPLIED to keep the light/unlit status, so don't reset it.
2107  Other objects just get unapplied, since the container "drops" them. */
2108  CLEAR_FLAG(op, FLAG_APPLIED);
2110  if (!QUERY_FLAG(op, FLAG_ALIVE))
2112 
2113  /* In many places, a player is passed as the originator, which
2114  * is fine. However, if the player is on a transport, they are not
2115  * actually on the map, so we can't use them for the linked pointers,
2116  * nor should the walk on function below use them either.
2117  */
2118  if (originator && originator->contr && originator->contr->transport)
2119  originator = originator->contr->transport;
2120 
2121  if (flag&INS_BELOW_ORIGINATOR) {
2122  if (originator->map != op->map
2123  || originator->x != op->x
2124  || originator->y != op->y) {
2125  LOG(llevError, "insert_ob_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
2126  abort();
2127  }
2128  op->above = originator;
2129  op->below = originator->below;
2130  if (op->below)
2131  op->below->above = op;
2132  else
2133  SET_MAP_OB(op->map, op->x, op->y, op);
2134  /* since *below *originator, no need to update top */
2135  originator->below = op;
2136  } else {
2137  /* If there are other objects, then */
2138  /* This test is incorrect i think, as ins_above_floor_only needs the floor variable
2139  if ((!(flag&INS_MAP_LOAD)) && ((top = GET_MAP_OB(op->map, op->x, op->y)) != NULL)) {
2140  */
2141  if (((top = GET_MAP_OB(op->map, op->x, op->y)) != NULL)) {
2142  object *last = NULL;
2143 
2144  /*
2145  * If there are multiple objects on this space, we do some trickier handling.
2146  * We've already dealt with merging if appropriate.
2147  * Generally, we want to put the new object on top. But if
2148  * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
2149  * floor, we want to insert above that and no further.
2150  * Also, if there are spell objects on this space, we stop processing
2151  * once we get to them. This reduces the need to traverse over all of
2152  * them when adding another one - this saves quite a bit of cpu time
2153  * when lots of spells are cast in one area. Currently, it is presumed
2154  * that flying non pickable objects are spell objects.
2155  */
2156 
2157  while (top != NULL) {
2158  if (QUERY_FLAG(top, FLAG_IS_FLOOR)
2159  || QUERY_FLAG(top, FLAG_OVERLAY_FLOOR))
2160  floor = top;
2161 
2162  if (QUERY_FLAG(top, FLAG_NO_PICK)
2164  && !QUERY_FLAG(top, FLAG_IS_FLOOR)) {
2165  /* We insert above top, so we want this object below this */
2166  top = top->below;
2167  break;
2168  }
2169  last = top;
2170  top = top->above;
2171  }
2172  /* Don't want top to be NULL, so set it to the last valid object */
2173  top = last;
2174 
2175  /* We let update_position deal with figuring out what the space
2176  * looks like instead of lots of conditions here.
2177  * makes things faster, and effectively the same result.
2178  */
2179 
2180  } /* If objects on this space */
2181  if (flag&INS_MAP_LOAD)
2182  top = GET_MAP_TOP(op->map, op->x, op->y);
2183  if (flag&INS_ABOVE_FLOOR_ONLY)
2184  top = floor;
2185 
2186  /* Top is the object that our object (op) is going to get inserted above. */
2187 
2188  /* First object on this space */
2189  if (!top) {
2190  op->above = GET_MAP_OB(op->map, op->x, op->y);
2191  if (op->above)
2192  op->above->below = op;
2193  op->below = NULL;
2194  SET_MAP_OB(op->map, op->x, op->y, op);
2195  } else { /* get inserted into the stack above top */
2196  op->above = top->above;
2197  if (op->above)
2198  op->above->below = op;
2199  op->below = top;
2200  top->above = op;
2201  }
2202  if (op->above == NULL)
2203  SET_MAP_TOP(op->map, op->x, op->y, op);
2204  } /* else not INS_BELOW_ORIGINATOR */
2205 
2206  if (op->type == PLAYER)
2207  op->contr->do_los = 1;
2208 
2209  /* If we have a floor, we know the player, if any, will be above
2210  * it, so save a few ticks and start from there.
2211  */
2212  if (!(flag&INS_MAP_LOAD))
2213  for (tmp = floor ? floor : GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) {
2214  if (tmp->type == PLAYER)
2215  tmp->contr->socket.update_look = 1;
2216  }
2217 
2218  /* If this object glows, it may affect lighting conditions that are
2219  * visible to others on this map. But update_all_los is really
2220  * an inefficient way to do this, as it means los for all players
2221  * on the map will get recalculated. The players could very well
2222  * be far away from this change and not affected in any way -
2223  * this should get redone to only look for players within range,
2224  * or just updating the P_NEED_UPDATE for spaces within this area
2225  * of effect may be sufficient.
2226  */
2227  if (MAP_DARKNESS(op->map) && (op->glow_radius != 0))
2228  update_all_los(op->map, op->x, op->y);
2229 
2230 
2231  /* updates flags (blocked, alive, no magic, etc) for this map space */
2233 
2234  if (op->contr && !op->contr->hidden)
2235  op->map->players++;
2236 
2237  /* Don't know if moving this to the end will break anything. However,
2238  * we want to have update_look set above before calling this.
2239  *
2240  * check_move_on() must be after this because code called from
2241  * check_move_on() depends on correct map flags (so functions like
2242  * blocked() and wall() work properly), and these flags are updated by
2243  * update_object().
2244  */
2245 
2246  /* if this is not the head or flag has been passed, don't check walk on status */
2247 
2248  if (!(flag&INS_NO_WALK_ON) && !op->head) {
2249  if (check_move_on(op, originator))
2250  return NULL;
2251 
2252  /* If we are a multi part object, lets work our way through the check
2253  * walk on's.
2254  */
2255  for (tmp = op->more; tmp != NULL; tmp = tmp->more)
2256  if (check_move_on(tmp, originator))
2257  return NULL;
2258  }
2259  return op;
2260 }
2261 
2271 void replace_insert_ob_in_map(const char *arch_string, object *op) {
2272  object *tmp;
2273  object *tmp1;
2274 
2275  /* first search for itself and remove any old instances */
2276  for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp1) {
2277  tmp1 = tmp->above;
2278  if (!strcmp(tmp->arch->name, arch_string)) { /* same archetype */
2279  remove_ob(tmp);
2280  free_object(tmp);
2281  }
2282  }
2283 
2284  tmp1 = arch_to_object(find_archetype(arch_string));
2285 
2286  tmp1->x = op->x;
2287  tmp1->y = op->y;
2288  insert_ob_in_map(tmp1, op->map, op, INS_BELOW_ORIGINATOR);
2289 }
2290 
2313 object *get_split_ob(object *orig_ob, uint32 nr, char *err, size_t size) {
2314  object *newob;
2315 
2316  if (orig_ob->nrof < nr) {
2317  /* If err is set, the caller knows that nr can be wrong (player trying to drop items), thus don't log that. */
2318  if (err)
2319  snprintf(err, size, "There are only %u %ss.", orig_ob->nrof ? orig_ob->nrof : 1, orig_ob->name);
2320  else
2321  LOG(llevDebug, "There are only %u %ss.\n", orig_ob->nrof ? orig_ob->nrof : 1, orig_ob->name);
2322  return NULL;
2323  }
2324  newob = object_create_clone(orig_ob);
2325  newob->nrof = nr;
2326  decrease_ob_nr(orig_ob, nr);
2327 
2328  return newob;
2329 }
2330 
2345 object *decrease_ob_nr(object *op, uint32 i) {
2346  object *tmp;
2347  player *pl;
2348 
2349  if (i == 0) /* objects with op->nrof require this check */
2350  return op;
2351 
2352  if (i > op->nrof)
2353  i = op->nrof;
2354 
2355  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2356  op->nrof -= i;
2357  } else if (op->env != NULL) {
2358  /* is this object in the players inventory, or sub container
2359  * therein?
2360  */
2361  tmp = get_player_container(op->env);
2362  /* nope. Is this a container the player has opened?
2363  * If so, set tmp to that player.
2364  * IMO, searching through all the players will mostly
2365  * likely be quicker than following op->env to the map,
2366  * and then searching the map for a player.
2367  */
2368  if (!tmp) {
2369  for (pl = first_player; pl; pl = pl->next)
2370  if (pl->ob->container == op->env)
2371  break;
2372  if (pl)
2373  tmp = pl->ob;
2374  else
2375  tmp = NULL;
2376  }
2377 
2378  if (i < op->nrof) {
2379  sub_weight(op->env, op->weight*i);
2380  op->nrof -= i;
2381  if (tmp) {
2382  esrv_update_item(UPD_NROF, tmp, op);
2383  }
2384  } else {
2385  remove_ob(op);
2386  op->nrof = 0;
2387  }
2388  } else {
2389  /* On a map. */
2390  if (i < op->nrof) {
2391  object *pl;
2392  op->nrof -= i;
2393 
2394  pl = GET_MAP_OB(op->map, op->x, op->y);
2395  while (pl && !pl->contr)
2396  pl = pl->above;
2397  if (pl && pl->contr)
2398  pl->contr->socket.update_look = 1;
2399  } else {
2400  remove_ob(op);
2401  op->nrof = 0;
2402  }
2403  }
2404 
2405  if (op->nrof) {
2406  return op;
2407  } else {
2408  free_object(op);
2409  return NULL;
2410  }
2411 }
2412 
2423 static void increase_ob_nr(object *op, uint32 i) {
2424  object *tmp;
2425  player *pl;
2426 
2427  if (i == 0) /* objects with op->nrof require this check */
2428  return;
2429 
2430  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2431  op->nrof += i;
2432  } else if (op->env != NULL) {
2433  /* is this object in the players inventory, or sub container
2434  * therein?
2435  */
2436  tmp = get_player_container(op->env);
2437  /* nope. Is this a container the player has opened?
2438  * If so, set tmp to that player.
2439  * IMO, searching through all the players will mostly
2440  * likely be quicker than following op->env to the map,
2441  * and then searching the map for a player.
2442  */
2443  if (!tmp) {
2444  for (pl = first_player; pl; pl = pl->next)
2445  if (pl->ob->container == op->env)
2446  break;
2447  if (pl)
2448  tmp = pl->ob;
2449  else
2450  tmp = NULL;
2451  }
2452 
2453  add_weight(op->env, op->weight*i);
2454  op->nrof += i;
2455  if (tmp) {
2456  esrv_update_item(UPD_NROF, tmp, op);
2457  }
2458  } else {
2459  /* On a map. */
2460  object *pl;
2461 
2462  op->nrof += i;
2463 
2464  pl = GET_MAP_OB(op->map, op->x, op->y);
2465  while (pl && !pl->contr)
2466  pl = pl->above;
2467  if (pl && pl->contr)
2468  pl->contr->socket.update_look = 1;
2469  }
2470 }
2471 
2486 void add_weight(object *op, signed long weight) {
2487  while (op != NULL) {
2488  if (op->type == CONTAINER) {
2489  weight = (signed long)(weight*(100-op->stats.Str)/100);
2490  }
2491  op->carrying += weight;
2492  op = op->env;
2493  }
2494 }
2495 
2510 object *insert_ob_in_ob(object *op, object *where) {
2511  object *tmp, *otmp;
2512 
2513  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2514  StringBuffer *sb;
2515  char *diff;
2516 
2517  sb = stringbuffer_new();
2518  dump_object(op, sb);
2519  diff = stringbuffer_finish(sb);
2520  LOG(llevError, "Trying to insert (ob) inserted object.\n%s\n", diff);
2521  free(diff);
2522  return op;
2523  }
2524 
2525  if (where == NULL) {
2526  StringBuffer *sb;
2527  char *diff;
2528 
2529  sb = stringbuffer_new();
2530  dump_object(op, sb);
2531  diff = stringbuffer_finish(sb);
2532  LOG(llevError, "Trying to put object in NULL.\n%s\n", diff);
2533  free(diff);
2534  return op;
2535  }
2536  if (where->head) {
2537  LOG(llevDebug, "Warning: Tried to insert object wrong part of multipart object.\n");
2538  where = where->head;
2539  }
2540  if (op->more) {
2541  LOG(llevError, "Tried to insert multipart object %s (%d)\n", op->name, op->count);
2542  return op;
2543  }
2545  CLEAR_FLAG(op, FLAG_REMOVED);
2546  if (op->nrof) {
2547  for (tmp = where->inv; tmp != NULL; tmp = tmp->below)
2548  if (can_merge(tmp, op)) {
2549  /* return the original object and remove inserted object
2550  * (client needs the original object) */
2551  increase_ob_nr(tmp, op->nrof);
2552  SET_FLAG(op, FLAG_REMOVED);
2553  free_object(op); /* free the inserted object */
2554  return tmp;
2555  }
2556 
2557  /* the item couldn't merge. */
2558  add_weight(where, op->weight*op->nrof);
2559  } else
2560  add_weight(where, (op->weight+op->carrying));
2561 
2562  op->map = NULL;
2563  op->env = where;
2564  op->above = NULL;
2565  op->below = NULL;
2566  op->x = 0,
2567  op->y = 0;
2568  op->ox = 0,
2569  op->oy = 0;
2570 
2571  /* Client has no idea of ordering so lets not bother ordering it here.
2572  * It sure simplifies this function...
2573  */
2574  if (where->inv == NULL)
2575  where->inv = op;
2576  else {
2577  op->below = where->inv;
2578  op->below->above = op;
2579  where->inv = op;
2580  }
2581 
2582  /* Update in 2 cases: object goes into player's inventory, or object goes into container the player
2583  * is looking into. */
2584  if (where->contr != NULL)
2585  esrv_send_item(where, op);
2586  else if (where->type == CONTAINER && QUERY_FLAG(where, FLAG_APPLIED)) {
2587  object *pl = NULL;
2588 
2589  if (op->env->env && op->env->env->contr)
2590  /* Container is in player's inventory. */
2591  pl = op->env->env;
2592  else if (op->env->map) {
2593  /* Container on map, look above for player. */
2594  object *above = op->env->above;
2595 
2596  while (above && !above->contr)
2597  above = above->above;
2598  if (above)
2599  pl = above;
2600  }
2601  if (pl)
2602  esrv_send_item(pl, op);
2603  }
2604 
2605  otmp = get_player_container(where);
2606  if (otmp && otmp->contr != NULL) {
2607  if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER)
2608  && (QUERY_FLAG(op, FLAG_APPLIED) || (op->type == SKILL) || (op->glow_radius != 0)))
2609  /* fix_object will only consider applied items, or skills, or items with a glow radius.
2610  thus no need to call it if our object hasn't that. */
2611  fix_object(otmp);
2612  }
2613 
2614  /* reset the light list and los of the players on the map */
2615  if ((op->glow_radius != 0) && where->map) {
2616 #ifdef DEBUG_LIGHTS
2617  LOG(llevDebug, " insert_ob_in_ob(): got %s to insert in map/op\n", op->name);
2618 #endif /* DEBUG_LIGHTS */
2619  if (MAP_DARKNESS(where->map)) {
2620  SET_MAP_FLAGS(where->map, where->x, where->y, P_NEED_UPDATE);
2621  update_position(where->map, where->x, where->y);
2622  update_all_los(where->map, where->x, where->y);
2623  }
2624  }
2625 
2626  return op;
2627 }
2628 
2651 int check_move_on(object *op, object *originator) {
2652  object *tmp;
2653  tag_t tag;
2654  mapstruct *m = op->map;
2655  int x = op->x, y = op->y;
2656  MoveType move_on, move_slow, move_block;
2657 
2658  if (QUERY_FLAG(op, FLAG_NO_APPLY))
2659  return 0;
2660 
2661  tag = op->count;
2662 
2663  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
2664  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
2665  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
2666 
2667  /* if nothing on this space will slow op down or be applied,
2668  * no need to do checking below. have to make sure move_type
2669  * is set, as lots of objects don't have it set - we treat that
2670  * as walking.
2671  */
2672  if (op->move_type
2673  && !(op->move_type&move_on)
2674  && !(op->move_type&move_slow))
2675  return 0;
2676 
2677  /* This is basically inverse logic of that below - basically,
2678  * if the object can avoid the move on or slow move, they do so,
2679  * but can't do it if the alternate movement they are using is
2680  * blocked. Logic on this seems confusing, but does seem correct.
2681  */
2682  if ((op->move_type&~move_on&~move_block) != 0
2683  && (op->move_type&~move_slow&~move_block) != 0)
2684  return 0;
2685 
2686  /* The objects have to be checked from top to bottom.
2687  * Hence, we first go to the top:
2688  */
2689 
2690  for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL && tmp->above != NULL; tmp = tmp->above) {
2691  /* Trim the search when we find the first other spell effect
2692  * this helps performance so that if a space has 50 spell objects,
2693  * we don't need to check all of them.
2694  */
2695  if ((tmp->move_type&MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK))
2696  break;
2697  }
2698  for (; tmp != NULL; tmp = tmp->below) {
2699  if (tmp == op)
2700  continue; /* Can't apply yourself */
2701 
2702  /* Check to see if one of the movement types should be slowed down.
2703  * Second check makes sure that the movement types not being slowed
2704  * (~slow_move) is not blocked on this space - just because the
2705  * space doesn't slow down swimming (for example), if you can't actually
2706  * swim on that space, can't use it to avoid the penalty.
2707  */
2708  if (!QUERY_FLAG(op, FLAG_WIZPASS)) {
2709  if ((!op->move_type && tmp->move_slow&MOVE_WALK)
2710  || ((op->move_type&tmp->move_slow) && (op->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
2711  float diff;
2712 
2713  diff = tmp->move_slow_penalty*FABS(op->speed);
2714  if (op->type == PLAYER) {
2717  diff /= 4.0;
2718  }
2719  }
2720  op->speed_left -= diff;
2721  }
2722  }
2723 
2724  /* Basically same logic as above, except now for actual apply. */
2725  if ((!op->move_type && tmp->move_on&MOVE_WALK)
2726  || ((op->move_type&tmp->move_on) && (op->move_type&~tmp->move_on&~tmp->move_block) == 0)) {
2727 
2728  ob_move_on(tmp, op, originator);
2729  if (was_destroyed(op, tag))
2730  return 1;
2731 
2732  /* what the person/creature stepped onto has moved the object
2733  * someplace new. Don't process any further - if we did,
2734  * have a feeling strange problems would result.
2735  */
2736  if (op->map != m || op->x != x || op->y != y)
2737  return 0;
2738  }
2739  }
2740  return 0;
2741 }
2742 
2755 object *present_arch(const archetype *at, mapstruct *m, int x, int y) {
2756  object *tmp;
2757 
2758  if (m == NULL || out_of_map(m, x, y)) {
2759  LOG(llevError, "Present_arch called outside map.\n");
2760  return NULL;
2761  }
2762 
2763  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above)
2764  if (tmp->arch == at)
2765  return tmp;
2766  return NULL;
2767 }
2768 
2782 object *present(uint8 type, mapstruct *m, int x, int y) {
2783  object *tmp;
2784 
2785  if (out_of_map(m, x, y)) {
2786  LOG(llevError, "Present called outside map.\n");
2787  return NULL;
2788  }
2789 
2790  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above)
2791  if (tmp->type == type)
2792  return tmp;
2793  return NULL;
2794 }
2795 
2806 object *present_in_ob(uint8 type, const object *op) {
2807  object *tmp;
2808 
2809  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
2810  if (tmp->type == type)
2811  return tmp;
2812  return NULL;
2813 }
2814 
2840 object *present_in_ob_by_name(int type, const char *str, const object *op) {
2841  object *tmp;
2842 
2843  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
2844  if ((type == -1 || tmp->type == type) && (!strcmp(str, tmp->name)))
2845  return tmp;
2846  }
2847  return NULL;
2848 }
2849 
2859 object *present_arch_in_ob(const archetype *at, const object *op) {
2860  object *tmp;
2861 
2862  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
2863  if (tmp->arch == at)
2864  return tmp;
2865  return NULL;
2866 }
2867 
2876 void flag_inv(object*op, int flag) {
2877  object *tmp;
2878 
2879  if (op->inv)
2880  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
2881  SET_FLAG(tmp, flag);
2882  flag_inv(tmp, flag);
2883  }
2884 }
2885 
2894 void unflag_inv(object*op, int flag) {
2895  object *tmp;
2896 
2897  if (op->inv)
2898  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
2899  CLEAR_FLAG(tmp, flag);
2900  unflag_inv(tmp, flag);
2901  }
2902 }
2903 
2913 void set_cheat(object *op) {
2914  SET_FLAG(op, FLAG_WAS_WIZ);
2915  flag_inv(op, FLAG_WAS_WIZ);
2916 }
2917 
2935 int find_multi_free_spot_around(object *ob, object *gen, int *hx, int *hy) {
2936  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
2937  int freecount = 0;
2938 
2939  if (ob->head)
2940  ob = ob->head;
2941 
2942  get_multi_size(ob, &sx, &sy, &sx2, &sy2);
2943  get_multi_size(gen, &genx, &geny, &genx2, &geny2);
2944  /*
2945  * sx and sy are now the coords of the bottom right corner of ob relative to the head.
2946  * genx and geny are now the coords of the bottom right corner of gen relative to the head.
2947  * sx2 and sy2 are now the coords of the head of ob relative to the top left corner.
2948  * genx2 and geny2 are now the coords of the head of gen relative to the top left corner.
2949  */
2950 
2951  sx++;
2952  sy++;
2953  genx++;
2954  geny++;
2955  /*
2956  * sx, sy, genx, and geny, are now the size of the object, excluding parts left and above
2957  * the head.
2958  */
2959 
2960  ix = gen->x-sx-genx2;
2961  iy = gen->y-sy-geny2;
2962  sx += genx+sx2;
2963  sy += geny+sy2;
2964  /*
2965  * ix and iy are the map coords of the top left square where the head of ob could possibly
2966  * be placed. sx and sy are now the size of the square to search for placement of the head
2967  * relative to ix and iy.
2968  */
2969 
2970  /*
2971  * Loop around the square of possible positions for the head of ob object:
2972  */
2973  for (i = 0; i < (sx+sx+sy+sy); i++) {
2974  if (i <= sx) {
2975  nx = i+ix;
2976  ny = iy;
2977  } else if (i <= (sx+sy)) {
2978  nx = ix+sx;
2979  ny = iy+i-sx;
2980  } else if (i <= (sx+sy+sx)) {
2981  nx = ix+sx-(i-(sx+sy));
2982  ny = iy+sy;
2983  } else {
2984  nx = ix;
2985  ny = iy+sy-(i-(sx+sy+sx));
2986  }
2987  /* Check if the spot is free. */
2988  flag = ob_blocked(ob, gen->map, nx, ny);
2989  if (!flag) {
2990  freecount++;
2991  }
2992  }
2993  /* If no free spaces, return. */
2994  if (!freecount)
2995  return -1;
2996 
2997  /* Choose a random valid position */
2998  freecount = RANDOM()%freecount;
2999  for (i = 0; i < (sx+sx+sy+sy); i++) {
3000  if (i <= sx) {
3001  nx = i+ix;
3002  ny = iy;
3003  } else if (i <= (sx+sy)) {
3004  nx = ix+sx;
3005  ny = iy+i-sx;
3006  } else if (i <= (sx+sy+sx)) {
3007  nx = ix+sx-(i-(sx+sy));
3008  ny = iy+sy;
3009  } else {
3010  nx = ix;
3011  ny = iy+sy-(i-(sx+sy+sx));
3012  }
3013 
3014  /* Make sure it's within map. */
3015  if (nx < 0 || nx >= MAP_WIDTH(gen->map)
3016  || ny < 0 || ny >= MAP_HEIGHT(gen->map))
3017  continue;
3018 
3019  /* Check if the spot is free.*/
3020  flag = ob_blocked(ob, gen->map, nx, ny);
3021  if (!flag) {
3022  freecount--;
3023  if (freecount <= 0) {
3024  *hx = nx;
3025  *hy = ny;
3026  return 0;
3027  }
3028  }
3029  }
3030  return -1;
3031 }
3032 
3052 int find_multi_free_spot_within_radius(object *ob, object *gen, int *hx, int *hy) {
3053  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3054  sint8 x, y, radius;
3055  int freecount = 0, freecountstop = 0;
3056  const char *value;
3057  sint8 *x_array;
3058  sint8 *y_array;
3059 
3060  /* If radius is not set, default to 1 */
3061  value = get_ob_key_value(gen, "generator_radius");
3062  if (value) {
3063  radius = (sint8)strtol((char *)value, NULL, 10);
3064  if (radius < 1) {
3065  radius = 1;
3066  }
3067  } else {
3068  radius = 1;
3069  }
3070 
3071  if (ob->head)
3072  ob = ob->head;
3073 
3074  get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3075  get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3076  /*
3077  * sx and sy are now the coords of the bottom right corner
3078  * of ob relative to the head.
3079  * genx and geny are now the coords of the bottom right corner
3080  * of gen relative to the head.
3081  * sx2 and sy2 are now the coords of the head of ob relative
3082  * to the top left corner.
3083  * genx2 and geny2 are now the coords of the head of gen relative
3084  * to the top left corner.
3085  */
3086 
3087  sx++;
3088  sy++;
3089  genx++;
3090  geny++;
3091  /*
3092  * sx, sy, genx, and geny, are now the size of the object,
3093  * excluding parts left and above the head.
3094  */
3095 
3096  ix = gen->x-sx-genx2-radius+1;
3097  iy = gen->y-sy-geny2-radius+1;
3098  sx += genx+sx2+radius*2-1;
3099  sy += geny+sy2+radius*2-1;
3100 
3101  /*
3102  * ix and iy are the map coords of the top left square where
3103  * the head of ob could possibly be placed. sx and sy are now
3104  * the size of the square to search for placement of the head
3105  * relative to ix and iy.
3106  */
3107 
3108  /* Create arrays large enough to hold free space coordinates */
3109  x_array = malloc(sx*sy*sizeof(sint8));
3110  y_array = malloc(sx*sy*sizeof(sint8));
3111 
3112  /*
3113  * Loop through the area of possible positions for the head of ob object:
3114  */
3115  for (x = 0; x < sx; x++) {
3116  for (y = 0; y < sy; y++) {
3117  nx = ix+x;
3118  ny = iy+y;
3119 
3120 
3121  /* Make sure it's within map. */
3122  if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) {
3123  continue;
3124  }
3125 
3126  /* Check if the spot is free. */
3127  flag = ob_blocked(ob, gen->map, nx, ny);
3128  if (!flag) {
3129  x_array[freecount] = nx;
3130  y_array[freecount] = ny;
3131  freecount++;
3132  }
3133  }
3134  }
3135  /* If no free spaces, return. */
3136  if (!freecount) {
3137  free(x_array);
3138  free(y_array);
3139  return -1;
3140  }
3141 
3142  /* Choose a random valid position */
3143  freecountstop = RANDOM()%freecount;
3144  for (i = 0; i < freecount; i++) {
3145  nx = x_array[i];
3146  ny = y_array[i];
3147 
3148  /* Check if the spot is free.*/
3149  flag = ob_blocked(ob, gen->map, nx, ny);
3150  if (!flag) {
3151  freecountstop--;
3152  if (freecountstop <= 0) {
3153  *hx = nx;
3154  *hy = ny;
3155  free(x_array);
3156  free(y_array);
3157  return 0;
3158  }
3159  }
3160  }
3161  free(x_array);
3162  free(y_array);
3163  return -1;
3164 }
3165 
3200 int find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop) {
3201  int i, index = 0, flag;
3202  static int altern[SIZEOFFREE];
3203 
3204  for (i = start; i < stop; i++) {
3205  flag = ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]);
3206  if (!flag)
3207  altern[index++] = i;
3208 
3209  /* Basically, if we find a wall on a space, we cut down the search size.
3210  * In this way, we won't return spaces that are on another side of a wall.
3211  * This mostly work, but it cuts down the search size in all directions -
3212  * if the space being examined only has a wall to the north and empty
3213  * spaces in all the other directions, this will reduce the search space
3214  * to only the spaces immediately surrounding the target area, and
3215  * won't look 2 spaces south of the target space.
3216  */
3217  else if ((flag&AB_NO_PASS) && maxfree[i] < stop)
3218  stop = maxfree[i];
3219  }
3220  if (!index)
3221  return -1;
3222  return altern[RANDOM()%index];
3223 }
3224 
3240 int find_first_free_spot(const object *ob, mapstruct *m, int x, int y) {
3241  int i;
3242 
3243  for (i = 0; i < SIZEOFFREE; i++) {
3244  if (!ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]))
3245  return i;
3246  }
3247  return -1;
3248 }
3249 
3259 static void permute(int *arr, int begin, int end) {
3260  int i, j, tmp, len;
3261 
3262  len = end-begin;
3263  for (i = begin; i < end; i++) {
3264  j = begin+RANDOM()%len;
3265 
3266  tmp = arr[i];
3267  arr[i] = arr[j];
3268  arr[j] = tmp;
3269  }
3270 }
3271 
3283 void get_search_arr(int *search_arr) {
3284  int i;
3285 
3286  for (i = 0; i < SIZEOFFREE; i++) {
3287  search_arr[i] = i;
3288  }
3289 
3290  permute(search_arr, 1, SIZEOFFREE1+1);
3291  permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1);
3292  permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE);
3293 }
3294 
3313 int find_dir(mapstruct *m, int x, int y, object *exclude) {
3314  int i, max = SIZEOFFREE, mflags;
3315  sint16 nx, ny;
3316  object *tmp;
3317  mapstruct *mp;
3318  MoveType blocked, move_type;
3319 
3320  if (exclude && exclude->head) {
3321  exclude = exclude->head;
3322  move_type = exclude->move_type;
3323  } else {
3324  /* If we don't have anything, presume it can use all movement types. */
3325  move_type = MOVE_ALL;
3326  }
3327 
3328  for (i = 1; i < max; i++) {
3329  mp = m;
3330  nx = x+freearr_x[i];
3331  ny = y+freearr_y[i];
3332 
3333  mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny);
3334  if (mflags&P_OUT_OF_MAP) {
3335  max = maxfree[i];
3336  } else {
3337  blocked = GET_MAP_MOVE_BLOCK(mp, nx, ny);
3338 
3339  if ((move_type&blocked) == move_type) {
3340  max = maxfree[i];
3341  } else if (mflags&P_IS_ALIVE) {
3342  for (tmp = GET_MAP_OB(mp, nx, ny); tmp != NULL; tmp = tmp->above) {
3343  if ((QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type == PLAYER)
3344  && (tmp != exclude ||(tmp->head && tmp->head != exclude))) {
3345  break;
3346  }
3347  }
3348  if (tmp) {
3349  return freedir[i];
3350  }
3351  }
3352  }
3353  }
3354  return 0;
3355 }
3356 
3364 int distance(const object *ob1, const object *ob2) {
3365  int i;
3366 
3367  i = (ob1->x-ob2->x)*(ob1->x-ob2->x)+
3368  (ob1->y-ob2->y)*(ob1->y-ob2->y);
3369  return i;
3370 }
3371 
3380 int find_dir_2(int x, int y) {
3381  int q;
3382 
3383  if (!y)
3384  q = -300*x;
3385  else
3386  q = x*100/y;
3387  if (y > 0) {
3388  if (q < -242)
3389  return 3;
3390  if (q < -41)
3391  return 2;
3392  if (q < 41)
3393  return 1;
3394  if (q < 242)
3395  return 8;
3396  return 7;
3397  }
3398  if (q < -242)
3399  return 7;
3400  if (q < -41)
3401  return 6;
3402  if (q < 41)
3403  return 5;
3404  if (q < 242)
3405  return 4;
3406  return 3;
3407 }
3408 
3417 int absdir(int d) {
3418  while (d < 1)
3419  d += 8;
3420  while (d > 8)
3421  d -= 8;
3422  return d;
3423 }
3424 
3434 int dirdiff(int dir1, int dir2) {
3435  int d;
3436 
3437  d = abs(dir1-dir2);
3438  if (d > 4)
3439  d = 8-d;
3440  return d;
3441 }
3442 
3454 static const int reduction_dir[SIZEOFFREE][3] = {
3455  { 0, 0, 0 }, /* 0 */
3456  { 0, 0, 0 }, /* 1 */
3457  { 0, 0, 0 }, /* 2 */
3458  { 0, 0, 0 }, /* 3 */
3459  { 0, 0, 0 }, /* 4 */
3460  { 0, 0, 0 }, /* 5 */
3461  { 0, 0, 0 }, /* 6 */
3462  { 0, 0, 0 }, /* 7 */
3463  { 0, 0, 0 }, /* 8 */
3464  { 8, 1, 2 }, /* 9 */
3465  { 1, 2, -1 }, /* 10 */
3466  { 2, 10, 12 }, /* 11 */
3467  { 2, 3, -1 }, /* 12 */
3468  { 2, 3, 4 }, /* 13 */
3469  { 3, 4, -1 }, /* 14 */
3470  { 4, 14, 16 }, /* 15 */
3471  { 5, 4, -1 }, /* 16 */
3472  { 4, 5, 6 }, /* 17 */
3473  { 6, 5, -1 }, /* 18 */
3474  { 6, 20, 18 }, /* 19 */
3475  { 7, 6, -1 }, /* 20 */
3476  { 6, 7, 8 }, /* 21 */
3477  { 7, 8, -1 }, /* 22 */
3478  { 8, 22, 24 }, /* 23 */
3479  { 8, 1, -1 }, /* 24 */
3480  { 24, 9, 10 }, /* 25 */
3481  { 9, 10, -1 }, /* 26 */
3482  { 10, 11, -1 }, /* 27 */
3483  { 27, 11, 29 }, /* 28 */
3484  { 11, 12, -1 }, /* 29 */
3485  { 12, 13, -1 }, /* 30 */
3486  { 12, 13, 14 }, /* 31 */
3487  { 13, 14, -1 }, /* 32 */
3488  { 14, 15, -1 }, /* 33 */
3489  { 33, 15, 35 }, /* 34 */
3490  { 16, 15, -1 }, /* 35 */
3491  { 17, 16, -1 }, /* 36 */
3492  { 18, 17, 16 }, /* 37 */
3493  { 18, 17, -1 }, /* 38 */
3494  { 18, 19, -1 }, /* 39 */
3495  { 41, 19, 39 }, /* 40 */
3496  { 19, 20, -1 }, /* 41 */
3497  { 20, 21, -1 }, /* 42 */
3498  { 20, 21, 22 }, /* 43 */
3499  { 21, 22, -1 }, /* 44 */
3500  { 23, 22, -1 }, /* 45 */
3501  { 45, 47, 23 }, /* 46 */
3502  { 23, 24, -1 }, /* 47 */
3503  { 24, 9, -1 } /* 48 */
3504 };
3505 
3524 int can_see_monsterP(mapstruct *m, int x, int y, int dir) {
3525  sint16 dx, dy;
3526  int mflags;
3527 
3528  if (dir < 0)
3529  return 0; /* exit condition: invalid direction */
3530 
3531  dx = x+freearr_x[dir];
3532  dy = y+freearr_y[dir];
3533 
3534  mflags = get_map_flags(m, &m, dx, dy, &dx, &dy);
3535 
3536  /* This functional arguably was incorrect before - it was
3537  * checking for P_WALL - that was basically seeing if
3538  * we could move to the monster - this is being more
3539  * literal on if we can see it. To know if we can actually
3540  * move to the monster, we'd need the monster passed in or
3541  * at least its move type.
3542  */
3543  if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
3544  return 0;
3545 
3546  /* yes, can see. */
3547  if (dir < 9)
3548  return 1;
3549  return can_see_monsterP(m, x, y, reduction_dir[dir][0])|
3550  can_see_monsterP(m, x, y, reduction_dir[dir][1])|
3551  can_see_monsterP(m, x, y, reduction_dir[dir][2]);
3552 }
3553 
3569 int can_pick(const object *who, const object *item) {
3570  /* I re-wrote this as a series of if statements
3571  * instead of a nested return (foo & bar && yaz)
3572  * - I think this is much more readable,
3573  * and likely compiler effectively optimizes it the
3574  * same.
3575  */
3576  if (item->weight <= 0)
3577  return 0;
3578  if (QUERY_FLAG(item, FLAG_NO_PICK))
3579  return 0;
3580  if (QUERY_FLAG(item, FLAG_ALIVE))
3581  return 0;
3582  if (item->invisible)
3583  return 0;
3584 
3585  /* Weight limit for monsters */
3586  if (who->type != PLAYER && item->weight > (who->weight/3))
3587  return 0;
3588 
3589  /* Can not pick up multipart objects */
3590  if (item->head || item->more)
3591  return 0;
3592 
3593  /* Everything passes, so OK to pick up */
3594  return 1;
3595 }
3596 
3608 object *object_create_clone(object *asrc) {
3609  object *dst = NULL, *tmp, *src, *part, *prev, *item;
3610 
3611  if (!asrc)
3612  return NULL;
3613  src = asrc;
3614  if (src->head)
3615  src = src->head;
3616 
3617  prev = NULL;
3618  for (part = src; part; part = part->more) {
3619  tmp = get_object();
3620  copy_object(part, tmp);
3621  tmp->x -= src->x;
3622  tmp->y -= src->y;
3623  if (!part->head) {
3624  dst = tmp;
3625  tmp->head = NULL;
3626  } else {
3627  tmp->head = dst;
3628  }
3629  tmp->more = NULL;
3630  if (prev)
3631  prev->more = tmp;
3632  prev = tmp;
3633  }
3634  /*** copy inventory ***/
3635  for (item = src->inv; item; item = item->below) {
3636  (void)insert_ob_in_ob(object_create_clone(item), dst);
3637  }
3638 
3639  return dst;
3640 }
3641 
3656 object *find_obj_by_type_subtype(const object *who, int type, int subtype) {
3657  object *tmp;
3658 
3659  for (tmp = who->inv; tmp; tmp = tmp->below)
3660  if (tmp->type == type && tmp->subtype == subtype)
3661  return tmp;
3662 
3663  return NULL;
3664 }
3665 
3676 key_value *get_ob_key_link(const object *ob, const char *key) {
3677  key_value *link;
3678 
3679  for (link = ob->key_values; link != NULL; link = link->next) {
3680  if (link->key == key) {
3681  return link;
3682  }
3683  }
3684 
3685  return NULL;
3686 }
3687 
3701 const char *get_ob_key_value(const object *op, const char *const key) {
3702  key_value *link;
3703  const char *canonical_key;
3704 
3705  canonical_key = find_string(key);
3706 
3707  if (canonical_key == NULL) {
3708  /* 1. There being a field named key on any object
3709  * implies there'd be a shared string to find.
3710  * 2. Since there isn't, no object has this field.
3711  * 3. Therefore, *this *object doesn't have this field.
3712  */
3713  return NULL;
3714  }
3715 
3716  /* This is copied from get_ob_key_link() above -
3717  * only 4 lines, and saves the function call overhead.
3718  */
3719  for (link = op->key_values; link != NULL; link = link->next) {
3720  if (link->key == canonical_key) {
3721  return link->value;
3722  }
3723  }
3724  return NULL;
3725 }
3726 
3741 static int set_ob_key_value_s(object *op, const char *canonical_key, const char *value, int add_key) {
3742  key_value *field = NULL, *last = NULL;
3743 
3744  LOG(llevDebug, "set_ob_value_s: '%s' '%s' %d\n", canonical_key, value ? value : "null", add_key);
3745 
3746  for (field = op->key_values; field != NULL; field = field->next) {
3747  if (field->key != canonical_key) {
3748  last = field;
3749  continue;
3750  }
3751 
3752  if (field->value)
3753  FREE_AND_CLEAR_STR(field->value);
3754  if (value)
3755  field->value = add_string(value);
3756  else {
3757  /* Basically, if the archetype has this key set,
3758  * we need to store the null value so when we save
3759  * it, we save the empty value so that when we load,
3760  * we get this value back again.
3761  */
3762  if (get_ob_key_link(&op->arch->clone, canonical_key))
3763  field->value = NULL;
3764  else {
3765  /* Delete this link */
3766  if (field->key)
3767  FREE_AND_CLEAR_STR(field->key);
3768  if (field->value)
3769  FREE_AND_CLEAR_STR(field->value);
3770  if (last)
3771  last->next = field->next;
3772  else
3773  op->key_values = field->next;
3774  free(field);
3775  }
3776  }
3777  return TRUE;
3778  }
3779  /* IF we get here, key doesn't exist */
3780 
3781  /* No field, we'll have to add it. */
3782 
3783  if (!add_key) {
3784  return FALSE;
3785  }
3786  /* There isn't any good reason to store a null
3787  * value in the key/value list. If the archetype has
3788  * this key, then we should also have it, so shouldn't
3789  * be here. If user wants to store empty strings,
3790  * should pass in ""
3791  */
3792  if (value == NULL)
3793  return TRUE;
3794 
3795  field = malloc(sizeof(key_value));
3796 
3797  field->key = add_refcount(canonical_key);
3798  field->value = add_string(value);
3799  /* Usual prepend-addition. */
3800  field->next = op->key_values;
3801  op->key_values = field;
3802 
3803  return TRUE;
3804 }
3805 
3826 int set_ob_key_value(object *op, const char *key, const char *value, int add_key) {
3827  const char *canonical_key = NULL;
3828  int floating_ref = FALSE;
3829  int ret;
3830 
3831  /* HACK This mess is to make sure set_ob_value() passes a shared string
3832  * to get_ob_key_link(), without leaving a leaked refcount.
3833  */
3834 
3835  canonical_key = find_string(key);
3836  if (canonical_key == NULL) {
3837  canonical_key = add_string(key);
3838  floating_ref = TRUE;
3839  }
3840 
3841  ret = set_ob_key_value_s(op, canonical_key, value, add_key);
3842 
3843  if (floating_ref) {
3844  free_string(canonical_key);
3845  }
3846 
3847  return ret;
3848 }
3849 
3901 int item_matched_string(object *pl, object *op, const char *name) {
3902  char *cp, local_name[MAX_BUF], name_op[MAX_BUF], name_short[HUGE_BUF], bname_s[MAX_BUF], bname_p[MAX_BUF];
3903  int count, retval = 0;
3904  strcpy(local_name, name); /* strtok is destructive to name */
3905 
3906  for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) {
3907  while (cp[0] == ' ')
3908  ++cp; /* get rid of spaces */
3909 
3910  /* LOG(llevDebug, "Trying to match %s\n", cp);*/
3911  /* All is a very generic match - low match value */
3912  if (!strcmp(cp, "all"))
3913  return 1;
3914 
3915  /* unpaid is a little more specific */
3916  if (!strcmp(cp, "unpaid") && QUERY_FLAG(op, FLAG_UNPAID))
3917  return 2;
3918  if (!strcmp(cp, "cursed")
3920  && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)))
3921  return 2;
3922 
3923  if (!strcmp(cp, "unlocked") && !QUERY_FLAG(op, FLAG_INV_LOCKED))
3924  return 2;
3925 
3926  /* Allow for things like '100 arrows' */
3927  if ((count = atoi(cp)) != 0) {
3928  cp = strchr(cp, ' ');
3929  while (cp && cp[0] == ' ')
3930  ++cp; /* get rid of spaces */
3931  } else {
3932  if (pl->type == PLAYER)
3933  count = pl->contr->count;
3934  else
3935  count = 0;
3936  }
3937 
3938  if (!cp || cp[0] == '\0' || count < 0)
3939  return 0;
3940 
3941  /* The code here should go from highest retval to lowest. That
3942  * is because of the 'else' handling - we don't want to match on
3943  * something and set a low retval, even though it may match a higher retcal
3944  * later. So keep it in descending order here, so we try for the best
3945  * match first, and work downward.
3946  */
3947  query_name(op, name_op, MAX_BUF);
3948  query_short_name(op, name_short, HUGE_BUF);
3949  query_base_name(op, 0, bname_s, MAX_BUF);
3950  query_base_name(op, 1, bname_p, MAX_BUF);
3951 
3952  if (!strcasecmp(cp, name_op))
3953  retval = 20;
3954  else if (!strcasecmp(cp, name_short))
3955  retval = 18;
3956  else if (!strcasecmp(cp, bname_s))
3957  retval = 16;
3958  else if (!strcasecmp(cp, bname_p))
3959  retval = 16;
3960  else if (op->custom_name && !strcasecmp(cp, op->custom_name))
3961  retval = 15;
3962  else if (!strncasecmp(cp, bname_s, strlen(cp)))
3963  retval = 14;
3964  else if (!strncasecmp(cp, bname_p, strlen(cp)))
3965  retval = 14;
3966  /* Do substring checks, so things like 'Str+1' will match.
3967  * retval of these should perhaps be lower - they are lower
3968  * then the specific strcasecmp aboves, but still higher than
3969  * some other match criteria.
3970  */
3971  else if (strstr(bname_p, cp))
3972  retval = 12;
3973  else if (strstr(bname_s, cp))
3974  retval = 12;
3975  else if (strstr(name_short, cp))
3976  retval = 12;
3977  /* Check against plural/non plural based on count. */
3978  else if (count > 1 && !strcasecmp(cp, op->name_pl)) {
3979  retval = 6;
3980  } else if (count == 1 && !strcasecmp(op->name, cp)) {
3981  retval = 6;
3982  }
3983  /* base name matched - not bad */
3984  else if (strcasecmp(cp, op->name) == 0 && !count)
3985  retval = 4;
3986  /* Check for partial custom name, but give a real low priority */
3987  else if (op->custom_name && strstr(op->custom_name, cp))
3988  retval = 3;
3989 
3990  if (retval) {
3991  if (pl->type == PLAYER)
3992  pl->contr->count = count;
3993  return retval;
3994  }
3995  }
3996  return 0;
3997 }
3998 
4007 void fix_multipart_object(object *tmp) {
4008  archetype *at;
4009  object *op, *last;
4010 
4011  if (!tmp->map) {
4012  LOG(llevError, "fix_multipart_object: not on a map!\n");
4013  return;
4014  }
4015 
4016  /* already multipart - don't do anything more */
4017  if (tmp->head || tmp->more)
4018  return;
4019 
4020  /* If there is nothing more to this object, this for loop
4021  * won't do anything.
4022  */
4023  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
4024  op = arch_to_object(at);
4025 
4026  /* update x,y coordinates */
4027  op->x += tmp->x;
4028  op->y += tmp->y;
4029  op->head = tmp;
4030  op->map = tmp->map;
4031  last->more = op;
4032  if (tmp->name != op->name) {
4033  if (op->name)
4034  free_string(op->name);
4035  op->name = add_string(tmp->name);
4036  }
4037  if (tmp->title != op->title) {
4038  if (op->title)
4039  free_string(op->title);
4040  op->title = add_string(tmp->title);
4041  }
4042  /* we could link all the parts onto tmp, and then just
4043  * call insert_ob_in_map once, but the effect is the same,
4044  * as insert_ob_in_map will call itself with each part, and
4045  * the coding is simpler to just to it here with each part.
4046  */
4048  } /* for at = tmp->arch->more */
4049 }
4050 
4066 void get_multi_size(object *ob, int *sx, int *sy, int *hx, int *hy) {
4067  archetype *part;
4068  int maxx = 0, maxy = 0, minx = 0, miny = 0;
4069 
4070  if (ob->head)
4071  ob = ob->head;
4072  *sx = 1;
4073  *sy = 1;
4074  if (ob->arch->more) {
4075  for (part = ob->arch; part; part = part->more) {
4076  if (part->clone.x > maxx)
4077  maxx = part->clone.x;
4078  if (part->clone.y > maxy)
4079  maxy = part->clone.y;
4080  if (part->clone.x < minx)
4081  minx = part->clone.x;
4082  if (part->clone.y < miny)
4083  miny = part->clone.y;
4084  }
4085  }
4086  if (sx)
4087  *sx = maxx;
4088  if (sy)
4089  *sy = maxy;
4090  if (hx)
4091  *hx = -minx;
4092  if (hy)
4093  *hy = -miny;
4094 }
static int compare_ob_value_lists(const object *, const object *)
Definition: object.c:149
#define FLAG_NO_MAGIC
Definition: define.h:572
char path[HUGE_BUF]
Definition: map.h:384
uint8 map_layer
Definition: object.h:275
int find_dir_2(int x, int y)
Definition: object.c:3380
#define SET_MAP_OB(M, X, Y, tmp)
Definition: map.h:198
int reference_count
Definition: object.h:329
signed char sint8
Definition: global.h:80
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny)
Definition: map.c:330
#define FLAG_NO_DROP
Definition: define.h:585
sint16 oy
Definition: object.h:180
Definition: player.h:146
archetype * find_archetype(const char *name)
Definition: arch.c:700
#define FLAG_DAMNED
Definition: define.h:614
#define FLAG_IS_FLOOR
Definition: define.h:599
#define FLAG_UNPAID
Definition: define.h:532
struct _key_value * next
Definition: object.h:69
#define MOVE_WALK
Definition: define.h:700
#define UP_OBJ_FACE
Definition: object.h:356
tag_t ownercount
Definition: object.h:231
MoveType move_type
Definition: object.h:277
#define INS_BELOW_ORIGINATOR
Definition: object.h:398
int find_multi_free_spot_within_radius(object *ob, object *gen, int *hx, int *hy)
Definition: object.c:3052
int count_free(void)
Definition: object.c:1433
#define GET_MAP_MOVE_OFF(M, X, Y)
Definition: map.h:228
#define FALSE
Definition: exp.c:42
#define SK_CLIMBING
Definition: skills.h:67
const char * get_ob_key_value(const object *op, const char *const key)
Definition: object.c:3701
#define OUT_OF_MEMORY
Definition: define.h:94
MoveType move_on
Definition: object.h:280
signed short sint16
Definition: global.h:72
EXTERN long ob_count
Definition: global.h:232
object * find_obj_by_type_subtype(const object *who, int type, int subtype)
Definition: object.c:3656
#define P_PLAYER
Definition: map.h:257
struct Statistics statistics
Definition: init.c:119
const char * race
Definition: object.h:171
#define P_NEED_UPDATE
Definition: map.h:260
void set_owner(object *op, object *owner)
Definition: object.c:564
int count_active(void)
Definition: object.c:1465
#define CALLOC(x, y)
Definition: global.h:295
long strtol(register char *str, char **ptr, register int base)
Definition: porting.c:339
#define OBJ_EXPAND
Definition: config.h:592
void merge_spell(object *op, sint16 x, sint16 y)
Definition: object.c:1792
void esrv_send_item(object *pl, object *op)
Definition: standalone.c:197
tag_t attacked_by_count
Definition: object.h:234
#define SET_FLAG(xyz, p)
Definition: define.h:510
object * present_in_ob(uint8 type, const object *op)
Definition: object.c:2806
sstring add_refcount(sstring str)
Definition: shstr.c:202
MoveType move_allow
Definition: object.h:279
#define FABS(x)
Definition: define.h:61
static int set_ob_key_value_s(object *, const char *, const char *, int)
Definition: object.c:3741
int find_multi_free_spot_around(object *ob, object *gen, int *hx, int *hy)
Definition: object.c:2935
sint8 range
Definition: object.h:256
#define TRAP
Definition: define.h:326
uint16 client_type
Definition: object.h:191
tag_t * spell_tags
Definition: object.h:292
#define EVENT_DESTROY
Definition: plugin.h:74
object * object_get_env_recursive(object *op)
Definition: object.c:339
struct obj * container
Definition: object.h:149
#define FLAG_FRIENDLY
Definition: define.h:542
#define P_NO_MAGIC
Definition: map.h:248
void unflag_inv(object *op, int flag)
Definition: object.c:2894
void remove_from_active_list(object *op)
Definition: object.c:1070
object * insert_ob_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1761
#define FLAG_NO_FIX_PLAYER
Definition: define.h:573
#define LOOK_OBJ(ob)
Definition: object.h:344
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:64
uint8 casting_time
Definition: global.h:358
void get_search_arr(int *search_arr)
Definition: object.c:3283
unsigned char MoveType
Definition: define.h:725
object * find_object_name(const char *str)
Definition: object.c:459
void free_string(sstring str)
Definition: shstr.c:272
#define UP_OBJ_INSERT
Definition: object.h:353
#define HUGE_BUF
Definition: define.h:83
#define SET_ANIMATION(ob, newanim)
Definition: global.h:247
void esrv_update_item(int flags, object *pl, object *op)
Definition: standalone.c:200
sint16 players
Definition: map.h:365
int item_matched_string(object *pl, object *op, const char *name)
Definition: object.c:3901
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:732
#define MAP_HEIGHT(m)
Definition: map.h:99
object clone
Definition: object.h:326
sint16 duration
Definition: object.h:254
socket_struct socket
Definition: player.h:148
sint16 invisible
Definition: object.h:211
short freearr_x[SIZEOFFREE]
Definition: object.c:75
void flag_inv(object *op, int flag)
Definition: object.c:2876
object * merge_ob(object *op, object *top)
Definition: object.c:1724
const char * key
Definition: object.h:67
struct obj * prev
Definition: object.h:136
const char * slaying
Definition: object.h:172
#define SCROLL
Definition: define.h:293
void update_object(object *op, int action)
Definition: object.c:1112
uint8 subtype
Definition: object.h:190
#define RUNE
Definition: define.h:325
uint32 in_memory
Definition: map.h:366
int arch_init
Definition: arch.c:54
struct obj * above
Definition: object.h:146
double expmul
Definition: object.h:246
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:238
int freedir[SIZEOFFREE]
Definition: object.c:93
sint16 x
Definition: object.h:179
void remove_friendly_object(object *op)
Definition: friend.c:69
signed long sum_weight(object *op)
Definition: object.c:317
void get_multi_size(object *ob, int *sx, int *sy, int *hx, int *hy)
Definition: object.c:4066
object * find_object(tag_t i)
Definition: object.c:439
int distance(const object *ob1, const object *ob2)
Definition: object.c:3364
void free_dialog_information(object *op)
Definition: dialog.c:39
struct archt * other_arch
Definition: object.h:264
int absdir(int d)
Definition: object.c:3417
Definition: object.h:321
#define PLAYER
Definition: define.h:113
#define FLAG_REMOVED
Definition: define.h:528
int nrofallocobjects
Definition: object.c:67
short freearr_y[SIZEOFFREE]
Definition: object.c:81
object * active_objects
Definition: object.c:72
static const int reduction_dir[SIZEOFFREE][3]
Definition: object.c:3454
#define MOVE_ALL
Definition: define.h:706
uint32 flags[4]
Definition: object.h:266
const char * lore
Definition: object.h:176
uint32 tag_t
Definition: object.h:40
void fix_multipart_object(object *tmp)
Definition: object.c:4007
#define MAP_IN_MEMORY
Definition: map.h:151
const char * title
Definition: object.h:170
void remove_ob(object *op)
Definition: object.c:1515
sint16 maxhp
Definition: living.h:82
sstring find_string(const char *str)
Definition: shstr.c:228
int dirdiff(int dir1, int dir2)
Definition: object.c:3434
#define FLAG_CLIENT_ANIM_RANDOM
Definition: define.h:537
EXTERN archetype * empty_archetype
Definition: global.h:227
int maxfree[SIZEOFFREE]
Definition: object.c:87
#define STARTMAX
Definition: config.h:591
#define FLAG_ALIVE
Definition: define.h:526
void clear_owner(object *op)
Definition: object.c:544
const char * name_pl
Definition: object.h:168
#define FLAG_OBJ_ORIGINAL
Definition: define.h:661
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:97
object * get_player_container(object *op)
Definition: object.c:356
float speed_left
Definition: object.h:182
#define MAP_DARKNESS(m)
Definition: map.h:94
uint32 hidden
Definition: player.h:186
#define FLAG_NO_STEAL
Definition: define.h:639
const char * materialname
Definition: object.h:197
sint32 weight
Definition: object.h:216
uint64 spell_merges
Definition: global.h:424
#define MOVE_FLY_LOW
Definition: define.h:701
void update_all_los(const mapstruct *map, int x, int y)
Definition: los.c:544
struct mapdef * map
Definition: object.h:155
void free_arch(archetype *at)
Definition: arch.c:273
struct obj * active_prev
Definition: object.h:141
void dump_object(object *op, StringBuffer *sb)
Definition: object.c:372
#define FLAG_CLIENT_ANIM_SYNC
Definition: define.h:536
object * transport
Definition: player.h:249
#define FLAG_IDENTIFIED
Definition: define.h:557
int count_used(void)
Definition: object.c:1449
uint64 spell_hash_full
Definition: global.h:425
int find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
Definition: object.c:3240
void update_position(mapstruct *m, int x, int y)
Definition: map.c:2124
sint16 dam
Definition: living.h:87
sint32 carrying
Definition: object.h:218
object * objects
Definition: object.c:70
#define FLAG_BLOCKSVIEW
Definition: define.h:565
const char * name
Definition: object.h:167
struct obj * env
Definition: object.h:151
int can_merge(object *ob1, object *ob2)
Definition: object.c:178
#define OB_SPELL_TAG_MATCH(op, count)
Definition: object.h:109
object * get_owner(object *op)
Definition: object.c:524
object * present(uint8 type, mapstruct *m, int x, int y)
Definition: object.c:2782
struct obj * below
Definition: object.h:145
struct archt * more
Definition: object.h:325
#define INS_NO_WALK_ON
Definition: object.h:396
void fatal(int err)
Definition: glue.c:60
#define offsetof(type, member)
Definition: shstr.h:37
#define FLAG_IS_A_TEMPLATE
Definition: define.h:671
#define TRUE
Definition: exp.c:41
#define GET_MAP_TOP(M, X, Y)
Definition: map.h:195
object * object_create_clone(object *asrc)
Definition: object.c:3608
uint32 nrof
Definition: object.h:184
#define SK_WOODSMAN
Definition: skills.h:68
unsigned char uint8
Definition: global.h:75
int find_dir(mapstruct *m, int x, int y, object *exclude)
Definition: object.c:3313
object * present_in_ob_by_name(int type, const char *str, const object *op)
Definition: object.c:2840
#define GET_MAP_MOVE_ON(M, X, Y)
Definition: map.h:223
#define FLAG_OVERLAY_FLOOR
Definition: define.h:551
#define SIZEOFFREE
Definition: define.h:441
#define P_OUT_OF_MAP
Definition: map.h:272
MoveType move_off
Definition: object.h:281
mapstruct * get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y)
Definition: map.c:2366
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:213
sint16 y
Definition: object.h:179
struct pl * contr
Definition: object.h:134
sint8 item_power
Definition: object.h:213
int can_pick(const object *who, const object *item)
Definition: object.c:3569
#define UPD_NROF
Definition: newclient.h:261
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:283
void add_weight(object *op, signed long weight)
Definition: object.c:2486
object * present_arch(const archetype *at, mapstruct *m, int x, int y)
Definition: object.c:2755
#define MAP_SAVING
Definition: map.h:154
#define MAX(x, y)
Definition: define.h:70
uint32 count
Definition: player.h:163
float speed
Definition: object.h:181
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
#define CLEAR_FLAG(xyz, p)
Definition: define.h:512
#define INS_ABOVE_FLOOR_ONLY
Definition: object.h:395
#define FLAG_BEEN_APPLIED
Definition: define.h:620
object * insert_ob_in_ob(object *op, object *where)
Definition: object.c:2510
#define MAX_BUF
Definition: define.h:81
object * free_objects
Definition: object.c:71
struct obj * active_next
Definition: object.h:137
static void expand_objects(void)
Definition: object.c:880
method_ret ob_move_on(object *op, object *victim, object *originator)
Definition: ob_methods.c:122
object * get_object(void)
Definition: object.c:921
int strncasecmp(const char *s1, const char *s2, int n)
Definition: porting.c:402
object * insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1992
int nroffreeobjects
Definition: object.c:66
MoveType move_slow
Definition: object.h:282
const char * skill
Definition: object.h:174
sint8 wc
Definition: living.h:79
void copy_owner(object *op, object *clone)
Definition: object.c:614
#define LAMP
Definition: define.h:263
static const flag_definition flags[]
struct obj * next
Definition: object.h:135
key_value * key_values
Definition: object.h:286
sint8 Str
Definition: living.h:78
#define FLAG_NO_APPLY
Definition: define.h:598
sint16 resist[NROFATTACKS]
Definition: object.h:192
#define FLAG_KNOWN_CURSED
Definition: define.h:617
object * ob
Definition: player.h:207
#define GET_MAP_FLAGS(M, X, Y)
Definition: map.h:182
#define FLAG_IS_HILLY
Definition: define.h:629
#define SPELL_TAG_SIZE
Definition: object.h:107
#define FLAG_CURSED
Definition: define.h:613
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
void get_ob_diff(StringBuffer *sb, object *op, object *op2)
#define SET_MAP_FLAGS(M, X, Y, C)
Definition: map.h:184
#define FLAG_ANIMATE
Definition: define.h:538
uint32 attacktype
Definition: object.h:193
#define INS_NO_MERGE
Definition: object.h:394
sint8 direction
Definition: object.h:185
#define CONTAINER
Definition: define.h:306
#define UP_OBJ_CHANGE
Definition: object.h:355
uint32 update_look
Definition: newserver.h:131
struct obj * owner
Definition: object.h:228
int set_ob_key_value(object *op, const char *key, const char *value, int add_key)
Definition: object.c:3826
void free_object2(object *ob, int free_inventory)
Definition: object.c:1258
#define GET_MAP_PLAYER(M, X, Y)
Definition: map.h:189
New_Face * blank_face
Definition: image.c:66
void update_turn_face(object *op)
Definition: object.c:990
const char * custom_name
Definition: object.h:285
void set_cheat(object *op)
Definition: object.c:2913
#define UP_OBJ_REMOVE
Definition: object.h:354
tag_t count
Definition: object.h:157
living stats
Definition: object.h:219
struct archt * arch
Definition: object.h:263
#define AB_NO_PASS
Definition: map.h:256
#define MAP_WIDTH(m)
Definition: map.h:97
object * present_arch_in_ob(const archetype *at, const object *op)
Definition: object.c:2859
object * decrease_ob_nr(object *op, uint32 i)
Definition: object.c:2345
uint32 do_los
Definition: player.h:180
void reset_object(object *op)
Definition: object.c:639
#define SKILL
Definition: define.h:157
struct Settings settings
Definition: init.c:48
void free_key_values(object *op)
Definition: object.c:659
void dump_all_objects(void)
Definition: object.c:416
#define SPELL_EFFECT
Definition: define.h:284
#define FLAG_APPLIED
Definition: define.h:531
#define NROFATTACKS
Definition: attack.h:45
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:551
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2300
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: standalone.c:225
const char * anim_suffix
Definition: object.h:169
object objarray[STARTMAX]
Definition: object.c:65
#define SIZEOFFREE2
Definition: define.h:440
#define OB_SPELL_TAG_HASH(op, count)
Definition: object.h:108
const char * msg
Definition: object.h:175
const char * value
Definition: object.h:68
static void permute(int *, int, int)
Definition: object.c:3259
sint16 casting_time
Definition: object.h:253
uint16 animation_id
Definition: object.h:267
#define FLAG_STARTEQUIP
Definition: define.h:564
void update_ob_speed(object *op)
Definition: object.c:1008
sstring add_string(const char *str)
Definition: shstr.c:116
EXTERN player * first_player
Definition: global.h:190
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.c:106
struct pl * next
Definition: player.h:147
#define MIN_ACTIVE_SPEED
Definition: define.h:1063
void copy_object_with_inv(object *src_ob, object *dest_ob)
Definition: object.c:862
#define GET_MAP_OB(M, X, Y)
Definition: map.h:193
int strcasecmp(const char *s1, const char *s2)
Definition: porting.c:434
int find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
Definition: object.c:3200
void clear_object(object *op)
Definition: object.c:688
sint8 glow_radius
Definition: object.h:215
#define FLAG_MONSTER
Definition: define.h:541
struct obj * inv
Definition: object.h:148
#define SIZEOFFREE1
Definition: define.h:439
struct obj * head
Definition: object.h:154
#define MOVE_FLY_HIGH
Definition: define.h:702
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
object * get_split_ob(object *orig_ob, uint32 nr, char *err, size_t size)
Definition: object.c:2313
void sub_weight(object *op, signed long weight)
Definition: object.c:1489
#define SET_MAP_TOP(M, X, Y, tmp)
Definition: map.h:200
unsigned int uint32
Definition: global.h:58
#define FLAG_WAS_WIZ
Definition: define.h:530
#define was_destroyed(op, old_tag)
Definition: object.h:94
MoveType move_block
Definition: object.h:278
#define GET_MAP_MOVE_SLOW(M, X, Y)
Definition: map.h:218
#define P_BLOCKSVIEW
Definition: map.h:247
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
Definition: object.c:3524
#define FLAG_DIALOG_PARSED
Definition: define.h:539
void copy_object(object *op2, object *op)
Definition: object.c:758
#define P_NO_ERROR
Definition: map.h:261
float move_slow_penalty
Definition: object.h:283
#define UPD_FACE
Definition: newclient.h:257
int check_move_on(object *op, object *originator)
Definition: object.c:2651
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:628
sint16 ox
Definition: object.h:180
object * find_skill_by_number(object *who, int skillno)
Definition: standalone.c:209
void free_object(object *ob)
Definition: object.c:1238
Definition: map.h:346
#define P_IS_ALIVE
Definition: map.h:258
New_Face * face
Definition: object.h:183
#define FREE_AND_CLEAR(xyz)
Definition: global.h:282
#define FLAG_IS_WOODED
Definition: define.h:627
#define FLAG_NO_PICK
Definition: define.h:535
#define FLAG_WIZPASS
Definition: define.h:611
void replace_insert_ob_in_map(const char *arch_string, object *op)
Definition: object.c:2271
sint16 level
Definition: object.h:202
sint16 * discrete_damage
Definition: object.h:291
#define FLAG_INV_LOCKED
Definition: define.h:626
void esrv_del_item(player *pl, int tag)
Definition: standalone.c:213
void fix_object(object *op)
Definition: living.c:900
void free_all_object_data(void)
Definition: object.c:479
struct obj * more
Definition: object.h:153
object * arch_to_object(archetype *at)
Definition: arch.c:576
#define SCRIPT_FIX_NOTHING
Definition: global.h:451
sint32 value
Definition: object.h:201
sint8 magic
Definition: object.h:199
const char * name
Definition: object.h:322
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:78
#define P_NO_CLERIC
Definition: map.h:259
uint8 type
Definition: object.h:189
key_value * get_ob_key_link(const object *ob, const char *key)
Definition: object.c:3676
static int compare_ob_value_lists_one(const object *, const object *)
Definition: object.c:108
int ob_blocked(const object *ob, mapstruct *m, sint16 x, sint16 y)
Definition: map.c:525
#define INS_MAP_LOAD
Definition: object.h:399
#define FLAG_FREED
Definition: define.h:529
static void increase_ob_nr(object *op, uint32 i)
Definition: object.c:2423
#define FLAG_IS_TURNABLE
Definition: define.h:552