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 
558 /* TODO should check call this this are made a place where we really need reevaluaton of whole tree */
559 signed long object_sum_weight(object *op) {
560  signed long sum;
561 
562  sum = 0;
563  FOR_INV_PREPARE(op, inv) {
564  if (inv->inv)
565  object_sum_weight(inv);
566  sum += inv->carrying+inv->weight*NROF(inv);
567  } FOR_INV_FINISH();
568  if (op->type == CONTAINER && op->stats.Str)
569  sum = (sum*(100-op->stats.Str))/100;
570  op->carrying = sum;
571  return sum;
572 }
573 
581 object *object_get_env_recursive(object *op) {
582  while (op->env != NULL)
583  op = op->env;
584  return op;
585 }
586 
598 object *object_get_player_container(object *op) {
599  for (; op != NULL && op->type != PLAYER; op = op->env)
600  /*TODO this is patching the structure on the flight as side effect. Shoudln't be needed in clean code */
601  if (op->env == op)
602  op->env = NULL;
603  return op;
604 }
605 
615 static const object *object_get_owner_const(const object *op) {
616  if (op->owner == NULL)
617  return NULL;
618 
619  if (!QUERY_FLAG(op->owner, FLAG_FREED)
620  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
621  && op->owner->count == op->ownercount)
622  return op->owner;
623 
624  LOG(llevError, "Warning, no owner found\n");
625  return NULL;
626 }
627 
636 void object_dump(const object *op, StringBuffer *sb) {
637  if (op == NULL) {
638  stringbuffer_append_string(sb, "[NULL pointer]");
639  return;
640  }
641 
642  /* object *tmp;*/
643 
644  if (op->arch != NULL) {
645  const object *owner;
646 
647  stringbuffer_append_string(sb, "arch ");
648  stringbuffer_append_string(sb, op->arch->name ? op->arch->name : "(null)");
649  stringbuffer_append_string(sb, "\n");
650 
651  if (op->artifact != NULL) {
652  stringbuffer_append_string(sb, "artifact ");
654  stringbuffer_append_string(sb, "\n");
655  }
656 
657  get_ob_diff(sb, op, &empty_archetype->clone);
658  if (op->more) {
659  stringbuffer_append_printf(sb, "more %u\n", op->more->count);
660  }
661  if (op->head) {
662  stringbuffer_append_printf(sb, "head %u\n", op->head->count);
663  }
664  if (op->env) {
665  stringbuffer_append_printf(sb, "env %u\n", op->env->count);
666  }
667  if (op->inv) {
668  stringbuffer_append_printf(sb, "inv %u\n", op->inv->count);
669  }
670  if (op->enemy) {
671  stringbuffer_append_printf(sb, "enemy %u\n", op->enemy->count);
672  }
673  if (op->attacked_by) {
674  stringbuffer_append_printf(sb, "attacked_by %u\n", op->attacked_by->count);
675  }
676  owner = object_get_owner_const(op);
677  if (owner != NULL) {
678  stringbuffer_append_printf(sb, "owner %u\n", owner->count);
679  }
680  stringbuffer_append_string(sb, "end\n");
681  } else {
682  stringbuffer_append_string(sb, "Object ");
683  stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
684  stringbuffer_append_string(sb, "\nend\n");
685  }
686 }
687 
695 void object_dump_all(void) {
696  object *op;
697 
698  for (op = objects; op != NULL; op = op->next) {
699  StringBuffer *sb;
700  char *diff;
701 
702  sb = stringbuffer_new();
703  object_dump(op, sb);
704  diff = stringbuffer_finish(sb);
705  LOG(llevDebug, "Object %u\n:%s\n", op->count, diff);
706  free(diff);
707  }
708 }
709 
719  if (i == OBJECT_INVALID) {
720  return nullptr;
721  }
722 
723  auto it = object_map.find(i);
724  if (it != object_map.end()) {
725  return it->second;
726  } else {
727  return nullptr;
728  }
729 }
730 
742 object *object_find_by_name_global(const char *str) {
743  const char *name = add_string(str);
744  object *op;
745 
746  for (op = objects; op != NULL; op = op->next)
747  if (op->name == name)
748  break;
749  free_string(name);
750  return op;
751 }
752 
763 #ifdef MEMORY_DEBUG
764  object *op, *next;
765 
766  for (op = free_objects; op != NULL; ) {
767  next = op->next;
768  free(op);
770  nroffreeobjects--;
771  op = next;
772  }
773  free_objects = NULL;
774 
775  for (op = objects; op != NULL; ) {
776  next = op->next;
777  if (!QUERY_FLAG(op, FLAG_FREED)) {
778  LOG(llevDebug, "non freed object: %s\n", op->name);
779  }
780  op = next;
781  }
782 #endif
783 
784  object_map.clear();
785 
786  LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX);
787 }
788 
801 object *object_get_owner(object *op) {
802  if (op->owner == NULL)
803  return NULL;
804 
805  if (!QUERY_FLAG(op->owner, FLAG_FREED)
806  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
807  && op->owner->count == op->ownercount)
808  return op->owner;
809 
810  object_clear_owner(op);
811  return NULL;
812 }
813 
820 void object_clear_owner(object *op) {
821  if (!op)
822  return;
823 
824  op->owner = NULL;
825  op->ownercount = 0;
826 }
827 
837 void object_set_owner(object *op, object *owner) {
838  /* Assign temp to something, so it can't accidentally be NULL */
839  object *tmp = owner;
840  if (op == NULL)
841  return;
842  if (owner == NULL) {
843  object_clear_owner(op);
844  return;
845  }
846 
847  /* next line added to allow objects which own objects */
848  /* Add a check for ownercounts in here, as I got into an endless loop
849  * with the fireball owning a poison cloud which then owned the
850  * fireball. I believe that was caused by one of the objects getting
851  * freed and then another object replacing it. Since the ownercounts
852  * didn't match, this check is valid and I believe that cause is valid.
853  */
854  /*
855  * if owner is NULL, function will have already returned,
856  * so loop should still function as before.
857  */
858  while (tmp) {
859  tmp = object_get_owner(owner);
860  if (tmp)
861  owner = tmp;
862  }
863 
864  /* must not cause owner cycles */
865  assert(op != owner);
866 
867  if (op->owner != NULL)
868  object_clear_owner(op);
869 
870  op->owner = owner;
871  op->ownercount = owner->count;
872 }
873 
890 void object_copy_owner(object *op, object *clone) {
891  object *owner = object_get_owner(clone);
892  if (owner == NULL) {
893  /* players don't have owners - they own themselves. Update
894  * as appropriate.
895  */
896  /*TODO owner=self is dangerous and should be avoided*/
897  if (clone->type != PLAYER)
898  return;
899  owner = clone;
900  }
901  object_set_owner(op, owner);
902 }
903 
912 void object_set_enemy(object *op, object *enemy) {
913  if (op->enemy == enemy) {
914  return;
915  }
916 
917 #if 0
918  if (op->type != PLAYER) {
919  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);
920  }
921 #endif
922  op->enemy = enemy;
923 }
924 
931 void object_reset(object *op) {
932  op->name = NULL;
933  op->name_pl = NULL;
934  op->title = NULL;
935  op->race = NULL;
936  op->slaying = NULL;
937  op->skill = NULL;
938  op->msg = NULL;
939  op->materialname = NULL;
940  op->lore = NULL;
941  object_clear(op);
942 }
943 
951 void object_free_key_values(object *op) {
952  key_value *i;
953  key_value *next = NULL;
954 
955  if (op->key_values == NULL)
956  return;
957 
958  for (i = op->key_values; i != NULL; i = next) {
959  /* Store next *first*. */
960  next = i->next;
961 
962  if (i->key)
964  if (i->value)
966  i->next = NULL;
967  free(i);
968  }
969 
970  op->key_values = NULL;
971 }
972 
980 void object_clear(object *op) {
981  /*TODO this comment must be investigated*/
982  /* redo this to be simpler/more efficient. Was also seeing
983  * crashes in the old code. Move this to the top - am
984  * seeing periodic crashes in this code, and would like to have
985  * as much info available as possible (eg, object name).
986  */
989 
990  /* the memset will clear all these values for us, but we need
991  * to reduce the refcount on them.
992  */
993  if (op->name != NULL)
995  if (op->name_pl != NULL)
997  if (op->title != NULL)
999  if (op->race != NULL)
1000  FREE_AND_CLEAR_STR(op->race);
1001  if (op->slaying != NULL)
1003  if (op->skill != NULL)
1005  if (op->msg != NULL)
1006  FREE_AND_CLEAR_STR(op->msg);
1007  if (op->lore != NULL)
1008  FREE_AND_CLEAR_STR(op->lore);
1009  if (op->materialname != NULL)
1011 
1012  /* Remove object from friendly list if needed. */
1013  if (QUERY_FLAG(op, FLAG_FRIENDLY))
1015 
1016  memset((void *)((char *)op+offsetof(object, name)), 0, sizeof(object)-offsetof(object, name));
1017  /* Below here, we clear things that are not done by the memset,
1018  * or set default values that are not zero.
1019  */
1020  /* This is more or less true */
1021  SET_FLAG(op, FLAG_REMOVED);
1022 
1023 
1024  op->contr = NULL;
1025  op->below = NULL;
1026  op->above = NULL;
1027  op->inv = NULL;
1028  op->container = NULL;
1029  op->env = NULL;
1030  op->more = NULL;
1031  op->head = NULL;
1032  op->map = NULL;
1033  op->active_next = NULL;
1034  op->active_prev = NULL;
1035  /* What is not cleared is next, prev, and count */
1036 
1037  op->expmul = 1.0;
1038  op->face = blank_face;
1039  op->attacked_by_count = -1;
1040  if (settings.casting_time)
1041  op->casting_time = -1;
1042 }
1043 
1058 void object_copy_no_speed(const object *src_ob, object *dest_ob) {
1059  int is_freed = QUERY_FLAG(dest_ob, FLAG_FREED), is_removed = QUERY_FLAG(dest_ob, FLAG_REMOVED);
1060 
1061  /* Decrement the refcounts, but don't bother zeroing the fields;
1062  they'll be overwritten by memcpy. */
1063  if (dest_ob->artifact != NULL)
1064  free_string(dest_ob->artifact);
1065  if (dest_ob->name != NULL)
1066  free_string(dest_ob->name);
1067  if (dest_ob->name_pl != NULL)
1068  free_string(dest_ob->name_pl);
1069  if (dest_ob->anim_suffix != NULL)
1070  free_string(dest_ob->anim_suffix);
1071  if (dest_ob->title != NULL)
1072  free_string(dest_ob->title);
1073  if (dest_ob->race != NULL)
1074  free_string(dest_ob->race);
1075  if (dest_ob->slaying != NULL)
1076  free_string(dest_ob->slaying);
1077  if (dest_ob->skill != NULL)
1078  free_string(dest_ob->skill);
1079  if (dest_ob->msg != NULL)
1080  free_string(dest_ob->msg);
1081  if (dest_ob->lore != NULL)
1082  free_string(dest_ob->lore);
1083  if (dest_ob->materialname != NULL)
1084  free_string(dest_ob->materialname);
1085  if (dest_ob->spell_tags != NULL)
1086  FREE_AND_CLEAR(dest_ob->spell_tags);
1087 
1088  /* Basically, same code as from object_clear() */
1089 
1090  object_free_key_values(dest_ob);
1091  free_dialog_information(dest_ob);
1092 
1093  /* Copy all attributes below name (name included). */
1094  (void)memcpy((void *)((char *)dest_ob+offsetof(object, name)),
1095  (void *)((char *)src_ob+offsetof(object, name)),
1096  sizeof(object)-offsetof(object, name));
1097 
1098  if (is_freed)
1099  SET_FLAG(dest_ob, FLAG_FREED);
1100  if (is_removed)
1101  SET_FLAG(dest_ob, FLAG_REMOVED);
1102  if (dest_ob->artifact != NULL)
1103  add_refcount(dest_ob->artifact);
1104  if (dest_ob->name != NULL)
1105  add_refcount(dest_ob->name);
1106  if (dest_ob->name_pl != NULL)
1107  add_refcount(dest_ob->name_pl);
1108  if (dest_ob->anim_suffix != NULL)
1109  add_refcount(dest_ob->anim_suffix);
1110  if (dest_ob->title != NULL)
1111  add_refcount(dest_ob->title);
1112  if (dest_ob->race != NULL)
1113  add_refcount(dest_ob->race);
1114  if (dest_ob->slaying != NULL)
1115  add_refcount(dest_ob->slaying);
1116  if (dest_ob->skill != NULL)
1117  add_refcount(dest_ob->skill);
1118  if (dest_ob->lore != NULL)
1119  add_refcount(dest_ob->lore);
1120  if (dest_ob->msg != NULL)
1121  add_refcount(dest_ob->msg);
1122  if (dest_ob->materialname != NULL)
1123  add_refcount(dest_ob->materialname);
1124 
1125  if (dest_ob->spell_tags != NULL) {
1126  dest_ob->spell_tags = static_cast<tag_t *>(malloc(sizeof(tag_t)*SPELL_TAG_SIZE));
1127  memcpy(dest_ob->spell_tags, src_ob->spell_tags, sizeof(tag_t)*SPELL_TAG_SIZE);
1128  }
1129 
1130  /* If archetype is a temporary one, we need to update reference count, because
1131  * that archetype will be freed by object_free_drop_inventory() when the last object is removed.
1132  */
1133  if (dest_ob->arch != NULL) {
1134  if (dest_ob->arch->reference_count > 0)
1135  dest_ob->arch->reference_count++;
1136  }
1137 
1138  if (src_ob->speed < 0)
1139  dest_ob->speed_left = src_ob->speed_left-RANDOM()%200/100.0;
1140 
1141  /* Copy over key_values, if any. */
1142  if (src_ob->key_values != NULL) {
1143  key_value *tail = NULL;
1144  key_value *i;
1145 
1146  dest_ob->key_values = NULL;
1147 
1148  for (i = src_ob->key_values; i != NULL; i = i->next) {
1149  key_value *new_link = static_cast<key_value *>(malloc(sizeof(key_value)));
1150 
1151  new_link->next = NULL;
1152  new_link->key = add_refcount(i->key);
1153  if (i->value)
1154  new_link->value = add_refcount(i->value);
1155  else
1156  new_link->value = NULL;
1157 
1158  /* Try and be clever here, too. */
1159  if (dest_ob->key_values == NULL) {
1160  dest_ob->key_values = new_link;
1161  tail = new_link;
1162  } else {
1163  tail->next = new_link;
1164  tail = new_link;
1165  }
1166  }
1167  }
1168 
1169  /* This way, dialog information will be parsed again when/if needed. */
1170  CLEAR_FLAG(dest_ob, FLAG_DIALOG_PARSED);
1171 
1172  dest_ob->event_bitmask = BITMASK_VALID; // Empty inventory so valid
1173 }
1174 
1189 void object_copy(const object *src_ob, object *dest_ob) {
1190  object_copy_no_speed(src_ob, dest_ob);
1191  object_update_speed(dest_ob);
1192 }
1193 
1205 void object_copy_with_inv(const object *src_ob, object *dest_ob, bool update_speed) {
1206  if (update_speed) {
1207  object_copy(src_ob, dest_ob);
1208  } else {
1209  object_copy_no_speed(src_ob, dest_ob);
1210  }
1211  FOR_INV_PREPARE(src_ob, walk) {
1212  object *tmp;
1213 
1214  tmp = object_new();
1215  object_copy_with_inv(walk, tmp, update_speed);
1216  object_insert_in_ob(tmp, dest_ob);
1217  } FOR_INV_FINISH();
1218 }
1219 
1220 #ifndef MEMORY_DEBUG
1221 
1228 static void expand_objects(void) {
1229  int i;
1230  object *add;
1231 
1232  add = (object *)CALLOC(OBJ_EXPAND, sizeof(object));
1233 
1234  if (add == NULL)
1236  free_objects = add;
1237  add[0].prev = NULL;
1238  add[0].next = &add[1],
1239  SET_FLAG(&add[0], FLAG_REMOVED);
1240  SET_FLAG(&add[0], FLAG_FREED);
1241 
1242  for (i = 1; i < OBJ_EXPAND-1; i++) {
1243  add[i].next = &add[i+1],
1244  add[i].prev = &add[i-1],
1245  SET_FLAG(&add[i], FLAG_REMOVED);
1246  SET_FLAG(&add[i], FLAG_FREED);
1247  }
1248  add[OBJ_EXPAND-1].prev = &add[OBJ_EXPAND-2],
1249  add[OBJ_EXPAND-1].next = NULL,
1250  SET_FLAG(&add[OBJ_EXPAND-1], FLAG_REMOVED);
1251  SET_FLAG(&add[OBJ_EXPAND-1], FLAG_FREED);
1252 
1255 }
1256 #endif
1257 
1270 object *object_new(void) {
1271  object *op;
1272 #ifdef MEMORY_DEBUG
1273  /* FIXME: However this doesn't work since object_free() sometimes add
1274  * objects back to the free_objects linked list, and some functions mess
1275  * with the object after return of object_free(). This is bad and should be
1276  * fixed. But it would need fairly extensive changes and a lot of debugging.
1277  */
1278  op = static_cast<object *>(calloc(1, sizeof(object)));
1279  if (op == NULL)
1281 #else
1282  if (free_objects == NULL) {
1283  expand_objects();
1284  }
1285  op = free_objects;
1286  if (!QUERY_FLAG(op, FLAG_FREED)) {
1287  LOG(llevError, "Fatal: Getting busy object.\n");
1288 #ifdef MANY_CORES
1289  abort();
1290 #endif
1291  }
1292  free_objects = op->next;
1293  if (free_objects != NULL)
1294  free_objects->prev = NULL;
1295  nroffreeobjects--;
1296 #endif
1297  op->count = ++ob_count;
1298  object_map[op->count] = op;
1299  op->name = NULL;
1300  op->name_pl = NULL;
1301  op->title = NULL;
1302  op->race = NULL;
1303  op->slaying = NULL;
1304  op->skill = NULL;
1305  op->lore = NULL;
1306  op->msg = NULL;
1307  op->materialname = NULL;
1308  op->next = objects;
1309  op->prev = NULL;
1310  op->active_next = NULL;
1311  op->active_prev = NULL;
1312  op->spell_tags = NULL;
1314  if (objects != NULL)
1315  objects->prev = op;
1316  objects = op;
1317  object_clear(op);
1318  SET_FLAG(op, FLAG_REMOVED);
1319  return op;
1320 }
1321 
1330 void object_update_turn_face(object *op) {
1331  if (op->animation == 0 || !QUERY_FLAG(op, FLAG_IS_TURNABLE))
1332  return;
1333  animate_object(op, op->direction);
1334 }
1335 
1347 void object_update_speed(object *op) {
1348 
1349  /* No reason putting the archetypes objects on the speed list,
1350  * since they never really need to be updated.
1351  */
1352 
1353  if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
1354  LOG(llevError, "Object %s is freed but has speed.\n", op->name);
1355 #ifdef MANY_CORES
1356  abort();
1357 #else
1358  op->speed = 0;
1359 #endif
1360  }
1361  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
1362  /* If already on active list, don't do anything */
1363  /* TODO this check can probably be simplified a lot */
1364  if (op->active_next || op->active_prev || op == active_objects)
1365  return;
1366 
1367  /* process_events() expects us to insert the object at the beginning
1368  * of the list. */
1370  if (op->active_next != NULL)
1371  op->active_next->active_prev = op;
1372  active_objects = op;
1373  } else {
1375  }
1376 }
1377 
1391  /* If not on the active list, nothing needs to be done */
1392  if (!op->active_next && !op->active_prev && op != active_objects)
1393  return;
1394 
1395  if (op->active_prev == NULL) {
1397  if (op->active_next != NULL)
1398  op->active_next->active_prev = NULL;
1399  } else {
1400  op->active_prev->active_next = op->active_next;
1401  if (op->active_next)
1402  op->active_next->active_prev = op->active_prev;
1403  }
1404  op->active_next = NULL;
1405  op->active_prev = NULL;
1406 }
1407 
1432 void object_update(object *op, int action) {
1433  int update_now = 0, flags;
1434  MoveType move_on, move_off, move_block, move_slow;
1435  object *pl;
1436 
1437  if (op == NULL) {
1438  /* this should never happen */
1439  LOG(llevDebug, "object_update() called for NULL object.\n");
1440  return;
1441  }
1442 
1443  if (op->env != NULL) {
1444  /* Animation is currently handled by client, so nothing
1445  * to do in this case.
1446  */
1447  return;
1448  }
1449 
1450  /* If the map is saving, don't do anything as everything is
1451  * going to get freed anyways.
1452  */
1453  if (!op->map || op->map->in_memory == MAP_SAVING)
1454  return;
1455 
1456  /* make sure the object is within map boundaries */
1457  if (op->x < 0 || op->x >= MAP_WIDTH(op->map)
1458  || op->y < 0 || op->y >= MAP_HEIGHT(op->map)) {
1459  LOG(llevError, "object_update() called for object out of map!\n");
1460 #ifdef MANY_CORES
1461  abort();
1462 #endif
1463  return;
1464  }
1465 
1466  flags = GET_MAP_FLAGS(op->map, op->x, op->y);
1467  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NEED_UPDATE);
1468  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
1469  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
1470  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
1471  move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y);
1472 
1473  if (action == UP_OBJ_INSERT) {
1475  update_now = 1;
1476 
1477  if (QUERY_FLAG(op, FLAG_NO_MAGIC) && !(flags&P_NO_MAGIC))
1478  update_now = 1;
1479 
1480  if (QUERY_FLAG(op, FLAG_DAMNED) && !(flags&P_NO_CLERIC))
1481  update_now = 1;
1482 
1483  if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags&P_IS_ALIVE))
1484  update_now = 1;
1485 
1486  if ((move_on|op->move_on) != move_on)
1487  update_now = 1;
1488  if ((move_off|op->move_off) != move_off)
1489  update_now = 1;
1490  /* This isn't perfect, but I don't expect a lot of objects to
1491  * to have move_allow right now.
1492  */
1493  if (((move_block|op->move_block)&~op->move_allow) != move_block)
1494  update_now = 1;
1495  if ((move_slow|op->move_slow) != move_slow)
1496  update_now = 1;
1497 
1498  if (op->type == PLAYER)
1499  update_now = 1;
1500  /* if the object is being removed, we can't make intelligent
1501  * decisions, because object_remove() can't really pass the object
1502  * that is being removed.
1503  */
1504  } else if (action == UP_OBJ_REMOVE) {
1505  update_now = 1;
1506  } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) {
1507  /* In addition to sending info to client, need to update space
1508  * information.
1509  */
1510  if (action == UP_OBJ_CHANGE)
1511  update_now = 1;
1512 
1513  /* There is a player on this space - we may need to send an
1514  * update to the client.
1515  * If this object is supposed to be animated by the client,
1516  * nothing to do here - let the client animate it.
1517  * We can't use FLAG_ANIMATE, as that is basically set for
1518  * all objects with multiple faces, regardless if they are animated.
1519  * (levers have it set for example).
1520  */
1521  if (flags&P_PLAYER
1524  pl = GET_MAP_PLAYER(op->map, op->x, op->y);
1525 
1526  /* If update_look is set, we're going to send this entire space
1527  * to the client, so no reason to send face information now.
1528  */
1529  if (!pl->contr->socket->update_look) {
1530  esrv_update_item(UPD_FACE, pl, op);
1531  }
1532  }
1533  } else {
1534  LOG(llevError, "object_update called with invalid action: %d\n", action);
1535  }
1536 
1537  if (update_now) {
1538  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NO_ERROR|P_NEED_UPDATE);
1539  update_position(op->map, op->x, op->y);
1540  }
1541 
1542  if (op->more != NULL)
1543  object_update(op->more, action);
1544 }
1545 
1558 void object_free_drop_inventory(object *ob) {
1559  object_free(ob, 0);
1560 }
1561 
1566 void object_free_inventory(object *ob) {
1567  while (ob->inv) {
1568  object *inv = ob->inv;
1569  object_remove(inv);
1571  }
1572 }
1573 
1590 void object_free(object *ob, int flags) {
1591  if (!QUERY_FLAG(ob, FLAG_REMOVED)) {
1592  StringBuffer *sb;
1593  char *diff;
1594 
1595  LOG(llevError, "Free object called with non removed object\n");
1596  sb = stringbuffer_new();
1597  object_dump(ob, sb);
1598  diff = stringbuffer_finish(sb);
1599  LOG(llevError, "%s", diff);
1600  free(diff);
1601 #ifdef MANY_CORES
1602  abort();
1603 #endif
1604  }
1605  if (QUERY_FLAG(ob, FLAG_FRIENDLY)) {
1606  LOG(llevMonster, "Warning: tried to free friendly object.\n");
1608  }
1609  if (QUERY_FLAG(ob, FLAG_FREED)) {
1610  StringBuffer *sb;
1611  char *diff;
1612 
1613  sb = stringbuffer_new();
1614  object_dump(ob, sb);
1615  diff = stringbuffer_finish(sb);
1616  LOG(llevError, "Trying to free freed object.\n%s\n", diff);
1617  free(diff);
1618  return;
1619  }
1620 
1621  if ((flags & FREE_OBJ_NO_DESTROY_CALLBACK) == 0) {
1623  }
1624 
1625  if (ob->inv) {
1626  /* Only if the space blocks everything do we not process -
1627  * if some form of movemnt is allowed, let objects
1628  * drop on that space.
1629  */
1630  if ((flags & FREE_OBJ_FREE_INVENTORY) != 0
1631  || ob->map == NULL
1632  || ob->map->in_memory != MAP_IN_MEMORY
1633  || (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL)) {
1634  FOR_INV_PREPARE(ob, op) {
1635  object_remove(op);
1636  object_free(op, flags);
1637  } FOR_INV_FINISH();
1638  } else { /* Put objects in inventory onto this space */
1639  FOR_INV_PREPARE(ob, op) {
1640  object_remove(op);
1641  /* No drop means no drop, including its inventory */
1642  if (QUERY_FLAG(op, FLAG_NO_DROP))
1644  else if (QUERY_FLAG(op, FLAG_STARTEQUIP)
1645  || QUERY_FLAG(op, FLAG_NO_DROP)
1646  || op->type == RUNE
1647  || op->type == TRAP
1650  else {
1651  object *part;
1652 
1653  /* If it's a multi-tile object, scatter dropped items randomly */
1654  if (ob->more) {
1655  int partcount = 0;
1656  /* Get the number of non-head parts */
1657  for (part = ob; part; part = part->more) {
1658  partcount++;
1659  }
1660  /* Select a random part */
1661  partcount = RANDOM()%partcount;
1662  for (part = ob; partcount > 0; partcount--) {
1663  part = part->more;
1664  }
1665  } else {
1666  part = ob;
1667  }
1668 
1669  if (QUERY_FLAG(op, FLAG_ALIVE)) {
1670  object_insert_to_free_spot_or_free(op, part->map, part->x, part->y, 0, SIZEOFFREE, NULL);
1671  } else {
1672  int f = 0;
1675  object_insert_in_map_at(op, part->map, NULL, f, part->x, part->y); /* Insert in same map as the envir */
1676  }
1677  }
1678  } FOR_INV_FINISH();
1679  }
1680  }
1681 
1682  if (ob->more != NULL) {
1683  object_free(ob->more, flags);
1684  ob->more = NULL;
1685  }
1686 
1687  /* Remove object from the active list */
1688  ob->speed = 0;
1689  object_update_speed(ob);
1690 
1691  SET_FLAG(ob, FLAG_FREED);
1692  object_map.erase(ob->count);
1693  ob->count = 0;
1694 
1695  /* Remove this object from the list of used objects */
1696  if (ob->prev == NULL) {
1697  objects = ob->next;
1698  if (objects != NULL)
1699  objects->prev = NULL;
1700  } else {
1701  ob->prev->next = ob->next;
1702  if (ob->next != NULL)
1703  ob->next->prev = ob->prev;
1704  }
1705 
1706  if (ob->artifact != NULL) FREE_AND_CLEAR_STR(ob->artifact);
1707  if (ob->name != NULL) FREE_AND_CLEAR_STR(ob->name);
1708  if (ob->name_pl != NULL) FREE_AND_CLEAR_STR(ob->name_pl);
1709  if (ob->title != NULL) FREE_AND_CLEAR_STR(ob->title);
1710  if (ob->race != NULL) FREE_AND_CLEAR_STR(ob->race);
1711  if (ob->slaying != NULL) FREE_AND_CLEAR_STR(ob->slaying);
1712  if (ob->skill != NULL) FREE_AND_CLEAR_STR(ob->skill);
1713  if (ob->lore != NULL) FREE_AND_CLEAR_STR(ob->lore);
1714  if (ob->msg != NULL) FREE_AND_CLEAR_STR(ob->msg);
1715  if (ob->materialname != NULL) FREE_AND_CLEAR_STR(ob->materialname);
1716  if (ob->spell_tags) FREE_AND_CLEAR(ob->spell_tags);
1718 
1719  /* Why aren't events freed? */
1721 
1723 
1724  /* Test whether archetype is a temporary one, and if so look whether it should be trashed. */
1725  if (ob->arch && ob->arch->reference_count > 0) {
1726  if (--ob->arch->reference_count == 0) {
1727  free_arch(ob->arch);
1728  }
1729  }
1730 
1731 #ifdef MEMORY_DEBUG
1732  free(ob);
1733 #else
1734  /* Now link it with the free_objects list: */
1735  ob->prev = NULL;
1736  ob->next = free_objects;
1737  if (free_objects != NULL)
1738  free_objects->prev = ob;
1739  free_objects = ob;
1740  nroffreeobjects++;
1741 #endif
1742 }
1743 
1751  int i = 0;
1752  object *tmp = free_objects;
1753 
1754  while (tmp != NULL)
1755  tmp = tmp->next,
1756  i++;
1757  return i;
1758 }
1759 
1767  int i = 0;
1768  object *tmp = objects;
1769 
1770  while (tmp != NULL)
1771  tmp = tmp->next,
1772  i++;
1773  return i;
1774 }
1775 
1783  int i = 0;
1784  object *tmp = active_objects;
1785 
1786  while (tmp != NULL)
1787  tmp = tmp->active_next,
1788  i++;
1789  return i;
1790 }
1791 
1806 void object_sub_weight(object *op, signed long weight) {
1807  while (op != NULL) {
1808  if (op->type == CONTAINER) {
1809  weight = (signed long)(weight*(100-op->stats.Str)/100);
1810  }
1811  op->carrying -= weight;
1812  op = op->env;
1813  }
1814 }
1815 
1832 void object_remove(object *op) {
1833  object *last = NULL;
1834  object *otmp;
1835  tag_t tag;
1836  int check_walk_off;
1837  mapstruct *m;
1838  int16_t x, y;
1839 
1840  if (QUERY_FLAG(op, FLAG_REMOVED)) {
1841  StringBuffer *sb;
1842  char *diff;
1843 
1844  sb = stringbuffer_new();
1845  object_dump(op, sb);
1846  diff = stringbuffer_finish(sb);
1847  LOG(llevError, "Trying to remove removed object.\n%s\n", diff);
1848  free(diff);
1849  abort();
1850  }
1851  if (op->more != NULL)
1852  object_remove(op->more);
1853 
1854  SET_FLAG(op, FLAG_REMOVED);
1855 
1856  /*
1857  * In this case, the object to be removed is in someones
1858  * inventory.
1859  */
1860  /* TODO try to call a generic inventory weight adjusting function like object_sub_weight */
1861  if (op->env != NULL) {
1862  player *pl = NULL;
1863 
1864  if (op->nrof)
1865  object_sub_weight(op->env, op->weight*op->nrof);
1866  else
1867  object_sub_weight(op->env, op->weight+op->carrying);
1868 
1869  /* Update in two cases: item is in a player, or in a container the player is looking into. */
1870  if (op->env->contr != NULL && op->head == NULL) {
1871  pl = op->env->contr;
1872  } else if (op->env->type == CONTAINER && QUERY_FLAG(op->env, FLAG_APPLIED)) {
1873 
1874  if (op->env->env && op->env->env->contr)
1875  /* Container is in player's inventory. */
1876  pl = op->env->env->contr;
1877  else if (op->env->map) {
1878  /* Container on map, look above for player. */
1879  object *above = op->env->above;
1880 
1881  while (above && !above->contr)
1882  above = above->above;
1883  if (above)
1884  pl = above->contr;
1885  }
1886  }
1887 
1888  /* NO_FIX_PLAYER is set when a great many changes are being
1889  * made to players inventory. If set, avoiding the call
1890  * to save cpu time.
1891  */
1892  otmp = object_get_player_container(op->env);
1893  if (otmp != NULL
1894  && otmp->contr
1895  && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
1896  fix_object(otmp);
1897 
1898  if (op->above != NULL)
1899  op->above->below = op->below;
1900  else
1901  op->env->inv = op->below;
1902 
1903  if (op->below != NULL)
1904  op->below->above = op->above;
1905 
1906  if (op->type == EVENT_CONNECTOR) {
1907  op->env->event_bitmask = 0; // Will be recomputed if needed
1908  }
1909 
1910  /* we set up values so that it could be inserted into
1911  * the map, but we don't actually do that - it is up
1912  * to the caller to decide what we want to do.
1913  */
1914  op->x = op->env->x;
1915  op->y = op->env->y;
1916  op->ox = op->x;
1917  op->oy = op->y;
1918  op->map = op->env->map;
1919  op->above = NULL;
1920  op->below = NULL;
1921  /* send the delitem before resetting env, so container's contents be may
1922  * refreshed */
1923  if (LOOK_OBJ(op) && pl != NULL)
1924  esrv_del_item(pl, op);
1925  op->env = NULL;
1926  return;
1927  }
1928 
1929  /* If we get here, we are removing it from a map */
1930  if (op->map == NULL)
1931  return;
1932 
1933  if (op->contr != NULL && !op->contr->hidden)
1934  op->map->players--;
1935 
1936  x = op->x;
1937  y = op->y;
1938  m = get_map_from_coord(op->map, &x, &y);
1939 
1940  if (!m) {
1941  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);
1942  abort();
1943  }
1944  if (op->map != m) {
1945  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);
1946  }
1947 
1948  /* link the object above us */
1949  if (op->above)
1950  op->above->below = op->below;
1951  else
1952  SET_MAP_TOP(m, x, y, op->below); /* we were top, set new top */
1953 
1954  /* Relink the object below us, if there is one */
1955  if (op->below) {
1956  op->below->above = op->above;
1957  } else {
1958  /* Nothing below, which means we need to relink map object for this space
1959  * use translated coordinates in case some oddness with map tiling is
1960  * evident
1961  */
1962  /*TODO is this check really needed?*/
1963  if (GET_MAP_OB(m, x, y) != op) {
1964  StringBuffer *sb;
1965  char *diff;
1966 
1967  sb = stringbuffer_new();
1968  object_dump(op, sb);
1969  diff = stringbuffer_finish(sb);
1970  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);
1971  free(diff);
1972 
1973  sb = stringbuffer_new();
1974  object_dump(GET_MAP_OB(m, x, y), sb);
1975  diff = stringbuffer_finish(sb);
1976  LOG(llevError, "%s\n", diff);
1977  free(diff);
1978  }
1979  SET_MAP_OB(m, x, y, op->above); /* goes on above it. */
1980  }
1981  op->above = NULL;
1982  op->below = NULL;
1983 
1984  if (op->map->in_memory == MAP_SAVING)
1985  return;
1986 
1987  tag = op->count;
1988  check_walk_off = !QUERY_FLAG(op, FLAG_NO_APPLY);
1989  FOR_MAP_PREPARE(m, x, y, tmp) {
1990  /* No point updating the players look faces if he is the object
1991  * being removed.
1992  */
1993 
1994  if (tmp->type == PLAYER && tmp != op) {
1995  /* If a container that the player is currently using somehow gets
1996  * removed (most likely destroyed), update the player view
1997  * appropriately.
1998  */
1999  if (tmp->container == op) {
2000  CLEAR_FLAG(op, FLAG_APPLIED);
2001  tmp->container = NULL;
2002  // Notify the client the container is gone so it clears its active container.
2003  esrv_update_item(UPD_FLAGS, tmp, op);
2004  }
2005  tmp->contr->socket->update_look = 1;
2006  }
2007  /* See if player moving off should effect something */
2008  if (check_walk_off
2009  && ((op->move_type&tmp->move_off) && (op->move_type&~tmp->move_off&~tmp->move_block) == 0)) {
2010  ob_move_on(tmp, op, NULL);
2011  if (object_was_destroyed(op, tag)) {
2012  LOG(llevError, "BUG: object_remove(): name %s, archname %s destroyed leaving object\n", tmp->name, tmp->arch->name);
2013  }
2014  }
2015 
2016  /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
2017  if (tmp->above == tmp)
2018  tmp->above = NULL;
2019  last = tmp;
2020  } FOR_MAP_FINISH();
2021  /* last == NULL or there are no objects on this space */
2022  if (last == NULL) {
2023  /* set P_NEED_UPDATE, otherwise update_position will complain. In theory,
2024  * we could preserve the flags (GET_MAP_FLAGS), but update_position figures
2025  * those out anyways, and if there are any flags set right now, they won't
2026  * be correct anyways.
2027  */
2028  SET_MAP_FLAGS(op->map, op->x, op->y, P_NEED_UPDATE);
2029  update_position(op->map, op->x, op->y);
2030  } else
2032 
2033  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) || (op->glow_radius != 0))
2034  update_all_los(op->map, op->x, op->y);
2035 }
2036 
2050 object *object_merge(object *op, object *top) {
2051  if (!op->nrof)
2052  return NULL;
2053 
2054  if (top == NULL)
2055  for (top = op; top != NULL && top->above != NULL; top = top->above)
2056  ;
2058  if (top == op)
2059  continue;
2060  if (object_can_merge(op, top)) {
2061  object_increase_nrof(top, op->nrof);
2062  /*
2063  * Previous behavior set weight to zero here.
2064  * This, however, caused the object_sub_weight
2065  * call in object_remove to subtract zero weight
2066  * when removing the object. Thus, until inventory
2067  * weight is next recalculated, the object merged
2068  * into another pile added weight in object_increase_nrof
2069  * but did not remove the weight from the original
2070  * instance of itself in object_remove, essentially
2071  * counting for double weight for several minutes.
2072  *
2073  * SilverNexus 2014-05-27
2074  */
2075  object_remove(op);
2077  return top;
2078  }
2080  return NULL;
2081 }
2082 
2099 object *object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y) {
2100  object *tmp;
2101 
2102  op = HEAD(op);
2103  for (tmp = op; tmp; tmp = tmp->more) {
2104  tmp->x = x+tmp->arch->clone.x;
2105  tmp->y = y+tmp->arch->clone.y;
2106  tmp->map = m;
2107  }
2108  return object_insert_in_map(op, m, originator, flag);
2109 }
2110 
2128 void object_merge_spell(object *op, int16_t x, int16_t y) {
2129  int i;
2130 
2131  /* We try to do some merging of spell objects - if something has same owner,
2132  * is same type of spell, and going in the same direction, it is somewhat
2133  * mergable.
2134  *
2135  * If the spell object has an other_arch, don't merge - when the spell
2136  * does something, like explodes, it will use this other_arch, and
2137  * if we merge, there is no easy way to make the correct values be
2138  * set on this new object (values should be doubled, tripled, etc.)
2139  *
2140  * We also care about speed - only process objects that will not be
2141  * active this tick. Without this, the results are incorrect - think
2142  * of a case where tmp would normally get processed this tick, but
2143  * get merges with op, which does not get processed.
2144  */
2145  FOR_MAP_PREPARE(op->map, x, y, tmp) {
2146  if (op->type == tmp->type
2147  && op->subtype == tmp->subtype
2148  && op->direction == tmp->direction
2149  && op->owner == tmp->owner && op->ownercount == tmp->ownercount
2150  && op->range == tmp->range
2151  && op->stats.wc == tmp->stats.wc
2152  && op->level == tmp->level
2153  && op->attacktype == tmp->attacktype
2154  && op->speed == tmp->speed
2155  && !tmp->other_arch
2156  && (tmp->speed_left+tmp->speed) < 0.0
2157  && op != tmp) {
2158  /* Quick test - if one or the other objects already have hash tables
2159  * set up, and that hash bucket contains a value that doesn't
2160  * match what we want to set it up, we won't be able to merge.
2161  * Note that these two if statements are the same, except
2162  * for which object they are checking against. They could
2163  * be merged, but the line wrapping would be large enough
2164  * that IMO it would become difficult to read the different clauses
2165  * so its cleaner just to do 2 statements - MSW
2166  */
2167  if (op->spell_tags
2168  && !OB_SPELL_TAG_MATCH(op, (tag_t)tmp->stats.maxhp)
2169  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0)
2170  continue;
2171 
2172  if (tmp->spell_tags
2173  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)op->stats.maxhp)
2174  && OB_SPELL_TAG_HASH(tmp, op->stats.maxhp) != 0)
2175  continue;
2176 
2177  /* If we merge, the data from tmp->spell_tags gets copied into op.
2178  * so we need to make sure that slot isn't filled up.
2179  */
2180  if (tmp->spell_tags
2181  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)tmp->stats.maxhp)
2182  && OB_SPELL_TAG_HASH(tmp, tmp->stats.maxhp) != 0)
2183  continue;
2184 
2185  /* If both objects have spell_tags, we need to see if there are conflicting
2186  * values - if there are, we won't be able to merge then.
2187  */
2188  if (tmp->spell_tags && op->spell_tags) {
2189  int need_copy = 0;
2190 
2191  for (i = 0; i < SPELL_TAG_SIZE; i++) {
2192  /* If the two tag values in the hash are set, but are
2193  * not set to the same value, then these objects
2194  * can not be merged.
2195  */
2196  if (op->spell_tags[i] && tmp->spell_tags[i]
2197  && op->spell_tags[i] != tmp->spell_tags[i]) {
2199  break;
2200  }
2201  /* If one tag is set and the other is not, that is
2202  * fine, but we have to note that we need to copy
2203  * the data in that case.
2204  */
2205  if ((!op->spell_tags[i] && tmp->spell_tags[i])
2206  || (op->spell_tags[i] && !tmp->spell_tags[i])) {
2207  need_copy = 1;
2208  }
2209  }
2210  /* If we did not get through entire array, it means
2211  * we got a conflicting hash, and so we won't be
2212  * able to merge these - just continue processing
2213  * object on this space.
2214  */
2215  if (i <= SPELL_TAG_SIZE)
2216  continue;
2217 
2218  /* Ok - everything checked out - we should be able to
2219  * merge tmp in op. So lets copy the tag data if
2220  * needed. Note that this is a selective copy, as
2221  * we don't want to clear values that may be set in op.
2222  */
2223  if (need_copy) {
2224  for (i = 0; i < SPELL_TAG_SIZE; i++)
2225  if (!op->spell_tags[i]
2226  && tmp->spell_tags[i]
2227  && tmp->spell_tags[i] != (tag_t)op->stats.maxhp)
2228  op->spell_tags[i] = tmp->spell_tags[i];
2229  }
2230  FREE_AND_CLEAR(tmp->spell_tags);
2231  }
2232 
2233  /* if tmp has a spell_tags table, copy it to op and free tmps */
2234  if (tmp->spell_tags && !op->spell_tags) {
2235  op->spell_tags = tmp->spell_tags;
2236  tmp->spell_tags = NULL;
2237 
2238  /* We don't need to keep a copy of our maxhp value
2239  * in the copied over value
2240  */
2241  if (OB_SPELL_TAG_MATCH(op, (tag_t)op->stats.maxhp))
2242  OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0;
2243  }
2244 
2245  /* For spells to work correctly, we need to record what spell
2246  * tags we've merged in with this effect. This is used
2247  * in ok_to_put_more() to see if a spell effect is already on
2248  * the space.
2249  */
2250  if (op->stats.maxhp != tmp->stats.maxhp) {
2251 #ifdef OBJECT_DEBUG
2252  /* This if statement should never happen - the logic above should
2253  * have prevented it. It is a problem, because by now its possible
2254  * we've destroyed the spell_tags in tmp, so we can't really
2255  * just bail out.
2256  */
2257 
2258  if (op->spell_tags
2259  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0
2260  && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)) {
2261  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);
2262  }
2263 #endif
2264  if (!op->spell_tags)
2265  op->spell_tags = static_cast<tag_t *>(calloc(SPELL_TAG_SIZE, sizeof(tag_t)));
2266 
2267  OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) = tmp->stats.maxhp;
2268  }
2269 
2271  op->speed_left = MAX(op->speed_left, tmp->speed_left);
2272 
2273  if (tmp->duration != op->duration) {
2274  /* We need to use tmp_dam here because otherwise the
2275  * calculations can overflow the size of stats.dam.
2276  */
2277  int tmp_dam = tmp->stats.dam*(tmp->duration+1)+
2278  op->stats.dam*(op->duration+1);
2279 
2280  op->duration = MAX(op->duration, tmp->duration);
2281  tmp_dam /= op->duration+1;
2282  op->stats.dam = tmp_dam+1;
2283  } else {
2284  /* in this case, duration is the same, so simply adding
2285  * up damage works.
2286  */
2287  op->stats.dam += tmp->stats.dam;
2288  }
2289 
2290  object_remove(tmp);
2292  }
2293  } FOR_MAP_FINISH();
2294 }
2295 
2296 static object *find_insert_pos(object *op, const int flag) {
2297  object *floor = NULL;
2298  /*
2299  * If there are multiple objects on this space, we do some trickier handling.
2300  * We've already dealt with merging if appropriate.
2301  * Generally, we want to put the new object on top. But if
2302  * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
2303  * floor, we want to insert above that and no further.
2304  * Also, if there are spell objects on this space, we stop processing
2305  * once we get to them. This reduces the need to traverse over all of
2306  * them when adding another one - this saves quite a bit of cpu time
2307  * when lots of spells are cast in one area. Currently, it is presumed
2308  * that flying non pickable objects are spell objects.
2309  */
2310  if (flag&INS_ON_TOP) {
2311  return GET_MAP_TOP(op->map, op->x, op->y);
2312  }
2313  object *last = NULL;
2314  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2315  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)
2316  || QUERY_FLAG(tmp, FLAG_OVERLAY_FLOOR))
2317  floor = tmp;
2318 
2319  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
2320  && (tmp->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH))
2321  && !QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2322  /* We insert above tmp, so we want this object below this */
2323  break;
2324  }
2325  last = tmp;
2326  } FOR_MAP_FINISH();
2327  if (flag&INS_ABOVE_FLOOR_ONLY)
2328  return floor;
2329  return last;
2330 }
2331 
2360 object *object_insert_in_map(object *op, mapstruct *m, object *originator, int flag) {
2361  object *tmp, *top, *floor = NULL;
2362  int16_t x, y;
2363 
2364  if (QUERY_FLAG(op, FLAG_FREED)) {
2365  LOG(llevError, "Trying to insert freed object!\n");
2366  return NULL;
2367  }
2368  if (m == NULL) {
2369  StringBuffer *sb;
2370  char *diff;
2371 
2372  sb = stringbuffer_new();
2373  object_dump(op, sb);
2374  diff = stringbuffer_finish(sb);
2375  LOG(llevError, "Trying to insert in null-map!\n%s\n", diff);
2376  free(diff);
2377  return op;
2378  }
2379  if (out_of_map(m, op->x, op->y)) {
2380  StringBuffer *sb;
2381  char *diff;
2382 
2383  sb = stringbuffer_new();
2384  object_dump(op, sb);
2385  diff = stringbuffer_finish(sb);
2386  LOG(llevError, "Trying to insert object outside the map.\n%s\n", diff);
2387  free(diff);
2388 #ifdef MANY_CORES
2389  /* Better to catch this here, as otherwise the next use of this object
2390  * is likely to cause a crash. Better to find out where it is getting
2391  * improperly inserted.
2392  */
2393  abort();
2394 #endif
2395  return op;
2396  }
2397  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2398  StringBuffer *sb;
2399  char *diff;
2400 
2401  sb = stringbuffer_new();
2402  object_dump(op, sb);
2403  diff = stringbuffer_finish(sb);
2404  LOG(llevError, "Trying to insert (map) inserted object.\n%s\n", diff);
2405  free(diff);
2406  return op;
2407  }
2408  if (op->more != NULL) {
2409  /* The part may be on a different map. */
2410 
2411  object *more = op->more;
2412 
2413  /* We really need the caller to normalize coordinates - if
2414  * we set the map, that doesn't work if the location is within
2415  * a map and this is straddling an edge. So only if coordinate
2416  * is clear wrong do we normalize it.
2417  */
2418  if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
2419  /* Debugging information so you can see the last coordinates this object had */
2420  more->ox = more->x;
2421  more->oy = more->y;
2422  more->map = get_map_from_coord(more->map, &more->x, &more->y);
2423  } else if (!more->map) {
2424  /* For backwards compatibility - when not dealing with tiled maps,
2425  * more->map should always point to the parent.
2426  */
2427  more->map = m;
2428  }
2429 
2430  if (object_insert_in_map(more, more->map, originator, flag) == NULL) {
2431  if (!op->head)
2432  LOG(llevError, "BUG: object_insert_in_map(): inserting op->more killed op\n");
2433  return NULL;
2434  }
2435  }
2436  CLEAR_FLAG(op, FLAG_REMOVED);
2437 
2438  /* Debugging information so you can see the last coordinates this object had */
2439  op->ox = op->x;
2440  op->oy = op->y;
2441  x = op->x;
2442  y = op->y;
2443  op->map = get_map_from_coord(m, &x, &y);
2444  if (op->map == NULL) {
2445  // This can fail despite out_of_map() returning false.
2446  return op;
2447  }
2448 
2449  /* this has to be done after we translate the coordinates. */
2450  if (op->nrof
2451  && !(flag&INS_NO_MERGE)
2452  && op->type != SPELL_EFFECT) {
2453  FOR_MAP_PREPARE(op->map, x, y, spot) {
2454  if (object_can_merge(op, spot)) {
2455  op->nrof += spot->nrof;
2456  object_remove(spot);
2458  }
2459  } FOR_MAP_FINISH();
2460  } else if (op->type == SPELL_EFFECT
2461  && !op->range
2462  && !op->other_arch
2463  && (op->speed_left+op->speed) < 0.0) {
2464  object_merge_spell(op, x, y);
2465  }
2466 
2467  /* Ideally, the caller figures this out. However, it complicates a lot
2468  * of areas of callers (eg, anything that uses object_find_free_spot() would now
2469  * need extra work
2470  */
2471  if (op->map != m) {
2472  /* coordinates should not change unless map also changes */
2473  op->x = x;
2474  op->y = y;
2475  }
2476 
2477  if (op->type != LAMP)
2478  /* lamps use the FLAG_APPLIED to keep the light/unlit status, so don't reset it.
2479  Other objects just get unapplied, since the container "drops" them. */
2480  CLEAR_FLAG(op, FLAG_APPLIED);
2482  if (!QUERY_FLAG(op, FLAG_ALIVE))
2484 
2485  /* In many places, a player is passed as the originator, which
2486  * is fine. However, if the player is on a transport, they are not
2487  * actually on the map, so we can't use them for the linked pointers,
2488  * nor should the walk on function below use them either.
2489  */
2490  if (originator && originator->contr && originator->contr->transport)
2491  originator = originator->contr->transport;
2492 
2493  if (flag&INS_BELOW_ORIGINATOR && originator != NULL) {
2494  if (originator->map != op->map
2495  || originator->x != op->x
2496  || originator->y != op->y) {
2497  LOG(llevError, "object_insert_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
2498  abort();
2499  }
2500  op->above = originator;
2501  op->below = originator->below;
2502  if (op->below)
2503  op->below->above = op;
2504  else
2505  SET_MAP_OB(op->map, op->x, op->y, op);
2506  /* since *below *originator, no need to update top */
2507  originator->below = op;
2508  } else {
2509  /* Top is the object that our object (op) is going to get inserted above. */
2510  top = find_insert_pos(op, flag);
2511 
2512  /* First object on this space */
2513  if (!top) {
2514  op->above = GET_MAP_OB(op->map, op->x, op->y);
2515  if (op->above)
2516  op->above->below = op;
2517  op->below = NULL;
2518  SET_MAP_OB(op->map, op->x, op->y, op);
2519  } else { /* get inserted into the stack above top */
2520  op->above = top->above;
2521  if (op->above)
2522  op->above->below = op;
2523  op->below = top;
2524  top->above = op;
2525  }
2526  if (op->above == NULL)
2527  SET_MAP_TOP(op->map, op->x, op->y, op);
2528  } /* else not INS_BELOW_ORIGINATOR */
2529 
2530  if (!(flag&INS_MAP_LOAD)) {
2531  if (op->type == PLAYER)
2532  op->contr->do_los = 1;
2533 
2534  /* If we have a floor, we know the player, if any, will be above
2535  * it, so save a few ticks and start from there.
2536  */
2537  tmp = floor ? floor : GET_MAP_OB(op->map, op->x, op->y);
2539  if (tmp->type == PLAYER)
2540  tmp->contr->socket->update_look = 1;
2542 
2543  /* If this object glows, it may affect lighting conditions that are
2544  * visible to others on this map. But update_all_los is really
2545  * an inefficient way to do this, as it means los for all players
2546  * on the map will get recalculated. The players could very well
2547  * be far away from this change and not affected in any way -
2548  * this should get redone to only look for players within range,
2549  * or just updating the P_NEED_UPDATE for spaces within this area
2550  * of effect may be sufficient.
2551  */
2552  if (MAP_DARKNESS(op->map) && (op->glow_radius != 0))
2553  update_all_los(op->map, op->x, op->y);
2554 
2555  if (op->contr && !op->contr->hidden)
2556  op->map->players++;
2557  }
2558 
2559  /* updates flags (blocked, alive, no magic, etc) for this map space */
2561 
2562  /* Don't know if moving this to the end will break anything. However,
2563  * we want to have update_look set above before calling this.
2564  *
2565  * object_check_move_on() must be after this because code called from
2566  * object_check_move_on() depends on correct map flags (so functions like
2567  * blocked() and wall() work properly), and these flags are updated by
2568  * object_update().
2569  */
2570 
2571  /* if this is not the head or flag has been passed, don't check walk on status */
2572 
2573  if (!(flag&INS_NO_WALK_ON) && !op->head) {
2574  if (object_check_move_on(op, originator))
2575  return NULL;
2576 
2577  /* If we are a multi part object, lets work our way through the check
2578  * walk on's.
2579  */
2580  for (tmp = op->more; tmp != NULL; tmp = tmp->more)
2581  if (object_check_move_on(tmp, originator))
2582  return NULL;
2583  }
2584  return op;
2585 }
2586 
2596 void object_replace_insert_in_map(const char *arch_string, object *op) {
2597  object *tmp1;
2598  archetype *at;
2599 
2600  /* first search for itself and remove any old instances */
2601  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2602  if (!strcmp(tmp->arch->name, arch_string)) { /* same archetype */
2603  object_remove(tmp);
2605  }
2606  } FOR_MAP_FINISH();
2607 
2608  at = find_archetype(arch_string);
2609  if (at == NULL) {
2610  return;
2611  }
2612  tmp1 = arch_to_object(at);
2613  object_insert_in_map_at(tmp1, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
2614 }
2615 
2636 object *object_split(object *orig_ob, uint32_t nr, char *err, size_t size) {
2637  object *newob;
2638 
2639  if (MAX(1, orig_ob->nrof) < nr) {
2640  /* If err is set, the caller knows that nr can be wrong (player trying to drop items), thus don't log that. */
2641  if (err)
2642  snprintf(err, size, "There are only %u %ss.", NROF(orig_ob), orig_ob->name);
2643  else
2644  LOG(llevDebug, "There are only %u %ss.\n", NROF(orig_ob), orig_ob->name);
2645  return NULL;
2646  }
2647  newob = object_create_clone(orig_ob);
2648  if (orig_ob->nrof == 0) {
2649  if (!QUERY_FLAG(orig_ob, FLAG_REMOVED)) {
2650  object_remove(orig_ob);
2651  }
2653  } else {
2654  newob->nrof = nr;
2655  object_decrease_nrof(orig_ob, nr);
2656  }
2657 
2658  return newob;
2659 }
2660 
2675 object *object_decrease_nrof(object *op, uint32_t i) {
2676  object *tmp;
2677 
2678  if (i == 0) /* objects with op->nrof require this check */
2679  return op;
2680 
2681  if (i > op->nrof)
2682  i = op->nrof;
2683 
2684  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2685  op->nrof -= i;
2686  } else if (op->env != NULL) {
2687  if (i < op->nrof) {
2688  player *pl;
2689  /* is this object in the players inventory, or sub container
2690  * therein?
2691  */
2692  tmp = object_get_player_container(op->env);
2693  /* nope. Is this a container the player has opened?
2694  * If so, set tmp to that player.
2695  * IMO, searching through all the players will mostly
2696  * likely be quicker than following op->env to the map,
2697  * and then searching the map for a player.
2698  */
2699  if (!tmp) {
2700  for (pl = first_player; pl; pl = pl->next)
2701  if (pl->ob->container == op->env)
2702  break;
2703  if (pl)
2704  tmp = pl->ob;
2705  else
2706  tmp = NULL;
2707  }
2708 
2709  /* Because of weight reduction by container and integer arithmetic,
2710  * there is no guarantee the rounded weight of combined items will be
2711  * the same as the sum of rounded weights.
2712  * Therefore just remove the current weight, and add the new.
2713  * Same adjustment done in object_increase_nrof().
2714  */
2715  object_sub_weight(op->env, op->weight * op->nrof);
2716  op->nrof -= i;
2717  object_add_weight(op->env, op->weight * op->nrof);
2718  if (tmp) {
2719  esrv_update_item(UPD_NROF, tmp, op);
2720  esrv_update_item(UPD_WEIGHT, tmp, op->env);
2721  fix_object(tmp);
2722  }
2723  } else {
2724  object_remove(op);
2725  op->nrof = 0;
2726  }
2727  } else {
2728  /* On a map. */
2729  if (i < op->nrof) {
2730  op->nrof -= i;
2731 
2732  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2733  if (pl->contr) {
2734  pl->contr->socket->update_look = 1;
2735  break;
2736  }
2737  FOR_MAP_FINISH();
2738  } else {
2739  object_remove(op);
2740  op->nrof = 0;
2741  }
2742  }
2743 
2744  if (op->nrof) {
2745  return op;
2746  } else {
2748  return NULL;
2749  }
2750 }
2751 
2762 static void object_increase_nrof(object *op, uint32_t i) {
2763  object *tmp;
2764 
2765  if (i == 0) /* objects with op->nrof require this check */
2766  return;
2767 
2768  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2769  op->nrof += i;
2770  } else if (op->env != NULL) {
2771  player *pl;
2772  /* is this object in the players inventory, or sub container
2773  * therein?
2774  */
2775  tmp = object_get_player_container(op->env);
2776  /* nope. Is this a container the player has opened?
2777  * If so, set tmp to that player.
2778  * IMO, searching through all the players will mostly
2779  * likely be quicker than following op->env to the map,
2780  * and then searching the map for a player.
2781  */
2782  if (!tmp) {
2783  for (pl = first_player; pl; pl = pl->next)
2784  if (pl->ob->container == op->env)
2785  break;
2786  if (pl)
2787  tmp = pl->ob;
2788  else
2789  tmp = NULL;
2790  }
2791 
2792  /* Because of weight reduction by container and integer arithmetic,
2793  * there is no guarantee the rounded weight of combined items will be
2794  * the same as the sum of rounded weights.
2795  * Therefore just remove the current weight, and add the new.
2796  * Same adjustment done in object_decrease_nrof().
2797  */
2798  object_sub_weight(op->env, op->weight * op->nrof);
2799  op->nrof += i;
2800  object_add_weight(op->env, op->weight * op->nrof);
2801  if (tmp) {
2802  esrv_update_item(UPD_NROF, tmp, op);
2803  // Why don't we need to update weight of op->env here?
2804  }
2805  } else {
2806  /* On a map. */
2807  op->nrof += i;
2808 
2809  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2810  if (pl->contr) {
2811  pl->contr->socket->update_look = 1;
2812  break;
2813  }
2814  FOR_MAP_FINISH();
2815  }
2816 }
2817 
2832 void object_add_weight(object *op, signed long weight) {
2833  while (op != NULL) {
2834  if (op->type == CONTAINER) {
2835  weight = (signed long)(weight*(100-op->stats.Str)/100);
2836  }
2837  op->carrying += weight;
2838  op = op->env;
2839  }
2840 }
2841 
2856 object *object_insert_in_ob(object *op, object *where) {
2857  object *otmp;
2858 
2859  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2860  StringBuffer *sb;
2861  char *diff;
2862 
2863  sb = stringbuffer_new();
2864  object_dump(op, sb);
2865  diff = stringbuffer_finish(sb);
2866  LOG(llevError, "Trying to insert (ob) inserted object.\n%s\n", diff);
2867  free(diff);
2868  return op;
2869  }
2870 
2871  if (where == NULL) {
2872  StringBuffer *sb;
2873  char *diff;
2874 
2875  sb = stringbuffer_new();
2876  object_dump(op, sb);
2877  diff = stringbuffer_finish(sb);
2878  LOG(llevError, "Trying to put object in NULL.\n%s\n", diff);
2879  free(diff);
2880  return op;
2881  }
2882  if (where->head) {
2883  LOG(llevDebug, "Warning: Tried to insert object wrong part of multipart object.\n");
2884  }
2885  where = HEAD(where);
2886  if (op->more) {
2887  LOG(llevError, "Tried to insert multipart object %s (%u)\n", op->name, op->count);
2888  return op;
2889  }
2891  CLEAR_FLAG(op, FLAG_REMOVED);
2892  if (op->nrof || op->type == SKILL) {
2893  FOR_INV_PREPARE(where, tmp)
2894  // Since harvesting skills have the same subtype, we need to check our shared string skill name as well
2895  if (op->type == SKILL && tmp->type == SKILL && op->subtype == tmp->subtype && op->skill == tmp->skill) {
2896  // Duplicate skill. Sum exp and total_exp.
2897  LOG(llevDebug, "Merged duplicate skill %s for %s\n", op->arch->name, where->name);
2898  tmp->stats.exp += op->stats.exp;
2899  tmp->total_exp += op->total_exp;
2900  SET_FLAG(op, FLAG_REMOVED);
2901  object_free(op, FREE_OBJ_FREE_INVENTORY | FREE_OBJ_NO_DESTROY_CALLBACK); /* free the inserted object */
2902  return tmp;
2903  } else if (object_can_merge(tmp, op)) {
2904  /* return the original object and remove inserted object
2905  * (client needs the original object) */
2906  object_increase_nrof(tmp, op->nrof);
2907  SET_FLAG(op, FLAG_REMOVED);
2908  object_free(op, FREE_OBJ_FREE_INVENTORY | FREE_OBJ_NO_DESTROY_CALLBACK); /* free the inserted object */
2909  return tmp;
2910  }
2911  FOR_INV_FINISH();
2912 
2913  /* the item couldn't merge. */
2914  object_add_weight(where, op->weight*op->nrof);
2915  } else
2916  object_add_weight(where, op->weight+op->carrying);
2917 
2918  op->map = NULL;
2919  op->env = where;
2920  op->above = NULL;
2921  op->below = NULL;
2922  op->x = 0,
2923  op->y = 0;
2924  op->ox = 0,
2925  op->oy = 0;
2926 
2927  /* Client has no idea of ordering so lets not bother ordering it here.
2928  * It sure simplifies this function...
2929  */
2930  if (where->inv == NULL)
2931  where->inv = op;
2932  else {
2933  op->below = where->inv;
2934  op->below->above = op;
2935  where->inv = op;
2936  }
2937 
2938  if (op->type == EVENT_CONNECTOR) {
2939  where->event_bitmask |= BITMASK_EVENT(op->subtype);
2940  }
2941 
2942  /* Update in 2 cases: object goes into player's inventory, or object goes into container the player
2943  * is looking into. */
2944  if (where->contr != NULL)
2945  esrv_send_item(where, op);
2946  else if (where->type == CONTAINER && QUERY_FLAG(where, FLAG_APPLIED)) {
2947  object *pl = NULL;
2948 
2949  if (op->env->env && op->env->env->contr)
2950  /* Container is in player's inventory. */
2951  pl = op->env->env;
2952  else if (op->env->map) {
2953  /* Container on map, look above for player. */
2955  if (above->contr) {
2956  pl = above;
2957  break;
2958  }
2959  FOR_ABOVE_FINISH();
2960  }
2961  if (pl)
2962  esrv_send_item(pl, op);
2963  }
2964 
2965  otmp = object_get_player_container(where);
2966  if (otmp && otmp->contr != NULL) {
2967  if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER)
2968  && (QUERY_FLAG(op, FLAG_APPLIED) || op->type == SKILL || op->glow_radius != 0))
2969  /* fix_object will only consider applied items, or skills, or items with a glow radius.
2970  thus no need to call it if our object hasn't that. */
2971  fix_object(otmp);
2972  }
2973 
2974  /* reset the light list and los of the players on the map */
2975  if (op->glow_radius != 0 && where->map) {
2976 #ifdef DEBUG_LIGHTS
2977  LOG(llevDebug, " object_insert_in_ob(): got %s to insert in map/op\n", op->name);
2978 #endif /* DEBUG_LIGHTS */
2979  if (MAP_DARKNESS(where->map)) {
2980  SET_MAP_FLAGS(where->map, where->x, where->y, P_NEED_UPDATE);
2981  update_position(where->map, where->x, where->y);
2982  update_all_los(where->map, where->x, where->y);
2983  }
2984  }
2985 
2986  return op;
2987 }
2988 
3011 int object_check_move_on(object *op, object *originator) {
3012  object *tmp;
3013  tag_t tag;
3014  mapstruct *m = op->map;
3015  int x = op->x, y = op->y;
3016  MoveType move_on, move_slow, move_block;
3017 
3018  if (QUERY_FLAG(op, FLAG_NO_APPLY))
3019  return 0;
3020 
3021  tag = op->count;
3022 
3023  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
3024  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
3025  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
3026 
3027  /* if nothing on this space will slow op down or be applied,
3028  * no need to do checking below. have to make sure move_type
3029  * is set, as lots of objects don't have it set - we treat that
3030  * as walking.
3031  */
3032  if (op->move_type
3033  && !(op->move_type&move_on)
3034  && !(op->move_type&move_slow))
3035  return 0;
3036 
3037  /* This is basically inverse logic of that below - basically,
3038  * if the object can avoid the move on or slow move, they do so,
3039  * but can't do it if the alternate movement they are using is
3040  * blocked. Logic on this seems confusing, but does seem correct.
3041  */
3042  if ((op->move_type&~move_on&~move_block) != 0
3043  && (op->move_type&~move_slow&~move_block) != 0)
3044  return 0;
3045 
3046  /* The objects have to be checked from top to bottom.
3047  * Hence, we first go to the top:
3048  */
3049 
3050  tmp = GET_MAP_OB(op->map, op->x, op->y);
3052  if (tmp->above == NULL)
3053  break;
3054  /* Trim the search when we find the first other spell effect
3055  * this helps performance so that if a space has 50 spell objects,
3056  * we don't need to check all of them.
3057  */
3058  if ((tmp->move_type&MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK))
3059  break;
3062  if (tmp == op)
3063  continue; /* Can't apply yourself */
3064 
3065  /* Check to see if one of the movement types should be slowed down.
3066  * Second check makes sure that the movement types not being slowed
3067  * (~slow_move) is not blocked on this space - just because the
3068  * space doesn't slow down swimming (for example), if you can't actually
3069  * swim on that space, can't use it to avoid the penalty.
3070  */
3071  if (!QUERY_FLAG(op, FLAG_WIZPASS)) {
3072  if ((!op->move_type && tmp->move_slow&MOVE_WALK)
3073  || ((op->move_type&tmp->move_slow) && (op->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
3074  float diff;
3075 
3076  diff = tmp->move_slow_penalty*FABS(op->speed);
3077  if (op->type == PLAYER) {
3080  diff /= 4.0;
3081  }
3082  }
3083  op->speed_left -= diff;
3084  }
3085  }
3086 
3087  /* Basically same logic as above, except now for actual apply. */
3088  if ((!op->move_type && tmp->move_on&MOVE_WALK)
3089  || ((op->move_type&tmp->move_on) && (op->move_type&~tmp->move_on&~tmp->move_block) == 0)) {
3090  ob_move_on(tmp, op, originator);
3091  if (object_was_destroyed(op, tag))
3092  return 1;
3093 
3094  /* what the person/creature stepped onto has moved the object
3095  * someplace new. Don't process any further - if we did,
3096  * have a feeling strange problems would result.
3097  */
3098  if (op->map != m || op->x != x || op->y != y)
3099  return 0;
3100  }
3102  return 0;
3103 }
3104 
3117 object *map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at) {
3118  if (m == NULL || OUT_OF_REAL_MAP(m, x, y)) {
3119  LOG(llevError, "Present_arch called outside map.\n");
3120  return NULL;
3121  }
3122 
3123  FOR_MAP_PREPARE(m, x, y, tmp)
3124  if (tmp->arch == at)
3125  return tmp;
3126  FOR_MAP_FINISH();
3127 
3128  return NULL;
3129 }
3130 
3144 object *map_find_by_type(mapstruct *m, int x, int y, uint8_t type) {
3145  if (OUT_OF_REAL_MAP(m, x, y)) {
3146  return NULL;
3147  }
3148 
3149  FOR_MAP_PREPARE(m, x, y, tmp)
3150  if (tmp->type == type)
3151  return tmp;
3152  FOR_MAP_FINISH();
3153 
3154  return NULL;
3155 }
3156 
3167 object *object_present_in_ob(uint8_t type, const object *op) {
3168  object *tmp;
3169 
3170  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3171  if (tmp->type == type)
3172  return tmp;
3173 
3174  return NULL;
3175 }
3176 
3202 object *object_present_in_ob_by_name(int type, const char *str, const object *op) {
3203  object *tmp;
3204 
3205  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3206  if ((type == -1 || tmp->type == type) && !strcmp(str, tmp->name))
3207  return tmp;
3208  }
3209  return NULL;
3210 }
3211 
3221 object *arch_present_in_ob(const archetype *at, const object *op) {
3222  object *tmp;
3223 
3224  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3225  if (tmp->arch == at)
3226  return tmp;
3227  return NULL;
3228 }
3229 
3238 void object_set_flag_inv(object*op, int flag) {
3239  object *tmp;
3240 
3241  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3242  SET_FLAG(tmp, flag);
3243  object_set_flag_inv(tmp, flag);
3244  }
3245 }
3246 
3255 void object_unset_flag_inv(object*op, int flag) {
3256  object *tmp;
3257 
3258  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3259  CLEAR_FLAG(tmp, flag);
3260  object_unset_flag_inv(tmp, flag);
3261  }
3262 }
3263 
3273 void object_set_cheat(object *op) {
3274  SET_FLAG(op, FLAG_WAS_WIZ);
3276 }
3277 
3295 int object_find_multi_free_spot_around(const object *ob, const object *gen, int16_t *hx, int16_t *hy) {
3296  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3297  int freecount = 0;
3298 
3299  ob = HEAD(ob);
3300 
3301  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3302  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3303  /*
3304  * sx and sy are now the coords of the bottom right corner of ob relative to the head.
3305  * genx and geny are now the coords of the bottom right corner of gen relative to the head.
3306  * sx2 and sy2 are now the coords of the head of ob relative to the top left corner.
3307  * genx2 and geny2 are now the coords of the head of gen relative to the top left corner.
3308  */
3309 
3310  sx++;
3311  sy++;
3312  genx++;
3313  geny++;
3314  /*
3315  * sx, sy, genx, and geny, are now the size of the object, excluding parts left and above
3316  * the head.
3317  */
3318 
3319  ix = gen->x-sx-genx2;
3320  iy = gen->y-sy-geny2;
3321  sx += genx+sx2;
3322  sy += geny+sy2;
3323  /*
3324  * ix and iy are the map coords of the top left square where the head of ob could possibly
3325  * be placed. sx and sy are now the size of the square to search for placement of the head
3326  * relative to ix and iy.
3327  */
3328 
3329  /*
3330  * Loop around the square of possible positions for the head of ob object:
3331  */
3332  for (i = 0; i < (sx+sx+sy+sy); i++) {
3333  if (i <= sx) {
3334  nx = i+ix;
3335  ny = iy;
3336  } else if (i <= sx+sy) {
3337  nx = ix+sx;
3338  ny = iy+i-sx;
3339  } else if (i <= sx+sy+sx) {
3340  nx = ix+sx-(i-(sx+sy));
3341  ny = iy+sy;
3342  } else {
3343  nx = ix;
3344  ny = iy+sy-(i-(sx+sy+sx));
3345  }
3346  /* Check if the spot is free. */
3347  flag = ob_blocked(ob, gen->map, nx, ny);
3348  if (!flag) {
3349  freecount++;
3350  }
3351  }
3352  /* If no free spaces, return. */
3353  if (!freecount)
3354  return -1;
3355 
3356  /* Choose a random valid position */
3357  freecount = RANDOM()%freecount;
3358  for (i = 0; i < sx+sx+sy+sy; i++) {
3359  if (i <= sx) {
3360  nx = i+ix;
3361  ny = iy;
3362  } else if (i <= sx+sy) {
3363  nx = ix+sx;
3364  ny = iy+i-sx;
3365  } else if (i <= sx+sy+sx) {
3366  nx = ix+sx-(i-(sx+sy));
3367  ny = iy+sy;
3368  } else {
3369  nx = ix;
3370  ny = iy+sy-(i-(sx+sy+sx));
3371  }
3372 
3373  /* Make sure it's within map. */
3374  if (nx < 0 || nx >= MAP_WIDTH(gen->map)
3375  || ny < 0 || ny >= MAP_HEIGHT(gen->map))
3376  continue;
3377 
3378  /* Check if the spot is free.*/
3379  flag = ob_blocked(ob, gen->map, nx, ny);
3380  if (!flag) {
3381  freecount--;
3382  if (freecount <= 0) {
3383  *hx = nx;
3384  *hy = ny;
3385  return 0;
3386  }
3387  }
3388  }
3389  return -1;
3390 }
3391 
3411 int object_find_multi_free_spot_within_radius(const object *ob, const object *gen, int *hx, int *hy) {
3412  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3413  int8_t x, y, radius;
3414  int freecount = 0, freecountstop = 0;
3415  const char *value;
3416  int8_t *x_array;
3417  int8_t *y_array;
3418 
3419  /* If radius is not set, default to 1 */
3420  value = object_get_value(gen, "generator_radius");
3421  if (value) {
3422  radius = (int8_t)strtol(value, NULL, 10);
3423  if (radius < 1) {
3424  radius = 1;
3425  }
3426  } else {
3427  radius = 1;
3428  }
3429 
3430  ob = HEAD(ob);
3431 
3432  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3433  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3434  /*
3435  * sx and sy are now the coords of the bottom right corner
3436  * of ob relative to the head.
3437  * genx and geny are now the coords of the bottom right corner
3438  * of gen relative to the head.
3439  * sx2 and sy2 are now the coords of the head of ob relative
3440  * to the top left corner.
3441  * genx2 and geny2 are now the coords of the head of gen relative
3442  * to the top left corner.
3443  */
3444 
3445  sx++;
3446  sy++;
3447  genx++;
3448  geny++;
3449  /*
3450  * sx, sy, genx, and geny, are now the size of the object,
3451  * excluding parts left and above the head.
3452  */
3453 
3454  ix = gen->x-sx-genx2-radius+1;
3455  iy = gen->y-sy-geny2-radius+1;
3456  sx += genx+sx2+radius*2-1;
3457  sy += geny+sy2+radius*2-1;
3458 
3459  /*
3460  * ix and iy are the map coords of the top left square where
3461  * the head of ob could possibly be placed. sx and sy are now
3462  * the size of the square to search for placement of the head
3463  * relative to ix and iy.
3464  */
3465 
3466  /* Create arrays large enough to hold free space coordinates */
3467  x_array = static_cast<int8_t *>(malloc(sx*sy*sizeof(int8_t)));
3468  y_array = static_cast<int8_t *>(malloc(sx*sy*sizeof(int8_t)));
3469 
3470  /*
3471  * Loop through the area of possible positions for the head of ob object:
3472  */
3473  for (x = 0; x < sx; x++) {
3474  for (y = 0; y < sy; y++) {
3475  nx = ix+x;
3476  ny = iy+y;
3477 
3478 
3479  /* Make sure it's within map. */
3480  if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) {
3481  continue;
3482  }
3483 
3484  /* Check if the spot is free. */
3485  flag = ob_blocked(ob, gen->map, nx, ny);
3486  if (!flag) {
3487  x_array[freecount] = nx;
3488  y_array[freecount] = ny;
3489  freecount++;
3490  }
3491  }
3492  }
3493  /* If no free spaces, return. */
3494  if (!freecount) {
3495  free(x_array);
3496  free(y_array);
3497  return -1;
3498  }
3499 
3500  /* Choose a random valid position */
3501  freecountstop = RANDOM()%freecount;
3502  for (i = 0; i < freecount; i++) {
3503  nx = x_array[i];
3504  ny = y_array[i];
3505 
3506  /* Check if the spot is free.*/
3507  flag = ob_blocked(ob, gen->map, nx, ny);
3508  if (!flag) {
3509  freecountstop--;
3510  if (freecountstop <= 0) {
3511  *hx = nx;
3512  *hy = ny;
3513  free(x_array);
3514  free(y_array);
3515  return 0;
3516  }
3517  }
3518  }
3519  free(x_array);
3520  free(y_array);
3521  return -1;
3522 }
3523 
3558 int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop) {
3559  int i, index = 0, flag;
3560  static int altern[SIZEOFFREE];
3561 
3562  for (i = start; i < stop; i++) {
3563  flag = ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]);
3564  if (!flag)
3565  altern[index++] = i;
3566 
3567  /* Basically, if we find a wall on a space, we cut down the search size.
3568  * In this way, we won't return spaces that are on another side of a wall.
3569  * This mostly work, but it cuts down the search size in all directions -
3570  * if the space being examined only has a wall to the north and empty
3571  * spaces in all the other directions, this will reduce the search space
3572  * to only the spaces immediately surrounding the target area, and
3573  * won't look 2 spaces south of the target space.
3574  */
3575  else if ((flag&AB_NO_PASS) && maxfree[i] < stop)
3576  stop = maxfree[i];
3577  }
3578  if (!index)
3579  return -1;
3580  return altern[RANDOM()%index];
3581 }
3582 
3598 int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y) {
3599  int i;
3600 
3601  for (i = 0; i < SIZEOFFREE; i++) {
3602  if (!ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]))
3603  return i;
3604  }
3605  return -1;
3606 }
3607 
3617 static void permute(int *arr, int begin, int end) {
3618  int i, j, tmp, len;
3619 
3620  len = end-begin;
3621  for (i = begin; i < end; i++) {
3622  j = begin+RANDOM()%len;
3623 
3624  tmp = arr[i];
3625  arr[i] = arr[j];
3626  arr[j] = tmp;
3627  }
3628 }
3629 
3641 void get_search_arr(int *search_arr) {
3642  int i;
3643 
3644  for (i = 0; i < SIZEOFFREE; i++) {
3645  search_arr[i] = i;
3646  }
3647 
3648  permute(search_arr, 1, SIZEOFFREE1+1);
3649  permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1);
3650  permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE);
3651 }
3652 
3660 int object_distance(const object *ob1, const object *ob2) {
3661  int i;
3662 
3663  i = (ob1->x-ob2->x)*(ob1->x-ob2->x)+
3664  (ob1->y-ob2->y)*(ob1->y-ob2->y);
3665  return i;
3666 }
3667 
3676 int find_dir_2(int x, int y) {
3677  int q;
3678 
3679  if (!y)
3680  q = -300*x;
3681  else
3682  q = x*100/y;
3683  if (y > 0) {
3684  if (q < -242)
3685  return 3;
3686  if (q < -41)
3687  return 2;
3688  if (q < 41)
3689  return 1;
3690  if (q < 242)
3691  return 8;
3692  return 7;
3693  }
3694  if (q < -242)
3695  return 7;
3696  if (q < -41)
3697  return 6;
3698  if (q < 41)
3699  return 5;
3700  if (q < 242)
3701  return 4;
3702  return 3;
3703 }
3704 
3713 int absdir(int d) {
3714  // Shortcut for modulus that work becuase we have a power of 2
3715  d &= 7;
3716  // 0 needs to be 8
3717  if (!d)
3718  d = 8;
3719  return d;
3720 }
3721 
3731 int dirdiff(int dir1, int dir2) {
3732  int d;
3733 
3734  d = abs(dir1-dir2);
3735  if (d > 4)
3736  d = 8-d;
3737  return d;
3738 }
3739 
3751 static const int reduction_dir[SIZEOFFREE][3] = {
3752  { 0, 0, 0 }, /* 0 */
3753  { 0, 0, 0 }, /* 1 */
3754  { 0, 0, 0 }, /* 2 */
3755  { 0, 0, 0 }, /* 3 */
3756  { 0, 0, 0 }, /* 4 */
3757  { 0, 0, 0 }, /* 5 */
3758  { 0, 0, 0 }, /* 6 */
3759  { 0, 0, 0 }, /* 7 */
3760  { 0, 0, 0 }, /* 8 */
3761  { 8, 1, 2 }, /* 9 */
3762  { 1, 2, -1 }, /* 10 */
3763  { 2, 10, 12 }, /* 11 */
3764  { 2, 3, -1 }, /* 12 */
3765  { 2, 3, 4 }, /* 13 */
3766  { 3, 4, -1 }, /* 14 */
3767  { 4, 14, 16 }, /* 15 */
3768  { 5, 4, -1 }, /* 16 */
3769  { 4, 5, 6 }, /* 17 */
3770  { 6, 5, -1 }, /* 18 */
3771  { 6, 20, 18 }, /* 19 */
3772  { 7, 6, -1 }, /* 20 */
3773  { 6, 7, 8 }, /* 21 */
3774  { 7, 8, -1 }, /* 22 */
3775  { 8, 22, 24 }, /* 23 */
3776  { 8, 1, -1 }, /* 24 */
3777  { 24, 9, 10 }, /* 25 */
3778  { 9, 10, -1 }, /* 26 */
3779  { 10, 11, -1 }, /* 27 */
3780  { 27, 11, 29 }, /* 28 */
3781  { 11, 12, -1 }, /* 29 */
3782  { 12, 13, -1 }, /* 30 */
3783  { 12, 13, 14 }, /* 31 */
3784  { 13, 14, -1 }, /* 32 */
3785  { 14, 15, -1 }, /* 33 */
3786  { 33, 15, 35 }, /* 34 */
3787  { 16, 15, -1 }, /* 35 */
3788  { 17, 16, -1 }, /* 36 */
3789  { 18, 17, 16 }, /* 37 */
3790  { 18, 17, -1 }, /* 38 */
3791  { 18, 19, -1 }, /* 39 */
3792  { 41, 19, 39 }, /* 40 */
3793  { 19, 20, -1 }, /* 41 */
3794  { 20, 21, -1 }, /* 42 */
3795  { 20, 21, 22 }, /* 43 */
3796  { 21, 22, -1 }, /* 44 */
3797  { 23, 22, -1 }, /* 45 */
3798  { 45, 47, 23 }, /* 46 */
3799  { 23, 24, -1 }, /* 47 */
3800  { 24, 9, -1 } /* 48 */
3801 };
3802 
3821 int can_see_monsterP(mapstruct *m, int x, int y, int dir) {
3822  int16_t dx, dy;
3823  int mflags;
3824 
3825  if (dir < 0)
3826  return 0; /* exit condition: invalid direction */
3827 
3828  dx = x+freearr_x[dir];
3829  dy = y+freearr_y[dir];
3830 
3831  mflags = get_map_flags(m, &m, dx, dy, &dx, &dy);
3832 
3833  /* This functional arguably was incorrect before - it was
3834  * checking for P_WALL - that was basically seeing if
3835  * we could move to the monster - this is being more
3836  * literal on if we can see it. To know if we can actually
3837  * move to the monster, we'd need the monster passed in or
3838  * at least its move type.
3839  */
3840  if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
3841  return 0;
3842 
3843  /* yes, can see. */
3844  if (dir < 9)
3845  return 1;
3846  return can_see_monsterP(m, x, y, reduction_dir[dir][0])|
3847  can_see_monsterP(m, x, y, reduction_dir[dir][1])|
3848  can_see_monsterP(m, x, y, reduction_dir[dir][2]);
3849 }
3850 
3866 int object_can_pick(const object *who, const object *item) {
3867  /* I re-wrote this as a series of if statements
3868  * instead of a nested return (foo & bar && yaz)
3869  * - I think this is much more readable,
3870  * and likely compiler effectively optimizes it the
3871  * same.
3872  */
3873  if (item->weight <= 0)
3874  return 0;
3875  if (QUERY_FLAG(item, FLAG_NO_PICK))
3876  return 0;
3877  if (QUERY_FLAG(item, FLAG_ALIVE))
3878  return 0;
3879  if (item->invisible)
3880  return 0;
3881  if (item->type == TRANSPORT && item->contr != NULL) {
3882  return 0;
3883  }
3884 
3885  /* Weight limit for monsters */
3886  if (who->type != PLAYER && ((uint32_t)(who->weight+who->carrying+item->weight)) > get_weight_limit(who->stats.Str))
3887  return 0;
3888 
3889  /* Can not pick up multipart objects */
3890  if (item->head || item->more)
3891  return 0;
3892 
3893  /* Everything passes, so OK to pick up */
3894  return 1;
3895 }
3896 
3908 object *object_create_clone(object *asrc) {
3909  object *dst = NULL, *tmp, *src, *part, *prev;
3910 
3911  if (!asrc)
3912  return NULL;
3913  src = HEAD(asrc);
3914 
3915  prev = NULL;
3916  for (part = src; part; part = part->more) {
3917  tmp = object_new();
3918  object_copy(part, tmp);
3919  /*
3920  * Need to reset the weight, since object_insert_in_ob() later will
3921  * recompute this field.
3922  */
3923  tmp->carrying = tmp->arch->clone.carrying;
3924  tmp->x -= src->x;
3925  tmp->y -= src->y;
3926  if (!part->head) {
3927  dst = tmp;
3928  tmp->head = NULL;
3929  } else {
3930  tmp->head = dst;
3931  }
3932  tmp->more = NULL;
3933  if (prev)
3934  prev->more = tmp;
3935  prev = tmp;
3936  }
3937  /*** copy inventory ***/
3938  FOR_INV_PREPARE(src, item)
3939  (void)object_insert_in_ob(object_create_clone(item), dst);
3940  FOR_INV_FINISH();
3941 
3942  return dst;
3943 }
3944 
3955 object *object_find_by_name(const object *who, const char *name) {
3956  const char *name_shared = add_string(name);
3957  object *tmp;
3958 
3959  for (tmp = who->inv; tmp; tmp = tmp->below)
3960  if (tmp->name == name_shared)
3961  break;
3962  free_string(name_shared);
3963  return tmp;
3964 }
3965 
3979 object *object_find_by_type(const object *who, int type) {
3980  object *tmp;
3981 
3982  for (tmp = who->inv; tmp; tmp = tmp->below)
3983  if (tmp->type == type)
3984  return tmp;
3985 
3986  return NULL;
3987 }
3988 
4003 object *object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags) {
4004  int flag_okay;
4005  for (object *tmp = who->inv; tmp; tmp = tmp->below)
4006  if (tmp->type == type) {
4007  flag_okay = 1;
4008  for (int i = 0; i < num_flags; ++i) {
4009  if (QUERY_FLAG(tmp, flags[i])) {
4010  flag_okay = 0; // A flag we didn't want set was set. Skip this item.
4011  break;
4012  }
4013  }
4014  if (flag_okay) // If flag_okay == 1, then the flags specified were not set
4015  return tmp; // If we reach here, none of the flags specified were set. Just like we wanted.
4016  }
4017 
4018  return NULL;
4019 }
4020 
4036 object *object_find_by_type2(const object *who, int type1, int type2) {
4037  object *tmp;
4038 
4039  for (tmp = who->inv; tmp; tmp = tmp->below)
4040  if (tmp->type == type1 || tmp->type == type2)
4041  return tmp;
4042 
4043  return NULL;
4044 }
4045 
4059 object *object_find_by_tag(const object *who, tag_t tag) {
4060  object *tmp;
4061 
4062  for (tmp = who->inv; tmp; tmp = tmp->below)
4063  if (tmp->count == tag)
4064  return tmp;
4065 
4066  return NULL;
4067 }
4068 
4082 object *object_find_by_type_applied(const object *who, int type) {
4083  object *tmp;
4084 
4085  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4086  if (tmp->type == type && QUERY_FLAG(tmp, FLAG_APPLIED))
4087  return tmp;
4088 
4089  return NULL;
4090 }
4091 
4107 object *object_find_by_type_and_name(const object *who, int type, const char *name) {
4108  object *tmp;
4109 
4110  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4111  if (tmp->type == type && strcmp(tmp->name, name) == 0)
4112  return tmp;
4113 
4114  return NULL;
4115 }
4116 
4132 object *object_find_by_type_and_race(const object *who, int type, const char *race) {
4133  object *tmp;
4134 
4135  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4136  if (tmp->type == type && strcmp(tmp->race, race) == 0)
4137  return tmp;
4138 
4139  return NULL;
4140 }
4141 
4157 object *object_find_by_type_and_slaying(const object *who, int type, const char *slaying) {
4158  object *tmp;
4159 
4160  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4161  if (tmp->type == type && tmp->slaying != NULL && strcmp(tmp->slaying, slaying) == 0)
4162  return tmp;
4163 
4164  return NULL;
4165 }
4166 
4182 object *object_find_by_type_and_skill(const object *who, int type, const char *skill) {
4183  object *tmp;
4184 
4185  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4186  if (tmp->type == type && tmp->skill != NULL && strcmp(tmp->skill, skill) == 0)
4187  return tmp;
4188 
4189  return NULL;
4190 }
4191 
4205 object *object_find_by_flag(const object *who, int flag) {
4206  object *tmp;
4207 
4208  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4209  if (QUERY_FLAG(tmp, flag))
4210  return tmp;
4211 
4212  return NULL;
4213 }
4214 
4228 object *object_find_by_flag_applied(const object *who, int flag) {
4229  object *tmp;
4230 
4231  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4232  if (QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, flag))
4233  return tmp;
4234 
4235  return NULL;
4236 }
4237 
4251 object *object_find_by_arch_name(const object *who, const char *name) {
4252  object *tmp;
4253 
4254  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4255  if (strcmp(tmp->arch->name, name) == 0)
4256  return tmp;
4257 
4258  return NULL;
4259 }
4260 
4276 object *object_find_by_type_and_arch_name(const object *who, int type, const char *name) {
4277  object *tmp;
4278 
4279  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4280  if (tmp->type == type && strcmp(tmp->arch->name, name) == 0)
4281  return tmp;
4282 
4283  return NULL;
4284 }
4285 
4300 object *object_find_by_type_subtype(const object *who, int type, int subtype) {
4301  object *tmp;
4302 
4303  for (tmp = who->inv; tmp; tmp = tmp->below)
4304  if (tmp->type == type && tmp->subtype == subtype)
4305  return tmp;
4306 
4307  return NULL;
4308 }
4309 
4320 key_value *object_get_key_value(const object *ob, const char *key) {
4321  key_value *link;
4322 
4323  for (link = ob->key_values; link != NULL; link = link->next) {
4324  if (link->key == key) {
4325  return link;
4326  }
4327  }
4328 
4329  return NULL;
4330 }
4331 
4345 sstring object_get_value(const object *op, const char *const key) {
4346  key_value *link;
4347  const char *canonical_key;
4348 
4349  canonical_key = find_string(key);
4350 
4351  if (canonical_key == NULL) {
4352  /* 1. There being a field named key on any object
4353  * implies there'd be a shared string to find.
4354  * 2. Since there isn't, no object has this field.
4355  * 3. Therefore, *this *object doesn't have this field.
4356  */
4357  return NULL;
4358  }
4359 
4360  /* This is copied from object_get_key_value() above -
4361  * only 4 lines, and saves the function call overhead.
4362  */
4363  for (link = op->key_values; link != NULL; link = link->next) {
4364  if (link->key == canonical_key) {
4365  return link->value;
4366  }
4367  }
4368  return NULL;
4369 }
4370 
4375 bool object_value_set(const object *op, const char *const key) {
4376  const char *ret = object_get_value(op, key);
4377  if (ret == NULL || (strcmp(ret, "") == 0) || (strcmp(ret, "0") == 0)) {
4378  return false;
4379  }
4380  return true;
4381 }
4382 
4389 bool object_value_set_shared(const object *op, sstring key) {
4390  for (key_value *link = op->key_values; link != NULL; link = link->next) {
4391  if (link->key == key) {
4392  if ((strcmp(link->value, "") == 0) || (strcmp(link->value, "0") == 0)) {
4393  return false;
4394  }
4395  return true;
4396  }
4397  }
4398  return false;
4399 }
4400 
4415 static int object_set_value_s(object *op, sstring canonical_key, const char *value, int add_key) {
4416  key_value *field = NULL, *last = NULL;
4417 
4418  for (field = op->key_values; field != NULL; field = field->next) {
4419  if (field->key != canonical_key) {
4420  last = field;
4421  continue;
4422  }
4423 
4424  if (field->value)
4425  FREE_AND_CLEAR_STR(field->value);
4426  if (value)
4427  field->value = add_string(value);
4428  else {
4429  /* Basically, if the archetype has this key set,
4430  * we need to store the null value so when we save
4431  * it, we save the empty value so that when we load,
4432  * we get this value back again.
4433  */
4434  if (object_get_key_value(&op->arch->clone, canonical_key))
4435  field->value = NULL;
4436  else {
4437  /* Delete this link */
4438  if (field->key)
4439  FREE_AND_CLEAR_STR(field->key);
4440  if (field->value)
4441  FREE_AND_CLEAR_STR(field->value);
4442  if (last)
4443  last->next = field->next;
4444  else
4445  op->key_values = field->next;
4446  free(field);
4447  }
4448  }
4449  return TRUE;
4450  }
4451  /* IF we get here, key doesn't exist */
4452 
4453  /* No field, we'll have to add it. */
4454 
4455  if (!add_key) {
4456  return FALSE;
4457  }
4458  /* There isn't any good reason to store a null
4459  * value in the key/value list. If the archetype has
4460  * this key, then we should also have it, so shouldn't
4461  * be here. If user wants to store empty strings,
4462  * should pass in ""
4463  */
4464  if (value == NULL)
4465  return TRUE;
4466 
4467  field = static_cast<key_value *>(malloc(sizeof(key_value)));
4468 
4469  field->key = add_refcount(canonical_key);
4470  field->value = add_string(value);
4471  /* Usual prepend-addition. */
4472  field->next = op->key_values;
4473  op->key_values = field;
4474 
4475  return TRUE;
4476 }
4477 
4498 int object_set_value(object *op, const char *key, const char *value, int add_key) {
4499  const char *canonical_key = NULL;
4500  int floating_ref = FALSE;
4501  int ret;
4502 
4503  /* HACK This mess is to make sure set_ob_value() passes a shared string
4504  * to object_get_key_value(), without leaving a leaked refcount.
4505  */
4506 
4507  canonical_key = find_string(key);
4508  if (canonical_key == NULL) {
4509  canonical_key = add_string(key);
4510  floating_ref = TRUE;
4511  }
4512 
4513  ret = object_set_value_s(op, canonical_key, value, add_key);
4514 
4515  if (floating_ref) {
4516  free_string(canonical_key);
4517  }
4518 
4519  return ret;
4520 }
4521 
4574 int object_matches_string(object *pl, object *op, const char *name) {
4575  char *cp, local_name[MAX_BUF], name_op[MAX_BUF], name_short[HUGE_BUF], bname_s[MAX_BUF], bname_p[MAX_BUF];
4576  int count, retval = 0;
4577 
4578  char *endptr;
4579  if (op->count == strtoul(name, &endptr, 10)) {
4580  if ((endptr != name) && (*endptr == '\0')) {
4581  return 30;
4582  }
4583  }
4584 
4585  /* strtok is destructive to name */
4586  safe_strncpy(local_name, name, sizeof(local_name));
4587  sstring custom_name = object_get_value(op, CUSTOM_NAME_FIELD);
4588 
4589  for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) {
4590  while (cp[0] == ' ')
4591  ++cp; /* get rid of spaces */
4592 
4593  /* LOG(llevDebug, "Trying to match %s\n", cp);*/
4594  /* All is a very generic match - low match value */
4595  if (!strcmp(cp, "all"))
4596  return 1;
4597 
4598  /* unpaid is a little more specific */
4599  if (!strcmp(cp, "unpaid") && QUERY_FLAG(op, FLAG_UNPAID))
4600  return 2;
4601  if (!strcmp(cp, "cursed")
4603  && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)))
4604  return 2;
4605 
4606  if (!strcmp(cp, "unlocked") && !QUERY_FLAG(op, FLAG_INV_LOCKED))
4607  return 2;
4608 
4609  /* Allow for things like '100 arrows' */
4610  count = atoi(cp);
4611  if (*cp == '+' || *cp == '-')
4612  count=0; // Let +/- searches look in description for magic bonuses
4613  if (count != 0) {
4614  cp = strchr(cp, ' ');
4615  while (cp && cp[0] == ' ')
4616  ++cp; /* get rid of spaces */
4617  } else {
4618  if (pl->type == PLAYER)
4619  count = pl->contr->count;
4620  else
4621  count = 0;
4622  }
4623 
4624  if (!cp || cp[0] == '\0' || count < 0)
4625  continue;
4626 
4627  /* The code here should go from highest retval to lowest. That
4628  * is because of the 'else' handling - we don't want to match on
4629  * something and set a low retval, even though it may match a higher retcal
4630  * later. So keep it in descending order here, so we try for the best
4631  * match first, and work downward.
4632  */
4633  query_name(op, name_op, MAX_BUF);
4634  query_short_name(op, name_short, HUGE_BUF);
4635  query_base_name(op, 0, bname_s, MAX_BUF);
4636  query_base_name(op, 1, bname_p, MAX_BUF);
4637 
4638  if (!strcasecmp(cp, name_op))
4639  retval = 20;
4640  else if (!strcasecmp(cp, name_short))
4641  retval = 18;
4642  else if (!strcasecmp(cp, bname_s))
4643  retval = 16;
4644  else if (!strcasecmp(cp, bname_p))
4645  retval = 16;
4646  else if (custom_name && !strcasecmp(cp, custom_name))
4647  retval = 15;
4648  else if (!strncasecmp(cp, bname_s, strlen(cp)))
4649  retval = 14;
4650  else if (!strncasecmp(cp, bname_p, strlen(cp)))
4651  retval = 14;
4652  /* Do substring checks, so things like 'Str+1' will match.
4653  * retval of these should perhaps be lower - they are lower
4654  * then the specific strcasecmp aboves, but still higher than
4655  * some other match criteria.
4656  */
4657  else if (strstr(bname_p, cp))
4658  retval = 12;
4659  else if (strstr(bname_s, cp))
4660  retval = 12;
4661  else if (strstr(name_short, cp))
4662  retval = 12;
4663  /* Check against plural/non plural based on count. */
4664  else if (count > 1 && !strcasecmp(cp, op->name_pl)) {
4665  retval = 6;
4666  } else if (count == 1 && !strcasecmp(op->name, cp)) {
4667  retval = 6;
4668  }
4669  /* base name matched - not bad */
4670  else if (strcasecmp(cp, op->name) == 0 && !count)
4671  retval = 4;
4672  /* Check for partial custom name, but give a real low priority */
4673  else if (custom_name && strstr(custom_name, cp))
4674  retval = 3;
4675 
4676  if (retval) {
4677  if (pl->type == PLAYER)
4678  pl->contr->count = count;
4679  return retval;
4680  }
4681  }
4682  return 0;
4683 }
4684 
4693 void object_fix_multipart(object *tmp) {
4694  archetype *at;
4695  object *op, *last;
4696 
4697  if (!tmp->map) {
4698  LOG(llevError, "object_fix_multipart: not on a map!\n");
4699  return;
4700  }
4701 
4702  /* already multipart - don't do anything more */
4703  if (tmp->head || tmp->more)
4704  return;
4705 
4706  /* If there is nothing more to this object, this for loop
4707  * won't do anything.
4708  */
4709  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
4710  op = arch_to_object(at);
4711 
4712  /* update x,y coordinates */
4713  op->x += tmp->x;
4714  op->y += tmp->y;
4715  op->head = tmp;
4716  op->map = tmp->map;
4717  last->more = op;
4718  if (tmp->name != op->name) {
4719  if (op->name)
4720  free_string(op->name);
4721  op->name = add_string(tmp->name);
4722  }
4723  if (tmp->title != op->title) {
4724  if (op->title)
4725  free_string(op->title);
4726  op->title = add_string(tmp->title);
4727  }
4728  /* we could link all the parts onto tmp, and then just
4729  * call object_insert_in_map once, but the effect is the same,
4730  * as object_insert_in_map will call itself with each part, and
4731  * the coding is simpler to just to it here with each part.
4732  */
4734  } /* for at = tmp->arch->more */
4735 }
4736 
4752 void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy) {
4753  archetype *part;
4754  int maxx = 0, maxy = 0, minx = 0, miny = 0;
4755 
4756  ob = HEAD(ob);
4757  *sx = 1;
4758  *sy = 1;
4759  if (ob->arch->more) {
4760  for (part = ob->arch; part; part = part->more) {
4761  if (part->clone.x > maxx)
4762  maxx = part->clone.x;
4763  if (part->clone.y > maxy)
4764  maxy = part->clone.y;
4765  if (part->clone.x < minx)
4766  minx = part->clone.x;
4767  if (part->clone.y < miny)
4768  miny = part->clone.y;
4769  }
4770  }
4771  *sx = maxx;
4772  *sy = maxy;
4773  if (hx)
4774  *hx = -minx;
4775  if (hy)
4776  *hy = -miny;
4777 }
4778 
4799 void object_insert_to_free_spot_or_free(object *op, mapstruct *map, int x, int y, int start, int stop, object *originator) {
4800  int pos;
4801 
4802  pos = object_find_free_spot(op, map, x, y, start, stop);
4803  if (pos == -1) {
4805  return;
4806  }
4807 
4808  object_insert_in_map_at(op, map, originator, 0, x+freearr_x[pos], y+freearr_y[pos]);
4809 }
4810 
4819 void object_set_msg(object *op, const char *msg) {
4820  if (op->msg != NULL) {
4821  free_string(op->msg);
4822  }
4823 
4824  if (msg != NULL) {
4825  // If the message does not have a trailing newline, add one.
4826  if (*msg != '\0' && strchr(msg, '\0')[-1] != '\n') {
4828  stringbuffer_append_string(sb, msg);
4829  stringbuffer_append_string(sb, "\n");
4830  op->msg = stringbuffer_finish_shared(sb);
4831  } else {
4832  op->msg = add_string(msg);
4833  }
4834  } else {
4835  op->msg = NULL;
4836  }
4837 }
4838 
4840 const char *const move_name[] = {
4841  "walk",
4842  "fly_low",
4843  "fly_high",
4844  "swim",
4845  "boat",
4846  NULL
4847 };
4848 
4849 /* This array equates the FLAG_ values with the V_ values. Use -1 to
4850  * put gaps in the array that should not be processed.
4851  * The order matches the order of the define values in 'define.h'.
4852  */
4859 static const char *const flag_names[NUM_FLAGS+1] = {
4860  "alive", "wiz", NULL, NULL, "was_wiz", "applied", "unpaid",
4861  "can_use_shield", "no_pick", "client_anim_sync", "client_anim_random", /* 10 */
4862  "is_animated", NULL /* FLAG_DIALOG_PARSED, not saved */,
4863  NULL /* flying */, "monster", "friendly", "generator",
4864  "is_thrown", "auto_apply", "treasure", "player sold", /* 20 */
4865  "see_invisible", "can_roll", "overlay_floor",
4866  "is_turnable", NULL /* walk_off */, NULL /* fly_on */,
4867  NULL /*fly_off*/, "is_used_up", "identified", "reflecting", /* 30 */
4868  "changing", "splitting", "hitback", "startequip",
4869  "blocksview", "undead", "scared", "unaggressive",
4870  "reflect_missile", "reflect_spell", /* 40 */
4871  "no_magic", "no_fix_player", "is_lightable", "tear_down",
4872  "run_away", NULL /*pass_thru */, NULL /*can_pass_thru*/,
4873  NULL /*"pick_up"*/, "unique", "no_drop", /* 50 */
4874  NULL /* wizcast*/, "can_cast_spell", "can_use_scroll", "can_use_range",
4875  "can_use_bow", "can_use_armour", "can_use_weapon",
4876  "can_use_ring", "has_ready_range", "has_ready_bow", /* 60 */
4877  "xrays", NULL, "is_floor", "lifesave", "no_strength", "sleep",
4878  "stand_still", "random_movement", "only_attack", "confused", /* 70 */
4879  "stealth", NULL, NULL, "cursed", "damned",
4880  "see_anywhere", "known_magical", "known_cursed",
4881  "can_use_skill", "been_applied", /* 80 */
4882  "has_ready_scroll", NULL, NULL,
4883  NULL, "make_invisible", "inv_locked", "is_wooded",
4884  "is_hilly", "has_ready_skill", "has_ready_weapon", /* 90 */
4885  "no_skill_ident", "is_blind", "can_see_in_dark", "is_cauldron",
4886  NULL, "no_steal", "one_hit", NULL, "berserk", "neutral", /* 100 */
4887  "no_attack", "no_damage", NULL, NULL, "activate_on_push",
4888  "activate_on_release", "is_water", "use_content_on_gen", NULL, "is_buildable", /* 110 */
4889  NULL, "blessed", "known_blessed"
4890 };
4891 
4901 {
4902  std::string retbuf{""}, retbuf_all{" all"};
4903  int i, all_count = 0, count;
4904 
4905  /* Quick check, and probably fairly common */
4906  if (mt == MOVE_ALL) {
4907  stringbuffer_append_string(sb, "all");
4908  return;
4909  }
4910  if (mt == 0) {
4911  stringbuffer_append_string(sb, "0");
4912  return;
4913  }
4914 
4915  /* We basically slide the bits down. Why look at MOVE_ALL?
4916  * because we may want to return a string like 'all -swim',
4917  * and if we just looked at mt, we couldn't get that.
4918  */
4919  for (i = MOVE_ALL, count = 0; i != 0; i >>= 1, count++) {
4920  if (mt&(1<<count)) {
4921  retbuf += " ";
4922  retbuf += move_name[count];
4923  } else {
4924  retbuf_all += " -";
4925  retbuf_all += move_name[count];
4926  all_count++;
4927  }
4928  }
4929  /* Basically, if there is a single negation, return it, eg
4930  * 'all -swim'. But more than that, just return the
4931  * enumerated values. It doesn't make sense to return
4932  * 'all -walk -fly_low' - it is shorter to return 'fly_high swim'
4933  */
4934  if (all_count <= 1)
4935  stringbuffer_append_string(sb, retbuf_all.c_str()+1);
4936  else
4937  stringbuffer_append_string(sb, retbuf.c_str()+1);
4938 }
4939 
4941 static inline void ADD_STRINGLINE_ENTRY(StringBuffer *sb, const char *name, const char *value) {
4943  stringbuffer_append_string(sb, value);
4944  stringbuffer_append_string(sb, "\n");
4945 }
4946 
4948 static inline void FAST_SAVE_LONG(StringBuffer *sb, const char *name, const long value) {
4950  stringbuffer_append_int64(sb, value);
4951  stringbuffer_append_char(sb, '\n');
4952 }
4953 
4955 static inline void FAST_SAVE_DOUBLE(StringBuffer *sb, const char *name, const double value) {
4956  stringbuffer_append_printf(sb, "%s%g\n", name, value);
4957 }
4958 
4966  for (int i = 0; i < 4; i++) {
4967  int idx = ffs((*diff)[i]);
4968  if (idx != 0) {
4969  int bit = idx - 1;
4970  // Clear difference bit.
4971  (*diff)[i] &= ~(1 << bit);
4972  return 32*i + bit;
4973  }
4974  }
4975  return -1;
4976 }
4977 
4991 void get_ob_diff(StringBuffer *sb, const object *op, const object *op2) {
4992  static char buf2[64];
4993  int tmp;
4994  int i;
4995  key_value *my_field;
4996  key_value *arch_field;
4997 
4998  /* This saves the key/value lists. We do it first so that any
4999  * keys that match field names will be overwritten by the loader.
5000  */
5001  for (my_field = op->key_values; my_field != NULL; my_field = my_field->next) {
5002  /* Find the field in the opposing member. */
5003  arch_field = object_get_key_value(op2, my_field->key);
5004 
5005  /* If there's no partnering field, or it's got a different value, save our field. */
5006  if (arch_field == NULL || my_field->value != arch_field->value) {
5007  stringbuffer_append_string(sb, my_field->key);
5008  stringbuffer_append_string(sb, " ");
5009  /* If this is null, then saving it as a space should
5010  * cause it to be null again.
5011  */
5012  if (my_field->value)
5013  stringbuffer_append_string(sb, my_field->value);
5014  stringbuffer_append_string(sb, "\n");
5015  }
5016  }
5017  /* We don't need to worry about the arch's extra fields - they
5018  * will get taken care of the object_copy() function.
5019  */
5020 
5021  if (op->name && op->name != op2->name) {
5022  ADD_STRINGLINE_ENTRY(sb, "name ", op->name);
5023  }
5024  if (op->name_pl && op->name_pl != op2->name_pl) {
5025  // The loader will set name_pl = name if there is no special plural name,
5026  // so check for that when we save out.
5027  if (op->name_pl != op->name)
5028  ADD_STRINGLINE_ENTRY(sb, "name_pl ", op->name_pl);
5029  }
5030  if (op->anim_suffix && op->anim_suffix != op2->anim_suffix) {
5031  ADD_STRINGLINE_ENTRY(sb, "anim_suffix ", op->anim_suffix);
5032  }
5033  if (op->title && op->title != op2->title) {
5034  ADD_STRINGLINE_ENTRY(sb, "title ", op->title);
5035  }
5036  if (op->race && op->race != op2->race) {
5037  ADD_STRINGLINE_ENTRY(sb, "race ", op->race);
5038  }
5039  if (op->slaying && op->slaying != op2->slaying) {
5040  ADD_STRINGLINE_ENTRY(sb, "slaying ", op->slaying);
5041  }
5042  if (op->skill && op->skill != op2->skill) {
5043  ADD_STRINGLINE_ENTRY(sb, "skill ", op->skill);
5044  }
5045  if (op->msg && op->msg != op2->msg) {
5046  stringbuffer_append_string(sb, "msg\n");
5048  stringbuffer_append_string(sb, "endmsg\n");
5049  }
5050  if (op->lore && op->lore != op2->lore) {
5051  stringbuffer_append_string(sb, "lore\n");
5053  stringbuffer_append_string(sb, "endlore\n");
5054  }
5055  if (op->other_arch != op2->other_arch && op->other_arch != NULL && op->other_arch->name) {
5056  ADD_STRINGLINE_ENTRY(sb, "other_arch ", op->other_arch->name);
5057  }
5058  if (op->face != op2->face) {
5059  ADD_STRINGLINE_ENTRY(sb, "face ", op->face->name);
5060  }
5061 
5062  if (op->animation != op2->animation) {
5063  if (op->animation) {
5064  ADD_STRINGLINE_ENTRY(sb, "animation ", op->animation->name);
5065  if (!QUERY_FLAG (op, FLAG_ANIMATE)) {
5066  stringbuffer_append_string(sb, "is_animated 0\n");
5067  }
5068  } else {
5069  stringbuffer_append_string(sb, "animation NONE\n");
5070  }
5071  }
5072  if (op->stats.Str != op2->stats.Str)
5073  FAST_SAVE_LONG(sb, "Str ", op->stats.Str);
5074  if (op->stats.Dex != op2->stats.Dex)
5075  FAST_SAVE_LONG(sb, "Dex ", op->stats.Dex);
5076  if (op->stats.Con != op2->stats.Con)
5077  FAST_SAVE_LONG(sb, "Con ", op->stats.Con);
5078  if (op->stats.Wis != op2->stats.Wis)
5079  FAST_SAVE_LONG(sb, "Wis ", op->stats.Wis);
5080  if (op->stats.Pow != op2->stats.Pow)
5081  FAST_SAVE_LONG(sb, "Pow ", op->stats.Pow);
5082  if (op->stats.Cha != op2->stats.Cha)
5083  FAST_SAVE_LONG(sb, "Cha ", op->stats.Cha);
5084  if (op->stats.Int != op2->stats.Int)
5085  FAST_SAVE_LONG(sb, "Int ", op->stats.Int);
5086  if (op->stats.hp != op2->stats.hp)
5087  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5088  if (op->stats.maxhp != op2->stats.maxhp)
5089  FAST_SAVE_LONG(sb, "maxhp ", op->stats.maxhp);
5090  if (op->stats.sp != op2->stats.sp)
5091  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5092  if (op->stats.maxsp != op2->stats.maxsp)
5093  FAST_SAVE_LONG(sb, "maxsp ", op->stats.maxsp);
5094  if (op->stats.grace != op2->stats.grace)
5095  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5096  if (op->stats.maxgrace != op2->stats.maxgrace)
5097  FAST_SAVE_LONG(sb, "maxgrace ", op->stats.maxgrace);
5098 
5099  if (op->stats.exp != op2->stats.exp) {
5100  snprintf(buf2, sizeof(buf2), "%" FMT64, op->stats.exp);
5101  ADD_STRINGLINE_ENTRY(sb, "exp ", buf2);
5102  }
5103 
5104  if (op->total_exp != op2->total_exp) {
5105  snprintf(buf2, sizeof(buf2), "%" FMT64, op->total_exp);
5106  ADD_STRINGLINE_ENTRY(sb, "total_exp ", buf2);
5107  }
5108 
5109  if (op->expmul != op2->expmul)
5110  FAST_SAVE_DOUBLE(sb, "expmul ", op->expmul);
5111  if (op->stats.food != op2->stats.food)
5112  FAST_SAVE_LONG(sb, "food ", op->stats.food);
5113  if (op->stats.dam != op2->stats.dam)
5114  FAST_SAVE_LONG(sb, "dam ", op->stats.dam);
5115  if (op->stats.luck != op2->stats.luck)
5116  FAST_SAVE_LONG(sb, "luck ", op->stats.luck);
5117  if (op->stats.wc != op2->stats.wc)
5118  FAST_SAVE_LONG(sb, "wc ", op->stats.wc);
5119  if (op->stats.ac != op2->stats.ac)
5120  FAST_SAVE_LONG(sb, "ac ", op->stats.ac);
5121  if (op->x != op2->x)
5122  FAST_SAVE_LONG(sb, "x ", op->x);
5123  if (op->y != op2->y)
5124  FAST_SAVE_LONG(sb, "y ", op->y);
5125  if (op->speed != op2->speed) {
5126  FAST_SAVE_DOUBLE(sb, "speed ", op->speed);
5127  }
5128  if (op->speed > 0 && op->speed_left != op2->speed_left) {
5129  FAST_SAVE_DOUBLE(sb, "speed_left ", op->speed_left);
5130  }
5131  if (op->weapon_speed != op2->weapon_speed) {
5132  FAST_SAVE_DOUBLE(sb, "weapon_speed ", op->weapon_speed);
5133  }
5134  if (op->weapon_speed > 0 && op->weapon_speed_left != op2->weapon_speed_left) {
5135  FAST_SAVE_DOUBLE(sb, "weapon_speed_left ", op->weapon_speed_left);
5136  }
5137  if (op->move_status != op2->move_status)
5138  FAST_SAVE_LONG(sb, "move_state ", op->move_status);
5139  if (op->attack_movement != op2->attack_movement)
5140  FAST_SAVE_LONG(sb, "attack_movement ", op->attack_movement);
5141  if (op->nrof != op2->nrof)
5142  FAST_SAVE_LONG(sb, "nrof ", op->nrof);
5143  if (op->level != op2->level)
5144  FAST_SAVE_LONG(sb, "level ", op->level);
5145  if (op->direction != op2->direction)
5146  FAST_SAVE_LONG(sb, "direction ", op->direction);
5147  if (op->type != op2->type)
5148  FAST_SAVE_LONG(sb, "type ", op->type);
5149  if (op->subtype != op2->subtype)
5150  FAST_SAVE_LONG(sb, "subtype ", op->subtype);
5151  if (op->attacktype != op2->attacktype)
5152  FAST_SAVE_LONG(sb, "attacktype ", op->attacktype);
5153 
5154  for (tmp = 0; tmp < NROFATTACKS; tmp++) {
5155  if (op->resist[tmp] != op2->resist[tmp]) {
5156  stringbuffer_append_string(sb, "resist_");
5157  FAST_SAVE_LONG(sb, resist_save[tmp], op->resist[tmp]);
5158  }
5159  }
5160 
5161  if (op->path_attuned != op2->path_attuned)
5162  FAST_SAVE_LONG(sb, "path_attuned ", op->path_attuned);
5163  if (op->path_repelled != op2->path_repelled)
5164  FAST_SAVE_LONG(sb, "path_repelled ", op->path_repelled);
5165  if (op->path_denied != op2->path_denied)
5166  FAST_SAVE_LONG(sb, "path_denied ", op->path_denied);
5167  if (op->material != op2->material)
5168  FAST_SAVE_LONG(sb, "material ", op->material);
5169  if (op->materialname && op->materialname != op2->materialname) {
5170  ADD_STRINGLINE_ENTRY(sb, "materialname ", op->materialname);
5171  }
5172  if (op->value != op2->value)
5173  FAST_SAVE_LONG(sb, "value ", op->value);
5174  // op->carrying is always recomputed at load, so don't save it
5175  if (op->weight != op2->weight)
5176  FAST_SAVE_LONG(sb, "weight ", op->weight);
5177  if (op->invisible != op2->invisible)
5178  FAST_SAVE_LONG(sb, "invisible ", op->invisible);
5179  if (op->state != op2->state)
5180  FAST_SAVE_LONG(sb, "state ", op->state);
5181  if (op->magic != op2->magic)
5182  FAST_SAVE_LONG(sb, "magic ", op->magic);
5183  if (op->last_heal != op2->last_heal)
5184  FAST_SAVE_LONG(sb, "last_heal ", op->last_heal);
5185  if (op->last_sp != op2->last_sp)
5186  FAST_SAVE_LONG(sb, "last_sp ", op->last_sp);
5187  if (op->last_grace != op2->last_grace)
5188  FAST_SAVE_LONG(sb, "last_grace ", op->last_grace);
5189  if (op->last_eat != op2->last_eat)
5190  FAST_SAVE_LONG(sb, "last_eat ", op->last_eat);
5191  if (QUERY_FLAG(op, FLAG_IS_LINKED) && (tmp = get_button_value(op)))
5192  FAST_SAVE_LONG(sb, "connected ", tmp);
5193  if (op->glow_radius != op2->glow_radius)
5194  FAST_SAVE_LONG(sb, "glow_radius ", op->glow_radius);
5195  if (op->randomitems != op2->randomitems) {
5196  ADD_STRINGLINE_ENTRY(sb, "randomitems ", op->randomitems ? op->randomitems->name : "none");
5197  }
5198 
5199  if (op->run_away != op2->run_away)
5200  FAST_SAVE_LONG(sb, "run_away ", op->run_away);
5201  if (op->pick_up != op2->pick_up)
5202  FAST_SAVE_LONG(sb, "pick_up ", op->pick_up);
5203  if (op->weight_limit != op2->weight_limit)
5204  FAST_SAVE_LONG(sb, "container ", op->weight_limit);
5205  if (op->will_apply != op2->will_apply)
5206  FAST_SAVE_LONG(sb, "will_apply ", op->will_apply);
5207  if (op->smoothlevel != op2->smoothlevel)
5208  FAST_SAVE_LONG(sb, "smoothlevel ", op->smoothlevel);
5209 
5210  if (op->map_layer != op2->map_layer)
5211  ADD_STRINGLINE_ENTRY(sb, "map_layer ", map_layer_name[op->map_layer]);
5212 
5213  if (op->weapontype && op->weapontype != op2->weapontype) {
5214  FAST_SAVE_LONG(sb, "weapontype ", op->weapontype);
5215  }
5216  if (op->elevation && op->elevation != op2->elevation) {
5217  FAST_SAVE_LONG(sb, "elevation ", op->elevation);
5218  }
5219  if (op->client_type && op->client_type != op2->client_type) {
5220  FAST_SAVE_LONG(sb, "client_type ", op->client_type);
5221  }
5222 
5223  if (op->item_power != op2->item_power) {
5224  FAST_SAVE_LONG(sb, "item_power ", op->item_power);
5225  }
5226 
5227  if (op->duration != op2->duration)
5228  FAST_SAVE_LONG(sb, "duration ", op->duration);
5229 
5230  if (op->range != op2->range)
5231  FAST_SAVE_LONG(sb, "range ", op->range);
5232 
5233  if (op->range_modifier != op2->range_modifier)
5234  FAST_SAVE_LONG(sb, "range_modifier ", op->range_modifier);
5235 
5236  if (op->duration_modifier != op2->duration_modifier)
5237  FAST_SAVE_LONG(sb, "duration_modifier ", op->duration_modifier);
5238 
5239  if (op->dam_modifier != op2->dam_modifier)
5240  FAST_SAVE_LONG(sb, "dam_modifier ", op->dam_modifier);
5241 
5242  if (op->gen_sp_armour != op2->gen_sp_armour) {
5243  FAST_SAVE_LONG(sb, "gen_sp_armour ", op->gen_sp_armour);
5244  }
5245 
5246  /* I've kept the old int move type saving code commented out.
5247  * In an ideal world, we'd know if we want to do a quick
5248  * save (say to a temp map, where we don't care about strings),
5249  * or a slower save/dm dump, where printing out strings is handy.
5250  */
5251  if (op->move_type != op2->move_type) {
5252  /*FAST_SAVE_LONG(sb, "move_type ", op->move_type)*/
5253  stringbuffer_append_string(sb, "move_type ");
5255  stringbuffer_append_string(sb, "\n");
5256  }
5257  if (op->move_block != op2->move_block) {
5258  /*FAST_SAVE_LONG(sb, "move_block ", op->move_block)*/
5259  stringbuffer_append_string(sb, "move_block ");
5261  stringbuffer_append_string(sb, "\n");
5262  }
5263  if (op->move_allow != op2->move_allow) {
5264  /*FAST_SAVE_LONG(sb, "move_allow ", op->move_allow);*/
5265  stringbuffer_append_string(sb, "move_allow ");
5267  stringbuffer_append_string(sb, "\n");
5268  }
5269  if (op->move_on != op2->move_on) {
5270  /*FAST_SAVE_LONG(sb, "move_on ", op->move_on);*/
5271  stringbuffer_append_string(sb, "move_on ");
5272  get_string_move_type(sb, op->move_on);
5273  stringbuffer_append_string(sb, "\n");
5274  }
5275  if (op->move_off != op2->move_off) {
5276  /*FAST_SAVE_LONG(sb, "move_off ", op->move_off);*/
5277  stringbuffer_append_string(sb, "move_off ");
5278  get_string_move_type(sb, op->move_off);
5279  stringbuffer_append_string(sb, "\n");
5280  }
5281  if (op->move_slow != op2->move_slow) {
5282  /*FAST_SAVE_LONG(sb, "move_slow ", op->move_slow);*/
5283  stringbuffer_append_string(sb, "move_slow ");
5285  stringbuffer_append_string(sb, "\n");
5286  }
5287 
5288  if (op->move_slow_penalty != op2->move_slow_penalty) {
5289  FAST_SAVE_DOUBLE(sb, "move_slow_penalty ", op->move_slow_penalty);
5290  }
5291 
5292  // Make sure we save sound_chance overrides, or sound chance only works on the initial map load.
5293  if (op->sound_chance != op2->sound_chance) {
5294  FAST_SAVE_LONG(sb, "sound_chance ", op->sound_chance);
5295  }
5296 
5297  ob_flags diff_flags;
5298  compare_flags(&diff_flags, op, op2);
5299  int flag;
5300  while ((flag = flags_differ(&diff_flags)) != -1) {
5301  if (flag_names[flag]) {
5302  ADD_STRINGLINE_ENTRY(sb, flag_names[flag], QUERY_FLAG(op, flag) ? " 1" : " 0");
5303  }
5304  }
5305 
5306  /* Save body locations */
5307  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
5308  if (op->body_info[i] != op2->body_info[i]) {
5309  stringbuffer_append_string(sb, body_locations[i].save_name);
5310  FAST_SAVE_LONG(sb, " ", op->body_info[i]);
5311  }
5312  }
5313 }
5314 
5319 void save_object_in_sb(StringBuffer *sb, object *op, const int flag) {
5320  /* If the object has no_save set, just return */
5321  if (QUERY_FLAG(op, FLAG_NO_SAVE)) {
5322  return;
5323  }
5324 
5325  /* Even if the object does have an owner, it would seem that we should
5326  * still save it.
5327  */
5328  if (object_get_owner(op) != NULL) {
5329  return;
5330  }
5331 
5332  /* If it is unpaid and we don't want to save those, just return. */
5333  if (!(flag&SAVE_FLAG_SAVE_UNPAID) && (QUERY_FLAG(op, FLAG_UNPAID))) {
5334  return;
5335  }
5336 
5337  archetype *at = op->arch;
5338  if (at == NULL)
5339  at = empty_archetype;
5340 
5341  ADD_STRINGLINE_ENTRY(sb, "arch ", at->name);
5342 
5343  if (at->reference_count > 0) {
5344  /* The object is a custom item/monster, so we handle its save differently.
5345  * We compare the custom archetype to the "original" one, then only save hp/gr/sp
5346  * which are the only values we can't recompute later - all others are modified by items in inventory.
5347  * Note that hp/gr/sp will appear twice in save, but last value will take precedence.
5348  */
5349  archetype *original = find_archetype(at->name);
5350  if (!original) {
5351  LOG(llevError, "could not find original archetype %s for custom monster!\n", at->name);
5352  abort();
5353  }
5354  get_ob_diff(sb, &at->clone, &original->clone);
5355  if (op->stats.hp != at->clone.stats.hp)
5356  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5357  if (op->stats.sp != at->clone.stats.sp)
5358  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5359  if (op->stats.grace != at->clone.stats.grace)
5360  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5361  if (op->x != at->clone.x)
5362  FAST_SAVE_LONG(sb, "x ", op->x);
5363  if (op->y != at->clone.y)
5364  FAST_SAVE_LONG(sb, "y ", op->y);
5365  } else if (op->artifact != NULL) {
5366  /* if op is an artifact, then find the "standard" artifact to use that for the diff */
5367  object *base;
5368  const artifact *artifact;
5369 
5370  artifact = find_artifact(op, op->artifact);
5371  if (artifact == NULL) {
5372  LOG(llevError, "could not find artifact %s [%d] to save data\n", op->artifact, op->type);
5373  get_ob_diff(sb, op, &at->clone);
5374  } else {
5375  ADD_STRINGLINE_ENTRY(sb, "artifact ", op->artifact);
5376  base = arch_to_object(at);
5378  get_ob_diff(sb, op, base);
5380  }
5381  } else {
5382  get_ob_diff(sb, op, &at->clone);
5383  }
5384 
5385  /* Eneq(@csd.uu.se): Added this to allow containers being saved with contents*/
5386  FOR_INV_PREPARE(op, tmp)
5387  save_object_in_sb(sb, tmp, flag);
5388  FOR_INV_FINISH();
5389 
5390  stringbuffer_append_string(sb, "end\n");
5391 }
5392 
5405 int save_object(FILE *fp, object *op, int flag) {
5407  save_object_in_sb(sb, op, flag);
5408  char *cp = stringbuffer_finish(sb);
5409  if (fputs(cp, fp) == EOF) {
5410  free(cp);
5411  return SAVE_ERROR_WRITE;
5412  } else {
5413  free(cp);
5414  return SAVE_ERROR_OK;
5415  }
5416 }
5417 
5419  if (op->map) {
5420  sstring death_animation = object_get_value(op, "death_animation");
5421  if (death_animation != NULL && strcmp(death_animation, "NONE")) {
5422  object *death = create_archetype(death_animation);
5423 
5424  if (death != NULL) {
5425  object_insert_in_map_at(death, op->map, op, 0, op->x, op->y);
5426  if (death->arch->more)
5427  object_fix_multipart(death);
5428  }
5429  }
5430  }
5431 }
5432 
5433 object *find_force(object *op, const char *name) {
5434  assert(op != NULL);
5436 }
5437 
5438 object *add_force(object *op, const char *name, int duration) {
5439  assert(op != NULL);
5440  object *force = find_force(op, name);
5441  if (force == NULL) {
5442  force = create_archetype(FORCE_NAME);
5443  force->slaying = add_string(name);
5444  object_insert_in_ob(force, op);
5445  }
5446 
5447  if (duration != 0) {
5448  force->speed = 0.01;
5449  force->speed_left = -duration;
5450  } else {
5451  force->speed = 0;
5452  }
5453 
5454  // Even if duration is zero, a force could be set previously.
5455  object_update_speed(force);
5456 
5457  return force;
5458 }
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:4375
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:615
object_get_owner
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:801
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:4300
object_clear_owner
void object_clear_owner(object *op)
Clears the owner of specified object.
Definition: object.cpp:820
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:581
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:1330
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:1782
object_find_by_type_applied
object * object_find_by_type_applied(const object *who, int type)
Find applied object in inventory.
Definition: object.cpp:4082
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:3238
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:4941
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:762
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:3117
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:2050
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:3713
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:4859
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:912
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:4799
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:695
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:3598
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:3221
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:837
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:5418
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:931
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:1189
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:4228
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:3411
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:4182
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:4965
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:1205
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:718
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:1228
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:2128
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:2856
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:4955
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:980
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:4132
m
static event_registration m
Definition: citylife.cpp:424
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:1558
object_update
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1432
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:3955
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:4320
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:4036
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:4389
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:3202
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:3144
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:3821
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
FLAG_NO_STEAL
#define FLAG_NO_STEAL
Item can't be stolen.
Definition: define.h:329
object_dump
void object_dump(const object *op, StringBuffer *sb)
Dumps an object.
Definition: object.cpp:636
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:86
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:1750
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:4752
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:4107
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
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:1347
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:4059
object_find_by_flag
object * object_find_by_flag(const object *who, int flag)
Find object in inventory by flag.
Definition: object.cpp:4205
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:1590
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:4574
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:3295
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:4003
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:3751
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:2099
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:3908
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:1058
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:4840
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:3273
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:1270
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:2360
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:3167
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:3641
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:3676
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:2832
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:2675
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:4157
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:1766
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:4251
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:3866
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:3979
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:742
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:4900
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:3617
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:2636
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:3558
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:4819
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:3255
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:951
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4345
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:5438
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:5319
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:4991
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:1390
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:4276
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:2296
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:3660
find_force
object * find_force(object *op, const char *name)
Find a force with the given 'name' in the slaying field.
Definition: object.cpp:5433
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:4693
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:1832
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
object_sum_weight
signed long object_sum_weight(object *op)
object_sum_weight() is a recursive function which calculates the weight an object is carrying.
Definition: object.cpp:559
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:3011
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:890
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:2762
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:4498
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:1806
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:5405
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:598
dirdiff
int dirdiff(int dir1, int dir2)
Computes a direction difference.
Definition: object.cpp:3731
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
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:1566
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:2596
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:4948
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