Crossfire Server, Trunk
object.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
20  object_sub/add_weight will transcend the environment updating the carrying
21  variable. */
22 
23 #include "global.h"
24 
25 #include <assert.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #ifndef WIN32 /* ---win32 exclude headers */
32 #include <sys/types.h>
33 #include <sys/uio.h>
34 #endif /* win32 */
35 
36 #include "loader.h"
37 #include "object.h"
38 #include "skills.h"
39 #include "sproto.h"
40 #include "stringbuffer.h"
41 
42 static int compare_ob_value_lists_one(const object *, const object *);
43 static int compare_ob_value_lists(const object *, const object *);
44 static void expand_objects(void);
45 static void permute(int *, int, int);
46 static int object_set_value_s(object *, const char *, const char *, int);
47 static void object_increase_nrof(object *op, uint32_t i);
48 
63 const char *const spell_mapping[SPELL_MAPPINGS] = {
64  "spell_magic_bullet", /* 0 */
65  "spell_small_fireball", /* 1 */
66  "spell_medium_fireball", /* 2 */
67  "spell_large_fireball", /* 3 */
68  "spell_burning_hands", /* 4 */
69  "spell_sm_lightning", /* 5 */
70  "spell_large_lightning", /* 6 */
71  "spell_magic_missile", /* 7 */
72  "spell_create_bomb", /* 8 */
73  "spell_summon_golem", /* 9 */
74  "spell_summon_fire_elemental", /* 10 */
75  "spell_summon_earth_elemental", /* 11 */
76  "spell_summon_water_elemental", /* 12 */
77  "spell_summon_air_elemental", /* 13 */
78  "spell_dimension_door", /* 14 */
79  "spell_create_earth_wall", /* 15 */
80  "spell_paralyze", /* 16 */
81  "spell_icestorm", /* 17 */
82  "spell_magic_mapping", /* 18 */
83  "spell_turn_undead", /* 19 */
84  "spell_fear", /* 20 */
85  "spell_poison_cloud", /* 21 */
86  "spell_wonder", /* 22 */
87  "spell_destruction", /* 23 */
88  "spell_perceive_self", /* 24 */
89  "spell_word_of_recall", /* 25 */
90  "spell_invisible", /* 26 */
91  "spell_invisible_to_undead", /* 27 */
92  "spell_probe", /* 28 */
93  "spell_lg_magic_bullet", /* 29 */
94  "spell_improved_invisibility", /* 30 */
95  "spell_holy_word", /* 31 */
96  "spell_minor_healing", /* 32 */
97  "spell_medium_healing", /* 33 */
98  "spell_major_healing", /* 34 */
99  "spell_heal", /* 35 */
100  "spell_create_food", /* 36 */
101  "spell_earth_to_dust", /* 37 */
102  "spell_armour", /* 38 */
103  "spell_strength", /* 39 */
104  "spell_dexterity", /* 40 */
105  "spell_constitution", /* 41 */
106  "spell_charisma", /* 42 */
107  "spell_create_fire_wall", /* 43 */
108  "spell_create_frost_wall", /* 44 */
109  "spell_protection_from_cold", /* 45 */
110  "spell_protection_from_electricity", /* 46 */
111  "spell_protection_from_fire", /* 47 */
112  "spell_protection_from_poison", /* 48 */
113  "spell_protection_from_slow", /* 49 */
114  "spell_protection_from_paralysis", /* 50 */
115  "spell_protection_from_draining", /* 51 */
116  "spell_protection_from_magic", /* 52 */
117  "spell_protection_from_attack", /* 53 */
118  "spell_levitate", /* 54 */
119  "spell_small_speedball", /* 55 */
120  "spell_large_speedball", /* 56 */
121  "spell_hellfire", /* 57 */
122  "spell_dragonbreath", /* 58 */
123  "spell_large_icestorm", /* 59 */
124  "spell_charging", /* 60 */
125  "spell_polymorph", /* 61 */
126  "spell_cancellation", /* 62 */
127  "spell_confusion", /* 63 */
128  "spell_mass_confusion", /* 64 */
129  "spell_summon_pet_monster", /* 65 */
130  "spell_slow", /* 66 */
131  "spell_regenerate_spellpoints", /* 67 */
132  "spell_cure_poison", /* 68 */
133  "spell_protection_from_confusion", /* 69 */
134  "spell_protection_from_cancellation", /* 70 */
135  "spell_protection_from_depletion", /* 71 */
136  "spell_alchemy", /* 72 */
137  "spell_remove_curse", /* 73 */
138  "spell_remove_damnation", /* 74 */
139  "spell_identify", /* 75 */
140  "spell_detect_magic", /* 76 */
141  "spell_detect_monster", /* 77 */
142  "spell_detect_evil", /* 78 */
143  "spell_detect_curse", /* 79 */
144  "spell_heroism", /* 80 */
145  "spell_aggravation", /* 81 */
146  "spell_firebolt", /* 82 */
147  "spell_frostbolt", /* 83 */
148  "spell_shockwave", /* 84 */
149  "spell_color_spray", /* 85 */
150  "spell_haste", /* 86 */
151  "spell_face_of_death", /* 87 */
152  "spell_ball_lightning", /* 88 */
153  "spell_meteor_swarm", /* 89 */
154  "spell_comet", /* 90 */
155  "spell_mystic_fist", /* 91 */
156  "spell_raise_dead", /* 92 */
157  "spell_resurrection", /* 93 */
158  "spell_reincarnation", /* 94 */
159  NULL, /* 95 spell_immunity_to_cold */
160  NULL, /* 96 spell_immunity_to_electricity */
161  NULL, /* 97 spell_immunity_to_fire */
162  NULL, /* 98 spell_immunity_to_poison */
163  NULL, /* 99 spell_immunity_to_slow */
164  NULL, /* 100 spell_immunity_to_paralysis */
165  NULL, /* 101 spell_immunity_to_draining */
166  NULL, /* 102 spell_immunity_to_magic */
167  NULL, /* 103 spell_immunity_to_attack */
168  "spell_invulnerability", /* 104 */
169  "spell_defense", /* 105 */
170  "spell_rune_of_fire", /* 106 */
171  "spell_rune_of_frost", /* 107 */
172  "spell_rune_of_shocking", /* 108 */
173  "spell_rune_of_blasting", /* 109 */
174  "spell_rune_of_death", /* 110 */
175  "spell_marking_rune", /* 111 */
176  "spell_build_director", /* 112 */
177  "spell_create_pool_of_chaos", /* 113 */
178  "spell_build_bullet_wall", /* 114 */
179  "spell_build_lightning_wall", /* 115 */
180  "spell_build_fireball_wall", /* 116 */
181  "spell_magic_rune", /* 117 */
182  "spell_rune_of_magic_drain", /* 118 */
183  "spell_antimagic_rune", /* 119 */
184  "spell_rune_of_transference", /* 120 */
185  "spell_transference", /* 121 */
186  "spell_magic_drain", /* 122 */
187  "spell_counterspell", /* 123 */
188  "spell_disarm", /* 124 */
189  "spell_cure_confusion", /* 125 */
190  "spell_restoration", /* 126 */
191  NULL, /* 127 */ /* Was summon evil monster */
192  "spell_counterwall", /* 128 */
193  "spell_cause_light_wounds", /* 129 */
194  "spell_cause_medium_wounds", /* 130 */
195  "spell_cause_heavy_wounds", /* 131 */
196  "spell_charm_monsters", /* 132 */
197  "spell_banishment", /* 133 */
198  "spell_create_missile", /* 134 */
199  "spell_show_invisible", /* 135 */
200  "spell_xray", /* 136 */
201  "spell_pacify", /* 137 */
202  "spell_summon_fog", /* 138 */
203  "spell_steambolt", /* 139 */
204  "spell_command_undead", /* 140 */
205  "spell_holy_orb", /* 141 */
206  "spell_summon_avatar", /* 142 */
207  "spell_holy_possession", /* 143 */
208  "spell_bless", /* 144 */
209  "spell_curse", /* 145 */
210  "spell_regeneration", /* 146 */
211  "spell_consecrate", /* 147 */
212  "spell_summon_cult_monsters", /* 148 */
213  "spell_cause_critical_wounds", /* 149 */
214  "spell_holy_wrath", /* 150 */
215  "spell_retributive_strike", /* 151 */
216  "spell_finger_of_death", /* 152 */
217  "spell_insect_plague", /* 153 */
218  "spell_call_holy_servant", /* 154 */
219  "spell_wall_of_thorns", /* 155 */
220  "spell_staff_to_snake", /* 156 */
221  "spell_light", /* 157 */
222  "spell_darkness", /* 158 */
223  "spell_nightfall", /* 159 */
224  "spell_daylight", /* 160 */
225  "spell_sunspear", /* 161 */
226  "spell_faery_fire", /* 162 */
227  "spell_cure_blindness", /* 163 */
228  "spell_dark_vision", /* 164 */
229  "spell_bullet_swarm", /* 165 */
230  "spell_bullet_storm", /* 166 */
231  "spell_cause_many_wounds", /* 167 */
232  "spell_small_snowstorm", /* 168 */
233  "spell_medium_snowstorm", /* 169 */
234  "spell_large_snowstorm", /* 170 */
235  "spell_cure_disease", /* 171 */
236  "spell_cause_red_death", /* 172 */
237  "spell_cause_flu", /* 173 */
238  "spell_cause_black_death", /* 174 */
239  "spell_cause_leprosy", /* 175 */
240  "spell_cause_smallpox", /* 176 */
241  "spell_cause_white_death", /* 177 */
242  "spell_cause_anthrax", /* 178 */
243  "spell_cause_typhoid", /* 179 */
244  "spell_mana_blast", /* 180 */
245  "spell_small_manaball", /* 181 */
246  "spell_medium_manaball", /* 182 */
247  "spell_large_manaball", /* 183 */
248  "spell_manabolt", /* 184 */
249  "spell_dancing_sword", /* 185 */
250  "spell_animate_weapon", /* 186 */
251  "spell_cause_cold", /* 187 */
252  "spell_divine_shock", /* 188 */
253  "spell_windstorm", /* 189 */
254  "spell_sanctuary", /* 190 */
255  "spell_peace", /* 191 */
256  "spell_spiderweb", /* 192 */
257  "spell_conflict", /* 193 */
258  "spell_rage", /* 194 */
259  "spell_forked_lightning", /* 195 */
260  "spell_poison_fog", /* 196 */
261  "spell_flaming_aura", /* 197 */
262  "spell_vitriol", /* 198 */
263  "spell_vitriol_splash", /* 199 */
264  "spell_iron_skin", /* 200 */
265  "spell_wrathful_eye", /* 201 */
266  "spell_town_portal", /* 202 */
267  "spell_missile_swarm", /* 203 */
268  "spell_cause_rabies", /* 204 */
269  "spell_glyph", /* 205 */
270 };
271 
272 #ifdef MEMORY_DEBUG
273 int nroffreeobjects = 0;
274 int nrofallocobjects = 0;
275 #undef OBJ_EXPAND
276 #define OBJ_EXPAND 1
277 #else
278 static object objarray[STARTMAX];
281 #endif
282 
283 object *objects;
284 static object *free_objects;
285 object *active_objects;
289  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,
290  0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
291 };
292 
295  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,
296  -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3
297 };
298 
301  0, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45,
302  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
303 };
304 
307  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,
308  1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
309 };
310 
316 void init_objects(void) {
317  /* Initialize all objects: */
318  objects = NULL;
319  active_objects = NULL;
320 
321 #ifdef MEMORY_DEBUG
322  free_objects = NULL;
323 #else
325  objarray[0].prev = NULL,
326  objarray[0].next = &objarray[1],
329  for (int i = 1; i < STARTMAX-1; i++) {
330  objarray[i].next = &objarray[i+1];
331  objarray[i].prev = &objarray[i-1];
334  }
335  objarray[STARTMAX-1].next = NULL;
339 #endif
340 }
341 
352 static int compare_ob_value_lists_one(const object *wants, const object *has) {
353  key_value *wants_field;
354 
355  /* n-squared behaviour (see object_get_key_value()), but I'm hoping both
356  * objects with lists are rare, and lists stay short. If not, use a
357  * different structure or at least keep the lists sorted...
358  */
359 
360  /* For each field in wants, */
361  for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) {
362  key_value *has_field;
363 
364  /* Look for a field in has with the same key. */
365  has_field = object_get_key_value(has, wants_field->key);
366 
367  if (has_field == NULL) {
368  /* No field with that name. */
369  return FALSE;
370  }
371 
372  /* Found the matching field. */
373  if (has_field->value != wants_field->value) {
374  /* Values don't match, so this half of the comparison is false. */
375  return FALSE;
376  }
377 
378  /* If we get here, we found a match. Now for the next field in wants. */
379  }
380 
381  /* If we get here, every field in wants has a matching field in has. */
382  return TRUE;
383 }
384 
393 static int compare_ob_value_lists(const object *ob1, const object *ob2) {
394  /* However, there may be fields in has which aren't partnered in wants,
395  * so we need to run the comparison *twice*. :(
396  */
398 }
399 
422 int object_can_merge(object *ob1, object *ob2) {
423  /* A couple quicksanity checks */
424  if (ob1 == ob2 || ob1->type != ob2->type)
425  return 0;
426 
427  if (ob1->speed != ob2->speed)
428  return 0;
429  /* Note sure why the following is the case - either the object has to
430  * be animated or have a very low speed. Is this an attempted monster
431  * check?
432  */
433  /*TODO is this check really needed?*/
434  if (!QUERY_FLAG(ob1, FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
435  return 0;
436 
437  /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
438  * value could not be stored in a int32_t (which unfortunately sometimes is
439  * used to store nrof).
440  */
441  if (ob1->nrof+ob2->nrof >= 1UL<<31)
442  return 0;
443 
444  /* This is really a spellbook check - really, we should
445  * check all objects in the inventory.
446  */
447  /*TODO is this check really needed?*/
448  if (ob1->inv || ob2->inv) {
449  /* if one object has inventory but the other doesn't, not equiv */
450  if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
451  return 0;
452 
453  /* Now check to see if the two inventory objects could merge */
454  if (!object_can_merge(ob1->inv, ob2->inv))
455  return 0;
456 
457  /* inventory ok - still need to check rest of this object to see
458  * if it is valid.
459  */
460  }
461 
462  /* If the objects have been identified, set the BEEN_APPLIED flag.
463  * This is to the comparison of the flags below will be OK. We
464  * just can't ignore the been applied or identified flags, as they
465  * are not equal - just if it has been identified, the been_applied
466  * flags lose any meaning.
467  */
468 
469  /*TODO is this hack on BEEN_APPLIED really needed? */
472 
475 
476 
477  /* Note: FLAG_INV_LOCKED is ignored for merging purposes */
478  if ((ob1->arch != ob2->arch)
479  || (ob1->flags[0] != ob2->flags[0])
480  || (ob1->flags[1] != ob2->flags[1])
481  || (ob1->flags[2] != ob2->flags[2])
482  || ((ob1->flags[3]&~0x84) != (ob2->flags[3]&~0x84)) /* ignore CLIENT_SENT and FLAG_OBJ_ORIGINAL */
483  || (ob1->name != ob2->name)
484  || (ob1->title != ob2->title)
485  || (ob1->msg != ob2->msg)
486  || (ob1->weight != ob2->weight)
487  || (ob1->item_power != ob2->item_power)
488  || (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist)) != 0)
489  || (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats)) != 0)
490  || (ob1->attacktype != ob2->attacktype)
491  || (ob1->magic != ob2->magic)
492  || (ob1->slaying != ob2->slaying)
493  || (ob1->skill != ob2->skill)
494  || (ob1->value != ob2->value)
495  || (ob1->animation != ob2->animation)
496  || (ob1->client_type != ob2->client_type)
497  || (ob1->materialname != ob2->materialname)
498  || (ob1->lore != ob2->lore)
499  || (ob1->subtype != ob2->subtype)
500  || (ob1->move_type != ob2->move_type)
501  || (ob1->move_block != ob2->move_block)
502  || (ob1->move_allow != ob2->move_allow)
503  || (ob1->move_on != ob2->move_on)
504  || (ob1->move_off != ob2->move_off)
505  || (ob1->move_slow != ob2->move_slow)
506  || (ob1->move_slow_penalty != ob2->move_slow_penalty)
507  || (ob1->map_layer != ob2->map_layer))
508  return 0;
509 
510  /* Don't merge objects that are applied. With the new 'body' code,
511  * it is possible for most any character to have more than one of
512  * some items equipped, and we don't want those to merge.
513  */
515  return 0;
516 
517  if (ob1->key_values != NULL || ob2->key_values != NULL) {
518  /* At least one of these has key_values. */
519  if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
520  /* One has fields, but the other one doesn't. */
521  return 0;
522  } else {
523  if (!compare_ob_value_lists(ob1, ob2)) {
524  return 0;
525  }
526  }
527  }
528 
529  /*TODO should this really be limited to scrolls?*/
530  switch (ob1->type) {
531  case SCROLL:
532  if (ob1->level != ob2->level)
533  return 0;
534  break;
535  }
536 
537  /* Don't merge items with differing custom names. */
538  if (ob1->custom_name != ob2->custom_name)
539  return 0;
540 
541  /* Everything passes, must be OK. */
542  return 1;
543 }
544 
560 /* TODO should check call this this are made a place where we really need reevaluaton of whole tree */
561 signed long object_sum_weight(object *op) {
562  signed long sum;
563 
564  sum = 0;
566  if (inv->inv)
568  sum += inv->carrying+inv->weight*NROF(inv);
569  } FOR_INV_FINISH();
570  if (op->type == CONTAINER && op->stats.Str)
571  sum = (sum*(100-op->stats.Str))/100;
572  op->carrying = sum;
573  return sum;
574 }
575 
583 object *object_get_env_recursive(object *op) {
584  while (op->env != NULL)
585  op = op->env;
586  return op;
587 }
588 
600 object *object_get_player_container(object *op) {
601  for (; op != NULL && op->type != PLAYER; op = op->env)
602  /*TODO this is patching the structure on the flight as side effect. Shoudln't be needed in clean code */
603  if (op->env == op)
604  op->env = NULL;
605  return op;
606 }
607 
617 static const object *object_get_owner_const(const object *op) {
618  if (op->owner == NULL)
619  return NULL;
620 
621  if (!QUERY_FLAG(op->owner, FLAG_FREED)
622  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
623  && op->owner->count == op->ownercount)
624  return op->owner;
625 
626  LOG(llevError, "Warning, no owner found\n");
627  return NULL;
628 }
629 
638 void object_dump(const object *op, StringBuffer *sb) {
639  if (op == NULL) {
640  stringbuffer_append_string(sb, "[NULL pointer]");
641  return;
642  }
643 
644  /* object *tmp;*/
645 
646  if (op->arch != NULL) {
647  const object *owner;
648 
649  stringbuffer_append_string(sb, "arch ");
650  stringbuffer_append_string(sb, op->arch->name ? op->arch->name : "(null)");
651  stringbuffer_append_string(sb, "\n");
652 
653  if (op->artifact != NULL) {
654  stringbuffer_append_string(sb, "artifact ");
655  stringbuffer_append_string(sb, op->artifact);
656  stringbuffer_append_string(sb, "\n");
657  }
658 
660  if (op->more) {
661  stringbuffer_append_printf(sb, "more %u\n", op->more->count);
662  }
663  if (op->head) {
664  stringbuffer_append_printf(sb, "head %u\n", op->head->count);
665  }
666  if (op->env) {
667  stringbuffer_append_printf(sb, "env %u\n", op->env->count);
668  }
669  if (op->inv) {
670  stringbuffer_append_printf(sb, "inv %u\n", op->inv->count);
671  }
672  if (op->enemy) {
673  stringbuffer_append_printf(sb, "enemy %u\n", op->enemy->count);
674  }
675  if (op->attacked_by) {
676  stringbuffer_append_printf(sb, "attacked_by %u\n", op->attacked_by->count);
677  }
678  owner = object_get_owner_const(op);
679  if (owner != NULL) {
680  stringbuffer_append_printf(sb, "owner %u\n", owner->count);
681  }
682  stringbuffer_append_string(sb, "end\n");
683  } else {
684  stringbuffer_append_string(sb, "Object ");
685  stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
686  stringbuffer_append_string(sb, "\nend\n");
687  }
688 }
689 
697 void object_dump_all(void) {
698  object *op;
699 
700  for (op = objects; op != NULL; op = op->next) {
701  StringBuffer *sb;
702  char *diff;
703 
704  sb = stringbuffer_new();
705  object_dump(op, sb);
706  diff = stringbuffer_finish(sb);
707  LOG(llevDebug, "Object %u\n:%s\n", op->count, diff);
708  free(diff);
709  }
710 }
711 
721  object *op;
722 
723  for (op = objects; op != NULL; op = op->next)
724  if (op->count == i)
725  break;
726  return op;
727 }
728 
740 object *object_find_by_name_global(const char *str) {
741  const char *name = add_string(str);
742  object *op;
743 
744  for (op = objects; op != NULL; op = op->next)
745  if (op->name == name)
746  break;
747  free_string(name);
748  return op;
749 }
750 
761 #ifdef MEMORY_DEBUG
762  object *op, *next;
763 
764  for (op = free_objects; op != NULL; ) {
765  next = op->next;
766  free(op);
768  nroffreeobjects--;
769  op = next;
770  }
771  free_objects = NULL;
772 
773  for (op = objects; op != NULL; ) {
774  next = op->next;
775  if (!QUERY_FLAG(op, FLAG_FREED)) {
776  LOG(llevDebug, "non freed object: %s\n", op->name);
777  }
778  op = next;
779  }
780 #endif
781 
782  LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX);
783 }
784 
797 object *object_get_owner(object *op) {
798  if (op->owner == NULL)
799  return NULL;
800 
801  if (!QUERY_FLAG(op->owner, FLAG_FREED)
802  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
803  && op->owner->count == op->ownercount)
804  return op->owner;
805 
807  return NULL;
808 }
809 
816 void object_clear_owner(object *op) {
817  if (!op)
818  return;
819 
820  op->owner = NULL;
821  op->ownercount = 0;
822 }
823 
833 void object_set_owner(object *op, object *owner) {
834  /* Assign temp to something, so it can't accidentally be NULL */
835  object *tmp = owner;
836  if (op == NULL)
837  return;
838  if (owner == NULL) {
840  return;
841  }
842 
843  /* next line added to allow objects which own objects */
844  /* Add a check for ownercounts in here, as I got into an endless loop
845  * with the fireball owning a poison cloud which then owned the
846  * fireball. I believe that was caused by one of the objects getting
847  * freed and then another object replacing it. Since the ownercounts
848  * didn't match, this check is valid and I believe that cause is valid.
849  */
850  /*
851  * if owner is NULL, function will have already returned,
852  * so loop should still function as before.
853  */
854  while (tmp) {
855  tmp = object_get_owner(owner);
856  if (tmp)
857  owner = tmp;
858  }
859 
860  /* must not cause owner cycles */
861  assert(op != owner);
862 
863  if (op->owner != NULL)
865 
866  op->owner = owner;
867  op->ownercount = owner->count;
868 }
869 
886 void object_copy_owner(object *op, object *clone) {
887  object *owner = object_get_owner(clone);
888  if (owner == NULL) {
889  /* players don't have owners - they own themselves. Update
890  * as appropriate.
891  */
892  /*TODO owner=self is dangerous and should be avoided*/
893  if (clone->type != PLAYER)
894  return;
895  owner = clone;
896  }
897  object_set_owner(op, owner);
898 }
899 
908 void object_set_enemy(object *op, object *enemy) {
909  if (op->enemy == enemy) {
910  return;
911  }
912 
913 #if 0
914  if (op->type != PLAYER) {
915  LOG(llevDebug, "object_set_enemy: %s(%lu)->enemy=%s(%lu)\n", op->name, op->count, enemy == NULL ? "NONE" : enemy->name, enemy == NULL ? 0 : enemy->count);
916  }
917 #endif
918  op->enemy = enemy;
919 }
920 
927 void object_reset(object *op) {
928  op->name = NULL;
929  op->name_pl = NULL;
930  op->title = NULL;
931  op->race = NULL;
932  op->slaying = NULL;
933  op->skill = NULL;
934  op->msg = NULL;
935  op->materialname = NULL;
936  op->lore = NULL;
937  object_clear(op);
938 }
939 
947 void object_free_key_values(object *op) {
948  key_value *i;
949  key_value *next = NULL;
950 
951  if (op->key_values == NULL)
952  return;
953 
954  for (i = op->key_values; i != NULL; i = next) {
955  /* Store next *first*. */
956  next = i->next;
957 
958  if (i->key)
960  if (i->value)
962  i->next = NULL;
963  free(i);
964  }
965 
966  op->key_values = NULL;
967 }
968 
976 void object_clear(object *op) {
977  /*TODO this comment must be investigated*/
978  /* redo this to be simpler/more efficient. Was also seeing
979  * crashes in the old code. Move this to the top - am
980  * seeing periodic crashes in this code, and would like to have
981  * as much info available as possible (eg, object name).
982  */
985 
986  /* the memset will clear all these values for us, but we need
987  * to reduce the refcount on them.
988  */
989  if (op->name != NULL)
990  FREE_AND_CLEAR_STR(op->name);
991  if (op->name_pl != NULL)
992  FREE_AND_CLEAR_STR(op->name_pl);
993  if (op->title != NULL)
994  FREE_AND_CLEAR_STR(op->title);
995  if (op->race != NULL)
996  FREE_AND_CLEAR_STR(op->race);
997  if (op->slaying != NULL)
998  FREE_AND_CLEAR_STR(op->slaying);
999  if (op->skill != NULL)
1000  FREE_AND_CLEAR_STR(op->skill);
1001  if (op->msg != NULL)
1002  FREE_AND_CLEAR_STR(op->msg);
1003  if (op->lore != NULL)
1004  FREE_AND_CLEAR_STR(op->lore);
1005  if (op->materialname != NULL)
1006  FREE_AND_CLEAR_STR(op->materialname);
1007 
1008  /* Remove object from friendly list if needed. */
1009  if (QUERY_FLAG(op, FLAG_FRIENDLY))
1011 
1012  memset((void *)((char *)op+offsetof(object, name)), 0, sizeof(object)-offsetof(object, name));
1013  /* Below here, we clear things that are not done by the memset,
1014  * or set default values that are not zero.
1015  */
1016  /* This is more or less true */
1018 
1019 
1020  op->contr = NULL;
1021  op->below = NULL;
1022  op->above = NULL;
1023  op->inv = NULL;
1024  op->container = NULL;
1025  op->env = NULL;
1026  op->more = NULL;
1027  op->head = NULL;
1028  op->map = NULL;
1029  op->active_next = NULL;
1030  op->active_prev = NULL;
1031  /* What is not cleared is next, prev, and count */
1032 
1033  op->expmul = 1.0;
1034  op->face = blank_face;
1035  op->attacked_by_count = -1;
1036  if (settings.casting_time)
1037  op->casting_time = -1;
1038 }
1039 
1053 void object_copy(const object *src_ob, object *dest_ob) {
1054  int is_freed = QUERY_FLAG(dest_ob, FLAG_FREED), is_removed = QUERY_FLAG(dest_ob, FLAG_REMOVED);
1055 
1056  /* Decrement the refcounts, but don't bother zeroing the fields;
1057  they'll be overwritten by memcpy. */
1058  if (dest_ob->artifact != NULL)
1059  free_string(dest_ob->artifact);
1060  if (dest_ob->name != NULL)
1061  free_string(dest_ob->name);
1062  if (dest_ob->name_pl != NULL)
1063  free_string(dest_ob->name_pl);
1064  if (dest_ob->anim_suffix != NULL)
1065  free_string(dest_ob->anim_suffix);
1066  if (dest_ob->title != NULL)
1067  free_string(dest_ob->title);
1068  if (dest_ob->race != NULL)
1069  free_string(dest_ob->race);
1070  if (dest_ob->slaying != NULL)
1071  free_string(dest_ob->slaying);
1072  if (dest_ob->skill != NULL)
1073  free_string(dest_ob->skill);
1074  if (dest_ob->msg != NULL)
1075  free_string(dest_ob->msg);
1076  if (dest_ob->lore != NULL)
1077  free_string(dest_ob->lore);
1078  if (dest_ob->materialname != NULL)
1079  free_string(dest_ob->materialname);
1080  if (dest_ob->custom_name != NULL)
1081  free_string(dest_ob->custom_name);
1082  if (dest_ob->spell_tags != NULL)
1083  FREE_AND_CLEAR(dest_ob->spell_tags);
1084 
1085  /* Basically, same code as from object_clear() */
1086 
1087  object_free_key_values(dest_ob);
1088  free_dialog_information(dest_ob);
1089 
1090  /* Copy all attributes below name (name included). */
1091  (void)memcpy((void *)((char *)dest_ob+offsetof(object, name)),
1092  (void *)((char *)src_ob+offsetof(object, name)),
1093  sizeof(object)-offsetof(object, name));
1094 
1095  if (is_freed)
1096  SET_FLAG(dest_ob, FLAG_FREED);
1097  if (is_removed)
1098  SET_FLAG(dest_ob, FLAG_REMOVED);
1099  if (dest_ob->artifact != NULL)
1100  add_refcount(dest_ob->artifact);
1101  if (dest_ob->name != NULL)
1102  add_refcount(dest_ob->name);
1103  if (dest_ob->name_pl != NULL)
1104  add_refcount(dest_ob->name_pl);
1105  if (dest_ob->anim_suffix != NULL)
1106  add_refcount(dest_ob->anim_suffix);
1107  if (dest_ob->title != NULL)
1108  add_refcount(dest_ob->title);
1109  if (dest_ob->race != NULL)
1110  add_refcount(dest_ob->race);
1111  if (dest_ob->slaying != NULL)
1112  add_refcount(dest_ob->slaying);
1113  if (dest_ob->skill != NULL)
1114  add_refcount(dest_ob->skill);
1115  if (dest_ob->lore != NULL)
1116  add_refcount(dest_ob->lore);
1117  if (dest_ob->msg != NULL)
1118  add_refcount(dest_ob->msg);
1119  if (dest_ob->custom_name != NULL)
1120  add_refcount(dest_ob->custom_name);
1121  if (dest_ob->materialname != NULL)
1122  add_refcount(dest_ob->materialname);
1123 
1124  if (dest_ob->spell_tags != NULL) {
1125  dest_ob->spell_tags = malloc(sizeof(tag_t)*SPELL_TAG_SIZE);
1126  memcpy(dest_ob->spell_tags, src_ob->spell_tags, sizeof(tag_t)*SPELL_TAG_SIZE);
1127  }
1128 
1129  /* If archetype is a temporary one, we need to update reference count, because
1130  * that archetype will be freed by object_free_drop_inventory() when the last object is removed.
1131  */
1132  if (dest_ob->arch != NULL) {
1133  if (dest_ob->arch->reference_count > 0)
1134  dest_ob->arch->reference_count++;
1135  }
1136 
1137  if (src_ob->speed < 0)
1138  dest_ob->speed_left = src_ob->speed_left-RANDOM()%200/100.0;
1139 
1140  /* Copy over key_values, if any. */
1141  if (src_ob->key_values != NULL) {
1142  key_value *tail = NULL;
1143  key_value *i;
1144 
1145  dest_ob->key_values = NULL;
1146 
1147  for (i = src_ob->key_values; i != NULL; i = i->next) {
1148  key_value *new_link = malloc(sizeof(key_value));
1149 
1150  new_link->next = NULL;
1151  new_link->key = add_refcount(i->key);
1152  if (i->value)
1153  new_link->value = add_refcount(i->value);
1154  else
1155  new_link->value = NULL;
1156 
1157  /* Try and be clever here, too. */
1158  if (dest_ob->key_values == NULL) {
1159  dest_ob->key_values = new_link;
1160  tail = new_link;
1161  } else {
1162  tail->next = new_link;
1163  tail = new_link;
1164  }
1165  }
1166  }
1167 
1168  /* This way, dialog information will be parsed again when/if needed. */
1169  CLEAR_FLAG(dest_ob, FLAG_DIALOG_PARSED);
1170 
1171  object_update_speed(dest_ob);
1172 }
1173 
1183 void object_copy_with_inv(const object *src_ob, object *dest_ob) {
1184  object_copy(src_ob, dest_ob);
1185  FOR_INV_PREPARE(src_ob, walk) {
1186  object *tmp;
1187 
1188  tmp = object_new();
1189  object_copy_with_inv(walk, tmp);
1190  object_insert_in_ob(tmp, dest_ob);
1191  } FOR_INV_FINISH();
1192 }
1193 
1201 static void expand_objects(void) {
1202  int i;
1203  object *new;
1204 
1205  new = (object *)CALLOC(OBJ_EXPAND, sizeof(object));
1206 
1207  if (new == NULL)
1209  free_objects = new;
1210  new[0].prev = NULL;
1211  new[0].next = &new[1],
1212  SET_FLAG(&new[0], FLAG_REMOVED);
1213  SET_FLAG(&new[0], FLAG_FREED);
1214 
1215  for (i = 1; i < OBJ_EXPAND-1; i++) {
1216  new[i].next = &new[i+1],
1217  new[i].prev = &new[i-1],
1218  SET_FLAG(&new[i], FLAG_REMOVED);
1219  SET_FLAG(&new[i], FLAG_FREED);
1220  }
1221  new[OBJ_EXPAND-1].prev = &new[OBJ_EXPAND-2],
1222  new[OBJ_EXPAND-1].next = NULL,
1223  SET_FLAG(&new[OBJ_EXPAND-1], FLAG_REMOVED);
1224  SET_FLAG(&new[OBJ_EXPAND-1], FLAG_FREED);
1225 
1228 }
1229 
1242 object *object_new(void) {
1243  object *op;
1244 #ifdef MEMORY_DEBUG
1245  /* FIXME: However this doesn't work since object_free() sometimes add
1246  * objects back to the free_objects linked list, and some functions mess
1247  * with the object after return of object_free(). This is bad and should be
1248  * fixed. But it would need fairly extensive changes and a lot of debugging.
1249  */
1250  op = calloc(1, sizeof(object));
1251  if (op == NULL)
1253 #else
1254  if (free_objects == NULL) {
1255  expand_objects();
1256  }
1257  op = free_objects;
1258  if (!QUERY_FLAG(op, FLAG_FREED)) {
1259  LOG(llevError, "Fatal: Getting busy object.\n");
1260 #ifdef MANY_CORES
1261  abort();
1262 #endif
1263  }
1264  free_objects = op->next;
1265  if (free_objects != NULL)
1266  free_objects->prev = NULL;
1267  nroffreeobjects--;
1268 #endif
1269  op->count = ++ob_count;
1270  op->name = NULL;
1271  op->name_pl = NULL;
1272  op->title = NULL;
1273  op->race = NULL;
1274  op->slaying = NULL;
1275  op->skill = NULL;
1276  op->lore = NULL;
1277  op->msg = NULL;
1278  op->materialname = NULL;
1279  op->next = objects;
1280  op->prev = NULL;
1281  op->active_next = NULL;
1282  op->active_prev = NULL;
1283  op->spell_tags = NULL;
1284  if (objects != NULL)
1285  objects->prev = op;
1286  objects = op;
1287  object_clear(op);
1289  return op;
1290 }
1291 
1301  if (op->animation == 0 || !QUERY_FLAG(op, FLAG_IS_TURNABLE))
1302  return;
1303  animate_object(op, op->direction);
1304 }
1305 
1317 void object_update_speed(object *op) {
1318  /* FIXME what the hell is this crappy hack?*/
1319  extern int arch_init;
1320 
1321  /* No reason putting the archetypes objects on the speed list,
1322  * since they never really need to be updated.
1323  */
1324 
1325  if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
1326  LOG(llevError, "Object %s is freed but has speed.\n", op->name);
1327 #ifdef MANY_CORES
1328  abort();
1329 #else
1330  op->speed = 0;
1331 #endif
1332  }
1333  if (arch_init) {
1334  return;
1335  }
1336  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
1337  /* If already on active list, don't do anything */
1338  /* TODO this check can probably be simplified a lot */
1339  if (op->active_next || op->active_prev || op == active_objects)
1340  return;
1341 
1342  /* process_events() expects us to insert the object at the beginning
1343  * of the list. */
1344  op->active_next = active_objects;
1345  if (op->active_next != NULL)
1346  op->active_next->active_prev = op;
1347  active_objects = op;
1348  } else {
1350  }
1351 }
1352 
1366  /* If not on the active list, nothing needs to be done */
1367  if (!op->active_next && !op->active_prev && op != active_objects)
1368  return;
1369 
1370  if (op->active_prev == NULL) {
1371  active_objects = op->active_next;
1372  if (op->active_next != NULL)
1373  op->active_next->active_prev = NULL;
1374  } else {
1375  op->active_prev->active_next = op->active_next;
1376  if (op->active_next)
1377  op->active_next->active_prev = op->active_prev;
1378  }
1379  op->active_next = NULL;
1380  op->active_prev = NULL;
1381 }
1382 
1407 void object_update(object *op, int action) {
1408  int update_now = 0, flags;
1409  MoveType move_on, move_off, move_block, move_slow;
1410  object *pl;
1411 
1412  if (op == NULL) {
1413  /* this should never happen */
1414  LOG(llevDebug, "object_update() called for NULL object.\n");
1415  return;
1416  }
1417 
1418  if (op->env != NULL) {
1419  /* Animation is currently handled by client, so nothing
1420  * to do in this case.
1421  */
1422  return;
1423  }
1424 
1425  /* If the map is saving, don't do anything as everything is
1426  * going to get freed anyways.
1427  */
1428  if (!op->map || op->map->in_memory == MAP_SAVING)
1429  return;
1430 
1431  /* make sure the object is within map boundaries */
1432  if (op->x < 0 || op->x >= MAP_WIDTH(op->map)
1433  || op->y < 0 || op->y >= MAP_HEIGHT(op->map)) {
1434  LOG(llevError, "object_update() called for object out of map!\n");
1435 #ifdef MANY_CORES
1436  abort();
1437 #endif
1438  return;
1439  }
1440 
1441  flags = GET_MAP_FLAGS(op->map, op->x, op->y);
1442  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NEED_UPDATE);
1443  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
1444  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
1445  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
1446  move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y);
1447 
1448  if (action == UP_OBJ_INSERT) {
1450  update_now = 1;
1451 
1453  update_now = 1;
1454 
1456  update_now = 1;
1457 
1458  if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags&P_IS_ALIVE))
1459  update_now = 1;
1460 
1461  if ((move_on|op->move_on) != move_on)
1462  update_now = 1;
1463  if ((move_off|op->move_off) != move_off)
1464  update_now = 1;
1465  /* This isn't perfect, but I don't expect a lot of objects to
1466  * to have move_allow right now.
1467  */
1468  if (((move_block|op->move_block)&~op->move_allow) != move_block)
1469  update_now = 1;
1470  if ((move_slow|op->move_slow) != move_slow)
1471  update_now = 1;
1472 
1473  if (op->type == PLAYER)
1474  update_now = 1;
1475  /* if the object is being removed, we can't make intelligent
1476  * decisions, because object_remove() can't really pass the object
1477  * that is being removed.
1478  */
1479  } else if (action == UP_OBJ_REMOVE) {
1480  update_now = 1;
1481  } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) {
1482  /* In addition to sending info to client, need to update space
1483  * information.
1484  */
1485  if (action == UP_OBJ_CHANGE)
1486  update_now = 1;
1487 
1488  /* There is a player on this space - we may need to send an
1489  * update to the client.
1490  * If this object is supposed to be animated by the client,
1491  * nothing to do here - let the client animate it.
1492  * We can't use FLAG_ANIMATE, as that is basically set for
1493  * all objects with multiple faces, regardless if they are animated.
1494  * (levers have it set for example).
1495  */
1496  if (flags&P_PLAYER
1499  pl = GET_MAP_PLAYER(op->map, op->x, op->y);
1500 
1501  /* If update_look is set, we're going to send this entire space
1502  * to the client, so no reason to send face information now.
1503  */
1504  if (!pl->contr->socket.update_look) {
1506  }
1507  }
1508  } else {
1509  LOG(llevError, "object_update called with invalid action: %d\n", action);
1510  }
1511 
1512  if (update_now) {
1514  update_position(op->map, op->x, op->y);
1515  }
1516 
1517  if (op->more != NULL)
1518  object_update(op->more, action);
1519 }
1520 
1534  object_free(ob, 0);
1535 }
1536 
1541 void object_free_inventory(object *ob) {
1542  while (ob->inv) {
1543  object *inv = ob->inv;
1544  object_remove(inv);
1546  }
1547 }
1548 
1565 void object_free(object *ob, int flags) {
1566  if (!QUERY_FLAG(ob, FLAG_REMOVED)) {
1567  StringBuffer *sb;
1568  char *diff;
1569 
1570  LOG(llevError, "Free object called with non removed object\n");
1571  sb = stringbuffer_new();
1572  object_dump(ob, sb);
1573  diff = stringbuffer_finish(sb);
1574  LOG(llevError, "%s", diff);
1575  free(diff);
1576 #ifdef MANY_CORES
1577  abort();
1578 #endif
1579  }
1580  if (QUERY_FLAG(ob, FLAG_FRIENDLY)) {
1581  LOG(llevMonster, "Warning: tried to free friendly object.\n");
1583  }
1584  if (QUERY_FLAG(ob, FLAG_FREED)) {
1585  StringBuffer *sb;
1586  char *diff;
1587 
1588  sb = stringbuffer_new();
1589  object_dump(ob, sb);
1590  diff = stringbuffer_finish(sb);
1591  LOG(llevError, "Trying to free freed object.\n%s\n", diff);
1592  free(diff);
1593  return;
1594  }
1595 
1596  if ((flags & FREE_OBJ_NO_DESTROY_CALLBACK) == 0) {
1598  }
1599 
1600  if (ob->inv) {
1601  /* Only if the space blocks everything do we not process -
1602  * if some form of movemnt is allowed, let objects
1603  * drop on that space.
1604  */
1605  if ((flags & FREE_OBJ_FREE_INVENTORY) != 0
1606  || ob->map == NULL
1607  || ob->map->in_memory != MAP_IN_MEMORY
1608  || (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL)) {
1609  FOR_INV_PREPARE(ob, op) {
1610  object_remove(op);
1611  object_free(op, flags);
1612  } FOR_INV_FINISH();
1613  } else { /* Put objects in inventory onto this space */
1614  FOR_INV_PREPARE(ob, op) {
1615  object_remove(op);
1616  /* No drop means no drop, including its inventory */
1617  if (QUERY_FLAG(op, FLAG_NO_DROP))
1619  else if (QUERY_FLAG(op, FLAG_STARTEQUIP)
1621  || op->type == RUNE
1622  || op->type == TRAP
1625  else {
1626  object *part;
1627 
1628  /* If it's a multi-tile object, scatter dropped items randomly */
1629  if (ob->more) {
1630  int partcount = 0;
1631  /* Get the number of non-head parts */
1632  for (part = ob; part; part = part->more) {
1633  partcount++;
1634  }
1635  /* Select a random part */
1636  partcount = RANDOM()%partcount;
1637  for (part = ob; partcount > 0; partcount--) {
1638  part = part->more;
1639  }
1640  } else {
1641  part = ob;
1642  }
1643 
1644  if (QUERY_FLAG(op, FLAG_ALIVE)) {
1645  object_insert_to_free_spot_or_free(op, part->map, part->x, part->y, 0, SIZEOFFREE, NULL);
1646  } else {
1647  int f = 0;
1650  object_insert_in_map_at(op, part->map, NULL, f, part->x, part->y); /* Insert in same map as the envir */
1651  }
1652  }
1653  } FOR_INV_FINISH();
1654  }
1655  }
1656 
1657  if (ob->more != NULL) {
1658  object_free(ob->more, flags);
1659  ob->more = NULL;
1660  }
1661 
1662  /* Remove object from the active list */
1663  ob->speed = 0;
1665 
1667  ob->count = 0;
1668 
1669  /* Remove this object from the list of used objects */
1670  if (ob->prev == NULL) {
1671  objects = ob->next;
1672  if (objects != NULL)
1673  objects->prev = NULL;
1674  } else {
1675  ob->prev->next = ob->next;
1676  if (ob->next != NULL)
1677  ob->next->prev = ob->prev;
1678  }
1679 
1680  if (ob->artifact != NULL) FREE_AND_CLEAR_STR(ob->artifact);
1681  if (ob->name != NULL) FREE_AND_CLEAR_STR(ob->name);
1682  if (ob->name_pl != NULL) FREE_AND_CLEAR_STR(ob->name_pl);
1683  if (ob->title != NULL) FREE_AND_CLEAR_STR(ob->title);
1684  if (ob->race != NULL) FREE_AND_CLEAR_STR(ob->race);
1685  if (ob->slaying != NULL) FREE_AND_CLEAR_STR(ob->slaying);
1686  if (ob->skill != NULL) FREE_AND_CLEAR_STR(ob->skill);
1687  if (ob->lore != NULL) FREE_AND_CLEAR_STR(ob->lore);
1688  if (ob->msg != NULL) FREE_AND_CLEAR_STR(ob->msg);
1689  if (ob->materialname != NULL) FREE_AND_CLEAR_STR(ob->materialname);
1690  if (ob->spell_tags) FREE_AND_CLEAR(ob->spell_tags);
1691  FREE_AND_CLEAR_STR_IF(ob->anim_suffix);
1692 
1693  /* Why aren't events freed? */
1695 
1697 
1698  /* Test whether archetype is a temporary one, and if so look whether it should be trashed. */
1699  if (ob->arch && ob->arch->reference_count > 0) {
1700  if (--ob->arch->reference_count == 0) {
1701  free_arch(ob->arch);
1702  }
1703  }
1704 
1705 #ifdef MEMORY_DEBUG
1706  free(ob);
1707 #else
1708  /* Now link it with the free_objects list: */
1709  ob->prev = NULL;
1710  ob->next = free_objects;
1711  if (free_objects != NULL)
1712  free_objects->prev = ob;
1713  free_objects = ob;
1714  nroffreeobjects++;
1715 #endif
1716 }
1717 
1725  int i = 0;
1726  object *tmp = free_objects;
1727 
1728  while (tmp != NULL)
1729  tmp = tmp->next,
1730  i++;
1731  return i;
1732 }
1733 
1741  int i = 0;
1742  object *tmp = objects;
1743 
1744  while (tmp != NULL)
1745  tmp = tmp->next,
1746  i++;
1747  return i;
1748 }
1749 
1757  int i = 0;
1758  object *tmp = active_objects;
1759 
1760  while (tmp != NULL)
1761  tmp = tmp->active_next,
1762  i++;
1763  return i;
1764 }
1765 
1780 void object_sub_weight(object *op, signed long weight) {
1781  while (op != NULL) {
1782  if (op->type == CONTAINER) {
1783  weight = (signed long)(weight*(100-op->stats.Str)/100);
1784  }
1785  op->carrying -= weight;
1786  op = op->env;
1787  }
1788 }
1789 
1806 void object_remove(object *op) {
1807  object *last = NULL;
1808  object *otmp;
1809  tag_t tag;
1810  int check_walk_off;
1811  mapstruct *m;
1812  int16_t x, y;
1813 
1814  if (QUERY_FLAG(op, FLAG_REMOVED)) {
1815  StringBuffer *sb;
1816  char *diff;
1817 
1818  sb = stringbuffer_new();
1819  object_dump(op, sb);
1820  diff = stringbuffer_finish(sb);
1821  LOG(llevError, "Trying to remove removed object.\n%s\n", diff);
1822  free(diff);
1823  abort();
1824  }
1825  if (op->more != NULL)
1826  object_remove(op->more);
1827 
1829 
1830  /*
1831  * In this case, the object to be removed is in someones
1832  * inventory.
1833  */
1834  /* TODO try to call a generic inventory weight adjusting function like object_sub_weight */
1835  if (op->env != NULL) {
1836  player *pl = NULL;
1837 
1838  if (op->nrof)
1839  object_sub_weight(op->env, op->weight*op->nrof);
1840  else
1841  object_sub_weight(op->env, op->weight+op->carrying);
1842 
1843  /* Update in two cases: item is in a player, or in a container the player is looking into. */
1844  if (op->env->contr != NULL && op->head == NULL) {
1845  pl = op->env->contr;
1846  } else if (op->env->type == CONTAINER && QUERY_FLAG(op->env, FLAG_APPLIED)) {
1847 
1848  if (op->env->env && op->env->env->contr)
1849  /* Container is in player's inventory. */
1850  pl = op->env->env->contr;
1851  else if (op->env->map) {
1852  /* Container on map, look above for player. */
1853  object *above = op->env->above;
1854 
1855  while (above && !above->contr)
1856  above = above->above;
1857  if (above)
1858  pl = above->contr;
1859  }
1860  }
1861 
1862  /* NO_FIX_PLAYER is set when a great many changes are being
1863  * made to players inventory. If set, avoiding the call
1864  * to save cpu time.
1865  */
1866  otmp = object_get_player_container(op->env);
1867  if (otmp != NULL
1868  && otmp->contr
1869  && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
1870  fix_object(otmp);
1871 
1872  if (op->above != NULL)
1873  op->above->below = op->below;
1874  else
1875  op->env->inv = op->below;
1876 
1877  if (op->below != NULL)
1878  op->below->above = op->above;
1879 
1880  /* we set up values so that it could be inserted into
1881  * the map, but we don't actually do that - it is up
1882  * to the caller to decide what we want to do.
1883  */
1884  op->x = op->env->x;
1885  op->y = op->env->y;
1886  op->ox = op->x;
1887  op->oy = op->y;
1888  op->map = op->env->map;
1889  op->above = NULL;
1890  op->below = NULL;
1891  /* send the delitem before resetting env, so container's contents be may
1892  * refreshed */
1893  if (LOOK_OBJ(op) && pl != NULL)
1894  esrv_del_item(pl, op);
1895  op->env = NULL;
1896  return;
1897  }
1898 
1899  /* If we get here, we are removing it from a map */
1900  if (op->map == NULL)
1901  return;
1902 
1903  if (op->contr != NULL && !op->contr->hidden)
1904  op->map->players--;
1905 
1906  x = op->x;
1907  y = op->y;
1908  m = get_map_from_coord(op->map, &x, &y);
1909 
1910  if (!m) {
1911  LOG(llevError, "object_remove called when object was on map but appears to not be within valid coordinates? %s (%d,%d)\n", op->map->path, op->x, op->y);
1912  abort();
1913  }
1914  if (op->map != m) {
1915  LOG(llevError, "object_remove: Object not really on map it claimed to be on? %s != %s, %d,%d != %d,%d\n", op->map->path, m->path, op->x, op->y, x, y);
1916  }
1917 
1918  /* link the object above us */
1919  if (op->above)
1920  op->above->below = op->below;
1921  else
1922  SET_MAP_TOP(m, x, y, op->below); /* we were top, set new top */
1923 
1924  /* Relink the object below us, if there is one */
1925  if (op->below) {
1926  op->below->above = op->above;
1927  } else {
1928  /* Nothing below, which means we need to relink map object for this space
1929  * use translated coordinates in case some oddness with map tiling is
1930  * evident
1931  */
1932  /*TODO is this check really needed?*/
1933  if (GET_MAP_OB(m, x, y) != op) {
1934  StringBuffer *sb;
1935  char *diff;
1936 
1937  sb = stringbuffer_new();
1938  object_dump(op, sb);
1939  diff = stringbuffer_finish(sb);
1940  LOG(llevError, "object_remove: GET_MAP_OB on %s does not return object to be removed even though it appears to be on the bottom?\n%s\n", m->path, diff);
1941  free(diff);
1942 
1943  sb = stringbuffer_new();
1944  object_dump(GET_MAP_OB(m, x, y), sb);
1945  diff = stringbuffer_finish(sb);
1946  LOG(llevError, "%s\n", diff);
1947  free(diff);
1948  }
1949  SET_MAP_OB(m, x, y, op->above); /* goes on above it. */
1950  }
1951  op->above = NULL;
1952  op->below = NULL;
1953 
1954  if (op->map->in_memory == MAP_SAVING)
1955  return;
1956 
1957  tag = op->count;
1958  check_walk_off = !QUERY_FLAG(op, FLAG_NO_APPLY);
1959  FOR_MAP_PREPARE(m, x, y, tmp) {
1960  /* No point updating the players look faces if he is the object
1961  * being removed.
1962  */
1963 
1964  if (tmp->type == PLAYER && tmp != op) {
1965  /* If a container that the player is currently using somehow gets
1966  * removed (most likely destroyed), update the player view
1967  * appropriately.
1968  */
1969  if (tmp->container == op) {
1971  tmp->container = NULL;
1972  }
1973  tmp->contr->socket.update_look = 1;
1974  }
1975  /* See if player moving off should effect something */
1976  if (check_walk_off
1977  && ((op->move_type&tmp->move_off) && (op->move_type&~tmp->move_off&~tmp->move_block) == 0)) {
1978  ob_move_on(tmp, op, NULL);
1979  if (object_was_destroyed(op, tag)) {
1980  LOG(llevError, "BUG: object_remove(): name %s, archname %s destroyed leaving object\n", tmp->name, tmp->arch->name);
1981  }
1982  }
1983 
1984  /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
1985  if (tmp->above == tmp)
1986  tmp->above = NULL;
1987  last = tmp;
1988  } FOR_MAP_FINISH();
1989  /* last == NULL or there are no objects on this space */
1990  if (last == NULL) {
1991  /* set P_NEED_UPDATE, otherwise update_position will complain. In theory,
1992  * we could preserve the flags (GET_MAP_FLAGS), but update_position figures
1993  * those out anyways, and if there are any flags set right now, they won't
1994  * be correct anyways.
1995  */
1996  SET_MAP_FLAGS(op->map, op->x, op->y, P_NEED_UPDATE);
1997  update_position(op->map, op->x, op->y);
1998  } else
2000 
2001  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) || (op->glow_radius != 0))
2002  update_all_los(op->map, op->x, op->y);
2003 }
2004 
2018 object *object_merge(object *op, object *top) {
2019  if (!op->nrof)
2020  return NULL;
2021 
2022  if (top == NULL)
2023  for (top = op; top != NULL && top->above != NULL; top = top->above)
2024  ;
2026  if (top == op)
2027  continue;
2028  if (object_can_merge(op, top)) {
2029  object_increase_nrof(top, op->nrof);
2030  /*
2031  * Previous behavior set weight to zero here.
2032  * This, however, caused the object_sub_weight
2033  * call in object_remove to subtract zero weight
2034  * when removing the object. Thus, until inventory
2035  * weight is next recalculated, the object merged
2036  * into another pile added weight in object_increase_nrof
2037  * but did not remove the weight from the original
2038  * instance of itself in object_remove, essentially
2039  * counting for double weight for several minutes.
2040  *
2041  * SilverNexus 2014-05-27
2042  */
2043  object_remove(op);
2045  return top;
2046  }
2048  return NULL;
2049 }
2050 
2067 object *object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y) {
2068  object *tmp;
2069 
2070  op = HEAD(op);
2071  for (tmp = op; tmp; tmp = tmp->more) {
2072  tmp->x = x+tmp->arch->clone.x;
2073  tmp->y = y+tmp->arch->clone.y;
2074  tmp->map = m;
2075  }
2076  return object_insert_in_map(op, m, originator, flag);
2077 }
2078 
2096 void object_merge_spell(object *op, int16_t x, int16_t y) {
2097  int i;
2098 
2099  /* We try to do some merging of spell objects - if something has same owner,
2100  * is same type of spell, and going in the same direction, it is somewhat
2101  * mergable.
2102  *
2103  * If the spell object has an other_arch, don't merge - when the spell
2104  * does something, like explodes, it will use this other_arch, and
2105  * if we merge, there is no easy way to make the correct values be
2106  * set on this new object (values should be doubled, tripled, etc.)
2107  *
2108  * We also care about speed - only process objects that will not be
2109  * active this tick. Without this, the results are incorrect - think
2110  * of a case where tmp would normally get processed this tick, but
2111  * get merges with op, which does not get processed.
2112  */
2113  FOR_MAP_PREPARE(op->map, x, y, tmp) {
2114  if (op->type == tmp->type
2115  && op->subtype == tmp->subtype
2116  && op->direction == tmp->direction
2117  && op->owner == tmp->owner && op->ownercount == tmp->ownercount
2118  && op->range == tmp->range
2119  && op->stats.wc == tmp->stats.wc
2120  && op->level == tmp->level
2121  && op->attacktype == tmp->attacktype
2122  && op->speed == tmp->speed
2123  && !tmp->other_arch
2124  && (tmp->speed_left+tmp->speed) < 0.0
2125  && op != tmp) {
2126  /* Quick test - if one or the other objects already have hash tables
2127  * set up, and that hash bucket contains a value that doesn't
2128  * match what we want to set it up, we won't be able to merge.
2129  * Note that these two if statements are the same, except
2130  * for which object they are checking against. They could
2131  * be merged, but the line wrapping would be large enough
2132  * that IMO it would become difficult to read the different clauses
2133  * so its cleaner just to do 2 statements - MSW
2134  */
2135  if (op->spell_tags
2136  && !OB_SPELL_TAG_MATCH(op, (tag_t)tmp->stats.maxhp)
2137  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0)
2138  continue;
2139 
2140  if (tmp->spell_tags
2141  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)op->stats.maxhp)
2142  && OB_SPELL_TAG_HASH(tmp, op->stats.maxhp) != 0)
2143  continue;
2144 
2145  /* If we merge, the data from tmp->spell_tags gets copied into op.
2146  * so we need to make sure that slot isn't filled up.
2147  */
2148  if (tmp->spell_tags
2149  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)tmp->stats.maxhp)
2150  && OB_SPELL_TAG_HASH(tmp, tmp->stats.maxhp) != 0)
2151  continue;
2152 
2153  /* If both objects have spell_tags, we need to see if there are conflicting
2154  * values - if there are, we won't be able to merge then.
2155  */
2156  if (tmp->spell_tags && op->spell_tags) {
2157  int need_copy = 0;
2158 
2159  for (i = 0; i < SPELL_TAG_SIZE; i++) {
2160  /* If the two tag values in the hash are set, but are
2161  * not set to the same value, then these objects
2162  * can not be merged.
2163  */
2164  if (op->spell_tags[i] && tmp->spell_tags[i]
2165  && op->spell_tags[i] != tmp->spell_tags[i]) {
2167  break;
2168  }
2169  /* If one tag is set and the other is not, that is
2170  * fine, but we have to note that we need to copy
2171  * the data in that case.
2172  */
2173  if ((!op->spell_tags[i] && tmp->spell_tags[i])
2174  || (op->spell_tags[i] && !tmp->spell_tags[i])) {
2175  need_copy = 1;
2176  }
2177  }
2178  /* If we did not get through entire array, it means
2179  * we got a conflicting hash, and so we won't be
2180  * able to merge these - just continue processing
2181  * object on this space.
2182  */
2183  if (i <= SPELL_TAG_SIZE)
2184  continue;
2185 
2186  /* Ok - everything checked out - we should be able to
2187  * merge tmp in op. So lets copy the tag data if
2188  * needed. Note that this is a selective copy, as
2189  * we don't want to clear values that may be set in op.
2190  */
2191  if (need_copy) {
2192  for (i = 0; i < SPELL_TAG_SIZE; i++)
2193  if (!op->spell_tags[i]
2194  && tmp->spell_tags[i]
2195  && tmp->spell_tags[i] != (tag_t)op->stats.maxhp)
2196  op->spell_tags[i] = tmp->spell_tags[i];
2197  }
2198  FREE_AND_CLEAR(tmp->spell_tags);
2199  }
2200 
2201  /* if tmp has a spell_tags table, copy it to op and free tmps */
2202  if (tmp->spell_tags && !op->spell_tags) {
2203  op->spell_tags = tmp->spell_tags;
2204  tmp->spell_tags = NULL;
2205 
2206  /* We don't need to keep a copy of our maxhp value
2207  * in the copied over value
2208  */
2209  if (OB_SPELL_TAG_MATCH(op, (tag_t)op->stats.maxhp))
2210  OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0;
2211  }
2212 
2213  /* For spells to work correctly, we need to record what spell
2214  * tags we've merged in with this effect. This is used
2215  * in ok_to_put_more() to see if a spell effect is already on
2216  * the space.
2217  */
2218  if (op->stats.maxhp != tmp->stats.maxhp) {
2219 #ifdef OBJECT_DEBUG
2220  /* This if statement should never happen - the logic above should
2221  * have prevented it. It is a problem, because by now its possible
2222  * we've destroyed the spell_tags in tmp, so we can't really
2223  * just bail out.
2224  */
2225 
2226  if (op->spell_tags
2227  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0
2228  && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)) {
2229  LOG(llevError, "object_insert_in_map: Got non matching spell tags: %d != %d\n", OB_SPELL_TAG_HASH(op, tmp->stats.maxhp), tmp->stats.maxhp);
2230  }
2231 #endif
2232  if (!op->spell_tags)
2233  op->spell_tags = calloc(SPELL_TAG_SIZE, sizeof(tag_t));
2234 
2235  OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) = tmp->stats.maxhp;
2236  }
2237 
2239  op->speed_left = MAX(op->speed_left, tmp->speed_left);
2240 
2241  if (tmp->duration != op->duration) {
2242  /* We need to use tmp_dam here because otherwise the
2243  * calculations can overflow the size of stats.dam.
2244  */
2245  int tmp_dam = tmp->stats.dam*(tmp->duration+1)+
2246  op->stats.dam*(op->duration+1);
2247 
2248  op->duration = MAX(op->duration, tmp->duration);
2249  tmp_dam /= op->duration+1;
2250  op->stats.dam = tmp_dam+1;
2251  } else {
2252  /* in this case, duration is the same, so simply adding
2253  * up damage works.
2254  */
2255  op->stats.dam += tmp->stats.dam;
2256  }
2257 
2258  object_remove(tmp);
2260  }
2261  } FOR_MAP_FINISH();
2262 }
2263 
2264 static object *find_insert_pos(object *op, const int flag) {
2265  object *floor = NULL;
2266  /*
2267  * If there are multiple objects on this space, we do some trickier handling.
2268  * We've already dealt with merging if appropriate.
2269  * Generally, we want to put the new object on top. But if
2270  * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
2271  * floor, we want to insert above that and no further.
2272  * Also, if there are spell objects on this space, we stop processing
2273  * once we get to them. This reduces the need to traverse over all of
2274  * them when adding another one - this saves quite a bit of cpu time
2275  * when lots of spells are cast in one area. Currently, it is presumed
2276  * that flying non pickable objects are spell objects.
2277  */
2278  if (flag&INS_ON_TOP) {
2279  return GET_MAP_TOP(op->map, op->x, op->y);
2280  }
2281  object *last = NULL;
2282  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2285  floor = tmp;
2286 
2288  && (tmp->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH))
2289  && !QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2290  /* We insert above tmp, so we want this object below this */
2291  break;
2292  }
2293  last = tmp;
2294  } FOR_MAP_FINISH();
2295  if (flag&INS_ABOVE_FLOOR_ONLY)
2296  return floor;
2297  return last;
2298 }
2299 
2328 object *object_insert_in_map(object *op, mapstruct *m, object *originator, int flag) {
2329  object *tmp, *top, *floor = NULL;
2330  int16_t x, y;
2331 
2332  if (QUERY_FLAG(op, FLAG_FREED)) {
2333  LOG(llevError, "Trying to insert freed object!\n");
2334  return NULL;
2335  }
2336  if (m == NULL) {
2337  StringBuffer *sb;
2338  char *diff;
2339 
2340  sb = stringbuffer_new();
2341  object_dump(op, sb);
2342  diff = stringbuffer_finish(sb);
2343  LOG(llevError, "Trying to insert in null-map!\n%s\n", diff);
2344  free(diff);
2345  return op;
2346  }
2347  if (out_of_map(m, op->x, op->y)) {
2348  StringBuffer *sb;
2349  char *diff;
2350 
2351  sb = stringbuffer_new();
2352  object_dump(op, sb);
2353  diff = stringbuffer_finish(sb);
2354  LOG(llevError, "Trying to insert object outside the map.\n%s\n", diff);
2355  free(diff);
2356 #ifdef MANY_CORES
2357  /* Better to catch this here, as otherwise the next use of this object
2358  * is likely to cause a crash. Better to find out where it is getting
2359  * improperly inserted.
2360  */
2361  abort();
2362 #endif
2363  return op;
2364  }
2365  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2366  StringBuffer *sb;
2367  char *diff;
2368 
2369  sb = stringbuffer_new();
2370  object_dump(op, sb);
2371  diff = stringbuffer_finish(sb);
2372  LOG(llevError, "Trying to insert (map) inserted object.\n%s\n", diff);
2373  free(diff);
2374  return op;
2375  }
2376  if (op->more != NULL) {
2377  /* The part may be on a different map. */
2378 
2379  object *more = op->more;
2380 
2381  /* We really need the caller to normalize coordinates - if
2382  * we set the map, that doesn't work if the location is within
2383  * a map and this is straddling an edge. So only if coordinate
2384  * is clear wrong do we normalize it.
2385  */
2386  if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
2387  /* Debugging information so you can see the last coordinates this object had */
2388  more->ox = more->x;
2389  more->oy = more->y;
2390  more->map = get_map_from_coord(more->map, &more->x, &more->y);
2391  } else if (!more->map) {
2392  /* For backwards compatibility - when not dealing with tiled maps,
2393  * more->map should always point to the parent.
2394  */
2395  more->map = m;
2396  }
2397 
2398  if (object_insert_in_map(more, more->map, originator, flag) == NULL) {
2399  if (!op->head)
2400  LOG(llevError, "BUG: object_insert_in_map(): inserting op->more killed op\n");
2401  return NULL;
2402  }
2403  }
2405 
2406  /* Debugging information so you can see the last coordinates this object had */
2407  op->ox = op->x;
2408  op->oy = op->y;
2409  x = op->x;
2410  y = op->y;
2411  op->map = get_map_from_coord(m, &x, &y);
2412 
2413  /* this has to be done after we translate the coordinates. */
2414  if (op->nrof
2415  && !(flag&INS_NO_MERGE)
2416  && op->type != SPELL_EFFECT) {
2417  FOR_MAP_PREPARE(op->map, x, y, spot) {
2418  if (object_can_merge(op, spot)) {
2419  op->nrof += spot->nrof;
2420  object_remove(spot);
2422  }
2423  } FOR_MAP_FINISH();
2424  } else if (op->type == SPELL_EFFECT
2425  && !op->range
2426  && !op->other_arch
2427  && (op->speed_left+op->speed) < 0.0) {
2428  object_merge_spell(op, x, y);
2429  }
2430 
2431  /* Ideally, the caller figures this out. However, it complicates a lot
2432  * of areas of callers (eg, anything that uses object_find_free_spot() would now
2433  * need extra work
2434  */
2435  if (op->map != m) {
2436  /* coordinates should not change unless map also changes */
2437  op->x = x;
2438  op->y = y;
2439  }
2440 
2441  if (op->type != LAMP)
2442  /* lamps use the FLAG_APPLIED to keep the light/unlit status, so don't reset it.
2443  Other objects just get unapplied, since the container "drops" them. */
2446  if (!QUERY_FLAG(op, FLAG_ALIVE))
2448 
2449  /* In many places, a player is passed as the originator, which
2450  * is fine. However, if the player is on a transport, they are not
2451  * actually on the map, so we can't use them for the linked pointers,
2452  * nor should the walk on function below use them either.
2453  */
2454  if (originator && originator->contr && originator->contr->transport)
2455  originator = originator->contr->transport;
2456 
2457  if (flag&INS_BELOW_ORIGINATOR) {
2458  if (originator->map != op->map
2459  || originator->x != op->x
2460  || originator->y != op->y) {
2461  LOG(llevError, "object_insert_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
2462  abort();
2463  }
2464  op->above = originator;
2465  op->below = originator->below;
2466  if (op->below)
2467  op->below->above = op;
2468  else
2469  SET_MAP_OB(op->map, op->x, op->y, op);
2470  /* since *below *originator, no need to update top */
2471  originator->below = op;
2472  } else {
2473  /* Top is the object that our object (op) is going to get inserted above. */
2474  top = find_insert_pos(op, flag);
2475 
2476  /* First object on this space */
2477  if (!top) {
2478  op->above = GET_MAP_OB(op->map, op->x, op->y);
2479  if (op->above)
2480  op->above->below = op;
2481  op->below = NULL;
2482  SET_MAP_OB(op->map, op->x, op->y, op);
2483  } else { /* get inserted into the stack above top */
2484  op->above = top->above;
2485  if (op->above)
2486  op->above->below = op;
2487  op->below = top;
2488  top->above = op;
2489  }
2490  if (op->above == NULL)
2491  SET_MAP_TOP(op->map, op->x, op->y, op);
2492  } /* else not INS_BELOW_ORIGINATOR */
2493 
2494  if (!(flag&INS_MAP_LOAD)) {
2495  if (op->type == PLAYER)
2496  op->contr->do_los = 1;
2497 
2498  /* If we have a floor, we know the player, if any, will be above
2499  * it, so save a few ticks and start from there.
2500  */
2501  tmp = floor ? floor : GET_MAP_OB(op->map, op->x, op->y);
2503  if (tmp->type == PLAYER)
2504  tmp->contr->socket.update_look = 1;
2506 
2507  /* If this object glows, it may affect lighting conditions that are
2508  * visible to others on this map. But update_all_los is really
2509  * an inefficient way to do this, as it means los for all players
2510  * on the map will get recalculated. The players could very well
2511  * be far away from this change and not affected in any way -
2512  * this should get redone to only look for players within range,
2513  * or just updating the P_NEED_UPDATE for spaces within this area
2514  * of effect may be sufficient.
2515  */
2516  if (MAP_DARKNESS(op->map) && (op->glow_radius != 0))
2517  update_all_los(op->map, op->x, op->y);
2518 
2519  if (op->contr && !op->contr->hidden)
2520  op->map->players++;
2521  }
2522 
2523  /* updates flags (blocked, alive, no magic, etc) for this map space */
2525 
2526  /* Don't know if moving this to the end will break anything. However,
2527  * we want to have update_look set above before calling this.
2528  *
2529  * object_check_move_on() must be after this because code called from
2530  * object_check_move_on() depends on correct map flags (so functions like
2531  * blocked() and wall() work properly), and these flags are updated by
2532  * object_update().
2533  */
2534 
2535  /* if this is not the head or flag has been passed, don't check walk on status */
2536 
2537  if (!(flag&INS_NO_WALK_ON) && !op->head) {
2538  if (object_check_move_on(op, originator))
2539  return NULL;
2540 
2541  /* If we are a multi part object, lets work our way through the check
2542  * walk on's.
2543  */
2544  for (tmp = op->more; tmp != NULL; tmp = tmp->more)
2545  if (object_check_move_on(tmp, originator))
2546  return NULL;
2547  }
2548  return op;
2549 }
2550 
2560 void object_replace_insert_in_map(const char *arch_string, object *op) {
2561  object *tmp1;
2562  archetype *at;
2563 
2564  /* first search for itself and remove any old instances */
2565  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2566  if (!strcmp(tmp->arch->name, arch_string)) { /* same archetype */
2567  object_remove(tmp);
2569  }
2570  } FOR_MAP_FINISH();
2571 
2572  at = find_archetype(arch_string);
2573  if (at == NULL) {
2574  return;
2575  }
2576  tmp1 = arch_to_object(at);
2577  object_insert_in_map_at(tmp1, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
2578 }
2579 
2600 object *object_split(object *orig_ob, uint32_t nr, char *err, size_t size) {
2601  object *newob;
2602 
2603  if (MAX(1, orig_ob->nrof) < nr) {
2604  /* If err is set, the caller knows that nr can be wrong (player trying to drop items), thus don't log that. */
2605  if (err)
2606  snprintf(err, size, "There are only %u %ss.", NROF(orig_ob), orig_ob->name);
2607  else
2608  LOG(llevDebug, "There are only %u %ss.\n", NROF(orig_ob), orig_ob->name);
2609  return NULL;
2610  }
2611  newob = object_create_clone(orig_ob);
2612  if (orig_ob->nrof == 0) {
2613  if (!QUERY_FLAG(orig_ob, FLAG_REMOVED)) {
2614  object_remove(orig_ob);
2615  }
2617  } else {
2618  newob->nrof = nr;
2619  object_decrease_nrof(orig_ob, nr);
2620  }
2621 
2622  return newob;
2623 }
2624 
2639 object *object_decrease_nrof(object *op, uint32_t i) {
2640  object *tmp;
2641 
2642  if (i == 0) /* objects with op->nrof require this check */
2643  return op;
2644 
2645  if (i > op->nrof)
2646  i = op->nrof;
2647 
2648  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2649  op->nrof -= i;
2650  } else if (op->env != NULL) {
2651  if (i < op->nrof) {
2652  player *pl;
2653  /* is this object in the players inventory, or sub container
2654  * therein?
2655  */
2657  /* nope. Is this a container the player has opened?
2658  * If so, set tmp to that player.
2659  * IMO, searching through all the players will mostly
2660  * likely be quicker than following op->env to the map,
2661  * and then searching the map for a player.
2662  */
2663  if (!tmp) {
2664  for (pl = first_player; pl; pl = pl->next)
2665  if (pl->ob->container == op->env)
2666  break;
2667  if (pl)
2668  tmp = pl->ob;
2669  else
2670  tmp = NULL;
2671  }
2672 
2673  /* Because of weight reduction by container and integer arithmetic,
2674  * there is no guarantee the rounded weight of combined items will be
2675  * the same as the sum of rounded weights.
2676  * Therefore just remove the current weight, and add the new.
2677  * Same adjustment done in object_increase_nrof().
2678  */
2679  object_sub_weight(op->env, op->weight * op->nrof);
2680  op->nrof -= i;
2681  object_add_weight(op->env, op->weight * op->nrof);
2682  if (tmp) {
2685  fix_object(tmp);
2686  }
2687  } else {
2688  object_remove(op);
2689  op->nrof = 0;
2690  }
2691  } else {
2692  /* On a map. */
2693  if (i < op->nrof) {
2694  op->nrof -= i;
2695 
2696  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2697  if (pl->contr) {
2698  pl->contr->socket.update_look = 1;
2699  break;
2700  }
2701  FOR_MAP_FINISH();
2702  } else {
2703  object_remove(op);
2704  op->nrof = 0;
2705  }
2706  }
2707 
2708  if (op->nrof) {
2709  return op;
2710  } else {
2712  return NULL;
2713  }
2714 }
2715 
2726 static void object_increase_nrof(object *op, uint32_t i) {
2727  object *tmp;
2728 
2729  if (i == 0) /* objects with op->nrof require this check */
2730  return;
2731 
2732  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2733  op->nrof += i;
2734  } else if (op->env != NULL) {
2735  player *pl;
2736  /* is this object in the players inventory, or sub container
2737  * therein?
2738  */
2740  /* nope. Is this a container the player has opened?
2741  * If so, set tmp to that player.
2742  * IMO, searching through all the players will mostly
2743  * likely be quicker than following op->env to the map,
2744  * and then searching the map for a player.
2745  */
2746  if (!tmp) {
2747  for (pl = first_player; pl; pl = pl->next)
2748  if (pl->ob->container == op->env)
2749  break;
2750  if (pl)
2751  tmp = pl->ob;
2752  else
2753  tmp = NULL;
2754  }
2755 
2756  /* Because of weight reduction by container and integer arithmetic,
2757  * there is no guarantee the rounded weight of combined items will be
2758  * the same as the sum of rounded weights.
2759  * Therefore just remove the current weight, and add the new.
2760  * Same adjustment done in object_decrease_nrof().
2761  */
2762  object_sub_weight(op->env, op->weight * op->nrof);
2763  op->nrof += i;
2764  object_add_weight(op->env, op->weight * op->nrof);
2765  if (tmp) {
2767  // Why don't we need to update weight of op->env here?
2768  }
2769  } else {
2770  /* On a map. */
2771  op->nrof += i;
2772 
2773  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2774  if (pl->contr) {
2775  pl->contr->socket.update_look = 1;
2776  break;
2777  }
2778  FOR_MAP_FINISH();
2779  }
2780 }
2781 
2796 void object_add_weight(object *op, signed long weight) {
2797  while (op != NULL) {
2798  if (op->type == CONTAINER) {
2799  weight = (signed long)(weight*(100-op->stats.Str)/100);
2800  }
2801  op->carrying += weight;
2802  op = op->env;
2803  }
2804 }
2805 
2820 object *object_insert_in_ob(object *op, object *where) {
2821  object *otmp;
2822 
2823  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2824  StringBuffer *sb;
2825  char *diff;
2826 
2827  sb = stringbuffer_new();
2828  object_dump(op, sb);
2829  diff = stringbuffer_finish(sb);
2830  LOG(llevError, "Trying to insert (ob) inserted object.\n%s\n", diff);
2831  free(diff);
2832  return op;
2833  }
2834 
2835  if (where == NULL) {
2836  StringBuffer *sb;
2837  char *diff;
2838 
2839  sb = stringbuffer_new();
2840  object_dump(op, sb);
2841  diff = stringbuffer_finish(sb);
2842  LOG(llevError, "Trying to put object in NULL.\n%s\n", diff);
2843  free(diff);
2844  return op;
2845  }
2846  if (where->head) {
2847  LOG(llevDebug, "Warning: Tried to insert object wrong part of multipart object.\n");
2848  }
2849  where = HEAD(where);
2850  if (op->more) {
2851  LOG(llevError, "Tried to insert multipart object %s (%u)\n", op->name, op->count);
2852  return op;
2853  }
2856  if (op->nrof) {
2858  if (object_can_merge(tmp, op)) {
2859  /* return the original object and remove inserted object
2860  * (client needs the original object) */
2861  object_increase_nrof(tmp, op->nrof);
2863  object_free(op, FREE_OBJ_FREE_INVENTORY | FREE_OBJ_NO_DESTROY_CALLBACK); /* free the inserted object */
2864  return tmp;
2865  }
2866  FOR_INV_FINISH();
2867 
2868  /* the item couldn't merge. */
2869  object_add_weight(where, op->weight*op->nrof);
2870  } else
2871  object_add_weight(where, op->weight+op->carrying);
2872 
2873  op->map = NULL;
2874  op->env = where;
2875  op->above = NULL;
2876  op->below = NULL;
2877  op->x = 0,
2878  op->y = 0;
2879  op->ox = 0,
2880  op->oy = 0;
2881 
2882  /* Client has no idea of ordering so lets not bother ordering it here.
2883  * It sure simplifies this function...
2884  */
2885  if (where->inv == NULL)
2886  where->inv = op;
2887  else {
2888  op->below = where->inv;
2889  op->below->above = op;
2890  where->inv = op;
2891  }
2892 
2893  /* Update in 2 cases: object goes into player's inventory, or object goes into container the player
2894  * is looking into. */
2895  if (where->contr != NULL)
2897  else if (where->type == CONTAINER && QUERY_FLAG(where, FLAG_APPLIED)) {
2898  object *pl = NULL;
2899 
2900  if (op->env->env && op->env->env->contr)
2901  /* Container is in player's inventory. */
2902  pl = op->env->env;
2903  else if (op->env->map) {
2904  /* Container on map, look above for player. */
2905  FOR_ABOVE_PREPARE(op->env, above)
2906  if (above->contr) {
2907  pl = above;
2908  break;
2909  }
2910  FOR_ABOVE_FINISH();
2911  }
2912  if (pl)
2913  esrv_send_item(pl, op);
2914  }
2915 
2917  if (otmp && otmp->contr != NULL) {
2918  if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER)
2919  && (QUERY_FLAG(op, FLAG_APPLIED) || op->type == SKILL || op->glow_radius != 0))
2920  /* fix_object will only consider applied items, or skills, or items with a glow radius.
2921  thus no need to call it if our object hasn't that. */
2922  fix_object(otmp);
2923  }
2924 
2925  /* reset the light list and los of the players on the map */
2926  if (op->glow_radius != 0 && where->map) {
2927 #ifdef DEBUG_LIGHTS
2928  LOG(llevDebug, " object_insert_in_ob(): got %s to insert in map/op\n", op->name);
2929 #endif /* DEBUG_LIGHTS */
2930  if (MAP_DARKNESS(where->map)) {
2931  SET_MAP_FLAGS(where->map, where->x, where->y, P_NEED_UPDATE);
2932  update_position(where->map, where->x, where->y);
2933  update_all_los(where->map, where->x, where->y);
2934  }
2935  }
2936 
2937  return op;
2938 }
2939 
2962 int object_check_move_on(object *op, object *originator) {
2963  object *tmp;
2964  tag_t tag;
2965  mapstruct *m = op->map;
2966  int x = op->x, y = op->y;
2967  MoveType move_on, move_slow, move_block;
2968 
2969  if (QUERY_FLAG(op, FLAG_NO_APPLY))
2970  return 0;
2971 
2972  tag = op->count;
2973 
2974  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
2975  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
2976  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
2977 
2978  /* if nothing on this space will slow op down or be applied,
2979  * no need to do checking below. have to make sure move_type
2980  * is set, as lots of objects don't have it set - we treat that
2981  * as walking.
2982  */
2983  if (op->move_type
2984  && !(op->move_type&move_on)
2985  && !(op->move_type&move_slow))
2986  return 0;
2987 
2988  /* This is basically inverse logic of that below - basically,
2989  * if the object can avoid the move on or slow move, they do so,
2990  * but can't do it if the alternate movement they are using is
2991  * blocked. Logic on this seems confusing, but does seem correct.
2992  */
2993  if ((op->move_type&~move_on&~move_block) != 0
2994  && (op->move_type&~move_slow&~move_block) != 0)
2995  return 0;
2996 
2997  /* The objects have to be checked from top to bottom.
2998  * Hence, we first go to the top:
2999  */
3000 
3001  tmp = GET_MAP_OB(op->map, op->x, op->y);
3003  if (tmp->above == NULL)
3004  break;
3005  /* Trim the search when we find the first other spell effect
3006  * this helps performance so that if a space has 50 spell objects,
3007  * we don't need to check all of them.
3008  */
3009  if ((tmp->move_type&MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK))
3010  break;
3013  if (tmp == op)
3014  continue; /* Can't apply yourself */
3015 
3016  /* Check to see if one of the movement types should be slowed down.
3017  * Second check makes sure that the movement types not being slowed
3018  * (~slow_move) is not blocked on this space - just because the
3019  * space doesn't slow down swimming (for example), if you can't actually
3020  * swim on that space, can't use it to avoid the penalty.
3021  */
3022  if (!QUERY_FLAG(op, FLAG_WIZPASS)) {
3023  if ((!op->move_type && tmp->move_slow&MOVE_WALK)
3024  || ((op->move_type&tmp->move_slow) && (op->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
3025  float diff;
3026 
3027  diff = tmp->move_slow_penalty*FABS(op->speed);
3028  if (op->type == PLAYER) {
3031  diff /= 4.0;
3032  }
3033  }
3034  op->speed_left -= diff;
3035  }
3036  }
3037 
3038  /* Basically same logic as above, except now for actual apply. */
3039  if ((!op->move_type && tmp->move_on&MOVE_WALK)
3040  || ((op->move_type&tmp->move_on) && (op->move_type&~tmp->move_on&~tmp->move_block) == 0)) {
3041  ob_move_on(tmp, op, originator);
3042  if (object_was_destroyed(op, tag))
3043  return 1;
3044 
3045  /* what the person/creature stepped onto has moved the object
3046  * someplace new. Don't process any further - if we did,
3047  * have a feeling strange problems would result.
3048  */
3049  if (op->map != m || op->x != x || op->y != y)
3050  return 0;
3051  }
3053  return 0;
3054 }
3055 
3068 object *map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at) {
3069  if (m == NULL || OUT_OF_REAL_MAP(m, x, y)) {
3070  LOG(llevError, "Present_arch called outside map.\n");
3071  return NULL;
3072  }
3073 
3074  FOR_MAP_PREPARE(m, x, y, tmp)
3075  if (tmp->arch == at)
3076  return tmp;
3077  FOR_MAP_FINISH();
3078 
3079  return NULL;
3080 }
3081 
3095 object *map_find_by_type(mapstruct *m, int x, int y, uint8_t type) {
3096  if (OUT_OF_REAL_MAP(m, x, y)) {
3097  return NULL;
3098  }
3099 
3100  FOR_MAP_PREPARE(m, x, y, tmp)
3101  if (tmp->type == type)
3102  return tmp;
3103  FOR_MAP_FINISH();
3104 
3105  return NULL;
3106 }
3107 
3118 object *object_present_in_ob(uint8_t type, const object *op) {
3119  object *tmp;
3120 
3121  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3122  if (tmp->type == type)
3123  return tmp;
3124 
3125  return NULL;
3126 }
3127 
3153 object *object_present_in_ob_by_name(int type, const char *str, const object *op) {
3154  object *tmp;
3155 
3156  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3157  if ((type == -1 || tmp->type == type) && !strcmp(str, tmp->name))
3158  return tmp;
3159  }
3160  return NULL;
3161 }
3162 
3172 object *arch_present_in_ob(const archetype *at, const object *op) {
3173  object *tmp;
3174 
3175  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3176  if (tmp->arch == at)
3177  return tmp;
3178  return NULL;
3179 }
3180 
3189 void object_set_flag_inv(object*op, int flag) {
3190  object *tmp;
3191 
3192  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3193  SET_FLAG(tmp, flag);
3194  object_set_flag_inv(tmp, flag);
3195  }
3196 }
3197 
3206 void object_unset_flag_inv(object*op, int flag) {
3207  object *tmp;
3208 
3209  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3210  CLEAR_FLAG(tmp, flag);
3211  object_unset_flag_inv(tmp, flag);
3212  }
3213 }
3214 
3224 void object_set_cheat(object *op) {
3227 }
3228 
3246 int object_find_multi_free_spot_around(const object *ob, const object *gen, int16_t *hx, int16_t *hy) {
3247  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3248  int freecount = 0;
3249 
3250  ob = HEAD(ob);
3251 
3252  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3253  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3254  /*
3255  * sx and sy are now the coords of the bottom right corner of ob relative to the head.
3256  * genx and geny are now the coords of the bottom right corner of gen relative to the head.
3257  * sx2 and sy2 are now the coords of the head of ob relative to the top left corner.
3258  * genx2 and geny2 are now the coords of the head of gen relative to the top left corner.
3259  */
3260 
3261  sx++;
3262  sy++;
3263  genx++;
3264  geny++;
3265  /*
3266  * sx, sy, genx, and geny, are now the size of the object, excluding parts left and above
3267  * the head.
3268  */
3269 
3270  ix = gen->x-sx-genx2;
3271  iy = gen->y-sy-geny2;
3272  sx += genx+sx2;
3273  sy += geny+sy2;
3274  /*
3275  * ix and iy are the map coords of the top left square where the head of ob could possibly
3276  * be placed. sx and sy are now the size of the square to search for placement of the head
3277  * relative to ix and iy.
3278  */
3279 
3280  /*
3281  * Loop around the square of possible positions for the head of ob object:
3282  */
3283  for (i = 0; i < (sx+sx+sy+sy); i++) {
3284  if (i <= sx) {
3285  nx = i+ix;
3286  ny = iy;
3287  } else if (i <= sx+sy) {
3288  nx = ix+sx;
3289  ny = iy+i-sx;
3290  } else if (i <= sx+sy+sx) {
3291  nx = ix+sx-(i-(sx+sy));
3292  ny = iy+sy;
3293  } else {
3294  nx = ix;
3295  ny = iy+sy-(i-(sx+sy+sx));
3296  }
3297  /* Check if the spot is free. */
3298  flag = ob_blocked(ob, gen->map, nx, ny);
3299  if (!flag) {
3300  freecount++;
3301  }
3302  }
3303  /* If no free spaces, return. */
3304  if (!freecount)
3305  return -1;
3306 
3307  /* Choose a random valid position */
3308  freecount = RANDOM()%freecount;
3309  for (i = 0; i < sx+sx+sy+sy; i++) {
3310  if (i <= sx) {
3311  nx = i+ix;
3312  ny = iy;
3313  } else if (i <= sx+sy) {
3314  nx = ix+sx;
3315  ny = iy+i-sx;
3316  } else if (i <= sx+sy+sx) {
3317  nx = ix+sx-(i-(sx+sy));
3318  ny = iy+sy;
3319  } else {
3320  nx = ix;
3321  ny = iy+sy-(i-(sx+sy+sx));
3322  }
3323 
3324  /* Make sure it's within map. */
3325  if (nx < 0 || nx >= MAP_WIDTH(gen->map)
3326  || ny < 0 || ny >= MAP_HEIGHT(gen->map))
3327  continue;
3328 
3329  /* Check if the spot is free.*/
3330  flag = ob_blocked(ob, gen->map, nx, ny);
3331  if (!flag) {
3332  freecount--;
3333  if (freecount <= 0) {
3334  *hx = nx;
3335  *hy = ny;
3336  return 0;
3337  }
3338  }
3339  }
3340  return -1;
3341 }
3342 
3362 int object_find_multi_free_spot_within_radius(const object *ob, const object *gen, int *hx, int *hy) {
3363  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3364  int8_t x, y, radius;
3365  int freecount = 0, freecountstop = 0;
3366  const char *value;
3367  int8_t *x_array;
3368  int8_t *y_array;
3369 
3370  /* If radius is not set, default to 1 */
3371  value = object_get_value(gen, "generator_radius");
3372  if (value) {
3373  radius = (int8_t)strtol(value, NULL, 10);
3374  if (radius < 1) {
3375  radius = 1;
3376  }
3377  } else {
3378  radius = 1;
3379  }
3380 
3381  ob = HEAD(ob);
3382 
3383  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3384  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3385  /*
3386  * sx and sy are now the coords of the bottom right corner
3387  * of ob relative to the head.
3388  * genx and geny are now the coords of the bottom right corner
3389  * of gen relative to the head.
3390  * sx2 and sy2 are now the coords of the head of ob relative
3391  * to the top left corner.
3392  * genx2 and geny2 are now the coords of the head of gen relative
3393  * to the top left corner.
3394  */
3395 
3396  sx++;
3397  sy++;
3398  genx++;
3399  geny++;
3400  /*
3401  * sx, sy, genx, and geny, are now the size of the object,
3402  * excluding parts left and above the head.
3403  */
3404 
3405  ix = gen->x-sx-genx2-radius+1;
3406  iy = gen->y-sy-geny2-radius+1;
3407  sx += genx+sx2+radius*2-1;
3408  sy += geny+sy2+radius*2-1;
3409 
3410  /*
3411  * ix and iy are the map coords of the top left square where
3412  * the head of ob could possibly be placed. sx and sy are now
3413  * the size of the square to search for placement of the head
3414  * relative to ix and iy.
3415  */
3416 
3417  /* Create arrays large enough to hold free space coordinates */
3418  x_array = malloc(sx*sy*sizeof(int8_t));
3419  y_array = malloc(sx*sy*sizeof(int8_t));
3420 
3421  /*
3422  * Loop through the area of possible positions for the head of ob object:
3423  */
3424  for (x = 0; x < sx; x++) {
3425  for (y = 0; y < sy; y++) {
3426  nx = ix+x;
3427  ny = iy+y;
3428 
3429 
3430  /* Make sure it's within map. */
3431  if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) {
3432  continue;
3433  }
3434 
3435  /* Check if the spot is free. */
3436  flag = ob_blocked(ob, gen->map, nx, ny);
3437  if (!flag) {
3438  x_array[freecount] = nx;
3439  y_array[freecount] = ny;
3440  freecount++;
3441  }
3442  }
3443  }
3444  /* If no free spaces, return. */
3445  if (!freecount) {
3446  free(x_array);
3447  free(y_array);
3448  return -1;
3449  }
3450 
3451  /* Choose a random valid position */
3452  freecountstop = RANDOM()%freecount;
3453  for (i = 0; i < freecount; i++) {
3454  nx = x_array[i];
3455  ny = y_array[i];
3456 
3457  /* Check if the spot is free.*/
3458  flag = ob_blocked(ob, gen->map, nx, ny);
3459  if (!flag) {
3460  freecountstop--;
3461  if (freecountstop <= 0) {
3462  *hx = nx;
3463  *hy = ny;
3464  free(x_array);
3465  free(y_array);
3466  return 0;
3467  }
3468  }
3469  }
3470  free(x_array);
3471  free(y_array);
3472  return -1;
3473 }
3474 
3509 int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop) {
3510  int i, index = 0, flag;
3511  static int altern[SIZEOFFREE];
3512 
3513  for (i = start; i < stop; i++) {
3514  flag = ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]);
3515  if (!flag)
3516  altern[index++] = i;
3517 
3518  /* Basically, if we find a wall on a space, we cut down the search size.
3519  * In this way, we won't return spaces that are on another side of a wall.
3520  * This mostly work, but it cuts down the search size in all directions -
3521  * if the space being examined only has a wall to the north and empty
3522  * spaces in all the other directions, this will reduce the search space
3523  * to only the spaces immediately surrounding the target area, and
3524  * won't look 2 spaces south of the target space.
3525  */
3526  else if ((flag&AB_NO_PASS) && maxfree[i] < stop)
3527  stop = maxfree[i];
3528  }
3529  if (!index)
3530  return -1;
3531  return altern[RANDOM()%index];
3532 }
3533 
3549 int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y) {
3550  int i;
3551 
3552  for (i = 0; i < SIZEOFFREE; i++) {
3553  if (!ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]))
3554  return i;
3555  }
3556  return -1;
3557 }
3558 
3568 static void permute(int *arr, int begin, int end) {
3569  int i, j, tmp, len;
3570 
3571  len = end-begin;
3572  for (i = begin; i < end; i++) {
3573  j = begin+RANDOM()%len;
3574 
3575  tmp = arr[i];
3576  arr[i] = arr[j];
3577  arr[j] = tmp;
3578  }
3579 }
3580 
3592 void get_search_arr(int *search_arr) {
3593  int i;
3594 
3595  for (i = 0; i < SIZEOFFREE; i++) {
3596  search_arr[i] = i;
3597  }
3598 
3599  permute(search_arr, 1, SIZEOFFREE1+1);
3600  permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1);
3601  permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE);
3602 }
3603 
3622 int map_find_dir(mapstruct *m, int x, int y, object *exclude) {
3623  int i, max = SIZEOFFREE, mflags;
3624  int16_t nx, ny;
3625  mapstruct *mp;
3626  MoveType blocked, move_type;
3627 
3628  if (exclude && exclude->head) {
3629  exclude = exclude->head;
3630  move_type = exclude->move_type;
3631  } else {
3632  /* If we don't have anything, presume it can use all movement types. */
3633  move_type = MOVE_ALL;
3634  }
3635 
3636  for (i = 1; i < max; i++) {
3637  mp = m;
3638  nx = x+freearr_x[i];
3639  ny = y+freearr_y[i];
3640 
3641  mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny);
3642  if (mflags&P_OUT_OF_MAP) {
3643  max = maxfree[i];
3644  } else {
3645  blocked = GET_MAP_MOVE_BLOCK(mp, nx, ny);
3646 
3647  if ((move_type&blocked) == move_type) {
3648  max = maxfree[i];
3649  } else if (mflags&P_IS_ALIVE) {
3650  FOR_MAP_PREPARE(mp, nx, ny, tmp) {
3651  if ((QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type == PLAYER)
3652  && (tmp != exclude || (tmp->head && tmp->head != exclude))) {
3653  return freedir[i];
3654  }
3655  } FOR_MAP_FINISH();
3656  }
3657  }
3658  }
3659  return 0;
3660 }
3661 
3669 int object_distance(const object *ob1, const object *ob2) {
3670  int i;
3671 
3672  i = (ob1->x-ob2->x)*(ob1->x-ob2->x)+
3673  (ob1->y-ob2->y)*(ob1->y-ob2->y);
3674  return i;
3675 }
3676 
3685 int find_dir_2(int x, int y) {
3686  int q;
3687 
3688  if (!y)
3689  q = -300*x;
3690  else
3691  q = x*100/y;
3692  if (y > 0) {
3693  if (q < -242)
3694  return 3;
3695  if (q < -41)
3696  return 2;
3697  if (q < 41)
3698  return 1;
3699  if (q < 242)
3700  return 8;
3701  return 7;
3702  }
3703  if (q < -242)
3704  return 7;
3705  if (q < -41)
3706  return 6;
3707  if (q < 41)
3708  return 5;
3709  if (q < 242)
3710  return 4;
3711  return 3;
3712 }
3713 
3722 int absdir(int d) {
3723  // Shortcut for modulus that work becuase we have a power of 2
3724  d &= 7;
3725  // 0 needs to be 8
3726  if (!d)
3727  d = 8;
3728  return d;
3729 }
3730 
3740 int dirdiff(int dir1, int dir2) {
3741  int d;
3742 
3743  d = abs(dir1-dir2);
3744  if (d > 4)
3745  d = 8-d;
3746  return d;
3747 }
3748 
3760 static const int reduction_dir[SIZEOFFREE][3] = {
3761  { 0, 0, 0 }, /* 0 */
3762  { 0, 0, 0 }, /* 1 */
3763  { 0, 0, 0 }, /* 2 */
3764  { 0, 0, 0 }, /* 3 */
3765  { 0, 0, 0 }, /* 4 */
3766  { 0, 0, 0 }, /* 5 */
3767  { 0, 0, 0 }, /* 6 */
3768  { 0, 0, 0 }, /* 7 */
3769  { 0, 0, 0 }, /* 8 */
3770  { 8, 1, 2 }, /* 9 */
3771  { 1, 2, -1 }, /* 10 */
3772  { 2, 10, 12 }, /* 11 */
3773  { 2, 3, -1 }, /* 12 */
3774  { 2, 3, 4 }, /* 13 */
3775  { 3, 4, -1 }, /* 14 */
3776  { 4, 14, 16 }, /* 15 */
3777  { 5, 4, -1 }, /* 16 */
3778  { 4, 5, 6 }, /* 17 */
3779  { 6, 5, -1 }, /* 18 */
3780  { 6, 20, 18 }, /* 19 */
3781  { 7, 6, -1 }, /* 20 */
3782  { 6, 7, 8 }, /* 21 */
3783  { 7, 8, -1 }, /* 22 */
3784  { 8, 22, 24 }, /* 23 */
3785  { 8, 1, -1 }, /* 24 */
3786  { 24, 9, 10 }, /* 25 */
3787  { 9, 10, -1 }, /* 26 */
3788  { 10, 11, -1 }, /* 27 */
3789  { 27, 11, 29 }, /* 28 */
3790  { 11, 12, -1 }, /* 29 */
3791  { 12, 13, -1 }, /* 30 */
3792  { 12, 13, 14 }, /* 31 */
3793  { 13, 14, -1 }, /* 32 */
3794  { 14, 15, -1 }, /* 33 */
3795  { 33, 15, 35 }, /* 34 */
3796  { 16, 15, -1 }, /* 35 */
3797  { 17, 16, -1 }, /* 36 */
3798  { 18, 17, 16 }, /* 37 */
3799  { 18, 17, -1 }, /* 38 */
3800  { 18, 19, -1 }, /* 39 */
3801  { 41, 19, 39 }, /* 40 */
3802  { 19, 20, -1 }, /* 41 */
3803  { 20, 21, -1 }, /* 42 */
3804  { 20, 21, 22 }, /* 43 */
3805  { 21, 22, -1 }, /* 44 */
3806  { 23, 22, -1 }, /* 45 */
3807  { 45, 47, 23 }, /* 46 */
3808  { 23, 24, -1 }, /* 47 */
3809  { 24, 9, -1 } /* 48 */
3810 };
3811 
3830 int can_see_monsterP(mapstruct *m, int x, int y, int dir) {
3831  int16_t dx, dy;
3832  int mflags;
3833 
3834  if (dir < 0)
3835  return 0; /* exit condition: invalid direction */
3836 
3837  dx = x+freearr_x[dir];
3838  dy = y+freearr_y[dir];
3839 
3840  mflags = get_map_flags(m, &m, dx, dy, &dx, &dy);
3841 
3842  /* This functional arguably was incorrect before - it was
3843  * checking for P_WALL - that was basically seeing if
3844  * we could move to the monster - this is being more
3845  * literal on if we can see it. To know if we can actually
3846  * move to the monster, we'd need the monster passed in or
3847  * at least its move type.
3848  */
3849  if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
3850  return 0;
3851 
3852  /* yes, can see. */
3853  if (dir < 9)
3854  return 1;
3855  return can_see_monsterP(m, x, y, reduction_dir[dir][0])|
3856  can_see_monsterP(m, x, y, reduction_dir[dir][1])|
3857  can_see_monsterP(m, x, y, reduction_dir[dir][2]);
3858 }
3859 
3875 int object_can_pick(const object *who, const object *item) {
3876  /* I re-wrote this as a series of if statements
3877  * instead of a nested return (foo & bar && yaz)
3878  * - I think this is much more readable,
3879  * and likely compiler effectively optimizes it the
3880  * same.
3881  */
3882  if (item->weight <= 0)
3883  return 0;
3885  return 0;
3886  if (QUERY_FLAG(item, FLAG_ALIVE))
3887  return 0;
3888  if (item->invisible)
3889  return 0;
3890  if (item->type == TRANSPORT && item->contr != NULL) {
3891  return 0;
3892  }
3893 
3894  /* Weight limit for monsters */
3895  if (who->type != PLAYER && ((uint32_t)(who->weight+who->carrying+item->weight)) > get_weight_limit(who->stats.Str))
3896  return 0;
3897 
3898  /* Can not pick up multipart objects */
3899  if (item->head || item->more)
3900  return 0;
3901 
3902  /* Everything passes, so OK to pick up */
3903  return 1;
3904 }
3905 
3917 object *object_create_clone(object *asrc) {
3918  object *dst = NULL, *tmp, *src, *part, *prev;
3919 
3920  if (!asrc)
3921  return NULL;
3922  src = HEAD(asrc);
3923 
3924  prev = NULL;
3925  for (part = src; part; part = part->more) {
3926  tmp = object_new();
3927  object_copy(part, tmp);
3928  /*
3929  * Need to reset the weight, since object_insert_in_ob() later will
3930  * recompute this field.
3931  */
3932  tmp->carrying = tmp->arch->clone.carrying;
3933  tmp->x -= src->x;
3934  tmp->y -= src->y;
3935  if (!part->head) {
3936  dst = tmp;
3937  tmp->head = NULL;
3938  } else {
3939  tmp->head = dst;
3940  }
3941  tmp->more = NULL;
3942  if (prev)
3943  prev->more = tmp;
3944  prev = tmp;
3945  }
3946  /*** copy inventory ***/
3947  FOR_INV_PREPARE(src, item)
3949  FOR_INV_FINISH();
3950 
3951  return dst;
3952 }
3953 
3964 object *object_find_by_name(const object *who, const char *name) {
3965  const char *name_shared = add_string(name);
3966  object *tmp;
3967 
3968  for (tmp = who->inv; tmp; tmp = tmp->below)
3969  if (tmp->name == name_shared)
3970  break;
3971  free_string(name_shared);
3972  return tmp;
3973 }
3974 
3988 object *object_find_by_type(const object *who, int type) {
3989  object *tmp;
3990 
3991  for (tmp = who->inv; tmp; tmp = tmp->below)
3992  if (tmp->type == type)
3993  return tmp;
3994 
3995  return NULL;
3996 }
3997 
4012 object *object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags) {
4013  int flag_okay;
4014  for (object *tmp = who->inv; tmp; tmp = tmp->below)
4015  if (tmp->type == type) {
4016  flag_okay = 1;
4017  for (int i = 0; i < num_flags; ++i) {
4018  if (QUERY_FLAG(tmp, flags[i])) {
4019  flag_okay = 0; // A flag we didn't want set was set. Skip this item.
4020  break;
4021  }
4022  }
4023  if (flag_okay) // If flag_okay == 1, then the flags specified were not set
4024  return tmp; // If we reach here, none of the flags specified were set. Just like we wanted.
4025  }
4026 
4027  return NULL;
4028 }
4029 
4045 object *object_find_by_type2(const object *who, int type1, int type2) {
4046  object *tmp;
4047 
4048  for (tmp = who->inv; tmp; tmp = tmp->below)
4049  if (tmp->type == type1 || tmp->type == type2)
4050  return tmp;
4051 
4052  return NULL;
4053 }
4054 
4068 object *object_find_by_tag(const object *who, tag_t tag) {
4069  object *tmp;
4070 
4071  for (tmp = who->inv; tmp; tmp = tmp->below)
4072  if (tmp->count == tag)
4073  return tmp;
4074 
4075  return NULL;
4076 }
4077 
4091 object *object_find_by_type_applied(const object *who, int type) {
4092  object *tmp;
4093 
4094  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4095  if (tmp->type == type && QUERY_FLAG(tmp, FLAG_APPLIED))
4096  return tmp;
4097 
4098  return NULL;
4099 }
4100 
4116 object *object_find_by_type_and_name(const object *who, int type, const char *name) {
4117  object *tmp;
4118 
4119  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4120  if (tmp->type == type && strcmp(tmp->name, name) == 0)
4121  return tmp;
4122 
4123  return NULL;
4124 }
4125 
4141 object *object_find_by_type_and_race(const object *who, int type, const char *race) {
4142  object *tmp;
4143 
4144  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4145  if (tmp->type == type && strcmp(tmp->race, race) == 0)
4146  return tmp;
4147 
4148  return NULL;
4149 }
4150 
4166 object *object_find_by_type_and_slaying(const object *who, int type, const char *slaying) {
4167  object *tmp;
4168 
4169  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4170  if (tmp->type == type && tmp->slaying != NULL && strcmp(tmp->slaying, slaying) == 0)
4171  return tmp;
4172 
4173  return NULL;
4174 }
4175 
4191 object *object_find_by_type_and_skill(const object *who, int type, const char *skill) {
4192  object *tmp;
4193 
4194  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4195  if (tmp->type == type && tmp->skill != NULL && strcmp(tmp->skill, skill) == 0)
4196  return tmp;
4197 
4198  return NULL;
4199 }
4200 
4214 object *object_find_by_flag(const object *who, int flag) {
4215  object *tmp;
4216 
4217  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4218  if (QUERY_FLAG(tmp, flag))
4219  return tmp;
4220 
4221  return NULL;
4222 }
4223 
4237 object *object_find_by_flag_applied(const object *who, int flag) {
4238  object *tmp;
4239 
4240  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4241  if (QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, flag))
4242  return tmp;
4243 
4244  return NULL;
4245 }
4246 
4260 object *object_find_by_arch_name(const object *who, const char *name) {
4261  object *tmp;
4262 
4263  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4264  if (strcmp(tmp->arch->name, name) == 0)
4265  return tmp;
4266 
4267  return NULL;
4268 }
4269 
4285 object *object_find_by_type_and_arch_name(const object *who, int type, const char *name) {
4286  object *tmp;
4287 
4288  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4289  if (tmp->type == type && strcmp(tmp->arch->name, name) == 0)
4290  return tmp;
4291 
4292  return NULL;
4293 }
4294 
4309 object *object_find_by_type_subtype(const object *who, int type, int subtype) {
4310  object *tmp;
4311 
4312  for (tmp = who->inv; tmp; tmp = tmp->below)
4313  if (tmp->type == type && tmp->subtype == subtype)
4314  return tmp;
4315 
4316  return NULL;
4317 }
4318 
4329 key_value *object_get_key_value(const object *ob, const char *key) {
4330  key_value *link;
4331 
4332  for (link = ob->key_values; link != NULL; link = link->next) {
4333  if (link->key == key) {
4334  return link;
4335  }
4336  }
4337 
4338  return NULL;
4339 }
4340 
4354 const char *object_get_value(const object *op, const char *const key) {
4355  key_value *link;
4356  const char *canonical_key;
4357 
4358  canonical_key = find_string(key);
4359 
4360  if (canonical_key == NULL) {
4361  /* 1. There being a field named key on any object
4362  * implies there'd be a shared string to find.
4363  * 2. Since there isn't, no object has this field.
4364  * 3. Therefore, *this *object doesn't have this field.
4365  */
4366  return NULL;
4367  }
4368 
4369  /* This is copied from object_get_key_value() above -
4370  * only 4 lines, and saves the function call overhead.
4371  */
4372  for (link = op->key_values; link != NULL; link = link->next) {
4373  if (link->key == canonical_key) {
4374  return link->value;
4375  }
4376  }
4377  return NULL;
4378 }
4379 
4384 bool object_value_set(const object *op, const char *const key) {
4385  const char *ret = object_get_value(op, key);
4386  if (ret == NULL || (strcmp(ret, "") == 0) || (strcmp(ret, "0") == 0)) {
4387  return false;
4388  }
4389  return true;
4390 }
4391 
4406 static int object_set_value_s(object *op, const char *canonical_key, const char *value, int add_key) {
4407  key_value *field = NULL, *last = NULL;
4408 
4409  for (field = op->key_values; field != NULL; field = field->next) {
4410  if (field->key != canonical_key) {
4411  last = field;
4412  continue;
4413  }
4414 
4415  if (field->value)
4416  FREE_AND_CLEAR_STR(field->value);
4417  if (value)
4418  field->value = add_string(value);
4419  else {
4420  /* Basically, if the archetype has this key set,
4421  * we need to store the null value so when we save
4422  * it, we save the empty value so that when we load,
4423  * we get this value back again.
4424  */
4425  if (object_get_key_value(&op->arch->clone, canonical_key))
4426  field->value = NULL;
4427  else {
4428  /* Delete this link */
4429  if (field->key)
4430  FREE_AND_CLEAR_STR(field->key);
4431  if (field->value)
4432  FREE_AND_CLEAR_STR(field->value);
4433  if (last)
4434  last->next = field->next;
4435  else
4436  op->key_values = field->next;
4437  free(field);
4438  }
4439  }
4440  return TRUE;
4441  }
4442  /* IF we get here, key doesn't exist */
4443 
4444  /* No field, we'll have to add it. */
4445 
4446  if (!add_key) {
4447  return FALSE;
4448  }
4449  /* There isn't any good reason to store a null
4450  * value in the key/value list. If the archetype has
4451  * this key, then we should also have it, so shouldn't
4452  * be here. If user wants to store empty strings,
4453  * should pass in ""
4454  */
4455  if (value == NULL)
4456  return TRUE;
4457 
4458  field = malloc(sizeof(key_value));
4459 
4460  field->key = add_refcount(canonical_key);
4461  field->value = add_string(value);
4462  /* Usual prepend-addition. */
4463  field->next = op->key_values;
4464  op->key_values = field;
4465 
4466  return TRUE;
4467 }
4468 
4489 int object_set_value(object *op, const char *key, const char *value, int add_key) {
4490  const char *canonical_key = NULL;
4491  int floating_ref = FALSE;
4492  int ret;
4493 
4494  /* HACK This mess is to make sure set_ob_value() passes a shared string
4495  * to object_get_key_value(), without leaving a leaked refcount.
4496  */
4497 
4498  canonical_key = find_string(key);
4499  if (canonical_key == NULL) {
4500  canonical_key = add_string(key);
4501  floating_ref = TRUE;
4502  }
4503 
4504  ret = object_set_value_s(op, canonical_key, value, add_key);
4505 
4506  if (floating_ref) {
4507  free_string(canonical_key);
4508  }
4509 
4510  return ret;
4511 }
4512 
4564 int object_matches_string(object *pl, object *op, const char *name) {
4565  char *cp, local_name[MAX_BUF], name_op[MAX_BUF], name_short[HUGE_BUF], bname_s[MAX_BUF], bname_p[MAX_BUF];
4566  int count, retval = 0;
4567  /* strtok is destructive to name */
4568  safe_strncpy(local_name, name, sizeof(local_name));
4569 
4570  for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) {
4571  while (cp[0] == ' ')
4572  ++cp; /* get rid of spaces */
4573 
4574  /* LOG(llevDebug, "Trying to match %s\n", cp);*/
4575  /* All is a very generic match - low match value */
4576  if (!strcmp(cp, "all"))
4577  return 1;
4578 
4579  /* unpaid is a little more specific */
4580  if (!strcmp(cp, "unpaid") && QUERY_FLAG(op, FLAG_UNPAID))
4581  return 2;
4582  if (!strcmp(cp, "cursed")
4585  return 2;
4586 
4587  if (!strcmp(cp, "unlocked") && !QUERY_FLAG(op, FLAG_INV_LOCKED))
4588  return 2;
4589 
4590  /* Allow for things like '100 arrows' */
4591  count = atoi(cp);
4592  if (count != 0) {
4593  cp = strchr(cp, ' ');
4594  while (cp && cp[0] == ' ')
4595  ++cp; /* get rid of spaces */
4596  } else {
4597  if (pl->type == PLAYER)
4598  count = pl->contr->count;
4599  else
4600  count = 0;
4601  }
4602 
4603  if (!cp || cp[0] == '\0' || count < 0)
4604  return 0;
4605 
4606  /* The code here should go from highest retval to lowest. That
4607  * is because of the 'else' handling - we don't want to match on
4608  * something and set a low retval, even though it may match a higher retcal
4609  * later. So keep it in descending order here, so we try for the best
4610  * match first, and work downward.
4611  */
4612  query_name(op, name_op, MAX_BUF);
4613  query_short_name(op, name_short, HUGE_BUF);
4614  query_base_name(op, 0, bname_s, MAX_BUF);
4615  query_base_name(op, 1, bname_p, MAX_BUF);
4616 
4617  if (!strcasecmp(cp, name_op))
4618  retval = 20;
4619  else if (!strcasecmp(cp, name_short))
4620  retval = 18;
4621  else if (!strcasecmp(cp, bname_s))
4622  retval = 16;
4623  else if (!strcasecmp(cp, bname_p))
4624  retval = 16;
4625  else if (op->custom_name && !strcasecmp(cp, op->custom_name))
4626  retval = 15;
4627  else if (!strncasecmp(cp, bname_s, strlen(cp)))
4628  retval = 14;
4629  else if (!strncasecmp(cp, bname_p, strlen(cp)))
4630  retval = 14;
4631  /* Do substring checks, so things like 'Str+1' will match.
4632  * retval of these should perhaps be lower - they are lower
4633  * then the specific strcasecmp aboves, but still higher than
4634  * some other match criteria.
4635  */
4636  else if (strstr(bname_p, cp))
4637  retval = 12;
4638  else if (strstr(bname_s, cp))
4639  retval = 12;
4640  else if (strstr(name_short, cp))
4641  retval = 12;
4642  /* Check against plural/non plural based on count. */
4643  else if (count > 1 && !strcasecmp(cp, op->name_pl)) {
4644  retval = 6;
4645  } else if (count == 1 && !strcasecmp(op->name, cp)) {
4646  retval = 6;
4647  }
4648  /* base name matched - not bad */
4649  else if (strcasecmp(cp, op->name) == 0 && !count)
4650  retval = 4;
4651  /* Check for partial custom name, but give a real low priority */
4652  else if (op->custom_name && strstr(op->custom_name, cp))
4653  retval = 3;
4654 
4655  if (retval) {
4656  if (pl->type == PLAYER)
4657  pl->contr->count = count;
4658  return retval;
4659  }
4660  }
4661  return 0;
4662 }
4663 
4672 void object_fix_multipart(object *tmp) {
4673  archetype *at;
4674  object *op, *last;
4675 
4676  if (!tmp->map) {
4677  LOG(llevError, "object_fix_multipart: not on a map!\n");
4678  return;
4679  }
4680 
4681  /* already multipart - don't do anything more */
4682  if (tmp->head || tmp->more)
4683  return;
4684 
4685  /* If there is nothing more to this object, this for loop
4686  * won't do anything.
4687  */
4688  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
4689  op = arch_to_object(at);
4690 
4691  /* update x,y coordinates */
4692  op->x += tmp->x;
4693  op->y += tmp->y;
4694  op->head = tmp;
4695  op->map = tmp->map;
4696  last->more = op;
4697  if (tmp->name != op->name) {
4698  if (op->name)
4699  free_string(op->name);
4700  op->name = add_string(tmp->name);
4701  }
4702  if (tmp->title != op->title) {
4703  if (op->title)
4704  free_string(op->title);
4705  op->title = add_string(tmp->title);
4706  }
4707  /* we could link all the parts onto tmp, and then just
4708  * call object_insert_in_map once, but the effect is the same,
4709  * as object_insert_in_map will call itself with each part, and
4710  * the coding is simpler to just to it here with each part.
4711  */
4713  } /* for at = tmp->arch->more */
4714 }
4715 
4731 void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy) {
4732  archetype *part;
4733  int maxx = 0, maxy = 0, minx = 0, miny = 0;
4734 
4735  ob = HEAD(ob);
4736  *sx = 1;
4737  *sy = 1;
4738  if (ob->arch->more) {
4739  for (part = ob->arch; part; part = part->more) {
4740  if (part->clone.x > maxx)
4741  maxx = part->clone.x;
4742  if (part->clone.y > maxy)
4743  maxy = part->clone.y;
4744  if (part->clone.x < minx)
4745  minx = part->clone.x;
4746  if (part->clone.y < miny)
4747  miny = part->clone.y;
4748  }
4749  }
4750  *sx = maxx;
4751  *sy = maxy;
4752  if (hx)
4753  *hx = -minx;
4754  if (hy)
4755  *hy = -miny;
4756 }
4757 
4778 void object_insert_to_free_spot_or_free(object *op, mapstruct *map, int x, int y, int start, int stop, object *originator) {
4779  int pos;
4780 
4781  pos = object_find_free_spot(op, map, x, y, start, stop);
4782  if (pos == -1) {
4784  return;
4785  }
4786 
4787  object_insert_in_map_at(op, map, originator, 0, x+freearr_x[pos], y+freearr_y[pos]);
4788 }
4789 
4798 void object_set_msg(object *op, const char *msg) {
4799  if (op->msg != NULL) {
4800  free_string(op->msg);
4801  }
4802 
4803  if (msg != NULL) {
4804  // If the message does not have a trailing newline, add one.
4805  if (*msg != '\0' && strchr(msg, '\0')[-1] != '\n') {
4808  stringbuffer_append_string(sb, "\n");
4809  op->msg = stringbuffer_finish_shared(sb);
4810  } else {
4811  op->msg = add_string(msg);
4812  }
4813  } else {
4814  op->msg = NULL;
4815  }
4816 }
4817 
4819 const char *const move_name[] = {
4820  "walk",
4821  "fly_low",
4822  "fly_high",
4823  "swim",
4824  "boat",
4825  NULL
4826 };
4827 
4828 /* This array equates the FLAG_ values with the V_ values. Use -1 to
4829  * put gaps in the array that should not be processed.
4830  * The order matches the order of the define values in 'define.h'.
4831  */
4838 static const char *const flag_names[NUM_FLAGS+1] = {
4839  "alive", "wiz", NULL, NULL, "was_wiz", "applied", "unpaid",
4840  "can_use_shield", "no_pick", "client_anim_sync", "client_anim_random", /* 10 */
4841  "is_animated", NULL /* FLAG_DIALOG_PARSED, not saved */,
4842  NULL /* flying */, "monster", "friendly", "generator",
4843  "is_thrown", "auto_apply", "treasure", "player sold", /* 20 */
4844  "see_invisible", "can_roll", "overlay_floor",
4845  "is_turnable", NULL /* walk_off */, NULL /* fly_on */,
4846  NULL /*fly_off*/, "is_used_up", "identified", "reflecting", /* 30 */
4847  "changing", "splitting", "hitback", "startequip",
4848  "blocksview", "undead", "scared", "unaggressive",
4849  "reflect_missile", "reflect_spell", /* 40 */
4850  "no_magic", "no_fix_player", "is_lightable", "tear_down",
4851  "run_away", NULL /*pass_thru */, NULL /*can_pass_thru*/,
4852  NULL /*"pick_up"*/, "unique", "no_drop", /* 50 */
4853  NULL /* wizcast*/, "can_cast_spell", "can_use_scroll", "can_use_range",
4854  "can_use_bow", "can_use_armour", "can_use_weapon",
4855  "can_use_ring", "has_ready_range", "has_ready_bow", /* 60 */
4856  "xrays", NULL, "is_floor", "lifesave", "no_strength", "sleep",
4857  "stand_still", "random_movement", "only_attack", "confused", /* 70 */
4858  "stealth", NULL, NULL, "cursed", "damned",
4859  "see_anywhere", "known_magical", "known_cursed",
4860  "can_use_skill", "been_applied", /* 80 */
4861  "has_ready_scroll", NULL, NULL,
4862  NULL, "make_invisible", "inv_locked", "is_wooded",
4863  "is_hilly", "has_ready_skill", "has_ready_weapon", /* 90 */
4864  "no_skill_ident", "is_blind", "can_see_in_dark", "is_cauldron",
4865  NULL, "no_steal", "one_hit", NULL, "berserk", "neutral", /* 100 */
4866  "no_attack", "no_damage", NULL, NULL, "activate_on_push",
4867  "activate_on_release", "is_water", "use_content_on_gen", NULL, "is_buildable", /* 110 */
4868  NULL, "blessed", "known_blessed"
4869 };
4870 
4880 {
4881  static char retbuf[MAX_BUF], retbuf_all[MAX_BUF];
4882  int i, all_count = 0, count;
4883 
4884  strcpy(retbuf, "");
4885  strcpy(retbuf_all, " all");
4886 
4887  /* Quick check, and probably fairly common */
4888  if (mt == MOVE_ALL) {
4889  stringbuffer_append_string(sb, "all");
4890  return;
4891  }
4892  if (mt == 0) {
4893  stringbuffer_append_string(sb, "0");
4894  return;
4895  }
4896 
4897  /* We basically slide the bits down. Why look at MOVE_ALL?
4898  * because we may want to return a string like 'all -swim',
4899  * and if we just looked at mt, we couldn't get that.
4900  */
4901  for (i = MOVE_ALL, count = 0; i != 0; i >>= 1, count++) {
4902  if (mt&(1<<count)) {
4903  strcat(retbuf, " ");
4904  strcat(retbuf, move_name[count]);
4905  } else {
4906  strcat(retbuf_all, " -");
4907  strcat(retbuf_all, move_name[count]);
4908  all_count++;
4909  }
4910  }
4911  /* Basically, if there is a single negation, return it, eg
4912  * 'all -swim'. But more than that, just return the
4913  * enumerated values. It doesn't make sense to return
4914  * 'all -walk -fly_low' - it is shorter to return 'fly_high swim'
4915  */
4916  if (all_count <= 1)
4917  stringbuffer_append_string(sb, retbuf_all+1);
4918  else
4919  stringbuffer_append_string(sb, retbuf+1);
4920 }
4921 
4923 static inline void ADD_STRINGLINE_ENTRY(StringBuffer *sb, const char *name, const char *value) {
4926  stringbuffer_append_string(sb, "\n");
4927 }
4928 
4930 static inline void FAST_SAVE_LONG(StringBuffer *sb, const char *name, const long value) {
4931  stringbuffer_append_printf(sb, "%s%ld\n", name, (long int)value);
4932 }
4933 
4935 static inline void FAST_SAVE_DOUBLE(StringBuffer *sb, const char *name, const double value) {
4936  stringbuffer_append_printf(sb, "%s%f\n", name, value);
4937 }
4938 
4952 void get_ob_diff(StringBuffer *sb, const object *op, const object *op2) {
4953  static char buf2[64];
4954  int tmp;
4955  int i;
4956  key_value *my_field;
4957  key_value *arch_field;
4958 
4959  /* This saves the key/value lists. We do it first so that any
4960  * keys that match field names will be overwritten by the loader.
4961  */
4962  for (my_field = op->key_values; my_field != NULL; my_field = my_field->next) {
4963  /* Find the field in the opposing member. */
4964  arch_field = object_get_key_value(op2, my_field->key);
4965 
4966  /* If there's no partnering field, or it's got a different value, save our field. */
4967  if (arch_field == NULL || my_field->value != arch_field->value) {
4968  stringbuffer_append_string(sb, my_field->key);
4969  stringbuffer_append_string(sb, " ");
4970  /* If this is null, then saving it as a space should
4971  * cause it to be null again.
4972  */
4973  if (my_field->value)
4974  stringbuffer_append_string(sb, my_field->value);
4975  stringbuffer_append_string(sb, "\n");
4976  }
4977  }
4978  /* We don't need to worry about the arch's extra fields - they
4979  * will get taken care of the object_copy() function.
4980  */
4981 
4982  if (op->name && op->name != op2->name) {
4983  ADD_STRINGLINE_ENTRY(sb, "name ", op->name);
4984  }
4985  if (op->name_pl && op->name_pl != op2->name_pl) {
4986  ADD_STRINGLINE_ENTRY(sb, "name_pl ", op->name_pl);
4987  }
4988  if (op->anim_suffix && op->anim_suffix != op2->anim_suffix) {
4989  ADD_STRINGLINE_ENTRY(sb, "anim_suffix ", op->anim_suffix);
4990  }
4991  if (op->custom_name && op->custom_name != op2->custom_name) {
4992  ADD_STRINGLINE_ENTRY(sb, "custom_name ", op->custom_name);
4993  }
4994  if (op->title && op->title != op2->title) {
4995  ADD_STRINGLINE_ENTRY(sb, "title ", op->title);
4996  }
4997  if (op->race && op->race != op2->race) {
4998  ADD_STRINGLINE_ENTRY(sb, "race ", op->race);
4999  }
5000  if (op->slaying && op->slaying != op2->slaying) {
5001  ADD_STRINGLINE_ENTRY(sb, "slaying ", op->slaying);
5002  }
5003  if (op->skill && op->skill != op2->skill) {
5004  ADD_STRINGLINE_ENTRY(sb, "skill ", op->skill);
5005  }
5006  if (op->msg && op->msg != op2->msg) {
5007  stringbuffer_append_string(sb, "msg\n");
5008  stringbuffer_append_string(sb, op->msg);
5009  stringbuffer_append_string(sb, "endmsg\n");
5010  }
5011  if (op->lore && op->lore != op2->lore) {
5012  stringbuffer_append_string(sb, "lore\n");
5013  stringbuffer_append_string(sb, op->lore);
5014  stringbuffer_append_string(sb, "endlore\n");
5015  }
5016  if (op->other_arch != op2->other_arch && op->other_arch != NULL && op->other_arch->name) {
5017  ADD_STRINGLINE_ENTRY(sb, "other_arch ", op->other_arch->name);
5018  }
5019  if (op->face != op2->face) {
5020  ADD_STRINGLINE_ENTRY(sb, "face ", op->face->name);
5021  }
5022 
5023  if (op->animation != op2->animation) {
5024  if (op->animation) {
5025  ADD_STRINGLINE_ENTRY(sb, "animation ", op->animation->name);
5026  if (!QUERY_FLAG (op, FLAG_ANIMATE)) {
5027  stringbuffer_append_string(sb, "is_animated 0\n");
5028  }
5029  } else {
5030  stringbuffer_append_string(sb, "animation NONE\n");
5031  }
5032  }
5033  if (op->stats.Str != op2->stats.Str)
5034  FAST_SAVE_LONG(sb, "Str ", op->stats.Str);
5035  if (op->stats.Dex != op2->stats.Dex)
5036  FAST_SAVE_LONG(sb, "Dex ", op->stats.Dex);
5037  if (op->stats.Con != op2->stats.Con)
5038  FAST_SAVE_LONG(sb, "Con ", op->stats.Con);
5039  if (op->stats.Wis != op2->stats.Wis)
5040  FAST_SAVE_LONG(sb, "Wis ", op->stats.Wis);
5041  if (op->stats.Pow != op2->stats.Pow)
5042  FAST_SAVE_LONG(sb, "Pow ", op->stats.Pow);
5043  if (op->stats.Cha != op2->stats.Cha)
5044  FAST_SAVE_LONG(sb, "Cha ", op->stats.Cha);
5045  if (op->stats.Int != op2->stats.Int)
5046  FAST_SAVE_LONG(sb, "Int ", op->stats.Int);
5047  if (op->stats.hp != op2->stats.hp)
5048  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5049  if (op->stats.maxhp != op2->stats.maxhp)
5050  FAST_SAVE_LONG(sb, "maxhp ", op->stats.maxhp);
5051  if (op->stats.sp != op2->stats.sp)
5052  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5053  if (op->stats.maxsp != op2->stats.maxsp)
5054  FAST_SAVE_LONG(sb, "maxsp ", op->stats.maxsp);
5055  if (op->stats.grace != op2->stats.grace)
5056  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5057  if (op->stats.maxgrace != op2->stats.maxgrace)
5058  FAST_SAVE_LONG(sb, "maxgrace ", op->stats.maxgrace);
5059 
5060  if (op->stats.exp != op2->stats.exp) {
5061  snprintf(buf2, sizeof(buf2), "%"FMT64, op->stats.exp);
5062  ADD_STRINGLINE_ENTRY(sb, "exp ", buf2);
5063  }
5064 
5065  if (op->total_exp != op2->total_exp) {
5066  snprintf(buf2, sizeof(buf2), "%"FMT64, op->total_exp);
5067  ADD_STRINGLINE_ENTRY(sb, "total_exp ", buf2);
5068  }
5069 
5070  if (op->expmul != op2->expmul)
5071  FAST_SAVE_DOUBLE(sb, "expmul ", op->expmul);
5072  if (op->stats.food != op2->stats.food)
5073  FAST_SAVE_LONG(sb, "food ", op->stats.food);
5074  if (op->stats.dam != op2->stats.dam)
5075  FAST_SAVE_LONG(sb, "dam ", op->stats.dam);
5076  if (op->stats.luck != op2->stats.luck)
5077  FAST_SAVE_LONG(sb, "luck ", op->stats.luck);
5078  if (op->stats.wc != op2->stats.wc)
5079  FAST_SAVE_LONG(sb, "wc ", op->stats.wc);
5080  if (op->stats.ac != op2->stats.ac)
5081  FAST_SAVE_LONG(sb, "ac ", op->stats.ac);
5082  if (op->x != op2->x)
5083  FAST_SAVE_LONG(sb, "x ", op->x);
5084  if (op->y != op2->y)
5085  FAST_SAVE_LONG(sb, "y ", op->y);
5086  if (op->speed != op2->speed) {
5087  FAST_SAVE_DOUBLE(sb, "speed ", op->speed);
5088  }
5089  if (op->speed > 0 && op->speed_left != op2->speed_left) {
5090  FAST_SAVE_DOUBLE(sb, "speed_left ", op->speed_left);
5091  }
5092  if (op->weapon_speed != op2->weapon_speed) {
5093  FAST_SAVE_DOUBLE(sb, "weapon_speed ", op->weapon_speed);
5094  }
5095  if (op->weapon_speed > 0 && op->weapon_speed_left != op2->weapon_speed_left) {
5096  FAST_SAVE_DOUBLE(sb, "weapon_speed_left ", op->weapon_speed_left);
5097  }
5098  if (op->move_status != op2->move_status)
5099  FAST_SAVE_LONG(sb, "move_state ", op->move_status);
5100  if (op->attack_movement != op2->attack_movement)
5101  FAST_SAVE_LONG(sb, "attack_movement ", op->attack_movement);
5102  if (op->nrof != op2->nrof)
5103  FAST_SAVE_LONG(sb, "nrof ", op->nrof);
5104  if (op->level != op2->level)
5105  FAST_SAVE_LONG(sb, "level ", op->level);
5106  if (op->direction != op2->direction)
5107  FAST_SAVE_LONG(sb, "direction ", op->direction);
5108  if (op->type != op2->type)
5109  FAST_SAVE_LONG(sb, "type ", op->type);
5110  if (op->subtype != op2->subtype)
5111  FAST_SAVE_LONG(sb, "subtype ", op->subtype);
5112  if (op->attacktype != op2->attacktype)
5113  FAST_SAVE_LONG(sb, "attacktype ", op->attacktype);
5114 
5115  for (tmp = 0; tmp < NROFATTACKS; tmp++) {
5116  if (op->resist[tmp] != op2->resist[tmp]) {
5117  stringbuffer_append_string(sb, "resist_");
5118  FAST_SAVE_LONG(sb, resist_save[tmp], op->resist[tmp]);
5119  }
5120  }
5121 
5122  if (op->path_attuned != op2->path_attuned)
5123  FAST_SAVE_LONG(sb, "path_attuned ", op->path_attuned);
5124  if (op->path_repelled != op2->path_repelled)
5125  FAST_SAVE_LONG(sb, "path_repelled ", op->path_repelled);
5126  if (op->path_denied != op2->path_denied)
5127  FAST_SAVE_LONG(sb, "path_denied ", op->path_denied);
5128  if (op->material != op2->material)
5129  FAST_SAVE_LONG(sb, "material ", op->material);
5130  if (op->materialname && op->materialname != op2->materialname) {
5131  ADD_STRINGLINE_ENTRY(sb, "materialname ", op->materialname);
5132  }
5133  if (op->value != op2->value)
5134  FAST_SAVE_LONG(sb, "value ", op->value);
5135  if (op->carrying != op2->carrying)
5136  FAST_SAVE_LONG(sb, "carrying ", op->carrying);
5137  if (op->weight != op2->weight)
5138  FAST_SAVE_LONG(sb, "weight ", op->weight);
5139  if (op->invisible != op2->invisible)
5140  FAST_SAVE_LONG(sb, "invisible ", op->invisible);
5141  if (op->state != op2->state)
5142  FAST_SAVE_LONG(sb, "state ", op->state);
5143  if (op->magic != op2->magic)
5144  FAST_SAVE_LONG(sb, "magic ", op->magic);
5145  if (op->last_heal != op2->last_heal)
5146  FAST_SAVE_LONG(sb, "last_heal ", op->last_heal);
5147  if (op->last_sp != op2->last_sp)
5148  FAST_SAVE_LONG(sb, "last_sp ", op->last_sp);
5149  if (op->last_grace != op2->last_grace)
5150  FAST_SAVE_LONG(sb, "last_grace ", op->last_grace);
5151  if (op->last_eat != op2->last_eat)
5152  FAST_SAVE_LONG(sb, "last_eat ", op->last_eat);
5154  FAST_SAVE_LONG(sb, "connected ", tmp);
5155  if (op->glow_radius != op2->glow_radius)
5156  FAST_SAVE_LONG(sb, "glow_radius ", op->glow_radius);
5157  if (op->randomitems != op2->randomitems) {
5158  ADD_STRINGLINE_ENTRY(sb, "randomitems ", op->randomitems ? op->randomitems->name : "none");
5159  }
5160 
5161  if (op->run_away != op2->run_away)
5162  FAST_SAVE_LONG(sb, "run_away ", op->run_away);
5163  if (op->pick_up != op2->pick_up)
5164  FAST_SAVE_LONG(sb, "pick_up ", op->pick_up);
5165  if (op->weight_limit != op2->weight_limit)
5166  FAST_SAVE_LONG(sb, "container ", op->weight_limit);
5167  if (op->will_apply != op2->will_apply)
5168  FAST_SAVE_LONG(sb, "will_apply ", op->will_apply);
5169  if (op->smoothlevel != op2->smoothlevel)
5170  FAST_SAVE_LONG(sb, "smoothlevel ", op->smoothlevel);
5171 
5172  if (op->map_layer != op2->map_layer)
5173  ADD_STRINGLINE_ENTRY(sb, "map_layer ", map_layer_name[op->map_layer]);
5174 
5175  if (op->weapontype && op->weapontype != op2->weapontype) {
5176  FAST_SAVE_LONG(sb, "weapontype ", op->weapontype);
5177  }
5178  if (op->client_type && op->client_type != op2->client_type) {
5179  FAST_SAVE_LONG(sb, "client_type ", op->client_type);
5180  }
5181 
5182  if (op->item_power != op2->item_power) {
5183  FAST_SAVE_LONG(sb, "item_power ", op->item_power);
5184  }
5185 
5186  if (op->duration != op2->duration)
5187  FAST_SAVE_LONG(sb, "duration ", op->duration);
5188 
5189  if (op->range != op2->range)
5190  FAST_SAVE_LONG(sb, "range ", op->range);
5191 
5192  if (op->range_modifier != op2->range_modifier)
5193  FAST_SAVE_LONG(sb, "range_modifier ", op->range_modifier);
5194 
5195  if (op->duration_modifier != op2->duration_modifier)
5196  FAST_SAVE_LONG(sb, "duration_modifier ", op->duration_modifier);
5197 
5198  if (op->dam_modifier != op2->dam_modifier)
5199  FAST_SAVE_LONG(sb, "dam_modifier ", op->dam_modifier);
5200 
5201  if (op->gen_sp_armour != op2->gen_sp_armour) {
5202  FAST_SAVE_LONG(sb, "gen_sp_armour ", op->gen_sp_armour);
5203  }
5204 
5205  /* I've kept the old int move type saving code commented out.
5206  * In an ideal world, we'd know if we want to do a quick
5207  * save (say to a temp map, where we don't care about strings),
5208  * or a slower save/dm dump, where printing out strings is handy.
5209  */
5210  if (op->move_type != op2->move_type) {
5211  /*FAST_SAVE_LONG(sb, "move_type ", op->move_type)*/
5212  stringbuffer_append_string(sb, "move_type ");
5213  get_string_move_type(sb, op->move_type);
5214  stringbuffer_append_string(sb, "\n");
5215  }
5216  if (op->move_block != op2->move_block) {
5217  /*FAST_SAVE_LONG(sb, "move_block ", op->move_block)*/
5218  stringbuffer_append_string(sb, "move_block ");
5219  get_string_move_type(sb, op->move_block);
5220  stringbuffer_append_string(sb, "\n");
5221  }
5222  if (op->move_allow != op2->move_allow) {
5223  /*FAST_SAVE_LONG(sb, "move_allow ", op->move_allow);*/
5224  stringbuffer_append_string(sb, "move_allow ");
5225  get_string_move_type(sb, op->move_allow);
5226  stringbuffer_append_string(sb, "\n");
5227  }
5228  if (op->move_on != op2->move_on) {
5229  /*FAST_SAVE_LONG(sb, "move_on ", op->move_on);*/
5230  stringbuffer_append_string(sb, "move_on ");
5231  get_string_move_type(sb, op->move_on);
5232  stringbuffer_append_string(sb, "\n");
5233  }
5234  if (op->move_off != op2->move_off) {
5235  /*FAST_SAVE_LONG(sb, "move_off ", op->move_off);*/
5236  stringbuffer_append_string(sb, "move_off ");
5237  get_string_move_type(sb, op->move_off);
5238  stringbuffer_append_string(sb, "\n");
5239  }
5240  if (op->move_slow != op2->move_slow) {
5241  /*FAST_SAVE_LONG(sb, "move_slow ", op->move_slow);*/
5242  stringbuffer_append_string(sb, "move_slow ");
5243  get_string_move_type(sb, op->move_slow);
5244  stringbuffer_append_string(sb, "\n");
5245  }
5246 
5247  if (op->move_slow_penalty != op2->move_slow_penalty) {
5248  FAST_SAVE_DOUBLE(sb, "move_slow_penalty ", op->move_slow_penalty);
5249  }
5250 
5251  uint32_t *diff_flags = compare_flags(op, op2);
5252  for (int flag = 0; flag <= NUM_FLAGS; flag++) {
5253  bool flag_different = diff_flags[flag / 32] & (1U << (flag % 32));
5254  if (flag_names[flag] && flag_different) {
5255  ADD_STRINGLINE_ENTRY(sb, flag_names[flag], QUERY_FLAG(op, flag) ? " 1" : " 0");
5256  }
5257  }
5258 
5259  /* Save body locations */
5260  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
5261  if (op->body_info[i] != op2->body_info[i]) {
5262  stringbuffer_append_string(sb, body_locations[i].save_name);
5263  FAST_SAVE_LONG(sb, " ", op->body_info[i]);
5264  }
5265  }
5266 
5267 }
5268 
5273 void save_object_in_sb(StringBuffer *sb, const object *op, const int flag) {
5274  /* If the object has no_save set, just return */
5275  if (QUERY_FLAG(op, FLAG_NO_SAVE)) {
5276  return;
5277  }
5278 
5279  archetype *at = op->arch;
5280  if (at == NULL)
5281  at = empty_archetype;
5282 
5283  ADD_STRINGLINE_ENTRY(sb, "arch ", at->name);
5284 
5285  if (op->arch->reference_count > 0) {
5286  /* The object is a custom item/monster, so we handle its save differently.
5287  * We compare the custom archetype to the "original" one, then only save hp/gr/sp
5288  * which are the only values we can't recompute later - all others are modified by items in inventory.
5289  * Note that hp/gr/sp will appear twice in save, but last value will take precedence.
5290  */
5291  archetype *original = find_archetype(op->arch->name);
5292  if (!original) {
5293  LOG(llevError, "could not find original archetype %s for custom monster!\n", op->arch->name);
5294  abort();
5295  }
5296  get_ob_diff(sb, &op->arch->clone, &original->clone);
5297  if (op->stats.hp != op->arch->clone.stats.hp)
5298  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5299  if (op->stats.sp != op->arch->clone.stats.sp)
5300  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5301  if (op->stats.grace != op->arch->clone.stats.grace)
5302  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5303  if (op->x != op->arch->clone.x)
5304  FAST_SAVE_LONG(sb, "x ", op->x);
5305  if (op->y != op->arch->clone.y)
5306  FAST_SAVE_LONG(sb, "y ", op->y);
5307  } else if (op->artifact != NULL) {
5308  /* if op is an artifact, then find the "standard" artifact to use that for the diff */
5309  object *base;
5310  const artifact *artifact;
5311 
5312  artifact = find_artifact(op, op->artifact);
5313  if (artifact == NULL) {
5314  LOG(llevError, "could not find artifact %s [%d] to save data\n", op->artifact, op->type);
5315  get_ob_diff(sb, op, &at->clone);
5316  } else {
5317  ADD_STRINGLINE_ENTRY(sb, "artifact ", op->artifact);
5318  base = arch_to_object(at);
5320  get_ob_diff(sb, op, base);
5322  }
5323  } else {
5324  get_ob_diff(sb, op, &at->clone);
5325  }
5326 
5327  /* Eneq(@csd.uu.se): Added this to allow containers being saved with contents*/
5329  save_object_in_sb(sb, tmp, flag);
5330  FOR_INV_FINISH();
5331 
5332  stringbuffer_append_string(sb, "end\n");
5333 }
5334 
5347 int save_object(FILE *fp, object *op, int flag) {
5348  /* Even if the object does have an owner, it would seem that we should
5349  * still save it.
5350  */
5351  if (object_get_owner(op) != NULL || fp == NULL)
5352  return SAVE_ERROR_OK;
5353 
5354  /* If it is unpaid and we don't want to save those, just return. */
5355  if (!(flag&SAVE_FLAG_SAVE_UNPAID) && (QUERY_FLAG(op, FLAG_UNPAID))) {
5356  return SAVE_ERROR_OK;
5357  }
5358 
5360  save_object_in_sb(sb, op, flag);
5361  char *cp = stringbuffer_finish(sb);
5362  if (fputs(cp, fp) == EOF) {
5363  free(cp);
5364  return SAVE_ERROR_WRITE;
5365  } else {
5366  free(cp);
5367  return SAVE_ERROR_OK;
5368  }
5369 }
5370 
5372  if (op->map) {
5373  sstring death_animation = object_get_value(op, "death_animation");
5374  if (death_animation != NULL) {
5375  object *death = create_archetype(death_animation);
5376 
5377  if (death != NULL) {
5378  object_insert_in_map_at(death, op->map, op, 0, op->x, op->y);
5379  if (death->arch->more)
5380  object_fix_multipart(death);
5381  }
5382  }
5383  }
5384 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
Settings::casting_time
uint8_t casting_time
Definition: global.h:266
obj::weapon_speed
float weapon_speed
Definition: object.h:332
give.next
def next
Definition: give.py:44
obj::move_off
MoveType move_off
Definition: object.h:432
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:173
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.c:2362
object_find_first_free_spot
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
Definition: object.c:3549
UP_OBJ_FACE
#define UP_OBJ_FACE
Definition: object.h:520
empty_archetype
EXTERN archetype * empty_archetype
Definition: global.h:142
PLAYER
@ PLAYER
Definition: object.h:107
obj::attack_movement
uint16_t attack_movement
Definition: object.h:395
artifact
struct artifactstruct artifact
FREE_AND_CLEAR_STR_IF
#define FREE_AND_CLEAR_STR_IF(xyz)
Definition: global.h:198
freedir
int freedir[SIZEOFFREE]
Definition: object.c:306
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Definition: object.h:532
UPD_FACE
#define UPD_FACE
Definition: newclient.h:317
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.c:210
liv::dam
int16_t dam
Definition: living.h:46
object_free
void object_free(object *ob, int flags)
Definition: object.c:1565
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Definition: object.h:569
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
pl::count
uint32_t count
Definition: player.h:109
object_find_by_flag_applied
object * object_find_by_flag_applied(const object *who, int flag)
Definition: object.c:4237
object_remove
void object_remove(object *op)
Definition: object.c:1806
UP_OBJ_REMOVE
#define UP_OBJ_REMOVE
Definition: object.h:518
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:728
permute
static void permute(int *, int, int)
Definition: object.c:3568
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
object_sum_weight
signed long object_sum_weight(object *op)
Definition: object.c:561
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.c:908
pl::transport
object * transport
Definition: player.h:199
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Definition: object.h:13
objarray
static object objarray[STARTMAX]
Definition: object.c:278
MAP_SAVING
#define MAP_SAVING
Definition: map.h:134
obj::face
const Face * face
Definition: object.h:334
obj::move_block
MoveType move_block
Definition: object.h:429
object_find_by_type2
object * object_find_by_type2(const object *who, int type1, int type2)
Definition: object.c:4045
object_free_key_values
void object_free_key_values(object *op)
Definition: object.c:947
GET_MAP_TOP
#define GET_MAP_TOP(M, X, Y)
Definition: map.h:175
object_find_by_type_and_skill
object * object_find_by_type_and_skill(const object *who, int type, const char *skill)
Definition: object.c:4191
llevError
@ llevError
Definition: logger.h:11
give_artifact_abilities
void give_artifact_abilities(object *op, const object *artifact)
Definition: artifact.c:194
FABS
#define FABS(x)
Definition: define.h:22
FLAG_CLIENT_ANIM_RANDOM
#define FLAG_CLIENT_ANIM_RANDOM
Definition: define.h:241
find_skill_by_number
object * find_skill_by_number(object *who, int skillno)
Definition: main.c:376
MOVE_ALL
#define MOVE_ALL
Definition: define.h:398
object_reset
void object_reset(object *op)
Definition: object.c:927
object_copy_owner
void object_copy_owner(object *op, object *clone)
Definition: object.c:886
object_create_clone
object * object_create_clone(object *asrc)
Definition: object.c:3917
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Definition: define.h:255
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
object_find_by_type_and_arch_name
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
Definition: object.c:4285
object_add_weight
void object_add_weight(object *op, signed long weight)
Definition: object.c:2796
object_update
void object_update(object *op, int action)
Definition: object.c:1407
diamondslots.x
x
Definition: diamondslots.py:15
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Definition: define.h:268
obj::count
tag_t count
Definition: object.h:300
Statistics::spell_merges
uint64_t spell_merges
Definition: global.h:352
obj::map
struct mapdef * map
Definition: object.h:298
SIZEOFFREE1
#define SIZEOFFREE1
Definition: define.h:153
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
obj::race
sstring race
Definition: object.h:319
liv::maxgrace
int16_t maxgrace
Definition: living.h:45
ob_count
EXTERN long ob_count
Definition: global.h:146
obj::value
int32_t value
Definition: object.h:353
liv::wc
int8_t wc
Definition: living.h:37
FLAG_IS_TURNABLE
#define FLAG_IS_TURNABLE
Definition: define.h:256
STARTMAX
#define STARTMAX
Definition: config.h:515
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2302
liv::Str
int8_t Str
Definition: living.h:36
FALSE
#define FALSE
Definition: compat.h:14
SET_MAP_TOP
#define SET_MAP_TOP(M, X, Y, tmp)
Definition: map.h:180
object_new
object * object_new(void)
Definition: object.c:1242
obj::gen_sp_armour
int8_t gen_sp_armour
Definition: object.h:366
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Definition: object.c:4260
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:316
obj::path_attuned
uint32_t path_attuned
Definition: object.h:346
liv::maxhp
int16_t maxhp
Definition: living.h:41
objects
object * objects
Definition: object.c:283
pl::socket
socket_struct socket
Definition: player.h:94
flag_names
static const char *const flag_names[NUM_FLAGS+1]
Definition: object.c:4838
pl
Definition: player.h:92
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
Definition: define.h:357
TRAP
@ TRAP
Definition: object.h:241
object_distance
int object_distance(const object *ob1, const object *ob2)
Definition: object.c:3669
OB_SPELL_TAG_MATCH
#define OB_SPELL_TAG_MATCH(op, count)
Definition: object.h:93
obj::artifact
sstring artifact
Definition: object.h:315
get_ob_diff
void get_ob_diff(StringBuffer *sb, const object *op, const object *op2)
Definition: object.c:4952
object_merge_spell
void object_merge_spell(object *op, int16_t x, int16_t y)
Definition: object.c:2096
obj::invisible
int16_t invisible
Definition: object.h:363
arch_present_in_ob
object * arch_present_in_ob(const archetype *at, const object *op)
Definition: object.c:3172
object_set_flag_inv
void object_set_flag_inv(object *op, int flag)
Definition: object.c:3189
MoveType
unsigned char MoveType
Definition: define.h:417
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.c:4564
_key_value::key
const char * key
Definition: object.h:41
guildjoin.ob
ob
Definition: guildjoin.py:42
liv::hp
int16_t hp
Definition: living.h:40
obj::range_modifier
uint8_t range_modifier
Definition: object.h:410
commongive.inv
inv
Definition: commongive.py:28
blank_face
const Face * blank_face
Definition: image.c:35
obj::custom_name
sstring custom_name
Definition: object.h:436
CALLOC
#define CALLOC(x, y)
Definition: compat.h:31
NUM_FLAGS
#define NUM_FLAGS
Definition: define.h:374
GET_MAP_MOVE_SLOW
#define GET_MAP_MOVE_SLOW(M, X, Y)
Definition: map.h:198
pl::ob
object * ob
Definition: player.h:162
SKILL
@ SKILL
Definition: object.h:143
compare_ob_value_lists_one
static int compare_ob_value_lists_one(const object *, const object *)
Definition: object.c:352
object_find_by_type_applied
object * object_find_by_type_applied(const object *who, int type)
Definition: object.c:4091
object_can_merge
int object_can_merge(object *ob1, object *ob2)
Definition: object.c:422
RUNE
@ RUNE
Definition: object.h:240
init_objects
void init_objects(void)
Definition: object.c:316
give.top
def top
Definition: give.py:42
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.c:498
obj::path_denied
uint32_t path_denied
Definition: object.h:348
Ice.tmp
int tmp
Definition: Ice.py:207
GET_MAP_PLAYER
#define GET_MAP_PLAYER(M, X, Y)
Definition: map.h:169
FLAG_NO_MAGIC
#define FLAG_NO_MAGIC
Definition: define.h:276
remove_friendly_object
void remove_friendly_object(object *op)
Definition: friend.c:56
P_NO_MAGIC
#define P_NO_MAGIC
Definition: map.h:228
object_set_value_s
static int object_set_value_s(object *, const char *, const char *, int)
Definition: object.c:4406
llevMonster
@ llevMonster
Definition: logger.h:14
obj::smoothlevel
uint8_t smoothlevel
Definition: object.h:425
TRANSPORT
@ TRANSPORT
Definition: object.h:108
UPD_NROF
#define UPD_NROF
Definition: newclient.h:321
FOR_ABOVE_PREPARE
#define FOR_ABOVE_PREPARE(op_, it_)
Definition: define.h:685
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.c:101
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
obj::msg
sstring msg
Definition: object.h:323
FLAG_BLOCKSVIEW
#define FLAG_BLOCKSVIEW
Definition: define.h:269
obj::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:376
skills.h
object_free_all_data
void object_free_all_data(void)
Definition: object.c:760
free_arch
void free_arch(archetype *at)
Definition: arch.cpp:172
compare_flags
static uint32_t * compare_flags(const object *p, const object *q)
Definition: object.h:484
MAP_DARKNESS
#define MAP_DARKNESS(m)
Definition: map.h:75
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
FOR_OB_AND_ABOVE_FINISH
#define FOR_OB_AND_ABOVE_FINISH()
Definition: define.h:741
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:238
Statistics::spell_hash_full
uint64_t spell_hash_full
Definition: global.h:353
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: events.cpp:259
resist_save
const EXTERN char *const resist_save[NROFATTACKS]
Definition: attack.h:139
obj::randomitems
struct treasureliststruct * randomitems
Definition: object.h:389
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
AB_NO_PASS
#define AB_NO_PASS
Definition: map.h:236
MAX
#define MAX(x, y)
Definition: compat.h:24
obj::expmul
double expmul
Definition: object.h:399
active_objects
object * active_objects
Definition: object.c:285
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.c:288
SAVE_ERROR_WRITE
#define SAVE_ERROR_WRITE
Definition: map.h:147
map_layer_name
const char *const map_layer_name[MAP_LAYERS]
Definition: map.c:55
obj::nrof
uint32_t nrof
Definition: object.h:335
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.c:294
obj::ox
int16_t ox
Definition: object.h:329
obj::duration_modifier
uint8_t duration_modifier
Definition: object.h:408
obj::duration
int16_t duration
Definition: object.h:407
find_artifact
const artifact * find_artifact(const object *op, const char *name)
Definition: artifact.c:657
FLAG_DIALOG_PARSED
#define FLAG_DIALOG_PARSED
Definition: define.h:243
archt
Definition: object.h:468
settings
struct Settings settings
Definition: init.c:39
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
animate_object
void animate_object(object *op, int dir)
Definition: anim.c:43
obj::last_heal
int32_t last_heal
Definition: object.h:360
esrv_send_item
void esrv_send_item(object *pl, object *op)
Definition: main.c:355
socket_struct::update_look
uint32_t update_look
Definition: newserver.h:104
INS_ABOVE_FLOOR_ONLY
#define INS_ABOVE_FLOOR_ONLY
Definition: object.h:568
object_merge
object * object_merge(object *op, object *top)
Definition: object.c:2018
FOR_OB_AND_ABOVE_PREPARE
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Definition: define.h:737
FAST_SAVE_LONG
static void FAST_SAVE_LONG(StringBuffer *sb, const char *name, const long value)
Definition: object.c:4930
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4354
FLAG_IS_A_TEMPLATE
#define FLAG_IS_A_TEMPLATE
Definition: define.h:366
obj::slaying
sstring slaying
Definition: object.h:320
LOOK_OBJ
#define LOOK_OBJ(ob)
Definition: object.h:508
free_string
void free_string(sstring str)
Definition: shstr.c:280
stringbuffer.h
m
static event_registration m
Definition: citylife.cpp:425
liv::maxsp
int16_t maxsp
Definition: living.h:43
object_free_inventory
void object_free_inventory(object *ob)
Definition: object.c:1541
liv::luck
int8_t luck
Definition: living.h:39
autojail.who
who
Definition: autojail.py:3
object_get_key_value
key_value * object_get_key_value(const object *ob, const char *key)
Definition: object.c:4329
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:131
obj::spell_tags
tag_t * spell_tags
Definition: object.h:439
OBJ_EXPAND
#define OBJ_EXPAND
Definition: config.h:516
object_find_by_type_subtype
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Definition: object.c:4309
liv::exp
int64_t exp
Definition: living.h:47
object_unset_flag_inv
void object_unset_flag_inv(object *op, int flag)
Definition: object.c:3206
object_find_by_type_without_flags
object * object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags)
Definition: object.c:4012
item.q
q
Definition: item.py:32
pl::next
struct pl * next
Definition: player.h:93
FMT64
#define FMT64
Definition: compat.h:16
NROF
static uint32_t NROF(const object *const ob)
Definition: object.h:612
expand_objects
static void expand_objects(void)
Definition: object.c:1201
object_sub_weight
void object_sub_weight(object *op, signed long weight)
Definition: object.c:1780
object_find_by_flag
object * object_find_by_flag(const object *who, int flag)
Definition: object.c:4214
object_dump_all
void object_dump_all(void)
Definition: object.c:697
disinfect.map
map
Definition: disinfect.py:4
object_copy_with_inv
void object_copy_with_inv(const object *src_ob, object *dest_ob)
Definition: object.c:1183
object_find_by_type_and_slaying
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Definition: object.c:4166
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Definition: define.h:234
obj::name
sstring name
Definition: object.h:312
P_NO_ERROR
#define P_NO_ERROR
Definition: map.h:241
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.c:1053
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:584
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Definition: stringbuffer.c:85
object_update_turn_face
void object_update_turn_face(object *op)
Definition: object.c:1300
MOVE_WALK
#define MOVE_WALK
Definition: define.h:392
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
Definition: define.h:320
obj::path_repelled
uint32_t path_repelled
Definition: object.h:347
FOR_ABOVE_FINISH
#define FOR_ABOVE_FINISH()
Definition: define.h:692
obj::total_exp
int64_t total_exp
Definition: object.h:373
object_dump
void object_dump(const object *op, StringBuffer *sb)
Definition: object.c:638
liv::Cha
int8_t Cha
Definition: living.h:36
obj::name_pl
sstring name_pl
Definition: object.h:316
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:752
HEAD
#define HEAD(op)
Definition: object.h:594
fatal
void fatal(enum fatal_error err)
Definition: utils.c:597
object_fix_multipart
void object_fix_multipart(object *tmp)
Definition: object.c:4672
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:95
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.c:3875
CONTAINER
@ CONTAINER
Definition: object.h:231
object_clear
void object_clear(object *op)
Definition: object.c:976
make_face_from_files.str
str
Definition: make_face_from_files.py:24
obj::speed_left
float speed_left
Definition: object.h:331
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
ADD_STRINGLINE_ENTRY
static void ADD_STRINGLINE_ENTRY(StringBuffer *sb, const char *name, const char *value)
Definition: object.c:4923
convert.action
action
Definition: convert.py:25
find_string
sstring find_string(const char *str)
Definition: shstr.c:236
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:509
obj::prev
struct obj * prev
Definition: object.h:279
object_present_in_ob
object * object_present_in_ob(uint8_t type, const object *op)
Definition: object.c:3118
navar-midane_pickup.msg
list msg
Definition: navar-midane_pickup.py:13
absdir
int absdir(int d)
Definition: object.c:3722
obj::carrying
int32_t carrying
Definition: object.h:370
FAST_SAVE_DOUBLE
static void FAST_SAVE_DOUBLE(StringBuffer *sb, const char *name, const double value)
Definition: object.c:4935
first_player
EXTERN player * first_player
Definition: global.h:115
FLAG_IS_WOODED
#define FLAG_IS_WOODED
Definition: define.h:330
obj::container
struct obj * container
Definition: object.h:292
obj::x
int16_t x
Definition: object.h:328
INS_NO_MERGE
#define INS_NO_MERGE
Definition: object.h:567
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
SET_MAP_FLAGS
#define SET_MAP_FLAGS(M, X, Y, C)
Definition: map.h:164
fix_object
void fix_object(object *op)
Definition: living.c:1126
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
object_increase_nrof
static void object_increase_nrof(object *op, uint32_t i)
Definition: object.c:2726
nrofallocobjects
int nrofallocobjects
Definition: object.c:280
FLAG_WIZPASS
#define FLAG_WIZPASS
Definition: define.h:314
maxfree
int maxfree[SIZEOFFREE]
Definition: object.c:300
LAMP
@ LAMP
Definition: object.h:201
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:193
obj::other_arch
struct archt * other_arch
Definition: object.h:417
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:675
get_string_move_type
static void get_string_move_type(StringBuffer *sb, MoveType mt)
Definition: object.c:4879
archt::more
struct archt * more
Definition: object.h:471
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Definition: object.h:571
sstring
const typedef char * sstring
Definition: global.h:40
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.c:4489
disinfect.count
int count
Definition: disinfect.py:7
obj::speed
float speed
Definition: object.h:330
say.max
dictionary max
Definition: say.py:148
obj::weapontype
uint32_t weapontype
Definition: object.h:375
tag_t
uint32_t tag_t
Definition: object.h:12
P_PLAYER
#define P_PLAYER
Definition: map.h:237
liv::Con
int8_t Con
Definition: living.h:36
obj::client_type
uint16_t client_type
Definition: object.h:343
obj::below
struct obj * below
Definition: object.h:288
sproto.h
liv::food
int32_t food
Definition: living.h:48
free_dialog_information
void free_dialog_information(object *op)
Definition: dialog.c:32
FLAG_NO_DROP
#define FLAG_NO_DROP
Definition: define.h:288
FLAG_NO_SAVE
#define FLAG_NO_SAVE
Definition: define.h:244
obj::move_slow_penalty
float move_slow_penalty
Definition: object.h:434
FLAG_NO_STEAL
#define FLAG_NO_STEAL
Definition: define.h:342
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:748
mapdef
Definition: map.h:324
GET_MAP_MOVE_ON
#define GET_MAP_MOVE_ON(M, X, Y)
Definition: map.h:203
liv::Int
int8_t Int
Definition: living.h:36
map_find_dir
int map_find_dir(mapstruct *m, int x, int y, object *exclude)
Definition: object.c:3622
obj::map_layer
uint8_t map_layer
Definition: object.h:426
save_object_in_sb
void save_object_in_sb(StringBuffer *sb, const object *op, const int flag)
Definition: object.c:5273
free_objects
static object * free_objects
Definition: object.c:284
obj::animation
const Animations * animation
Definition: object.h:420
FREE_OBJ_DROP_ABOVE_FLOOR
#define FREE_OBJ_DROP_ABOVE_FLOOR
Definition: object.h:533
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
object_check_move_on
int object_check_move_on(object *op, object *originator)
Definition: object.c:2962
obj::material
uint16_t material
Definition: object.h:350
object_find_multi_free_spot_around
int object_find_multi_free_spot_around(const object *ob, const object *gen, int16_t *hx, int16_t *hy)
Definition: object.c:3246
ob_move_on
method_ret ob_move_on(object *op, object *victim, object *originator)
Definition: ob_methods.c:111
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
object_set_owner
void object_set_owner(object *op, object *owner)
Definition: object.c:833
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:78
reduction_dir
static const int reduction_dir[SIZEOFFREE][3]
Definition: object.c:3760
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
move_name
const char *const move_name[]
Definition: object.c:4819
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:250
MAX_BUF
#define MAX_BUF
Definition: define.h:35
artifactstruct
Definition: artifact.h:14
object_get_multi_size
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Definition: object.c:4731
INS_ON_TOP
#define INS_ON_TOP
Definition: object.h:570
find_insert_pos
static object * find_insert_pos(object *op, const int flag)
Definition: object.c:2264
obj::item_power
int8_t item_power
Definition: object.h:365
obj::lore
sstring lore
Definition: object.h:325
esrv_del_item
void esrv_del_item(player *pl, object *ob)
Definition: main.c:382
UP_OBJ_INSERT
#define UP_OBJ_INSERT
Definition: object.h:517
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:281
object_insert_to_free_spot_or_free
void object_insert_to_free_spot_or_free(object *op, mapstruct *map, int x, int y, int start, int stop, object *originator)
Definition: object.c:4778
obj::next
struct obj * next
Definition: object.h:278
offsetof
#define offsetof(type, member)
Definition: shstr.h:37
RANDOM
#define RANDOM()
Definition: define.h:642
StringBuffer
Definition: stringbuffer.c:25
statistics
struct Statistics statistics
Definition: init.c:100
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:196
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Definition: define.h:393
FLAG_CLIENT_ANIM_SYNC
#define FLAG_CLIENT_ANIM_SYNC
Definition: define.h:240
guildbuy.ob2
ob2
Definition: guildbuy.py:23
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:721
obj::y
int16_t y
Definition: object.h:328
object_count_used
int object_count_used(void)
Definition: object.c:1740
obj::glow_radius
int8_t glow_radius
Definition: object.h:367
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:218
dirdiff
int dirdiff(int dir1, int dir2)
Definition: object.c:3740
obj::title
sstring title
Definition: object.h:318
obj::arch
struct archt * arch
Definition: object.h:416
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.c:4798
obj::oy
int16_t oy
Definition: object.h:329
object_count_active
int object_count_active(void)
Definition: object.c:1756
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
INS_MAP_LOAD
#define INS_MAP_LOAD
Definition: object.h:572
SK_WOODSMAN
@ SK_WOODSMAN
Definition: skills.h:40
obj::type
uint8_t type
Definition: object.h:341
obj::last_grace
int16_t last_grace
Definition: object.h:362
object_count_free
int object_count_free(void)
Definition: object.c:1724
object_find_by_tag_global
object * object_find_by_tag_global(tag_t i)
Definition: object.c:720
roll-o-matic.stop
def stop()
Definition: roll-o-matic.py:49
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
guildbuy.ob1
ob1
Definition: guildbuy.py:22
object_find_by_tag
object * object_find_by_tag(const object *who, tag_t tag)
Definition: object.c:4068
obj::move_slow
MoveType move_slow
Definition: object.h:433
obj::stats
living stats
Definition: object.h:371
SPELL_MAPPINGS
#define SPELL_MAPPINGS
Definition: global.h:147
obj::direction
int8_t direction
Definition: object.h:337
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Definition: global.h:191
archt::clone
object clone
Definition: object.h:472
obj::state
uint8_t state
Definition: object.h:352
SIZEOFFREE2
#define SIZEOFFREE2
Definition: define.h:154
obj::contr
struct pl * contr
Definition: object.h:277
SCRIPT_FIX_NOTHING
#define SCRIPT_FIX_NOTHING
Definition: global.h:368
map_find_by_archetype
object * map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at)
Definition: object.c:3068
obj::weight
int32_t weight
Definition: object.h:368
liv::Dex
int8_t Dex
Definition: living.h:36
item
Definition: item.py:1
object_remove_from_active_list
void object_remove_from_active_list(object *op)
Definition: object.c:1365
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
P_NEED_UPDATE
#define P_NEED_UPDATE
Definition: map.h:240
liv::Wis
int8_t Wis
Definition: living.h:36
archt::reference_count
int reference_count
Definition: object.h:475
get_button_value
int get_button_value(const object *button)
Definition: button.c:749
liv::grace
int16_t grace
Definition: living.h:44
object_set_cheat
void object_set_cheat(object *op)
Definition: object.c:3224
give.op
op
Definition: give.py:33
object_find_free_spot
int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
Definition: object.c:3509
autojail.value
value
Definition: autojail.py:6
object_insert_in_map
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:2328
object_value_set
bool object_value_set(const object *op, const char *const key)
Definition: object.c:4384
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:278
obj::key_values
key_value * key_values
Definition: object.h:437
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.c:360
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:685
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:215
obj::weapon_speed_left
float weapon_speed_left
Definition: object.h:333
_key_value
Definition: object.h:40
map_find_by_type
object * map_find_by_type(mapstruct *m, int x, int y, uint8_t type)
Definition: object.c:3095
obj::last_sp
int32_t last_sp
Definition: object.h:361
FLAG_NO_FIX_PLAYER
#define FLAG_NO_FIX_PLAYER
Definition: define.h:277
diamondslots.y
y
Definition: diamondslots.py:16
FLAG_BEEN_APPLIED
#define FLAG_BEEN_APPLIED
Definition: define.h:323
python_pickup.where
where
Definition: python_pickup.py:7
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
npc_dialog.index
int index
Definition: npc_dialog.py:102
object_find_by_type
object * object_find_by_type(const object *who, int type)
Definition: object.c:3988
SET_MAP_OB
#define SET_MAP_OB(M, X, Y, tmp)
Definition: map.h:178
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.c:104
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:80
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2820
update_all_los
void update_all_los(const mapstruct *map, int x, int y)
Definition: los.c:536
object_update_speed
void object_update_speed(object *op)
Definition: object.c:1317
obj::head
struct obj * head
Definition: object.h:297
object_handle_death_animation
void object_handle_death_animation(object *op)
Definition: object.c:5371
object_get_owner_const
static const object * object_get_owner_const(const object *op)
Definition: object.c:617
obj::subtype
uint8_t subtype
Definition: object.h:342
obj::more
struct obj * more
Definition: object.h:296
object_get_env_recursive
object * object_get_env_recursive(object *op)
Definition: object.c:583
object_find_by_name_global
object * object_find_by_name_global(const char *str)
Definition: object.c:740
obj::last_eat
int32_t last_eat
Definition: object.h:359
obj::move_type
MoveType move_type
Definition: object.h:428
obj::weight_limit
int32_t weight_limit
Definition: object.h:369
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:232
obj::materialname
sstring materialname
Definition: object.h:349
strcasecmp
int strcasecmp(const char *s1, const char *s2)
artifactstruct::item
object * item
Definition: artifact.h:15
castle_read.key
key
Definition: castle_read.py:64
MIN_ACTIVE_SPEED
#define MIN_ACTIVE_SPEED
Definition: define.h:637
find_dir_2
int find_dir_2(int x, int y)
Definition: object.c:3685
object_present_in_ob_by_name
object * object_present_in_ob_by_name(int type, const char *str, const object *op)
Definition: object.c:3153
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
obj::pick_up
uint8_t pick_up
Definition: object.h:364
liv::ac
int8_t ac
Definition: living.h:38
obj::skill
sstring skill
Definition: object.h:322
SAVE_ERROR_OK
#define SAVE_ERROR_OK
Definition: map.h:144
loader.h
nroffreeobjects
int nroffreeobjects
Definition: object.c:279
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:2067
obj::move_status
int32_t move_status
Definition: object.h:394
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1533
GET_MAP_MOVE_OFF
#define GET_MAP_MOVE_OFF(M, X, Y)
Definition: map.h:208
update_position
void update_position(mapstruct *m, int x, int y)
Definition: map.c:2123
FLAG_IS_HILLY
#define FLAG_IS_HILLY
Definition: define.h:332
MOVE_FLY_HIGH
#define MOVE_FLY_HIGH
Definition: define.h:394
object_find_multi_free_spot_within_radius
int object_find_multi_free_spot_within_radius(const object *ob, const object *gen, int *hx, int *hy)
Definition: object.c:3362
object_replace_insert_in_map
void object_replace_insert_in_map(const char *arch_string, object *op)
Definition: object.c:2560
UP_OBJ_CHANGE
#define UP_OBJ_CHANGE
Definition: object.h:519
GET_MAP_FLAGS
#define GET_MAP_FLAGS(M, X, Y)
Definition: map.h:162
_key_value::next
struct _key_value * next
Definition: object.h:43
object_find_by_type_and_race
object * object_find_by_type_and_race(const object *who, int type, const char *race)
Definition: object.c:4141
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
object_decrease_nrof
object * object_decrease_nrof(object *op, uint32_t i)
Definition: object.c:2639
P_NO_CLERIC
#define P_NO_CLERIC
Definition: map.h:239
object_find_by_name
object * object_find_by_name(const object *who, const char *name)
Definition: object.c:3964
FREE_OBJ_FREE_INVENTORY
#define FREE_OBJ_FREE_INVENTORY
Definition: object.h:531
archt::name
sstring name
Definition: object.h:469
_key_value::value
const char * value
Definition: object.h:42
SCROLL
@ SCROLL
Definition: object.h:221
FLAG_IS_LINKED
#define FLAG_IS_LINKED
Definition: define.h:315
object_find_by_type_and_name
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.c:4116
obj::above
struct obj * above
Definition: object.h:289
obj::will_apply
uint8_t will_apply
Definition: object.h:396
obj::anim_suffix
sstring anim_suffix
Definition: object.h:317
obj::move_on
MoveType move_on
Definition: object.h:431
obj::attacktype
uint32_t attacktype
Definition: object.h:345
obj::run_away
uint8_t run_away
Definition: object.h:388
TRUE
#define TRUE
Definition: compat.h:11
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:311
object_get_player_container
object * object_get_player_container(object *op)
Definition: object.