Crossfire Server, Trunk  1.75.0
object.cpp
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 #include <map>
32 
33 #ifndef WIN32 /* ---win32 exclude headers */
34 #include <sys/types.h>
35 #include <sys/uio.h>
36 #endif /* win32 */
37 
38 #include "loader.h"
39 #include "object.h"
40 #include "skills.h"
41 #include "sproto.h"
42 #include "stringbuffer.h"
43 
44 #if defined(CF_MXE_CROSS_COMPILE) || defined(WIN32)
45 # define ffs(word) (__builtin_constant_p (word) \
46  ? __builtin_ffs (word) \
47  : ({ int __cnt, __tmp; \
48  __asm__ __volatile__ \
49  ("bsfl %2,%0\n\t" \
50  "cmovel %1,%0" \
51  : "=&r" (__cnt), "=r" (__tmp) \
52  : "rm" (word), "1" (-1)); \
53  __cnt + 1; }))
54 #endif
55 
56 static int compare_ob_value_lists_one(const object *, const object *);
57 static int compare_ob_value_lists(const object *, const object *);
58 static void permute(int *, int, int);
59 static int object_set_value_s(object *, const char *, const char *, int);
60 static void object_increase_nrof(object *op, uint32_t i);
61 
76 const char *const spell_mapping[SPELL_MAPPINGS] = {
77  "spell_magic_bullet", /* 0 */
78  "spell_small_fireball", /* 1 */
79  "spell_medium_fireball", /* 2 */
80  "spell_large_fireball", /* 3 */
81  "spell_burning_hands", /* 4 */
82  "spell_sm_lightning", /* 5 */
83  "spell_large_lightning", /* 6 */
84  "spell_magic_missile", /* 7 */
85  "spell_create_bomb", /* 8 */
86  "spell_summon_golem", /* 9 */
87  "spell_summon_fire_elemental", /* 10 */
88  "spell_summon_earth_elemental", /* 11 */
89  "spell_summon_water_elemental", /* 12 */
90  "spell_summon_air_elemental", /* 13 */
91  "spell_dimension_door", /* 14 */
92  "spell_create_earth_wall", /* 15 */
93  "spell_paralyze", /* 16 */
94  "spell_icestorm", /* 17 */
95  "spell_magic_mapping", /* 18 */
96  "spell_turn_undead", /* 19 */
97  "spell_fear", /* 20 */
98  "spell_poison_cloud", /* 21 */
99  "spell_wonder", /* 22 */
100  "spell_destruction", /* 23 */
101  "spell_perceive_self", /* 24 */
102  "spell_word_of_recall", /* 25 */
103  "spell_invisible", /* 26 */
104  "spell_invisible_to_undead", /* 27 */
105  "spell_probe", /* 28 */
106  "spell_lg_magic_bullet", /* 29 */
107  "spell_improved_invisibility", /* 30 */
108  "spell_holy_word", /* 31 */
109  "spell_minor_healing", /* 32 */
110  "spell_medium_healing", /* 33 */
111  "spell_major_healing", /* 34 */
112  "spell_heal", /* 35 */
113  "spell_create_food", /* 36 */
114  "spell_earth_to_dust", /* 37 */
115  "spell_armour", /* 38 */
116  "spell_strength", /* 39 */
117  "spell_dexterity", /* 40 */
118  "spell_constitution", /* 41 */
119  "spell_charisma", /* 42 */
120  "spell_create_fire_wall", /* 43 */
121  "spell_create_frost_wall", /* 44 */
122  "spell_protection_from_cold", /* 45 */
123  "spell_protection_from_electricity", /* 46 */
124  "spell_protection_from_fire", /* 47 */
125  "spell_protection_from_poison", /* 48 */
126  "spell_protection_from_slow", /* 49 */
127  "spell_protection_from_paralysis", /* 50 */
128  "spell_protection_from_draining", /* 51 */
129  "spell_protection_from_magic", /* 52 */
130  "spell_protection_from_attack", /* 53 */
131  "spell_levitate", /* 54 */
132  "spell_small_speedball", /* 55 */
133  "spell_large_speedball", /* 56 */
134  "spell_hellfire", /* 57 */
135  "spell_dragonbreath", /* 58 */
136  "spell_large_icestorm", /* 59 */
137  "spell_charging", /* 60 */
138  "spell_polymorph", /* 61 */
139  "spell_cancellation", /* 62 */
140  "spell_confusion", /* 63 */
141  "spell_mass_confusion", /* 64 */
142  "spell_summon_pet_monster", /* 65 */
143  "spell_slow", /* 66 */
144  "spell_regenerate_spellpoints", /* 67 */
145  "spell_cure_poison", /* 68 */
146  "spell_protection_from_confusion", /* 69 */
147  "spell_protection_from_cancellation", /* 70 */
148  "spell_protection_from_depletion", /* 71 */
149  "spell_alchemy", /* 72 */
150  "spell_remove_curse", /* 73 */
151  "spell_remove_damnation", /* 74 */
152  "spell_identify", /* 75 */
153  "spell_detect_magic", /* 76 */
154  "spell_detect_monster", /* 77 */
155  "spell_detect_evil", /* 78 */
156  "spell_detect_curse", /* 79 */
157  "spell_heroism", /* 80 */
158  "spell_aggravation", /* 81 */
159  "spell_firebolt", /* 82 */
160  "spell_frostbolt", /* 83 */
161  "spell_shockwave", /* 84 */
162  "spell_color_spray", /* 85 */
163  "spell_haste", /* 86 */
164  "spell_face_of_death", /* 87 */
165  "spell_ball_lightning", /* 88 */
166  "spell_meteor_swarm", /* 89 */
167  "spell_comet", /* 90 */
168  "spell_mystic_fist", /* 91 */
169  "spell_raise_dead", /* 92 */
170  "spell_resurrection", /* 93 */
171  "spell_reincarnation", /* 94 */
172  NULL, /* 95 spell_immunity_to_cold */
173  NULL, /* 96 spell_immunity_to_electricity */
174  NULL, /* 97 spell_immunity_to_fire */
175  NULL, /* 98 spell_immunity_to_poison */
176  NULL, /* 99 spell_immunity_to_slow */
177  NULL, /* 100 spell_immunity_to_paralysis */
178  NULL, /* 101 spell_immunity_to_draining */
179  NULL, /* 102 spell_immunity_to_magic */
180  NULL, /* 103 spell_immunity_to_attack */
181  "spell_invulnerability", /* 104 */
182  "spell_defense", /* 105 */
183  "spell_rune_of_fire", /* 106 */
184  "spell_rune_of_frost", /* 107 */
185  "spell_rune_of_shocking", /* 108 */
186  "spell_rune_of_blasting", /* 109 */
187  "spell_rune_of_death", /* 110 */
188  "spell_marking_rune", /* 111 */
189  "spell_build_director", /* 112 */
190  "spell_create_pool_of_chaos", /* 113 */
191  "spell_build_bullet_wall", /* 114 */
192  "spell_build_lightning_wall", /* 115 */
193  "spell_build_fireball_wall", /* 116 */
194  "spell_magic_rune", /* 117 */
195  "spell_rune_of_magic_drain", /* 118 */
196  "spell_antimagic_rune", /* 119 */
197  "spell_rune_of_transference", /* 120 */
198  "spell_transference", /* 121 */
199  "spell_magic_drain", /* 122 */
200  "spell_counterspell", /* 123 */
201  "spell_disarm", /* 124 */
202  "spell_cure_confusion", /* 125 */
203  "spell_restoration", /* 126 */
204  NULL, /* 127 */ /* Was summon evil monster */
205  "spell_counterwall", /* 128 */
206  "spell_cause_light_wounds", /* 129 */
207  "spell_cause_medium_wounds", /* 130 */
208  "spell_cause_heavy_wounds", /* 131 */
209  "spell_charm_monsters", /* 132 */
210  "spell_banishment", /* 133 */
211  "spell_create_missile", /* 134 */
212  "spell_show_invisible", /* 135 */
213  "spell_xray", /* 136 */
214  "spell_pacify", /* 137 */
215  "spell_summon_fog", /* 138 */
216  "spell_steambolt", /* 139 */
217  "spell_command_undead", /* 140 */
218  "spell_holy_orb", /* 141 */
219  "spell_summon_avatar", /* 142 */
220  "spell_holy_possession", /* 143 */
221  "spell_bless", /* 144 */
222  "spell_curse", /* 145 */
223  "spell_regeneration", /* 146 */
224  "spell_consecrate", /* 147 */
225  "spell_summon_cult_monsters", /* 148 */
226  "spell_cause_critical_wounds", /* 149 */
227  "spell_holy_wrath", /* 150 */
228  "spell_retributive_strike", /* 151 */
229  "spell_finger_of_death", /* 152 */
230  "spell_insect_plague", /* 153 */
231  "spell_call_holy_servant", /* 154 */
232  "spell_wall_of_thorns", /* 155 */
233  "spell_staff_to_snake", /* 156 */
234  "spell_light", /* 157 */
235  "spell_darkness", /* 158 */
236  "spell_nightfall", /* 159 */
237  "spell_daylight", /* 160 */
238  "spell_sunspear", /* 161 */
239  "spell_faery_fire", /* 162 */
240  "spell_cure_blindness", /* 163 */
241  "spell_dark_vision", /* 164 */
242  "spell_bullet_swarm", /* 165 */
243  "spell_bullet_storm", /* 166 */
244  "spell_cause_many_wounds", /* 167 */
245  "spell_small_snowstorm", /* 168 */
246  "spell_medium_snowstorm", /* 169 */
247  "spell_large_snowstorm", /* 170 */
248  "spell_cure_disease", /* 171 */
249  "spell_cause_red_death", /* 172 */
250  "spell_cause_flu", /* 173 */
251  "spell_cause_black_death", /* 174 */
252  "spell_cause_leprosy", /* 175 */
253  "spell_cause_smallpox", /* 176 */
254  "spell_cause_white_death", /* 177 */
255  "spell_cause_anthrax", /* 178 */
256  "spell_cause_typhoid", /* 179 */
257  "spell_mana_blast", /* 180 */
258  "spell_small_manaball", /* 181 */
259  "spell_medium_manaball", /* 182 */
260  "spell_large_manaball", /* 183 */
261  "spell_manabolt", /* 184 */
262  "spell_dancing_sword", /* 185 */
263  "spell_animate_weapon", /* 186 */
264  "spell_cause_cold", /* 187 */
265  "spell_divine_shock", /* 188 */
266  "spell_windstorm", /* 189 */
267  "spell_sanctuary", /* 190 */
268  "spell_peace", /* 191 */
269  "spell_spiderweb", /* 192 */
270  "spell_conflict", /* 193 */
271  "spell_rage", /* 194 */
272  "spell_forked_lightning", /* 195 */
273  "spell_poison_fog", /* 196 */
274  "spell_flaming_aura", /* 197 */
275  "spell_vitriol", /* 198 */
276  "spell_vitriol_splash", /* 199 */
277  "spell_iron_skin", /* 200 */
278  "spell_wrathful_eye", /* 201 */
279  "spell_town_portal", /* 202 */
280  "spell_missile_swarm", /* 203 */
281  "spell_cause_rabies", /* 204 */
282  "spell_glyph", /* 205 */
283 };
284 
285 #ifdef MEMORY_DEBUG
286 int nroffreeobjects = 0;
287 int nrofallocobjects = 0;
288 #undef OBJ_EXPAND
289 #define OBJ_EXPAND 1
290 #else
291 static object objarray[STARTMAX];
294 #endif
295 
296 static object *objects;
297 static object *free_objects;
298 object *active_objects;
300 static std::map<tag_t, object *> object_map;
301 
304  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,
305  0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
306 };
307 
310  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,
311  -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3
312 };
313 
316  0, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45,
317  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
318 };
319 
322  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,
323  1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
324 };
325 
331 void init_objects(void) {
332  /* Initialize all objects: */
333  objects = NULL;
334  active_objects = NULL;
335 
336 #ifdef MEMORY_DEBUG
337  free_objects = NULL;
338 #else
340  objarray[0].prev = NULL,
341  objarray[0].next = &objarray[1],
344  for (int i = 1; i < STARTMAX-1; i++) {
345  objarray[i].next = &objarray[i+1];
346  objarray[i].prev = &objarray[i-1];
349  }
350  objarray[STARTMAX-1].next = NULL;
354 #endif
355 
356  object_map = {};
357 }
358 
369 static int compare_ob_value_lists_one(const object *wants, const object *has) {
370  key_value *wants_field;
371 
372  /* n-squared behaviour (see object_get_key_value()), but I'm hoping both
373  * objects with lists are rare, and lists stay short. If not, use a
374  * different structure or at least keep the lists sorted...
375  */
376 
377  /* For each field in wants, */
378  for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) {
379  key_value *has_field;
380 
381  /* Look for a field in has with the same key. */
382  has_field = object_get_key_value(has, wants_field->key);
383 
384  if (has_field == NULL) {
385  /* No field with that name. */
386  return FALSE;
387  }
388 
389  /* Found the matching field. */
390  if (has_field->value != wants_field->value) {
391  /* Values don't match, so this half of the comparison is false. */
392  return FALSE;
393  }
394 
395  /* If we get here, we found a match. Now for the next field in wants. */
396  }
397 
398  /* If we get here, every field in wants has a matching field in has. */
399  return TRUE;
400 }
401 
410 static int compare_ob_value_lists(const object *ob1, const object *ob2) {
411  /* However, there may be fields in has which aren't partnered in wants,
412  * so we need to run the comparison *twice*. :(
413  */
414  return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1);
415 }
416 
439 int object_can_merge(object *ob1, object *ob2) {
440  /* A couple quicksanity checks */
441  if (ob1 == ob2 || ob1->type != ob2->type)
442  return 0;
443 
444  if (ob1->speed != ob2->speed)
445  return 0;
446  /* Note sure why the following is the case - either the object has to
447  * be animated or have a very low speed. Is this an attempted monster
448  * check?
449  */
450  /*TODO is this check really needed?*/
451  if (!QUERY_FLAG(ob1, FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
452  return 0;
453 
454  /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
455  * value could not be stored in a int32_t (which unfortunately sometimes is
456  * used to store nrof).
457  */
458  if (ob1->nrof+ob2->nrof >= 1UL<<31)
459  return 0;
460 
461  /* This is really a spellbook check - really, we should
462  * check all objects in the inventory.
463  */
464  /*TODO is this check really needed?*/
465  if (ob1->inv || ob2->inv) {
466  /* if one object has inventory but the other doesn't, not equiv */
467  if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
468  return 0;
469 
470  /* Now check to see if the two inventory objects could merge */
471  if (!object_can_merge(ob1->inv, ob2->inv))
472  return 0;
473 
474  /* inventory ok - still need to check rest of this object to see
475  * if it is valid.
476  */
477  }
478 
479  /* Note: FLAG_INV_LOCKED is ignored for merging purposes */
480  if ((ob1->arch != ob2->arch)
481  || (ob1->flags[0] != ob2->flags[0])
482  || (ob1->flags[1] != ob2->flags[1])
483  || (ob1->flags[2] != ob2->flags[2])
484  || ((ob1->flags[3]&~0x84) != (ob2->flags[3]&~0x84)) /* ignore CLIENT_SENT and FLAG_OBJ_ORIGINAL */
485  || (ob1->name != ob2->name)
486  || (ob1->title != ob2->title)
487  || (ob1->msg != ob2->msg)
488  || (ob1->weight != ob2->weight)
489  || (ob1->item_power != ob2->item_power)
490  || (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist)) != 0)
491  || (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats)) != 0)
492  || (ob1->attacktype != ob2->attacktype)
493  || (ob1->magic != ob2->magic)
494  || (ob1->slaying != ob2->slaying)
495  || (ob1->skill != ob2->skill)
496  || (ob1->value != ob2->value)
497  || (ob1->animation != ob2->animation)
498  || (ob1->client_type != ob2->client_type)
499  || (ob1->materialname != ob2->materialname)
500  || (ob1->lore != ob2->lore)
501  || (ob1->subtype != ob2->subtype)
502  || (ob1->move_type != ob2->move_type)
503  || (ob1->move_block != ob2->move_block)
504  || (ob1->move_allow != ob2->move_allow)
505  || (ob1->move_on != ob2->move_on)
506  || (ob1->move_off != ob2->move_off)
507  || (ob1->move_slow != ob2->move_slow)
508  || (ob1->move_slow_penalty != ob2->move_slow_penalty)
509  || (ob1->map_layer != ob2->map_layer))
510  return 0;
511 
512  /* Don't merge objects that are applied. With the new 'body' code,
513  * it is possible for most any character to have more than one of
514  * some items equipped, and we don't want those to merge.
515  */
516  if (QUERY_FLAG(ob1, FLAG_APPLIED) || QUERY_FLAG(ob2, FLAG_APPLIED))
517  return 0;
518 
519  if (ob1->key_values != NULL || ob2->key_values != NULL) {
520  /* At least one of these has key_values. */
521  if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
522  /* One has fields, but the other one doesn't. */
523  return 0;
524  } else {
525  if (!compare_ob_value_lists(ob1, ob2)) {
526  return 0;
527  }
528  }
529  }
530 
531  /*TODO should this really be limited to scrolls?*/
532  switch (ob1->type) {
533  case SCROLL:
534  if (ob1->level != ob2->level)
535  return 0;
536  break;
537  }
538 
539  /* Everything passes, must be OK. */
540  return 1;
541 }
542 
556 /* TODO should check call this this are made a place where we really need reevaluaton of whole tree */
557 void object_sum_weight(object *op) {
558  signed long sum;
559 
560  sum = 0;
561  FOR_INV_PREPARE(op, inv) {
562  if (inv->inv)
563  object_sum_weight(inv);
564  sum += inv->carrying+inv->weight*NROF(inv);
565  } FOR_INV_FINISH();
566  if (op->type == CONTAINER && op->stats.Str)
567  sum = (sum*(100-op->stats.Str))/100;
568  op->carrying = sum;
569 }
570 
578 object *object_get_env_recursive(object *op) {
579  while (op->env != NULL)
580  op = op->env;
581  return op;
582 }
583 
595 object *object_get_player_container(object *op) {
596  for (; op != NULL && op->type != PLAYER; op = op->env)
597  /*TODO this is patching the structure on the flight as side effect. Shoudln't be needed in clean code */
598  if (op->env == op)
599  op->env = NULL;
600  return op;
601 }
602 
612 static const object *object_get_owner_const(const object *op) {
613  if (op->owner == NULL)
614  return NULL;
615 
616  if (!QUERY_FLAG(op->owner, FLAG_FREED)
617  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
618  && op->owner->count == op->ownercount)
619  return op->owner;
620 
621  LOG(llevError, "Warning, no owner found\n");
622  return NULL;
623 }
624 
633 void object_dump(const object *op, StringBuffer *sb) {
634  if (op == NULL) {
635  stringbuffer_append_string(sb, "[NULL pointer]");
636  return;
637  }
638 
639  /* object *tmp;*/
640 
641  if (op->arch != NULL) {
642  const object *owner;
643 
644  stringbuffer_append_string(sb, "arch ");
645  stringbuffer_append_string(sb, op->arch->name ? op->arch->name : "(null)");
646  stringbuffer_append_string(sb, "\n");
647 
648  if (op->artifact != NULL) {
649  stringbuffer_append_string(sb, "artifact ");
651  stringbuffer_append_string(sb, "\n");
652  }
653 
654  get_ob_diff(sb, op, &empty_archetype->clone);
655  if (op->more) {
656  stringbuffer_append_printf(sb, "more %u\n", op->more->count);
657  }
658  if (op->head) {
659  stringbuffer_append_printf(sb, "head %u\n", op->head->count);
660  }
661  if (op->env) {
662  stringbuffer_append_printf(sb, "env %u\n", op->env->count);
663  }
664  if (op->inv) {
665  stringbuffer_append_printf(sb, "inv %u\n", op->inv->count);
666  }
667  if (op->enemy) {
668  stringbuffer_append_printf(sb, "enemy %u\n", op->enemy->count);
669  }
670  if (op->attacked_by) {
671  stringbuffer_append_printf(sb, "attacked_by %u\n", op->attacked_by->count);
672  }
673  owner = object_get_owner_const(op);
674  if (owner != NULL) {
675  stringbuffer_append_printf(sb, "owner %u\n", owner->count);
676  }
677  stringbuffer_append_string(sb, "end\n");
678  } else {
679  stringbuffer_append_string(sb, "Object ");
680  stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
681  stringbuffer_append_string(sb, "\nend\n");
682  }
683 }
684 
692 void object_dump_all(void) {
693  object *op;
694 
695  for (op = objects; op != NULL; op = op->next) {
696  StringBuffer *sb;
697  char *diff;
698 
699  sb = stringbuffer_new();
700  object_dump(op, sb);
701  diff = stringbuffer_finish(sb);
702  LOG(llevDebug, "Object %u\n:%s\n", op->count, diff);
703  free(diff);
704  }
705 }
706 
716  if (i == OBJECT_INVALID) {
717  return nullptr;
718  }
719 
720  auto it = object_map.find(i);
721  if (it != object_map.end()) {
722  return it->second;
723  } else {
724  return nullptr;
725  }
726 }
727 
739 object *object_find_by_name_global(const char *str) {
740  const char *name = add_string(str);
741  object *op;
742 
743  for (op = objects; op != NULL; op = op->next)
744  if (op->name == name)
745  break;
746  free_string(name);
747  return op;
748 }
749 
760 #ifdef MEMORY_DEBUG
761  object *op, *next;
762 
763  for (op = free_objects; op != NULL; ) {
764  next = op->next;
765  free(op);
767  nroffreeobjects--;
768  op = next;
769  }
770  free_objects = NULL;
771 
772  for (op = objects; op != NULL; ) {
773  next = op->next;
774  if (!QUERY_FLAG(op, FLAG_FREED)) {
775  LOG(llevDebug, "non freed object: %s\n", op->name);
776  }
777  op = next;
778  }
779 #endif
780 
781  object_map.clear();
782 
783  LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX);
784 }
785 
798 object *object_get_owner(object *op) {
799  if (op->owner == NULL)
800  return NULL;
801 
802  if (!QUERY_FLAG(op->owner, FLAG_FREED)
803  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
804  && op->owner->count == op->ownercount)
805  return op->owner;
806 
807  object_clear_owner(op);
808  return NULL;
809 }
810 
817 void object_clear_owner(object *op) {
818  if (!op)
819  return;
820 
821  op->owner = NULL;
822  op->ownercount = 0;
823 }
824 
834 void object_set_owner(object *op, object *owner) {
835  /* Assign temp to something, so it can't accidentally be NULL */
836  object *tmp = owner;
837  if (op == NULL)
838  return;
839  if (owner == NULL) {
840  object_clear_owner(op);
841  return;
842  }
843 
844  /* next line added to allow objects which own objects */
845  /* Add a check for ownercounts in here, as I got into an endless loop
846  * with the fireball owning a poison cloud which then owned the
847  * fireball. I believe that was caused by one of the objects getting
848  * freed and then another object replacing it. Since the ownercounts
849  * didn't match, this check is valid and I believe that cause is valid.
850  */
851  /*
852  * if owner is NULL, function will have already returned,
853  * so loop should still function as before.
854  */
855  while (tmp) {
856  tmp = object_get_owner(owner);
857  if (tmp)
858  owner = tmp;
859  }
860 
861  /* must not cause owner cycles */
862  assert(op != owner);
863 
864  if (op->owner != NULL)
865  object_clear_owner(op);
866 
867  op->owner = owner;
868  op->ownercount = owner->count;
869 }
870 
887 void object_copy_owner(object *op, object *clone) {
888  object *owner = object_get_owner(clone);
889  if (owner == NULL) {
890  /* players don't have owners - they own themselves. Update
891  * as appropriate.
892  */
893  /*TODO owner=self is dangerous and should be avoided*/
894  if (clone->type != PLAYER)
895  return;
896  owner = clone;
897  }
898  object_set_owner(op, owner);
899 }
900 
909 void object_set_enemy(object *op, object *enemy) {
910  if (op->enemy == enemy) {
911  return;
912  }
913 
914 #if 0
915  if (op->type != PLAYER) {
916  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);
917  }
918 #endif
919  op->enemy = enemy;
920 }
921 
928 void object_reset(object *op) {
929  op->name = NULL;
930  op->name_pl = NULL;
931  op->title = NULL;
932  op->race = NULL;
933  op->slaying = NULL;
934  op->skill = NULL;
935  op->msg = NULL;
936  op->materialname = NULL;
937  op->lore = NULL;
938  object_clear(op);
939 }
940 
948 void object_free_key_values(object *op) {
949  key_value *i;
950  key_value *next = NULL;
951 
952  if (op->key_values == NULL)
953  return;
954 
955  for (i = op->key_values; i != NULL; i = next) {
956  /* Store next *first*. */
957  next = i->next;
958 
959  if (i->key)
961  if (i->value)
963  i->next = NULL;
964  free(i);
965  }
966 
967  op->key_values = NULL;
968 }
969 
977 void object_clear(object *op) {
978  /*TODO this comment must be investigated*/
979  /* redo this to be simpler/more efficient. Was also seeing
980  * crashes in the old code. Move this to the top - am
981  * seeing periodic crashes in this code, and would like to have
982  * as much info available as possible (eg, object name).
983  */
986 
987  /* the memset will clear all these values for us, but we need
988  * to reduce the refcount on them.
989  */
990  if (op->name != NULL)
992  if (op->name_pl != NULL)
994  if (op->title != NULL)
996  if (op->race != NULL)
998  if (op->slaying != NULL)
1000  if (op->skill != NULL)
1002  if (op->msg != NULL)
1003  FREE_AND_CLEAR_STR(op->msg);
1004  if (op->lore != NULL)
1005  FREE_AND_CLEAR_STR(op->lore);
1006  if (op->materialname != NULL)
1008 
1009  /* Remove object from friendly list if needed. */
1010  if (QUERY_FLAG(op, FLAG_FRIENDLY))
1012 
1013  memset((void *)((char *)op+offsetof(object, name)), 0, sizeof(object)-offsetof(object, name));
1014  /* Below here, we clear things that are not done by the memset,
1015  * or set default values that are not zero.
1016  */
1017  /* This is more or less true */
1018  SET_FLAG(op, FLAG_REMOVED);
1019 
1020 
1021  op->contr = NULL;
1022  op->below = NULL;
1023  op->above = NULL;
1024  op->inv = NULL;
1025  op->container = NULL;
1026  op->env = NULL;
1027  op->more = NULL;
1028  op->head = NULL;
1029  op->map = NULL;
1030  op->active_next = NULL;
1031  op->active_prev = NULL;
1032  /* What is not cleared is next, prev, and count */
1033 
1034  op->expmul = 1.0;
1035  op->face = blank_face;
1036  op->attacked_by_count = -1;
1037  if (settings.casting_time)
1038  op->casting_time = -1;
1039 }
1040 
1055 void object_copy_no_speed(const object *src_ob, object *dest_ob) {
1056  int is_freed = QUERY_FLAG(dest_ob, FLAG_FREED), is_removed = QUERY_FLAG(dest_ob, FLAG_REMOVED);
1057 
1058  /* Decrement the refcounts, but don't bother zeroing the fields;
1059  they'll be overwritten by memcpy. */
1060  if (dest_ob->artifact != NULL)
1061  free_string(dest_ob->artifact);
1062  if (dest_ob->name != NULL)
1063  free_string(dest_ob->name);
1064  if (dest_ob->name_pl != NULL)
1065  free_string(dest_ob->name_pl);
1066  if (dest_ob->anim_suffix != NULL)
1067  free_string(dest_ob->anim_suffix);
1068  if (dest_ob->title != NULL)
1069  free_string(dest_ob->title);
1070  if (dest_ob->race != NULL)
1071  free_string(dest_ob->race);
1072  if (dest_ob->slaying != NULL)
1073  free_string(dest_ob->slaying);
1074  if (dest_ob->skill != NULL)
1075  free_string(dest_ob->skill);
1076  if (dest_ob->msg != NULL)
1077  free_string(dest_ob->msg);
1078  if (dest_ob->lore != NULL)
1079  free_string(dest_ob->lore);
1080  if (dest_ob->materialname != NULL)
1081  free_string(dest_ob->materialname);
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->materialname != NULL)
1120  add_refcount(dest_ob->materialname);
1121 
1122  if (dest_ob->spell_tags != NULL) {
1123  dest_ob->spell_tags = static_cast<tag_t *>(malloc(sizeof(tag_t)*SPELL_TAG_SIZE));
1124  memcpy(dest_ob->spell_tags, src_ob->spell_tags, sizeof(tag_t)*SPELL_TAG_SIZE);
1125  }
1126 
1127  /* If archetype is a temporary one, we need to update reference count, because
1128  * that archetype will be freed by object_free_drop_inventory() when the last object is removed.
1129  */
1130  if (dest_ob->arch != NULL) {
1131  if (dest_ob->arch->reference_count > 0)
1132  dest_ob->arch->reference_count++;
1133  }
1134 
1135  if (src_ob->speed < 0)
1136  dest_ob->speed_left = src_ob->speed_left-RANDOM()%200/100.0;
1137 
1138  /* Copy over key_values, if any. */
1139  if (src_ob->key_values != NULL) {
1140  key_value *tail = NULL;
1141  key_value *i;
1142 
1143  dest_ob->key_values = NULL;
1144 
1145  for (i = src_ob->key_values; i != NULL; i = i->next) {
1146  key_value *new_link = static_cast<key_value *>(malloc(sizeof(key_value)));
1147 
1148  new_link->next = NULL;
1149  new_link->key = add_refcount(i->key);
1150  if (i->value)
1151  new_link->value = add_refcount(i->value);
1152  else
1153  new_link->value = NULL;
1154 
1155  /* Try and be clever here, too. */
1156  if (dest_ob->key_values == NULL) {
1157  dest_ob->key_values = new_link;
1158  tail = new_link;
1159  } else {
1160  tail->next = new_link;
1161  tail = new_link;
1162  }
1163  }
1164  }
1165 
1166  /* This way, dialog information will be parsed again when/if needed. */
1167  CLEAR_FLAG(dest_ob, FLAG_DIALOG_PARSED);
1168 
1169  dest_ob->event_bitmask = BITMASK_VALID; // Empty inventory so valid
1170 }
1171 
1186 void object_copy(const object *src_ob, object *dest_ob) {
1187  object_copy_no_speed(src_ob, dest_ob);
1188  object_update_speed(dest_ob);
1189 }
1190 
1202 void object_copy_with_inv(const object *src_ob, object *dest_ob, bool update_speed) {
1203  if (update_speed) {
1204  object_copy(src_ob, dest_ob);
1205  } else {
1206  object_copy_no_speed(src_ob, dest_ob);
1207  }
1208  FOR_INV_PREPARE(src_ob, walk) {
1209  object *tmp;
1210 
1211  tmp = object_new();
1212  object_copy_with_inv(walk, tmp, update_speed);
1213  object_insert_in_ob(tmp, dest_ob);
1214  } FOR_INV_FINISH();
1215 }
1216 
1217 #ifndef MEMORY_DEBUG
1218 
1225 static void expand_objects(void) {
1226  int i;
1227  object *add;
1228 
1229  add = (object *)CALLOC(OBJ_EXPAND, sizeof(object));
1230 
1231  if (add == NULL)
1233  free_objects = add;
1234  add[0].prev = NULL;
1235  add[0].next = &add[1],
1236  SET_FLAG(&add[0], FLAG_REMOVED);
1237  SET_FLAG(&add[0], FLAG_FREED);
1238 
1239  for (i = 1; i < OBJ_EXPAND-1; i++) {
1240  add[i].next = &add[i+1],
1241  add[i].prev = &add[i-1],
1242  SET_FLAG(&add[i], FLAG_REMOVED);
1243  SET_FLAG(&add[i], FLAG_FREED);
1244  }
1245  add[OBJ_EXPAND-1].prev = &add[OBJ_EXPAND-2],
1246  add[OBJ_EXPAND-1].next = NULL,
1247  SET_FLAG(&add[OBJ_EXPAND-1], FLAG_REMOVED);
1248  SET_FLAG(&add[OBJ_EXPAND-1], FLAG_FREED);
1249 
1252 }
1253 #endif
1254 
1267 object *object_new(void) {
1268  object *op;
1269 #ifdef MEMORY_DEBUG
1270  /* FIXME: However this doesn't work since object_free() sometimes add
1271  * objects back to the free_objects linked list, and some functions mess
1272  * with the object after return of object_free(). This is bad and should be
1273  * fixed. But it would need fairly extensive changes and a lot of debugging.
1274  */
1275  op = static_cast<object *>(calloc(1, sizeof(object)));
1276  if (op == NULL)
1278 #else
1279  if (free_objects == NULL) {
1280  expand_objects();
1281  }
1282  op = free_objects;
1283  if (!QUERY_FLAG(op, FLAG_FREED)) {
1284  LOG(llevError, "Fatal: Getting busy object.\n");
1285 #ifdef MANY_CORES
1286  abort();
1287 #endif
1288  }
1289  free_objects = op->next;
1290  if (free_objects != NULL)
1291  free_objects->prev = NULL;
1292  nroffreeobjects--;
1293 #endif
1294  op->count = ++ob_count;
1295  object_map[op->count] = op;
1296  op->name = NULL;
1297  op->name_pl = NULL;
1298  op->title = NULL;
1299  op->race = NULL;
1300  op->slaying = NULL;
1301  op->skill = NULL;
1302  op->lore = NULL;
1303  op->msg = NULL;
1304  op->materialname = NULL;
1305  op->next = objects;
1306  op->prev = NULL;
1307  op->active_next = NULL;
1308  op->active_prev = NULL;
1309  op->spell_tags = NULL;
1311  if (objects != NULL)
1312  objects->prev = op;
1313  objects = op;
1314  object_clear(op);
1315  SET_FLAG(op, FLAG_REMOVED);
1316  return op;
1317 }
1318 
1327 void object_update_turn_face(object *op) {
1328  if (op->animation == 0 || !QUERY_FLAG(op, FLAG_IS_TURNABLE))
1329  return;
1330  animate_object(op, op->direction);
1331 }
1332 
1344 void object_update_speed(object *op) {
1345 
1346  /* No reason putting the archetypes objects on the speed list,
1347  * since they never really need to be updated.
1348  */
1349 
1350  if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
1351  LOG(llevError, "Object %s is freed but has speed.\n", op->name);
1352 #ifdef MANY_CORES
1353  abort();
1354 #else
1355  op->speed = 0;
1356 #endif
1357  }
1358  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
1359  /* If already on active list, don't do anything */
1360  /* TODO this check can probably be simplified a lot */
1361  if (op->active_next || op->active_prev || op == active_objects)
1362  return;
1363 
1364  /* process_events() expects us to insert the object at the beginning
1365  * of the list. */
1367  if (op->active_next != NULL)
1368  op->active_next->active_prev = op;
1369  active_objects = op;
1370  } else {
1372  }
1373 }
1374 
1388  /* If not on the active list, nothing needs to be done */
1389  if (!op->active_next && !op->active_prev && op != active_objects)
1390  return;
1391 
1392  if (op->active_prev == NULL) {
1394  if (op->active_next != NULL)
1395  op->active_next->active_prev = NULL;
1396  } else {
1397  op->active_prev->active_next = op->active_next;
1398  if (op->active_next)
1399  op->active_next->active_prev = op->active_prev;
1400  }
1401  op->active_next = NULL;
1402  op->active_prev = NULL;
1403 }
1404 
1429 void object_update(object *op, int action) {
1430  int update_now = 0, flags;
1431  MoveType move_on, move_off, move_block, move_slow;
1432  object *pl;
1433 
1434  if (op == NULL) {
1435  /* this should never happen */
1436  LOG(llevDebug, "object_update() called for NULL object.\n");
1437  return;
1438  }
1439 
1440  if (op->env != NULL) {
1441  /* Animation is currently handled by client, so nothing
1442  * to do in this case.
1443  */
1444  return;
1445  }
1446 
1447  /* If the map is saving, don't do anything as everything is
1448  * going to get freed anyways.
1449  */
1450  if (!op->map || op->map->in_memory == MAP_SAVING)
1451  return;
1452 
1453  /* make sure the object is within map boundaries */
1454  if (op->x < 0 || op->x >= MAP_WIDTH(op->map)
1455  || op->y < 0 || op->y >= MAP_HEIGHT(op->map)) {
1456  LOG(llevError, "object_update() called for object out of map!\n");
1457 #ifdef MANY_CORES
1458  abort();
1459 #endif
1460  return;
1461  }
1462 
1463  flags = GET_MAP_FLAGS(op->map, op->x, op->y);
1464  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NEED_UPDATE);
1465  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
1466  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
1467  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
1468  move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y);
1469 
1470  if (action == UP_OBJ_INSERT) {
1472  update_now = 1;
1473 
1474  if (QUERY_FLAG(op, FLAG_NO_MAGIC) && !(flags&P_NO_MAGIC))
1475  update_now = 1;
1476 
1477  if (QUERY_FLAG(op, FLAG_DAMNED) && !(flags&P_NO_CLERIC))
1478  update_now = 1;
1479 
1480  if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags&P_IS_ALIVE))
1481  update_now = 1;
1482 
1483  if ((move_on|op->move_on) != move_on)
1484  update_now = 1;
1485  if ((move_off|op->move_off) != move_off)
1486  update_now = 1;
1487  /* This isn't perfect, but I don't expect a lot of objects to
1488  * to have move_allow right now.
1489  */
1490  if (((move_block|op->move_block)&~op->move_allow) != move_block)
1491  update_now = 1;
1492  if ((move_slow|op->move_slow) != move_slow)
1493  update_now = 1;
1494 
1495  if (op->type == PLAYER)
1496  update_now = 1;
1497  /* if the object is being removed, we can't make intelligent
1498  * decisions, because object_remove() can't really pass the object
1499  * that is being removed.
1500  */
1501  } else if (action == UP_OBJ_REMOVE) {
1502  update_now = 1;
1503  } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) {
1504  /* In addition to sending info to client, need to update space
1505  * information.
1506  */
1507  if (action == UP_OBJ_CHANGE)
1508  update_now = 1;
1509 
1510  /* There is a player on this space - we may need to send an
1511  * update to the client.
1512  * If this object is supposed to be animated by the client,
1513  * nothing to do here - let the client animate it.
1514  * We can't use FLAG_ANIMATE, as that is basically set for
1515  * all objects with multiple faces, regardless if they are animated.
1516  * (levers have it set for example).
1517  */
1518  if (flags&P_PLAYER
1521  pl = GET_MAP_PLAYER(op->map, op->x, op->y);
1522 
1523  /* If update_look is set, we're going to send this entire space
1524  * to the client, so no reason to send face information now.
1525  */
1526  if (!pl->contr->socket->update_look) {
1527  esrv_update_item(UPD_FACE, pl, op);
1528  }
1529  }
1530  } else {
1531  LOG(llevError, "object_update called with invalid action: %d\n", action);
1532  }
1533 
1534  if (update_now) {
1535  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NO_ERROR|P_NEED_UPDATE);
1536  update_position(op->map, op->x, op->y);
1537  }
1538 
1539  if (op->more != NULL)
1540  object_update(op->more, action);
1541 }
1542 
1555 void object_free_drop_inventory(object *ob) {
1556  object_free(ob, 0);
1557 }
1558 
1563 void object_free_inventory(object *ob) {
1564  while (ob->inv) {
1565  object *inv = ob->inv;
1566  object_remove(inv);
1568  }
1569 }
1570 
1587 void object_free(object *ob, int flags) {
1588  if (!QUERY_FLAG(ob, FLAG_REMOVED)) {
1589  StringBuffer *sb;
1590  char *diff;
1591 
1592  LOG(llevError, "Free object called with non removed object\n");
1593  sb = stringbuffer_new();
1594  object_dump(ob, sb);
1595  diff = stringbuffer_finish(sb);
1596  LOG(llevError, "%s", diff);
1597  free(diff);
1598 #ifdef MANY_CORES
1599  abort();
1600 #endif
1601  }
1602  if (QUERY_FLAG(ob, FLAG_FRIENDLY)) {
1603  LOG(llevMonster, "Warning: tried to free friendly object.\n");
1605  }
1606  if (QUERY_FLAG(ob, FLAG_FREED)) {
1607  StringBuffer *sb;
1608  char *diff;
1609 
1610  sb = stringbuffer_new();
1611  object_dump(ob, sb);
1612  diff = stringbuffer_finish(sb);
1613  LOG(llevError, "Trying to free freed object.\n%s\n", diff);
1614  free(diff);
1615  return;
1616  }
1617 
1618  if ((flags & FREE_OBJ_NO_DESTROY_CALLBACK) == 0) {
1620  }
1621 
1622  if (ob->inv) {
1623  /* Only if the space blocks everything do we not process -
1624  * if some form of movemnt is allowed, let objects
1625  * drop on that space.
1626  */
1627  if ((flags & FREE_OBJ_FREE_INVENTORY) != 0
1628  || ob->map == NULL
1629  || ob->map->in_memory != MAP_IN_MEMORY
1630  || (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL)) {
1631  FOR_INV_PREPARE(ob, op) {
1632  object_remove(op);
1633  object_free(op, flags);
1634  } FOR_INV_FINISH();
1635  } else { /* Put objects in inventory onto this space */
1636  FOR_INV_PREPARE(ob, op) {
1637  object_remove(op);
1638  /* No drop means no drop, including its inventory */
1639  if (QUERY_FLAG(op, FLAG_NO_DROP))
1641  else if (QUERY_FLAG(op, FLAG_STARTEQUIP)
1642  || QUERY_FLAG(op, FLAG_NO_DROP)
1643  || op->type == RUNE
1644  || op->type == TRAP
1647  else {
1648  object *part;
1649 
1650  /* If it's a multi-tile object, scatter dropped items randomly */
1651  if (ob->more) {
1652  int partcount = 0;
1653  /* Get the number of non-head parts */
1654  for (part = ob; part; part = part->more) {
1655  partcount++;
1656  }
1657  /* Select a random part */
1658  partcount = RANDOM()%partcount;
1659  for (part = ob; partcount > 0; partcount--) {
1660  part = part->more;
1661  }
1662  } else {
1663  part = ob;
1664  }
1665 
1666  if (QUERY_FLAG(op, FLAG_ALIVE)) {
1667  object_insert_to_free_spot_or_free(op, part->map, part->x, part->y, 0, SIZEOFFREE, NULL);
1668  } else {
1669  int f = 0;
1672  object_insert_in_map_at(op, part->map, NULL, f, part->x, part->y); /* Insert in same map as the envir */
1673  }
1674  }
1675  } FOR_INV_FINISH();
1676  }
1677  }
1678 
1679  if (ob->more != NULL) {
1680  object_free(ob->more, flags);
1681  ob->more = NULL;
1682  }
1683 
1684  /* Remove object from the active list */
1685  ob->speed = 0;
1686  object_update_speed(ob);
1687 
1688  SET_FLAG(ob, FLAG_FREED);
1689  object_map.erase(ob->count);
1690  ob->count = 0;
1691 
1692  /* Remove this object from the list of used objects */
1693  if (ob->prev == NULL) {
1694  objects = ob->next;
1695  if (objects != NULL)
1696  objects->prev = NULL;
1697  } else {
1698  ob->prev->next = ob->next;
1699  if (ob->next != NULL)
1700  ob->next->prev = ob->prev;
1701  }
1702 
1703  if (ob->artifact != NULL) FREE_AND_CLEAR_STR(ob->artifact);
1704  if (ob->name != NULL) FREE_AND_CLEAR_STR(ob->name);
1705  if (ob->name_pl != NULL) FREE_AND_CLEAR_STR(ob->name_pl);
1706  if (ob->title != NULL) FREE_AND_CLEAR_STR(ob->title);
1707  if (ob->race != NULL) FREE_AND_CLEAR_STR(ob->race);
1708  if (ob->slaying != NULL) FREE_AND_CLEAR_STR(ob->slaying);
1709  if (ob->skill != NULL) FREE_AND_CLEAR_STR(ob->skill);
1710  if (ob->lore != NULL) FREE_AND_CLEAR_STR(ob->lore);
1711  if (ob->msg != NULL) FREE_AND_CLEAR_STR(ob->msg);
1712  if (ob->materialname != NULL) FREE_AND_CLEAR_STR(ob->materialname);
1713  if (ob->spell_tags) FREE_AND_CLEAR(ob->spell_tags);
1715 
1716  /* Why aren't events freed? */
1718 
1720 
1721  /* Test whether archetype is a temporary one, and if so look whether it should be trashed. */
1722  if (ob->arch && ob->arch->reference_count > 0) {
1723  if (--ob->arch->reference_count == 0) {
1724  free_arch(ob->arch);
1725  }
1726  }
1727 
1728 #ifdef MEMORY_DEBUG
1729  free(ob);
1730 #else
1731  /* Now link it with the free_objects list: */
1732  ob->prev = NULL;
1733  ob->next = free_objects;
1734  if (free_objects != NULL)
1735  free_objects->prev = ob;
1736  free_objects = ob;
1737  nroffreeobjects++;
1738 #endif
1739 }
1740 
1748  int i = 0;
1749  object *tmp = free_objects;
1750 
1751  while (tmp != NULL)
1752  tmp = tmp->next,
1753  i++;
1754  return i;
1755 }
1756 
1764  int i = 0;
1765  object *tmp = objects;
1766 
1767  while (tmp != NULL)
1768  tmp = tmp->next,
1769  i++;
1770  return i;
1771 }
1772 
1780  int i = 0;
1781  object *tmp = active_objects;
1782 
1783  while (tmp != NULL)
1784  tmp = tmp->active_next,
1785  i++;
1786  return i;
1787 }
1788 
1803 void object_sub_weight(object *op, signed long weight) {
1804  while (op != NULL) {
1805  if (op->type == CONTAINER) {
1806  weight = (signed long)(weight*(100-op->stats.Str)/100);
1807  }
1808  op->carrying -= weight;
1809  op = op->env;
1810  }
1811 }
1812 
1829 void object_remove(object *op) {
1830  object *last = NULL;
1831  object *otmp;
1832  tag_t tag;
1833  int check_walk_off;
1834  mapstruct *m;
1835  int16_t x, y;
1836 
1837  if (QUERY_FLAG(op, FLAG_REMOVED)) {
1838  StringBuffer *sb;
1839  char *diff;
1840 
1841  sb = stringbuffer_new();
1842  object_dump(op, sb);
1843  diff = stringbuffer_finish(sb);
1844  LOG(llevError, "Trying to remove removed object.\n%s\n", diff);
1845  free(diff);
1846  abort();
1847  }
1848  if (op->more != NULL)
1849  object_remove(op->more);
1850 
1851  SET_FLAG(op, FLAG_REMOVED);
1852 
1853  /*
1854  * In this case, the object to be removed is in someones
1855  * inventory.
1856  */
1857  /* TODO try to call a generic inventory weight adjusting function like object_sub_weight */
1858  if (op->env != NULL) {
1859  player *pl = NULL;
1860 
1861  if (op->nrof)
1862  object_sub_weight(op->env, op->weight*op->nrof);
1863  else
1864  object_sub_weight(op->env, op->weight+op->carrying);
1865 
1866  /* Update in two cases: item is in a player, or in a container the player is looking into. */
1867  if (op->env->contr != NULL && op->head == NULL) {
1868  pl = op->env->contr;
1869  } else if (op->env->type == CONTAINER && QUERY_FLAG(op->env, FLAG_APPLIED)) {
1870 
1871  if (op->env->env && op->env->env->contr)
1872  /* Container is in player's inventory. */
1873  pl = op->env->env->contr;
1874  else if (op->env->map) {
1875  /* Container on map, look above for player. */
1876  object *above = op->env->above;
1877 
1878  while (above && !above->contr)
1879  above = above->above;
1880  if (above)
1881  pl = above->contr;
1882  }
1883  }
1884 
1885  /* NO_FIX_PLAYER is set when a great many changes are being
1886  * made to players inventory. If set, avoiding the call
1887  * to save cpu time.
1888  */
1889  otmp = object_get_player_container(op->env);
1890  if (otmp != NULL
1891  && otmp->contr
1892  && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
1893  fix_object(otmp);
1894 
1895  if (op->above != NULL)
1896  op->above->below = op->below;
1897  else
1898  op->env->inv = op->below;
1899 
1900  if (op->below != NULL)
1901  op->below->above = op->above;
1902 
1903  if (op->type == EVENT_CONNECTOR) {
1904  op->env->event_bitmask = 0; // Will be recomputed if needed
1905  }
1906 
1907  /* we set up values so that it could be inserted into
1908  * the map, but we don't actually do that - it is up
1909  * to the caller to decide what we want to do.
1910  */
1911  op->x = op->env->x;
1912  op->y = op->env->y;
1913  op->ox = op->x;
1914  op->oy = op->y;
1915  op->map = op->env->map;
1916  op->above = NULL;
1917  op->below = NULL;
1918  /* send the delitem before resetting env, so container's contents be may
1919  * refreshed */
1920  if (LOOK_OBJ(op) && pl != NULL)
1921  esrv_del_item(pl, op);
1922  op->env = NULL;
1923  return;
1924  }
1925 
1926  /* If we get here, we are removing it from a map */
1927  if (op->map == NULL)
1928  return;
1929 
1930  if (op->contr != NULL && !op->contr->hidden)
1931  op->map->players--;
1932 
1933  x = op->x;
1934  y = op->y;
1935  m = get_map_from_coord(op->map, &x, &y);
1936 
1937  if (!m) {
1938  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);
1939  abort();
1940  }
1941  if (op->map != m) {
1942  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);
1943  }
1944 
1945  /* link the object above us */
1946  if (op->above)
1947  op->above->below = op->below;
1948  else
1949  SET_MAP_TOP(m, x, y, op->below); /* we were top, set new top */
1950 
1951  /* Relink the object below us, if there is one */
1952  if (op->below) {
1953  op->below->above = op->above;
1954  } else {
1955  /* Nothing below, which means we need to relink map object for this space
1956  * use translated coordinates in case some oddness with map tiling is
1957  * evident
1958  */
1959  /*TODO is this check really needed?*/
1960  if (GET_MAP_OB(m, x, y) != op) {
1961  StringBuffer *sb;
1962  char *diff;
1963 
1964  sb = stringbuffer_new();
1965  object_dump(op, sb);
1966  diff = stringbuffer_finish(sb);
1967  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);
1968  free(diff);
1969 
1970  sb = stringbuffer_new();
1971  object_dump(GET_MAP_OB(m, x, y), sb);
1972  diff = stringbuffer_finish(sb);
1973  LOG(llevError, "%s\n", diff);
1974  free(diff);
1975  }
1976  SET_MAP_OB(m, x, y, op->above); /* goes on above it. */
1977  }
1978  op->above = NULL;
1979  op->below = NULL;
1980 
1981  if (op->map->in_memory == MAP_SAVING)
1982  return;
1983 
1984  tag = op->count;
1985  check_walk_off = !QUERY_FLAG(op, FLAG_NO_APPLY);
1986  FOR_MAP_PREPARE(m, x, y, tmp) {
1987  /* No point updating the players look faces if he is the object
1988  * being removed.
1989  */
1990 
1991  if (tmp->type == PLAYER && tmp != op) {
1992  /* If a container that the player is currently using somehow gets
1993  * removed (most likely destroyed), update the player view
1994  * appropriately.
1995  */
1996  if (tmp->container == op) {
1997  CLEAR_FLAG(op, FLAG_APPLIED);
1998  tmp->container = NULL;
1999  // Notify the client the container is gone so it clears its active container.
2000  esrv_update_item(UPD_FLAGS, tmp, op);
2001  }
2002  tmp->contr->socket->update_look = 1;
2003  }
2004  /* See if player moving off should effect something */
2005  if (check_walk_off
2006  && ((op->move_type&tmp->move_off) && (op->move_type&~tmp->move_off&~tmp->move_block) == 0)) {
2007  ob_move_on(tmp, op, NULL);
2008  if (object_was_destroyed(op, tag)) {
2009  LOG(llevError, "BUG: object_remove(): name %s, archname %s destroyed leaving object\n", tmp->name, tmp->arch->name);
2010  }
2011  }
2012 
2013  /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
2014  if (tmp->above == tmp)
2015  tmp->above = NULL;
2016  last = tmp;
2017  } FOR_MAP_FINISH();
2018  /* last == NULL or there are no objects on this space */
2019  if (last == NULL) {
2020  /* set P_NEED_UPDATE, otherwise update_position will complain. In theory,
2021  * we could preserve the flags (GET_MAP_FLAGS), but update_position figures
2022  * those out anyways, and if there are any flags set right now, they won't
2023  * be correct anyways.
2024  */
2025  SET_MAP_FLAGS(op->map, op->x, op->y, P_NEED_UPDATE);
2026  update_position(op->map, op->x, op->y);
2027  } else
2029 
2030  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) || (op->glow_radius != 0))
2031  update_all_los(op->map, op->x, op->y);
2032 }
2033 
2047 object *object_merge(object *op, object *top) {
2048  if (!op->nrof)
2049  return NULL;
2050 
2051  if (top == NULL)
2052  for (top = op; top != NULL && top->above != NULL; top = top->above)
2053  ;
2055  if (top == op)
2056  continue;
2057  if (object_can_merge(op, top)) {
2058  object_increase_nrof(top, op->nrof);
2059  /*
2060  * Previous behavior set weight to zero here.
2061  * This, however, caused the object_sub_weight
2062  * call in object_remove to subtract zero weight
2063  * when removing the object. Thus, until inventory
2064  * weight is next recalculated, the object merged
2065  * into another pile added weight in object_increase_nrof
2066  * but did not remove the weight from the original
2067  * instance of itself in object_remove, essentially
2068  * counting for double weight for several minutes.
2069  *
2070  * SilverNexus 2014-05-27
2071  */
2072  object_remove(op);
2074  return top;
2075  }
2077  return NULL;
2078 }
2079 
2096 object *object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y) {
2097  object *tmp;
2098 
2099  op = HEAD(op);
2100  for (tmp = op; tmp; tmp = tmp->more) {
2101  tmp->x = x+tmp->arch->clone.x;
2102  tmp->y = y+tmp->arch->clone.y;
2103  tmp->map = m;
2104  }
2105  return object_insert_in_map(op, m, originator, flag);
2106 }
2107 
2125 void object_merge_spell(object *op, int16_t x, int16_t y) {
2126  int i;
2127 
2128  /* We try to do some merging of spell objects - if something has same owner,
2129  * is same type of spell, and going in the same direction, it is somewhat
2130  * mergable.
2131  *
2132  * If the spell object has an other_arch, don't merge - when the spell
2133  * does something, like explodes, it will use this other_arch, and
2134  * if we merge, there is no easy way to make the correct values be
2135  * set on this new object (values should be doubled, tripled, etc.)
2136  *
2137  * We also care about speed - only process objects that will not be
2138  * active this tick. Without this, the results are incorrect - think
2139  * of a case where tmp would normally get processed this tick, but
2140  * get merges with op, which does not get processed.
2141  */
2142  FOR_MAP_PREPARE(op->map, x, y, tmp) {
2143  if (op->type == tmp->type
2144  && op->subtype == tmp->subtype
2145  && op->direction == tmp->direction
2146  && op->owner == tmp->owner && op->ownercount == tmp->ownercount
2147  && op->range == tmp->range
2148  && op->stats.wc == tmp->stats.wc
2149  && op->level == tmp->level
2150  && op->attacktype == tmp->attacktype
2151  && op->speed == tmp->speed
2152  && !tmp->other_arch
2153  && (tmp->speed_left+tmp->speed) < 0.0
2154  && op != tmp) {
2155  /* Quick test - if one or the other objects already have hash tables
2156  * set up, and that hash bucket contains a value that doesn't
2157  * match what we want to set it up, we won't be able to merge.
2158  * Note that these two if statements are the same, except
2159  * for which object they are checking against. They could
2160  * be merged, but the line wrapping would be large enough
2161  * that IMO it would become difficult to read the different clauses
2162  * so its cleaner just to do 2 statements - MSW
2163  */
2164  if (op->spell_tags
2165  && !OB_SPELL_TAG_MATCH(op, (tag_t)tmp->stats.maxhp)
2166  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0)
2167  continue;
2168 
2169  if (tmp->spell_tags
2170  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)op->stats.maxhp)
2171  && OB_SPELL_TAG_HASH(tmp, op->stats.maxhp) != 0)
2172  continue;
2173 
2174  /* If we merge, the data from tmp->spell_tags gets copied into op.
2175  * so we need to make sure that slot isn't filled up.
2176  */
2177  if (tmp->spell_tags
2178  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)tmp->stats.maxhp)
2179  && OB_SPELL_TAG_HASH(tmp, tmp->stats.maxhp) != 0)
2180  continue;
2181 
2182  /* If both objects have spell_tags, we need to see if there are conflicting
2183  * values - if there are, we won't be able to merge then.
2184  */
2185  if (tmp->spell_tags && op->spell_tags) {
2186  int need_copy = 0;
2187 
2188  for (i = 0; i < SPELL_TAG_SIZE; i++) {
2189  /* If the two tag values in the hash are set, but are
2190  * not set to the same value, then these objects
2191  * can not be merged.
2192  */
2193  if (op->spell_tags[i] && tmp->spell_tags[i]
2194  && op->spell_tags[i] != tmp->spell_tags[i]) {
2196  break;
2197  }
2198  /* If one tag is set and the other is not, that is
2199  * fine, but we have to note that we need to copy
2200  * the data in that case.
2201  */
2202  if ((!op->spell_tags[i] && tmp->spell_tags[i])
2203  || (op->spell_tags[i] && !tmp->spell_tags[i])) {
2204  need_copy = 1;
2205  }
2206  }
2207  /* If we did not get through entire array, it means
2208  * we got a conflicting hash, and so we won't be
2209  * able to merge these - just continue processing
2210  * object on this space.
2211  */
2212  if (i <= SPELL_TAG_SIZE)
2213  continue;
2214 
2215  /* Ok - everything checked out - we should be able to
2216  * merge tmp in op. So lets copy the tag data if
2217  * needed. Note that this is a selective copy, as
2218  * we don't want to clear values that may be set in op.
2219  */
2220  if (need_copy) {
2221  for (i = 0; i < SPELL_TAG_SIZE; i++)
2222  if (!op->spell_tags[i]
2223  && tmp->spell_tags[i]
2224  && tmp->spell_tags[i] != (tag_t)op->stats.maxhp)
2225  op->spell_tags[i] = tmp->spell_tags[i];
2226  }
2227  FREE_AND_CLEAR(tmp->spell_tags);
2228  }
2229 
2230  /* if tmp has a spell_tags table, copy it to op and free tmps */
2231  if (tmp->spell_tags && !op->spell_tags) {
2232  op->spell_tags = tmp->spell_tags;
2233  tmp->spell_tags = NULL;
2234 
2235  /* We don't need to keep a copy of our maxhp value
2236  * in the copied over value
2237  */
2238  if (OB_SPELL_TAG_MATCH(op, (tag_t)op->stats.maxhp))
2239  OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0;
2240  }
2241 
2242  /* For spells to work correctly, we need to record what spell
2243  * tags we've merged in with this effect. This is used
2244  * in ok_to_put_more() to see if a spell effect is already on
2245  * the space.
2246  */
2247  if (op->stats.maxhp != tmp->stats.maxhp) {
2248 #ifdef OBJECT_DEBUG
2249  /* This if statement should never happen - the logic above should
2250  * have prevented it. It is a problem, because by now its possible
2251  * we've destroyed the spell_tags in tmp, so we can't really
2252  * just bail out.
2253  */
2254 
2255  if (op->spell_tags
2256  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0
2257  && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)) {
2258  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);
2259  }
2260 #endif
2261  if (!op->spell_tags)
2262  op->spell_tags = static_cast<tag_t *>(calloc(SPELL_TAG_SIZE, sizeof(tag_t)));
2263 
2264  OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) = tmp->stats.maxhp;
2265  }
2266 
2268  op->speed_left = MAX(op->speed_left, tmp->speed_left);
2269 
2270  if (tmp->duration != op->duration) {
2271  /* We need to use tmp_dam here because otherwise the
2272  * calculations can overflow the size of stats.dam.
2273  */
2274  int tmp_dam = tmp->stats.dam*(tmp->duration+1)+
2275  op->stats.dam*(op->duration+1);
2276 
2277  op->duration = MAX(op->duration, tmp->duration);
2278  tmp_dam /= op->duration+1;
2279  op->stats.dam = tmp_dam+1;
2280  } else {
2281  /* in this case, duration is the same, so simply adding
2282  * up damage works.
2283  */
2284  op->stats.dam += tmp->stats.dam;
2285  }
2286 
2287  object_remove(tmp);
2289  }
2290  } FOR_MAP_FINISH();
2291 }
2292 
2293 static object *find_insert_pos(object *op, const int flag) {
2294  object *floor = NULL;
2295  /*
2296  * If there are multiple objects on this space, we do some trickier handling.
2297  * We've already dealt with merging if appropriate.
2298  * Generally, we want to put the new object on top. But if
2299  * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
2300  * floor, we want to insert above that and no further.
2301  * Also, if there are spell objects on this space, we stop processing
2302  * once we get to them. This reduces the need to traverse over all of
2303  * them when adding another one - this saves quite a bit of cpu time
2304  * when lots of spells are cast in one area. Currently, it is presumed
2305  * that flying non pickable objects are spell objects.
2306  */
2307  if (flag&INS_ON_TOP) {
2308  return GET_MAP_TOP(op->map, op->x, op->y);
2309  }
2310  object *last = NULL;
2311  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2312  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)
2313  || QUERY_FLAG(tmp, FLAG_OVERLAY_FLOOR))
2314  floor = tmp;
2315 
2316  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
2317  && (tmp->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH))
2318  && !QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2319  /* We insert above tmp, so we want this object below this */
2320  break;
2321  }
2322  last = tmp;
2323  } FOR_MAP_FINISH();
2324  if (flag&INS_ABOVE_FLOOR_ONLY)
2325  return floor;
2326  return last;
2327 }
2328 
2357 object *object_insert_in_map(object *op, mapstruct *m, object *originator, int flag) {
2358  object *tmp, *top, *floor = NULL;
2359  int16_t x, y;
2360 
2361  if (QUERY_FLAG(op, FLAG_FREED)) {
2362  LOG(llevError, "Trying to insert freed object!\n");
2363  return NULL;
2364  }
2365  if (m == NULL) {
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 in null-map!\n%s\n", diff);
2373  free(diff);
2374  return op;
2375  }
2376  if (out_of_map(m, op->x, op->y)) {
2377  StringBuffer *sb;
2378  char *diff;
2379 
2380  sb = stringbuffer_new();
2381  object_dump(op, sb);
2382  diff = stringbuffer_finish(sb);
2383  LOG(llevError, "Trying to insert object outside the map.\n%s\n", diff);
2384  free(diff);
2385 #ifdef MANY_CORES
2386  /* Better to catch this here, as otherwise the next use of this object
2387  * is likely to cause a crash. Better to find out where it is getting
2388  * improperly inserted.
2389  */
2390  abort();
2391 #endif
2392  return op;
2393  }
2394  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2395  StringBuffer *sb;
2396  char *diff;
2397 
2398  sb = stringbuffer_new();
2399  object_dump(op, sb);
2400  diff = stringbuffer_finish(sb);
2401  LOG(llevError, "Trying to insert (map) inserted object.\n%s\n", diff);
2402  free(diff);
2403  return op;
2404  }
2405  if (op->more != NULL) {
2406  /* The part may be on a different map. */
2407 
2408  object *more = op->more;
2409 
2410  /* We really need the caller to normalize coordinates - if
2411  * we set the map, that doesn't work if the location is within
2412  * a map and this is straddling an edge. So only if coordinate
2413  * is clear wrong do we normalize it.
2414  */
2415  if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
2416  /* Debugging information so you can see the last coordinates this object had */
2417  more->ox = more->x;
2418  more->oy = more->y;
2419  more->map = get_map_from_coord(more->map, &more->x, &more->y);
2420  } else if (!more->map) {
2421  /* For backwards compatibility - when not dealing with tiled maps,
2422  * more->map should always point to the parent.
2423  */
2424  more->map = m;
2425  }
2426 
2427  if (object_insert_in_map(more, more->map, originator, flag) == NULL) {
2428  if (!op->head)
2429  LOG(llevError, "BUG: object_insert_in_map(): inserting op->more killed op\n");
2430  return NULL;
2431  }
2432  }
2433  CLEAR_FLAG(op, FLAG_REMOVED);
2434 
2435  /* Debugging information so you can see the last coordinates this object had */
2436  op->ox = op->x;
2437  op->oy = op->y;
2438  x = op->x;
2439  y = op->y;
2440  op->map = get_map_from_coord(m, &x, &y);
2441  if (op->map == NULL) {
2442  // This can fail despite out_of_map() returning false.
2443  return op;
2444  }
2445 
2446  /* this has to be done after we translate the coordinates. */
2447  if (op->nrof
2448  && !(flag&INS_NO_MERGE)
2449  && op->type != SPELL_EFFECT) {
2450  FOR_MAP_PREPARE(op->map, x, y, spot) {
2451  if (object_can_merge(op, spot)) {
2452  op->nrof += spot->nrof;
2453  object_remove(spot);
2455  }
2456  } FOR_MAP_FINISH();
2457  } else if (op->type == SPELL_EFFECT
2458  && !op->range
2459  && !op->other_arch
2460  && (op->speed_left+op->speed) < 0.0) {
2461  object_merge_spell(op, x, y);
2462  }
2463 
2464  /* Ideally, the caller figures this out. However, it complicates a lot
2465  * of areas of callers (eg, anything that uses object_find_free_spot() would now
2466  * need extra work
2467  */
2468  if (op->map != m) {
2469  /* coordinates should not change unless map also changes */
2470  op->x = x;
2471  op->y = y;
2472  }
2473 
2474  if (op->type != LAMP)
2475  /* lamps use the FLAG_APPLIED to keep the light/unlit status, so don't reset it.
2476  Other objects just get unapplied, since the container "drops" them. */
2477  CLEAR_FLAG(op, FLAG_APPLIED);
2479  if (!QUERY_FLAG(op, FLAG_ALIVE))
2481 
2482  /* In many places, a player is passed as the originator, which
2483  * is fine. However, if the player is on a transport, they are not
2484  * actually on the map, so we can't use them for the linked pointers,
2485  * nor should the walk on function below use them either.
2486  */
2487  if (originator && originator->contr && originator->contr->transport)
2488  originator = originator->contr->transport;
2489 
2490  if (flag&INS_BELOW_ORIGINATOR && originator != NULL) {
2491  if (originator->map != op->map
2492  || originator->x != op->x
2493  || originator->y != op->y) {
2494  LOG(llevError, "object_insert_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
2495  abort();
2496  }
2497  op->above = originator;
2498  op->below = originator->below;
2499  if (op->below)
2500  op->below->above = op;
2501  else
2502  SET_MAP_OB(op->map, op->x, op->y, op);
2503  /* since *below *originator, no need to update top */
2504  originator->below = op;
2505  } else {
2506  /* Top is the object that our object (op) is going to get inserted above. */
2507  top = find_insert_pos(op, flag);
2508 
2509  /* First object on this space */
2510  if (!top) {
2511  op->above = GET_MAP_OB(op->map, op->x, op->y);
2512  if (op->above)
2513  op->above->below = op;
2514  op->below = NULL;
2515  SET_MAP_OB(op->map, op->x, op->y, op);
2516  } else { /* get inserted into the stack above top */
2517  op->above = top->above;
2518  if (op->above)
2519  op->above->below = op;
2520  op->below = top;
2521  top->above = op;
2522  }
2523  if (op->above == NULL)
2524  SET_MAP_TOP(op->map, op->x, op->y, op);
2525  } /* else not INS_BELOW_ORIGINATOR */
2526 
2527  if (!(flag&INS_MAP_LOAD)) {
2528  if (op->type == PLAYER)
2529  op->contr->do_los = 1;
2530 
2531  /* If we have a floor, we know the player, if any, will be above
2532  * it, so save a few ticks and start from there.
2533  */
2534  tmp = floor ? floor : GET_MAP_OB(op->map, op->x, op->y);
2536  if (tmp->type == PLAYER)
2537  tmp->contr->socket->update_look = 1;
2539 
2540  /* If this object glows, it may affect lighting conditions that are
2541  * visible to others on this map. But update_all_los is really
2542  * an inefficient way to do this, as it means los for all players
2543  * on the map will get recalculated. The players could very well
2544  * be far away from this change and not affected in any way -
2545  * this should get redone to only look for players within range,
2546  * or just updating the P_NEED_UPDATE for spaces within this area
2547  * of effect may be sufficient.
2548  */
2549  if (MAP_DARKNESS(op->map) && (op->glow_radius != 0))
2550  update_all_los(op->map, op->x, op->y);
2551 
2552  if (op->contr && !op->contr->hidden)
2553  op->map->players++;
2554  }
2555 
2556  /* updates flags (blocked, alive, no magic, etc) for this map space */
2558 
2559  /* Don't know if moving this to the end will break anything. However,
2560  * we want to have update_look set above before calling this.
2561  *
2562  * object_check_move_on() must be after this because code called from
2563  * object_check_move_on() depends on correct map flags (so functions like
2564  * blocked() and wall() work properly), and these flags are updated by
2565  * object_update().
2566  */
2567 
2568  /* if this is not the head or flag has been passed, don't check walk on status */
2569 
2570  if (!(flag&INS_NO_WALK_ON) && !op->head) {
2571  if (object_check_move_on(op, originator))
2572  return NULL;
2573 
2574  /* If we are a multi part object, lets work our way through the check
2575  * walk on's.
2576  */
2577  for (tmp = op->more; tmp != NULL; tmp = tmp->more)
2578  if (object_check_move_on(tmp, originator))
2579  return NULL;
2580  }
2581  return op;
2582 }
2583 
2593 void object_replace_insert_in_map(const char *arch_string, object *op) {
2594  object *tmp1;
2595  archetype *at;
2596 
2597  /* first search for itself and remove any old instances */
2598  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2599  if (!strcmp(tmp->arch->name, arch_string)) { /* same archetype */
2600  object_remove(tmp);
2602  }
2603  } FOR_MAP_FINISH();
2604 
2605  at = find_archetype(arch_string);
2606  if (at == NULL) {
2607  return;
2608  }
2609  tmp1 = arch_to_object(at);
2610  object_insert_in_map_at(tmp1, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
2611 }
2612 
2633 object *object_split(object *orig_ob, uint32_t nr, char *err, size_t size) {
2634  object *newob;
2635 
2636  if (MAX(1, orig_ob->nrof) < nr) {
2637  /* If err is set, the caller knows that nr can be wrong (player trying to drop items), thus don't log that. */
2638  if (err)
2639  snprintf(err, size, "There are only %u %ss.", NROF(orig_ob), orig_ob->name);
2640  else
2641  LOG(llevDebug, "There are only %u %ss.\n", NROF(orig_ob), orig_ob->name);
2642  return NULL;
2643  }
2644  newob = object_create_clone(orig_ob);
2645  if (orig_ob->nrof == 0) {
2646  if (!QUERY_FLAG(orig_ob, FLAG_REMOVED)) {
2647  object_remove(orig_ob);
2648  }
2650  } else {
2651  newob->nrof = nr;
2652  object_decrease_nrof(orig_ob, nr);
2653  }
2654 
2655  return newob;
2656 }
2657 
2672 object *object_decrease_nrof(object *op, uint32_t i) {
2673  object *tmp;
2674 
2675  if (i == 0) /* objects with op->nrof require this check */
2676  return op;
2677 
2678  if (i > op->nrof)
2679  i = op->nrof;
2680 
2681  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2682  op->nrof -= i;
2683  } else if (op->env != NULL) {
2684  if (i < op->nrof) {
2685  player *pl;
2686  /* is this object in the players inventory, or sub container
2687  * therein?
2688  */
2689  tmp = object_get_player_container(op->env);
2690  /* nope. Is this a container the player has opened?
2691  * If so, set tmp to that player.
2692  * IMO, searching through all the players will mostly
2693  * likely be quicker than following op->env to the map,
2694  * and then searching the map for a player.
2695  */
2696  if (!tmp) {
2697  for (pl = first_player; pl; pl = pl->next)
2698  if (pl->ob->container == op->env)
2699  break;
2700  if (pl)
2701  tmp = pl->ob;
2702  else
2703  tmp = NULL;
2704  }
2705 
2706  /* Because of weight reduction by container and integer arithmetic,
2707  * there is no guarantee the rounded weight of combined items will be
2708  * the same as the sum of rounded weights.
2709  * Therefore just remove the current weight, and add the new.
2710  * Same adjustment done in object_increase_nrof().
2711  */
2712  object_sub_weight(op->env, op->weight * op->nrof);
2713  op->nrof -= i;
2714  object_add_weight(op->env, op->weight * op->nrof);
2715  if (tmp) {
2716  esrv_update_item(UPD_NROF, tmp, op);
2717  esrv_update_item(UPD_WEIGHT, tmp, op->env);
2718  fix_object(tmp);
2719  }
2720  } else {
2721  object_remove(op);
2722  op->nrof = 0;
2723  }
2724  } else {
2725  /* On a map. */
2726  if (i < op->nrof) {
2727  op->nrof -= i;
2728 
2729  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2730  if (pl->contr) {
2731  pl->contr->socket->update_look = 1;
2732  break;
2733  }
2734  FOR_MAP_FINISH();
2735  } else {
2736  object_remove(op);
2737  op->nrof = 0;
2738  }
2739  }
2740 
2741  if (op->nrof) {
2742  return op;
2743  } else {
2745  return NULL;
2746  }
2747 }
2748 
2759 static void object_increase_nrof(object *op, uint32_t i) {
2760  object *tmp;
2761 
2762  if (i == 0) /* objects with op->nrof require this check */
2763  return;
2764 
2765  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2766  op->nrof += i;
2767  } else if (op->env != NULL) {
2768  player *pl;
2769  /* is this object in the players inventory, or sub container
2770  * therein?
2771  */
2772  tmp = object_get_player_container(op->env);
2773  /* nope. Is this a container the player has opened?
2774  * If so, set tmp to that player.
2775  * IMO, searching through all the players will mostly
2776  * likely be quicker than following op->env to the map,
2777  * and then searching the map for a player.
2778  */
2779  if (!tmp) {
2780  for (pl = first_player; pl; pl = pl->next)
2781  if (pl->ob->container == op->env)
2782  break;
2783  if (pl)
2784  tmp = pl->ob;
2785  else
2786  tmp = NULL;
2787  }
2788 
2789  /* Because of weight reduction by container and integer arithmetic,
2790  * there is no guarantee the rounded weight of combined items will be
2791  * the same as the sum of rounded weights.
2792  * Therefore just remove the current weight, and add the new.
2793  * Same adjustment done in object_decrease_nrof().
2794  */
2795  object_sub_weight(op->env, op->weight * op->nrof);
2796  op->nrof += i;
2797  object_add_weight(op->env, op->weight * op->nrof);
2798  if (tmp) {
2799  esrv_update_item(UPD_NROF, tmp, op);
2800  // Why don't we need to update weight of op->env here?
2801  }
2802  } else {
2803  /* On a map. */
2804  op->nrof += i;
2805 
2806  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2807  if (pl->contr) {
2808  pl->contr->socket->update_look = 1;
2809  break;
2810  }
2811  FOR_MAP_FINISH();
2812  }
2813 }
2814 
2829 void object_add_weight(object *op, signed long weight) {
2830  while (op != NULL) {
2831  if (op->type == CONTAINER) {
2832  weight = (signed long)(weight*(100-op->stats.Str)/100);
2833  }
2834  op->carrying += weight;
2835  op = op->env;
2836  }
2837 }
2838 
2853 object *object_insert_in_ob(object *op, object *where) {
2854  object *otmp;
2855 
2856  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2857  StringBuffer *sb;
2858  char *diff;
2859 
2860  sb = stringbuffer_new();
2861  object_dump(op, sb);
2862  diff = stringbuffer_finish(sb);
2863  LOG(llevError, "Trying to insert (ob) inserted object.\n%s\n", diff);
2864  free(diff);
2865  return op;
2866  }
2867 
2868  if (where == NULL) {
2869  StringBuffer *sb;
2870  char *diff;
2871 
2872  sb = stringbuffer_new();
2873  object_dump(op, sb);
2874  diff = stringbuffer_finish(sb);
2875  LOG(llevError, "Trying to put object in NULL.\n%s\n", diff);
2876  free(diff);
2877  return op;
2878  }
2879  if (where->head) {
2880  LOG(llevDebug, "Warning: Tried to insert object wrong part of multipart object.\n");
2881  }
2882  where = HEAD(where);
2883  if (op->more) {
2884  LOG(llevError, "Tried to insert multipart object %s (%u)\n", op->name, op->count);
2885  return op;
2886  }
2888  CLEAR_FLAG(op, FLAG_REMOVED);
2889  if (op->nrof || op->type == SKILL) {
2890  FOR_INV_PREPARE(where, tmp)
2891  // Since harvesting skills have the same subtype, we need to check our shared string skill name as well
2892  if (op->type == SKILL && tmp->type == SKILL && op->subtype == tmp->subtype && op->skill == tmp->skill) {
2893  // Duplicate skill. Sum exp and total_exp.
2894  LOG(llevDebug, "Merged duplicate skill %s for %s\n", op->arch->name, where->name);
2895  tmp->stats.exp += op->stats.exp;
2896  tmp->total_exp += op->total_exp;
2897  SET_FLAG(op, FLAG_REMOVED);
2898  object_free(op, FREE_OBJ_FREE_INVENTORY | FREE_OBJ_NO_DESTROY_CALLBACK); /* free the inserted object */
2899  return tmp;
2900  } else if (object_can_merge(tmp, op)) {
2901  /* return the original object and remove inserted object
2902  * (client needs the original object) */
2903  object_increase_nrof(tmp, op->nrof);
2904  SET_FLAG(op, FLAG_REMOVED);
2905  object_free(op, FREE_OBJ_FREE_INVENTORY | FREE_OBJ_NO_DESTROY_CALLBACK); /* free the inserted object */
2906  return tmp;
2907  }
2908  FOR_INV_FINISH();
2909 
2910  /* the item couldn't merge. */
2911  object_add_weight(where, op->weight*op->nrof);
2912  } else
2913  object_add_weight(where, op->weight+op->carrying);
2914 
2915  op->map = NULL;
2916  op->env = where;
2917  op->above = NULL;
2918  op->below = NULL;
2919  op->x = 0,
2920  op->y = 0;
2921  op->ox = 0,
2922  op->oy = 0;
2923 
2924  /* Client has no idea of ordering so lets not bother ordering it here.
2925  * It sure simplifies this function...
2926  */
2927  if (where->inv == NULL)
2928  where->inv = op;
2929  else {
2930  op->below = where->inv;
2931  op->below->above = op;
2932  where->inv = op;
2933  }
2934 
2935  if (op->type == EVENT_CONNECTOR) {
2936  where->event_bitmask |= BITMASK_EVENT(op->subtype);
2937  }
2938 
2939  /* Update in 2 cases: object goes into player's inventory, or object goes into container the player
2940  * is looking into. */
2941  if (where->contr != NULL)
2942  esrv_send_item(where, op);
2943  else if (where->type == CONTAINER && QUERY_FLAG(where, FLAG_APPLIED)) {
2944  object *pl = NULL;
2945 
2946  if (op->env->env && op->env->env->contr)
2947  /* Container is in player's inventory. */
2948  pl = op->env->env;
2949  else if (op->env->map) {
2950  /* Container on map, look above for player. */
2952  if (above->contr) {
2953  pl = above;
2954  break;
2955  }
2956  FOR_ABOVE_FINISH();
2957  }
2958  if (pl)
2959  esrv_send_item(pl, op);
2960  }
2961 
2962  otmp = object_get_player_container(where);
2963  if (otmp && otmp->contr != NULL) {
2964  if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER)
2965  && (QUERY_FLAG(op, FLAG_APPLIED) || op->type == SKILL || op->glow_radius != 0))
2966  /* fix_object will only consider applied items, or skills, or items with a glow radius.
2967  thus no need to call it if our object hasn't that. */
2968  fix_object(otmp);
2969  }
2970 
2971  /* reset the light list and los of the players on the map */
2972  if (op->glow_radius != 0 && where->map) {
2973 #ifdef DEBUG_LIGHTS
2974  LOG(llevDebug, " object_insert_in_ob(): got %s to insert in map/op\n", op->name);
2975 #endif /* DEBUG_LIGHTS */
2976  if (MAP_DARKNESS(where->map)) {
2977  SET_MAP_FLAGS(where->map, where->x, where->y, P_NEED_UPDATE);
2978  update_position(where->map, where->x, where->y);
2979  update_all_los(where->map, where->x, where->y);
2980  }
2981  }
2982 
2983  return op;
2984 }
2985 
3008 int object_check_move_on(object *op, object *originator) {
3009  object *tmp;
3010  tag_t tag;
3011  mapstruct *m = op->map;
3012  int x = op->x, y = op->y;
3013  MoveType move_on, move_slow, move_block;
3014 
3015  if (QUERY_FLAG(op, FLAG_NO_APPLY))
3016  return 0;
3017 
3018  tag = op->count;
3019 
3020  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
3021  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
3022  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
3023 
3024  /* if nothing on this space will slow op down or be applied,
3025  * no need to do checking below. have to make sure move_type
3026  * is set, as lots of objects don't have it set - we treat that
3027  * as walking.
3028  */
3029  if (op->move_type
3030  && !(op->move_type&move_on)
3031  && !(op->move_type&move_slow))
3032  return 0;
3033 
3034  /* This is basically inverse logic of that below - basically,
3035  * if the object can avoid the move on or slow move, they do so,
3036  * but can't do it if the alternate movement they are using is
3037  * blocked. Logic on this seems confusing, but does seem correct.
3038  */
3039  if ((op->move_type&~move_on&~move_block) != 0
3040  && (op->move_type&~move_slow&~move_block) != 0)
3041  return 0;
3042 
3043  /* The objects have to be checked from top to bottom.
3044  * Hence, we first go to the top:
3045  */
3046 
3047  tmp = GET_MAP_OB(op->map, op->x, op->y);
3049  if (tmp->above == NULL)
3050  break;
3051  /* Trim the search when we find the first other spell effect
3052  * this helps performance so that if a space has 50 spell objects,
3053  * we don't need to check all of them.
3054  */
3055  if ((tmp->move_type&MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK))
3056  break;
3059  if (tmp == op)
3060  continue; /* Can't apply yourself */
3061 
3062  /* Check to see if one of the movement types should be slowed down.
3063  * Second check makes sure that the movement types not being slowed
3064  * (~slow_move) is not blocked on this space - just because the
3065  * space doesn't slow down swimming (for example), if you can't actually
3066  * swim on that space, can't use it to avoid the penalty.
3067  */
3068  if (!QUERY_FLAG(op, FLAG_WIZPASS)) {
3069  if ((!op->move_type && tmp->move_slow&MOVE_WALK)
3070  || ((op->move_type&tmp->move_slow) && (op->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
3071  float diff;
3072 
3073  diff = tmp->move_slow_penalty*FABS(op->speed);
3074  if (op->type == PLAYER) {
3077  diff /= 4.0;
3078  }
3079  }
3080  op->speed_left -= diff;
3081  }
3082  }
3083 
3084  /* Basically same logic as above, except now for actual apply. */
3085  if ((!op->move_type && tmp->move_on&MOVE_WALK)
3086  || ((op->move_type&tmp->move_on) && (op->move_type&~tmp->move_on&~tmp->move_block) == 0)) {
3087  ob_move_on(tmp, op, originator);
3088  if (object_was_destroyed(op, tag))
3089  return 1;
3090 
3091  /* what the person/creature stepped onto has moved the object
3092  * someplace new. Don't process any further - if we did,
3093  * have a feeling strange problems would result.
3094  */
3095  if (op->map != m || op->x != x || op->y != y)
3096  return 0;
3097  }
3099  return 0;
3100 }
3101 
3114 object *map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at) {
3115  if (m == NULL || OUT_OF_REAL_MAP(m, x, y)) {
3116  LOG(llevError, "Present_arch called outside map.\n");
3117  return NULL;
3118  }
3119 
3120  FOR_MAP_PREPARE(m, x, y, tmp)
3121  if (tmp->arch == at)
3122  return tmp;
3123  FOR_MAP_FINISH();
3124 
3125  return NULL;
3126 }
3127 
3141 object *map_find_by_type(mapstruct *m, int x, int y, uint8_t type) {
3142  if (OUT_OF_REAL_MAP(m, x, y)) {
3143  return NULL;
3144  }
3145 
3146  FOR_MAP_PREPARE(m, x, y, tmp)
3147  if (tmp->type == type)
3148  return tmp;
3149  FOR_MAP_FINISH();
3150 
3151  return NULL;
3152 }
3153 
3164 object *object_present_in_ob(uint8_t type, const object *op) {
3165  object *tmp;
3166 
3167  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3168  if (tmp->type == type)
3169  return tmp;
3170 
3171  return NULL;
3172 }
3173 
3199 object *object_present_in_ob_by_name(int type, const char *str, const object *op) {
3200  object *tmp;
3201 
3202  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3203  if ((type == -1 || tmp->type == type) && !strcmp(str, tmp->name))
3204  return tmp;
3205  }
3206  return NULL;
3207 }
3208 
3218 object *arch_present_in_ob(const archetype *at, const object *op) {
3219  object *tmp;
3220 
3221  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3222  if (tmp->arch == at)
3223  return tmp;
3224  return NULL;
3225 }
3226 
3235 void object_set_flag_inv(object*op, int flag) {
3236  object *tmp;
3237 
3238  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3239  SET_FLAG(tmp, flag);
3240  object_set_flag_inv(tmp, flag);
3241  }
3242 }
3243 
3252 void object_unset_flag_inv(object*op, int flag) {
3253  object *tmp;
3254 
3255  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3256  CLEAR_FLAG(tmp, flag);
3257  object_unset_flag_inv(tmp, flag);
3258  }
3259 }
3260 
3270 void object_set_cheat(object *op) {
3271  SET_FLAG(op, FLAG_WAS_WIZ);
3273 }
3274 
3292 int object_find_multi_free_spot_around(const object *ob, const object *gen, int16_t *hx, int16_t *hy) {
3293  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3294  int freecount = 0;
3295 
3296  ob = HEAD(ob);
3297 
3298  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3299  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3300  /*
3301  * sx and sy are now the coords of the bottom right corner of ob relative to the head.
3302  * genx and geny are now the coords of the bottom right corner of gen relative to the head.
3303  * sx2 and sy2 are now the coords of the head of ob relative to the top left corner.
3304  * genx2 and geny2 are now the coords of the head of gen relative to the top left corner.
3305  */
3306 
3307  sx++;
3308  sy++;
3309  genx++;
3310  geny++;
3311  /*
3312  * sx, sy, genx, and geny, are now the size of the object, excluding parts left and above
3313  * the head.
3314  */
3315 
3316  ix = gen->x-sx-genx2;
3317  iy = gen->y-sy-geny2;
3318  sx += genx+sx2;
3319  sy += geny+sy2;
3320  /*
3321  * ix and iy are the map coords of the top left square where the head of ob could possibly
3322  * be placed. sx and sy are now the size of the square to search for placement of the head
3323  * relative to ix and iy.
3324  */
3325 
3326  /*
3327  * Loop around the square of possible positions for the head of ob object:
3328  */
3329  for (i = 0; i < (sx+sx+sy+sy); i++) {
3330  if (i <= sx) {
3331  nx = i+ix;
3332  ny = iy;
3333  } else if (i <= sx+sy) {
3334  nx = ix+sx;
3335  ny = iy+i-sx;
3336  } else if (i <= sx+sy+sx) {
3337  nx = ix+sx-(i-(sx+sy));
3338  ny = iy+sy;
3339  } else {
3340  nx = ix;
3341  ny = iy+sy-(i-(sx+sy+sx));
3342  }
3343  /* Check if the spot is free. */
3344  flag = ob_blocked(ob, gen->map, nx, ny);
3345  if (!flag) {
3346  freecount++;
3347  }
3348  }
3349  /* If no free spaces, return. */
3350  if (!freecount)
3351  return -1;
3352 
3353  /* Choose a random valid position */
3354  freecount = RANDOM()%freecount;
3355  for (i = 0; i < sx+sx+sy+sy; i++) {
3356  if (i <= sx) {
3357  nx = i+ix;
3358  ny = iy;
3359  } else if (i <= sx+sy) {
3360  nx = ix+sx;
3361  ny = iy+i-sx;
3362  } else if (i <= sx+sy+sx) {
3363  nx = ix+sx-(i-(sx+sy));
3364  ny = iy+sy;
3365  } else {
3366  nx = ix;
3367  ny = iy+sy-(i-(sx+sy+sx));
3368  }
3369 
3370  /* Make sure it's within map. */
3371  if (nx < 0 || nx >= MAP_WIDTH(gen->map)
3372  || ny < 0 || ny >= MAP_HEIGHT(gen->map))
3373  continue;
3374 
3375  /* Check if the spot is free.*/
3376  flag = ob_blocked(ob, gen->map, nx, ny);
3377  if (!flag) {
3378  freecount--;
3379  if (freecount <= 0) {
3380  *hx = nx;
3381  *hy = ny;
3382  return 0;
3383  }
3384  }
3385  }
3386  return -1;
3387 }
3388 
3408 int object_find_multi_free_spot_within_radius(const object *ob, const object *gen, int *hx, int *hy) {
3409  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3410  int8_t x, y, radius;
3411  int freecount = 0, freecountstop = 0;
3412  const char *value;
3413  int8_t *x_array;
3414  int8_t *y_array;
3415 
3416  /* If radius is not set, default to 1 */
3417  value = object_get_value(gen, "generator_radius");
3418  if (value) {
3419  radius = (int8_t)strtol(value, NULL, 10);
3420  if (radius < 1) {
3421  radius = 1;
3422  }
3423  } else {
3424  radius = 1;
3425  }
3426 
3427  ob = HEAD(ob);
3428 
3429  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3430  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3431  /*
3432  * sx and sy are now the coords of the bottom right corner
3433  * of ob relative to the head.
3434  * genx and geny are now the coords of the bottom right corner
3435  * of gen relative to the head.
3436  * sx2 and sy2 are now the coords of the head of ob relative
3437  * to the top left corner.
3438  * genx2 and geny2 are now the coords of the head of gen relative
3439  * to the top left corner.
3440  */
3441 
3442  sx++;
3443  sy++;
3444  genx++;
3445  geny++;
3446  /*
3447  * sx, sy, genx, and geny, are now the size of the object,
3448  * excluding parts left and above the head.
3449  */
3450 
3451  ix = gen->x-sx-genx2-radius+1;
3452  iy = gen->y-sy-geny2-radius+1;
3453  sx += genx+sx2+radius*2-1;
3454  sy += geny+sy2+radius*2-1;
3455 
3456  /*
3457  * ix and iy are the map coords of the top left square where
3458  * the head of ob could possibly be placed. sx and sy are now
3459  * the size of the square to search for placement of the head
3460  * relative to ix and iy.
3461  */
3462 
3463  /* Create arrays large enough to hold free space coordinates */
3464  x_array = static_cast<int8_t *>(malloc(sx*sy*sizeof(int8_t)));
3465  y_array = static_cast<int8_t *>(malloc(sx*sy*sizeof(int8_t)));
3466 
3467  /*
3468  * Loop through the area of possible positions for the head of ob object:
3469  */
3470  for (x = 0; x < sx; x++) {
3471  for (y = 0; y < sy; y++) {
3472  nx = ix+x;
3473  ny = iy+y;
3474 
3475 
3476  /* Make sure it's within map. */
3477  if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) {
3478  continue;
3479  }
3480 
3481  /* Check if the spot is free. */
3482  flag = ob_blocked(ob, gen->map, nx, ny);
3483  if (!flag) {
3484  x_array[freecount] = nx;
3485  y_array[freecount] = ny;
3486  freecount++;
3487  }
3488  }
3489  }
3490  /* If no free spaces, return. */
3491  if (!freecount) {
3492  free(x_array);
3493  free(y_array);
3494  return -1;
3495  }
3496 
3497  /* Choose a random valid position */
3498  freecountstop = RANDOM()%freecount;
3499  for (i = 0; i < freecount; i++) {
3500  nx = x_array[i];
3501  ny = y_array[i];
3502 
3503  /* Check if the spot is free.*/
3504  flag = ob_blocked(ob, gen->map, nx, ny);
3505  if (!flag) {
3506  freecountstop--;
3507  if (freecountstop <= 0) {
3508  *hx = nx;
3509  *hy = ny;
3510  free(x_array);
3511  free(y_array);
3512  return 0;
3513  }
3514  }
3515  }
3516  free(x_array);
3517  free(y_array);
3518  return -1;
3519 }
3520 
3555 int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop) {
3556  int i, index = 0, flag;
3557  static int altern[SIZEOFFREE];
3558 
3559  for (i = start; i < stop; i++) {
3560  flag = ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]);
3561  if (!flag)
3562  altern[index++] = i;
3563 
3564  /* Basically, if we find a wall on a space, we cut down the search size.
3565  * In this way, we won't return spaces that are on another side of a wall.
3566  * This mostly work, but it cuts down the search size in all directions -
3567  * if the space being examined only has a wall to the north and empty
3568  * spaces in all the other directions, this will reduce the search space
3569  * to only the spaces immediately surrounding the target area, and
3570  * won't look 2 spaces south of the target space.
3571  */
3572  else if ((flag&AB_NO_PASS) && maxfree[i] < stop)
3573  stop = maxfree[i];
3574  }
3575  if (!index)
3576  return -1;
3577  return altern[RANDOM()%index];
3578 }
3579 
3595 int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y) {
3596  int i;
3597 
3598  for (i = 0; i < SIZEOFFREE; i++) {
3599  if (!ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]))
3600  return i;
3601  }
3602  return -1;
3603 }
3604 
3614 static void permute(int *arr, int begin, int end) {
3615  int i, j, tmp, len;
3616 
3617  len = end-begin;
3618  for (i = begin; i < end; i++) {
3619  j = begin+RANDOM()%len;
3620 
3621  tmp = arr[i];
3622  arr[i] = arr[j];
3623  arr[j] = tmp;
3624  }
3625 }
3626 
3638 void get_search_arr(int *search_arr) {
3639  int i;
3640 
3641  for (i = 0; i < SIZEOFFREE; i++) {
3642  search_arr[i] = i;
3643  }
3644 
3645  permute(search_arr, 1, SIZEOFFREE1+1);
3646  permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1);
3647  permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE);
3648 }
3649 
3657 int object_distance(const object *ob1, const object *ob2) {
3658  int i;
3659 
3660  i = (ob1->x-ob2->x)*(ob1->x-ob2->x)+
3661  (ob1->y-ob2->y)*(ob1->y-ob2->y);
3662  return i;
3663 }
3664 
3673 int find_dir_2(int x, int y) {
3674  int q;
3675 
3676  if (!y)
3677  q = -300*x;
3678  else
3679  q = x*100/y;
3680  if (y > 0) {
3681  if (q < -242)
3682  return 3;
3683  if (q < -41)
3684  return 2;
3685  if (q < 41)
3686  return 1;
3687  if (q < 242)
3688  return 8;
3689  return 7;
3690  }
3691  if (q < -242)
3692  return 7;
3693  if (q < -41)
3694  return 6;
3695  if (q < 41)
3696  return 5;
3697  if (q < 242)
3698  return 4;
3699  return 3;
3700 }
3701 
3710 int absdir(int d) {
3711  // Shortcut for modulus that work becuase we have a power of 2
3712  d &= 7;
3713  // 0 needs to be 8
3714  if (!d)
3715  d = 8;
3716  return d;
3717 }
3718 
3728 int dirdiff(int dir1, int dir2) {
3729  int d;
3730 
3731  d = abs(dir1-dir2);
3732  if (d > 4)
3733  d = 8-d;
3734  return d;
3735 }
3736 
3748 static const int reduction_dir[SIZEOFFREE][3] = {
3749  { 0, 0, 0 }, /* 0 */
3750  { 0, 0, 0 }, /* 1 */
3751  { 0, 0, 0 }, /* 2 */
3752  { 0, 0, 0 }, /* 3 */
3753  { 0, 0, 0 }, /* 4 */
3754  { 0, 0, 0 }, /* 5 */
3755  { 0, 0, 0 }, /* 6 */
3756  { 0, 0, 0 }, /* 7 */
3757  { 0, 0, 0 }, /* 8 */
3758  { 8, 1, 2 }, /* 9 */
3759  { 1, 2, -1 }, /* 10 */
3760  { 2, 10, 12 }, /* 11 */
3761  { 2, 3, -1 }, /* 12 */
3762  { 2, 3, 4 }, /* 13 */
3763  { 3, 4, -1 }, /* 14 */
3764  { 4, 14, 16 }, /* 15 */
3765  { 5, 4, -1 }, /* 16 */
3766  { 4, 5, 6 }, /* 17 */
3767  { 6, 5, -1 }, /* 18 */
3768  { 6, 20, 18 }, /* 19 */
3769  { 7, 6, -1 }, /* 20 */
3770  { 6, 7, 8 }, /* 21 */
3771  { 7, 8, -1 }, /* 22 */
3772  { 8, 22, 24 }, /* 23 */
3773  { 8, 1, -1 }, /* 24 */
3774  { 24, 9, 10 }, /* 25 */
3775  { 9, 10, -1 }, /* 26 */
3776  { 10, 11, -1 }, /* 27 */
3777  { 27, 11, 29 }, /* 28 */
3778  { 11, 12, -1 }, /* 29 */
3779  { 12, 13, -1 }, /* 30 */
3780  { 12, 13, 14 }, /* 31 */
3781  { 13, 14, -1 }, /* 32 */
3782  { 14, 15, -1 }, /* 33 */
3783  { 33, 15, 35 }, /* 34 */
3784  { 16, 15, -1 }, /* 35 */
3785  { 17, 16, -1 }, /* 36 */
3786  { 18, 17, 16 }, /* 37 */
3787  { 18, 17, -1 }, /* 38 */
3788  { 18, 19, -1 }, /* 39 */
3789  { 41, 19, 39 }, /* 40 */
3790  { 19, 20, -1 }, /* 41 */
3791  { 20, 21, -1 }, /* 42 */
3792  { 20, 21, 22 }, /* 43 */
3793  { 21, 22, -1 }, /* 44 */
3794  { 23, 22, -1 }, /* 45 */
3795  { 45, 47, 23 }, /* 46 */
3796  { 23, 24, -1 }, /* 47 */
3797  { 24, 9, -1 } /* 48 */
3798 };
3799 
3818 int can_see_monsterP(mapstruct *m, int x, int y, int dir) {
3819  int16_t dx, dy;
3820  int mflags;
3821 
3822  if (dir < 0)
3823  return 0; /* exit condition: invalid direction */
3824 
3825  dx = x+freearr_x[dir];
3826  dy = y+freearr_y[dir];
3827 
3828  mflags = get_map_flags(m, &m, dx, dy, &dx, &dy);
3829 
3830  /* This functional arguably was incorrect before - it was
3831  * checking for P_WALL - that was basically seeing if
3832  * we could move to the monster - this is being more
3833  * literal on if we can see it. To know if we can actually
3834  * move to the monster, we'd need the monster passed in or
3835  * at least its move type.
3836  */
3837  if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
3838  return 0;
3839 
3840  /* yes, can see. */
3841  if (dir < 9)
3842  return 1;
3843  return can_see_monsterP(m, x, y, reduction_dir[dir][0])|
3844  can_see_monsterP(m, x, y, reduction_dir[dir][1])|
3845  can_see_monsterP(m, x, y, reduction_dir[dir][2]);
3846 }
3847 
3863 int object_can_pick(const object *who, const object *item) {
3864  /* I re-wrote this as a series of if statements
3865  * instead of a nested return (foo & bar && yaz)
3866  * - I think this is much more readable,
3867  * and likely compiler effectively optimizes it the
3868  * same.
3869  */
3870  if (item->weight <= 0)
3871  return 0;
3872  if (QUERY_FLAG(item, FLAG_NO_PICK))
3873  return 0;
3874  if (QUERY_FLAG(item, FLAG_ALIVE))
3875  return 0;
3876  if (item->invisible)
3877  return 0;
3878  if (item->type == TRANSPORT && item->contr != NULL) {
3879  return 0;
3880  }
3881 
3882  /* Weight limit for monsters */
3883  if (who->type != PLAYER && ((uint32_t)(who->weight+who->carrying+item->weight)) > get_weight_limit(who->stats.Str))
3884  return 0;
3885 
3886  /* Can not pick up multipart objects */
3887  if (item->head || item->more)
3888  return 0;
3889 
3890  /* Everything passes, so OK to pick up */
3891  return 1;
3892 }
3893 
3905 object *object_create_clone(object *asrc) {
3906  object *dst = NULL, *tmp, *src, *part, *prev;
3907 
3908  if (!asrc)
3909  return NULL;
3910  src = HEAD(asrc);
3911 
3912  prev = NULL;
3913  for (part = src; part; part = part->more) {
3914  tmp = object_new();
3915  object_copy(part, tmp);
3916  /*
3917  * Need to reset the weight, since object_insert_in_ob() later will
3918  * recompute this field.
3919  */
3920  tmp->carrying = tmp->arch->clone.carrying;
3921  tmp->x -= src->x;
3922  tmp->y -= src->y;
3923  if (!part->head) {
3924  dst = tmp;
3925  tmp->head = NULL;
3926  } else {
3927  tmp->head = dst;
3928  }
3929  tmp->more = NULL;
3930  if (prev)
3931  prev->more = tmp;
3932  prev = tmp;
3933  }
3934  /*** copy inventory ***/
3935  FOR_INV_PREPARE(src, item)
3936  (void)object_insert_in_ob(object_create_clone(item), dst);
3937  FOR_INV_FINISH();
3938 
3939  return dst;
3940 }
3941 
3952 object *object_find_by_name(const object *who, const char *name) {
3953  const char *name_shared = add_string(name);
3954  object *tmp;
3955 
3956  for (tmp = who->inv; tmp; tmp = tmp->below)
3957  if (tmp->name == name_shared)
3958  break;
3959  free_string(name_shared);
3960  return tmp;
3961 }
3962 
3976 object *object_find_by_type(const object *who, int type) {
3977  object *tmp;
3978 
3979  for (tmp = who->inv; tmp; tmp = tmp->below)
3980  if (tmp->type == type)
3981  return tmp;
3982 
3983  return NULL;
3984 }
3985 
4000 object *object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags) {
4001  int flag_okay;
4002  for (object *tmp = who->inv; tmp; tmp = tmp->below)
4003  if (tmp->type == type) {
4004  flag_okay = 1;
4005  for (int i = 0; i < num_flags; ++i) {
4006  if (QUERY_FLAG(tmp, flags[i])) {
4007  flag_okay = 0; // A flag we didn't want set was set. Skip this item.
4008  break;
4009  }
4010  }
4011  if (flag_okay) // If flag_okay == 1, then the flags specified were not set
4012  return tmp; // If we reach here, none of the flags specified were set. Just like we wanted.
4013  }
4014 
4015  return NULL;
4016 }
4017 
4033 object *object_find_by_type2(const object *who, int type1, int type2) {
4034  object *tmp;
4035 
4036  for (tmp = who->inv; tmp; tmp = tmp->below)
4037  if (tmp->type == type1 || tmp->type == type2)
4038  return tmp;
4039 
4040  return NULL;
4041 }
4042 
4056 object *object_find_by_tag(const object *who, tag_t tag) {
4057  object *tmp;
4058 
4059  for (tmp = who->inv; tmp; tmp = tmp->below)
4060  if (tmp->count == tag)
4061  return tmp;
4062 
4063  return NULL;
4064 }
4065 
4079 object *object_find_by_type_applied(const object *who, int type) {
4080  object *tmp;
4081 
4082  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4083  if (tmp->type == type && QUERY_FLAG(tmp, FLAG_APPLIED))
4084  return tmp;
4085 
4086  return NULL;
4087 }
4088 
4104 object *object_find_by_type_and_name(const object *who, int type, const char *name) {
4105  object *tmp;
4106 
4107  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4108  if (tmp->type == type && strcmp(tmp->name, name) == 0)
4109  return tmp;
4110 
4111  return NULL;
4112 }
4113 
4129 object *object_find_by_type_and_race(const object *who, int type, const char *race) {
4130  object *tmp;
4131 
4132  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4133  if (tmp->type == type && strcmp(tmp->race, race) == 0)
4134  return tmp;
4135 
4136  return NULL;
4137 }
4138 
4154 object *object_find_by_type_and_slaying(const object *who, int type, const char *slaying) {
4155  object *tmp;
4156 
4157  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4158  if (tmp->type == type && tmp->slaying != NULL && strcmp(tmp->slaying, slaying) == 0)
4159  return tmp;
4160 
4161  return NULL;
4162 }
4163 
4179 object *object_find_by_type_and_skill(const object *who, int type, const char *skill) {
4180  object *tmp;
4181 
4182  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4183  if (tmp->type == type && tmp->skill != NULL && strcmp(tmp->skill, skill) == 0)
4184  return tmp;
4185 
4186  return NULL;
4187 }
4188 
4202 object *object_find_by_flag(const object *who, int flag) {
4203  object *tmp;
4204 
4205  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4206  if (QUERY_FLAG(tmp, flag))
4207  return tmp;
4208 
4209  return NULL;
4210 }
4211 
4225 object *object_find_by_flag_applied(const object *who, int flag) {
4226  object *tmp;
4227 
4228  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4229  if (QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, flag))
4230  return tmp;
4231 
4232  return NULL;
4233 }
4234 
4248 object *object_find_by_arch_name(const object *who, const char *name) {
4249  object *tmp;
4250 
4251  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4252  if (strcmp(tmp->arch->name, name) == 0)
4253  return tmp;
4254 
4255  return NULL;
4256 }
4257 
4273 object *object_find_by_type_and_arch_name(const object *who, int type, const char *name) {
4274  object *tmp;
4275 
4276  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4277  if (tmp->type == type && strcmp(tmp->arch->name, name) == 0)
4278  return tmp;
4279 
4280  return NULL;
4281 }
4282 
4297 object *object_find_by_type_subtype(const object *who, int type, int subtype) {
4298  object *tmp;
4299 
4300  for (tmp = who->inv; tmp; tmp = tmp->below)
4301  if (tmp->type == type && tmp->subtype == subtype)
4302  return tmp;
4303 
4304  return NULL;
4305 }
4306 
4317 key_value *object_get_key_value(const object *ob, const char *key) {
4318  key_value *link;
4319 
4320  for (link = ob->key_values; link != NULL; link = link->next) {
4321  if (link->key == key) {
4322  return link;
4323  }
4324  }
4325 
4326  return NULL;
4327 }
4328 
4342 sstring object_get_value(const object *op, const char *const key) {
4343  key_value *link;
4344  const char *canonical_key;
4345 
4346  canonical_key = find_string(key);
4347 
4348  if (canonical_key == NULL) {
4349  /* 1. There being a field named key on any object
4350  * implies there'd be a shared string to find.
4351  * 2. Since there isn't, no object has this field.
4352  * 3. Therefore, *this *object doesn't have this field.
4353  */
4354  return NULL;
4355  }
4356 
4357  /* This is copied from object_get_key_value() above -
4358  * only 4 lines, and saves the function call overhead.
4359  */
4360  for (link = op->key_values; link != NULL; link = link->next) {
4361  if (link->key == canonical_key) {
4362  return link->value;
4363  }
4364  }
4365  return NULL;
4366 }
4367 
4372 bool object_value_set(const object *op, const char *const key) {
4373  const char *ret = object_get_value(op, key);
4374  if (ret == NULL || (strcmp(ret, "") == 0) || (strcmp(ret, "0") == 0)) {
4375  return false;
4376  }
4377  return true;
4378 }
4379 
4386 bool object_value_set_shared(const object *op, sstring key) {
4387  for (key_value *link = op->key_values; link != NULL; link = link->next) {
4388  if (link->key == key) {
4389  if ((strcmp(link->value, "") == 0) || (strcmp(link->value, "0") == 0)) {
4390  return false;
4391  }
4392  return true;
4393  }
4394  }
4395  return false;
4396 }
4397 
4412 static int object_set_value_s(object *op, sstring canonical_key, const char *value, int add_key) {
4413  key_value *field = NULL, *last = NULL;
4414 
4415  for (field = op->key_values; field != NULL; field = field->next) {
4416  if (field->key != canonical_key) {
4417  last = field;
4418  continue;
4419  }
4420 
4421  if (field->value)
4422  FREE_AND_CLEAR_STR(field->value);
4423  if (value)
4424  field->value = add_string(value);
4425  else {
4426  /* Basically, if the archetype has this key set,
4427  * we need to store the null value so when we save
4428  * it, we save the empty value so that when we load,
4429  * we get this value back again.
4430  */
4431  if (object_get_key_value(&op->arch->clone, canonical_key))
4432  field->value = NULL;
4433  else {
4434  /* Delete this link */
4435  if (field->key)
4436  FREE_AND_CLEAR_STR(field->key);
4437  if (field->value)
4438  FREE_AND_CLEAR_STR(field->value);
4439  if (last)
4440  last->next = field->next;
4441  else
4442  op->key_values = field->next;
4443  free(field);
4444  }
4445  }
4446  return TRUE;
4447  }
4448  /* IF we get here, key doesn't exist */
4449 
4450  /* No field, we'll have to add it. */
4451 
4452  if (!add_key) {
4453  return FALSE;
4454  }
4455  /* There isn't any good reason to store a null
4456  * value in the key/value list. If the archetype has
4457  * this key, then we should also have it, so shouldn't
4458  * be here. If user wants to store empty strings,
4459  * should pass in ""
4460  */
4461  if (value == NULL)
4462  return TRUE;
4463 
4464  field = static_cast<key_value *>(malloc(sizeof(key_value)));
4465 
4466  field->key = add_refcount(canonical_key);
4467  field->value = add_string(value);
4468  /* Usual prepend-addition. */
4469  field->next = op->key_values;
4470  op->key_values = field;
4471 
4472  return TRUE;
4473 }
4474 
4495 int object_set_value(object *op, const char *key, const char *value, int add_key) {
4496  const char *canonical_key = NULL;
4497  int floating_ref = FALSE;
4498  int ret;
4499 
4500  /* HACK This mess is to make sure set_ob_value() passes a shared string
4501  * to object_get_key_value(), without leaving a leaked refcount.
4502  */
4503 
4504  canonical_key = find_string(key);
4505  if (canonical_key == NULL) {
4506  canonical_key = add_string(key);
4507  floating_ref = TRUE;
4508  }
4509 
4510  ret = object_set_value_s(op, canonical_key, value, add_key);
4511 
4512  if (floating_ref) {
4513  free_string(canonical_key);
4514  }
4515 
4516  return ret;
4517 }
4518 
4571 int object_matches_string(object *pl, object *op, const char *name) {
4572  char *cp, local_name[MAX_BUF], name_op[MAX_BUF], name_short[HUGE_BUF], bname_s[MAX_BUF], bname_p[MAX_BUF];
4573  int count, retval = 0;
4574 
4575  char *endptr;
4576  if (op->count == strtoul(name, &endptr, 10)) {
4577  if ((endptr != name) && (*endptr == '\0')) {
4578  return 30;
4579  }
4580  }
4581 
4582  /* strtok is destructive to name */
4583  safe_strncpy(local_name, name, sizeof(local_name));
4584  sstring custom_name = object_get_value(op, CUSTOM_NAME_FIELD);
4585 
4586  for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) {
4587  while (cp[0] == ' ')
4588  ++cp; /* get rid of spaces */
4589 
4590  /* LOG(llevDebug, "Trying to match %s\n", cp);*/
4591  /* All is a very generic match - low match value */
4592  if (!strcmp(cp, "all"))
4593  return 1;
4594 
4595  /* unpaid is a little more specific */
4596  if (!strcmp(cp, "unpaid") && QUERY_FLAG(op, FLAG_UNPAID))
4597  return 2;
4598  if (!strcmp(cp, "cursed")
4600  && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)))
4601  return 2;
4602 
4603  if (!strcmp(cp, "unlocked") && !QUERY_FLAG(op, FLAG_INV_LOCKED))
4604  return 2;
4605 
4606  /* Allow for things like '100 arrows' */
4607  count = atoi(cp);
4608  if (*cp == '+' || *cp == '-')
4609  count=0; // Let +/- searches look in description for magic bonuses
4610  if (count != 0) {
4611  cp = strchr(cp, ' ');
4612  while (cp && cp[0] == ' ')
4613  ++cp; /* get rid of spaces */
4614  } else {
4615  if (pl->type == PLAYER)
4616  count = pl->contr->count;
4617  else
4618  count = 0;
4619  }
4620 
4621  if (!cp || cp[0] == '\0' || count < 0)
4622  continue;
4623 
4624  /* The code here should go from highest retval to lowest. That
4625  * is because of the 'else' handling - we don't want to match on
4626  * something and set a low retval, even though it may match a higher retcal
4627  * later. So keep it in descending order here, so we try for the best
4628  * match first, and work downward.
4629  */
4630  query_name(op, name_op, MAX_BUF);
4631  query_short_name(op, name_short, HUGE_BUF);
4632  query_base_name(op, 0, bname_s, MAX_BUF);
4633  query_base_name(op, 1, bname_p, MAX_BUF);
4634 
4635  if (!strcasecmp(cp, name_op))
4636  retval = 20;
4637  else if (!strcasecmp(cp, name_short))
4638  retval = 18;
4639  else if (!strcasecmp(cp, bname_s))
4640  retval = 16;
4641  else if (!strcasecmp(cp, bname_p))
4642  retval = 16;
4643  else if (custom_name && !strcasecmp(cp, custom_name))
4644  retval = 15;
4645  else if (!strncasecmp(cp, bname_s, strlen(cp)))
4646  retval = 14;
4647  else if (!strncasecmp(cp, bname_p, strlen(cp)))
4648  retval = 14;
4649  /* Do substring checks, so things like 'Str+1' will match.
4650  * retval of these should perhaps be lower - they are lower
4651  * then the specific strcasecmp aboves, but still higher than
4652  * some other match criteria.
4653  */
4654  else if (strstr(bname_p, cp))
4655  retval = 12;
4656  else if (strstr(bname_s, cp))
4657  retval = 12;
4658  else if (strstr(name_short, cp))
4659  retval = 12;
4660  /* Check against plural/non plural based on count. */
4661  else if (count > 1 && !strcasecmp(cp, op->name_pl)) {
4662  retval = 6;
4663  } else if (count == 1 && !strcasecmp(op->name, cp)) {
4664  retval = 6;
4665  }
4666  /* base name matched - not bad */
4667  else if (strcasecmp(cp, op->name) == 0 && !count)
4668  retval = 4;
4669  /* Check for partial custom name, but give a real low priority */
4670  else if (custom_name && strstr(custom_name, cp))
4671  retval = 3;
4672 
4673  if (retval) {
4674  if (pl->type == PLAYER)
4675  pl->contr->count = count;
4676  return retval;
4677  }
4678  }
4679  return 0;
4680 }
4681 
4690 void object_fix_multipart(object *tmp) {
4691  archetype *at;
4692  object *op, *last;
4693 
4694  if (!tmp->map) {
4695  LOG(llevError, "object_fix_multipart: not on a map!\n");
4696  return;
4697  }
4698 
4699  /* already multipart - don't do anything more */
4700  if (tmp->head || tmp->more)
4701  return;
4702 
4703  /* If there is nothing more to this object, this for loop
4704  * won't do anything.
4705  */
4706  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
4707  op = arch_to_object(at);
4708 
4709  /* update x,y coordinates */
4710  op->x += tmp->x;
4711  op->y += tmp->y;
4712  op->head = tmp;
4713  op->map = tmp->map;
4714  last->more = op;
4715  if (tmp->name != op->name) {
4716  if (op->name)
4717  free_string(op->name);
4718  op->name = add_string(tmp->name);
4719  }
4720  if (tmp->title != op->title) {
4721  if (op->title)
4722  free_string(op->title);
4723  op->title = add_string(tmp->title);
4724  }
4725  /* we could link all the parts onto tmp, and then just
4726  * call object_insert_in_map once, but the effect is the same,
4727  * as object_insert_in_map will call itself with each part, and
4728  * the coding is simpler to just to it here with each part.
4729  */
4731  } /* for at = tmp->arch->more */
4732 }
4733 
4749 void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy) {
4750  archetype *part;
4751  int maxx = 0, maxy = 0, minx = 0, miny = 0;
4752 
4753  ob = HEAD(ob);
4754  *sx = 1;
4755  *sy = 1;
4756  if (ob->arch->more) {
4757  for (part = ob->arch; part; part = part->more) {
4758  if (part->clone.x > maxx)
4759  maxx = part->clone.x;
4760  if (part->clone.y > maxy)
4761  maxy = part->clone.y;
4762  if (part->clone.x < minx)
4763  minx = part->clone.x;
4764  if (part->clone.y < miny)
4765  miny = part->clone.y;
4766  }
4767  }
4768  *sx = maxx;
4769  *sy = maxy;
4770  if (hx)
4771  *hx = -minx;
4772  if (hy)
4773  *hy = -miny;
4774 }
4775 
4796 void object_insert_to_free_spot_or_free(object *op, mapstruct *map, int x, int y, int start, int stop, object *originator) {
4797  int pos;
4798 
4799  pos = object_find_free_spot(op, map, x, y, start, stop);
4800  if (pos == -1) {
4802  return;
4803  }
4804 
4805  object_insert_in_map_at(op, map, originator, 0, x+freearr_x[pos], y+freearr_y[pos]);
4806 }
4807 
4816 void object_set_msg(object *op, const char *msg) {
4817  if (op->msg != NULL) {
4818  free_string(op->msg);
4819  }
4820 
4821  if (msg != NULL) {
4822  // If the message does not have a trailing newline, add one.
4823  if (*msg != '\0' && strchr(msg, '\0')[-1] != '\n') {
4825  stringbuffer_append_string(sb, msg);
4826  stringbuffer_append_string(sb, "\n");
4827  op->msg = stringbuffer_finish_shared(sb);
4828  } else {
4829  op->msg = add_string(msg);
4830  }
4831  } else {
4832  op->msg = NULL;
4833  }
4834 }
4835 
4837 const char *const move_name[] = {
4838  "walk",
4839  "fly_low",
4840  "fly_high",
4841  "swim",
4842  "boat",
4843  NULL
4844 };
4845 
4846 /* This array equates the FLAG_ values with the V_ values. Use -1 to
4847  * put gaps in the array that should not be processed.
4848  * The order matches the order of the define values in 'define.h'.
4849  */
4856 static const char *const flag_names[NUM_FLAGS+1] = {
4857  "alive", "wiz", NULL, NULL, "was_wiz", "applied", "unpaid",
4858  "can_use_shield", "no_pick", "client_anim_sync", "client_anim_random", /* 10 */
4859  "is_animated", NULL /* FLAG_DIALOG_PARSED, not saved */,
4860  NULL /* flying */, "monster", "friendly", "generator",
4861  "is_thrown", "auto_apply", "treasure", "player sold", /* 20 */
4862  "see_invisible", "can_roll", "overlay_floor",
4863  "is_turnable", NULL /* walk_off */, NULL /* fly_on */,
4864  NULL /*fly_off*/, "is_used_up", "identified", "reflecting", /* 30 */
4865  "changing", "splitting", "hitback", "startequip",
4866  "blocksview", "undead", "scared", "unaggressive",
4867  "reflect_missile", "reflect_spell", /* 40 */
4868  "no_magic", "no_fix_player", "is_lightable", "tear_down",
4869  "run_away", NULL /*pass_thru */, NULL /*can_pass_thru*/,
4870  NULL /*"pick_up"*/, "unique", "no_drop", /* 50 */
4871  NULL /* wizcast*/, "can_cast_spell", "can_use_scroll", "can_use_range",
4872  "can_use_bow", "can_use_armour", "can_use_weapon",
4873  "can_use_ring", "has_ready_range", "has_ready_bow", /* 60 */
4874  "xrays", NULL, "is_floor", "lifesave", "no_strength", "sleep",
4875  "stand_still", "random_movement", "only_attack", "confused", /* 70 */
4876  "stealth", NULL, NULL, "cursed", "damned",
4877  "see_anywhere", "known_magical", "known_cursed",
4878  "can_use_skill", "been_applied", /* 80 */
4879  "has_ready_scroll", NULL, NULL,
4880  NULL, "make_invisible", "inv_locked", "is_wooded",
4881  "is_hilly", "has_ready_skill", "has_ready_weapon", /* 90 */
4882  "no_skill_ident", "is_blind", "can_see_in_dark", "is_cauldron",
4883  NULL, "no_steal", "one_hit", NULL, "berserk", "neutral", /* 100 */
4884  "no_attack", "no_damage", NULL, NULL, "activate_on_push",
4885  "activate_on_release", "is_water", "use_content_on_gen", NULL, "is_buildable", /* 110 */
4886  NULL, "blessed", "known_blessed"
4887 };
4888 
4898 {
4899  std::string retbuf{""}, retbuf_all{" all"};
4900  int i, all_count = 0, count;
4901 
4902  /* Quick check, and probably fairly common */
4903  if (mt == MOVE_ALL) {
4904  stringbuffer_append_string(sb, "all");
4905  return;
4906  }
4907  if (mt == 0) {
4908  stringbuffer_append_string(sb, "0");
4909  return;
4910  }
4911 
4912  /* We basically slide the bits down. Why look at MOVE_ALL?
4913  * because we may want to return a string like 'all -swim',
4914  * and if we just looked at mt, we couldn't get that.
4915  */
4916  for (i = MOVE_ALL, count = 0; i != 0; i >>= 1, count++) {
4917  if (mt&(1<<count)) {
4918  retbuf += " ";
4919  retbuf += move_name[count];
4920  } else {
4921  retbuf_all += " -";
4922  retbuf_all += move_name[count];
4923  all_count++;
4924  }
4925  }
4926  /* Basically, if there is a single negation, return it, eg
4927  * 'all -swim'. But more than that, just return the
4928  * enumerated values. It doesn't make sense to return
4929  * 'all -walk -fly_low' - it is shorter to return 'fly_high swim'
4930  */
4931  if (all_count <= 1)
4932  stringbuffer_append_string(sb, retbuf_all.c_str()+1);
4933  else
4934  stringbuffer_append_string(sb, retbuf.c_str()+1);
4935 }
4936 
4938 static inline void ADD_STRINGLINE_ENTRY(StringBuffer *sb, const char *name, const char *value) {
4940  stringbuffer_append_string(sb, value);
4941  stringbuffer_append_string(sb, "\n");
4942 }
4943 
4945 static inline void FAST_SAVE_LONG(StringBuffer *sb, const char *name, const long value) {
4947  stringbuffer_append_int64(sb, value);
4948  stringbuffer_append_char(sb, '\n');
4949 }
4950 
4952 static inline void FAST_SAVE_DOUBLE(StringBuffer *sb, const char *name, const double value) {
4953  stringbuffer_append_printf(sb, "%s%g\n", name, value);
4954 }
4955 
4963  for (int i = 0; i < 4; i++) {
4964  int idx = ffs((*diff)[i]);
4965  if (idx != 0) {
4966  int bit = idx - 1;
4967  // Clear difference bit.
4968  (*diff)[i] &= ~(1 << bit);
4969  return 32*i + bit;
4970  }
4971  }
4972  return -1;
4973 }
4974 
4988 void get_ob_diff(StringBuffer *sb, const object *op, const object *op2) {
4989  static char buf2[64];
4990  int tmp;
4991  int i;
4992  key_value *my_field;
4993  key_value *arch_field;
4994 
4995  /* This saves the key/value lists. We do it first so that any
4996  * keys that match field names will be overwritten by the loader.
4997  */
4998  for (my_field = op->key_values; my_field != NULL; my_field = my_field->next) {
4999  /* Find the field in the opposing member. */
5000  arch_field = object_get_key_value(op2, my_field->key);
5001 
5002  /* If there's no partnering field, or it's got a different value, save our field. */
5003  if (arch_field == NULL || my_field->value != arch_field->value) {
5004  stringbuffer_append_string(sb, my_field->key);
5005  stringbuffer_append_string(sb, " ");
5006  /* If this is null, then saving it as a space should
5007  * cause it to be null again.
5008  */
5009  if (my_field->value)
5010  stringbuffer_append_string(sb, my_field->value);
5011  stringbuffer_append_string(sb, "\n");
5012  }
5013  }
5014  /* We don't need to worry about the arch's extra fields - they
5015  * will get taken care of the object_copy() function.
5016  */
5017 
5018  if (op->name && op->name != op2->name) {
5019  ADD_STRINGLINE_ENTRY(sb, "name ", op->name);
5020  }
5021  if (op->name_pl && op->name_pl != op2->name_pl) {
5022  // The loader will set name_pl = name if there is no special plural name,
5023  // so check for that when we save out.
5024  if (op->name_pl != op->name)
5025  ADD_STRINGLINE_ENTRY(sb, "name_pl ", op->name_pl);
5026  }
5027  if (op->anim_suffix && op->anim_suffix != op2->anim_suffix) {
5028  ADD_STRINGLINE_ENTRY(sb, "anim_suffix ", op->anim_suffix);
5029  }
5030  if (op->title && op->title != op2->title) {
5031  ADD_STRINGLINE_ENTRY(sb, "title ", op->title);
5032  }
5033  if (op->race && op->race != op2->race) {
5034  ADD_STRINGLINE_ENTRY(sb, "race ", op->race);
5035  }
5036  if (op->slaying && op->slaying != op2->slaying) {
5037  ADD_STRINGLINE_ENTRY(sb, "slaying ", op->slaying);
5038  }
5039  if (op->skill && op->skill != op2->skill) {
5040  ADD_STRINGLINE_ENTRY(sb, "skill ", op->skill);
5041  }
5042  if (op->msg && op->msg != op2->msg) {
5043  stringbuffer_append_string(sb, "msg\n");
5045  stringbuffer_append_string(sb, "endmsg\n");
5046  }
5047  if (op->lore && op->lore != op2->lore) {
5048  stringbuffer_append_string(sb, "lore\n");
5050  stringbuffer_append_string(sb, "endlore\n");
5051  }
5052  if (op->other_arch != op2->other_arch && op->other_arch != NULL && op->other_arch->name) {
5053  ADD_STRINGLINE_ENTRY(sb, "other_arch ", op->other_arch->name);
5054  }
5055  if (op->face != op2->face) {
5056  ADD_STRINGLINE_ENTRY(sb, "face ", op->face->name);
5057  }
5058 
5059  if (op->animation != op2->animation) {
5060  if (op->animation) {
5061  ADD_STRINGLINE_ENTRY(sb, "animation ", op->animation->name);
5062  if (!QUERY_FLAG (op, FLAG_ANIMATE)) {
5063  stringbuffer_append_string(sb, "is_animated 0\n");
5064  }
5065  } else {
5066  stringbuffer_append_string(sb, "animation NONE\n");
5067  }
5068  }
5069  if (op->stats.Str != op2->stats.Str)
5070  FAST_SAVE_LONG(sb, "Str ", op->stats.Str);
5071  if (op->stats.Dex != op2->stats.Dex)
5072  FAST_SAVE_LONG(sb, "Dex ", op->stats.Dex);
5073  if (op->stats.Con != op2->stats.Con)
5074  FAST_SAVE_LONG(sb, "Con ", op->stats.Con);
5075  if (op->stats.Wis != op2->stats.Wis)
5076  FAST_SAVE_LONG(sb, "Wis ", op->stats.Wis);
5077  if (op->stats.Pow != op2->stats.Pow)
5078  FAST_SAVE_LONG(sb, "Pow ", op->stats.Pow);
5079  if (op->stats.Cha != op2->stats.Cha)
5080  FAST_SAVE_LONG(sb, "Cha ", op->stats.Cha);
5081  if (op->stats.Int != op2->stats.Int)
5082  FAST_SAVE_LONG(sb, "Int ", op->stats.Int);
5083  if (op->stats.hp != op2->stats.hp)
5084  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5085  if (op->stats.maxhp != op2->stats.maxhp)
5086  FAST_SAVE_LONG(sb, "maxhp ", op->stats.maxhp);
5087  if (op->stats.sp != op2->stats.sp)
5088  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5089  if (op->stats.maxsp != op2->stats.maxsp)
5090  FAST_SAVE_LONG(sb, "maxsp ", op->stats.maxsp);
5091  if (op->stats.grace != op2->stats.grace)
5092  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5093  if (op->stats.maxgrace != op2->stats.maxgrace)
5094  FAST_SAVE_LONG(sb, "maxgrace ", op->stats.maxgrace);
5095 
5096  if (op->stats.exp != op2->stats.exp) {
5097  snprintf(buf2, sizeof(buf2), "%" FMT64, op->stats.exp);
5098  ADD_STRINGLINE_ENTRY(sb, "exp ", buf2);
5099  }
5100 
5101  if (op->total_exp != op2->total_exp) {
5102  snprintf(buf2, sizeof(buf2), "%" FMT64, op->total_exp);
5103  ADD_STRINGLINE_ENTRY(sb, "total_exp ", buf2);
5104  }
5105 
5106  if (op->expmul != op2->expmul)
5107  FAST_SAVE_DOUBLE(sb, "expmul ", op->expmul);
5108  if (op->stats.food != op2->stats.food)
5109  FAST_SAVE_LONG(sb, "food ", op->stats.food);
5110  if (op->stats.dam != op2->stats.dam)
5111  FAST_SAVE_LONG(sb, "dam ", op->stats.dam);
5112  if (op->stats.luck != op2->stats.luck)
5113  FAST_SAVE_LONG(sb, "luck ", op->stats.luck);
5114  if (op->stats.wc != op2->stats.wc)
5115  FAST_SAVE_LONG(sb, "wc ", op->stats.wc);
5116  if (op->stats.ac != op2->stats.ac)
5117  FAST_SAVE_LONG(sb, "ac ", op->stats.ac);
5118  if (op->x != op2->x)
5119  FAST_SAVE_LONG(sb, "x ", op->x);
5120  if (op->y != op2->y)
5121  FAST_SAVE_LONG(sb, "y ", op->y);
5122  if (op->speed != op2->speed) {
5123  FAST_SAVE_DOUBLE(sb, "speed ", op->speed);
5124  }
5125  if (op->speed > 0 && op->speed_left != op2->speed_left) {
5126  FAST_SAVE_DOUBLE(sb, "speed_left ", op->speed_left);
5127  }
5128  if (op->weapon_speed != op2->weapon_speed) {
5129  FAST_SAVE_DOUBLE(sb, "weapon_speed ", op->weapon_speed);
5130  }
5131  if (op->weapon_speed > 0 && op->weapon_speed_left != op2->weapon_speed_left) {
5132  FAST_SAVE_DOUBLE(sb, "weapon_speed_left ", op->weapon_speed_left);
5133  }
5134  if (op->move_status != op2->move_status)
5135  FAST_SAVE_LONG(sb, "move_state ", op->move_status);
5136  if (op->attack_movement != op2->attack_movement)
5137  FAST_SAVE_LONG(sb, "attack_movement ", op->attack_movement);
5138  if (op->nrof != op2->nrof)
5139  FAST_SAVE_LONG(sb, "nrof ", op->nrof);
5140  if (op->level != op2->level)
5141  FAST_SAVE_LONG(sb, "level ", op->level);
5142  if (op->direction != op2->direction)
5143  FAST_SAVE_LONG(sb, "direction ", op->direction);
5144  if (op->type != op2->type)
5145  FAST_SAVE_LONG(sb, "type ", op->type);
5146  if (op->subtype != op2->subtype)
5147  FAST_SAVE_LONG(sb, "subtype ", op->subtype);
5148  if (op->attacktype != op2->attacktype)
5149  FAST_SAVE_LONG(sb, "attacktype ", op->attacktype);
5150 
5151  for (tmp = 0; tmp < NROFATTACKS; tmp++) {
5152  if (op->resist[tmp] != op2->resist[tmp]) {
5153  stringbuffer_append_string(sb, "resist_");
5154  FAST_SAVE_LONG(sb, resist_save[tmp], op->resist[tmp]);
5155  }
5156  }
5157 
5158  if (op->path_attuned != op2->path_attuned)
5159  FAST_SAVE_LONG(sb, "path_attuned ", op->path_attuned);
5160  if (op->path_repelled != op2->path_repelled)
5161  FAST_SAVE_LONG(sb, "path_repelled ", op->path_repelled);
5162  if (op->path_denied != op2->path_denied)
5163  FAST_SAVE_LONG(sb, "path_denied ", op->path_denied);
5164  if (op->material != op2->material)
5165  FAST_SAVE_LONG(sb, "material ", op->material);
5166  if (op->materialname && op->materialname != op2->materialname) {
5167  ADD_STRINGLINE_ENTRY(sb, "materialname ", op->materialname);
5168  }
5169  if (op->value != op2->value)
5170  FAST_SAVE_LONG(sb, "value ", op->value);
5171  // op->carrying is always recomputed at load, so don't save it
5172  if (op->weight != op2->weight)
5173  FAST_SAVE_LONG(sb, "weight ", op->weight);
5174  if (op->invisible != op2->invisible)
5175  FAST_SAVE_LONG(sb, "invisible ", op->invisible);
5176  if (op->state != op2->state)
5177  FAST_SAVE_LONG(sb, "state ", op->state);
5178  if (op->magic != op2->magic)
5179  FAST_SAVE_LONG(sb, "magic ", op->magic);
5180  if (op->last_heal != op2->last_heal)
5181  FAST_SAVE_LONG(sb, "last_heal ", op->last_heal);
5182  if (op->last_sp != op2->last_sp)
5183  FAST_SAVE_LONG(sb, "last_sp ", op->last_sp);
5184  if (op->last_grace != op2->last_grace)
5185  FAST_SAVE_LONG(sb, "last_grace ", op->last_grace);
5186  if (op->last_eat != op2->last_eat)
5187  FAST_SAVE_LONG(sb, "last_eat ", op->last_eat);
5188  if (QUERY_FLAG(op, FLAG_IS_LINKED) && (tmp = get_button_value(op)))
5189  FAST_SAVE_LONG(sb, "connected ", tmp);
5190  if (op->glow_radius != op2->glow_radius)
5191  FAST_SAVE_LONG(sb, "glow_radius ", op->glow_radius);
5192  if (op->randomitems != op2->randomitems) {
5193  ADD_STRINGLINE_ENTRY(sb, "randomitems ", op->randomitems ? op->randomitems->name : "none");
5194  }
5195 
5196  if (op->run_away != op2->run_away)
5197  FAST_SAVE_LONG(sb, "run_away ", op->run_away);
5198  if (op->pick_up != op2->pick_up)
5199  FAST_SAVE_LONG(sb, "pick_up ", op->pick_up);
5200  if (op->weight_limit != op2->weight_limit)
5201  FAST_SAVE_LONG(sb, "container ", op->weight_limit);
5202  if (op->will_apply != op2->will_apply)
5203  FAST_SAVE_LONG(sb, "will_apply ", op->will_apply);
5204  if (op->smoothlevel != op2->smoothlevel)
5205  FAST_SAVE_LONG(sb, "smoothlevel ", op->smoothlevel);
5206 
5207  if (op->map_layer != op2->map_layer)
5208  ADD_STRINGLINE_ENTRY(sb, "map_layer ", map_layer_name[op->map_layer]);
5209 
5210  if (op->weapontype && op->weapontype != op2->weapontype) {
5211  FAST_SAVE_LONG(sb, "weapontype ", op->weapontype);
5212  }
5213  if (op->elevation && op->elevation != op2->elevation) {
5214  FAST_SAVE_LONG(sb, "elevation ", op->elevation);
5215  }
5216  if (op->client_type && op->client_type != op2->client_type) {
5217  FAST_SAVE_LONG(sb, "client_type ", op->client_type);
5218  }
5219 
5220  if (op->item_power != op2->item_power) {
5221  FAST_SAVE_LONG(sb, "item_power ", op->item_power);
5222  }
5223 
5224  if (op->duration != op2->duration)
5225  FAST_SAVE_LONG(sb, "duration ", op->duration);
5226 
5227  if (op->range != op2->range)
5228  FAST_SAVE_LONG(sb, "range ", op->range);
5229 
5230  if (op->range_modifier != op2->range_modifier)
5231  FAST_SAVE_LONG(sb, "range_modifier ", op->range_modifier);
5232 
5233  if (op->duration_modifier != op2->duration_modifier)
5234  FAST_SAVE_LONG(sb, "duration_modifier ", op->duration_modifier);
5235 
5236  if (op->dam_modifier != op2->dam_modifier)
5237  FAST_SAVE_LONG(sb, "dam_modifier ", op->dam_modifier);
5238 
5239  if (op->gen_sp_armour != op2->gen_sp_armour) {
5240  FAST_SAVE_LONG(sb, "gen_sp_armour ", op->gen_sp_armour);
5241  }
5242 
5243  /* I've kept the old int move type saving code commented out.
5244  * In an ideal world, we'd know if we want to do a quick
5245  * save (say to a temp map, where we don't care about strings),
5246  * or a slower save/dm dump, where printing out strings is handy.
5247  */
5248  if (op->move_type != op2->move_type) {
5249  /*FAST_SAVE_LONG(sb, "move_type ", op->move_type)*/
5250  stringbuffer_append_string(sb, "move_type ");
5252  stringbuffer_append_string(sb, "\n");
5253  }
5254  if (op->move_block != op2->move_block) {
5255  /*FAST_SAVE_LONG(sb, "move_block ", op->move_block)*/
5256  stringbuffer_append_string(sb, "move_block ");
5258  stringbuffer_append_string(sb, "\n");
5259  }
5260  if (op->move_allow != op2->move_allow) {
5261  /*FAST_SAVE_LONG(sb, "move_allow ", op->move_allow);*/
5262  stringbuffer_append_string(sb, "move_allow ");
5264  stringbuffer_append_string(sb, "\n");
5265  }
5266  if (op->move_on != op2->move_on) {
5267  /*FAST_SAVE_LONG(sb, "move_on ", op->move_on);*/
5268  stringbuffer_append_string(sb, "move_on ");
5269  get_string_move_type(sb, op->move_on);
5270  stringbuffer_append_string(sb, "\n");
5271  }
5272  if (op->move_off != op2->move_off) {
5273  /*FAST_SAVE_LONG(sb, "move_off ", op->move_off);*/
5274  stringbuffer_append_string(sb, "move_off ");
5275  get_string_move_type(sb, op->move_off);
5276  stringbuffer_append_string(sb, "\n");
5277  }
5278  if (op->move_slow != op2->move_slow) {
5279  /*FAST_SAVE_LONG(sb, "move_slow ", op->move_slow);*/
5280  stringbuffer_append_string(sb, "move_slow ");
5282  stringbuffer_append_string(sb, "\n");
5283  }
5284 
5285  if (op->move_slow_penalty != op2->move_slow_penalty) {
5286  FAST_SAVE_DOUBLE(sb, "move_slow_penalty ", op->move_slow_penalty);
5287  }
5288 
5289  // Make sure we save sound_chance overrides, or sound chance only works on the initial map load.
5290  if (op->sound_chance != op2->sound_chance) {
5291  FAST_SAVE_LONG(sb, "sound_chance ", op->sound_chance);
5292  }
5293 
5294  ob_flags diff_flags;
5295  compare_flags(&diff_flags, op, op2);
5296  int flag;
5297  while ((flag = flags_differ(&diff_flags)) != -1) {
5298  if (flag_names[flag]) {
5299  ADD_STRINGLINE_ENTRY(sb, flag_names[flag], QUERY_FLAG(op, flag) ? " 1" : " 0");
5300  }
5301  }
5302 
5303  /* Save body locations */
5304  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
5305  if (op->body_info[i] != op2->body_info[i]) {
5306  stringbuffer_append_string(sb, body_locations[i].save_name);
5307  FAST_SAVE_LONG(sb, " ", op->body_info[i]);
5308  }
5309  }
5310 }
5311 
5316 void save_object_in_sb(StringBuffer *sb, object *op, const int flag) {
5317  /* If the object has no_save set, just return */
5318  if (QUERY_FLAG(op, FLAG_NO_SAVE)) {
5319  return;
5320  }
5321 
5322  /* Even if the object does have an owner, it would seem that we should
5323  * still save it.
5324  */
5325  if (object_get_owner(op) != NULL) {
5326  return;
5327  }
5328 
5329  /* If it is unpaid and we don't want to save those, just return. */
5330  if (!(flag&SAVE_FLAG_SAVE_UNPAID) && (QUERY_FLAG(op, FLAG_UNPAID))) {
5331  return;
5332  }
5333 
5334  archetype *at = op->arch;
5335  if (at == NULL)
5336  at = empty_archetype;
5337 
5338  ADD_STRINGLINE_ENTRY(sb, "arch ", at->name);
5339 
5340  if (at->reference_count > 0) {
5341  /* The object is a custom item/monster, so we handle its save differently.
5342  * We compare the custom archetype to the "original" one, then only save hp/gr/sp
5343  * which are the only values we can't recompute later - all others are modified by items in inventory.
5344  * Note that hp/gr/sp will appear twice in save, but last value will take precedence.
5345  */
5346  archetype *original = find_archetype(at->name);
5347  if (!original) {
5348  LOG(llevError, "could not find original archetype %s for custom monster!\n", at->name);
5349  abort();
5350  }
5351  get_ob_diff(sb, &at->clone, &original->clone);
5352  if (op->stats.hp != at->clone.stats.hp)
5353  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5354  if (op->stats.sp != at->clone.stats.sp)
5355  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5356  if (op->stats.grace != at->clone.stats.grace)
5357  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5358  if (op->x != at->clone.x)
5359  FAST_SAVE_LONG(sb, "x ", op->x);
5360  if (op->y != at->clone.y)
5361  FAST_SAVE_LONG(sb, "y ", op->y);
5362  } else if (op->artifact != NULL) {
5363  /* if op is an artifact, then find the "standard" artifact to use that for the diff */
5364  object *base;
5365  const artifact *artifact;
5366 
5367  artifact = find_artifact(op, op->artifact);
5368  if (artifact == NULL) {
5369  LOG(llevError, "could not find artifact %s [%d] to save data\n", op->artifact, op->type);
5370  get_ob_diff(sb, op, &at->clone);
5371  } else {
5372  ADD_STRINGLINE_ENTRY(sb, "artifact ", op->artifact);
5373  base = arch_to_object(at);
5375  get_ob_diff(sb, op, base);
5377  }
5378  } else {
5379  get_ob_diff(sb, op, &at->clone);
5380  }
5381 
5382  /* Eneq(@csd.uu.se): Added this to allow containers being saved with contents*/
5383  FOR_INV_PREPARE(op, tmp)
5384  save_object_in_sb(sb, tmp, flag);
5385  FOR_INV_FINISH();
5386 
5387  stringbuffer_append_string(sb, "end\n");
5388 }
5389 
5402 int save_object(FILE *fp, object *op, int flag) {
5404  save_object_in_sb(sb, op, flag);
5405  char *cp = stringbuffer_finish(sb);
5406  if (fputs(cp, fp) == EOF) {
5407  free(cp);
5408  return SAVE_ERROR_WRITE;
5409  } else {
5410  free(cp);
5411  return SAVE_ERROR_OK;
5412  }
5413 }
5414 
5416  if (op->map) {
5417  sstring death_animation = object_get_value(op, "death_animation");
5418  if (death_animation != NULL && strcmp(death_animation, "NONE")) {
5419  object *death = create_archetype(death_animation);
5420 
5421  if (death != NULL) {
5422  object_insert_in_map_at(death, op->map, op, 0, op->x, op->y);
5423  if (death->arch->more)
5424  object_fix_multipart(death);
5425  }
5426  }
5427  }
5428 }
5429 
5430 object *find_force(object *op, const char *name) {
5431  assert(op != NULL);
5433 }
5434 
5435 object *add_force(object *op, const char *name, int duration) {
5436  assert(op != NULL);
5437  object *force = find_force(op, name);
5438  if (force == NULL) {
5439  force = create_archetype(FORCE_NAME);
5440  force->slaying = add_string(name);
5441  object_insert_in_ob(force, op);
5442  }
5443 
5444  if (duration != 0) {
5445  force->speed = 0.01;
5446  force->speed_left = -duration;
5447  } else {
5448  force->speed = 0;
5449  }
5450 
5451  // Even if duration is zero, a force could be set previously.
5452  object_update_speed(force);
5453 
5454  return force;
5455 }
FLAG_IS_TURNABLE
#define FLAG_IS_TURNABLE
Object can change face with direction.
Definition: define.h:243
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
Settings::casting_time
uint8_t casting_time
It takes awhile to cast a spell.
Definition: global.h:274
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4372
free_objects
static object * free_objects
Pointer to the list of unused objects.
Definition: object.cpp:297
Face::name
sstring name
Face name, as used by archetypes and such.
Definition: face.h:19
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:325
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:175
player::do_los
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:143
init_objects
void init_objects(void)
Sets up and initialises the linked list of free and used objects.
Definition: object.cpp:331
living::exp
int64_t exp
Experience.
Definition: living.h:47
SPELL_MAPPINGS
#define SPELL_MAPPINGS
Definition: global.h:158
object::weapon_speed_left
float weapon_speed_left
How much speed is left to spend this round.
Definition: object.h:342
PLAYER
@ PLAYER
Definition: object.h:112
object_get_owner_const
static const object * object_get_owner_const(const object *op)
Returns the object which this object marks as being the owner, constant version.
Definition: object.cpp:612
object_get_owner
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:798
player::next
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:108
FREE_AND_CLEAR_STR_IF
#define FREE_AND_CLEAR_STR_IF(xyz)
Definition: global.h:206
global.h
UPD_FACE
#define UPD_FACE
Definition: newclient.h:321
object_find_by_type_subtype
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Find object in inventory.
Definition: object.cpp:4297
object_clear_owner
void object_clear_owner(object *op)
Clears the owner of specified object.
Definition: object.cpp:817
first_player
player * first_player
First player.
Definition: init.cpp:106
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
MOVE_WALK
#define MOVE_WALK
Object walks.
Definition: define.h:383
object::range_modifier
uint8_t range_modifier
How going up in level affects range
Definition: object.h:420
object::move_status
int32_t move_status
What stage in attack mode.
Definition: object.h:402
object_get_env_recursive
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.cpp:578
object_update_turn_face
void object_update_turn_face(object *op)
If an object with the IS_TURNABLE() flag needs to be turned due to the closest player being on the ot...
Definition: object.cpp:1327
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:714
FLAG_NO_APPLY
#define FLAG_NO_APPLY
Avoids step_on/fly_on to this object.
Definition: define.h:288
remove_friendly_object
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
object::owner
object * owner
Pointer to the object which controls this one.
Definition: object.h:389
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
SCRIPT_FIX_NOTHING
#define SCRIPT_FIX_NOTHING
Definition: global.h:382
object_count_active
int object_count_active(void)
Objects statistics.
Definition: object.cpp:1779
object_find_by_type_applied
object * object_find_by_type_applied(const object *who, int type)
Find applied object in inventory.
Definition: object.cpp:4079
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Number of body locations.
Definition: object.h:15
object::weapontype
uint32_t weapontype
Type of weapon.
Definition: object.h:383
object::map_layer
uint8_t map_layer
What level to draw this on the map.
Definition: object.h:436
find_artifact
const artifact * find_artifact(const object *op, const char *name)
Searches and returns a specific artifact compatible with an object, NULL if not found.
Definition: artifact.cpp:585
GET_MAP_TOP
#define GET_MAP_TOP(M, X, Y)
Gets the top object on a map.
Definition: map.h:177
statistics
struct Statistics statistics
Merged spell statistics.
Definition: init.cpp:226
llevError
@ llevError
Problems requiring server admin to fix.
Definition: logger.h:11
object_set_flag_inv
void object_set_flag_inv(object *op, int flag)
Activate recursively a flag on an object's inventory.
Definition: object.cpp:3235
P_BLOCKSVIEW
#define P_BLOCKSVIEW
This spot blocks the player's view.
Definition: map.h:231
FABS
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
FLAG_ANIMATE
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:229
EVENT_CONNECTOR
@ EVENT_CONNECTOR
Lauwenmark: an invisible object holding a plugin event hook.
Definition: object.h:232
find_skill_by_number
object * find_skill_by_number(object *who, int skillno)
This returns the first skill pointer of the given subtype (the one that accumulates exp,...
Definition: main.cpp:389
object::path_attuned
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:355
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:82
ADD_STRINGLINE_ENTRY
static void ADD_STRINGLINE_ENTRY(StringBuffer *sb, const char *name, const char *value)
Adds a line to the buffer.
Definition: object.cpp:4938
INS_MAP_LOAD
#define INS_MAP_LOAD
Disable lots of checkings.
Definition: object.h:586
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:369
archetype::more
archetype * more
Next part of a linked object.
Definition: object.h:488
player
One player.
Definition: player.h:107
object::client_type
uint16_t client_type
Public type information.
Definition: object.h:352
object_free_all_data
void object_free_all_data(void)
Destroys all allocated objects.
Definition: object.cpp:759
FLAG_IS_LINKED
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:302
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:300
Statistics::spell_merges
uint64_t spell_merges
Number of spell merges done.
Definition: global.h:355
SIZEOFFREE1
#define SIZEOFFREE1
Definition: define.h:153
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:371
map_find_by_archetype
object * map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at)
Searches for any objects with a matching archetype at the given map and coordinates.
Definition: object.cpp:3114
object::ownercount
tag_t ownercount
What count the owner had (in case owner has been freed)
Definition: object.h:392
object_merge
object * object_merge(object *op, object *top)
This function goes through all objects below and including top, and merges op to the first matching o...
Definition: object.cpp:2047
STARTMAX
#define STARTMAX
How big array of objects to start with.
Definition: config.h:522
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.cpp:79
FALSE
#define FALSE
Definition: compat.h:14
update_position
void update_position(mapstruct *m, int x, int y)
This function updates various attributes about a specific space on the map (what it looks like,...
Definition: map.cpp:2127
BITMASK_EVENT
#define BITMASK_EVENT(evt)
Convert an event to its bit.
Definition: events.h:77
SET_MAP_TOP
#define SET_MAP_TOP(M, X, Y, tmp)
Sets the top object on a map.
Definition: map.h:182
object::item_power
int8_t item_power
Power rating of the object.
Definition: object.h:374
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:233
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:426
P_NO_CLERIC
#define P_NO_CLERIC
No clerical spells cast here.
Definition: map.h:243
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:24
mapstruct::players
int16_t players
How many players are on this level right now.
Definition: map.h:338
object::attack_movement
uint16_t attack_movement
What kind of attack movement.
Definition: object.h:403
absdir
int absdir(int d)
Computes an absolute direction.
Definition: object.cpp:3710
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:320
flag_names
static const char *const flag_names[NUM_FLAGS+1]
This is a list of pointers that correspond to the FLAG_.
Definition: object.cpp:4856
object::range
int8_t range
Range of the spell.
Definition: object.h:419
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:339
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.cpp:909
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)
Inserts an object into its map.
Definition: object.cpp:4796
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:372
living::Dex
int8_t Dex
Definition: living.h:36
TRAP
@ TRAP
Definition: object.h:246
object::x
int16_t x
Definition: object.h:337
OB_SPELL_TAG_MATCH
#define OB_SPELL_TAG_MATCH(op, count)
Check whether a tag matches in the tags.
Definition: object.h:95
player::ob
object * ob
The object representing the player.
Definition: player.h:179
object_dump_all
void object_dump_all(void)
Dumps all objects to console.
Definition: object.cpp:692
UP_OBJ_CHANGE
#define UP_OBJ_CHANGE
Object changed.
Definition: object.h:533
player::transport
object * transport
Transport the player is in.
Definition: player.h:216
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:340
give_artifact_abilities
void give_artifact_abilities(object *op, const object *artifact)
Fixes the given object, giving it the abilities and titles it should have due to the second artifact-...
Definition: artifact.cpp:230
object::pick_up
uint8_t pick_up
See crossfire.doc.
Definition: object.h:373
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:131
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:307
object::anim_suffix
sstring anim_suffix
Used to determine combined animations.
Definition: object.h:326
key_value
Each object (this also means archetypes!) could have a few of these "dangling" from it; this could al...
Definition: object.h:42
object_find_first_free_spot
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
object_find_first_free_spot(archetype, mapstruct, x, y) works like object_find_free_spot(),...
Definition: object.cpp:3595
MoveType
unsigned char MoveType
Typdef here to define type large enough to hold bitmask of all movement types.
Definition: define.h:409
arch_present_in_ob
object * arch_present_in_ob(const archetype *at, const object *op)
Searches for any objects with a matching archetype in the inventory of the given object.
Definition: object.cpp:3218
object_set_owner
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner's current skill and experience objects.
Definition: object.cpp:834
object_set_value_s
static int object_set_value_s(object *, const char *, const char *, int)
object::expmul
double expmul
needed experience = (calc_exp*expmul) - means some races/classes can need less/more exp to gain level...
Definition: object.h:409
object_handle_death_animation
void object_handle_death_animation(object *op)
Definition: object.cpp:5415
UP_OBJ_INSERT
#define UP_OBJ_INSERT
Object was inserted.
Definition: object.h:531
artifact::item
object * item
Special values of the artifact.
Definition: artifact.h:15
CALLOC
#define CALLOC(x, y)
Definition: compat.h:31
GET_MAP_MOVE_SLOW
#define GET_MAP_MOVE_SLOW(M, X, Y)
Gets the slowing state of a square.
Definition: map.h:202
object_reset
void object_reset(object *op)
Totally resets the specified object, without freeing associated memory.
Definition: object.cpp:928
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
object::direction
int8_t direction
Means the object is moving that way.
Definition: object.h:346
flags
static const flag_definition flags[]
Flag mapping.
Definition: gridarta-types-convert.cpp:101
object::count
tag_t count
Unique object number for this object.
Definition: object.h:309
object::last_grace
int16_t last_grace
As last_sp, except for grace.
Definition: object.h:371
RUNE
@ RUNE
Definition: object.h:245
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.cpp:1186
object::smoothlevel
uint8_t smoothlevel
how to smooth this square around
Definition: object.h:435
fix_object
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
object_find_by_flag_applied
object * object_find_by_flag_applied(const object *who, int flag)
Find applied object in inventory by flag.
Definition: object.cpp:4225
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)
Sets hx and hy to the coords to insert a possibly multi-tile ob at, within radius of generator,...
Definition: object.cpp:3408
object_find_by_type_and_skill
object * object_find_by_type_and_skill(const object *who, int type, const char *skill)
Find object in inventory by type and skill.
Definition: object.cpp:4179
FREE_OBJ_FREE_INVENTORY
#define FREE_OBJ_FREE_INVENTORY
Free inventory objects; if not set, drop inventory.
Definition: object.h:545
GET_MAP_PLAYER
#define GET_MAP_PLAYER(M, X, Y)
Definition: map.h:171
blank_face
const Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.cpp:36
llevMonster
@ llevMonster
Many many details.
Definition: logger.h:16
key_value::key
sstring key
Name of the key.
Definition: object.h:43
flags_differ
int flags_differ(ob_flags *diff)
Return the index of the first difference in the given object flag difference set (computed by compare...
Definition: object.cpp:4962
TRANSPORT
@ TRANSPORT
see doc/Developers/objects
Definition: object.h:113
player::hidden
uint32_t hidden
If True, player (DM) is hidden from view.
Definition: player.h:149
FLAG_DIALOG_PARSED
#define FLAG_DIALOG_PARSED
Was the object::msg field parsed? Temporary flag not saved.
Definition: define.h:230
UPD_NROF
#define UPD_NROF
Definition: newclient.h:325
FOR_ABOVE_PREPARE
#define FOR_ABOVE_PREPARE(op_, it_)
Constructs a loop iterating over all objects above an object.
Definition: define.h:671
object_copy_with_inv
void object_copy_with_inv(const object *src_ob, object *dest_ob, bool update_speed)
Copy an object with an inventory, duplicate the inv too.
Definition: object.cpp:1202
object::enemy
object * enemy
Monster/player to follow even if not closest.
Definition: object.h:393
object::key_values
key_value * key_values
Fields not explictly known by the loader.
Definition: object.h:446
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:15
stringbuffer_append_char
void stringbuffer_append_char(StringBuffer *sb, const char c)
Append a character to a string buffer instance.
Definition: stringbuffer.cpp:48
skills.h
free_arch
void free_arch(archetype *at)
Frees archetype.
Definition: arch.cpp:167
object::title
sstring title
Of foo, etc.
Definition: object.h:327
MAP_DARKNESS
#define MAP_DARKNESS(m)
Map darkness level (0-MAX_DARKNESS)
Definition: map.h:73
FLAG_IS_HILLY
#define FLAG_IS_HILLY
Item is hilly/mountain terrain.
Definition: define.h:319
FOR_OB_AND_ABOVE_FINISH
#define FOR_OB_AND_ABOVE_FINISH()
Finishes FOR_OB_AND_ABOVE_PREPARE().
Definition: define.h:727
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:303
object_find_by_tag_global
object * object_find_by_tag_global(tag_t i)
Returns the object which has the count-variable equal to the argument.
Definition: object.cpp:715
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:360
Statistics::spell_hash_full
uint64_t spell_hash_full
Number of times spell hash was full.
Definition: global.h:356
object::level
int16_t level
Level of creature or object.
Definition: object.h:363
expand_objects
static void expand_objects(void)
Allocates more objects for the list of unused objects.
Definition: object.cpp:1225
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Execute an event on the specified object.
Definition: events.cpp:309
object_merge_spell
void object_merge_spell(object *op, int16_t x, int16_t y)
This sees if there are any objects on the space that can merge with op.
Definition: object.cpp:2125
active_objects
object * active_objects
List of active objects that need to be processed.
Definition: object.cpp:298
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2853
object::will_apply
uint8_t will_apply
See crossfire.doc and What monsters apply.
Definition: object.h:404
UP_OBJ_REMOVE
#define UP_OBJ_REMOVE
Object was removed.
Definition: object.h:532
object::above
object * above
Pointer to the object stacked above this one.
Definition: object.h:298
HUGE_BUF
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
FAST_SAVE_DOUBLE
static void FAST_SAVE_DOUBLE(StringBuffer *sb, const char *name, const double value)
Adds a double to the buffer.
Definition: object.cpp:4952
stringbuffer_append_int64
void stringbuffer_append_int64(StringBuffer *sb, int64_t x)
Append a signed integer to a string buffer instance.
Definition: stringbuffer.cpp:52
MAX
#define MAX(x, y)
Definition: compat.h:24
OBJECT_INVALID
const tag_t OBJECT_INVALID
Definition: object.h:261
ob_move_on
method_ret ob_move_on(object *op, object *victim, object *originator)
Makes an object move on top of another one.
Definition: ob_methods.cpp:134
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:353
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:307
object::path_denied
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:357
object_clear
void object_clear(object *op)
Frees everything allocated by an object, and also clears all variables and flags to default settings.
Definition: object.cpp:977
esrv_send_item
void esrv_send_item(object *pl, object *op)
Sends item's info to player.
Definition: main.cpp:362
socket_struct::update_look
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:109
FOR_OB_AND_ABOVE_PREPARE
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Constructs a loop iterating over an object and all objects above it in the same pile.
Definition: define.h:723
object::carrying
int32_t carrying
How much weight this object contains.
Definition: object.h:379
LOOK_OBJ
#define LOOK_OBJ(ob)
This returns TRUE if the object is something that should be displayed in the look window.
Definition: object.h:522
stringbuffer.h
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
object::path_repelled
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:356
object::y
int16_t y
Position in the map for this object.
Definition: object.h:337
object_find_by_type_and_race
object * object_find_by_type_and_race(const object *who, int type, const char *race)
Find object in inventory by type and race.
Definition: object.cpp:4129
m
static event_registration m
Definition: citylife.cpp:427
MOVE_ALL
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:389
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.cpp:32
OBJ_EXPAND
#define OBJ_EXPAND
How big steps to use when expanding array.
Definition: config.h:523
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220
get_button_value
int get_button_value(const object *button)
Returns the first value linked to this button.
Definition: button.cpp:751
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1555
object_update
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1429
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:286
FMT64
#define FMT64
Definition: compat.h:16
NROF
static uint32_t NROF(const object *const ob)
Returns ob->nrof, unless it is 0, in which case return 1.
Definition: object.h:626
object_find_by_name
object * object_find_by_name(const object *who, const char *name)
Finds an object in inventory name.
Definition: object.cpp:3952
ob_flags
uint32_t ob_flags[4]
Definition: object.h:259
object_get_key_value
key_value * object_get_key_value(const object *ob, const char *key)
Search for a field by key.
Definition: object.cpp:4317
object::last_heal
int32_t last_heal
Last healed.
Definition: object.h:369
object_find_by_type2
object * object_find_by_type2(const object *who, int type1, int type2)
Find object in inventory.
Definition: object.cpp:4033
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:351
add_refcount
sstring add_refcount(sstring str)
Like add_string(), but the string is already a shared string.
Definition: shstr.cpp:224
object_value_set_shared
bool object_value_set_shared(const object *op, sstring key)
Determine if an extra value is set to a non empty or 0 value.
Definition: object.cpp:4386
FLAG_NO_DROP
#define FLAG_NO_DROP
Object can't be dropped.
Definition: define.h:275
freearr_y
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:309
key_value::next
key_value * next
Next key in the list.
Definition: object.h:45
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:223
P_NO_MAGIC
#define P_NO_MAGIC
Spells (some) can't pass this object.
Definition: map.h:232
object_present_in_ob_by_name
object * object_present_in_ob_by_name(int type, const char *str, const object *op)
Searches for any objects with a matching type & name variable in the inventory of the given object.
Definition: object.cpp:3199
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:593
map_find_by_type
object * map_find_by_type(mapstruct *m, int x, int y, uint8_t type)
Searches for any objects with a matching type variable at the given map and coordinates.
Definition: object.cpp:3141
object::weapon_speed
float weapon_speed
The overall speed of this object.
Definition: object.h:341
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:546
can_see_monsterP
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
Recursive routine to see if we can find a path to a certain point.
Definition: object.cpp:3818
object::prev
object * prev
Pointer to the previous object in the free/used list.
Definition: object.h:288
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Deallocate the string buffer instance and return the string as a shared string.
Definition: stringbuffer.cpp:38
SAVE_FLAG_SAVE_UNPAID
#define SAVE_FLAG_SAVE_UNPAID
If set, unpaid items will be saved.
Definition: map.h:111
FOR_ABOVE_FINISH
#define FOR_ABOVE_FINISH()
Finishes FOR_ABOVE_PREPARE().
Definition: define.h:678
FLAG_NO_MAGIC
#define FLAG_NO_MAGIC
Spells (some) can't pass this object.
Definition: define.h:263
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:489
object::run_away
uint8_t run_away
Monster runs away if it's hp goes below this percentage.
Definition: object.h:396
object_dump
void object_dump(const object *op, StringBuffer *sb)
Dumps an object.
Definition: object.cpp:633
object::ox
int16_t ox
Definition: object.h:338
object::weight_limit
int32_t weight_limit
Weight-limit of object.
Definition: object.h:378
add_string
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
speed
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters speed
Definition: stats.txt:23
treasurelist::name
sstring name
Usually monster-name/combination.
Definition: treasure.h:87
StringBuffer
std::string StringBuffer
The string buffer state.
Definition: stringbuffer.h:33
object_count_free
int object_count_free(void)
Objects statistics.
Definition: object.cpp:1747
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:738
object_get_multi_size
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Computes the size of a multitile object.
Definition: object.cpp:4749
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:608
CONTAINER
@ CONTAINER
Definition: object.h:236
object::below
object * below
Pointer to the object stacked below this one.
Definition: object.h:297
object::casting_time
int16_t casting_time
Time left before spell goes off.
Definition: object.h:416
object::move_type
MoveType move_type
Type of movement this object uses.
Definition: object.h:438
object_find_by_type_and_name
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Find object in inventory by type and name.
Definition: object.cpp:4104
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
query_short_name(object) is similar to query_name(), but doesn't contain any information about object...
Definition: item.cpp:518
object::event_bitmask
uint64_t event_bitmask
Bitmask of events this object has a handler for, see events.h.
Definition: object.h:449
FLAG_CLIENT_ANIM_RANDOM
#define FLAG_CLIENT_ANIM_RANDOM
Client animate this, randomized.
Definition: define.h:228
object::face
const Face * face
Face with colors.
Definition: object.h:343
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Return 1 if coordinates X and Y are out of the map M, taking into account tiling.
Definition: map.cpp:2303
find_string
sstring find_string(const char *str)
Searches a string in the shared strings.
Definition: shstr.cpp:250
FLAG_NO_STEAL
#define FLAG_NO_STEAL
Item can't be stolen.
Definition: define.h:329
object::last_eat
int32_t last_eat
How long since we last ate.
Definition: object.h:368
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:362
object_update_speed
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.cpp:1344
SAVE_ERROR_WRITE
#define SAVE_ERROR_WRITE
Write error.
Definition: map.h:147
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:350
NUM_FLAGS
#define NUM_FLAGS
Should always be equal to the last defined flag.
Definition: define.h:361
living::dam
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
object::magic
int8_t magic
Any magical bonuses to this item.
Definition: object.h:360
SET_MAP_FLAGS
#define SET_MAP_FLAGS(M, X, Y, C)
Sets map flags.
Definition: map.h:164
object::active_prev
object * active_prev
Previous object in the 'active list This is used in process_events so that the entire object list doe...
Definition: object.h:293
FLAG_BLOCKSVIEW
#define FLAG_BLOCKSVIEW
Object blocks view.
Definition: define.h:256
object::materialname
sstring materialname
Specific material name.
Definition: object.h:358
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:319
object_find_by_tag
object * object_find_by_tag(const object *who, tag_t tag)
Find object in inventory.
Definition: object.cpp:4056
object_find_by_flag
object * object_find_by_flag(const object *who, int flag)
Find object in inventory by flag.
Definition: object.cpp:4202
object_free
void object_free(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1587
LAMP
@ LAMP
Lamp.
Definition: object.h:206
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:197
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:661
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:226
FLAG_NO_SAVE
#define FLAG_NO_SAVE
If set (through plugins), the object is not saved on maps.
Definition: define.h:231
P_PLAYER
#define P_PLAYER
There is a player on this space.
Definition: map.h:241
INS_ON_TOP
#define INS_ON_TOP
Always put object on top.
Definition: object.h:584
object::move_on
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:441
living::food
int32_t food
How much food in stomach.
Definition: living.h:48
resist_save
const char *const resist_save[NROFATTACKS]
Attack types.
Definition: init.cpp:31
P_NEED_UPDATE
#define P_NEED_UPDATE
This space is out of date.
Definition: map.h:244
FLAG_IS_A_TEMPLATE
#define FLAG_IS_A_TEMPLATE
Object has no ingame life until instantiated.
Definition: define.h:353
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
body_locations
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
The ordering of this is actually doesn't make a difference However, for ease of use,...
Definition: item.cpp:56
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:485
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.cpp:4571
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)
Sets hx and hy to the coords to insert a possibly multi-tile ob at, around gen.
Definition: object.cpp:3292
sproto.h
living::sp
int16_t sp
Spell points.
Definition: living.h:42
nrofallocobjects
int nrofallocobjects
How many OBs allocated (free + used)
Definition: object.cpp:293
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.cpp:44
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.cpp:2331
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:289
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:734
living::Int
int8_t Int
Definition: living.h:36
object::sound_chance
uint8_t sound_chance
Probability, 1 to 100, of the object emitting a sound.
Definition: object.h:405
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Object is an overlay floor.
Definition: define.h:242
object::race
sstring race
Human, goblin, dragon, etc.
Definition: object.h:328
compare_flags
static void compare_flags(ob_flags *ret, const object *p, const object *q)
Definition: object.h:500
object::animation
const Animations * animation
Animation of this item, NULL if not animated.
Definition: object.h:430
GET_MAP_MOVE_ON
#define GET_MAP_MOVE_ON(M, X, Y)
Gets the move_on state of a square.
Definition: map.h:207
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Don't call check_walk_on against the originator.
Definition: object.h:583
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Returns true if the given object can't fit in the given spot.
Definition: map.cpp:469
weight
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be and may attack the nearest of your enemies Others can be in that they follow you around and help you in your quest to kill enemies and find treasure SPECIAL ITEMS There are many special items which can be found in of these the most important may be the signs all a player must do is apply the handle In the case of the player must move items over the button to hold it down Some of the larger buttons may need very large items to be moved onto before they can be activated Gates and locked but be for you could fall down into a pit full of ghosts or dragons and not be able to get back out Break away sometimes it may be worth a player s time to test the walls of a map for secret doors Fire such as missile weapons and spells you will notice them going up in smoke ! So be careful not to destroy valuable items Spellbooks sometimes a player can learn the other times they cannot There are many different types of books and scrolls out there Improve item have lower weight
Definition: survival-guide.txt:100
object_find_by_type_without_flags
object * object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags)
Find an object in inventory that does not have any of the provided flags set.
Definition: object.cpp:4000
reduction_dir
static const int reduction_dir[SIZEOFFREE][3]
Basically, this is a table of directions, and what directions one could go to go back to us.
Definition: object.cpp:3748
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2096
object::other_arch
struct archetype * other_arch
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:427
artifact
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn though Notes on Specific and settings file datadir Usually usr share crossfire Contains data that the server does not need to modify while such as the etc A default install will pack the artifact
Definition: server-directories.txt:46
object_create_clone
object * object_create_clone(object *asrc)
Create clone from object to another.
Definition: object.cpp:3905
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:316
object_copy_no_speed
void object_copy_no_speed(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.cpp:1055
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:595
MAP_WIDTH
#define MAP_WIDTH(m)
Map width.
Definition: map.h:76
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
move_name
const char *const move_name[]
Maps the MOVE_* values to names.
Definition: object.cpp:4837
d
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for d
Definition: INSTALL_WIN32.txt:13
object_set_cheat
void object_set_cheat(object *op)
object_set_cheat(object) sets the cheat flag (WAS_WIZ) in the object and in all it's inventory (recur...
Definition: object.cpp:3270
object_new
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it.
Definition: object.cpp:1267
object_insert_in_map
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
This function inserts the object in the two-way linked list which represents what is on a map.
Definition: object.cpp:2357
esrv_del_item
void esrv_del_item(player *pl, object *ob)
Tells the client to delete an item.
Definition: main.cpp:395
object::head
object * head
Points to the main object of a large body.
Definition: object.h:306
create_archetype
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.cpp:276
object_present_in_ob
object * object_present_in_ob(uint8_t type, const object *op)
Searches for any objects with a matching type variable in the inventory of the given object.
Definition: object.cpp:3164
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2373
object::weight
int32_t weight
Attributes of the object.
Definition: object.h:377
nroffreeobjects
int nroffreeobjects
How many OBs allocated and free (free)
Definition: object.cpp:292
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
object_map
static std::map< tag_t, object * > object_map
Definition: object.cpp:300
object::move_slow
MoveType move_slow
Movement types this slows down.
Definition: object.h:443
object::spell_tags
tag_t * spell_tags
Tags used for spell effect merging.
Definition: object.h:448
spell_mapping
const char *const spell_mapping[SPELL_MAPPINGS]
This table is only necessary to convert objects that existed before the spell object conversion to th...
Definition: object.cpp:76
living::wc
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
offsetof
#define offsetof(type, member)
The offsetof macro is part of ANSI C, but many compilers lack it, for example "gcc -ansi".
Definition: shstr.h:37
object::move_slow_penalty
float move_slow_penalty
How much this slows down the object.
Definition: object.h:444
RANDOM
#define RANDOM()
Definition: define.h:628
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:204
living::maxgrace
int16_t maxgrace
Maximum grace.
Definition: living.h:45
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:304
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:707
ob_count
long ob_count
Definition: init.cpp:123
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:222
get_search_arr
void get_search_arr(int *search_arr)
New function to make monster searching more efficient, and effective! This basically returns a random...
Definition: object.cpp:3638
find_dir_2
int find_dir_2(int x, int y)
Computes a direction which you should travel to move of x and y.
Definition: object.cpp:3673
living::Wis
int8_t Wis
Definition: living.h:36
object_add_weight
void object_add_weight(object *op, signed long weight)
object_add_weight(object, weight) adds the specified weight to an object, and also updates how much t...
Definition: object.cpp:2829
above
Magical Runes Runes are magical inscriptions on the dungeon which cast a spell or detonate when something steps on them Flying objects don t detonate runes Beware ! Runes are invisible most of the time They are only visible occasionally ! There are several runes which are there are some special runes which may only be called with the invoke and people may apply it to read it Maybe useful for mazes ! This rune will not nor is it ordinarily invisible Partial Visibility of they ll be visible only part of the time They have so the higher your the better hidden the runes you make are Examples of whichever way you re facing invoke magic rune transfer as above
Definition: runes-guide.txt:50
object_decrease_nrof
object * object_decrease_nrof(object *op, uint32_t i)
Decreases a specified number from the amount of an object.
Definition: object.cpp:2672
object_find_by_type_and_slaying
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Find object in inventory by type and slaying.
Definition: object.cpp:4154
BITMASK_VALID
#define BITMASK_VALID
Bit indicating if the event bitmask is valid or not.
Definition: events.h:79
object::lore
sstring lore
Obscure information about this object, to get put into books and the like.
Definition: object.h:334
object::dam_modifier
uint8_t dam_modifier
How going up in level affects damage.
Definition: object.h:421
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:242
SK_WOODSMAN
@ SK_WOODSMAN
Woodsman.
Definition: skills.h:40
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:329
object::glow_radius
int8_t glow_radius
indicates the glow radius of the object
Definition: object.h:376
object::duration_modifier
uint8_t duration_modifier
how level modifies duration
Definition: object.h:418
object::name
sstring name
The name of the object, obviously...
Definition: object.h:321
INS_ABOVE_FLOOR_ONLY
#define INS_ABOVE_FLOOR_ONLY
Put object immediatly above the floor.
Definition: object.h:582
object_count_used
int object_count_used(void)
Object statistics.
Definition: object.cpp:1763
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Free the pointer and then set it to NULL.
Definition: global.h:199
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Find object in inventory by archetype name.
Definition: object.cpp:4248
SIZEOFFREE2
#define SIZEOFFREE2
Definition: define.h:154
object_can_pick
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.cpp:3863
objarray
static object objarray[STARTMAX]
All objects, allocated this way at first.
Definition: object.cpp:291
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_.
Definition: map.cpp:280
object::artifact
sstring artifact
If set, the item is the artifact with this name and the matching type.
Definition: object.h:324
object_find_by_type
object * object_find_by_type(const object *who, int type)
Find object in inventory.
Definition: object.cpp:3976
living::maxsp
int16_t maxsp
Max spell points.
Definition: living.h:43
mapstruct
This is a game-map.
Definition: map.h:320
object_find_by_name_global
object * object_find_by_name_global(const char *str)
Finds an object by name.
Definition: object.cpp:739
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:303
compare_ob_value_lists
static int compare_ob_value_lists(const object *, const object *)
Compares two object lists.
Definition: object.cpp:410
object::last_sp
int32_t last_sp
As last_heal, but for spell points.
Definition: object.h:370
sstring
const typedef char * sstring
Definition: sstring.h:2
EVENT_DESTROY
#define EVENT_DESTROY
Object destroyed (includes map reset/swapout)
Definition: events.h:34
floor
Magical Runes Runes are magical inscriptions on the dungeon floor
Definition: runes-guide.txt:3
living::Cha
int8_t Cha
Definition: living.h:36
P_NO_ERROR
#define P_NO_ERROR
Purely temporary - if set, update_position does not complain if the flags are different.
Definition: map.h:245
get_string_move_type
static void get_string_move_type(StringBuffer *sb, MoveType mt)
This returns a string of the integer movement type.
Definition: object.cpp:4897
object::gen_sp_armour
int8_t gen_sp_armour
Sp regen penalty this object has (was last_heal)
Definition: object.h:375
permute
static void permute(int *, int, int)
Randomly permutes an array.
Definition: object.cpp:3614
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:331
animate_object
void animate_object(object *op, int dir)
Updates the face-variable of an object.
Definition: anim.cpp:44
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:270
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
object_split(ob,nr) splits up ob into two parts.
Definition: object.cpp:2633
key_value::value
sstring value
Key's value.
Definition: object.h:44
AB_NO_PASS
#define AB_NO_PASS
Definition: map.h:240
object_find_free_spot
int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
object_find_free_spot(object, map, x, y, start, stop) will search for a spot at the given map and coo...
Definition: object.cpp:3555
mapstruct::in_memory
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:339
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
object_set_msg
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.cpp:4816
object::attacked_by_count
tag_t attacked_by_count
The tag of attacker, so we can be sure.
Definition: object.h:395
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:367
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:220
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:332
objects
static object * objects
Pointer to the list of used objects.
Definition: object.cpp:296
archetype::reference_count
int reference_count
How many times this temporary archetype is used.
Definition: object.h:492
object_unset_flag_inv
void object_unset_flag_inv(object *op, int flag)
Desactivate recursively a flag on an object inventory.
Definition: object.cpp:3252
object_free_key_values
void object_free_key_values(object *op)
Zero the key_values on op, decrementing the shared-string refcounts and freeing the links.
Definition: object.cpp:948
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4342
add_force
object * add_force(object *op, const char *name, int duration)
Add or return an existing force inside 'op' with the given 'name' and 'duration' in units of 100 tick...
Definition: object.cpp:5435
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:370
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:255
SET_MAP_OB
#define SET_MAP_OB(M, X, Y, tmp)
Sets the bottom object on a map.
Definition: map.h:180
living::ac
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
MAP_HEIGHT
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:78
save_object_in_sb
void save_object_in_sb(StringBuffer *sb, object *op, const int flag)
Store a string representation of op in sb.
Definition: object.cpp:5316
get_ob_diff
void get_ob_diff(StringBuffer *sb, const object *op, const object *op2)
Returns a pointer to a static string which contains all variables which are different in the two give...
Definition: object.cpp:4988
object::attacked_by
object * attacked_by
This object start to attack us! only player & monster.
Definition: object.h:394
object::duration
int16_t duration
Number of moves (see 'speed') spell lasts.
Definition: object.h:417
object_remove_from_active_list
void object_remove_from_active_list(object *op)
This function removes object 'op' from the list of active objects.
Definition: object.cpp:1387
object_find_by_type_and_arch_name
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
Find object in inventory by type and archetype name.
Definition: object.cpp:4273
INS_NO_MERGE
#define INS_NO_MERGE
Don't try to merge with other items.
Definition: object.h:581
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
UP_OBJ_FACE
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:534
FLAG_CLIENT_ANIM_SYNC
#define FLAG_CLIENT_ANIM_SYNC
Let client animate this, synchronized.
Definition: define.h:227
player::count
uint32_t count
Any numbers typed before a command.
Definition: player.h:124
find_insert_pos
static object * find_insert_pos(object *op, const int flag)
Definition: object.cpp:2293
FLAG_NO_FIX_PLAYER
#define FLAG_NO_FIX_PLAYER
fix_object() won't be called
Definition: define.h:264
strcasecmp
int strcasecmp(const char *s1, const char *s2)
object::flags
ob_flags flags
Various flags.
Definition: object.h:429
object_distance
int object_distance(const object *ob1, const object *ob2)
Return the square of the distance between the two given objects.
Definition: object.cpp:3657
find_force
object * find_force(object *op, const char *name)
Find a force with the given 'name' in the slaying field.
Definition: object.cpp:5430
MIN_ACTIVE_SPEED
#define MIN_ACTIVE_SPEED
Cut off point of when an object is put on the active list or not.
Definition: define.h:623
object::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Body info as loaded from the file.
Definition: object.h:384
MOVE_FLY_HIGH
#define MOVE_FLY_HIGH
High flying object.
Definition: define.h:385
loader.h
object_fix_multipart
void object_fix_multipart(object *tmp)
Ensures specified object has its more parts correctly inserted in map.
Definition: object.cpp:4690
object::randomitems
struct treasurelist * randomitems
Items to be generated.
Definition: object.h:397
FREE_OBJ_DROP_ABOVE_FLOOR
#define FREE_OBJ_DROP_ABOVE_FLOOR
If FREE_OBJ_FREE_INVENTORY is not set, drop inventory just above ground instead on top.
Definition: object.h:547
object::elevation
int elevation
Definition: object.h:452
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
NEVER SET THIS.
Definition: define.h:344
GET_MAP_MOVE_OFF
#define GET_MAP_MOVE_OFF(M, X, Y)
Gets the move_off state of a square.
Definition: map.h:212
object::container
object * container
Current container being used.
Definition: object.h:301
object::active_next
object * active_next
Next object in the 'active' list This is used in process_events so that the entire object list does n...
Definition: object.h:289
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1829
GET_MAP_FLAGS
#define GET_MAP_FLAGS(M, X, Y)
Gets map flags.
Definition: map.h:162
object::move_off
MoveType move_off
Move types affected moving off this space.
Definition: object.h:442
empty_archetype
archetype * empty_archetype
Nice to have fast access to it.
Definition: init.cpp:119
freedir
int freedir[SIZEOFFREE]
Direction we're pointing on this spot.
Definition: object.cpp:321
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:384
object_check_move_on
int object_check_move_on(object *op, object *originator)
Checks if any objects has a move_type that matches objects that effect this object on this space.
Definition: object.cpp:3008
update_all_los
void update_all_los(const mapstruct *map, int x, int y)
This function makes sure that update_los() will be called for all players on the given map within the...
Definition: los.cpp:595
object::state
uint8_t state
How the object was last drawn (animation)
Definition: object.h:361
object_copy_owner
void object_copy_owner(object *op, object *clone)
Set the owner to clone's current owner and set the skill and experience objects to clone's objects (t...
Definition: object.cpp:887
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:486
SCROLL
@ SCROLL
Definition: object.h:226
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:344
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:221
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:109
object_increase_nrof
static void object_increase_nrof(object *op, uint32_t i)
Increase the count of an object.
Definition: object.cpp:2759
living::grace
int16_t grace
Grace.
Definition: living.h:44
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:691
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:380
object::move_allow
MoveType move_allow
What movement types explicitly allowed.
Definition: object.h:440
artifact
This is one artifact, ie one special item.
Definition: artifact.h:14
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Updates the key in op to value.
Definition: object.cpp:4495
object::more
object * more
Pointer to the rest of a large body of objects.
Definition: object.h:305
it
if you malloc the data for the make sure to free it when done There is also the newclient h file which is shared between the client and server This file contains the definition of the as well as many defined values for constants of varying you will need to grab these constant values for yourself Many of the constants in this file are used in the protocol to denote types Image Caching ~ Image caching has been implemented on the with necessary server support to handle it This section will briefly describe how image caching works on the protocol as well as how the current client does it the client checks for an option denoting the image caching is desired If we initialize all the images to a default value this means we don t need to put special checks into the drawing code to see if we have an image we just draw the default we know what filename to store it as we request the server to do image caching This is done by or ing the cache directive to the image mode we want C when the server finds an image number that it has not send to the it sends us a name command information us the number to name and there is no space between that the and the name Such formating is difficult but the above example illustrates the data is sent The client then checks for the existence of the image locally It is up to the client to organize images and then splits them into sub directories based on the first letters in the above the file would be crossfire images CS CSword If the client does not have the image or otherwise needs a copy from the it then requests it
Definition: protocol.txt:2164
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:303
object::total_exp
int64_t total_exp
All exp ever earned (used to calc perm_exp)
Definition: object.h:381
object_sub_weight
void object_sub_weight(object *op, signed long weight)
Recursively (outwards) subtracts a number from the weight of an object (and what is carried by it's e...
Definition: object.cpp:1803
TRUE
#define TRUE
Definition: compat.h:11
compare_ob_value_lists_one
static int compare_ob_value_lists_one(const object *, const object *)
Compares value lists.
Definition: object.cpp:369
living::Pow
int8_t Pow
Definition: living.h:36
SPELL_TAG_SIZE
#define SPELL_TAG_SIZE
Defines default size of the *spell_tags pointer.
Definition: object.h:83
object::attacktype
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:354
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
SAVE_ERROR_OK
#define SAVE_ERROR_OK
No error.
Definition: map.h:144
maxfree
int maxfree[SIZEOFFREE]
Number of spots around a location, including that location (except for 0)
Definition: object.cpp:315
FLAG_WIZPASS
#define FLAG_WIZPASS
The wizard can go through walls.
Definition: define.h:301
save_object
int save_object(FILE *fp, object *op, int flag)
Dumps all variables in an object to a file.
Definition: object.cpp:5402
SK_CLIMBING
@ SK_CLIMBING
Climbing.
Definition: skills.h:39
object_get_player_container
object * object_get_player_container(object *op)
Finds the player carrying an object.
Definition: object.cpp:595
dirdiff
int dirdiff(int dir1, int dir2)
Computes a direction difference.
Definition: object.cpp:3728
OB_SPELL_TAG_HASH
#define OB_SPELL_TAG_HASH(op, count)
Get the hash on an object for a specified count.
Definition: object.h:89
object::material
uint16_t material
What materials this object consist of.
Definition: object.h:359
object_sum_weight
void object_sum_weight(object *op)
object_sum_weight() is a recursive function which calculates the weight an object is carrying and sto...
Definition: object.cpp:557
map_layer_name
const char *const map_layer_name[MAP_LAYERS]
These correspond to the layer names in map.h - since some of the types can be on multiple layers,...
Definition: map.cpp:46
CUSTOM_NAME_FIELD
#define CUSTOM_NAME_FIELD
Key in an object for the player-assigned custom name.
Definition: object.h:98
object_free_inventory
void object_free_inventory(object *ob)
Frees the inventory of an object, without any callback.
Definition: object.cpp:1563
object::move_block
MoveType move_block
What movement types this blocks.
Definition: object.h:439
object::next
object * next
Pointer to the next object in the free/used list.
Definition: object.h:287
free_dialog_information
void free_dialog_information(object *op)
Frees obj::dialog_information.
Definition: dialog.cpp:34
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:654
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
living::luck
int8_t luck
Affects thaco and ac from time to time.
Definition: living.h:39
FORCE
@ FORCE
Definition: object.h:229
object::oy
int16_t oy
For debugging: Where it was last inserted.
Definition: object.h:338
object.h
Animations::name
sstring name
Name of the animation sequence.
Definition: face.h:26
object_replace_insert_in_map
void object_replace_insert_in_map(const char *arch_string, object *op)
This function inserts an object of a specified archetype in the map, but if it finds objects of its o...
Definition: object.cpp:2593
object_can_merge
int object_can_merge(object *ob1, object *ob2)
Examines the 2 objects given to it, and returns true if they can be merged together,...
Definition: object.cpp:439
FLAG_IS_WOODED
#define FLAG_IS_WOODED
Item is wooded terrain.
Definition: define.h:317
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:15
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:585
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
FAST_SAVE_LONG
static void FAST_SAVE_LONG(StringBuffer *sb, const char *name, const long value)
Adds a long to the buffer.
Definition: object.cpp:4945
living::Con
int8_t Con
Definition: living.h:36
MAP_SAVING
#define MAP_SAVING
Map being saved.
Definition: map.h:134
living::Str
int8_t Str
Definition: living.h:36