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