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 #ifndef WIN32 /* ---win32 exclude headers */
32 #include <sys/types.h>
33 #include <sys/uio.h>
34 #endif /* win32 */
35 
36 #include "loader.h"
37 #include "object.h"
38 #include "skills.h"
39 #include "sproto.h"
40 #include "stringbuffer.h"
41 
42 #ifdef CF_MXE_CROSS_COMPILE
43 # define ffs(word) (__builtin_constant_p (word) \
44  ? __builtin_ffs (word) \
45  : ({ int __cnt, __tmp; \
46  __asm__ __volatile__ \
47  ("bsfl %2,%0\n\t" \
48  "cmovel %1,%0" \
49  : "=&r" (__cnt), "=r" (__tmp) \
50  : "rm" (word), "1" (-1)); \
51  __cnt + 1; }))
52 #endif
53 
54 static int compare_ob_value_lists_one(const object *, const object *);
55 static int compare_ob_value_lists(const object *, const object *);
56 static void permute(int *, int, int);
57 static int object_set_value_s(object *, const char *, const char *, int);
58 static void object_increase_nrof(object *op, uint32_t i);
59 
74 const char *const spell_mapping[SPELL_MAPPINGS] = {
75  "spell_magic_bullet", /* 0 */
76  "spell_small_fireball", /* 1 */
77  "spell_medium_fireball", /* 2 */
78  "spell_large_fireball", /* 3 */
79  "spell_burning_hands", /* 4 */
80  "spell_sm_lightning", /* 5 */
81  "spell_large_lightning", /* 6 */
82  "spell_magic_missile", /* 7 */
83  "spell_create_bomb", /* 8 */
84  "spell_summon_golem", /* 9 */
85  "spell_summon_fire_elemental", /* 10 */
86  "spell_summon_earth_elemental", /* 11 */
87  "spell_summon_water_elemental", /* 12 */
88  "spell_summon_air_elemental", /* 13 */
89  "spell_dimension_door", /* 14 */
90  "spell_create_earth_wall", /* 15 */
91  "spell_paralyze", /* 16 */
92  "spell_icestorm", /* 17 */
93  "spell_magic_mapping", /* 18 */
94  "spell_turn_undead", /* 19 */
95  "spell_fear", /* 20 */
96  "spell_poison_cloud", /* 21 */
97  "spell_wonder", /* 22 */
98  "spell_destruction", /* 23 */
99  "spell_perceive_self", /* 24 */
100  "spell_word_of_recall", /* 25 */
101  "spell_invisible", /* 26 */
102  "spell_invisible_to_undead", /* 27 */
103  "spell_probe", /* 28 */
104  "spell_lg_magic_bullet", /* 29 */
105  "spell_improved_invisibility", /* 30 */
106  "spell_holy_word", /* 31 */
107  "spell_minor_healing", /* 32 */
108  "spell_medium_healing", /* 33 */
109  "spell_major_healing", /* 34 */
110  "spell_heal", /* 35 */
111  "spell_create_food", /* 36 */
112  "spell_earth_to_dust", /* 37 */
113  "spell_armour", /* 38 */
114  "spell_strength", /* 39 */
115  "spell_dexterity", /* 40 */
116  "spell_constitution", /* 41 */
117  "spell_charisma", /* 42 */
118  "spell_create_fire_wall", /* 43 */
119  "spell_create_frost_wall", /* 44 */
120  "spell_protection_from_cold", /* 45 */
121  "spell_protection_from_electricity", /* 46 */
122  "spell_protection_from_fire", /* 47 */
123  "spell_protection_from_poison", /* 48 */
124  "spell_protection_from_slow", /* 49 */
125  "spell_protection_from_paralysis", /* 50 */
126  "spell_protection_from_draining", /* 51 */
127  "spell_protection_from_magic", /* 52 */
128  "spell_protection_from_attack", /* 53 */
129  "spell_levitate", /* 54 */
130  "spell_small_speedball", /* 55 */
131  "spell_large_speedball", /* 56 */
132  "spell_hellfire", /* 57 */
133  "spell_dragonbreath", /* 58 */
134  "spell_large_icestorm", /* 59 */
135  "spell_charging", /* 60 */
136  "spell_polymorph", /* 61 */
137  "spell_cancellation", /* 62 */
138  "spell_confusion", /* 63 */
139  "spell_mass_confusion", /* 64 */
140  "spell_summon_pet_monster", /* 65 */
141  "spell_slow", /* 66 */
142  "spell_regenerate_spellpoints", /* 67 */
143  "spell_cure_poison", /* 68 */
144  "spell_protection_from_confusion", /* 69 */
145  "spell_protection_from_cancellation", /* 70 */
146  "spell_protection_from_depletion", /* 71 */
147  "spell_alchemy", /* 72 */
148  "spell_remove_curse", /* 73 */
149  "spell_remove_damnation", /* 74 */
150  "spell_identify", /* 75 */
151  "spell_detect_magic", /* 76 */
152  "spell_detect_monster", /* 77 */
153  "spell_detect_evil", /* 78 */
154  "spell_detect_curse", /* 79 */
155  "spell_heroism", /* 80 */
156  "spell_aggravation", /* 81 */
157  "spell_firebolt", /* 82 */
158  "spell_frostbolt", /* 83 */
159  "spell_shockwave", /* 84 */
160  "spell_color_spray", /* 85 */
161  "spell_haste", /* 86 */
162  "spell_face_of_death", /* 87 */
163  "spell_ball_lightning", /* 88 */
164  "spell_meteor_swarm", /* 89 */
165  "spell_comet", /* 90 */
166  "spell_mystic_fist", /* 91 */
167  "spell_raise_dead", /* 92 */
168  "spell_resurrection", /* 93 */
169  "spell_reincarnation", /* 94 */
170  NULL, /* 95 spell_immunity_to_cold */
171  NULL, /* 96 spell_immunity_to_electricity */
172  NULL, /* 97 spell_immunity_to_fire */
173  NULL, /* 98 spell_immunity_to_poison */
174  NULL, /* 99 spell_immunity_to_slow */
175  NULL, /* 100 spell_immunity_to_paralysis */
176  NULL, /* 101 spell_immunity_to_draining */
177  NULL, /* 102 spell_immunity_to_magic */
178  NULL, /* 103 spell_immunity_to_attack */
179  "spell_invulnerability", /* 104 */
180  "spell_defense", /* 105 */
181  "spell_rune_of_fire", /* 106 */
182  "spell_rune_of_frost", /* 107 */
183  "spell_rune_of_shocking", /* 108 */
184  "spell_rune_of_blasting", /* 109 */
185  "spell_rune_of_death", /* 110 */
186  "spell_marking_rune", /* 111 */
187  "spell_build_director", /* 112 */
188  "spell_create_pool_of_chaos", /* 113 */
189  "spell_build_bullet_wall", /* 114 */
190  "spell_build_lightning_wall", /* 115 */
191  "spell_build_fireball_wall", /* 116 */
192  "spell_magic_rune", /* 117 */
193  "spell_rune_of_magic_drain", /* 118 */
194  "spell_antimagic_rune", /* 119 */
195  "spell_rune_of_transference", /* 120 */
196  "spell_transference", /* 121 */
197  "spell_magic_drain", /* 122 */
198  "spell_counterspell", /* 123 */
199  "spell_disarm", /* 124 */
200  "spell_cure_confusion", /* 125 */
201  "spell_restoration", /* 126 */
202  NULL, /* 127 */ /* Was summon evil monster */
203  "spell_counterwall", /* 128 */
204  "spell_cause_light_wounds", /* 129 */
205  "spell_cause_medium_wounds", /* 130 */
206  "spell_cause_heavy_wounds", /* 131 */
207  "spell_charm_monsters", /* 132 */
208  "spell_banishment", /* 133 */
209  "spell_create_missile", /* 134 */
210  "spell_show_invisible", /* 135 */
211  "spell_xray", /* 136 */
212  "spell_pacify", /* 137 */
213  "spell_summon_fog", /* 138 */
214  "spell_steambolt", /* 139 */
215  "spell_command_undead", /* 140 */
216  "spell_holy_orb", /* 141 */
217  "spell_summon_avatar", /* 142 */
218  "spell_holy_possession", /* 143 */
219  "spell_bless", /* 144 */
220  "spell_curse", /* 145 */
221  "spell_regeneration", /* 146 */
222  "spell_consecrate", /* 147 */
223  "spell_summon_cult_monsters", /* 148 */
224  "spell_cause_critical_wounds", /* 149 */
225  "spell_holy_wrath", /* 150 */
226  "spell_retributive_strike", /* 151 */
227  "spell_finger_of_death", /* 152 */
228  "spell_insect_plague", /* 153 */
229  "spell_call_holy_servant", /* 154 */
230  "spell_wall_of_thorns", /* 155 */
231  "spell_staff_to_snake", /* 156 */
232  "spell_light", /* 157 */
233  "spell_darkness", /* 158 */
234  "spell_nightfall", /* 159 */
235  "spell_daylight", /* 160 */
236  "spell_sunspear", /* 161 */
237  "spell_faery_fire", /* 162 */
238  "spell_cure_blindness", /* 163 */
239  "spell_dark_vision", /* 164 */
240  "spell_bullet_swarm", /* 165 */
241  "spell_bullet_storm", /* 166 */
242  "spell_cause_many_wounds", /* 167 */
243  "spell_small_snowstorm", /* 168 */
244  "spell_medium_snowstorm", /* 169 */
245  "spell_large_snowstorm", /* 170 */
246  "spell_cure_disease", /* 171 */
247  "spell_cause_red_death", /* 172 */
248  "spell_cause_flu", /* 173 */
249  "spell_cause_black_death", /* 174 */
250  "spell_cause_leprosy", /* 175 */
251  "spell_cause_smallpox", /* 176 */
252  "spell_cause_white_death", /* 177 */
253  "spell_cause_anthrax", /* 178 */
254  "spell_cause_typhoid", /* 179 */
255  "spell_mana_blast", /* 180 */
256  "spell_small_manaball", /* 181 */
257  "spell_medium_manaball", /* 182 */
258  "spell_large_manaball", /* 183 */
259  "spell_manabolt", /* 184 */
260  "spell_dancing_sword", /* 185 */
261  "spell_animate_weapon", /* 186 */
262  "spell_cause_cold", /* 187 */
263  "spell_divine_shock", /* 188 */
264  "spell_windstorm", /* 189 */
265  "spell_sanctuary", /* 190 */
266  "spell_peace", /* 191 */
267  "spell_spiderweb", /* 192 */
268  "spell_conflict", /* 193 */
269  "spell_rage", /* 194 */
270  "spell_forked_lightning", /* 195 */
271  "spell_poison_fog", /* 196 */
272  "spell_flaming_aura", /* 197 */
273  "spell_vitriol", /* 198 */
274  "spell_vitriol_splash", /* 199 */
275  "spell_iron_skin", /* 200 */
276  "spell_wrathful_eye", /* 201 */
277  "spell_town_portal", /* 202 */
278  "spell_missile_swarm", /* 203 */
279  "spell_cause_rabies", /* 204 */
280  "spell_glyph", /* 205 */
281 };
282 
283 #ifdef MEMORY_DEBUG
284 int nroffreeobjects = 0;
285 int nrofallocobjects = 0;
286 #undef OBJ_EXPAND
287 #define OBJ_EXPAND 1
288 #else
289 static object objarray[STARTMAX];
292 #endif
293 
294 object *objects;
295 static object *free_objects;
296 object *active_objects;
300  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,
301  0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
302 };
303 
306  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,
307  -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3
308 };
309 
312  0, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45,
313  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
314 };
315 
318  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,
319  1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
320 };
321 
327 void init_objects(void) {
328  /* Initialize all objects: */
329  objects = NULL;
330  active_objects = NULL;
331 
332 #ifdef MEMORY_DEBUG
333  free_objects = NULL;
334 #else
336  objarray[0].prev = NULL,
337  objarray[0].next = &objarray[1],
340  for (int i = 1; i < STARTMAX-1; i++) {
341  objarray[i].next = &objarray[i+1];
342  objarray[i].prev = &objarray[i-1];
345  }
346  objarray[STARTMAX-1].next = NULL;
350 #endif
351 }
352 
363 static int compare_ob_value_lists_one(const object *wants, const object *has) {
364  key_value *wants_field;
365 
366  /* n-squared behaviour (see object_get_key_value()), but I'm hoping both
367  * objects with lists are rare, and lists stay short. If not, use a
368  * different structure or at least keep the lists sorted...
369  */
370 
371  /* For each field in wants, */
372  for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) {
373  key_value *has_field;
374 
375  /* Look for a field in has with the same key. */
376  has_field = object_get_key_value(has, wants_field->key);
377 
378  if (has_field == NULL) {
379  /* No field with that name. */
380  return FALSE;
381  }
382 
383  /* Found the matching field. */
384  if (has_field->value != wants_field->value) {
385  /* Values don't match, so this half of the comparison is false. */
386  return FALSE;
387  }
388 
389  /* If we get here, we found a match. Now for the next field in wants. */
390  }
391 
392  /* If we get here, every field in wants has a matching field in has. */
393  return TRUE;
394 }
395 
404 static int compare_ob_value_lists(const object *ob1, const object *ob2) {
405  /* However, there may be fields in has which aren't partnered in wants,
406  * so we need to run the comparison *twice*. :(
407  */
408  return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1);
409 }
410 
433 int object_can_merge(object *ob1, object *ob2) {
434  /* A couple quicksanity checks */
435  if (ob1 == ob2 || ob1->type != ob2->type)
436  return 0;
437 
438  if (ob1->speed != ob2->speed)
439  return 0;
440  /* Note sure why the following is the case - either the object has to
441  * be animated or have a very low speed. Is this an attempted monster
442  * check?
443  */
444  /*TODO is this check really needed?*/
445  if (!QUERY_FLAG(ob1, FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
446  return 0;
447 
448  /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
449  * value could not be stored in a int32_t (which unfortunately sometimes is
450  * used to store nrof).
451  */
452  if (ob1->nrof+ob2->nrof >= 1UL<<31)
453  return 0;
454 
455  /* This is really a spellbook check - really, we should
456  * check all objects in the inventory.
457  */
458  /*TODO is this check really needed?*/
459  if (ob1->inv || ob2->inv) {
460  /* if one object has inventory but the other doesn't, not equiv */
461  if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
462  return 0;
463 
464  /* Now check to see if the two inventory objects could merge */
465  if (!object_can_merge(ob1->inv, ob2->inv))
466  return 0;
467 
468  /* inventory ok - still need to check rest of this object to see
469  * if it is valid.
470  */
471  }
472 
473  /* Note: FLAG_INV_LOCKED is ignored for merging purposes */
474  if ((ob1->arch != ob2->arch)
475  || (ob1->flags[0] != ob2->flags[0])
476  || (ob1->flags[1] != ob2->flags[1])
477  || (ob1->flags[2] != ob2->flags[2])
478  || ((ob1->flags[3]&~0x84) != (ob2->flags[3]&~0x84)) /* ignore CLIENT_SENT and FLAG_OBJ_ORIGINAL */
479  || (ob1->name != ob2->name)
480  || (ob1->title != ob2->title)
481  || (ob1->msg != ob2->msg)
482  || (ob1->weight != ob2->weight)
483  || (ob1->item_power != ob2->item_power)
484  || (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist)) != 0)
485  || (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats)) != 0)
486  || (ob1->attacktype != ob2->attacktype)
487  || (ob1->magic != ob2->magic)
488  || (ob1->slaying != ob2->slaying)
489  || (ob1->skill != ob2->skill)
490  || (ob1->value != ob2->value)
491  || (ob1->animation != ob2->animation)
492  || (ob1->client_type != ob2->client_type)
493  || (ob1->materialname != ob2->materialname)
494  || (ob1->lore != ob2->lore)
495  || (ob1->subtype != ob2->subtype)
496  || (ob1->move_type != ob2->move_type)
497  || (ob1->move_block != ob2->move_block)
498  || (ob1->move_allow != ob2->move_allow)
499  || (ob1->move_on != ob2->move_on)
500  || (ob1->move_off != ob2->move_off)
501  || (ob1->move_slow != ob2->move_slow)
502  || (ob1->move_slow_penalty != ob2->move_slow_penalty)
503  || (ob1->map_layer != ob2->map_layer))
504  return 0;
505 
506  /* Don't merge objects that are applied. With the new 'body' code,
507  * it is possible for most any character to have more than one of
508  * some items equipped, and we don't want those to merge.
509  */
510  if (QUERY_FLAG(ob1, FLAG_APPLIED) || QUERY_FLAG(ob2, FLAG_APPLIED))
511  return 0;
512 
513  if (ob1->key_values != NULL || ob2->key_values != NULL) {
514  /* At least one of these has key_values. */
515  if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
516  /* One has fields, but the other one doesn't. */
517  return 0;
518  } else {
519  if (!compare_ob_value_lists(ob1, ob2)) {
520  return 0;
521  }
522  }
523  }
524 
525  /*TODO should this really be limited to scrolls?*/
526  switch (ob1->type) {
527  case SCROLL:
528  if (ob1->level != ob2->level)
529  return 0;
530  break;
531  }
532 
533  /* Everything passes, must be OK. */
534  return 1;
535 }
536 
552 /* TODO should check call this this are made a place where we really need reevaluaton of whole tree */
553 signed long object_sum_weight(object *op) {
554  signed long sum;
555 
556  sum = 0;
557  FOR_INV_PREPARE(op, inv) {
558  if (inv->inv)
559  object_sum_weight(inv);
560  sum += inv->carrying+inv->weight*NROF(inv);
561  } FOR_INV_FINISH();
562  if (op->type == CONTAINER && op->stats.Str)
563  sum = (sum*(100-op->stats.Str))/100;
564  op->carrying = sum;
565  return sum;
566 }
567 
575 object *object_get_env_recursive(object *op) {
576  while (op->env != NULL)
577  op = op->env;
578  return op;
579 }
580 
592 object *object_get_player_container(object *op) {
593  for (; op != NULL && op->type != PLAYER; op = op->env)
594  /*TODO this is patching the structure on the flight as side effect. Shoudln't be needed in clean code */
595  if (op->env == op)
596  op->env = NULL;
597  return op;
598 }
599 
609 static const object *object_get_owner_const(const object *op) {
610  if (op->owner == NULL)
611  return NULL;
612 
613  if (!QUERY_FLAG(op->owner, FLAG_FREED)
614  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
615  && op->owner->count == op->ownercount)
616  return op->owner;
617 
618  LOG(llevError, "Warning, no owner found\n");
619  return NULL;
620 }
621 
630 void object_dump(const object *op, StringBuffer *sb) {
631  if (op == NULL) {
632  stringbuffer_append_string(sb, "[NULL pointer]");
633  return;
634  }
635 
636  /* object *tmp;*/
637 
638  if (op->arch != NULL) {
639  const object *owner;
640 
641  stringbuffer_append_string(sb, "arch ");
642  stringbuffer_append_string(sb, op->arch->name ? op->arch->name : "(null)");
643  stringbuffer_append_string(sb, "\n");
644 
645  if (op->artifact != NULL) {
646  stringbuffer_append_string(sb, "artifact ");
648  stringbuffer_append_string(sb, "\n");
649  }
650 
651  get_ob_diff(sb, op, &empty_archetype->clone);
652  if (op->more) {
653  stringbuffer_append_printf(sb, "more %u\n", op->more->count);
654  }
655  if (op->head) {
656  stringbuffer_append_printf(sb, "head %u\n", op->head->count);
657  }
658  if (op->env) {
659  stringbuffer_append_printf(sb, "env %u\n", op->env->count);
660  }
661  if (op->inv) {
662  stringbuffer_append_printf(sb, "inv %u\n", op->inv->count);
663  }
664  if (op->enemy) {
665  stringbuffer_append_printf(sb, "enemy %u\n", op->enemy->count);
666  }
667  if (op->attacked_by) {
668  stringbuffer_append_printf(sb, "attacked_by %u\n", op->attacked_by->count);
669  }
670  owner = object_get_owner_const(op);
671  if (owner != NULL) {
672  stringbuffer_append_printf(sb, "owner %u\n", owner->count);
673  }
674  stringbuffer_append_string(sb, "end\n");
675  } else {
676  stringbuffer_append_string(sb, "Object ");
677  stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
678  stringbuffer_append_string(sb, "\nend\n");
679  }
680 }
681 
689 void object_dump_all(void) {
690  object *op;
691 
692  for (op = objects; op != NULL; op = op->next) {
693  StringBuffer *sb;
694  char *diff;
695 
696  sb = stringbuffer_new();
697  object_dump(op, sb);
698  diff = stringbuffer_finish(sb);
699  LOG(llevDebug, "Object %u\n:%s\n", op->count, diff);
700  free(diff);
701  }
702 }
703 
713  object *op;
714 
715  for (op = objects; op != NULL; op = op->next)
716  if (op->count == i)
717  break;
718  return op;
719 }
720 
732 object *object_find_by_name_global(const char *str) {
733  const char *name = add_string(str);
734  object *op;
735 
736  for (op = objects; op != NULL; op = op->next)
737  if (op->name == name)
738  break;
739  free_string(name);
740  return op;
741 }
742 
753 #ifdef MEMORY_DEBUG
754  object *op, *next;
755 
756  for (op = free_objects; op != NULL; ) {
757  next = op->next;
758  free(op);
760  nroffreeobjects--;
761  op = next;
762  }
763  free_objects = NULL;
764 
765  for (op = objects; op != NULL; ) {
766  next = op->next;
767  if (!QUERY_FLAG(op, FLAG_FREED)) {
768  LOG(llevDebug, "non freed object: %s\n", op->name);
769  }
770  op = next;
771  }
772 #endif
773 
774  LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX);
775 }
776 
789 object *object_get_owner(object *op) {
790  if (op->owner == NULL)
791  return NULL;
792 
793  if (!QUERY_FLAG(op->owner, FLAG_FREED)
794  && !QUERY_FLAG(op->owner, FLAG_REMOVED)
795  && op->owner->count == op->ownercount)
796  return op->owner;
797 
798  object_clear_owner(op);
799  return NULL;
800 }
801 
808 void object_clear_owner(object *op) {
809  if (!op)
810  return;
811 
812  op->owner = NULL;
813  op->ownercount = 0;
814 }
815 
825 void object_set_owner(object *op, object *owner) {
826  /* Assign temp to something, so it can't accidentally be NULL */
827  object *tmp = owner;
828  if (op == NULL)
829  return;
830  if (owner == NULL) {
831  object_clear_owner(op);
832  return;
833  }
834 
835  /* next line added to allow objects which own objects */
836  /* Add a check for ownercounts in here, as I got into an endless loop
837  * with the fireball owning a poison cloud which then owned the
838  * fireball. I believe that was caused by one of the objects getting
839  * freed and then another object replacing it. Since the ownercounts
840  * didn't match, this check is valid and I believe that cause is valid.
841  */
842  /*
843  * if owner is NULL, function will have already returned,
844  * so loop should still function as before.
845  */
846  while (tmp) {
847  tmp = object_get_owner(owner);
848  if (tmp)
849  owner = tmp;
850  }
851 
852  /* must not cause owner cycles */
853  assert(op != owner);
854 
855  if (op->owner != NULL)
856  object_clear_owner(op);
857 
858  op->owner = owner;
859  op->ownercount = owner->count;
860 }
861 
878 void object_copy_owner(object *op, object *clone) {
879  object *owner = object_get_owner(clone);
880  if (owner == NULL) {
881  /* players don't have owners - they own themselves. Update
882  * as appropriate.
883  */
884  /*TODO owner=self is dangerous and should be avoided*/
885  if (clone->type != PLAYER)
886  return;
887  owner = clone;
888  }
889  object_set_owner(op, owner);
890 }
891 
900 void object_set_enemy(object *op, object *enemy) {
901  if (op->enemy == enemy) {
902  return;
903  }
904 
905 #if 0
906  if (op->type != PLAYER) {
907  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);
908  }
909 #endif
910  op->enemy = enemy;
911 }
912 
919 void object_reset(object *op) {
920  op->name = NULL;
921  op->name_pl = NULL;
922  op->title = NULL;
923  op->race = NULL;
924  op->slaying = NULL;
925  op->skill = NULL;
926  op->msg = NULL;
927  op->materialname = NULL;
928  op->lore = NULL;
929  object_clear(op);
930 }
931 
939 void object_free_key_values(object *op) {
940  key_value *i;
941  key_value *next = NULL;
942 
943  if (op->key_values == NULL)
944  return;
945 
946  for (i = op->key_values; i != NULL; i = next) {
947  /* Store next *first*. */
948  next = i->next;
949 
950  if (i->key)
952  if (i->value)
954  i->next = NULL;
955  free(i);
956  }
957 
958  op->key_values = NULL;
959 }
960 
968 void object_clear(object *op) {
969  /*TODO this comment must be investigated*/
970  /* redo this to be simpler/more efficient. Was also seeing
971  * crashes in the old code. Move this to the top - am
972  * seeing periodic crashes in this code, and would like to have
973  * as much info available as possible (eg, object name).
974  */
977 
978  /* the memset will clear all these values for us, but we need
979  * to reduce the refcount on them.
980  */
981  if (op->name != NULL)
983  if (op->name_pl != NULL)
985  if (op->title != NULL)
987  if (op->race != NULL)
989  if (op->slaying != NULL)
991  if (op->skill != NULL)
993  if (op->msg != NULL)
994  FREE_AND_CLEAR_STR(op->msg);
995  if (op->lore != NULL)
997  if (op->materialname != NULL)
999 
1000  /* Remove object from friendly list if needed. */
1001  if (QUERY_FLAG(op, FLAG_FRIENDLY))
1003 
1004  memset((void *)((char *)op+offsetof(object, name)), 0, sizeof(object)-offsetof(object, name));
1005  /* Below here, we clear things that are not done by the memset,
1006  * or set default values that are not zero.
1007  */
1008  /* This is more or less true */
1009  SET_FLAG(op, FLAG_REMOVED);
1010 
1011 
1012  op->contr = NULL;
1013  op->below = NULL;
1014  op->above = NULL;
1015  op->inv = NULL;
1016  op->container = NULL;
1017  op->env = NULL;
1018  op->more = NULL;
1019  op->head = NULL;
1020  op->map = NULL;
1021  op->active_next = NULL;
1022  op->active_prev = NULL;
1023  /* What is not cleared is next, prev, and count */
1024 
1025  op->expmul = 1.0;
1026  op->face = blank_face;
1027  op->attacked_by_count = -1;
1028  if (settings.casting_time)
1029  op->casting_time = -1;
1030 }
1031 
1046 void object_copy_no_speed(const object *src_ob, object *dest_ob) {
1047  int is_freed = QUERY_FLAG(dest_ob, FLAG_FREED), is_removed = QUERY_FLAG(dest_ob, FLAG_REMOVED);
1048 
1049  /* Decrement the refcounts, but don't bother zeroing the fields;
1050  they'll be overwritten by memcpy. */
1051  if (dest_ob->artifact != NULL)
1052  free_string(dest_ob->artifact);
1053  if (dest_ob->name != NULL)
1054  free_string(dest_ob->name);
1055  if (dest_ob->name_pl != NULL)
1056  free_string(dest_ob->name_pl);
1057  if (dest_ob->anim_suffix != NULL)
1058  free_string(dest_ob->anim_suffix);
1059  if (dest_ob->title != NULL)
1060  free_string(dest_ob->title);
1061  if (dest_ob->race != NULL)
1062  free_string(dest_ob->race);
1063  if (dest_ob->slaying != NULL)
1064  free_string(dest_ob->slaying);
1065  if (dest_ob->skill != NULL)
1066  free_string(dest_ob->skill);
1067  if (dest_ob->msg != NULL)
1068  free_string(dest_ob->msg);
1069  if (dest_ob->lore != NULL)
1070  free_string(dest_ob->lore);
1071  if (dest_ob->materialname != NULL)
1072  free_string(dest_ob->materialname);
1073  if (dest_ob->spell_tags != NULL)
1074  FREE_AND_CLEAR(dest_ob->spell_tags);
1075 
1076  /* Basically, same code as from object_clear() */
1077 
1078  object_free_key_values(dest_ob);
1079  free_dialog_information(dest_ob);
1080 
1081  /* Copy all attributes below name (name included). */
1082  (void)memcpy((void *)((char *)dest_ob+offsetof(object, name)),
1083  (void *)((char *)src_ob+offsetof(object, name)),
1084  sizeof(object)-offsetof(object, name));
1085 
1086  if (is_freed)
1087  SET_FLAG(dest_ob, FLAG_FREED);
1088  if (is_removed)
1089  SET_FLAG(dest_ob, FLAG_REMOVED);
1090  if (dest_ob->artifact != NULL)
1091  add_refcount(dest_ob->artifact);
1092  if (dest_ob->name != NULL)
1093  add_refcount(dest_ob->name);
1094  if (dest_ob->name_pl != NULL)
1095  add_refcount(dest_ob->name_pl);
1096  if (dest_ob->anim_suffix != NULL)
1097  add_refcount(dest_ob->anim_suffix);
1098  if (dest_ob->title != NULL)
1099  add_refcount(dest_ob->title);
1100  if (dest_ob->race != NULL)
1101  add_refcount(dest_ob->race);
1102  if (dest_ob->slaying != NULL)
1103  add_refcount(dest_ob->slaying);
1104  if (dest_ob->skill != NULL)
1105  add_refcount(dest_ob->skill);
1106  if (dest_ob->lore != NULL)
1107  add_refcount(dest_ob->lore);
1108  if (dest_ob->msg != NULL)
1109  add_refcount(dest_ob->msg);
1110  if (dest_ob->materialname != NULL)
1111  add_refcount(dest_ob->materialname);
1112 
1113  if (dest_ob->spell_tags != NULL) {
1114  dest_ob->spell_tags = static_cast<tag_t *>(malloc(sizeof(tag_t)*SPELL_TAG_SIZE));
1115  memcpy(dest_ob->spell_tags, src_ob->spell_tags, sizeof(tag_t)*SPELL_TAG_SIZE);
1116  }
1117 
1118  /* If archetype is a temporary one, we need to update reference count, because
1119  * that archetype will be freed by object_free_drop_inventory() when the last object is removed.
1120  */
1121  if (dest_ob->arch != NULL) {
1122  if (dest_ob->arch->reference_count > 0)
1123  dest_ob->arch->reference_count++;
1124  }
1125 
1126  if (src_ob->speed < 0)
1127  dest_ob->speed_left = src_ob->speed_left-RANDOM()%200/100.0;
1128 
1129  /* Copy over key_values, if any. */
1130  if (src_ob->key_values != NULL) {
1131  key_value *tail = NULL;
1132  key_value *i;
1133 
1134  dest_ob->key_values = NULL;
1135 
1136  for (i = src_ob->key_values; i != NULL; i = i->next) {
1137  key_value *new_link = static_cast<key_value *>(malloc(sizeof(key_value)));
1138 
1139  new_link->next = NULL;
1140  new_link->key = add_refcount(i->key);
1141  if (i->value)
1142  new_link->value = add_refcount(i->value);
1143  else
1144  new_link->value = NULL;
1145 
1146  /* Try and be clever here, too. */
1147  if (dest_ob->key_values == NULL) {
1148  dest_ob->key_values = new_link;
1149  tail = new_link;
1150  } else {
1151  tail->next = new_link;
1152  tail = new_link;
1153  }
1154  }
1155  }
1156 
1157  /* This way, dialog information will be parsed again when/if needed. */
1158  CLEAR_FLAG(dest_ob, FLAG_DIALOG_PARSED);
1159 
1160  dest_ob->event_bitmask = BITMASK_VALID; // Empty inventory so valid
1161 }
1162 
1177 void object_copy(const object *src_ob, object *dest_ob) {
1178  object_copy_no_speed(src_ob, dest_ob);
1179  object_update_speed(dest_ob);
1180 }
1181 
1193 void object_copy_with_inv(const object *src_ob, object *dest_ob, bool update_speed) {
1194  if (update_speed) {
1195  object_copy(src_ob, dest_ob);
1196  } else {
1197  object_copy_no_speed(src_ob, dest_ob);
1198  }
1199  FOR_INV_PREPARE(src_ob, walk) {
1200  object *tmp;
1201 
1202  tmp = object_new();
1203  object_copy_with_inv(walk, tmp, update_speed);
1204  object_insert_in_ob(tmp, dest_ob);
1205  } FOR_INV_FINISH();
1206 }
1207 
1208 #ifndef MEMORY_DEBUG
1209 
1216 static void expand_objects(void) {
1217  int i;
1218  object *add;
1219 
1220  add = (object *)CALLOC(OBJ_EXPAND, sizeof(object));
1221 
1222  if (add == NULL)
1224  free_objects = add;
1225  add[0].prev = NULL;
1226  add[0].next = &add[1],
1227  SET_FLAG(&add[0], FLAG_REMOVED);
1228  SET_FLAG(&add[0], FLAG_FREED);
1229 
1230  for (i = 1; i < OBJ_EXPAND-1; i++) {
1231  add[i].next = &add[i+1],
1232  add[i].prev = &add[i-1],
1233  SET_FLAG(&add[i], FLAG_REMOVED);
1234  SET_FLAG(&add[i], FLAG_FREED);
1235  }
1236  add[OBJ_EXPAND-1].prev = &add[OBJ_EXPAND-2],
1237  add[OBJ_EXPAND-1].next = NULL,
1238  SET_FLAG(&add[OBJ_EXPAND-1], FLAG_REMOVED);
1239  SET_FLAG(&add[OBJ_EXPAND-1], FLAG_FREED);
1240 
1243 }
1244 #endif
1245 
1258 object *object_new(void) {
1259  object *op;
1260 #ifdef MEMORY_DEBUG
1261  /* FIXME: However this doesn't work since object_free() sometimes add
1262  * objects back to the free_objects linked list, and some functions mess
1263  * with the object after return of object_free(). This is bad and should be
1264  * fixed. But it would need fairly extensive changes and a lot of debugging.
1265  */
1266  op = static_cast<object *>(calloc(1, sizeof(object)));
1267  if (op == NULL)
1269 #else
1270  if (free_objects == NULL) {
1271  expand_objects();
1272  }
1273  op = free_objects;
1274  if (!QUERY_FLAG(op, FLAG_FREED)) {
1275  LOG(llevError, "Fatal: Getting busy object.\n");
1276 #ifdef MANY_CORES
1277  abort();
1278 #endif
1279  }
1280  free_objects = op->next;
1281  if (free_objects != NULL)
1282  free_objects->prev = NULL;
1283  nroffreeobjects--;
1284 #endif
1285  op->count = ++ob_count;
1286  op->name = NULL;
1287  op->name_pl = NULL;
1288  op->title = NULL;
1289  op->race = NULL;
1290  op->slaying = NULL;
1291  op->skill = NULL;
1292  op->lore = NULL;
1293  op->msg = NULL;
1294  op->materialname = NULL;
1295  op->next = objects;
1296  op->prev = NULL;
1297  op->active_next = NULL;
1298  op->active_prev = NULL;
1299  op->spell_tags = NULL;
1301  if (objects != NULL)
1302  objects->prev = op;
1303  objects = op;
1304  object_clear(op);
1305  SET_FLAG(op, FLAG_REMOVED);
1306  return op;
1307 }
1308 
1317 void object_update_turn_face(object *op) {
1318  if (op->animation == 0 || !QUERY_FLAG(op, FLAG_IS_TURNABLE))
1319  return;
1320  animate_object(op, op->direction);
1321 }
1322 
1334 void object_update_speed(object *op) {
1335 
1336  /* No reason putting the archetypes objects on the speed list,
1337  * since they never really need to be updated.
1338  */
1339 
1340  if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
1341  LOG(llevError, "Object %s is freed but has speed.\n", op->name);
1342 #ifdef MANY_CORES
1343  abort();
1344 #else
1345  op->speed = 0;
1346 #endif
1347  }
1348  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
1349  /* If already on active list, don't do anything */
1350  /* TODO this check can probably be simplified a lot */
1351  if (op->active_next || op->active_prev || op == active_objects)
1352  return;
1353 
1354  /* process_events() expects us to insert the object at the beginning
1355  * of the list. */
1357  if (op->active_next != NULL)
1358  op->active_next->active_prev = op;
1359  active_objects = op;
1360  } else {
1362  }
1363 }
1364 
1378  /* If not on the active list, nothing needs to be done */
1379  if (!op->active_next && !op->active_prev && op != active_objects)
1380  return;
1381 
1382  if (op->active_prev == NULL) {
1384  if (op->active_next != NULL)
1385  op->active_next->active_prev = NULL;
1386  } else {
1387  op->active_prev->active_next = op->active_next;
1388  if (op->active_next)
1389  op->active_next->active_prev = op->active_prev;
1390  }
1391  op->active_next = NULL;
1392  op->active_prev = NULL;
1393 }
1394 
1419 void object_update(object *op, int action) {
1420  int update_now = 0, flags;
1421  MoveType move_on, move_off, move_block, move_slow;
1422  object *pl;
1423 
1424  if (op == NULL) {
1425  /* this should never happen */
1426  LOG(llevDebug, "object_update() called for NULL object.\n");
1427  return;
1428  }
1429 
1430  if (op->env != NULL) {
1431  /* Animation is currently handled by client, so nothing
1432  * to do in this case.
1433  */
1434  return;
1435  }
1436 
1437  /* If the map is saving, don't do anything as everything is
1438  * going to get freed anyways.
1439  */
1440  if (!op->map || op->map->in_memory == MAP_SAVING)
1441  return;
1442 
1443  /* make sure the object is within map boundaries */
1444  if (op->x < 0 || op->x >= MAP_WIDTH(op->map)
1445  || op->y < 0 || op->y >= MAP_HEIGHT(op->map)) {
1446  LOG(llevError, "object_update() called for object out of map!\n");
1447 #ifdef MANY_CORES
1448  abort();
1449 #endif
1450  return;
1451  }
1452 
1453  flags = GET_MAP_FLAGS(op->map, op->x, op->y);
1454  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NEED_UPDATE);
1455  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
1456  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
1457  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
1458  move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y);
1459 
1460  if (action == UP_OBJ_INSERT) {
1462  update_now = 1;
1463 
1464  if (QUERY_FLAG(op, FLAG_NO_MAGIC) && !(flags&P_NO_MAGIC))
1465  update_now = 1;
1466 
1467  if (QUERY_FLAG(op, FLAG_DAMNED) && !(flags&P_NO_CLERIC))
1468  update_now = 1;
1469 
1470  if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags&P_IS_ALIVE))
1471  update_now = 1;
1472 
1473  if ((move_on|op->move_on) != move_on)
1474  update_now = 1;
1475  if ((move_off|op->move_off) != move_off)
1476  update_now = 1;
1477  /* This isn't perfect, but I don't expect a lot of objects to
1478  * to have move_allow right now.
1479  */
1480  if (((move_block|op->move_block)&~op->move_allow) != move_block)
1481  update_now = 1;
1482  if ((move_slow|op->move_slow) != move_slow)
1483  update_now = 1;
1484 
1485  if (op->type == PLAYER)
1486  update_now = 1;
1487  /* if the object is being removed, we can't make intelligent
1488  * decisions, because object_remove() can't really pass the object
1489  * that is being removed.
1490  */
1491  } else if (action == UP_OBJ_REMOVE) {
1492  update_now = 1;
1493  } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) {
1494  /* In addition to sending info to client, need to update space
1495  * information.
1496  */
1497  if (action == UP_OBJ_CHANGE)
1498  update_now = 1;
1499 
1500  /* There is a player on this space - we may need to send an
1501  * update to the client.
1502  * If this object is supposed to be animated by the client,
1503  * nothing to do here - let the client animate it.
1504  * We can't use FLAG_ANIMATE, as that is basically set for
1505  * all objects with multiple faces, regardless if they are animated.
1506  * (levers have it set for example).
1507  */
1508  if (flags&P_PLAYER
1511  pl = GET_MAP_PLAYER(op->map, op->x, op->y);
1512 
1513  /* If update_look is set, we're going to send this entire space
1514  * to the client, so no reason to send face information now.
1515  */
1516  if (!pl->contr->socket->update_look) {
1517  esrv_update_item(UPD_FACE, pl, op);
1518  }
1519  }
1520  } else {
1521  LOG(llevError, "object_update called with invalid action: %d\n", action);
1522  }
1523 
1524  if (update_now) {
1525  SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NO_ERROR|P_NEED_UPDATE);
1526  update_position(op->map, op->x, op->y);
1527  }
1528 
1529  if (op->more != NULL)
1530  object_update(op->more, action);
1531 }
1532 
1545 void object_free_drop_inventory(object *ob) {
1546  object_free(ob, 0);
1547 }
1548 
1553 void object_free_inventory(object *ob) {
1554  while (ob->inv) {
1555  object *inv = ob->inv;
1556  object_remove(inv);
1558  }
1559 }
1560 
1577 void object_free(object *ob, int flags) {
1578  if (!QUERY_FLAG(ob, FLAG_REMOVED)) {
1579  StringBuffer *sb;
1580  char *diff;
1581 
1582  LOG(llevError, "Free object called with non removed object\n");
1583  sb = stringbuffer_new();
1584  object_dump(ob, sb);
1585  diff = stringbuffer_finish(sb);
1586  LOG(llevError, "%s", diff);
1587  free(diff);
1588 #ifdef MANY_CORES
1589  abort();
1590 #endif
1591  }
1592  if (QUERY_FLAG(ob, FLAG_FRIENDLY)) {
1593  LOG(llevMonster, "Warning: tried to free friendly object.\n");
1595  }
1596  if (QUERY_FLAG(ob, FLAG_FREED)) {
1597  StringBuffer *sb;
1598  char *diff;
1599 
1600  sb = stringbuffer_new();
1601  object_dump(ob, sb);
1602  diff = stringbuffer_finish(sb);
1603  LOG(llevError, "Trying to free freed object.\n%s\n", diff);
1604  free(diff);
1605  return;
1606  }
1607 
1608  if ((flags & FREE_OBJ_NO_DESTROY_CALLBACK) == 0) {
1610  }
1611 
1612  if (ob->inv) {
1613  /* Only if the space blocks everything do we not process -
1614  * if some form of movemnt is allowed, let objects
1615  * drop on that space.
1616  */
1617  if ((flags & FREE_OBJ_FREE_INVENTORY) != 0
1618  || ob->map == NULL
1619  || ob->map->in_memory != MAP_IN_MEMORY
1620  || (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL)) {
1621  FOR_INV_PREPARE(ob, op) {
1622  object_remove(op);
1623  object_free(op, flags);
1624  } FOR_INV_FINISH();
1625  } else { /* Put objects in inventory onto this space */
1626  FOR_INV_PREPARE(ob, op) {
1627  object_remove(op);
1628  /* No drop means no drop, including its inventory */
1629  if (QUERY_FLAG(op, FLAG_NO_DROP))
1631  else if (QUERY_FLAG(op, FLAG_STARTEQUIP)
1632  || QUERY_FLAG(op, FLAG_NO_DROP)
1633  || op->type == RUNE
1634  || op->type == TRAP
1637  else {
1638  object *part;
1639 
1640  /* If it's a multi-tile object, scatter dropped items randomly */
1641  if (ob->more) {
1642  int partcount = 0;
1643  /* Get the number of non-head parts */
1644  for (part = ob; part; part = part->more) {
1645  partcount++;
1646  }
1647  /* Select a random part */
1648  partcount = RANDOM()%partcount;
1649  for (part = ob; partcount > 0; partcount--) {
1650  part = part->more;
1651  }
1652  } else {
1653  part = ob;
1654  }
1655 
1656  if (QUERY_FLAG(op, FLAG_ALIVE)) {
1657  object_insert_to_free_spot_or_free(op, part->map, part->x, part->y, 0, SIZEOFFREE, NULL);
1658  } else {
1659  int f = 0;
1662  object_insert_in_map_at(op, part->map, NULL, f, part->x, part->y); /* Insert in same map as the envir */
1663  }
1664  }
1665  } FOR_INV_FINISH();
1666  }
1667  }
1668 
1669  if (ob->more != NULL) {
1670  object_free(ob->more, flags);
1671  ob->more = NULL;
1672  }
1673 
1674  /* Remove object from the active list */
1675  ob->speed = 0;
1676  object_update_speed(ob);
1677 
1678  SET_FLAG(ob, FLAG_FREED);
1679  ob->count = 0;
1680 
1681  /* Remove this object from the list of used objects */
1682  if (ob->prev == NULL) {
1683  objects = ob->next;
1684  if (objects != NULL)
1685  objects->prev = NULL;
1686  } else {
1687  ob->prev->next = ob->next;
1688  if (ob->next != NULL)
1689  ob->next->prev = ob->prev;
1690  }
1691 
1692  if (ob->artifact != NULL) FREE_AND_CLEAR_STR(ob->artifact);
1693  if (ob->name != NULL) FREE_AND_CLEAR_STR(ob->name);
1694  if (ob->name_pl != NULL) FREE_AND_CLEAR_STR(ob->name_pl);
1695  if (ob->title != NULL) FREE_AND_CLEAR_STR(ob->title);
1696  if (ob->race != NULL) FREE_AND_CLEAR_STR(ob->race);
1697  if (ob->slaying != NULL) FREE_AND_CLEAR_STR(ob->slaying);
1698  if (ob->skill != NULL) FREE_AND_CLEAR_STR(ob->skill);
1699  if (ob->lore != NULL) FREE_AND_CLEAR_STR(ob->lore);
1700  if (ob->msg != NULL) FREE_AND_CLEAR_STR(ob->msg);
1701  if (ob->materialname != NULL) FREE_AND_CLEAR_STR(ob->materialname);
1702  if (ob->spell_tags) FREE_AND_CLEAR(ob->spell_tags);
1704 
1705  /* Why aren't events freed? */
1707 
1709 
1710  /* Test whether archetype is a temporary one, and if so look whether it should be trashed. */
1711  if (ob->arch && ob->arch->reference_count > 0) {
1712  if (--ob->arch->reference_count == 0) {
1713  free_arch(ob->arch);
1714  }
1715  }
1716 
1717 #ifdef MEMORY_DEBUG
1718  free(ob);
1719 #else
1720  /* Now link it with the free_objects list: */
1721  ob->prev = NULL;
1722  ob->next = free_objects;
1723  if (free_objects != NULL)
1724  free_objects->prev = ob;
1725  free_objects = ob;
1726  nroffreeobjects++;
1727 #endif
1728 }
1729 
1737  int i = 0;
1738  object *tmp = free_objects;
1739 
1740  while (tmp != NULL)
1741  tmp = tmp->next,
1742  i++;
1743  return i;
1744 }
1745 
1753  int i = 0;
1754  object *tmp = objects;
1755 
1756  while (tmp != NULL)
1757  tmp = tmp->next,
1758  i++;
1759  return i;
1760 }
1761 
1769  int i = 0;
1770  object *tmp = active_objects;
1771 
1772  while (tmp != NULL)
1773  tmp = tmp->active_next,
1774  i++;
1775  return i;
1776 }
1777 
1792 void object_sub_weight(object *op, signed long weight) {
1793  while (op != NULL) {
1794  if (op->type == CONTAINER) {
1795  weight = (signed long)(weight*(100-op->stats.Str)/100);
1796  }
1797  op->carrying -= weight;
1798  op = op->env;
1799  }
1800 }
1801 
1818 void object_remove(object *op) {
1819  object *last = NULL;
1820  object *otmp;
1821  tag_t tag;
1822  int check_walk_off;
1823  mapstruct *m;
1824  int16_t x, y;
1825 
1826  if (QUERY_FLAG(op, FLAG_REMOVED)) {
1827  StringBuffer *sb;
1828  char *diff;
1829 
1830  sb = stringbuffer_new();
1831  object_dump(op, sb);
1832  diff = stringbuffer_finish(sb);
1833  LOG(llevError, "Trying to remove removed object.\n%s\n", diff);
1834  free(diff);
1835  abort();
1836  }
1837  if (op->more != NULL)
1838  object_remove(op->more);
1839 
1840  SET_FLAG(op, FLAG_REMOVED);
1841 
1842  /*
1843  * In this case, the object to be removed is in someones
1844  * inventory.
1845  */
1846  /* TODO try to call a generic inventory weight adjusting function like object_sub_weight */
1847  if (op->env != NULL) {
1848  player *pl = NULL;
1849 
1850  if (op->nrof)
1851  object_sub_weight(op->env, op->weight*op->nrof);
1852  else
1853  object_sub_weight(op->env, op->weight+op->carrying);
1854 
1855  /* Update in two cases: item is in a player, or in a container the player is looking into. */
1856  if (op->env->contr != NULL && op->head == NULL) {
1857  pl = op->env->contr;
1858  } else if (op->env->type == CONTAINER && QUERY_FLAG(op->env, FLAG_APPLIED)) {
1859 
1860  if (op->env->env && op->env->env->contr)
1861  /* Container is in player's inventory. */
1862  pl = op->env->env->contr;
1863  else if (op->env->map) {
1864  /* Container on map, look above for player. */
1865  object *above = op->env->above;
1866 
1867  while (above && !above->contr)
1868  above = above->above;
1869  if (above)
1870  pl = above->contr;
1871  }
1872  }
1873 
1874  /* NO_FIX_PLAYER is set when a great many changes are being
1875  * made to players inventory. If set, avoiding the call
1876  * to save cpu time.
1877  */
1878  otmp = object_get_player_container(op->env);
1879  if (otmp != NULL
1880  && otmp->contr
1881  && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER))
1882  fix_object(otmp);
1883 
1884  if (op->above != NULL)
1885  op->above->below = op->below;
1886  else
1887  op->env->inv = op->below;
1888 
1889  if (op->below != NULL)
1890  op->below->above = op->above;
1891 
1892  if (op->type == EVENT_CONNECTOR) {
1893  op->env->event_bitmask = 0; // Will be recomputed if needed
1894  }
1895 
1896  /* we set up values so that it could be inserted into
1897  * the map, but we don't actually do that - it is up
1898  * to the caller to decide what we want to do.
1899  */
1900  op->x = op->env->x;
1901  op->y = op->env->y;
1902  op->ox = op->x;
1903  op->oy = op->y;
1904  op->map = op->env->map;
1905  op->above = NULL;
1906  op->below = NULL;
1907  /* send the delitem before resetting env, so container's contents be may
1908  * refreshed */
1909  if (LOOK_OBJ(op) && pl != NULL)
1910  esrv_del_item(pl, op);
1911  op->env = NULL;
1912  return;
1913  }
1914 
1915  /* If we get here, we are removing it from a map */
1916  if (op->map == NULL)
1917  return;
1918 
1919  if (op->contr != NULL && !op->contr->hidden)
1920  op->map->players--;
1921 
1922  x = op->x;
1923  y = op->y;
1924  m = get_map_from_coord(op->map, &x, &y);
1925 
1926  if (!m) {
1927  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);
1928  abort();
1929  }
1930  if (op->map != m) {
1931  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);
1932  }
1933 
1934  /* link the object above us */
1935  if (op->above)
1936  op->above->below = op->below;
1937  else
1938  SET_MAP_TOP(m, x, y, op->below); /* we were top, set new top */
1939 
1940  /* Relink the object below us, if there is one */
1941  if (op->below) {
1942  op->below->above = op->above;
1943  } else {
1944  /* Nothing below, which means we need to relink map object for this space
1945  * use translated coordinates in case some oddness with map tiling is
1946  * evident
1947  */
1948  /*TODO is this check really needed?*/
1949  if (GET_MAP_OB(m, x, y) != op) {
1950  StringBuffer *sb;
1951  char *diff;
1952 
1953  sb = stringbuffer_new();
1954  object_dump(op, sb);
1955  diff = stringbuffer_finish(sb);
1956  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);
1957  free(diff);
1958 
1959  sb = stringbuffer_new();
1960  object_dump(GET_MAP_OB(m, x, y), sb);
1961  diff = stringbuffer_finish(sb);
1962  LOG(llevError, "%s\n", diff);
1963  free(diff);
1964  }
1965  SET_MAP_OB(m, x, y, op->above); /* goes on above it. */
1966  }
1967  op->above = NULL;
1968  op->below = NULL;
1969 
1970  if (op->map->in_memory == MAP_SAVING)
1971  return;
1972 
1973  tag = op->count;
1974  check_walk_off = !QUERY_FLAG(op, FLAG_NO_APPLY);
1975  FOR_MAP_PREPARE(m, x, y, tmp) {
1976  /* No point updating the players look faces if he is the object
1977  * being removed.
1978  */
1979 
1980  if (tmp->type == PLAYER && tmp != op) {
1981  /* If a container that the player is currently using somehow gets
1982  * removed (most likely destroyed), update the player view
1983  * appropriately.
1984  */
1985  if (tmp->container == op) {
1986  CLEAR_FLAG(op, FLAG_APPLIED);
1987  tmp->container = NULL;
1988  // Notify the client the container is gone so it clears its active container.
1989  esrv_update_item(UPD_FLAGS, tmp, op);
1990  }
1991  tmp->contr->socket->update_look = 1;
1992  }
1993  /* See if player moving off should effect something */
1994  if (check_walk_off
1995  && ((op->move_type&tmp->move_off) && (op->move_type&~tmp->move_off&~tmp->move_block) == 0)) {
1996  ob_move_on(tmp, op, NULL);
1997  if (object_was_destroyed(op, tag)) {
1998  LOG(llevError, "BUG: object_remove(): name %s, archname %s destroyed leaving object\n", tmp->name, tmp->arch->name);
1999  }
2000  }
2001 
2002  /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
2003  if (tmp->above == tmp)
2004  tmp->above = NULL;
2005  last = tmp;
2006  } FOR_MAP_FINISH();
2007  /* last == NULL or there are no objects on this space */
2008  if (last == NULL) {
2009  /* set P_NEED_UPDATE, otherwise update_position will complain. In theory,
2010  * we could preserve the flags (GET_MAP_FLAGS), but update_position figures
2011  * those out anyways, and if there are any flags set right now, they won't
2012  * be correct anyways.
2013  */
2014  SET_MAP_FLAGS(op->map, op->x, op->y, P_NEED_UPDATE);
2015  update_position(op->map, op->x, op->y);
2016  } else
2018 
2019  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) || (op->glow_radius != 0))
2020  update_all_los(op->map, op->x, op->y);
2021 }
2022 
2036 object *object_merge(object *op, object *top) {
2037  if (!op->nrof)
2038  return NULL;
2039 
2040  if (top == NULL)
2041  for (top = op; top != NULL && top->above != NULL; top = top->above)
2042  ;
2044  if (top == op)
2045  continue;
2046  if (object_can_merge(op, top)) {
2047  object_increase_nrof(top, op->nrof);
2048  /*
2049  * Previous behavior set weight to zero here.
2050  * This, however, caused the object_sub_weight
2051  * call in object_remove to subtract zero weight
2052  * when removing the object. Thus, until inventory
2053  * weight is next recalculated, the object merged
2054  * into another pile added weight in object_increase_nrof
2055  * but did not remove the weight from the original
2056  * instance of itself in object_remove, essentially
2057  * counting for double weight for several minutes.
2058  *
2059  * SilverNexus 2014-05-27
2060  */
2061  object_remove(op);
2063  return top;
2064  }
2066  return NULL;
2067 }
2068 
2085 object *object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y) {
2086  object *tmp;
2087 
2088  op = HEAD(op);
2089  for (tmp = op; tmp; tmp = tmp->more) {
2090  tmp->x = x+tmp->arch->clone.x;
2091  tmp->y = y+tmp->arch->clone.y;
2092  tmp->map = m;
2093  }
2094  return object_insert_in_map(op, m, originator, flag);
2095 }
2096 
2114 void object_merge_spell(object *op, int16_t x, int16_t y) {
2115  int i;
2116 
2117  /* We try to do some merging of spell objects - if something has same owner,
2118  * is same type of spell, and going in the same direction, it is somewhat
2119  * mergable.
2120  *
2121  * If the spell object has an other_arch, don't merge - when the spell
2122  * does something, like explodes, it will use this other_arch, and
2123  * if we merge, there is no easy way to make the correct values be
2124  * set on this new object (values should be doubled, tripled, etc.)
2125  *
2126  * We also care about speed - only process objects that will not be
2127  * active this tick. Without this, the results are incorrect - think
2128  * of a case where tmp would normally get processed this tick, but
2129  * get merges with op, which does not get processed.
2130  */
2131  FOR_MAP_PREPARE(op->map, x, y, tmp) {
2132  if (op->type == tmp->type
2133  && op->subtype == tmp->subtype
2134  && op->direction == tmp->direction
2135  && op->owner == tmp->owner && op->ownercount == tmp->ownercount
2136  && op->range == tmp->range
2137  && op->stats.wc == tmp->stats.wc
2138  && op->level == tmp->level
2139  && op->attacktype == tmp->attacktype
2140  && op->speed == tmp->speed
2141  && !tmp->other_arch
2142  && (tmp->speed_left+tmp->speed) < 0.0
2143  && op != tmp) {
2144  /* Quick test - if one or the other objects already have hash tables
2145  * set up, and that hash bucket contains a value that doesn't
2146  * match what we want to set it up, we won't be able to merge.
2147  * Note that these two if statements are the same, except
2148  * for which object they are checking against. They could
2149  * be merged, but the line wrapping would be large enough
2150  * that IMO it would become difficult to read the different clauses
2151  * so its cleaner just to do 2 statements - MSW
2152  */
2153  if (op->spell_tags
2154  && !OB_SPELL_TAG_MATCH(op, (tag_t)tmp->stats.maxhp)
2155  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0)
2156  continue;
2157 
2158  if (tmp->spell_tags
2159  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)op->stats.maxhp)
2160  && OB_SPELL_TAG_HASH(tmp, op->stats.maxhp) != 0)
2161  continue;
2162 
2163  /* If we merge, the data from tmp->spell_tags gets copied into op.
2164  * so we need to make sure that slot isn't filled up.
2165  */
2166  if (tmp->spell_tags
2167  && !OB_SPELL_TAG_MATCH(tmp, (tag_t)tmp->stats.maxhp)
2168  && OB_SPELL_TAG_HASH(tmp, tmp->stats.maxhp) != 0)
2169  continue;
2170 
2171  /* If both objects have spell_tags, we need to see if there are conflicting
2172  * values - if there are, we won't be able to merge then.
2173  */
2174  if (tmp->spell_tags && op->spell_tags) {
2175  int need_copy = 0;
2176 
2177  for (i = 0; i < SPELL_TAG_SIZE; i++) {
2178  /* If the two tag values in the hash are set, but are
2179  * not set to the same value, then these objects
2180  * can not be merged.
2181  */
2182  if (op->spell_tags[i] && tmp->spell_tags[i]
2183  && op->spell_tags[i] != tmp->spell_tags[i]) {
2185  break;
2186  }
2187  /* If one tag is set and the other is not, that is
2188  * fine, but we have to note that we need to copy
2189  * the data in that case.
2190  */
2191  if ((!op->spell_tags[i] && tmp->spell_tags[i])
2192  || (op->spell_tags[i] && !tmp->spell_tags[i])) {
2193  need_copy = 1;
2194  }
2195  }
2196  /* If we did not get through entire array, it means
2197  * we got a conflicting hash, and so we won't be
2198  * able to merge these - just continue processing
2199  * object on this space.
2200  */
2201  if (i <= SPELL_TAG_SIZE)
2202  continue;
2203 
2204  /* Ok - everything checked out - we should be able to
2205  * merge tmp in op. So lets copy the tag data if
2206  * needed. Note that this is a selective copy, as
2207  * we don't want to clear values that may be set in op.
2208  */
2209  if (need_copy) {
2210  for (i = 0; i < SPELL_TAG_SIZE; i++)
2211  if (!op->spell_tags[i]
2212  && tmp->spell_tags[i]
2213  && tmp->spell_tags[i] != (tag_t)op->stats.maxhp)
2214  op->spell_tags[i] = tmp->spell_tags[i];
2215  }
2216  FREE_AND_CLEAR(tmp->spell_tags);
2217  }
2218 
2219  /* if tmp has a spell_tags table, copy it to op and free tmps */
2220  if (tmp->spell_tags && !op->spell_tags) {
2221  op->spell_tags = tmp->spell_tags;
2222  tmp->spell_tags = NULL;
2223 
2224  /* We don't need to keep a copy of our maxhp value
2225  * in the copied over value
2226  */
2227  if (OB_SPELL_TAG_MATCH(op, (tag_t)op->stats.maxhp))
2228  OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0;
2229  }
2230 
2231  /* For spells to work correctly, we need to record what spell
2232  * tags we've merged in with this effect. This is used
2233  * in ok_to_put_more() to see if a spell effect is already on
2234  * the space.
2235  */
2236  if (op->stats.maxhp != tmp->stats.maxhp) {
2237 #ifdef OBJECT_DEBUG
2238  /* This if statement should never happen - the logic above should
2239  * have prevented it. It is a problem, because by now its possible
2240  * we've destroyed the spell_tags in tmp, so we can't really
2241  * just bail out.
2242  */
2243 
2244  if (op->spell_tags
2245  && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0
2246  && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)) {
2247  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);
2248  }
2249 #endif
2250  if (!op->spell_tags)
2251  op->spell_tags = static_cast<tag_t *>(calloc(SPELL_TAG_SIZE, sizeof(tag_t)));
2252 
2253  OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) = tmp->stats.maxhp;
2254  }
2255 
2257  op->speed_left = MAX(op->speed_left, tmp->speed_left);
2258 
2259  if (tmp->duration != op->duration) {
2260  /* We need to use tmp_dam here because otherwise the
2261  * calculations can overflow the size of stats.dam.
2262  */
2263  int tmp_dam = tmp->stats.dam*(tmp->duration+1)+
2264  op->stats.dam*(op->duration+1);
2265 
2266  op->duration = MAX(op->duration, tmp->duration);
2267  tmp_dam /= op->duration+1;
2268  op->stats.dam = tmp_dam+1;
2269  } else {
2270  /* in this case, duration is the same, so simply adding
2271  * up damage works.
2272  */
2273  op->stats.dam += tmp->stats.dam;
2274  }
2275 
2276  object_remove(tmp);
2278  }
2279  } FOR_MAP_FINISH();
2280 }
2281 
2282 static object *find_insert_pos(object *op, const int flag) {
2283  object *floor = NULL;
2284  /*
2285  * If there are multiple objects on this space, we do some trickier handling.
2286  * We've already dealt with merging if appropriate.
2287  * Generally, we want to put the new object on top. But if
2288  * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last
2289  * floor, we want to insert above that and no further.
2290  * Also, if there are spell objects on this space, we stop processing
2291  * once we get to them. This reduces the need to traverse over all of
2292  * them when adding another one - this saves quite a bit of cpu time
2293  * when lots of spells are cast in one area. Currently, it is presumed
2294  * that flying non pickable objects are spell objects.
2295  */
2296  if (flag&INS_ON_TOP) {
2297  return GET_MAP_TOP(op->map, op->x, op->y);
2298  }
2299  object *last = NULL;
2300  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2301  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)
2302  || QUERY_FLAG(tmp, FLAG_OVERLAY_FLOOR))
2303  floor = tmp;
2304 
2305  if (QUERY_FLAG(tmp, FLAG_NO_PICK)
2306  && (tmp->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH))
2307  && !QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2308  /* We insert above tmp, so we want this object below this */
2309  break;
2310  }
2311  last = tmp;
2312  } FOR_MAP_FINISH();
2313  if (flag&INS_ABOVE_FLOOR_ONLY)
2314  return floor;
2315  return last;
2316 }
2317 
2346 object *object_insert_in_map(object *op, mapstruct *m, object *originator, int flag) {
2347  object *tmp, *top, *floor = NULL;
2348  int16_t x, y;
2349 
2350  if (QUERY_FLAG(op, FLAG_FREED)) {
2351  LOG(llevError, "Trying to insert freed object!\n");
2352  return NULL;
2353  }
2354  if (m == NULL) {
2355  StringBuffer *sb;
2356  char *diff;
2357 
2358  sb = stringbuffer_new();
2359  object_dump(op, sb);
2360  diff = stringbuffer_finish(sb);
2361  LOG(llevError, "Trying to insert in null-map!\n%s\n", diff);
2362  free(diff);
2363  return op;
2364  }
2365  if (out_of_map(m, op->x, op->y)) {
2366  StringBuffer *sb;
2367  char *diff;
2368 
2369  sb = stringbuffer_new();
2370  object_dump(op, sb);
2371  diff = stringbuffer_finish(sb);
2372  LOG(llevError, "Trying to insert object outside the map.\n%s\n", diff);
2373  free(diff);
2374 #ifdef MANY_CORES
2375  /* Better to catch this here, as otherwise the next use of this object
2376  * is likely to cause a crash. Better to find out where it is getting
2377  * improperly inserted.
2378  */
2379  abort();
2380 #endif
2381  return op;
2382  }
2383  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2384  StringBuffer *sb;
2385  char *diff;
2386 
2387  sb = stringbuffer_new();
2388  object_dump(op, sb);
2389  diff = stringbuffer_finish(sb);
2390  LOG(llevError, "Trying to insert (map) inserted object.\n%s\n", diff);
2391  free(diff);
2392  return op;
2393  }
2394  if (op->more != NULL) {
2395  /* The part may be on a different map. */
2396 
2397  object *more = op->more;
2398 
2399  /* We really need the caller to normalize coordinates - if
2400  * we set the map, that doesn't work if the location is within
2401  * a map and this is straddling an edge. So only if coordinate
2402  * is clear wrong do we normalize it.
2403  */
2404  if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
2405  /* Debugging information so you can see the last coordinates this object had */
2406  more->ox = more->x;
2407  more->oy = more->y;
2408  more->map = get_map_from_coord(more->map, &more->x, &more->y);
2409  } else if (!more->map) {
2410  /* For backwards compatibility - when not dealing with tiled maps,
2411  * more->map should always point to the parent.
2412  */
2413  more->map = m;
2414  }
2415 
2416  if (object_insert_in_map(more, more->map, originator, flag) == NULL) {
2417  if (!op->head)
2418  LOG(llevError, "BUG: object_insert_in_map(): inserting op->more killed op\n");
2419  return NULL;
2420  }
2421  }
2422  CLEAR_FLAG(op, FLAG_REMOVED);
2423 
2424  /* Debugging information so you can see the last coordinates this object had */
2425  op->ox = op->x;
2426  op->oy = op->y;
2427  x = op->x;
2428  y = op->y;
2429  op->map = get_map_from_coord(m, &x, &y);
2430  if (op->map == NULL) {
2431  // This can fail despite out_of_map() returning false.
2432  return op;
2433  }
2434 
2435  /* this has to be done after we translate the coordinates. */
2436  if (op->nrof
2437  && !(flag&INS_NO_MERGE)
2438  && op->type != SPELL_EFFECT) {
2439  FOR_MAP_PREPARE(op->map, x, y, spot) {
2440  if (object_can_merge(op, spot)) {
2441  op->nrof += spot->nrof;
2442  object_remove(spot);
2444  }
2445  } FOR_MAP_FINISH();
2446  } else if (op->type == SPELL_EFFECT
2447  && !op->range
2448  && !op->other_arch
2449  && (op->speed_left+op->speed) < 0.0) {
2450  object_merge_spell(op, x, y);
2451  }
2452 
2453  /* Ideally, the caller figures this out. However, it complicates a lot
2454  * of areas of callers (eg, anything that uses object_find_free_spot() would now
2455  * need extra work
2456  */
2457  if (op->map != m) {
2458  /* coordinates should not change unless map also changes */
2459  op->x = x;
2460  op->y = y;
2461  }
2462 
2463  if (op->type != LAMP)
2464  /* lamps use the FLAG_APPLIED to keep the light/unlit status, so don't reset it.
2465  Other objects just get unapplied, since the container "drops" them. */
2466  CLEAR_FLAG(op, FLAG_APPLIED);
2468  if (!QUERY_FLAG(op, FLAG_ALIVE))
2470 
2471  /* In many places, a player is passed as the originator, which
2472  * is fine. However, if the player is on a transport, they are not
2473  * actually on the map, so we can't use them for the linked pointers,
2474  * nor should the walk on function below use them either.
2475  */
2476  if (originator && originator->contr && originator->contr->transport)
2477  originator = originator->contr->transport;
2478 
2479  if (flag&INS_BELOW_ORIGINATOR && originator != NULL) {
2480  if (originator->map != op->map
2481  || originator->x != op->x
2482  || originator->y != op->y) {
2483  LOG(llevError, "object_insert_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n");
2484  abort();
2485  }
2486  op->above = originator;
2487  op->below = originator->below;
2488  if (op->below)
2489  op->below->above = op;
2490  else
2491  SET_MAP_OB(op->map, op->x, op->y, op);
2492  /* since *below *originator, no need to update top */
2493  originator->below = op;
2494  } else {
2495  /* Top is the object that our object (op) is going to get inserted above. */
2496  top = find_insert_pos(op, flag);
2497 
2498  /* First object on this space */
2499  if (!top) {
2500  op->above = GET_MAP_OB(op->map, op->x, op->y);
2501  if (op->above)
2502  op->above->below = op;
2503  op->below = NULL;
2504  SET_MAP_OB(op->map, op->x, op->y, op);
2505  } else { /* get inserted into the stack above top */
2506  op->above = top->above;
2507  if (op->above)
2508  op->above->below = op;
2509  op->below = top;
2510  top->above = op;
2511  }
2512  if (op->above == NULL)
2513  SET_MAP_TOP(op->map, op->x, op->y, op);
2514  } /* else not INS_BELOW_ORIGINATOR */
2515 
2516  if (!(flag&INS_MAP_LOAD)) {
2517  if (op->type == PLAYER)
2518  op->contr->do_los = 1;
2519 
2520  /* If we have a floor, we know the player, if any, will be above
2521  * it, so save a few ticks and start from there.
2522  */
2523  tmp = floor ? floor : GET_MAP_OB(op->map, op->x, op->y);
2525  if (tmp->type == PLAYER)
2526  tmp->contr->socket->update_look = 1;
2528 
2529  /* If this object glows, it may affect lighting conditions that are
2530  * visible to others on this map. But update_all_los is really
2531  * an inefficient way to do this, as it means los for all players
2532  * on the map will get recalculated. The players could very well
2533  * be far away from this change and not affected in any way -
2534  * this should get redone to only look for players within range,
2535  * or just updating the P_NEED_UPDATE for spaces within this area
2536  * of effect may be sufficient.
2537  */
2538  if (MAP_DARKNESS(op->map) && (op->glow_radius != 0))
2539  update_all_los(op->map, op->x, op->y);
2540 
2541  if (op->contr && !op->contr->hidden)
2542  op->map->players++;
2543  }
2544 
2545  /* updates flags (blocked, alive, no magic, etc) for this map space */
2547 
2548  /* Don't know if moving this to the end will break anything. However,
2549  * we want to have update_look set above before calling this.
2550  *
2551  * object_check_move_on() must be after this because code called from
2552  * object_check_move_on() depends on correct map flags (so functions like
2553  * blocked() and wall() work properly), and these flags are updated by
2554  * object_update().
2555  */
2556 
2557  /* if this is not the head or flag has been passed, don't check walk on status */
2558 
2559  if (!(flag&INS_NO_WALK_ON) && !op->head) {
2560  if (object_check_move_on(op, originator))
2561  return NULL;
2562 
2563  /* If we are a multi part object, lets work our way through the check
2564  * walk on's.
2565  */
2566  for (tmp = op->more; tmp != NULL; tmp = tmp->more)
2567  if (object_check_move_on(tmp, originator))
2568  return NULL;
2569  }
2570  return op;
2571 }
2572 
2582 void object_replace_insert_in_map(const char *arch_string, object *op) {
2583  object *tmp1;
2584  archetype *at;
2585 
2586  /* first search for itself and remove any old instances */
2587  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
2588  if (!strcmp(tmp->arch->name, arch_string)) { /* same archetype */
2589  object_remove(tmp);
2591  }
2592  } FOR_MAP_FINISH();
2593 
2594  at = find_archetype(arch_string);
2595  if (at == NULL) {
2596  return;
2597  }
2598  tmp1 = arch_to_object(at);
2599  object_insert_in_map_at(tmp1, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
2600 }
2601 
2622 object *object_split(object *orig_ob, uint32_t nr, char *err, size_t size) {
2623  object *newob;
2624 
2625  if (MAX(1, orig_ob->nrof) < nr) {
2626  /* If err is set, the caller knows that nr can be wrong (player trying to drop items), thus don't log that. */
2627  if (err)
2628  snprintf(err, size, "There are only %u %ss.", NROF(orig_ob), orig_ob->name);
2629  else
2630  LOG(llevDebug, "There are only %u %ss.\n", NROF(orig_ob), orig_ob->name);
2631  return NULL;
2632  }
2633  newob = object_create_clone(orig_ob);
2634  if (orig_ob->nrof == 0) {
2635  if (!QUERY_FLAG(orig_ob, FLAG_REMOVED)) {
2636  object_remove(orig_ob);
2637  }
2639  } else {
2640  newob->nrof = nr;
2641  object_decrease_nrof(orig_ob, nr);
2642  }
2643 
2644  return newob;
2645 }
2646 
2661 object *object_decrease_nrof(object *op, uint32_t i) {
2662  object *tmp;
2663 
2664  if (i == 0) /* objects with op->nrof require this check */
2665  return op;
2666 
2667  if (i > op->nrof)
2668  i = op->nrof;
2669 
2670  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2671  op->nrof -= i;
2672  } else if (op->env != NULL) {
2673  if (i < op->nrof) {
2674  player *pl;
2675  /* is this object in the players inventory, or sub container
2676  * therein?
2677  */
2678  tmp = object_get_player_container(op->env);
2679  /* nope. Is this a container the player has opened?
2680  * If so, set tmp to that player.
2681  * IMO, searching through all the players will mostly
2682  * likely be quicker than following op->env to the map,
2683  * and then searching the map for a player.
2684  */
2685  if (!tmp) {
2686  for (pl = first_player; pl; pl = pl->next)
2687  if (pl->ob->container == op->env)
2688  break;
2689  if (pl)
2690  tmp = pl->ob;
2691  else
2692  tmp = NULL;
2693  }
2694 
2695  /* Because of weight reduction by container and integer arithmetic,
2696  * there is no guarantee the rounded weight of combined items will be
2697  * the same as the sum of rounded weights.
2698  * Therefore just remove the current weight, and add the new.
2699  * Same adjustment done in object_increase_nrof().
2700  */
2701  object_sub_weight(op->env, op->weight * op->nrof);
2702  op->nrof -= i;
2703  object_add_weight(op->env, op->weight * op->nrof);
2704  if (tmp) {
2705  esrv_update_item(UPD_NROF, tmp, op);
2706  esrv_update_item(UPD_WEIGHT, tmp, op->env);
2707  fix_object(tmp);
2708  }
2709  } else {
2710  object_remove(op);
2711  op->nrof = 0;
2712  }
2713  } else {
2714  /* On a map. */
2715  if (i < op->nrof) {
2716  op->nrof -= i;
2717 
2718  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2719  if (pl->contr) {
2720  pl->contr->socket->update_look = 1;
2721  break;
2722  }
2723  FOR_MAP_FINISH();
2724  } else {
2725  object_remove(op);
2726  op->nrof = 0;
2727  }
2728  }
2729 
2730  if (op->nrof) {
2731  return op;
2732  } else {
2734  return NULL;
2735  }
2736 }
2737 
2748 static void object_increase_nrof(object *op, uint32_t i) {
2749  object *tmp;
2750 
2751  if (i == 0) /* objects with op->nrof require this check */
2752  return;
2753 
2754  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2755  op->nrof += i;
2756  } else if (op->env != NULL) {
2757  player *pl;
2758  /* is this object in the players inventory, or sub container
2759  * therein?
2760  */
2761  tmp = object_get_player_container(op->env);
2762  /* nope. Is this a container the player has opened?
2763  * If so, set tmp to that player.
2764  * IMO, searching through all the players will mostly
2765  * likely be quicker than following op->env to the map,
2766  * and then searching the map for a player.
2767  */
2768  if (!tmp) {
2769  for (pl = first_player; pl; pl = pl->next)
2770  if (pl->ob->container == op->env)
2771  break;
2772  if (pl)
2773  tmp = pl->ob;
2774  else
2775  tmp = NULL;
2776  }
2777 
2778  /* Because of weight reduction by container and integer arithmetic,
2779  * there is no guarantee the rounded weight of combined items will be
2780  * the same as the sum of rounded weights.
2781  * Therefore just remove the current weight, and add the new.
2782  * Same adjustment done in object_decrease_nrof().
2783  */
2784  object_sub_weight(op->env, op->weight * op->nrof);
2785  op->nrof += i;
2786  object_add_weight(op->env, op->weight * op->nrof);
2787  if (tmp) {
2788  esrv_update_item(UPD_NROF, tmp, op);
2789  // Why don't we need to update weight of op->env here?
2790  }
2791  } else {
2792  /* On a map. */
2793  op->nrof += i;
2794 
2795  FOR_MAP_PREPARE(op->map, op->x, op->y, pl)
2796  if (pl->contr) {
2797  pl->contr->socket->update_look = 1;
2798  break;
2799  }
2800  FOR_MAP_FINISH();
2801  }
2802 }
2803 
2818 void object_add_weight(object *op, signed long weight) {
2819  while (op != NULL) {
2820  if (op->type == CONTAINER) {
2821  weight = (signed long)(weight*(100-op->stats.Str)/100);
2822  }
2823  op->carrying += weight;
2824  op = op->env;
2825  }
2826 }
2827 
2842 object *object_insert_in_ob(object *op, object *where) {
2843  object *otmp;
2844 
2845  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
2846  StringBuffer *sb;
2847  char *diff;
2848 
2849  sb = stringbuffer_new();
2850  object_dump(op, sb);
2851  diff = stringbuffer_finish(sb);
2852  LOG(llevError, "Trying to insert (ob) inserted object.\n%s\n", diff);
2853  free(diff);
2854  return op;
2855  }
2856 
2857  if (where == NULL) {
2858  StringBuffer *sb;
2859  char *diff;
2860 
2861  sb = stringbuffer_new();
2862  object_dump(op, sb);
2863  diff = stringbuffer_finish(sb);
2864  LOG(llevError, "Trying to put object in NULL.\n%s\n", diff);
2865  free(diff);
2866  return op;
2867  }
2868  if (where->head) {
2869  LOG(llevDebug, "Warning: Tried to insert object wrong part of multipart object.\n");
2870  }
2871  where = HEAD(where);
2872  if (op->more) {
2873  LOG(llevError, "Tried to insert multipart object %s (%u)\n", op->name, op->count);
2874  return op;
2875  }
2877  CLEAR_FLAG(op, FLAG_REMOVED);
2878  if (op->nrof || op->type == SKILL) {
2879  FOR_INV_PREPARE(where, tmp)
2880  // Since harvesting skills have the same subtype, we need to check our shared string skill name as well
2881  if (op->type == SKILL && tmp->type == SKILL && op->subtype == tmp->subtype && op->skill == tmp->skill) {
2882  // Duplicate skill. Sum exp and total_exp.
2883  LOG(llevDebug, "Merged duplicate skill %s for %s\n", op->arch->name, where->name);
2884  tmp->stats.exp += op->stats.exp;
2885  tmp->total_exp += op->total_exp;
2886  SET_FLAG(op, FLAG_REMOVED);
2887  object_free(op, FREE_OBJ_FREE_INVENTORY | FREE_OBJ_NO_DESTROY_CALLBACK); /* free the inserted object */
2888  return tmp;
2889  } else if (object_can_merge(tmp, op)) {
2890  /* return the original object and remove inserted object
2891  * (client needs the original object) */
2892  object_increase_nrof(tmp, op->nrof);
2893  SET_FLAG(op, FLAG_REMOVED);
2894  object_free(op, FREE_OBJ_FREE_INVENTORY | FREE_OBJ_NO_DESTROY_CALLBACK); /* free the inserted object */
2895  return tmp;
2896  }
2897  FOR_INV_FINISH();
2898 
2899  /* the item couldn't merge. */
2900  object_add_weight(where, op->weight*op->nrof);
2901  } else
2902  object_add_weight(where, op->weight+op->carrying);
2903 
2904  op->map = NULL;
2905  op->env = where;
2906  op->above = NULL;
2907  op->below = NULL;
2908  op->x = 0,
2909  op->y = 0;
2910  op->ox = 0,
2911  op->oy = 0;
2912 
2913  /* Client has no idea of ordering so lets not bother ordering it here.
2914  * It sure simplifies this function...
2915  */
2916  if (where->inv == NULL)
2917  where->inv = op;
2918  else {
2919  op->below = where->inv;
2920  op->below->above = op;
2921  where->inv = op;
2922  }
2923 
2924  if (op->type == EVENT_CONNECTOR) {
2925  where->event_bitmask |= BITMASK_EVENT(op->subtype);
2926  }
2927 
2928  /* Update in 2 cases: object goes into player's inventory, or object goes into container the player
2929  * is looking into. */
2930  if (where->contr != NULL)
2931  esrv_send_item(where, op);
2932  else if (where->type == CONTAINER && QUERY_FLAG(where, FLAG_APPLIED)) {
2933  object *pl = NULL;
2934 
2935  if (op->env->env && op->env->env->contr)
2936  /* Container is in player's inventory. */
2937  pl = op->env->env;
2938  else if (op->env->map) {
2939  /* Container on map, look above for player. */
2941  if (above->contr) {
2942  pl = above;
2943  break;
2944  }
2945  FOR_ABOVE_FINISH();
2946  }
2947  if (pl)
2948  esrv_send_item(pl, op);
2949  }
2950 
2951  otmp = object_get_player_container(where);
2952  if (otmp && otmp->contr != NULL) {
2953  if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER)
2954  && (QUERY_FLAG(op, FLAG_APPLIED) || op->type == SKILL || op->glow_radius != 0))
2955  /* fix_object will only consider applied items, or skills, or items with a glow radius.
2956  thus no need to call it if our object hasn't that. */
2957  fix_object(otmp);
2958  }
2959 
2960  /* reset the light list and los of the players on the map */
2961  if (op->glow_radius != 0 && where->map) {
2962 #ifdef DEBUG_LIGHTS
2963  LOG(llevDebug, " object_insert_in_ob(): got %s to insert in map/op\n", op->name);
2964 #endif /* DEBUG_LIGHTS */
2965  if (MAP_DARKNESS(where->map)) {
2966  SET_MAP_FLAGS(where->map, where->x, where->y, P_NEED_UPDATE);
2967  update_position(where->map, where->x, where->y);
2968  update_all_los(where->map, where->x, where->y);
2969  }
2970  }
2971 
2972  return op;
2973 }
2974 
2997 int object_check_move_on(object *op, object *originator) {
2998  object *tmp;
2999  tag_t tag;
3000  mapstruct *m = op->map;
3001  int x = op->x, y = op->y;
3002  MoveType move_on, move_slow, move_block;
3003 
3004  if (QUERY_FLAG(op, FLAG_NO_APPLY))
3005  return 0;
3006 
3007  tag = op->count;
3008 
3009  move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y);
3010  move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y);
3011  move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y);
3012 
3013  /* if nothing on this space will slow op down or be applied,
3014  * no need to do checking below. have to make sure move_type
3015  * is set, as lots of objects don't have it set - we treat that
3016  * as walking.
3017  */
3018  if (op->move_type
3019  && !(op->move_type&move_on)
3020  && !(op->move_type&move_slow))
3021  return 0;
3022 
3023  /* This is basically inverse logic of that below - basically,
3024  * if the object can avoid the move on or slow move, they do so,
3025  * but can't do it if the alternate movement they are using is
3026  * blocked. Logic on this seems confusing, but does seem correct.
3027  */
3028  if ((op->move_type&~move_on&~move_block) != 0
3029  && (op->move_type&~move_slow&~move_block) != 0)
3030  return 0;
3031 
3032  /* The objects have to be checked from top to bottom.
3033  * Hence, we first go to the top:
3034  */
3035 
3036  tmp = GET_MAP_OB(op->map, op->x, op->y);
3038  if (tmp->above == NULL)
3039  break;
3040  /* Trim the search when we find the first other spell effect
3041  * this helps performance so that if a space has 50 spell objects,
3042  * we don't need to check all of them.
3043  */
3044  if ((tmp->move_type&MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK))
3045  break;
3048  if (tmp == op)
3049  continue; /* Can't apply yourself */
3050 
3051  /* Check to see if one of the movement types should be slowed down.
3052  * Second check makes sure that the movement types not being slowed
3053  * (~slow_move) is not blocked on this space - just because the
3054  * space doesn't slow down swimming (for example), if you can't actually
3055  * swim on that space, can't use it to avoid the penalty.
3056  */
3057  if (!QUERY_FLAG(op, FLAG_WIZPASS)) {
3058  if ((!op->move_type && tmp->move_slow&MOVE_WALK)
3059  || ((op->move_type&tmp->move_slow) && (op->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
3060  float diff;
3061 
3062  diff = tmp->move_slow_penalty*FABS(op->speed);
3063  if (op->type == PLAYER) {
3066  diff /= 4.0;
3067  }
3068  }
3069  op->speed_left -= diff;
3070  }
3071  }
3072 
3073  /* Basically same logic as above, except now for actual apply. */
3074  if ((!op->move_type && tmp->move_on&MOVE_WALK)
3075  || ((op->move_type&tmp->move_on) && (op->move_type&~tmp->move_on&~tmp->move_block) == 0)) {
3076  ob_move_on(tmp, op, originator);
3077  if (object_was_destroyed(op, tag))
3078  return 1;
3079 
3080  /* what the person/creature stepped onto has moved the object
3081  * someplace new. Don't process any further - if we did,
3082  * have a feeling strange problems would result.
3083  */
3084  if (op->map != m || op->x != x || op->y != y)
3085  return 0;
3086  }
3088  return 0;
3089 }
3090 
3103 object *map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at) {
3104  if (m == NULL || OUT_OF_REAL_MAP(m, x, y)) {
3105  LOG(llevError, "Present_arch called outside map.\n");
3106  return NULL;
3107  }
3108 
3109  FOR_MAP_PREPARE(m, x, y, tmp)
3110  if (tmp->arch == at)
3111  return tmp;
3112  FOR_MAP_FINISH();
3113 
3114  return NULL;
3115 }
3116 
3130 object *map_find_by_type(mapstruct *m, int x, int y, uint8_t type) {
3131  if (OUT_OF_REAL_MAP(m, x, y)) {
3132  return NULL;
3133  }
3134 
3135  FOR_MAP_PREPARE(m, x, y, tmp)
3136  if (tmp->type == type)
3137  return tmp;
3138  FOR_MAP_FINISH();
3139 
3140  return NULL;
3141 }
3142 
3153 object *object_present_in_ob(uint8_t type, const object *op) {
3154  object *tmp;
3155 
3156  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3157  if (tmp->type == type)
3158  return tmp;
3159 
3160  return NULL;
3161 }
3162 
3188 object *object_present_in_ob_by_name(int type, const char *str, const object *op) {
3189  object *tmp;
3190 
3191  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3192  if ((type == -1 || tmp->type == type) && !strcmp(str, tmp->name))
3193  return tmp;
3194  }
3195  return NULL;
3196 }
3197 
3207 object *arch_present_in_ob(const archetype *at, const object *op) {
3208  object *tmp;
3209 
3210  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
3211  if (tmp->arch == at)
3212  return tmp;
3213  return NULL;
3214 }
3215 
3224 void object_set_flag_inv(object*op, int flag) {
3225  object *tmp;
3226 
3227  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3228  SET_FLAG(tmp, flag);
3229  object_set_flag_inv(tmp, flag);
3230  }
3231 }
3232 
3241 void object_unset_flag_inv(object*op, int flag) {
3242  object *tmp;
3243 
3244  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3245  CLEAR_FLAG(tmp, flag);
3246  object_unset_flag_inv(tmp, flag);
3247  }
3248 }
3249 
3259 void object_set_cheat(object *op) {
3260  SET_FLAG(op, FLAG_WAS_WIZ);
3262 }
3263 
3281 int object_find_multi_free_spot_around(const object *ob, const object *gen, int16_t *hx, int16_t *hy) {
3282  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3283  int freecount = 0;
3284 
3285  ob = HEAD(ob);
3286 
3287  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3288  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3289  /*
3290  * sx and sy are now the coords of the bottom right corner of ob relative to the head.
3291  * genx and geny are now the coords of the bottom right corner of gen relative to the head.
3292  * sx2 and sy2 are now the coords of the head of ob relative to the top left corner.
3293  * genx2 and geny2 are now the coords of the head of gen relative to the top left corner.
3294  */
3295 
3296  sx++;
3297  sy++;
3298  genx++;
3299  geny++;
3300  /*
3301  * sx, sy, genx, and geny, are now the size of the object, excluding parts left and above
3302  * the head.
3303  */
3304 
3305  ix = gen->x-sx-genx2;
3306  iy = gen->y-sy-geny2;
3307  sx += genx+sx2;
3308  sy += geny+sy2;
3309  /*
3310  * ix and iy are the map coords of the top left square where the head of ob could possibly
3311  * be placed. sx and sy are now the size of the square to search for placement of the head
3312  * relative to ix and iy.
3313  */
3314 
3315  /*
3316  * Loop around the square of possible positions for the head of ob object:
3317  */
3318  for (i = 0; i < (sx+sx+sy+sy); i++) {
3319  if (i <= sx) {
3320  nx = i+ix;
3321  ny = iy;
3322  } else if (i <= sx+sy) {
3323  nx = ix+sx;
3324  ny = iy+i-sx;
3325  } else if (i <= sx+sy+sx) {
3326  nx = ix+sx-(i-(sx+sy));
3327  ny = iy+sy;
3328  } else {
3329  nx = ix;
3330  ny = iy+sy-(i-(sx+sy+sx));
3331  }
3332  /* Check if the spot is free. */
3333  flag = ob_blocked(ob, gen->map, nx, ny);
3334  if (!flag) {
3335  freecount++;
3336  }
3337  }
3338  /* If no free spaces, return. */
3339  if (!freecount)
3340  return -1;
3341 
3342  /* Choose a random valid position */
3343  freecount = RANDOM()%freecount;
3344  for (i = 0; i < sx+sx+sy+sy; i++) {
3345  if (i <= sx) {
3346  nx = i+ix;
3347  ny = iy;
3348  } else if (i <= sx+sy) {
3349  nx = ix+sx;
3350  ny = iy+i-sx;
3351  } else if (i <= sx+sy+sx) {
3352  nx = ix+sx-(i-(sx+sy));
3353  ny = iy+sy;
3354  } else {
3355  nx = ix;
3356  ny = iy+sy-(i-(sx+sy+sx));
3357  }
3358 
3359  /* Make sure it's within map. */
3360  if (nx < 0 || nx >= MAP_WIDTH(gen->map)
3361  || ny < 0 || ny >= MAP_HEIGHT(gen->map))
3362  continue;
3363 
3364  /* Check if the spot is free.*/
3365  flag = ob_blocked(ob, gen->map, nx, ny);
3366  if (!flag) {
3367  freecount--;
3368  if (freecount <= 0) {
3369  *hx = nx;
3370  *hy = ny;
3371  return 0;
3372  }
3373  }
3374  }
3375  return -1;
3376 }
3377 
3397 int object_find_multi_free_spot_within_radius(const object *ob, const object *gen, int *hx, int *hy) {
3398  int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag;
3399  int8_t x, y, radius;
3400  int freecount = 0, freecountstop = 0;
3401  const char *value;
3402  int8_t *x_array;
3403  int8_t *y_array;
3404 
3405  /* If radius is not set, default to 1 */
3406  value = object_get_value(gen, "generator_radius");
3407  if (value) {
3408  radius = (int8_t)strtol(value, NULL, 10);
3409  if (radius < 1) {
3410  radius = 1;
3411  }
3412  } else {
3413  radius = 1;
3414  }
3415 
3416  ob = HEAD(ob);
3417 
3418  object_get_multi_size(ob, &sx, &sy, &sx2, &sy2);
3419  object_get_multi_size(gen, &genx, &geny, &genx2, &geny2);
3420  /*
3421  * sx and sy are now the coords of the bottom right corner
3422  * of ob relative to the head.
3423  * genx and geny are now the coords of the bottom right corner
3424  * of gen relative to the head.
3425  * sx2 and sy2 are now the coords of the head of ob relative
3426  * to the top left corner.
3427  * genx2 and geny2 are now the coords of the head of gen relative
3428  * to the top left corner.
3429  */
3430 
3431  sx++;
3432  sy++;
3433  genx++;
3434  geny++;
3435  /*
3436  * sx, sy, genx, and geny, are now the size of the object,
3437  * excluding parts left and above the head.
3438  */
3439 
3440  ix = gen->x-sx-genx2-radius+1;
3441  iy = gen->y-sy-geny2-radius+1;
3442  sx += genx+sx2+radius*2-1;
3443  sy += geny+sy2+radius*2-1;
3444 
3445  /*
3446  * ix and iy are the map coords of the top left square where
3447  * the head of ob could possibly be placed. sx and sy are now
3448  * the size of the square to search for placement of the head
3449  * relative to ix and iy.
3450  */
3451 
3452  /* Create arrays large enough to hold free space coordinates */
3453  x_array = static_cast<int8_t *>(malloc(sx*sy*sizeof(int8_t)));
3454  y_array = static_cast<int8_t *>(malloc(sx*sy*sizeof(int8_t)));
3455 
3456  /*
3457  * Loop through the area of possible positions for the head of ob object:
3458  */
3459  for (x = 0; x < sx; x++) {
3460  for (y = 0; y < sy; y++) {
3461  nx = ix+x;
3462  ny = iy+y;
3463 
3464 
3465  /* Make sure it's within map. */
3466  if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) {
3467  continue;
3468  }
3469 
3470  /* Check if the spot is free. */
3471  flag = ob_blocked(ob, gen->map, nx, ny);
3472  if (!flag) {
3473  x_array[freecount] = nx;
3474  y_array[freecount] = ny;
3475  freecount++;
3476  }
3477  }
3478  }
3479  /* If no free spaces, return. */
3480  if (!freecount) {
3481  free(x_array);
3482  free(y_array);
3483  return -1;
3484  }
3485 
3486  /* Choose a random valid position */
3487  freecountstop = RANDOM()%freecount;
3488  for (i = 0; i < freecount; i++) {
3489  nx = x_array[i];
3490  ny = y_array[i];
3491 
3492  /* Check if the spot is free.*/
3493  flag = ob_blocked(ob, gen->map, nx, ny);
3494  if (!flag) {
3495  freecountstop--;
3496  if (freecountstop <= 0) {
3497  *hx = nx;
3498  *hy = ny;
3499  free(x_array);
3500  free(y_array);
3501  return 0;
3502  }
3503  }
3504  }
3505  free(x_array);
3506  free(y_array);
3507  return -1;
3508 }
3509 
3544 int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop) {
3545  int i, index = 0, flag;
3546  static int altern[SIZEOFFREE];
3547 
3548  for (i = start; i < stop; i++) {
3549  flag = ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]);
3550  if (!flag)
3551  altern[index++] = i;
3552 
3553  /* Basically, if we find a wall on a space, we cut down the search size.
3554  * In this way, we won't return spaces that are on another side of a wall.
3555  * This mostly work, but it cuts down the search size in all directions -
3556  * if the space being examined only has a wall to the north and empty
3557  * spaces in all the other directions, this will reduce the search space
3558  * to only the spaces immediately surrounding the target area, and
3559  * won't look 2 spaces south of the target space.
3560  */
3561  else if ((flag&AB_NO_PASS) && maxfree[i] < stop)
3562  stop = maxfree[i];
3563  }
3564  if (!index)
3565  return -1;
3566  return altern[RANDOM()%index];
3567 }
3568 
3584 int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y) {
3585  int i;
3586 
3587  for (i = 0; i < SIZEOFFREE; i++) {
3588  if (!ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]))
3589  return i;
3590  }
3591  return -1;
3592 }
3593 
3603 static void permute(int *arr, int begin, int end) {
3604  int i, j, tmp, len;
3605 
3606  len = end-begin;
3607  for (i = begin; i < end; i++) {
3608  j = begin+RANDOM()%len;
3609 
3610  tmp = arr[i];
3611  arr[i] = arr[j];
3612  arr[j] = tmp;
3613  }
3614 }
3615 
3627 void get_search_arr(int *search_arr) {
3628  int i;
3629 
3630  for (i = 0; i < SIZEOFFREE; i++) {
3631  search_arr[i] = i;
3632  }
3633 
3634  permute(search_arr, 1, SIZEOFFREE1+1);
3635  permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1);
3636  permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE);
3637 }
3638 
3646 int object_distance(const object *ob1, const object *ob2) {
3647  int i;
3648 
3649  i = (ob1->x-ob2->x)*(ob1->x-ob2->x)+
3650  (ob1->y-ob2->y)*(ob1->y-ob2->y);
3651  return i;
3652 }
3653 
3662 int find_dir_2(int x, int y) {
3663  int q;
3664 
3665  if (!y)
3666  q = -300*x;
3667  else
3668  q = x*100/y;
3669  if (y > 0) {
3670  if (q < -242)
3671  return 3;
3672  if (q < -41)
3673  return 2;
3674  if (q < 41)
3675  return 1;
3676  if (q < 242)
3677  return 8;
3678  return 7;
3679  }
3680  if (q < -242)
3681  return 7;
3682  if (q < -41)
3683  return 6;
3684  if (q < 41)
3685  return 5;
3686  if (q < 242)
3687  return 4;
3688  return 3;
3689 }
3690 
3699 int absdir(int d) {
3700  // Shortcut for modulus that work becuase we have a power of 2
3701  d &= 7;
3702  // 0 needs to be 8
3703  if (!d)
3704  d = 8;
3705  return d;
3706 }
3707 
3717 int dirdiff(int dir1, int dir2) {
3718  int d;
3719 
3720  d = abs(dir1-dir2);
3721  if (d > 4)
3722  d = 8-d;
3723  return d;
3724 }
3725 
3737 static const int reduction_dir[SIZEOFFREE][3] = {
3738  { 0, 0, 0 }, /* 0 */
3739  { 0, 0, 0 }, /* 1 */
3740  { 0, 0, 0 }, /* 2 */
3741  { 0, 0, 0 }, /* 3 */
3742  { 0, 0, 0 }, /* 4 */
3743  { 0, 0, 0 }, /* 5 */
3744  { 0, 0, 0 }, /* 6 */
3745  { 0, 0, 0 }, /* 7 */
3746  { 0, 0, 0 }, /* 8 */
3747  { 8, 1, 2 }, /* 9 */
3748  { 1, 2, -1 }, /* 10 */
3749  { 2, 10, 12 }, /* 11 */
3750  { 2, 3, -1 }, /* 12 */
3751  { 2, 3, 4 }, /* 13 */
3752  { 3, 4, -1 }, /* 14 */
3753  { 4, 14, 16 }, /* 15 */
3754  { 5, 4, -1 }, /* 16 */
3755  { 4, 5, 6 }, /* 17 */
3756  { 6, 5, -1 }, /* 18 */
3757  { 6, 20, 18 }, /* 19 */
3758  { 7, 6, -1 }, /* 20 */
3759  { 6, 7, 8 }, /* 21 */
3760  { 7, 8, -1 }, /* 22 */
3761  { 8, 22, 24 }, /* 23 */
3762  { 8, 1, -1 }, /* 24 */
3763  { 24, 9, 10 }, /* 25 */
3764  { 9, 10, -1 }, /* 26 */
3765  { 10, 11, -1 }, /* 27 */
3766  { 27, 11, 29 }, /* 28 */
3767  { 11, 12, -1 }, /* 29 */
3768  { 12, 13, -1 }, /* 30 */
3769  { 12, 13, 14 }, /* 31 */
3770  { 13, 14, -1 }, /* 32 */
3771  { 14, 15, -1 }, /* 33 */
3772  { 33, 15, 35 }, /* 34 */
3773  { 16, 15, -1 }, /* 35 */
3774  { 17, 16, -1 }, /* 36 */
3775  { 18, 17, 16 }, /* 37 */
3776  { 18, 17, -1 }, /* 38 */
3777  { 18, 19, -1 }, /* 39 */
3778  { 41, 19, 39 }, /* 40 */
3779  { 19, 20, -1 }, /* 41 */
3780  { 20, 21, -1 }, /* 42 */
3781  { 20, 21, 22 }, /* 43 */
3782  { 21, 22, -1 }, /* 44 */
3783  { 23, 22, -1 }, /* 45 */
3784  { 45, 47, 23 }, /* 46 */
3785  { 23, 24, -1 }, /* 47 */
3786  { 24, 9, -1 } /* 48 */
3787 };
3788 
3807 int can_see_monsterP(mapstruct *m, int x, int y, int dir) {
3808  int16_t dx, dy;
3809  int mflags;
3810 
3811  if (dir < 0)
3812  return 0; /* exit condition: invalid direction */
3813 
3814  dx = x+freearr_x[dir];
3815  dy = y+freearr_y[dir];
3816 
3817  mflags = get_map_flags(m, &m, dx, dy, &dx, &dy);
3818 
3819  /* This functional arguably was incorrect before - it was
3820  * checking for P_WALL - that was basically seeing if
3821  * we could move to the monster - this is being more
3822  * literal on if we can see it. To know if we can actually
3823  * move to the monster, we'd need the monster passed in or
3824  * at least its move type.
3825  */
3826  if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
3827  return 0;
3828 
3829  /* yes, can see. */
3830  if (dir < 9)
3831  return 1;
3832  return can_see_monsterP(m, x, y, reduction_dir[dir][0])|
3833  can_see_monsterP(m, x, y, reduction_dir[dir][1])|
3834  can_see_monsterP(m, x, y, reduction_dir[dir][2]);
3835 }
3836 
3852 int object_can_pick(const object *who, const object *item) {
3853  /* I re-wrote this as a series of if statements
3854  * instead of a nested return (foo & bar && yaz)
3855  * - I think this is much more readable,
3856  * and likely compiler effectively optimizes it the
3857  * same.
3858  */
3859  if (item->weight <= 0)
3860  return 0;
3861  if (QUERY_FLAG(item, FLAG_NO_PICK))
3862  return 0;
3863  if (QUERY_FLAG(item, FLAG_ALIVE))
3864  return 0;
3865  if (item->invisible)
3866  return 0;
3867  if (item->type == TRANSPORT && item->contr != NULL) {
3868  return 0;
3869  }
3870 
3871  /* Weight limit for monsters */
3872  if (who->type != PLAYER && ((uint32_t)(who->weight+who->carrying+item->weight)) > get_weight_limit(who->stats.Str))
3873  return 0;
3874 
3875  /* Can not pick up multipart objects */
3876  if (item->head || item->more)
3877  return 0;
3878 
3879  /* Everything passes, so OK to pick up */
3880  return 1;
3881 }
3882 
3894 object *object_create_clone(object *asrc) {
3895  object *dst = NULL, *tmp, *src, *part, *prev;
3896 
3897  if (!asrc)
3898  return NULL;
3899  src = HEAD(asrc);
3900 
3901  prev = NULL;
3902  for (part = src; part; part = part->more) {
3903  tmp = object_new();
3904  object_copy(part, tmp);
3905  /*
3906  * Need to reset the weight, since object_insert_in_ob() later will
3907  * recompute this field.
3908  */
3909  tmp->carrying = tmp->arch->clone.carrying;
3910  tmp->x -= src->x;
3911  tmp->y -= src->y;
3912  if (!part->head) {
3913  dst = tmp;
3914  tmp->head = NULL;
3915  } else {
3916  tmp->head = dst;
3917  }
3918  tmp->more = NULL;
3919  if (prev)
3920  prev->more = tmp;
3921  prev = tmp;
3922  }
3923  /*** copy inventory ***/
3924  FOR_INV_PREPARE(src, item)
3925  (void)object_insert_in_ob(object_create_clone(item), dst);
3926  FOR_INV_FINISH();
3927 
3928  return dst;
3929 }
3930 
3941 object *object_find_by_name(const object *who, const char *name) {
3942  const char *name_shared = add_string(name);
3943  object *tmp;
3944 
3945  for (tmp = who->inv; tmp; tmp = tmp->below)
3946  if (tmp->name == name_shared)
3947  break;
3948  free_string(name_shared);
3949  return tmp;
3950 }
3951 
3965 object *object_find_by_type(const object *who, int type) {
3966  object *tmp;
3967 
3968  for (tmp = who->inv; tmp; tmp = tmp->below)
3969  if (tmp->type == type)
3970  return tmp;
3971 
3972  return NULL;
3973 }
3974 
3989 object *object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags) {
3990  int flag_okay;
3991  for (object *tmp = who->inv; tmp; tmp = tmp->below)
3992  if (tmp->type == type) {
3993  flag_okay = 1;
3994  for (int i = 0; i < num_flags; ++i) {
3995  if (QUERY_FLAG(tmp, flags[i])) {
3996  flag_okay = 0; // A flag we didn't want set was set. Skip this item.
3997  break;
3998  }
3999  }
4000  if (flag_okay) // If flag_okay == 1, then the flags specified were not set
4001  return tmp; // If we reach here, none of the flags specified were set. Just like we wanted.
4002  }
4003 
4004  return NULL;
4005 }
4006 
4022 object *object_find_by_type2(const object *who, int type1, int type2) {
4023  object *tmp;
4024 
4025  for (tmp = who->inv; tmp; tmp = tmp->below)
4026  if (tmp->type == type1 || tmp->type == type2)
4027  return tmp;
4028 
4029  return NULL;
4030 }
4031 
4045 object *object_find_by_tag(const object *who, tag_t tag) {
4046  object *tmp;
4047 
4048  for (tmp = who->inv; tmp; tmp = tmp->below)
4049  if (tmp->count == tag)
4050  return tmp;
4051 
4052  return NULL;
4053 }
4054 
4068 object *object_find_by_type_applied(const object *who, int type) {
4069  object *tmp;
4070 
4071  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4072  if (tmp->type == type && QUERY_FLAG(tmp, FLAG_APPLIED))
4073  return tmp;
4074 
4075  return NULL;
4076 }
4077 
4093 object *object_find_by_type_and_name(const object *who, int type, const char *name) {
4094  object *tmp;
4095 
4096  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4097  if (tmp->type == type && strcmp(tmp->name, name) == 0)
4098  return tmp;
4099 
4100  return NULL;
4101 }
4102 
4118 object *object_find_by_type_and_race(const object *who, int type, const char *race) {
4119  object *tmp;
4120 
4121  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4122  if (tmp->type == type && strcmp(tmp->race, race) == 0)
4123  return tmp;
4124 
4125  return NULL;
4126 }
4127 
4143 object *object_find_by_type_and_slaying(const object *who, int type, const char *slaying) {
4144  object *tmp;
4145 
4146  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4147  if (tmp->type == type && tmp->slaying != NULL && strcmp(tmp->slaying, slaying) == 0)
4148  return tmp;
4149 
4150  return NULL;
4151 }
4152 
4168 object *object_find_by_type_and_skill(const object *who, int type, const char *skill) {
4169  object *tmp;
4170 
4171  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4172  if (tmp->type == type && tmp->skill != NULL && strcmp(tmp->skill, skill) == 0)
4173  return tmp;
4174 
4175  return NULL;
4176 }
4177 
4191 object *object_find_by_flag(const object *who, int flag) {
4192  object *tmp;
4193 
4194  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4195  if (QUERY_FLAG(tmp, flag))
4196  return tmp;
4197 
4198  return NULL;
4199 }
4200 
4214 object *object_find_by_flag_applied(const object *who, int flag) {
4215  object *tmp;
4216 
4217  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4218  if (QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, flag))
4219  return tmp;
4220 
4221  return NULL;
4222 }
4223 
4237 object *object_find_by_arch_name(const object *who, const char *name) {
4238  object *tmp;
4239 
4240  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4241  if (strcmp(tmp->arch->name, name) == 0)
4242  return tmp;
4243 
4244  return NULL;
4245 }
4246 
4262 object *object_find_by_type_and_arch_name(const object *who, int type, const char *name) {
4263  object *tmp;
4264 
4265  for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
4266  if (tmp->type == type && strcmp(tmp->arch->name, name) == 0)
4267  return tmp;
4268 
4269  return NULL;
4270 }
4271 
4286 object *object_find_by_type_subtype(const object *who, int type, int subtype) {
4287  object *tmp;
4288 
4289  for (tmp = who->inv; tmp; tmp = tmp->below)
4290  if (tmp->type == type && tmp->subtype == subtype)
4291  return tmp;
4292 
4293  return NULL;
4294 }
4295 
4306 key_value *object_get_key_value(const object *ob, const char *key) {
4307  key_value *link;
4308 
4309  for (link = ob->key_values; link != NULL; link = link->next) {
4310  if (link->key == key) {
4311  return link;
4312  }
4313  }
4314 
4315  return NULL;
4316 }
4317 
4331 sstring object_get_value(const object *op, const char *const key) {
4332  key_value *link;
4333  const char *canonical_key;
4334 
4335  canonical_key = find_string(key);
4336 
4337  if (canonical_key == NULL) {
4338  /* 1. There being a field named key on any object
4339  * implies there'd be a shared string to find.
4340  * 2. Since there isn't, no object has this field.
4341  * 3. Therefore, *this *object doesn't have this field.
4342  */
4343  return NULL;
4344  }
4345 
4346  /* This is copied from object_get_key_value() above -
4347  * only 4 lines, and saves the function call overhead.
4348  */
4349  for (link = op->key_values; link != NULL; link = link->next) {
4350  if (link->key == canonical_key) {
4351  return link->value;
4352  }
4353  }
4354  return NULL;
4355 }
4356 
4361 bool object_value_set(const object *op, const char *const key) {
4362  const char *ret = object_get_value(op, key);
4363  if (ret == NULL || (strcmp(ret, "") == 0) || (strcmp(ret, "0") == 0)) {
4364  return false;
4365  }
4366  return true;
4367 }
4368 
4375 bool object_value_set_shared(const object *op, sstring key) {
4376  for (key_value *link = op->key_values; link != NULL; link = link->next) {
4377  if (link->key == key) {
4378  if ((strcmp(link->value, "") == 0) || (strcmp(link->value, "0") == 0)) {
4379  return false;
4380  }
4381  return true;
4382  }
4383  }
4384  return false;
4385 }
4386 
4401 static int object_set_value_s(object *op, sstring canonical_key, const char *value, int add_key) {
4402  key_value *field = NULL, *last = NULL;
4403 
4404  for (field = op->key_values; field != NULL; field = field->next) {
4405  if (field->key != canonical_key) {
4406  last = field;
4407  continue;
4408  }
4409 
4410  if (field->value)
4411  FREE_AND_CLEAR_STR(field->value);
4412  if (value)
4413  field->value = add_string(value);
4414  else {
4415  /* Basically, if the archetype has this key set,
4416  * we need to store the null value so when we save
4417  * it, we save the empty value so that when we load,
4418  * we get this value back again.
4419  */
4420  if (object_get_key_value(&op->arch->clone, canonical_key))
4421  field->value = NULL;
4422  else {
4423  /* Delete this link */
4424  if (field->key)
4425  FREE_AND_CLEAR_STR(field->key);
4426  if (field->value)
4427  FREE_AND_CLEAR_STR(field->value);
4428  if (last)
4429  last->next = field->next;
4430  else
4431  op->key_values = field->next;
4432  free(field);
4433  }
4434  }
4435  return TRUE;
4436  }
4437  /* IF we get here, key doesn't exist */
4438 
4439  /* No field, we'll have to add it. */
4440 
4441  if (!add_key) {
4442  return FALSE;
4443  }
4444  /* There isn't any good reason to store a null
4445  * value in the key/value list. If the archetype has
4446  * this key, then we should also have it, so shouldn't
4447  * be here. If user wants to store empty strings,
4448  * should pass in ""
4449  */
4450  if (value == NULL)
4451  return TRUE;
4452 
4453  field = static_cast<key_value *>(malloc(sizeof(key_value)));
4454 
4455  field->key = add_refcount(canonical_key);
4456  field->value = add_string(value);
4457  /* Usual prepend-addition. */
4458  field->next = op->key_values;
4459  op->key_values = field;
4460 
4461  return TRUE;
4462 }
4463 
4484 int object_set_value(object *op, const char *key, const char *value, int add_key) {
4485  const char *canonical_key = NULL;
4486  int floating_ref = FALSE;
4487  int ret;
4488 
4489  /* HACK This mess is to make sure set_ob_value() passes a shared string
4490  * to object_get_key_value(), without leaving a leaked refcount.
4491  */
4492 
4493  canonical_key = find_string(key);
4494  if (canonical_key == NULL) {
4495  canonical_key = add_string(key);
4496  floating_ref = TRUE;
4497  }
4498 
4499  ret = object_set_value_s(op, canonical_key, value, add_key);
4500 
4501  if (floating_ref) {
4502  free_string(canonical_key);
4503  }
4504 
4505  return ret;
4506 }
4507 
4559 int object_matches_string(object *pl, object *op, const char *name) {
4560  char *cp, local_name[MAX_BUF], name_op[MAX_BUF], name_short[HUGE_BUF], bname_s[MAX_BUF], bname_p[MAX_BUF];
4561  int count, retval = 0;
4562  /* strtok is destructive to name */
4563  safe_strncpy(local_name, name, sizeof(local_name));
4564  sstring custom_name = object_get_value(op, CUSTOM_NAME_FIELD);
4565 
4566  for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) {
4567  while (cp[0] == ' ')
4568  ++cp; /* get rid of spaces */
4569 
4570  /* LOG(llevDebug, "Trying to match %s\n", cp);*/
4571  /* All is a very generic match - low match value */
4572  if (!strcmp(cp, "all"))
4573  return 1;
4574 
4575  /* unpaid is a little more specific */
4576  if (!strcmp(cp, "unpaid") && QUERY_FLAG(op, FLAG_UNPAID))
4577  return 2;
4578  if (!strcmp(cp, "cursed")
4580  && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)))
4581  return 2;
4582 
4583  if (!strcmp(cp, "unlocked") && !QUERY_FLAG(op, FLAG_INV_LOCKED))
4584  return 2;
4585 
4586  /* Allow for things like '100 arrows' */
4587  count = atoi(cp);
4588  if (*cp == '+' || *cp == '-')
4589  count=0; // Let +/- searches look in description for magic bonuses
4590  if (count != 0) {
4591  cp = strchr(cp, ' ');
4592  while (cp && cp[0] == ' ')
4593  ++cp; /* get rid of spaces */
4594  } else {
4595  if (pl->type == PLAYER)
4596  count = pl->contr->count;
4597  else
4598  count = 0;
4599  }
4600 
4601  if (!cp || cp[0] == '\0' || count < 0)
4602  continue;
4603 
4604  /* The code here should go from highest retval to lowest. That
4605  * is because of the 'else' handling - we don't want to match on
4606  * something and set a low retval, even though it may match a higher retcal
4607  * later. So keep it in descending order here, so we try for the best
4608  * match first, and work downward.
4609  */
4610  query_name(op, name_op, MAX_BUF);
4611  query_short_name(op, name_short, HUGE_BUF);
4612  query_base_name(op, 0, bname_s, MAX_BUF);
4613  query_base_name(op, 1, bname_p, MAX_BUF);
4614 
4615  if (!strcasecmp(cp, name_op))
4616  retval = 20;
4617  else if (!strcasecmp(cp, name_short))
4618  retval = 18;
4619  else if (!strcasecmp(cp, bname_s))
4620  retval = 16;
4621  else if (!strcasecmp(cp, bname_p))
4622  retval = 16;
4623  else if (custom_name && !strcasecmp(cp, custom_name))
4624  retval = 15;
4625  else if (!strncasecmp(cp, bname_s, strlen(cp)))
4626  retval = 14;
4627  else if (!strncasecmp(cp, bname_p, strlen(cp)))
4628  retval = 14;
4629  /* Do substring checks, so things like 'Str+1' will match.
4630  * retval of these should perhaps be lower - they are lower
4631  * then the specific strcasecmp aboves, but still higher than
4632  * some other match criteria.
4633  */
4634  else if (strstr(bname_p, cp))
4635  retval = 12;
4636  else if (strstr(bname_s, cp))
4637  retval = 12;
4638  else if (strstr(name_short, cp))
4639  retval = 12;
4640  /* Check against plural/non plural based on count. */
4641  else if (count > 1 && !strcasecmp(cp, op->name_pl)) {
4642  retval = 6;
4643  } else if (count == 1 && !strcasecmp(op->name, cp)) {
4644  retval = 6;
4645  }
4646  /* base name matched - not bad */
4647  else if (strcasecmp(cp, op->name) == 0 && !count)
4648  retval = 4;
4649  /* Check for partial custom name, but give a real low priority */
4650  else if (custom_name && strstr(custom_name, cp))
4651  retval = 3;
4652 
4653  if (retval) {
4654  if (pl->type == PLAYER)
4655  pl->contr->count = count;
4656  return retval;
4657  }
4658  }
4659  return 0;
4660 }
4661 
4670 void object_fix_multipart(object *tmp) {
4671  archetype *at;
4672  object *op, *last;
4673 
4674  if (!tmp->map) {
4675  LOG(llevError, "object_fix_multipart: not on a map!\n");
4676  return;
4677  }
4678 
4679  /* already multipart - don't do anything more */
4680  if (tmp->head || tmp->more)
4681  return;
4682 
4683  /* If there is nothing more to this object, this for loop
4684  * won't do anything.
4685  */
4686  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
4687  op = arch_to_object(at);
4688 
4689  /* update x,y coordinates */
4690  op->x += tmp->x;
4691  op->y += tmp->y;
4692  op->head = tmp;
4693  op->map = tmp->map;
4694  last->more = op;
4695  if (tmp->name != op->name) {
4696  if (op->name)
4697  free_string(op->name);
4698  op->name = add_string(tmp->name);
4699  }
4700  if (tmp->title != op->title) {
4701  if (op->title)
4702  free_string(op->title);
4703  op->title = add_string(tmp->title);
4704  }
4705  /* we could link all the parts onto tmp, and then just
4706  * call object_insert_in_map once, but the effect is the same,
4707  * as object_insert_in_map will call itself with each part, and
4708  * the coding is simpler to just to it here with each part.
4709  */
4711  } /* for at = tmp->arch->more */
4712 }
4713 
4729 void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy) {
4730  archetype *part;
4731  int maxx = 0, maxy = 0, minx = 0, miny = 0;
4732 
4733  ob = HEAD(ob);
4734  *sx = 1;
4735  *sy = 1;
4736  if (ob->arch->more) {
4737  for (part = ob->arch; part; part = part->more) {
4738  if (part->clone.x > maxx)
4739  maxx = part->clone.x;
4740  if (part->clone.y > maxy)
4741  maxy = part->clone.y;
4742  if (part->clone.x < minx)
4743  minx = part->clone.x;
4744  if (part->clone.y < miny)
4745  miny = part->clone.y;
4746  }
4747  }
4748  *sx = maxx;
4749  *sy = maxy;
4750  if (hx)
4751  *hx = -minx;
4752  if (hy)
4753  *hy = -miny;
4754 }
4755 
4776 void object_insert_to_free_spot_or_free(object *op, mapstruct *map, int x, int y, int start, int stop, object *originator) {
4777  int pos;
4778 
4779  pos = object_find_free_spot(op, map, x, y, start, stop);
4780  if (pos == -1) {
4782  return;
4783  }
4784 
4785  object_insert_in_map_at(op, map, originator, 0, x+freearr_x[pos], y+freearr_y[pos]);
4786 }
4787 
4796 void object_set_msg(object *op, const char *msg) {
4797  if (op->msg != NULL) {
4798  free_string(op->msg);
4799  }
4800 
4801  if (msg != NULL) {
4802  // If the message does not have a trailing newline, add one.
4803  if (*msg != '\0' && strchr(msg, '\0')[-1] != '\n') {
4805  stringbuffer_append_string(sb, msg);
4806  stringbuffer_append_string(sb, "\n");
4807  op->msg = stringbuffer_finish_shared(sb);
4808  } else {
4809  op->msg = add_string(msg);
4810  }
4811  } else {
4812  op->msg = NULL;
4813  }
4814 }
4815 
4817 const char *const move_name[] = {
4818  "walk",
4819  "fly_low",
4820  "fly_high",
4821  "swim",
4822  "boat",
4823  NULL
4824 };
4825 
4826 /* This array equates the FLAG_ values with the V_ values. Use -1 to
4827  * put gaps in the array that should not be processed.
4828  * The order matches the order of the define values in 'define.h'.
4829  */
4836 static const char *const flag_names[NUM_FLAGS+1] = {
4837  "alive", "wiz", NULL, NULL, "was_wiz", "applied", "unpaid",
4838  "can_use_shield", "no_pick", "client_anim_sync", "client_anim_random", /* 10 */
4839  "is_animated", NULL /* FLAG_DIALOG_PARSED, not saved */,
4840  NULL /* flying */, "monster", "friendly", "generator",
4841  "is_thrown", "auto_apply", "treasure", "player sold", /* 20 */
4842  "see_invisible", "can_roll", "overlay_floor",
4843  "is_turnable", NULL /* walk_off */, NULL /* fly_on */,
4844  NULL /*fly_off*/, "is_used_up", "identified", "reflecting", /* 30 */
4845  "changing", "splitting", "hitback", "startequip",
4846  "blocksview", "undead", "scared", "unaggressive",
4847  "reflect_missile", "reflect_spell", /* 40 */
4848  "no_magic", "no_fix_player", "is_lightable", "tear_down",
4849  "run_away", NULL /*pass_thru */, NULL /*can_pass_thru*/,
4850  NULL /*"pick_up"*/, "unique", "no_drop", /* 50 */
4851  NULL /* wizcast*/, "can_cast_spell", "can_use_scroll", "can_use_range",
4852  "can_use_bow", "can_use_armour", "can_use_weapon",
4853  "can_use_ring", "has_ready_range", "has_ready_bow", /* 60 */
4854  "xrays", NULL, "is_floor", "lifesave", "no_strength", "sleep",
4855  "stand_still", "random_movement", "only_attack", "confused", /* 70 */
4856  "stealth", NULL, NULL, "cursed", "damned",
4857  "see_anywhere", "known_magical", "known_cursed",
4858  "can_use_skill", "been_applied", /* 80 */
4859  "has_ready_scroll", NULL, NULL,
4860  NULL, "make_invisible", "inv_locked", "is_wooded",
4861  "is_hilly", "has_ready_skill", "has_ready_weapon", /* 90 */
4862  "no_skill_ident", "is_blind", "can_see_in_dark", "is_cauldron",
4863  NULL, "no_steal", "one_hit", NULL, "berserk", "neutral", /* 100 */
4864  "no_attack", "no_damage", NULL, NULL, "activate_on_push",
4865  "activate_on_release", "is_water", "use_content_on_gen", NULL, "is_buildable", /* 110 */
4866  NULL, "blessed", "known_blessed"
4867 };
4868 
4878 {
4879  static char retbuf[MAX_BUF], retbuf_all[MAX_BUF];
4880  int i, all_count = 0, count;
4881 
4882  strcpy(retbuf, "");
4883  strcpy(retbuf_all, " all");
4884 
4885  /* Quick check, and probably fairly common */
4886  if (mt == MOVE_ALL) {
4887  stringbuffer_append_string(sb, "all");
4888  return;
4889  }
4890  if (mt == 0) {
4891  stringbuffer_append_string(sb, "0");
4892  return;
4893  }
4894 
4895  /* We basically slide the bits down. Why look at MOVE_ALL?
4896  * because we may want to return a string like 'all -swim',
4897  * and if we just looked at mt, we couldn't get that.
4898  */
4899  for (i = MOVE_ALL, count = 0; i != 0; i >>= 1, count++) {
4900  if (mt&(1<<count)) {
4901  strcat(retbuf, " ");
4902  strcat(retbuf, move_name[count]);
4903  } else {
4904  strcat(retbuf_all, " -");
4905  strcat(retbuf_all, move_name[count]);
4906  all_count++;
4907  }
4908  }
4909  /* Basically, if there is a single negation, return it, eg
4910  * 'all -swim'. But more than that, just return the
4911  * enumerated values. It doesn't make sense to return
4912  * 'all -walk -fly_low' - it is shorter to return 'fly_high swim'
4913  */
4914  if (all_count <= 1)
4915  stringbuffer_append_string(sb, retbuf_all+1);
4916  else
4917  stringbuffer_append_string(sb, retbuf+1);
4918 }
4919 
4921 static inline void ADD_STRINGLINE_ENTRY(StringBuffer *sb, const char *name, const char *value) {
4923  stringbuffer_append_string(sb, value);
4924  stringbuffer_append_string(sb, "\n");
4925 }
4926 
4928 static inline void FAST_SAVE_LONG(StringBuffer *sb, const char *name, const long value) {
4930  stringbuffer_append_int64(sb, value);
4931  stringbuffer_append_char(sb, '\n');
4932 }
4933 
4935 static inline void FAST_SAVE_DOUBLE(StringBuffer *sb, const char *name, const double value) {
4936  stringbuffer_append_printf(sb, "%s%f\n", name, value);
4937 }
4938 
4946  for (int i = 0; i < 4; i++) {
4947  int idx = ffs((*diff)[i]);
4948  if (idx != 0) {
4949  int bit = idx - 1;
4950  // Clear difference bit.
4951  (*diff)[i] &= ~(1 << bit);
4952  return 32*i + bit;
4953  }
4954  }
4955  return -1;
4956 }
4957 
4971 void get_ob_diff(StringBuffer *sb, const object *op, const object *op2) {
4972  static char buf2[64];
4973  int tmp;
4974  int i;
4975  key_value *my_field;
4976  key_value *arch_field;
4977 
4978  /* This saves the key/value lists. We do it first so that any
4979  * keys that match field names will be overwritten by the loader.
4980  */
4981  for (my_field = op->key_values; my_field != NULL; my_field = my_field->next) {
4982  /* Find the field in the opposing member. */
4983  arch_field = object_get_key_value(op2, my_field->key);
4984 
4985  /* If there's no partnering field, or it's got a different value, save our field. */
4986  if (arch_field == NULL || my_field->value != arch_field->value) {
4987  stringbuffer_append_string(sb, my_field->key);
4988  stringbuffer_append_string(sb, " ");
4989  /* If this is null, then saving it as a space should
4990  * cause it to be null again.
4991  */
4992  if (my_field->value)
4993  stringbuffer_append_string(sb, my_field->value);
4994  stringbuffer_append_string(sb, "\n");
4995  }
4996  }
4997  /* We don't need to worry about the arch's extra fields - they
4998  * will get taken care of the object_copy() function.
4999  */
5000 
5001  if (op->name && op->name != op2->name) {
5002  ADD_STRINGLINE_ENTRY(sb, "name ", op->name);
5003  }
5004  if (op->name_pl && op->name_pl != op2->name_pl) {
5005  ADD_STRINGLINE_ENTRY(sb, "name_pl ", op->name_pl);
5006  }
5007  if (op->anim_suffix && op->anim_suffix != op2->anim_suffix) {
5008  ADD_STRINGLINE_ENTRY(sb, "anim_suffix ", op->anim_suffix);
5009  }
5010  if (op->title && op->title != op2->title) {
5011  ADD_STRINGLINE_ENTRY(sb, "title ", op->title);
5012  }
5013  if (op->race && op->race != op2->race) {
5014  ADD_STRINGLINE_ENTRY(sb, "race ", op->race);
5015  }
5016  if (op->slaying && op->slaying != op2->slaying) {
5017  ADD_STRINGLINE_ENTRY(sb, "slaying ", op->slaying);
5018  }
5019  if (op->skill && op->skill != op2->skill) {
5020  ADD_STRINGLINE_ENTRY(sb, "skill ", op->skill);
5021  }
5022  if (op->msg && op->msg != op2->msg) {
5023  stringbuffer_append_string(sb, "msg\n");
5025  stringbuffer_append_string(sb, "endmsg\n");
5026  }
5027  if (op->lore && op->lore != op2->lore) {
5028  stringbuffer_append_string(sb, "lore\n");
5030  stringbuffer_append_string(sb, "endlore\n");
5031  }
5032  if (op->other_arch != op2->other_arch && op->other_arch != NULL && op->other_arch->name) {
5033  ADD_STRINGLINE_ENTRY(sb, "other_arch ", op->other_arch->name);
5034  }
5035  if (op->face != op2->face) {
5036  ADD_STRINGLINE_ENTRY(sb, "face ", op->face->name);
5037  }
5038 
5039  if (op->animation != op2->animation) {
5040  if (op->animation) {
5041  ADD_STRINGLINE_ENTRY(sb, "animation ", op->animation->name);
5042  if (!QUERY_FLAG (op, FLAG_ANIMATE)) {
5043  stringbuffer_append_string(sb, "is_animated 0\n");
5044  }
5045  } else {
5046  stringbuffer_append_string(sb, "animation NONE\n");
5047  }
5048  }
5049  if (op->stats.Str != op2->stats.Str)
5050  FAST_SAVE_LONG(sb, "Str ", op->stats.Str);
5051  if (op->stats.Dex != op2->stats.Dex)
5052  FAST_SAVE_LONG(sb, "Dex ", op->stats.Dex);
5053  if (op->stats.Con != op2->stats.Con)
5054  FAST_SAVE_LONG(sb, "Con ", op->stats.Con);
5055  if (op->stats.Wis != op2->stats.Wis)
5056  FAST_SAVE_LONG(sb, "Wis ", op->stats.Wis);
5057  if (op->stats.Pow != op2->stats.Pow)
5058  FAST_SAVE_LONG(sb, "Pow ", op->stats.Pow);
5059  if (op->stats.Cha != op2->stats.Cha)
5060  FAST_SAVE_LONG(sb, "Cha ", op->stats.Cha);
5061  if (op->stats.Int != op2->stats.Int)
5062  FAST_SAVE_LONG(sb, "Int ", op->stats.Int);
5063  if (op->stats.hp != op2->stats.hp)
5064  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5065  if (op->stats.maxhp != op2->stats.maxhp)
5066  FAST_SAVE_LONG(sb, "maxhp ", op->stats.maxhp);
5067  if (op->stats.sp != op2->stats.sp)
5068  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5069  if (op->stats.maxsp != op2->stats.maxsp)
5070  FAST_SAVE_LONG(sb, "maxsp ", op->stats.maxsp);
5071  if (op->stats.grace != op2->stats.grace)
5072  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5073  if (op->stats.maxgrace != op2->stats.maxgrace)
5074  FAST_SAVE_LONG(sb, "maxgrace ", op->stats.maxgrace);
5075 
5076  if (op->stats.exp != op2->stats.exp) {
5077  snprintf(buf2, sizeof(buf2), "%" FMT64, op->stats.exp);
5078  ADD_STRINGLINE_ENTRY(sb, "exp ", buf2);
5079  }
5080 
5081  if (op->total_exp != op2->total_exp) {
5082  snprintf(buf2, sizeof(buf2), "%" FMT64, op->total_exp);
5083  ADD_STRINGLINE_ENTRY(sb, "total_exp ", buf2);
5084  }
5085 
5086  if (op->expmul != op2->expmul)
5087  FAST_SAVE_DOUBLE(sb, "expmul ", op->expmul);
5088  if (op->stats.food != op2->stats.food)
5089  FAST_SAVE_LONG(sb, "food ", op->stats.food);
5090  if (op->stats.dam != op2->stats.dam)
5091  FAST_SAVE_LONG(sb, "dam ", op->stats.dam);
5092  if (op->stats.luck != op2->stats.luck)
5093  FAST_SAVE_LONG(sb, "luck ", op->stats.luck);
5094  if (op->stats.wc != op2->stats.wc)
5095  FAST_SAVE_LONG(sb, "wc ", op->stats.wc);
5096  if (op->stats.ac != op2->stats.ac)
5097  FAST_SAVE_LONG(sb, "ac ", op->stats.ac);
5098  if (op->x != op2->x)
5099  FAST_SAVE_LONG(sb, "x ", op->x);
5100  if (op->y != op2->y)
5101  FAST_SAVE_LONG(sb, "y ", op->y);
5102  if (op->elevation != op2->elevation)
5103  FAST_SAVE_LONG(sb, "elevation ", op->elevation);
5104  if (op->speed != op2->speed) {
5105  FAST_SAVE_DOUBLE(sb, "speed ", op->speed);
5106  }
5107  if (op->speed > 0 && op->speed_left != op2->speed_left) {
5108  FAST_SAVE_DOUBLE(sb, "speed_left ", op->speed_left);
5109  }
5110  if (op->weapon_speed != op2->weapon_speed) {
5111  FAST_SAVE_DOUBLE(sb, "weapon_speed ", op->weapon_speed);
5112  }
5113  if (op->weapon_speed > 0 && op->weapon_speed_left != op2->weapon_speed_left) {
5114  FAST_SAVE_DOUBLE(sb, "weapon_speed_left ", op->weapon_speed_left);
5115  }
5116  if (op->move_status != op2->move_status)
5117  FAST_SAVE_LONG(sb, "move_state ", op->move_status);
5118  if (op->attack_movement != op2->attack_movement)
5119  FAST_SAVE_LONG(sb, "attack_movement ", op->attack_movement);
5120  if (op->nrof != op2->nrof)
5121  FAST_SAVE_LONG(sb, "nrof ", op->nrof);
5122  if (op->level != op2->level)
5123  FAST_SAVE_LONG(sb, "level ", op->level);
5124  if (op->direction != op2->direction)
5125  FAST_SAVE_LONG(sb, "direction ", op->direction);
5126  if (op->type != op2->type)
5127  FAST_SAVE_LONG(sb, "type ", op->type);
5128  if (op->subtype != op2->subtype)
5129  FAST_SAVE_LONG(sb, "subtype ", op->subtype);
5130  if (op->attacktype != op2->attacktype)
5131  FAST_SAVE_LONG(sb, "attacktype ", op->attacktype);
5132 
5133  for (tmp = 0; tmp < NROFATTACKS; tmp++) {
5134  if (op->resist[tmp] != op2->resist[tmp]) {
5135  stringbuffer_append_string(sb, "resist_");
5136  FAST_SAVE_LONG(sb, resist_save[tmp], op->resist[tmp]);
5137  }
5138  }
5139 
5140  if (op->path_attuned != op2->path_attuned)
5141  FAST_SAVE_LONG(sb, "path_attuned ", op->path_attuned);
5142  if (op->path_repelled != op2->path_repelled)
5143  FAST_SAVE_LONG(sb, "path_repelled ", op->path_repelled);
5144  if (op->path_denied != op2->path_denied)
5145  FAST_SAVE_LONG(sb, "path_denied ", op->path_denied);
5146  if (op->material != op2->material)
5147  FAST_SAVE_LONG(sb, "material ", op->material);
5148  if (op->materialname && op->materialname != op2->materialname) {
5149  ADD_STRINGLINE_ENTRY(sb, "materialname ", op->materialname);
5150  }
5151  if (op->value != op2->value)
5152  FAST_SAVE_LONG(sb, "value ", op->value);
5153  if (op->carrying != op2->carrying)
5154  FAST_SAVE_LONG(sb, "carrying ", op->carrying);
5155  if (op->weight != op2->weight)
5156  FAST_SAVE_LONG(sb, "weight ", op->weight);
5157  if (op->invisible != op2->invisible)
5158  FAST_SAVE_LONG(sb, "invisible ", op->invisible);
5159  if (op->state != op2->state)
5160  FAST_SAVE_LONG(sb, "state ", op->state);
5161  if (op->magic != op2->magic)
5162  FAST_SAVE_LONG(sb, "magic ", op->magic);
5163  if (op->last_heal != op2->last_heal)
5164  FAST_SAVE_LONG(sb, "last_heal ", op->last_heal);
5165  if (op->last_sp != op2->last_sp)
5166  FAST_SAVE_LONG(sb, "last_sp ", op->last_sp);
5167  if (op->last_grace != op2->last_grace)
5168  FAST_SAVE_LONG(sb, "last_grace ", op->last_grace);
5169  if (op->last_eat != op2->last_eat)
5170  FAST_SAVE_LONG(sb, "last_eat ", op->last_eat);
5171  if (QUERY_FLAG(op, FLAG_IS_LINKED) && (tmp = get_button_value(op)))
5172  FAST_SAVE_LONG(sb, "connected ", tmp);
5173  if (op->glow_radius != op2->glow_radius)
5174  FAST_SAVE_LONG(sb, "glow_radius ", op->glow_radius);
5175  if (op->randomitems != op2->randomitems) {
5176  ADD_STRINGLINE_ENTRY(sb, "randomitems ", op->randomitems ? op->randomitems->name : "none");
5177  }
5178 
5179  if (op->run_away != op2->run_away)
5180  FAST_SAVE_LONG(sb, "run_away ", op->run_away);
5181  if (op->pick_up != op2->pick_up)
5182  FAST_SAVE_LONG(sb, "pick_up ", op->pick_up);
5183  if (op->weight_limit != op2->weight_limit)
5184  FAST_SAVE_LONG(sb, "container ", op->weight_limit);
5185  if (op->will_apply != op2->will_apply)
5186  FAST_SAVE_LONG(sb, "will_apply ", op->will_apply);
5187  if (op->smoothlevel != op2->smoothlevel)
5188  FAST_SAVE_LONG(sb, "smoothlevel ", op->smoothlevel);
5189 
5190  if (op->map_layer != op2->map_layer)
5191  ADD_STRINGLINE_ENTRY(sb, "map_layer ", map_layer_name[op->map_layer]);
5192 
5193  if (op->weapontype && op->weapontype != op2->weapontype) {
5194  FAST_SAVE_LONG(sb, "weapontype ", op->weapontype);
5195  }
5196  if (op->client_type && op->client_type != op2->client_type) {
5197  FAST_SAVE_LONG(sb, "client_type ", op->client_type);
5198  }
5199 
5200  if (op->item_power != op2->item_power) {
5201  FAST_SAVE_LONG(sb, "item_power ", op->item_power);
5202  }
5203 
5204  if (op->duration != op2->duration)
5205  FAST_SAVE_LONG(sb, "duration ", op->duration);
5206 
5207  if (op->range != op2->range)
5208  FAST_SAVE_LONG(sb, "range ", op->range);
5209 
5210  if (op->range_modifier != op2->range_modifier)
5211  FAST_SAVE_LONG(sb, "range_modifier ", op->range_modifier);
5212 
5213  if (op->duration_modifier != op2->duration_modifier)
5214  FAST_SAVE_LONG(sb, "duration_modifier ", op->duration_modifier);
5215 
5216  if (op->dam_modifier != op2->dam_modifier)
5217  FAST_SAVE_LONG(sb, "dam_modifier ", op->dam_modifier);
5218 
5219  if (op->gen_sp_armour != op2->gen_sp_armour) {
5220  FAST_SAVE_LONG(sb, "gen_sp_armour ", op->gen_sp_armour);
5221  }
5222 
5223  /* I've kept the old int move type saving code commented out.
5224  * In an ideal world, we'd know if we want to do a quick
5225  * save (say to a temp map, where we don't care about strings),
5226  * or a slower save/dm dump, where printing out strings is handy.
5227  */
5228  if (op->move_type != op2->move_type) {
5229  /*FAST_SAVE_LONG(sb, "move_type ", op->move_type)*/
5230  stringbuffer_append_string(sb, "move_type ");
5232  stringbuffer_append_string(sb, "\n");
5233  }
5234  if (op->move_block != op2->move_block) {
5235  /*FAST_SAVE_LONG(sb, "move_block ", op->move_block)*/
5236  stringbuffer_append_string(sb, "move_block ");
5238  stringbuffer_append_string(sb, "\n");
5239  }
5240  if (op->move_allow != op2->move_allow) {
5241  /*FAST_SAVE_LONG(sb, "move_allow ", op->move_allow);*/
5242  stringbuffer_append_string(sb, "move_allow ");
5244  stringbuffer_append_string(sb, "\n");
5245  }
5246  if (op->move_on != op2->move_on) {
5247  /*FAST_SAVE_LONG(sb, "move_on ", op->move_on);*/
5248  stringbuffer_append_string(sb, "move_on ");
5249  get_string_move_type(sb, op->move_on);
5250  stringbuffer_append_string(sb, "\n");
5251  }
5252  if (op->move_off != op2->move_off) {
5253  /*FAST_SAVE_LONG(sb, "move_off ", op->move_off);*/
5254  stringbuffer_append_string(sb, "move_off ");
5255  get_string_move_type(sb, op->move_off);
5256  stringbuffer_append_string(sb, "\n");
5257  }
5258  if (op->move_slow != op2->move_slow) {
5259  /*FAST_SAVE_LONG(sb, "move_slow ", op->move_slow);*/
5260  stringbuffer_append_string(sb, "move_slow ");
5262  stringbuffer_append_string(sb, "\n");
5263  }
5264 
5265  if (op->move_slow_penalty != op2->move_slow_penalty) {
5266  FAST_SAVE_DOUBLE(sb, "move_slow_penalty ", op->move_slow_penalty);
5267  }
5268 
5269  // Make sure we save sound_chance overrides, or sound chance only works on the initial map load.
5270  if (op->sound_chance != op2->sound_chance) {
5271  FAST_SAVE_LONG(sb, "sound_chance ", op->sound_chance);
5272  }
5273 
5274  ob_flags diff_flags;
5275  compare_flags(&diff_flags, op, op2);
5276  int flag;
5277  while ((flag = flags_differ(&diff_flags)) != -1) {
5278  if (flag_names[flag]) {
5279  ADD_STRINGLINE_ENTRY(sb, flag_names[flag], QUERY_FLAG(op, flag) ? " 1" : " 0");
5280  }
5281  }
5282 
5283  /* Save body locations */
5284  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
5285  if (op->body_info[i] != op2->body_info[i]) {
5286  stringbuffer_append_string(sb, body_locations[i].save_name);
5287  FAST_SAVE_LONG(sb, " ", op->body_info[i]);
5288  }
5289  }
5290 }
5291 
5296 void save_object_in_sb(StringBuffer *sb, object *op, const int flag) {
5297  /* If the object has no_save set, just return */
5298  if (QUERY_FLAG(op, FLAG_NO_SAVE)) {
5299  return;
5300  }
5301 
5302  /* Even if the object does have an owner, it would seem that we should
5303  * still save it.
5304  */
5305  if (object_get_owner(op) != NULL) {
5306  return;
5307  }
5308 
5309  /* If it is unpaid and we don't want to save those, just return. */
5310  if (!(flag&SAVE_FLAG_SAVE_UNPAID) && (QUERY_FLAG(op, FLAG_UNPAID))) {
5311  return;
5312  }
5313 
5314  archetype *at = op->arch;
5315  if (at == NULL)
5316  at = empty_archetype;
5317 
5318  ADD_STRINGLINE_ENTRY(sb, "arch ", at->name);
5319 
5320  if (at->reference_count > 0) {
5321  /* The object is a custom item/monster, so we handle its save differently.
5322  * We compare the custom archetype to the "original" one, then only save hp/gr/sp
5323  * which are the only values we can't recompute later - all others are modified by items in inventory.
5324  * Note that hp/gr/sp will appear twice in save, but last value will take precedence.
5325  */
5326  archetype *original = find_archetype(at->name);
5327  if (!original) {
5328  LOG(llevError, "could not find original archetype %s for custom monster!\n", at->name);
5329  abort();
5330  }
5331  get_ob_diff(sb, &at->clone, &original->clone);
5332  if (op->stats.hp != at->clone.stats.hp)
5333  FAST_SAVE_LONG(sb, "hp ", op->stats.hp);
5334  if (op->stats.sp != at->clone.stats.sp)
5335  FAST_SAVE_LONG(sb, "sp ", op->stats.sp);
5336  if (op->stats.grace != at->clone.stats.grace)
5337  FAST_SAVE_LONG(sb, "grace ", op->stats.grace);
5338  if (op->x != at->clone.x)
5339  FAST_SAVE_LONG(sb, "x ", op->x);
5340  if (op->y != at->clone.y)
5341  FAST_SAVE_LONG(sb, "y ", op->y);
5342  } else if (op->artifact != NULL) {
5343  /* if op is an artifact, then find the "standard" artifact to use that for the diff */
5344  object *base;
5345  const artifact *artifact;
5346 
5347  artifact = find_artifact(op, op->artifact);
5348  if (artifact == NULL) {
5349  LOG(llevError, "could not find artifact %s [%d] to save data\n", op->artifact, op->type);
5350  get_ob_diff(sb, op, &at->clone);
5351  } else {
5352  ADD_STRINGLINE_ENTRY(sb, "artifact ", op->artifact);
5353  base = arch_to_object(at);
5355  get_ob_diff(sb, op, base);
5357  }
5358  } else {
5359  get_ob_diff(sb, op, &at->clone);
5360  }
5361 
5362  /* Eneq(@csd.uu.se): Added this to allow containers being saved with contents*/
5363  FOR_INV_PREPARE(op, tmp)
5364  save_object_in_sb(sb, tmp, flag);
5365  FOR_INV_FINISH();
5366 
5367  stringbuffer_append_string(sb, "end\n");
5368 }
5369 
5382 int save_object(FILE *fp, object *op, int flag) {
5384  save_object_in_sb(sb, op, flag);
5385  char *cp = stringbuffer_finish(sb);
5386  if (fputs(cp, fp) == EOF) {
5387  free(cp);
5388  return SAVE_ERROR_WRITE;
5389  } else {
5390  free(cp);
5391  return SAVE_ERROR_OK;
5392  }
5393 }
5394 
5396  if (op->map) {
5397  sstring death_animation = object_get_value(op, "death_animation");
5398  if (death_animation != NULL && strcmp(death_animation, "NONE")) {
5399  object *death = create_archetype(death_animation);
5400 
5401  if (death != NULL) {
5402  object_insert_in_map_at(death, op->map, op, 0, op->x, op->y);
5403  if (death->arch->more)
5404  object_fix_multipart(death);
5405  }
5406  }
5407  }
5408 }
5409 
5410 object *find_force(object *op, const char *name) {
5411  assert(op != NULL);
5413 }
5414 
5415 object *add_force(object *op, const char *name, int duration) {
5416  assert(op != NULL);
5417  object *force = find_force(op, name);
5418  if (force == NULL) {
5419  force = create_archetype(FORCE_NAME);
5420  force->slaying = add_string(name);
5421  object_insert_in_ob(force, op);
5422  }
5423 
5424  if (duration != 0) {
5425  force->speed = 0.01;
5426  force->speed_left = -duration;
5427  } else {
5428  force->speed = 0;
5429  }
5430 
5431  // Even if duration is zero, a force could be set previously.
5432  object_update_speed(force);
5433 
5434  return force;
5435 }
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:271
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
free_objects
static object * free_objects
Pointer to the list of unused objects.
Definition: object.cpp:295
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:323
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:170
player::do_los
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:141
init_objects
void init_objects(void)
Sets up and initialises the linked list of free and used objects.
Definition: object.cpp:327
living::exp
int64_t exp
Experience.
Definition: living.h:47
UP_OBJ_FACE
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
object::weapon_speed_left
float weapon_speed_left
How much speed is left to spend this round.
Definition: object.h:340
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:609
object_get_owner
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:789
player::next
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:106
FREE_AND_CLEAR_STR_IF
#define FREE_AND_CLEAR_STR_IF(xyz)
Definition: global.h:202
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:545
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:4286
object_clear_owner
void object_clear_owner(object *op)
Clears the owner of specified object.
Definition: object.cpp:808
first_player
player * first_player
First player.
Definition: init.cpp:106
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
object::range_modifier
uint8_t range_modifier
How going up in level affects range
Definition: object.h:418
object::move_status
int32_t move_status
What stage in attack mode.
Definition: object.h:400
object_get_env_recursive
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.cpp:575
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Don't call check_walk_on against the originator.
Definition: object.h:582
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:1317
UP_OBJ_REMOVE
#define UP_OBJ_REMOVE
Object was removed.
Definition: object.h:531
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
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:387
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
object_count_active
int object_count_active(void)
Objects statistics.
Definition: object.cpp:1768
object_find_by_type_applied
object * object_find_by_type_applied(const object *who, int type)
Find applied object in inventory.
Definition: object.cpp:4068
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Number of body locations.
Definition: object.h:15
MAP_SAVING
#define MAP_SAVING
Map being saved.
Definition: map.h:129
object::weapontype
uint32_t weapontype
Type of weapon.
Definition: object.h:381
object::map_layer
uint8_t map_layer
What level to draw this on the map.
Definition: object.h:434
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:589
GET_MAP_TOP
#define GET_MAP_TOP(M, X, Y)
Gets the top object on a map.
Definition: map.h:172
statistics
struct Statistics statistics
Merged spell statistics.
Definition: init.cpp:229
llevError
@ llevError
Error, serious thing.
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:3224
FABS
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
FLAG_CLIENT_ANIM_RANDOM
#define FLAG_CLIENT_ANIM_RANDOM
Client animate this, randomized.
Definition: define.h:241
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:375
MOVE_ALL
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:398
object::path_attuned
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
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:4921
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Object is an overlay floor.
Definition: define.h:255
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
archetype::more
archetype * more
Next part of a linked object.
Definition: object.h:486
player
One player.
Definition: player.h:105
object::client_type
uint16_t client_type
Public type information.
Definition: object.h:350
object_free_all_data
void object_free_all_data(void)
Destroys all allocated objects.
Definition: object.cpp:752
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:268
Statistics::spell_merges
uint64_t spell_merges
Number of spell merges done.
Definition: global.h:354
SIZEOFFREE1
#define SIZEOFFREE1
Definition: define.h:153
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
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:3103
FLAG_IS_TURNABLE
#define FLAG_IS_TURNABLE
Object can change face with direction.
Definition: define.h:256
object::ownercount
tag_t ownercount
What count the owner had (in case owner has been freed)
Definition: object.h:390
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:2036
STARTMAX
#define STARTMAX
How big array of objects to start with.
Definition: config.h:523
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.cpp:138
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:2148
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:177
object::item_power
int8_t item_power
Power rating of the object.
Definition: object.h:372
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:57
mapstruct::players
int16_t players
How many players are on this level right now.
Definition: map.h:334
object::attack_movement
uint16_t attack_movement
What kind of attack movement.
Definition: object.h:401
absdir
int absdir(int d)
Computes an absolute direction.
Definition: object.cpp:3699
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:4836
object::range
int8_t range
Range of the spell.
Definition: object.h:417
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:337
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.cpp:900
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:4776
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
living::Dex
int8_t Dex
Definition: living.h:36
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
NEVER SET THIS.
Definition: define.h:357
TRAP
@ TRAP
Definition: object.h:246
object::x
int16_t x
Definition: object.h:335
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:177
object_dump_all
void object_dump_all(void)
Dumps all objects to console.
Definition: object.cpp:689
player::transport
object * transport
Transport the player is in.
Definition: player.h:214
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
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:371
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
object::anim_suffix
sstring anim_suffix
Used to determine combined animations.
Definition: object.h:324
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:3584
MoveType
unsigned char MoveType
Typdef here to define type large enough to hold bitmask of all movement types.
Definition: define.h:417
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:3207
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:825
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:407
object_handle_death_animation
void object_handle_death_animation(object *op)
Definition: object.cpp:5395
artifact::item
object * item
Special values of the artifact.
Definition: artifact.h:15
CALLOC
#define CALLOC(x, y)
Definition: compat.h:31
NUM_FLAGS
#define NUM_FLAGS
Should always be equal to the last defined flag.
Definition: define.h:374
GET_MAP_MOVE_SLOW
#define GET_MAP_MOVE_SLOW(M, X, Y)
Gets the slowing state of a square.
Definition: map.h:197
object_reset
void object_reset(object *op)
Totally resets the specified object, without freeing associated memory.
Definition: object.cpp:919
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:344
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:307
object::last_grace
int16_t last_grace
As last_sp, except for grace.
Definition: object.h:369
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:1177
object::smoothlevel
uint8_t smoothlevel
how to smooth this square around
Definition: object.h:433
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:4214
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:3397
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:4168
GET_MAP_PLAYER
#define GET_MAP_PLAYER(M, X, Y)
Definition: map.h:166
FLAG_NO_MAGIC
#define FLAG_NO_MAGIC
Spells (some) can't pass this object.
Definition: define.h:276
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
P_NO_MAGIC
#define P_NO_MAGIC
Spells (some) can't pass this object.
Definition: map.h:227
llevMonster
@ llevMonster
Many many details.
Definition: logger.h:14
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:4945
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:147
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:681
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:1193
object::enemy
object * enemy
Monster/player to follow even if not closest.
Definition: object.h:391
object::key_values
key_value * key_values
Fields not explictly known by the loader.
Definition: object.h:444
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
stringbuffer_append_char
void stringbuffer_append_char(StringBuffer *sb, const char c)
Append a character to a string buffer instance.
Definition: stringbuffer.cpp:104
FLAG_BLOCKSVIEW
#define FLAG_BLOCKSVIEW
Object blocks view.
Definition: define.h:269
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:325
MAP_DARKNESS
#define MAP_DARKNESS(m)
Map darkness level (0-MAX_DARKNESS)
Definition: map.h:70
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:329
FOR_OB_AND_ABOVE_FINISH
#define FOR_OB_AND_ABOVE_FINISH()
Finishes FOR_OB_AND_ABOVE_PREPARE().
Definition: define.h:737
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:712
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:355
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
Statistics::spell_hash_full
uint64_t spell_hash_full
Number of times spell hash was full.
Definition: global.h:355
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
expand_objects
static void expand_objects(void)
Allocates more objects for the list of unused objects.
Definition: object.cpp:1216
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:2114
active_objects
object * active_objects
List of active objects that need to be processed.
Definition: object.cpp:296
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:2842
object::will_apply
uint8_t will_apply
See crossfire.doc and What monsters apply.
Definition: object.h:402
object::above
object * above
Pointer to the object stacked above this one.
Definition: object.h:296
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:4935
stringbuffer_append_int64
void stringbuffer_append_int64(StringBuffer *sb, int64_t x)
Append a signed integer to a string buffer instance.
Definition: stringbuffer.cpp:111
AB_NO_PASS
#define AB_NO_PASS
Definition: map.h:235
MAX
#define MAX(x, y)
Definition: compat.h:24
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:111
SAVE_ERROR_WRITE
#define SAVE_ERROR_WRITE
Write error.
Definition: map.h:142
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:239
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
FLAG_DIALOG_PARSED
#define FLAG_DIALOG_PARSED
Was the object::msg field parsed? Temporary flag not saved.
Definition: define.h:243
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:302
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
object::path_denied
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:355
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:968
esrv_send_item
void esrv_send_item(object *pl, object *op)
Sends item's info to player.
Definition: main.cpp:354
socket_struct::update_look
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:108
INS_ABOVE_FLOOR_ONLY
#define INS_ABOVE_FLOOR_ONLY
Put object immediatly above the floor.
Definition: object.h:581
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:733
FLAG_IS_A_TEMPLATE
#define FLAG_IS_A_TEMPLATE
Object has no ingame life until instantiated.
Definition: define.h:366
object::carrying
int32_t carrying
How much weight this object contains.
Definition: object.h:377
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:521
stringbuffer.h
object::path_repelled
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:354
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
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:4118
m
static event_registration m
Definition: citylife.cpp:424
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:126
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.cpp:76
OBJ_EXPAND
#define OBJ_EXPAND
How big steps to use when expanding array.
Definition: config.h:524
get_button_value
int get_button_value(const object *button)
Returns the first value linked to this button.
Definition: button.cpp:749
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:1545
object_update
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1419
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
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:625
object_find_by_name
object * object_find_by_name(const object *who, const char *name)
Finds an object in inventory name.
Definition: object.cpp:3941
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:4306
object::last_heal
int32_t last_heal
Last healed.
Definition: object.h:367
object_find_by_type2
object * object_find_by_type2(const object *who, int type1, int type2)
Find object in inventory.
Definition: object.cpp:4022
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:234
add_refcount
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.cpp:210
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:4375
freearr_y
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
key_value::next
key_value * next
Next key in the list.
Definition: object.h:45
P_NO_ERROR
#define P_NO_ERROR
Purely temporary - if set, update_position does not complain if the flags are different.
Definition: map.h:240
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:3188
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
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:3130
object::weapon_speed
float weapon_speed
The overall speed of this object.
Definition: object.h:339
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:3807
MOVE_WALK
#define MOVE_WALK
Object walks.
Definition: define.h:392
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:320
object::prev
object * prev
Pointer to the previous object in the free/used list.
Definition: object.h:286
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:85
FOR_ABOVE_FINISH
#define FOR_ABOVE_FINISH()
Finishes FOR_ABOVE_PREPARE().
Definition: define.h:688
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
object::run_away
uint8_t run_away
Monster runs away if it's hp goes below this percentage.
Definition: object.h:394
object_dump
void object_dump(const object *op, StringBuffer *sb)
Dumps an object.
Definition: object.cpp:630
object::ox
int16_t ox
Definition: object.h:336
object::weight_limit
int32_t weight_limit
Weight-limit of object.
Definition: object.h:376
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
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
object_count_free
int object_count_free(void)
Objects statistics.
Definition: object.cpp:1736
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:748
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:4729
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
CONTAINER
@ CONTAINER
Definition: object.h:236
object::below
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
object::casting_time
int16_t casting_time
Time left before spell goes off.
Definition: object.h:414
object::move_type
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
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:4093
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
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
object::event_bitmask
uint64_t event_bitmask
Bitmask of events this object has a handler for, see events.h.
Definition: object.h:447
object::face
const Face * face
Face with colors.
Definition: object.h:341
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:2324
find_string
sstring find_string(const char *str)
Searches a string in the shared strings.
Definition: shstr.cpp:236
object::last_eat
int32_t last_eat
How long since we last ate.
Definition: object.h:366
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
object_update_speed
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.cpp:1334
FLAG_IS_WOODED
#define FLAG_IS_WOODED
Item is wooded terrain.
Definition: define.h:330
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
INS_NO_MERGE
#define INS_NO_MERGE
Don't try to merge with other items.
Definition: object.h:580
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:317
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:358
SET_MAP_FLAGS
#define SET_MAP_FLAGS(M, X, Y, C)
Sets map flags.
Definition: map.h:159
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:291
object::materialname
sstring materialname
Specific material name.
Definition: object.h:356
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:4045
FLAG_WIZPASS
#define FLAG_WIZPASS
The wizard can go through walls.
Definition: define.h:314
object_find_by_flag
object * object_find_by_flag(const object *who, int flag)
Find object in inventory by flag.
Definition: object.cpp:4191
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:1577
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:192
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:584
object::move_on
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:439
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
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:483
P_PLAYER
#define P_PLAYER
There is a player on this space.
Definition: map.h:236
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:4559
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:3281
sproto.h
FLAG_NO_DROP
#define FLAG_NO_DROP
Object can't be dropped.
Definition: define.h:288
FLAG_NO_SAVE
#define FLAG_NO_SAVE
If set (through plugins), the object is not saved on maps.
Definition: define.h:244
living::sp
int16_t sp
Spell points.
Definition: living.h:42
nrofallocobjects
int nrofallocobjects
How many OBs allocated (free + used)
Definition: object.cpp:291
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.cpp:95
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:2352
FLAG_NO_STEAL
#define FLAG_NO_STEAL
Item can't be stolen.
Definition: define.h:342
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:744
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:403
object::race
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
compare_flags
static void compare_flags(ob_flags *ret, const object *p, const object *q)
Definition: object.h:499
object::animation
const Animations * animation
Animation of this item, NULL if not animated.
Definition: object.h:428
GET_MAP_MOVE_ON
#define GET_MAP_MOVE_ON(M, X, Y)
Gets the move_on state of a square.
Definition: map.h:202
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:546
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:489
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:3989
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:3737
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:2085
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:425
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:47
object_create_clone
object * object_create_clone(object *asrc)
Create clone from object to another.
Definition: object.cpp:3894
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:1046
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
MAP_WIDTH
#define MAP_WIDTH(m)
Map width.
Definition: map.h:73
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:249
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
INS_ON_TOP
#define INS_ON_TOP
Always put object on top.
Definition: object.h:583
move_name
const char *const move_name[]
Maps the MOVE_* values to names.
Definition: object.cpp:4817
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:3259
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:1258
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:2346
esrv_del_item
void esrv_del_item(player *pl, object *ob)
Tells the client to delete an item.
Definition: main.cpp:381
UP_OBJ_INSERT
#define UP_OBJ_INSERT
Object was inserted.
Definition: object.h:530
object::head
object * head
Points to the main object of a large body.
Definition: object.h:304
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:3153
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:375
nroffreeobjects
int nroffreeobjects
How many OBs allocated and free (free)
Definition: object.cpp:290
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:280
object::move_slow
MoveType move_slow
Movement types this slows down.
Definition: object.h:441
object::spell_tags
tag_t * spell_tags
Tags used for spell effect merging.
Definition: object.h:446
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:442
RANDOM
#define RANDOM()
Definition: define.h:638
StringBuffer
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.cpp:25
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:200
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:393
living::maxgrace
int16_t maxgrace
Maximum grace.
Definition: living.h:45
FLAG_CLIENT_ANIM_SYNC
#define FLAG_CLIENT_ANIM_SYNC
Let client animate this, synchronized.
Definition: define.h:240
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:717
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:217
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:3627
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:3662
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:2818
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
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
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:2661
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:4143
INS_MAP_LOAD
#define INS_MAP_LOAD
Disable lots of checkings.
Definition: object.h:585
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:332
object::dam_modifier
uint8_t dam_modifier
How going up in level affects damage.
Definition: object.h:419
SK_WOODSMAN
@ SK_WOODSMAN
Woodsman.
Definition: skills.h:40
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:327
object::glow_radius
int8_t glow_radius
indicates the glow radius of the object
Definition: object.h:374
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:246
object::duration_modifier
uint8_t duration_modifier
how level modifies duration
Definition: object.h:416
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
SPELL_MAPPINGS
#define SPELL_MAPPINGS
Definition: global.h:154
object_count_used
int object_count_used(void)
Object statistics.
Definition: object.cpp:1752
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Free the pointer and then set it to NULL.
Definition: global.h:195
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:4237
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:3852
SCRIPT_FIX_NOTHING
#define SCRIPT_FIX_NOTHING
Definition: global.h:381
objarray
static object objarray[STARTMAX]
All objects, allocated this way at first.
Definition: object.cpp:289
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:300
object::artifact
sstring artifact
If set, the item is the artifact with this name and the matching type.
Definition: object.h:322
object_find_by_type
object * object_find_by_type(const object *who, int type)
Find object in inventory.
Definition: object.cpp:3965
living::maxsp
int16_t maxsp
Max spell points.
Definition: living.h:43
P_NEED_UPDATE
#define P_NEED_UPDATE
This space is out of date.
Definition: map.h:239
mapstruct
This is a game-map.
Definition: map.h:315
object_find_by_name_global
object * object_find_by_name_global(const char *str)
Finds an object by name.
Definition: object.cpp:732
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:301
compare_ob_value_lists
static int compare_ob_value_lists(const object *, const object *)
Compares two object lists.
Definition: object.cpp:404
object::last_sp
int32_t last_sp
As last_heal, but for spell points.
Definition: object.h:368
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
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:4877
object::gen_sp_armour
int8_t gen_sp_armour
Sp regen penalty this object has (was last_heal)
Definition: object.h:373
permute
static void permute(int *, int, int)
Randomly permutes an array.
Definition: object.cpp:3603
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
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:266
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:2622
key_value::value
sstring value
Key's value.
Definition: object.h:44
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:3544
mapstruct::in_memory
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:335
object_set_msg
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.cpp:4796
object::attacked_by_count
tag_t attacked_by_count
The tag of attacker, so we can be sure.
Definition: object.h:393
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:220
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
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:74
objects
object * objects
Pointer to the list of used objects.
Definition: object.cpp:294
archetype::reference_count
int reference_count
How many times this temporary archetype is used.
Definition: object.h:490
FLAG_NO_FIX_PLAYER
#define FLAG_NO_FIX_PLAYER
fix_object() won't be called
Definition: define.h:277
object_unset_flag_inv
void object_unset_flag_inv(object *op, int flag)
Desactivate recursively a flag on an object inventory.
Definition: object.cpp:3241
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:939
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
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:5415
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
SET_MAP_OB
#define SET_MAP_OB(M, X, Y, tmp)
Sets the bottom object on a map.
Definition: map.h:175
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:75
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:5296
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:4971
object::attacked_by
object * attacked_by
This object start to attack us! only player & monster.
Definition: object.h:392
object::duration
int16_t duration
Number of moves (see 'speed') spell lasts.
Definition: object.h:415
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:1377
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:4262
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
player::count
uint32_t count
Any numbers typed before a command.
Definition: player.h:122
find_insert_pos
static object * find_insert_pos(object *op, const int flag)
Definition: object.cpp:2282
strcasecmp
int strcasecmp(const char *s1, const char *s2)
object::flags
ob_flags flags
Various flags.
Definition: object.h:427
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:3646
find_force
object * find_force(object *op, const char *name)
Find a force with the given 'name' in the slaying field.
Definition: object.cpp:5410
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:633
object::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Body info as loaded from the file.
Definition: object.h:382
FLAG_ANIMATE
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:242
SAVE_ERROR_OK
#define SAVE_ERROR_OK
No error.
Definition: map.h:139
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:4670
object::randomitems
struct treasurelist * randomitems
Items to be generated.
Definition: object.h:395
object::elevation
int elevation
Definition: object.h:450
GET_MAP_MOVE_OFF
#define GET_MAP_MOVE_OFF(M, X, Y)
Gets the move_off state of a square.
Definition: map.h:207
object::container
object * container
Current container being used.
Definition: object.h:299
FLAG_IS_HILLY
#define FLAG_IS_HILLY
Item is hilly/mountain terrain.
Definition: define.h:332
skill
skill
Definition: arch-handbook.txt:585
MOVE_FLY_HIGH
#define MOVE_FLY_HIGH
High flying object.
Definition: define.h:394
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:287
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:1818
UP_OBJ_CHANGE
#define UP_OBJ_CHANGE
Object changed.
Definition: object.h:532
GET_MAP_FLAGS
#define GET_MAP_FLAGS(M, X, Y)
Gets map flags.
Definition: map.h:157
object::move_off
MoveType move_off
Move types affected moving off this space.
Definition: object.h:440
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:553
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
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:317
P_NO_CLERIC
#define P_NO_CLERIC
No clerical spells cast here.
Definition: map.h:238
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:2997
FREE_OBJ_FREE_INVENTORY
#define FREE_OBJ_FREE_INVENTORY
Free inventory objects; if not set, drop inventory.
Definition: object.h:544
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:359
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:878
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
SCROLL
@ SCROLL
Definition: object.h:226
FLAG_IS_LINKED
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:315
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:107
object_increase_nrof
static void object_increase_nrof(object *op, uint32_t i)
Increase the count of an object.
Definition: object.cpp:2748
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:695
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
object::move_allow
MoveType move_allow
What movement types explicitly allowed.
Definition: object.h:438
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:4484
object::more
object * more
Pointer to the rest of a large body of objects.
Definition: object.h:303
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
object::total_exp
int64_t total_exp
All exp ever earned (used to calc perm_exp)
Definition: object.h:379
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:1792
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:363
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:352
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:316
maxfree
int maxfree[SIZEOFFREE]
Number of spots around a location, including that location (except for 0)
Definition: object.cpp:311
SAVE_FLAG_SAVE_UNPAID
#define SAVE_FLAG_SAVE_UNPAID
If set, unpaid items will be saved.
Definition: map.h:106
save_object
int save_object(FILE *fp, object *op, int flag)
Dumps all variables in an object to a file.
Definition: object.cpp:5382
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:592
dirdiff
int dirdiff(int dir1, int dir2)
Computes a direction difference.
Definition: object.cpp:3717
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:357
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:1553
object::move_block
MoveType move_block
What movement types this blocks.
Definition: object.h:437
object::next
object * next
Pointer to the next object in the free/used list.
Definition: object.h:285
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:664
FLAG_NO_APPLY
#define FLAG_NO_APPLY
Avoids step_on/fly_on to this object.
Definition: define.h:301
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:336
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:2582
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:433
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
P_BLOCKSVIEW
#define P_BLOCKSVIEW
This spot blocks the player's view.
Definition: map.h:226
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:4928
living::Con
int8_t Con
Definition: living.h:36
living::Str
int8_t Str
Definition: living.h:36