Atrinik Server  4.0
object.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
30 #include <global.h>
31 #include <loader.h>
32 #include <toolkit/string.h>
33 #include <monster_data.h>
34 #include <plugin.h>
35 #include <arch.h>
36 #include <object.h>
37 #include <player.h>
38 #include <object_methods.h>
39 #include <door.h>
40 
43 
47 const char *gender_noun[GENDER_MAX] = {
48  "neuter", "male", "female", "hermaphrodite"
49 };
53 const char *gender_subjective[GENDER_MAX] = {
54  "it", "he", "she", "it"
55 };
60  "It", "He", "She", "It"
61 };
65 const char *gender_objective[GENDER_MAX] = {
66  "it", "him", "her", "it"
67 };
71 const char *gender_possessive[GENDER_MAX] = {
72  "its", "his", "her", "its"
73 };
77 const char *gender_reflexive[GENDER_MAX] = {
78  "itself", "himself", "herself", "itself"
79 };
80 
85  /* Same tile */
86  0,
87  /* One square away */
88  0, 1, 1, 1, 0, -1, -1, -1,
89  /* Two squares away */
90  0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1,
91  /* Three squares away */
92  0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3,
93  -3, -3, -3, -3, -3, -2, -1,
94 };
95 
100  /* Same tile */
101  0,
102  /* One square away */
103  -1, -1, 0, 1, 1, 1, 0, -1,
104  /* Two squares away */
105  -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2,
106  /* Three squares away */
107  -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3,
108  2, 1, 0, -1, -2, -3, -3, -3,
109 };
110 
115  /* Same tile */
116  0,
117  /* One square away */
118  9, 10, 13, 14, 17, 18, 21, 22,
119  /* Two squares away */
120  25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45, 48,
121  /* Three squares away */
122  49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
123  49, 49, 49, 49, 49, 49, 49, 49,
124 };
125 
130  /* Same tile */
131  0,
132  /* One square away */
133  1, 2, 3, 4, 5, 6, 7, 8,
134  /* Two squares away */
135  1, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8,
136  /* Three squares away */
137  1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8,
138 };
139 
143 static mempool_struct *pool_object;
144 
153 const char *object_flag_names[NUM_FLAGS + 1] = {
154  "sleep", "confused", NULL, "scared", "is_blind",
155  "is_invisible", "is_ethereal", "is_good", "no_pick", "walk_on",
156  "no_pass", "is_animated", "slow_move", "flying", "monster",
157  "friendly", NULL, "been_applied", "auto_apply", NULL,
158  "is_neutral", "see_invisible", "can_roll", "connect_reset", "is_turnable",
159  "walk_off", "fly_on", "fly_off", "is_used_up", "identified",
160  "reflecting", "changing", "splitting", "hitback", "startequip",
161  "blocksview", "undead", "can_stack", "unaggressive", "reflect_missile",
162  "reflect_spell", "no_magic", "no_fix_player", "is_evil", "soulbound",
163  "run_away", "pass_thru", "can_pass_thru", "outdoor", "unique",
164  "no_drop", "is_indestructible", "can_cast_spell", NULL, "two_handed",
165  "can_use_bow", "can_use_armour", "can_use_weapon", "connect_no_push",
166  "connect_no_release", "has_ready_bow", "xrays", NULL, "is_floor",
167  "lifesave", "is_magical", NULL, "stand_still", "random_move", "only_attack",
168  NULL, "stealth", NULL, NULL, "cursed",
169  "damned", "is_buildable", "no_pvp", NULL, NULL,
170  "is_thrown", NULL, NULL, "is_male", "is_female",
171  "applied", "inv_locked", NULL, NULL, NULL,
172  "has_ready_weapon", "no_skill_ident", NULL, "can_see_in_dark", "is_cauldron",
173  "is_dust", NULL, "one_hit", "draw_double_always", "berserk",
174  "no_attack", "invulnerable", "quest_item", "is_trapped", NULL,
175  NULL, NULL, NULL, NULL, NULL,
176  "sys_object", "use_fix_pos", "unpaid", "hidden", "make_invisible",
177  "make_ethereal", "is_player", "is_named", NULL, "no_teleport",
178  "corpse", "corpse_forced", "player_only", NULL, "one_drop",
179  "cursed_perm", "damned_perm", "door_closed", "is_spell", "is_missile",
180  "draw_direction", "draw_double", "is_assassin", NULL, "no_save",
181  NULL
182 };
183 
185 static void
186 object_debugger (object *op, char *buf, size_t size)
187 {
188  snprintf(buf, size, "count: %d", op->count);
189 
190  if (op->name != NULL) {
192  char *name = object_get_name_s(op, NULL);
193  snprintfcat(buf, size, " name: %s", name);
194  efree(name);
195  }
196 
197  snprintfcat(buf, size, " coords: %d, %d", op->x, op->y);
198 }
199 
201 static bool
202 object_validator (object *op)
203 {
204  return op->count != 0 && !QUERY_FLAG(op, FLAG_REMOVED);
205 }
206 
210 void
212 {
213  pool_object = mempool_create("objects",
215  sizeof(object),
216  MEMPOOL_ALLOW_FREEING,
217  NULL,
218  NULL,
219  NULL,
220  NULL);
221  mempool_set_debugger(pool_object, (chunk_debugger) object_debugger);
222  mempool_set_validator(pool_object, (chunk_validator) object_validator);
223 }
224 
228 void
230 {
231 }
232 
244 static inline bool
245 object_can_merge_key_values_one (const object *op, const object *cmp)
246 {
247  HARD_ASSERT(op != NULL);
248  HARD_ASSERT(cmp != NULL);
249 
250  /* For each field in wants. */
251  for (key_value_t *op_field = op->key_values;
252  op_field != NULL;
253  op_field = op_field->next) {
254  key_value_t *cmp_field = object_get_key_link(cmp, op_field->key);
255  if (cmp_field == NULL) {
256  return false;
257  }
258 
259  /* Found the matching field. */
260  if (cmp_field->value != op_field->value) {
261  return false;
262  }
263  }
264 
265  return true;
266 }
267 
278 static inline bool
279 object_can_merge_key_values (const object *ob1, const object *ob2)
280 {
281  HARD_ASSERT(ob1 != NULL);
282  HARD_ASSERT(ob2 != NULL);
283 
284  return (object_can_merge_key_values_one(ob1, ob2) &&
286 }
287 
298 bool
299 object_can_merge (object *ob1, object *ob2)
300 {
301  HARD_ASSERT(ob1 != NULL);
302  HARD_ASSERT(ob2 != NULL);
303 
304  if (!QUERY_FLAG(ob1, FLAG_CAN_STACK) && ob1->type != EVENT_OBJECT) {
305  return false;
306  }
307 
308  if (ob1 == ob2) {
309  return false;
310  }
311 
312  /* Do not merge objects if nrof would overflow. We use INT32_MAX
313  * because int32_t is often used to store nrof instead of uint32_t. */
314  if (ob1->nrof + ob2->nrof > INT32_MAX) {
315  return false;
316  }
317 
318  /* Do not merge objects with different layer/sub-layer. */
319  if (ob1->layer != ob2->layer || ob1->sub_layer != ob2->sub_layer) {
320  return false;
321  }
322 
323  /* Do not allow merging objects if either has nrof of 0 and it's
324  * not an event object (those normally have nrof of 0 but they are
325  * allowed to merge). */
326  if ((ob1->nrof == 0 || ob2->nrof == 0) && ob1->type != EVENT_OBJECT) {
327  return false;
328  }
329 
330  /* Do not ever merge objects with glow radius, since more objects with
331  * the same glow_radius actually generate more light than one object. */
332  if (ob1->glow_radius || ob2->glow_radius) {
333  return false;
334  }
335 
336  /* Do not merge arrows with different owners. */
337  if (ob1->type == ARROW && ob2->type == ARROW &&
338  ob1->attacked_by_count != 0 && ob2->attacked_by_count != 0 &&
339  ob1->attacked_by_count != ob2->attacked_by_count) {
340  return false;
341  }
342 
343  /* Check attributes that cannot ever merge if they're different. */
344  if (ob1->arch != ob2->arch ||
345  ob1->item_condition != ob2->item_condition ||
346  ob1->item_level != ob2->item_level ||
347  ob1->item_power != ob2->item_power ||
348  ob1->item_quality != ob2->item_quality ||
349  ob1->item_race != ob2->item_race ||
350  ob1->item_skill != ob2->item_skill ||
351  ob1->last_grace != ob2->last_grace ||
352  ob1->level != ob2->level ||
353  ob1->magic != ob2->magic ||
354  ob1->material != ob2->material ||
355  ob1->material_real != ob2->material_real ||
356  ob1->other_arch != ob2->other_arch ||
357  ob1->path_attuned != ob2->path_attuned ||
358  ob1->path_denied != ob2->path_denied ||
359  ob1->path_repelled != ob2->path_repelled ||
360  ob1->randomitems != ob2->randomitems ||
361  ob1->sub_type != ob2->sub_type ||
362  ob1->terrain_flag != ob2->terrain_flag ||
363  ob1->terrain_type != ob2->terrain_type ||
364  ob1->type != ob2->type ||
365  ob1->value != ob2->value ||
366  ob1->weight != ob2->weight) {
367  return false;
368  }
369 
370  if (!DBL_EQUAL(ob1->speed, ob2->speed) ||
371  !DBL_EQUAL(ob1->weapon_speed, ob2->weapon_speed)) {
372  return false;
373  }
374 
375  /* If the inventory consists only of event objects, and the event objects
376  * are the same, allow merging. */
377  if (ob1->inv != NULL || ob2->inv != NULL) {
378  if (ob1->inv == NULL || ob2->inv == NULL) {
379  return false;
380  }
381 
382  /* Check that all inv objects are event objects */
383  object *tmp1, *tmp2;
384  for (tmp1 = ob1->inv, tmp2 = ob2->inv;
385  tmp1 != NULL && tmp2 != NULL;
386  tmp1 = tmp1->below, tmp2 = tmp2->below) {
387  if (tmp1->type != EVENT_OBJECT || tmp2->type != EVENT_OBJECT) {
388  return false;
389  }
390  }
391 
392  if (tmp1 != NULL || tmp2 != NULL) {
393  /* Different number of event objects. */
394  return false;
395  }
396 
397  for (tmp1 = ob1->inv; tmp1 != NULL; tmp1 = tmp1->below) {
398  for (tmp2 = ob2->inv; tmp2 != NULL; tmp2 = tmp2->below) {
399  if (object_can_merge(tmp1, tmp2)) {
400  break;
401  }
402  }
403 
404  /* Couldn't find something to merge event from ob1 with? */
405  if (tmp2 == NULL) {
406  return false;
407  }
408  }
409  }
410 
411  /* Check the shared strings of both objects. */
412  if (ob1->name != ob2->name ||
413  ob1->title != ob2->title ||
414  ob1->race != ob2->race ||
415  ob1->slaying != ob2->slaying ||
416  ob1->msg != ob2->msg ||
417  ob1->artifact != ob2->artifact ||
418  ob1->custom_name != ob2->custom_name ||
419  ob1->glow != ob2->glow) {
420  return false;
421  }
422 
423  /* Compare arrays and structures the object has (stats, protections, etc) */
424  if (memcmp(&ob1->stats, &ob2->stats, sizeof(living)) != 0 ||
425  memcmp(&ob1->attack, &ob2->attack, sizeof(ob1->attack)) != 0 ||
426  memcmp(&ob1->protection,
427  &ob2->protection,
428  sizeof(ob1->protection)) != 0) {
429  return false;
430  }
431 
432  /* Ignore REMOVED and BEEN_APPLIED */
433  if ((ob1->flags[0] | FLAG_BITMASK(FLAG_REMOVED) |
435  (ob2->flags[0] | FLAG_BITMASK(FLAG_REMOVED) |
437  (ob1->flags[1]) != (ob2->flags[1]) ||
438  (ob1->flags[2] | FLAG_BITMASK(FLAG_APPLIED)) !=
439  (ob2->flags[2] | FLAG_BITMASK(FLAG_APPLIED)) ||
440  (ob1->flags[3]) != (ob2->flags[3])) {
441  return false;
442  }
443 
444  /* Compare face and animation IDs. */
445  if (ob1->face != ob2->face ||
446  ob1->inv_face != ob2->inv_face ||
447  ob1->animation_id != ob2->animation_id ||
448  ob1->inv_animation_id != ob2->inv_animation_id) {
449  return false;
450  }
451 
452  /* Avoid merging empty containers. */
453  if (ob1->type == CONTAINER) {
454  return false;
455  }
456 
457  /* At least one of these has key_values. */
458  if (ob1->key_values != NULL || ob2->key_values != NULL) {
459  /* One has fields, but the other one doesn't. */
460  if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
461  return false;
462  }
463 
464  return object_can_merge_key_values(ob1, ob2);
465  }
466 
467  return true;
468 }
469 
478 object *
479 object_merge (object *op)
480 {
481  HARD_ASSERT(op != NULL);
482 
483  if (op->nrof == 0 || !QUERY_FLAG(op, FLAG_CAN_STACK)) {
484  return op;
485  }
486 
487  object *tmp;
488  if (op->map != NULL) {
489  tmp = GET_MAP_OB_LAST(op->map, op->x, op->y);
490  } else if (op->env != NULL) {
491  tmp = op->env->inv;
492  } else {
493  return op;
494  }
495 
496  for ( ; tmp != NULL; tmp = tmp->below) {
497  if (tmp != op && object_can_merge(op, tmp)) {
498  tmp->nrof += op->nrof;
500  esrv_update_item(UPD_NROF, tmp);
501 
503  object_destroy(op);
504  return tmp;
505  }
506  }
507 
508  return op;
509 }
510 
522 uint32_t
523 object_weight_sum (object *op)
524 {
525  HARD_ASSERT(op != NULL);
526 
527  if (QUERY_FLAG(op, FLAG_SYS_OBJECT)) {
528  return 0;
529  }
530 
531  uint32_t sum = 0;
532  for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) {
533  if (QUERY_FLAG(tmp, FLAG_SYS_OBJECT)) {
534  continue;
535  }
536 
537  if (tmp->inv != NULL) {
538  object_weight_sum(tmp);
539  }
540 
541  sum += WEIGHT_NROF(tmp, tmp->nrof);
542  }
543 
544  if (op->type == CONTAINER && !DBL_EQUAL(op->weapon_speed, 1.0)) {
545  /* We'll store the calculated value in damage_round_tag, so
546  * we can use that as 'cache' for unmodified carrying weight.
547  * This allows us to reliably calculate the weight again in
548  * object_weight_add() and object_weight_sub() without
549  * rounding errors. */
550  op->damage_round_tag = sum;
551  sum = sum * op->weapon_speed;
552  }
553 
554  op->carrying = sum;
555  return sum;
556 }
557 
567 void
568 object_weight_add (object *op, uint32_t weight)
569 {
570  HARD_ASSERT(op != NULL);
571 
572  while (op != NULL) {
573  if (op->type == CONTAINER && !DBL_EQUAL(op->weapon_speed, 1.0)) {
574  uint32_t old_carrying = op->carrying;
575  op->damage_round_tag += weight;
576  op->carrying = op->damage_round_tag * op->weapon_speed;
577  weight = op->carrying - old_carrying;
578  } else {
579  op->carrying += weight;
580  }
581 
582  if (op->env != NULL && op->env->type == PLAYER) {
583  esrv_update_item(UPD_WEIGHT, op);
584  }
585 
586  op = op->env;
587  }
588 }
589 
599 void
600 object_weight_sub (object *op, uint32_t weight)
601 {
602  HARD_ASSERT(op != NULL);
603 
604  while (op != NULL) {
605  if (op->type == CONTAINER && !DBL_EQUAL(op->weapon_speed, 1.0)) {
606  uint32_t old_carrying = op->carrying;
607  op->damage_round_tag -= weight;
608  op->carrying = op->damage_round_tag * op->weapon_speed;
609  weight = old_carrying - op->carrying;
610  } else {
611  op->carrying -= weight;
612  }
613 
614  if (op->env != NULL && op->env->type == PLAYER) {
615  esrv_update_item(UPD_WEIGHT, op);
616  }
617 
618  op = op->env;
619  }
620 }
621 
630 object *
631 object_get_env (object *op)
632 {
633  HARD_ASSERT(op != NULL);
634 
635  while (op->env != NULL) {
636  op = op->env;
637  }
638 
639  return op;
640 }
641 
654 bool
655 object_is_in_inventory (const object *op, const object *inv)
656 {
657  HARD_ASSERT(op != NULL);
658  HARD_ASSERT(inv != NULL);
659 
660  do {
661  if (op->env == inv) {
662  return true;
663  }
664 
665  op = op->env;
666  } while (op != NULL);
667 
668  return false;
669 }
670 
679 void
680 object_dump (const object *op, StringBuffer *sb)
681 {
682  HARD_ASSERT(sb != NULL);
683 
684  if (op == NULL) {
685  stringbuffer_append_string(sb, "[NULL pointer]");
686  return;
687  }
688 
689  if (op->arch != NULL) {
690  stringbuffer_append_printf(sb, "arch %s\n",
691  op->arch->name != NULL ? op->arch->name :
692  "(null)");
693  get_ob_diff(sb, op, &arches[ARCH_EMPTY_ARCHETYPE]->clone);
694  stringbuffer_append_string(sb, "end\n");
695  } else {
696  stringbuffer_append_string(sb, "Object ");
697  stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name);
698  stringbuffer_append_string(sb, "\nend\n");
699  }
700 }
701 
710 void
711 object_dump_rec (const object *op, StringBuffer *sb)
712 {
713  HARD_ASSERT(op != NULL);
714  HARD_ASSERT(sb != NULL);
715 
716  /* Get the difference from the object's archetype. */
717  archetype_t *at = op->arch;
718  if (at == NULL) {
719  /* No archetype, use empty archetype. */
721  }
722 
723  stringbuffer_append_printf(sb, "arch %s\n", at->name);
724  get_ob_diff(sb, op, &at->clone);
725 
726  /* Recursively dump the inventory. */
727  for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) {
728  object_dump_rec(tmp, sb);
729  }
730 
731  stringbuffer_append_string(sb, "end\n");
732 }
733 
740 void
741 object_owner_clear (object *op)
742 {
743  HARD_ASSERT(op != NULL);
744  op->owner = NULL;
745  op->ownercount = 0;
746 }
747 
757 static void
758 object_owner_set_internal (object *op, object *owner)
759 {
760  HARD_ASSERT(op != NULL);
761  HARD_ASSERT(owner != NULL);
762 
763  while (owner->owner != NULL &&
764  owner != owner->owner &&
765  owner->ownercount == owner->owner->count) {
766  owner = owner->owner;
767  }
768 
769  /* If the owner still has an owner, we did not resolve to a final owner,
770  * so lets not add to that. */
771  if (owner->owner != NULL) {
772  return;
773  }
774 
775  op->owner = owner;
776  op->ownercount = owner->count;
777 }
778 
787 void
788 object_owner_set (object *op, object *owner)
789 {
790  HARD_ASSERT(op != NULL);
791 
792  if (unlikely(owner == NULL)) {
793  log_error("Called with NULL owner, object: %s", object_get_str(op));
794  return;
795  }
796 
797  /* Ensure we have a head. */
798  owner = HEAD(owner);
799  object_owner_set_internal(op, owner);
800 
801  if (owner->type == PLAYER) {
802  op->chosen_skill = owner->chosen_skill;
803  }
804 }
805 
823 void
824 object_owner_copy (object *op, object *src)
825 {
826  HARD_ASSERT(op != NULL);
827  HARD_ASSERT(src != NULL);
828 
829  object *owner = object_owner(src);
830  if (owner == NULL) {
831  /* Players don't have owners - they own themselves. Update
832  * as appropriate. */
833  if (src->type == PLAYER) {
834  owner = src;
835  } else {
836  return;
837  }
838  }
839 
840  object_owner_set_internal(op, owner);
841  op->chosen_skill = src->chosen_skill;
842 }
843 
856 object *
857 object_owner (object *op)
858 {
859  HARD_ASSERT(op != NULL);
860 
861  if (op->owner == NULL) {
862  return NULL;
863  }
864 
865  if (OBJECT_FREE(op) || op->owner->count != op->ownercount) {
866  op->owner = NULL;
867  return NULL;
868  }
869 
870  return op->owner;
871 }
872 
885 void
886 object_copy (object *op, const object *src, bool no_speed)
887 {
888  HARD_ASSERT(op != NULL);
889  HARD_ASSERT(src != NULL);
890 
891  bool is_removed = QUERY_FLAG(op, FLAG_REMOVED);
892 
893  FREE_ONLY_HASH(op->name);
894  FREE_ONLY_HASH(op->title);
895  FREE_ONLY_HASH(op->race);
896  FREE_ONLY_HASH(op->slaying);
897  FREE_ONLY_HASH(op->msg);
900  FREE_ONLY_HASH(op->glow);
901 
903 
904  memcpy((char *) op + offsetof(object, name),
905  (const char *) src + offsetof(object, name),
906  sizeof(object) - offsetof(object, name));
907 
908  if (is_removed) {
909  SET_FLAG(op, FLAG_REMOVED);
910  }
911 
920 
921  /* Only alter speed_left when we are sure that we have not done it before */
922  if (!no_speed && op->speed < 0.0 &&
923  DBL_EQUAL(op->speed_left, op->arch->clone.speed_left)) {
924  op->speed_left += rndm(0, 90) / 100.0f;
925  }
926 
927  /* Copy over key_values, if any. */
928  if (src->key_values != NULL) {
929  op->key_values = NULL;
930 
931  for (key_value_t *link = src->key_values, *tail = NULL;
932  link != NULL;
933  link = link->next) {
934  key_value_t *new_link = emalloc(sizeof(*new_link));
935 
936  new_link->next = NULL;
937  new_link->key = add_refcount(link->key);
938 
939  if (link->value != NULL) {
940  new_link->value = add_refcount(link->value);
941  } else {
942  new_link->value = NULL;
943  }
944 
945  /* Link it up. */
946  if (op->key_values == NULL) {
947  op->key_values = new_link;
948  tail = new_link;
949  } else {
950  tail->next = new_link;
951  tail = new_link;
952  }
953  }
954  }
955 
956  if (!no_speed) {
958  }
959 }
960 
969 void
970 object_copy_full (object *op, const object *src)
971 {
972  HARD_ASSERT(op != NULL);
973  HARD_ASSERT(src != NULL);
974 
975  object_copy(op, src, false);
976 
977  for (object *tmp = src->inv; tmp != NULL; tmp = tmp->below) {
978  object *clone = object_get();
979  object_copy_full(clone, tmp);
980  object_insert_into(clone, op, 0);
981  }
982 }
983 
992 object *
994 {
995 
996  object *new_obj = mempool_get(pool_object);
997  SET_FLAG(new_obj, FLAG_REMOVED);
998 
999  static New_Face *blank_face = NULL;
1000  if (blank_face == NULL) {
1001  blank_face = &new_faces[find_face(BLANK_FACE_NAME, 0)];
1002  }
1003  new_obj->face = blank_face;
1004 
1005  static tag_t count = 0;
1006  /* Give the object a new (unique) count tag. */
1007  new_obj->count = ++count;
1008 
1009  return new_obj;
1010 }
1011 
1020 void
1022 {
1023  HARD_ASSERT(op != NULL);
1024 
1025  if (!QUERY_FLAG(op, FLAG_IS_TURNABLE)) {
1026  return;
1027  }
1028 
1029  SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction);
1031 }
1032 
1042 void
1044 {
1045  HARD_ASSERT(op != NULL);
1046 
1047  if (OBJECT_FREE(op) && DBL_EQUAL(op->speed, 0.0)) {
1048  LOG(ERROR, "Object %s is freed but has speed.", object_get_str(op));
1049  op->speed = 0.0;
1050  }
1051 
1052  /* No reason putting the archetypes objects on the speed list,
1053  * since they never really need to be updated. */
1054  if (arch_in_init) {
1055  return;
1056  }
1057 
1058  /* These are special case objects - they have speed set, but should not be
1059  * put on the active list. */
1060  if (op->type == SPAWN_POINT_MOB) {
1061  return;
1062  }
1063 
1064  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
1065  /* If already on active list, don't do anything */
1066  if (op->active_next || op->active_prev || op == active_objects) {
1067  return;
1068  }
1069 
1070  /* process_events() expects us to insert the object at the beginning
1071  * of the list. */
1073 
1074  if (op->active_next != NULL) {
1075  op->active_next->active_prev = op;
1076  }
1077 
1078  active_objects = op;
1079  op->active_prev = NULL;
1080  } else {
1081  /* If not on the active list, nothing needs to be done. */
1082  if (op->active_next == NULL &&
1083  op->active_prev == NULL &&
1084  op != active_objects) {
1085  return;
1086  }
1087 
1088  if (op->active_prev == NULL) {
1089  active_objects = op->active_next;
1090 
1091  if (op->active_next != NULL) {
1092  op->active_next->active_prev = NULL;
1093  }
1094  } else {
1095  op->active_prev->active_next = op->active_next;
1096 
1097  if (op->active_next != NULL) {
1098  op->active_next->active_prev = op->active_prev;
1099  }
1100  }
1101 
1102  op->active_next = NULL;
1103  op->active_prev = NULL;
1104  }
1105 }
1106 
1116 void
1117 object_update (object *op, int action)
1118 {
1119  HARD_ASSERT(op != NULL);
1120 
1121  if (op->env != NULL ||
1122  op->map == NULL ||
1123  op->map->in_memory == MAP_SAVING) {
1124  return;
1125  }
1126 
1127  /* No need to change anything except the map update counter. */
1128  if (action == UP_OBJ_FACE) {
1129  INC_MAP_UPDATE_COUNTER(op->map, op->x, op->y);
1130  return;
1131  }
1132 
1133  MapSpace *msp = GET_MAP_SPACE_PTR(op->map, op->x, op->y);
1134  int newflags = msp->flags;
1135  int flags = newflags;
1136 
1137  if (action == UP_OBJ_INSERT) {
1138  msp->update_tile++;
1139 
1140  if (op->glow_radius != 0) {
1141  adjust_light_source(op->map, op->x, op->y, op->glow_radius);
1142  }
1143 
1144  if (QUERY_FLAG(op, FLAG_NO_PASS) ||
1145  QUERY_FLAG(op, FLAG_PASS_THRU) ||
1147  newflags |= P_NEED_UPDATE;
1148  } else if (QUERY_FLAG(op, FLAG_IS_FLOOR)) {
1149  /* Floors define our node - force an update. */
1150  newflags |= P_NEED_UPDATE;
1151  msp->light_value += op->last_sp;
1152  } else {
1153  if (op->type == CHECK_INV) {
1154  newflags |= P_CHECK_INV;
1155  }
1156 
1157  if (QUERY_FLAG(op, FLAG_MONSTER)) {
1158  newflags |= P_IS_MONSTER;
1159  }
1160 
1161  if (QUERY_FLAG(op, FLAG_IS_PLAYER)) {
1162  newflags |= P_IS_PLAYER;
1163  }
1164 
1165  if (QUERY_FLAG(op, FLAG_PLAYER_ONLY)) {
1166  newflags |= P_PLAYER_ONLY;
1167  }
1168 
1169  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW)) {
1170  newflags |= P_BLOCKSVIEW;
1171  }
1172 
1173  if (QUERY_FLAG(op, FLAG_NO_MAGIC)) {
1174  newflags |= P_NO_MAGIC;
1175  }
1176 
1177  if (QUERY_FLAG(op, FLAG_WALK_ON)) {
1178  newflags |= P_WALK_ON;
1179  }
1180 
1181  if (QUERY_FLAG(op, FLAG_FLY_ON)) {
1182  newflags |= P_FLY_ON;
1183  }
1184 
1185  if (QUERY_FLAG(op, FLAG_WALK_OFF)) {
1186  newflags |= P_WALK_OFF;
1187  }
1188 
1189  if (QUERY_FLAG(op, FLAG_FLY_OFF)) {
1190  newflags |= P_FLY_OFF;
1191  }
1192 
1193  if (QUERY_FLAG(op, FLAG_DOOR_CLOSED)) {
1194  newflags |= P_DOOR_CLOSED;
1195  }
1196 
1197  if (QUERY_FLAG(op, FLAG_NO_PVP)) {
1198  newflags |= P_NO_PVP;
1199  }
1200 
1201  if (op->type == MAGIC_MIRROR) {
1202  newflags |= P_MAGIC_MIRROR;
1203  }
1204 
1205  if (op->type == EXIT) {
1206  newflags |= P_IS_EXIT;
1207  }
1208 
1209  if (QUERY_FLAG(op, FLAG_OUTDOOR)) {
1210  newflags |= P_OUTDOOR;
1211  }
1212  }
1213  } else if (action == UP_OBJ_REMOVE) {
1214  msp->update_tile++;
1215 
1216  if (op->glow_radius != 0) {
1217  adjust_light_source(op->map, op->x, op->y, -op->glow_radius);
1218  }
1219 
1220  /* We must rebuild the flags when one of these flags is touched from our
1221  * object */
1222  if (QUERY_FLAG(op, FLAG_MONSTER) ||
1223  QUERY_FLAG(op, FLAG_IS_PLAYER) ||
1224  QUERY_FLAG(op, FLAG_BLOCKSVIEW) ||
1226  QUERY_FLAG(op, FLAG_PASS_THRU) ||
1227  QUERY_FLAG(op, FLAG_NO_PASS) ||
1229  QUERY_FLAG(op, FLAG_NO_MAGIC) ||
1230  QUERY_FLAG(op, FLAG_WALK_ON) ||
1231  QUERY_FLAG(op, FLAG_FLY_ON) ||
1232  QUERY_FLAG(op, FLAG_WALK_OFF) ||
1233  QUERY_FLAG(op, FLAG_FLY_OFF) ||
1234  QUERY_FLAG(op, FLAG_IS_FLOOR) ||
1235  QUERY_FLAG(op, FLAG_OUTDOOR) ||
1236  QUERY_FLAG(op, FLAG_NO_PVP) ||
1237  op->type == CHECK_INV ||
1238  op->type == MAGIC_MIRROR ||
1239  op->type == EXIT) {
1240  newflags |= P_NEED_UPDATE;
1241  }
1242  } else if (action == UP_OBJ_FLAGS) {
1243  /* Force flags rebuild but no tile counter. */
1244  newflags |= P_NEED_UPDATE;
1245  } else if (action == UP_OBJ_FLAGFACE) {
1246  /* Force flags rebuild */
1247  newflags |= P_NEED_UPDATE;
1248  msp->update_tile++;
1249  } else if (action == UP_OBJ_ALL) {
1250  /* Force full tile update */
1251  newflags |= P_NEED_UPDATE;
1252  msp->update_tile++;
1253  } else {
1254  return;
1255  }
1256 
1257  if (flags != newflags) {
1258  /* Rebuild flags */
1259  if (newflags & P_NEED_UPDATE) {
1260  msp->flags |= newflags;
1261  update_position(op->map, op->x, op->y);
1262  } else {
1263  msp->flags |= newflags;
1264  }
1265  }
1266 
1267  if (op->more != NULL && action != UP_OBJ_INSERT) {
1268  object_update(op->more, action);
1269  }
1270 }
1271 
1281 void
1283 {
1284  HARD_ASSERT(op != NULL);
1285 
1286  if (op->type == PLAYER) {
1287  return;
1288  }
1289 
1290  if (op->env == NULL &&
1291  (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY)) {
1292  return;
1293  }
1294 
1295  object *enemy;
1296  if (op->enemy != NULL && op->enemy->type == PLAYER) {
1297  enemy = op->enemy;
1298  } else {
1299  enemy = object_owner(op->enemy);
1300  }
1301 
1302  object *corpse = NULL;
1303  /* Create race corpse and/or drop stuff to floor. */
1304  if ((QUERY_FLAG(op, FLAG_CORPSE) && !QUERY_FLAG(op, FLAG_STARTEQUIP)) ||
1306  ob_race *race_corpse = race_find(op->race);
1307  if (race_corpse != NULL) {
1308  corpse = arch_to_object(race_corpse->corpse);
1309  corpse->x = op->x;
1310  corpse->y = op->y;
1311  corpse->map = op->map;
1312  corpse->weight = op->weight;
1313  }
1314  }
1315 
1316  FOR_INV_PREPARE(op, tmp) {
1317  object_remove(tmp, 0);
1318 
1319  if (tmp->type == QUEST_CONTAINER) {
1320  if (enemy != NULL && enemy->type == PLAYER &&
1321  enemy->count == op->enemy_count) {
1322  quest_handle(enemy, tmp);
1323  }
1324 
1325  object_destroy(tmp);
1326  continue;
1327  }
1328 
1329  if ((QUERY_FLAG(op, FLAG_STARTEQUIP) &&
1330  !(tmp->type == ARROW && tmp->attacked_by_count != 0)) ||
1331  (tmp->type != RUNE && (QUERY_FLAG(tmp, FLAG_SYS_OBJECT) ||
1332  QUERY_FLAG(tmp, FLAG_STARTEQUIP) ||
1333  QUERY_FLAG(tmp, FLAG_NO_DROP)))) {
1334  object_destroy(tmp);
1335  continue;
1336  }
1337 
1338  tmp->x = op->x;
1339  tmp->y = op->y;
1340 
1341  /* Always clear these in case the monster used the item */
1342  CLEAR_FLAG(tmp, FLAG_APPLIED);
1344 
1345  /* If we have a corpse put the item in it. */
1346  if (corpse != NULL &&
1347  !(tmp->type == ARROW && tmp->attacked_by_count != 0 &&
1348  enemy != NULL && OBJECT_VALID(tmp->attacked_by,
1349  tmp->attacked_by_count) &&
1350  tmp->attacked_by_count != enemy->count &&
1351  !(tmp->attacked_by->type == PLAYER &&
1352  enemy->type == PLAYER &&
1353  CONTR(tmp->attacked_by)->party != NULL &&
1354  CONTR(tmp->attacked_by)->party == CONTR(enemy)->party))) {
1355  object_insert_into(tmp, corpse, 0);
1356  } else if (tmp->type != RUNE) {
1357  if (op->env != NULL) {
1358  object_insert_into(tmp, op->env, 0);
1359  } else {
1360  object_insert_map(tmp, op->map, NULL, 0);
1361  }
1362  } else {
1363  object_destroy(tmp);
1364  }
1365  } FOR_INV_FINISH();
1366 
1367  /* Drop the corpse. */
1368  if (corpse != NULL) {
1369  if (enemy != NULL && enemy->type == PLAYER) {
1370  if (enemy->count == op->enemy_count) {
1371  FREE_AND_ADD_REF_HASH(corpse->slaying, enemy->name);
1372  }
1373  } else if (QUERY_FLAG(op, FLAG_CORPSE_FORCED)) {
1374  corpse->stats.food = 5;
1375  }
1376 
1377  /* Change sub_type to mark this corpse. */
1378  if (corpse->slaying != NULL) {
1379  if (CONTR(enemy)->party != NULL &&
1380  CONTR(enemy)->party->loot != PARTY_LOOT_OWNER) {
1382  CONTR(enemy)->party->name);
1384  } else {
1386  }
1387  }
1388 
1389  /* Store the original food value. */
1390  corpse->last_eat = corpse->stats.food;
1391  corpse->sub_layer = op->sub_layer;
1392 
1393  if (op->env != NULL) {
1394  corpse = object_insert_into(corpse, op->env, 0);
1395  } else {
1396  corpse = object_insert_map(corpse, op->map, NULL, 0);
1397  }
1398 
1399  SOFT_ASSERT(corpse != NULL,
1400  "Failed to insert corpse for %s",
1401  object_get_str(op));
1402  object_reverse_inventory(corpse);
1403  }
1404 }
1405 
1413 void
1415 {
1416  HARD_ASSERT(op != NULL);
1417 
1419 
1420  FOR_INV_PREPARE(op, tmp) {
1421  if (tmp->inv != NULL) {
1422  object_destroy_inv(tmp);
1423  }
1424 
1425  object_remove(tmp, 0);
1426  object_destroy(tmp);
1427  } FOR_INV_FINISH();
1428 
1430 }
1431 
1440 void
1441 object_destroy (object *op)
1442 {
1443  HARD_ASSERT(op != NULL);
1444 
1445  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
1446  char buf[HUGE_BUF];
1447 
1448  object_debugger(op, VS(buf));
1449  LOG(ERROR, "Freeing an object that was not removed: %s", buf);
1450  return;
1451  }
1452 
1453  if (op->more != NULL) {
1454  object_destroy(op->more);
1455  }
1456 
1458 
1459  if (QUERY_FLAG(op, FLAG_IS_LINKED)) {
1461  }
1462 
1463  /* Remove and free the inventory. */
1464  object_destroy_inv(op);
1465 
1466  /* Remove object from the active list. */
1467  op->speed = 0.0;
1468  object_update_speed(op);
1469 
1470  if (op->head == NULL) {
1471  object_cb_deinit(op);
1472  }
1473 
1474  /* Free attached attrsets */
1475  if (op->custom_attrset) {
1476  switch (op->type) {
1477  case PLAYER:
1478  /* Players are changed into DEAD_OBJECTs when they logout */
1479  case DEAD_OBJECT:
1480  mempool_return(pool_player, op->custom_attrset);
1481  break;
1482 
1483  case MONSTER:
1484  monster_data_deinit(op);
1485  break;
1486 
1487  default:
1488  LOG(ERROR,
1489  "Custom attrset found in unsupported object %s "
1490  "(type %d)", object_get_str(op), op->type);
1491  }
1492 
1493  op->custom_attrset = NULL;
1494  }
1495 
1504 
1505  /* Mark object as freed and invalidate all references to it. */
1506  op->count = 0;
1507 
1508  /* Return the memory to the mempool. */
1509  mempool_return(pool_object, op);
1510 }
1511 
1520 void
1521 object_destruct (object *op)
1522 {
1524 
1525  if (op->inv != NULL) {
1527  }
1528 
1529  object_remove(op, 0);
1530  object_destroy(op);
1531 }
1532 
1546 static int
1547 object_check_move_on (object *op, object *originator, int state)
1548 {
1549  HARD_ASSERT(op != NULL);
1550 
1551  if (QUERY_FLAG(op, FLAG_NO_APPLY)) {
1552  return false;
1553  }
1554 
1555  MapSpace *msp = GET_MAP_SPACE_PTR(op->map, op->x, op->y);
1556  /* No event on this tile. */
1557  if (!(msp->flags &
1558  (state == 1 ? (P_WALK_ON | P_FLY_ON) : (P_WALK_OFF | P_FLY_OFF)))) {
1559  return false;
1560  }
1561 
1562  mapstruct *m = op->map;
1563  int x = op->x;
1564  int y = op->y;
1565 
1567  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
1568  if (tmp == op) {
1569  continue;
1570  }
1571 
1572  if (state == 1 && IS_LIVE(op) &&
1573  (op->type != PLAYER || !CONTR(op)->tcl) &&
1574  QUERY_FLAG(tmp, FLAG_SLOW_MOVE) &&
1575  (tmp->terrain_flag == 0 ||
1576  tmp->terrain_flag & op->terrain_flag)) {
1577  op->speed_left -= SLOW_PENALTY(tmp) * FABS(op->speed);
1578  }
1579 
1580  int flag;
1581  if (QUERY_FLAG(op, FLAG_FLYING)) {
1582  flag = state == 1 ? FLAG_FLY_ON : FLAG_FLY_OFF;
1583  } else {
1584  flag = state == 1 ? FLAG_WALK_ON : FLAG_WALK_OFF;
1585  }
1586 
1587  if (!QUERY_FLAG(tmp, flag)) {
1588  continue;
1589  }
1590 
1591  object_move_on(tmp, op, originator, state);
1592 
1593  if (OBJECTS_DESTROYED(op)) {
1594  return true;
1595  }
1596 
1597  if (op->map != m || op->x != x || op->y != y) {
1598  return false;
1599  }
1600  } FOR_MAP_FINISH();
1602 
1603  return false;
1604 }
1605 
1622 void
1623 object_remove (object *op, int flags)
1624 {
1625  HARD_ASSERT(op != NULL);
1626 
1627  if (QUERY_FLAG(op, FLAG_REMOVED)) {
1628  log_error("Tried to remove an already removed object %s.",
1629  object_get_str(op));
1630  return;
1631  }
1632 
1633  if (op->more != NULL) {
1634  object_remove(op->more, flags);
1635  }
1636 
1637  SET_FLAG(op, FLAG_REMOVED);
1639  op->quickslot = 0;
1640 
1641  /* In this case, the object to be removed is in someone's inventory. */
1642  if (op->env != NULL) {
1643  if (!QUERY_FLAG(op, FLAG_SYS_OBJECT) && !(flags & REMOVE_NO_WEIGHT)) {
1644  object_weight_sub(op->env, WEIGHT_NROF(op, op->nrof));
1645  }
1646 
1647  object *env = object_get_env(op);
1648 
1649  if (op->above != NULL) {
1650  op->above->below = op->below;
1651  } else {
1652  op->env->inv = op->below;
1653  }
1654 
1655  if (op->below != NULL) {
1656  op->below->above = op->above;
1657  }
1658 
1659  /* We set up values so that it could be inserted into the map,
1660  * but we don't actually do that - it is up to the caller to
1661  * decide what we want to do. */
1662  op->x = op->env->x;
1663  op->y = op->env->y;
1664  op->map = op->env->map;
1665 
1666  esrv_del_item(op);
1668 
1669  op->above = NULL;
1670  op->below = NULL;
1671  op->env = NULL;
1672 
1673  if (env != op && IS_LIVE(env) && env->map != NULL) {
1674  living_update(env);
1675  }
1676  } else if (op->map != NULL) {
1677  /* If this is the base layer object, we assign the next object
1678  * to be it if it is from same layer and sub-layer. */
1679  MapSpace *msp = GET_MAP_SPACE_PTR(op->map, op->x, op->y);
1680 
1681  if (op->layer != 0 &&
1682  GET_MAP_SPACE_LAYER(msp, op->layer, op->sub_layer) == op) {
1683  if (op->above != NULL &&
1684  op->above->layer == op->layer &&
1685  op->above->sub_layer == op->sub_layer) {
1686  SET_MAP_SPACE_LAYER(msp, op->layer, op->sub_layer, op->above);
1687  } else {
1688  SET_MAP_SPACE_LAYER(msp, op->layer, op->sub_layer, NULL);
1689  }
1690  }
1691 
1692  /* Link the object above us. */
1693  if (op->above != NULL) {
1694  op->above->below = op->below;
1695  } else {
1696  /* Assign below as last one. */
1697  SET_MAP_SPACE_LAST(msp, op->below);
1698  }
1699 
1700  /* Relink the object below us, if there is one. */
1701  if (op->below != NULL) {
1702  op->below->above = op->above;
1703  } else {
1704  /* First object goes on above it. */
1705  SET_MAP_SPACE_FIRST(msp, op->above);
1706  }
1707 
1708  op->above = NULL;
1709  op->below = NULL;
1710  op->env = NULL;
1711 
1712  if (op->map->in_memory != MAP_SAVING) {
1713  msp->update_tile++;
1715  }
1716 
1718 
1719  if (!(flags & REMOVE_NO_WALK_OFF)) {
1720  object_check_move_on(op, NULL, 0);
1721  }
1722  }
1723 }
1724 
1740 object *
1741 object_insert_map (object *op, mapstruct *m, object *originator, int flag)
1742 {
1743  HARD_ASSERT(op != NULL);
1744  HARD_ASSERT(m != NULL);
1745 
1746  if (OBJECT_FREE(op)) {
1747  log_error("Attempted to insert freed object: %s",
1748  object_get_str(op));
1749  return NULL;
1750  }
1751 
1752  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
1753  log_error("Attempted to insert non-removed object: %s",
1754  object_get_str(op));
1755  return op;
1756  }
1757 
1758  if (op->head == NULL && op->arch->more != NULL && op->more == NULL) {
1759  object *prev = op;
1760  for (archetype_t *at = op->arch->more; at != NULL; at = at->more) {
1761  object *tail = arch_to_object(at);
1762 
1763  tail->type = op->type;
1764  tail->layer = op->layer;
1765  tail->sub_layer = op->sub_layer;
1766 
1767  tail->head = op;
1768  prev->more = tail;
1769 
1770  prev = tail;
1771  }
1772 
1773  SET_OR_CLEAR_MULTI_FLAG(op, FLAG_SYS_OBJECT);
1774  SET_OR_CLEAR_MULTI_FLAG(op, FLAG_NO_APPLY);
1775  SET_OR_CLEAR_MULTI_FLAG(op, FLAG_IS_INVISIBLE);
1776  SET_OR_CLEAR_MULTI_FLAG(op, FLAG_IS_ETHEREAL);
1777  SET_OR_CLEAR_MULTI_FLAG(op, FLAG_CAN_PASS_THRU);
1778  SET_OR_CLEAR_MULTI_FLAG(op, FLAG_FLYING);
1779  SET_OR_CLEAR_MULTI_FLAG(op, FLAG_BLOCKSVIEW);
1780 
1781  SET_OR_CLEAR_MULTI_FLAG_IF_CLONE(op, FLAG_NO_PASS);
1782  SET_OR_CLEAR_MULTI_FLAG_IF_CLONE(op, FLAG_BLOCKSVIEW);
1783  }
1784 
1785  /* Attempt to fall down through empty map squares onto maps below, but
1786  * only if the object is not a player or the player doesn't have collision
1787  * disabled. */
1788  int fall_floors = 0;
1789  if (flag & INS_FALL_THROUGH && (op->type != PLAYER || !CONTR(op)->tcl)) {
1790  mapstruct *tiled;
1791  bool found_floor;
1792  int sub_layer;
1793  for (tiled = m;
1794  tiled != NULL;
1795  tiled = get_map_from_tiled(tiled, TILED_DOWN)) {
1796  object *floor = GET_MAP_OB_LAYER(tiled,
1797  op->x,
1798  op->y,
1799  LAYER_FLOOR,
1800  op->sub_layer);
1801  int z = floor != NULL ? floor->z : 0;
1802  int z_highest = 0;
1803  sub_layer = -1;
1804  found_floor = false;
1805 
1806  if (tiled != m) {
1807  fall_floors++;
1808  }
1809 
1810  object *floor_tmp;
1811  FOR_MAP_LAYER_BEGIN(tiled,
1812  op->x,
1813  op->y,
1814  LAYER_FLOOR,
1815  -1,
1816  floor_tmp) {
1817  found_floor = true;
1818 
1819  if (tiled == m) {
1820  continue;
1821  }
1822 
1823  if (floor_tmp->z - z > MOVE_MAX_HEIGHT_DIFF) {
1824  continue;
1825  }
1826 
1827  if (floor_tmp->z > z_highest) {
1828  z_highest = floor_tmp->z;
1829  sub_layer = floor_tmp->sub_layer;
1830  }
1832 
1833  if (found_floor || QUERY_FLAG(op, FLAG_FLYING)) {
1834  break;
1835  }
1836  }
1837 
1838  if (found_floor) {
1839  if (fall_floors != 0 && object_blocked(op, tiled, op->x, op->y)) {
1840  int i = map_free_spot_first(tiled, op->x, op->y, op->arch, op);
1841  if (i != -1) {
1842  op->x += freearr_x[i];
1843  op->y += freearr_y[i];
1844  }
1845  }
1846 
1847  if (sub_layer != -1) {
1848  op->sub_layer = sub_layer;
1849  }
1850 
1851  m = tiled;
1852  }
1853 
1854  flag &= ~INS_FALL_THROUGH;
1855  }
1856 
1857  if (op->more != NULL) {
1858  op->more->x = HEAD(op)->x + op->more->arch->clone.x;
1859  op->more->y = HEAD(op)->y + op->more->arch->clone.y;
1860  op->more->sub_layer = HEAD(op)->sub_layer;
1861 
1862  if (object_insert_map(op->more, m, originator, flag) == NULL) {
1863  return NULL;
1864  }
1865  }
1866 
1867  CLEAR_FLAG(op, FLAG_REMOVED);
1868 
1869  int x = op->x;
1870  int y = op->y;
1871  m = get_map_from_coord(m, &x, &y);
1872  if (m == NULL) {
1873  return NULL;
1874  }
1875 
1876  op->x = x;
1877  op->y = y;
1878  op->map = m;
1879 
1880  /* Merge objects if possible. */
1881  if (op->nrof != 0 && !(flag & INS_NO_MERGE)) {
1882  for (object *tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) {
1883  if (object_can_merge(op, tmp)) {
1884  op->nrof += tmp->nrof;
1885  object_remove(tmp, 0);
1886  object_destroy(tmp);
1887  break;
1888  }
1889  }
1890  }
1891 
1893  CLEAR_FLAG(op, FLAG_APPLIED);
1895 
1896  MapSpace *msp = GET_MAP_SPACE_PTR(op->map, op->x, op->y);
1897 
1898  if (op->layer != 0) {
1899  object *top = GET_MAP_SPACE_LAYER(msp, op->layer, op->sub_layer);
1900  if (top == NULL) {
1901  for (int layer = op->layer;
1902  layer <= NUM_LAYERS && top == NULL;
1903  layer++) {
1904  for (int sub_layer = op->sub_layer;
1905  sub_layer < NUM_SUB_LAYERS && top == NULL;
1906  sub_layer++) {
1907  top = GET_MAP_SPACE_LAYER(msp, layer, sub_layer);
1908  }
1909  }
1910  }
1911 
1912  SET_MAP_SPACE_LAYER(msp, op->layer, op->sub_layer, op);
1913 
1914  if (top != NULL) {
1915  if (top->below != NULL) {
1916  top->below->above = op;
1917  } else {
1918  SET_MAP_SPACE_FIRST(msp, op);
1919  }
1920 
1921  op->below = top->below;
1922  top->below = op;
1923  op->above = top;
1924  } else {
1925  top = GET_MAP_SPACE_LAST(msp);
1926  if (top != NULL) {
1927  top->above = op;
1928  op->below = top;
1929  } else {
1930  SET_MAP_SPACE_FIRST(msp, op);
1931  }
1932 
1933  SET_MAP_SPACE_LAST(msp, op);
1934  }
1935  } else {
1936  /* Easy chaining */
1937  object *top = GET_MAP_SPACE_FIRST(msp);
1938  if (top != NULL) {
1939  top->below = op;
1940  op->above = top;
1941  } else {
1942  SET_MAP_SPACE_LAST(msp, op);
1943  }
1944 
1945  SET_MAP_SPACE_FIRST(msp, op);
1946  }
1947 
1948  /* Some object-type-specific adjustments/initialization. */
1949  if (op->type == PLAYER) {
1950  CONTR(op)->cs->update_tile = 0;
1951  CONTR(op)->update_los = 1;
1952 
1953  if (op->map->player_first != NULL) {
1954  CONTR(op->map->player_first)->map_below = op;
1955  CONTR(op)->map_above = op->map->player_first;
1956  }
1957 
1958  op->map->player_first = op;
1959  } else if (op->type == MAP_EVENT_OBJ) {
1960  map_event_obj_init(op);
1961  } else {
1963  }
1964 
1965  /* Mark this tile as changed. */
1966  msp->update_tile++;
1967  /* Update flags for this tile. */
1969 
1970  /* Attempt to open doors. */
1971  door_try_open(op, op->map, op->x, op->y, false);
1972 
1973  if (!(flag & INS_NO_WALK_ON) &&
1974  (msp->flags & (P_WALK_ON | P_FLY_ON) || op->more != NULL) &&
1975  op->head == NULL) {
1976  for (object *tmp = op; tmp != NULL; tmp = tmp->more) {
1977  if (object_check_move_on(tmp, originator, 1)) {
1978  return NULL;
1979  }
1980  }
1981  }
1982 
1983  if (fall_floors != 0 && IS_LIVE(op)) {
1985  attack_perform_fall(op, fall_floors);
1986 
1987  if (OBJECTS_DESTROYED(op)) {
1988  return NULL;
1989  }
1991  }
1992 
1993  return op;
1994 }
1995 
2009 object *
2010 object_stack_get (object *op, uint32_t nrof)
2011 {
2012  HARD_ASSERT(op != NULL);
2013 
2014  nrof = MAX(1, nrof);
2015 
2016  if (MAX(1, op->nrof) <= nrof) {
2017  return op;
2018  }
2019 
2020  op->nrof -= nrof;
2022  esrv_update_item(UPD_NROF, op);
2023 
2024  if (op->env != NULL && !QUERY_FLAG(op, FLAG_SYS_OBJECT)) {
2025  object_weight_sub(op->env, WEIGHT_NROF(op, nrof));
2026  }
2027 
2028  object *split = object_get();
2029  object_copy_full(split, op);
2030  split->nrof = nrof;
2031  return split;
2032 }
2033 
2045 object *
2046 object_stack_get_reinsert (object *op, uint32_t nrof)
2047 {
2048  HARD_ASSERT(op != NULL);
2049 
2050  object *split = object_stack_get(op, nrof);
2051  if (split != op) {
2052  if (op->map != NULL) {
2053  split = object_insert_map(split, op->map, NULL, INS_NO_MERGE);
2054  } else if (op->env != NULL) {
2055  split = object_insert_into(split, op->env, INS_NO_MERGE);
2056  }
2057 
2058  if (split == NULL) {
2059  return op;
2060  }
2061  }
2062 
2063  return split;
2064 }
2065 
2077 object *
2078 object_stack_get_removed (object *op, uint32_t nrof)
2079 {
2080  HARD_ASSERT(op != NULL);
2081 
2082  object *split = object_stack_get(op, nrof);
2083  if (split == op) {
2084  object_remove(split, 0);
2085  }
2086 
2087  return split;
2088 }
2089 
2104 object *
2105 object_decrease (object *op, uint32_t nrof)
2106 {
2107  HARD_ASSERT(op != NULL);
2108 
2109  if (nrof == 0) {
2110  return op;
2111  }
2112 
2113  if (nrof > op->nrof) {
2114  nrof = op->nrof;
2115  }
2116 
2117  if (QUERY_FLAG(op, FLAG_REMOVED)) {
2118  op->nrof -= nrof;
2119  } else {
2120  if (nrof < op->nrof) {
2121  op->nrof -= nrof;
2122 
2123  if (op->env != NULL && !QUERY_FLAG(op, FLAG_SYS_OBJECT)) {
2124  object_weight_sub(op->env, op->weight * nrof);
2125  }
2126  } else {
2127  object_remove(op, 0);
2128  op->nrof = 0;
2129  }
2130  }
2131 
2132  if (op->nrof != 0) {
2134  esrv_update_item(UPD_NROF, op);
2135  return op;
2136  }
2137 
2138  object_destroy(op);
2139  return NULL;
2140 }
2141 
2157 object *
2158 object_insert_into (object *op, object *where, int flag)
2159 {
2160  HARD_ASSERT(op != NULL);
2161  SOFT_ASSERT_RC(where != NULL,
2162  op,
2163  "Attempting to insert %s into nothing.",
2164  object_get_str(op));
2165  SOFT_ASSERT_RC(QUERY_FLAG(op, FLAG_REMOVED),
2166  op,
2167  "Attempting to insert non-removed object %s into %s",
2168  object_get_str(op),
2169  object_get_str(where));
2170 
2171  where = HEAD(where);
2172  op = HEAD(op);
2173 
2174  /* If the object has tail parts, it means the object is a multi-part
2175  * object that was on a map prior to this insert call. Thus, we will
2176  * want to destroy the tail parts of this object, so if the object
2177  * is at some later point inserted on the map again, the tails will
2178  * be re-created. */
2179  if (op->more != NULL) {
2180  for (object *tmp = op->more, *next; tmp != NULL; tmp = next) {
2181  next = tmp->more;
2182  object_destroy(tmp);
2183  }
2184 
2185  op->more = NULL;
2186  }
2187 
2188  CLEAR_FLAG(op, FLAG_REMOVED);
2189 
2190  if (!QUERY_FLAG(op, FLAG_SYS_OBJECT)) {
2191  if (!(flag & INS_NO_MERGE)) {
2192  for (object *tmp = where->inv; tmp != NULL; tmp = tmp->below) {
2193  if (!QUERY_FLAG(tmp, FLAG_SYS_OBJECT) &&
2194  object_can_merge(tmp, op)) {
2195  tmp->nrof += op->nrof;
2196  esrv_update_item(UPD_NROF, tmp);
2197  object_weight_add(where, op->weight * MAX(1, op->nrof));
2198 
2199  SET_FLAG(op, FLAG_REMOVED);
2200  object_destroy(op);
2201 
2202  return tmp;
2203  }
2204  }
2205  }
2206 
2207  object_weight_add(where, WEIGHT_NROF(op, op->nrof));
2208  }
2209 
2211  op->map = NULL;
2212  op->env = where;
2213  op->above = NULL;
2214  op->below = NULL;
2215  op->x = 0;
2216  op->y = 0;
2217 
2218  if (where->inv == NULL) {
2219  where->inv = op;
2220  } else {
2221  op->below = where->inv;
2222  op->below->above = op;
2223  where->inv = op;
2224  }
2225 
2226  /* Check for event object and set the environment's object event flags. */
2227  if (op->type == EVENT_OBJECT && op->sub_type != 0) {
2228  where->event_flags |= (1U << (op->sub_type - 1));
2229  } else if (op->type == QUEST_CONTAINER && where->type == CONTAINER) {
2230  where->event_flags |= EVENT_FLAG(EVENT_QUEST);
2231  }
2232 
2233  /* Update living objects if inside living object. */
2234  object *env = object_get_env(op);
2235  if (env != op && IS_LIVE(env) && env->map != NULL) {
2236  living_update(env);
2237  }
2238 
2239  if (where->type == PLAYER || where->type == CONTAINER) {
2240  esrv_send_item(op);
2241  }
2242 
2243  return op;
2244 }
2245 
2257 object *
2259 {
2260  HARD_ASSERT(op != NULL);
2261  HARD_ASSERT(at != NULL);
2262 
2263  for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) {
2264  if (tmp->arch == at) {
2265  return tmp;
2266  }
2267  }
2268 
2269  return NULL;
2270 }
2271 
2283 object *
2284 object_find_type (object *op, uint8_t type)
2285 {
2286  HARD_ASSERT(op != NULL);
2287 
2288  for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) {
2289  if (tmp->type == type) {
2290  return tmp;
2291  }
2292  }
2293 
2294  return NULL;
2295 }
2296 
2309 int
2310 object_dir_to_target (object *op, object *target)
2311 {
2312  HARD_ASSERT(op != NULL);
2313  HARD_ASSERT(target != NULL);
2314 
2315  rv_vector rv;
2316  if (!get_rangevector(op, target, &rv, 0)) {
2317  return 0;
2318  }
2319 
2320  return rv.direction;
2321 }
2322 
2334 bool
2335 object_can_pick (const object *op, const object *item)
2336 {
2337  HARD_ASSERT(op != NULL);
2338  HARD_ASSERT(item != NULL);
2339  HARD_ASSERT(op->type == PLAYER || op->type == MONSTER);
2340 
2341  if (item->weight <= 0) {
2342  return false;
2343  }
2344 
2345  if (QUERY_FLAG(item, FLAG_NO_PICK) && !QUERY_FLAG(item, FLAG_UNPAID)) {
2346  return false;
2347  }
2348 
2349  if (IS_INVISIBLE(item, op) && !QUERY_FLAG(op, FLAG_SEE_INVISIBLE)) {
2350  return false;
2351  }
2352 
2353  if (QUERY_FLAG(item, FLAG_SOULBOUND)) {
2354  if (op->type != PLAYER) {
2355  return false;
2356  }
2357 
2358  shstr *name = object_get_value(item, "soulbound_name");
2359  if (name == NULL) {
2360  return false;
2361  }
2362 
2363  if (name != op->name) {
2364  return false;
2365  }
2366  }
2367 
2368  /* Weight limit for monsters */
2369  if (op->type != PLAYER && item->weight > op->weight / 3) {
2370  return false;
2371  }
2372 
2373  return true;
2374 }
2375 
2384 object *
2385 object_clone (const object *op)
2386 {
2387  HARD_ASSERT(op != NULL);
2388 
2389  op = HEAD(op);
2390 
2391  object *ret = NULL;
2392 
2393  object *prev = NULL;
2394  for (const object *part = op; part != NULL; part = part->more) {
2395  object *tmp = object_get();
2396  object_copy(tmp, part, false);
2397  tmp->x -= op->x;
2398  tmp->y -= op->y;
2399 
2400  if (part->head == NULL) {
2401  ret = tmp;
2402  tmp->head = NULL;
2403  } else {
2404  tmp->head = ret;
2405  }
2406 
2407  tmp->more = NULL;
2408 
2409  if (prev != NULL) {
2410  prev->more = tmp;
2411  }
2412 
2413  prev = tmp;
2414  }
2415 
2416  /* Copy inventory */
2417  for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) {
2418  object_insert_into(object_clone(tmp), ret, 0);
2419  }
2420 
2421  return ret;
2422 }
2423 
2432 object *
2433 object_load_str (const char *str)
2434 {
2435  HARD_ASSERT(str != NULL);
2436 
2437  object *obj = object_get();
2438  if (load_object(str, obj, 0) != LL_NORMAL) {
2439  LOG(ERROR, "load_object() failed.");
2440  object_destroy(obj);
2441  return NULL;
2442  }
2443 
2444  object_weight_sum(obj);
2445  return obj;
2446 }
2447 
2455 void
2457 {
2458  HARD_ASSERT(op != NULL);
2459 
2460  key_value_t *field, *tmp;
2461  LL_FOREACH_SAFE(op->key_values, field, tmp) {
2462  if (field->key != NULL) {
2463  free_string_shared(field->key);
2464  }
2465 
2466  if (field->value != NULL) {
2467  free_string_shared(field->value);
2468  }
2469 
2470  efree(field);
2471  }
2472 
2473  op->key_values = NULL;
2474 }
2475 
2486 key_value_t *
2487 object_get_key_link (const object *op, shstr *key)
2488 {
2489  HARD_ASSERT(op != NULL);
2490  HARD_ASSERT(key != NULL);
2491 
2492  key_value_t *field;
2493  LL_FOREACH(op->key_values, field) {
2494  if (field->key == key) {
2495  return field;
2496  }
2497  }
2498 
2499  return NULL;
2500 }
2501 
2514 shstr *
2515 object_get_value (const object *op, const char *const key)
2516 {
2517  HARD_ASSERT(op != NULL);
2518  HARD_ASSERT(key != NULL);
2519 
2520  shstr *shared_key = find_string(key);
2521  if (shared_key == NULL) {
2522  return NULL;
2523  }
2524 
2525  key_value_t *field;
2526  LL_FOREACH(op->key_values, field) {
2527  if (field->key == shared_key) {
2528  return field->value;
2529  }
2530  }
2531 
2532  return NULL;
2533 }
2534 
2549 static bool
2550 object_set_value_s (object *op, shstr *key, const char *value, bool add_key)
2551 {
2552  HARD_ASSERT(op != NULL);
2553  HARD_ASSERT(key != NULL);
2554 
2555  key_value_t *field;
2556  key_value_t *last = NULL;
2557  LL_FOREACH(op->key_values, field) {
2558  if (field->key != key) {
2559  last = field;
2560  continue;
2561  }
2562 
2563  if (field->value != NULL) {
2564  free_string_shared(field->value);
2565  }
2566 
2567  if (value != NULL) {
2568  field->value = add_string(value);
2569  } else {
2570  /* Basically, if the archetype has this key set, we need to
2571  * store the NULL value so when we save it, we save the empty
2572  * value so that when we load, we get this value back
2573  * again. */
2574  if (object_get_key_link(&op->arch->clone, key)) {
2575  field->value = NULL;
2576  } else {
2577  /* Delete this link */
2578  if (field->key != NULL) {
2579  free_string_shared(field->key);
2580  }
2581 
2582  if (last != NULL) {
2583  last->next = field->next;
2584  } else {
2585  op->key_values = field->next;
2586  }
2587 
2588  efree(field);
2589  }
2590  }
2591 
2592  return true;
2593  }
2594 
2595  if (!add_key) {
2596  return false;
2597  }
2598 
2599  /* There isn't any good reason to store a NULL value in the key/value
2600  * list. If the archetype has this key, then we should also have it,
2601  * so shouldn't be here. If user wants to store empty strings, should
2602  * pass in "". */
2603  if (value == NULL) {
2604  return true;
2605  }
2606 
2607  field = emalloc(sizeof(*field));
2608  field->key = add_refcount(key);
2609  field->value = add_string(value);
2610  /* Usual prepend-addition. */
2611  field->next = op->key_values;
2612  op->key_values = field;
2613 
2614  return true;
2615 }
2616 
2634 bool
2635 object_set_value (object *op, const char *key, const char *value, bool add_key)
2636 {
2637  HARD_ASSERT(op != NULL);
2638  HARD_ASSERT(key != NULL);
2639 
2640  bool temp_ref = false;
2641  shstr *shstr_key = find_string(key);
2642  if (shstr_key == NULL) {
2643  shstr_key = add_string(key);
2644  temp_ref = true;
2645  }
2646 
2647  bool ret = object_set_value_s(op, shstr_key, value, add_key);
2648 
2649  if (temp_ref) {
2650  free_string_shared(shstr_key);
2651  }
2652 
2653  return ret;
2654 }
2655 
2675 int
2676 object_matches_string (object *op, object *caller, const char *str)
2677 {
2678  HARD_ASSERT(op != NULL);
2679  HARD_ASSERT(caller != NULL);
2680  HARD_ASSERT(str != NULL);
2681 
2682  if (caller->type == PLAYER) {
2683  CONTR(caller)->count = op->nrof;
2684  }
2685 
2686  char word[MAX_BUF];
2687  size_t pos = 0;
2688  while (string_get_word(str, &pos, ',', VS(word), 0)) {
2689  char *cp = word;
2690 
2691  /* All is a very generic match - low match value */
2692  if (strcasecmp(cp, "all") == 0) {
2693  return 1;
2694  }
2695 
2696  /* Unpaid is a little more specific */
2697  if (QUERY_FLAG(op, FLAG_UNPAID) && strcasecmp(cp, "unpaid") == 0) {
2698  return 2;
2699  }
2700 
2701  bool identified = QUERY_FLAG(op, FLAG_IDENTIFIED);
2702  if (identified) {
2703  if ((QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)) &&
2704  strcasecmp(cp, "cursed") == 0) {
2705  return 2;
2706  }
2707 
2708  if (QUERY_FLAG(op, FLAG_IS_MAGICAL) &&
2709  strcasecmp(cp, "magical") == 0) {
2710  return 2;
2711  }
2712 
2713  if (op->artifact != NULL &&
2714  strcasecmp(cp, "artifact") == 0) {
2715  return 2;
2716  }
2717  }
2718 
2719  if (!QUERY_FLAG(op, FLAG_INV_LOCKED) &&
2720  strcasecmp(cp, "unlocked") == 0) {
2721  return 2;
2722  }
2723 
2724  if (identified && strcasecmp(cp, "identified") == 0) {
2725  return 2;
2726  }
2727 
2728  if (!identified && strcasecmp(cp, "unidentified") == 0) {
2729  return 2;
2730  }
2731 
2732  if ((op->type == FOOD || op->type == DRINK) &&
2733  strcasecmp(cp, "food") == 0) {
2734  return 2;
2735  }
2736 
2737  if ((op->type == GEM || op->type == JEWEL || op->type == NUGGET ||
2738  op->type == PEARL) && strcasecmp(cp, "valuables") == 0) {
2739  return 2;
2740  }
2741 
2742  if (op->type == WEAPON) {
2743  if (op->item_skill - 1 == SK_IMPACT_WEAPONS) {
2744  if (strcasecmp(cp, "impact weapons") == 0) {
2745  return 2;
2746  }
2747  } else if (op->item_skill - 1 == SK_SLASH_WEAPONS) {
2748  if (strcasecmp(cp, "slash weapons") == 0) {
2749  return 2;
2750  }
2751  } else if (op->item_skill - 1 == SK_CLEAVE_WEAPONS) {
2752  if (strcasecmp(cp, "cleave weapons") == 0) {
2753  return 2;
2754  }
2755  } else if (op->item_skill - 1 == SK_PIERCE_WEAPONS) {
2756  if (strcasecmp(cp, "pierce weapons") == 0) {
2757  return 2;
2758  }
2759  }
2760  } else if (op->type == BOOK) {
2761  if (strcasecmp(cp, "books") == 0) {
2762  return 2;
2763  }
2764 
2765  if (op->msg == NULL && strcasecmp(cp, "empty books") == 0) {
2766  return 2;
2767  }
2768 
2769  int book_level[2];
2770  if (!QUERY_FLAG(op, FLAG_NO_SKILL_IDENT)) {
2771  if (strcasecmp(cp, "unread books") == 0) {
2772  return 2;
2773  }
2774 
2775  if (sscanf(cp, "unread level %d books", &book_level[0]) == 1 &&
2776  op->level == book_level[0]) {
2777  return 2;
2778  }
2779 
2780  if (sscanf(cp, "unread level %d-%d books", &book_level[0],
2781  &book_level[1]) == 2 &&
2782  op->level >= book_level[0] && op->level <= book_level[1]) {
2783  return 2;
2784  }
2785  } else {
2786  if (strcasecmp(cp, "read books") == 0) {
2787  return 2;
2788  }
2789 
2790  if (sscanf(cp, "read level %d books", &book_level[0]) == 1 &&
2791  op->level == book_level[0]) {
2792  return 2;
2793  }
2794 
2795  if (sscanf(cp, "read level %d-%d books", &book_level[0],
2796  &book_level[1]) == 2 &&
2797  op->level >= book_level[0] && op->level <= book_level[1]) {
2798  return 2;
2799  }
2800  }
2801  }
2802 
2803  int count = 0;
2804 
2805  /* Allow for things like '100 arrows', but don't accept
2806  * strings like '+2', '-1' as numbers. */
2807  if (isdigit(cp[0]) && (count = atoi(cp)) != 0) {
2808  cp = strchr(cp, ' ');
2809 
2810  /* Get rid of spaces */
2811  while (cp != NULL && cp[0] == ' ') {
2812  cp++;
2813  }
2814  }
2815 
2816  if (cp == NULL || cp[0] == '\0' || count < 0) {
2817  return 0;
2818  }
2819 
2820  char *obj_name = object_get_name_s(op, caller);
2821  char *base_name = object_get_base_name_s(op, caller);
2822  char *short_name = object_get_short_name_s(op, caller);
2823 
2824  int retval;
2825  if (strcasecmp(cp, obj_name) == 0) {
2826  retval = 20;
2827  } else if (strcasecmp(cp, short_name) == 0) {
2828  retval = 18;
2829  } else if (strcasecmp(cp, base_name) == 0) {
2830  retval = 16;
2831  } else if (op->custom_name != NULL &&
2832  strcasecmp(cp, op->custom_name) == 0) {
2833  retval = 15;
2834  } else if (strncasecmp(cp, base_name, strlen(cp)) == 0) {
2835  retval = 14;
2836  } else if (strstr(base_name, cp) != NULL) {
2837  /* Do substring checks, so things like 'Str+1' will match.
2838  * retval of these should perhaps be lower - they are lower
2839  * than the specific strcasecmps above, but still higher than
2840  * some other match criteria. */
2841  retval = 12;
2842  } else if (strstr(short_name, cp) != NULL) {
2843  retval = 12;
2844  } else if (op->custom_name != NULL &&
2845  strstr(op->custom_name, cp) != NULL) {
2846  /* Check for partial custom name, but give a really low priority. */
2847  retval = 3;
2848  } else {
2849  retval = 0;
2850  }
2851 
2852  efree(obj_name);
2853  efree(base_name);
2854  efree(short_name);
2855 
2856  if (retval != 0) {
2857  if (caller->type == PLAYER && count != 0) {
2858  CONTR(caller)->count = count;
2859  }
2860 
2861  return retval;
2862  }
2863  }
2864 
2865  return 0;
2866 }
2867 
2876 int
2877 object_get_gender (const object *op)
2878 {
2879  HARD_ASSERT(op != NULL);
2880 
2881  if (QUERY_FLAG(op, FLAG_IS_MALE)) {
2882  if (QUERY_FLAG(op, FLAG_IS_FEMALE)) {
2883  return GENDER_HERMAPHRODITE;
2884  } else {
2885  return GENDER_MALE;
2886  }
2887  } else if (QUERY_FLAG(op, FLAG_IS_FEMALE)) {
2888  return GENDER_FEMALE;
2889  }
2890 
2891  return GENDER_NEUTER;
2892 }
2893 
2900 void
2902 {
2903  HARD_ASSERT(op != NULL);
2904 
2905  if (op->inv == NULL) {
2906  return;
2907  }
2908 
2909  if (op->inv->inv != NULL) {
2911  }
2912 
2913  object *next = op->inv->below;
2914  op->inv->above = NULL;
2915  op->inv->below = NULL;
2916 
2917  while (next != NULL) {
2918  object *tmp = next;
2919  next = next->below;
2920 
2921  tmp->above = NULL;
2922  tmp->below = op->inv;
2923  tmp->below->above = tmp;
2924  op->inv = tmp;
2925 
2926  if (tmp->inv != NULL) {
2928  }
2929  }
2930 }
2931 
2955 bool
2956 object_enter_map (object *op,
2957  object *exit,
2958  mapstruct *m,
2959  int x,
2960  int y,
2961  bool fixed_pos)
2962 {
2963  HARD_ASSERT(op != NULL);
2964 
2965  op = HEAD(op);
2966  mapstruct *oldmap = op->map;
2967 
2968  if (m == NULL && exit != NULL) {
2969  if (EXIT_PATH(exit) == NULL) {
2970  return false;
2971  }
2972 
2973  x = EXIT_X(exit);
2974  y = EXIT_Y(exit);
2975  fixed_pos = QUERY_FLAG(exit, FLAG_USE_FIX_POS);
2976 
2977  if (strcmp(EXIT_PATH(exit), "/random/") == 0) {
2978  RMParms rp;
2979  memset(&rp, 0, sizeof(RMParms));
2980 
2981  rp.Xsize = -1;
2982  rp.Ysize = -1;
2983 
2984  if (exit->msg != NULL) {
2985  set_random_map_variable(&rp, exit->msg);
2986  }
2987 
2988  rp.origin_x = exit->x;
2989  rp.origin_y = exit->y;
2990  snprintf(VS(rp.origin_map), "%s", op->map->path);
2991 
2992  /* Pick a new pathname for the new map. Currently, we just use a
2993  * static variable and increment the counter by one each time. */
2994  static uint64_t reference_number = 0;
2995  char newmap_name[HUGE_BUF];
2996  snprintf(VS(newmap_name), "/random/%"PRIu64, reference_number++);
2997 
2998  /* Now to generate the actual map. */
2999  m = generate_random_map(newmap_name, &rp);
3000 
3001  /* Update the exit_ob so it now points directly at the newly
3002  * created random map. */
3003  if (m != NULL) {
3004  x = EXIT_X(exit) = MAP_ENTER_X(m);
3005  y = EXIT_Y(exit) = MAP_ENTER_Y(m);
3006  FREE_AND_COPY_HASH(EXIT_PATH(exit), newmap_name);
3007  FREE_AND_COPY_HASH(m->path, newmap_name);
3008  }
3009  } else if (exit->map != NULL) {
3010  bool unique = (op->type == PLAYER &&
3011  (exit->last_eat == MAP_PLAYER_MAP ||
3012  (MAP_UNIQUE(exit->map) &&
3013  !map_path_isabs(EXIT_PATH(exit)))));
3014  char *path = map_get_path(exit->map,
3015  EXIT_PATH(exit),
3016  unique,
3017  op->name);
3018  m = ready_map_name(path, NULL, 0);
3019  efree(path);
3020 
3021  /* Failed to load a random map? */
3022  if (m == NULL &&
3023  op->type == PLAYER &&
3024  strncmp(EXIT_PATH(exit), "/random/", 8) == 0) {
3025  m = ready_map_name(CONTR(op)->savebed_map, NULL, 0);
3026  return object_enter_map(op,
3027  NULL,
3028  m,
3029  CONTR(op)->bed_x,
3030  CONTR(op)->bed_y,
3031  true);
3032  }
3033  } else {
3034  m = ready_map_name(EXIT_PATH(exit), NULL, MAP_NAME_SHARED);
3035  }
3036 
3037  if (m == NULL) {
3038  return false;
3039  }
3040 
3041  /* If exit is damned, update player's savebed position. */
3042  if (QUERY_FLAG(exit, FLAG_DAMNED) && op->type == PLAYER) {
3043  snprintf(VS(CONTR(op)->savebed_map), "%s", m->path);
3044  CONTR(op)->bed_x = x;
3045  CONTR(op)->bed_y = y;
3046  player_save(op);
3047  }
3048  }
3049 
3050  if (m == NULL) {
3051  m = ready_map_name(EMERGENCY_MAPPATH, NULL, 0);
3052  x = EMERGENCY_X;
3053  y = EMERGENCY_Y;
3054  fixed_pos = true;
3055  }
3056 
3057  if (exit == NULL && MAP_FIXEDLOGIN(m)) {
3058  x = MAP_ENTER_X(m);
3059  y = MAP_ENTER_Y(m);
3060  }
3061 
3062  mapstruct *m2 = get_map_from_coord(m, &x, &y);
3063  if (m2 == NULL) {
3064  LOG(ERROR,
3065  "Invalid exit coordinates (%d,%d): %s",
3066  x,
3067  y,
3068  object_get_str(exit));
3069  x = MAP_ENTER_X(m);
3070  y = MAP_ENTER_Y(m);
3071  } else {
3072  m = m2;
3073  }
3074 
3075  if (!fixed_pos && blocked(op, m, x, y, TERRAIN_ALL) != 0) {
3076  int i = map_free_spot(m, x, y, 1, SIZEOFFREE1, op->arch, NULL);
3077  if (i != -1) {
3078  x += freearr_x[i];
3079  y += freearr_y[i];
3080  }
3081  }
3082 
3083  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
3084  object_remove(op, 0);
3085  }
3086 
3087  if (exit != NULL) {
3088  int sub_direction = exit->last_heal - 1 == TILED_UP ? 1 : -1;
3089  for (int sub_layer = op->sub_layer;
3090  sub_layer >= 0 && sub_layer < NUM_SUB_LAYERS;
3091  sub_layer += sub_direction) {
3092  object *floor = GET_MAP_OB_LAYER(m, x, y, LAYER_FLOOR, sub_layer);
3093  if (floor != NULL) {
3094  op->sub_layer = sub_layer;
3095  break;
3096  }
3097  }
3098  }
3099 
3100  if (op->map != NULL && op->type == PLAYER) {
3101  trigger_map_event(MEVENT_LEAVE, op->map, op, NULL, NULL, NULL, 0);
3102  }
3103 
3104  op->x = x;
3105  op->y = y;
3106  op = object_insert_map(op, m, NULL, 0);
3107  if (op == NULL) {
3108  return false;
3109  }
3110 
3111  trigger_map_event(MEVENT_ENTER, m, op, NULL, NULL, NULL, 0);
3112  m->timeout = 0;
3113 
3114  /* Do some action special for players after we have inserted them. */
3115  if (op->type == PLAYER) {
3116  if (CONTR(op) != NULL) {
3117  snprintf(VS(CONTR(op)->maplevel), "%s", m->path);
3118  CONTR(op)->count = 0;
3119  }
3120 
3121  /* If the player is changing maps, we need to do some special things
3122  * Do this after the player is on the new map - otherwise the force
3123  * swap of the old map does not work. */
3124  if (oldmap != NULL && oldmap != m && oldmap->player_first == NULL) {
3125  set_map_timeout(oldmap);
3126  }
3127  }
3128 
3129  if (exit != NULL && exit->stats.dam != 0 && op->type == PLAYER) {
3130  attack_hit(op, exit, exit->stats.dam);
3131  }
3132 
3133  return true;
3134 }
3135 
3150 const char *
3151 object_get_str (const object *op)
3152 {
3153  static char buf[10][HUGE_BUF * 16];
3154  static int buf_idx = 0;
3155 
3156  buf_idx++;
3157  buf_idx %= 10;
3158 
3159  return object_get_str_r(op, VS(buf[buf_idx]));
3160 }
3161 
3174 char *
3175 object_get_str_r (const object *op, char *buf, size_t bufsize)
3176 {
3177  HARD_ASSERT(buf != NULL);
3178 
3179  if (op == NULL) {
3180  snprintf(buf, bufsize, "<no object>");
3181  return buf;
3182  }
3183 
3184  snprintf(buf, bufsize, "%s UID: %u",
3185  op->name != NULL ? op->name : "<no name>",
3186  op->count);
3187 
3188  if (arch_table != NULL && op->arch != NULL && op->arch->name != NULL) {
3189  snprintfcat(buf, bufsize, " arch: %s", op->arch->name);
3190  }
3191 
3192  if (first_map != NULL && op->map != NULL) {
3193  snprintfcat(buf, bufsize, " map: %s [%s] @ %d,%d",
3194  op->map->name != NULL ? op->map->name : "<no name>",
3195  op->map->path != NULL ? op->map->path : "<no path>",
3196  op->x, op->y);
3197  } else if (op->env != NULL) {
3198  char buf2[HUGE_BUF];
3199  snprintfcat(buf, bufsize, " env: [%s]", object_get_str_r(op->env,
3200  VS(buf2)));
3201  }
3202 
3203  return buf;
3204 }
3205 
3223 int
3224 object_blocked (object *op, mapstruct *m, int x, int y)
3225 {
3226  HARD_ASSERT(op != NULL);
3227  HARD_ASSERT(m != NULL);
3228 
3229  SOFT_ASSERT_RC(!OUT_OF_MAP(m, x, y),
3230  P_OUT_OF_MAP,
3231  "Out of map: %s %d,%d",
3232  m->path,
3233  x,
3234  y);
3235 
3236  op = HEAD(op);
3237 
3238  if (op->more == NULL) {
3239  return blocked(op, m, x, y, op->terrain_flag);
3240  }
3241 
3242  for (object *tmp = op; tmp != NULL; tmp = tmp->more) {
3243  int xt = x + tmp->arch->clone.x;
3244  int yt = y + tmp->arch->clone.y;
3245  mapstruct *map = get_map_from_coord(m, &xt, &yt);
3246  if (map == NULL) {
3247  return P_OUT_OF_MAP;
3248  }
3249 
3250  /* If this part is a different part of the head, then skip checking
3251  * this tile. */
3252  object *tmp2;
3253  for (tmp2 = op; tmp2 != NULL; tmp2 = tmp2->more) {
3254  if (tmp2->map == map && tmp2->x == xt && tmp2->y == yt) {
3255  break;
3256  }
3257  }
3258 
3259  if (tmp2 != NULL) {
3260  continue;
3261  }
3262 
3263  int ret = blocked(op, map, xt, yt, op->terrain_flag);
3264  if (ret != 0) {
3265  return ret;
3266  }
3267  }
3268 
3269  return 0;
3270 }
3271 
3280 object *
3281 object_create_singularity (const char *name)
3282 {
3283  char buf[MAX_BUF];
3284  snprintf(VS(buf), "singularity");
3285  if (name != NULL) {
3286  snprintfcat(VS(buf), " (%s)", name);
3287  }
3288 
3289  object *op = object_get();
3290  FREE_AND_COPY_HASH(op->name, buf);
3291  SET_FLAG(op, FLAG_NO_PICK);
3292  return op;
3293 }
3294 
3304 void
3305 object_save (const object *op, FILE *fp)
3306 {
3307  HARD_ASSERT(op != NULL);
3308 
3309  if (fp == NULL) {
3310  return;
3311  }
3312 
3313  archetype_t *at = op->arch;
3314  if (at == NULL) {
3316  }
3317 
3318  fprintf(fp, "arch %s\n", at->name);
3319 
3320  StringBuffer *sb = stringbuffer_new();
3321  get_ob_diff(sb, op, &at->clone);
3322 
3323  char *cp = stringbuffer_finish(sb);
3324  fputs(cp, fp);
3325  efree(cp);
3326 
3327  for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) {
3328  object_save(tmp, fp);
3329  }
3330 
3331  fprintf(fp, "end\n");
3332 }
static bool object_validator(object *op)
Definition: object.c:202
struct archetype * corpse
Definition: race.h:45
void get_ob_diff(StringBuffer *sb, const object *op, const object *op2)
Definition: object.c:48732
#define GENDER_MALE
Definition: object.h:633
void object_update_speed(object *op)
Definition: object.c:1043
#define FREE_AND_ADD_REF_HASH(_sv_, _nv_)
Definition: global.h:116
int find_face(const char *name, int error)
Definition: image.c:172
Definition: object.h:94
#define FLAG_FLY_OFF
Definition: define.h:972
#define FREE_AND_COPY_HASH(_sv_, _nv_)
Definition: global.h:100
archetype_t * arch_table
Definition: arch.c:41
#define MONSTER
Definition: define.h:353
#define REMOVE_NO_WALK_OFF
Definition: object.h:589
const char * object_get_str(const object *op)
Definition: object.c:3151
#define EXIT
Definition: define.h:312
object * object_decrease(object *op, uint32_t nrof)
Definition: object.c:2105
#define UP_OBJ_FACE
Definition: object.h:537
tag_t ownercount
Definition: object.h:219
#define MAP_IN_MEMORY
Definition: map.h:170
shstr * name
Definition: map.h:553
static mempool_struct * pool_object
Definition: object.c:143
uint8_t item_level
Definition: object.h:375
ob_race * race_find(shstr *name)
Definition: race.c:157
int get_rangevector(object *op1, object *op2, rv_vector *retval, int flags)
Definition: map.c:2238
#define FLAG_SYS_OBJECT
Definition: define.h:1243
#define MOVE_MAX_HEIGHT_DIFF
Definition: define.h:1604
int direction
Definition: map.h:787
const char * race
Definition: object.h:174
double weapon_speed
Definition: object.h:475
bool object_can_merge(object *ob1, object *ob2)
Definition: object.c:299
#define FLAG_CURSED
Definition: define.h:1154
#define DEAD_OBJECT
Definition: define.h:275
tag_t attacked_by_count
Definition: object.h:222
#define BOOK
Definition: define.h:150
tag_t enemy_count
Definition: object.h:216
#define JEWEL
Definition: define.h:473
#define NUM_FACINGS(ob)
Definition: global.h:300
#define QUEST_CONTAINER
Definition: define.h:489
void object_dump(const object *op, StringBuffer *sb)
Definition: object.c:680
void * custom_attrset
Definition: object.h:160
uint16_t material
Definition: object.h:304
#define FLAG_IS_LINKED
Definition: define.h:1150
bool object_can_pick(const object *op, const object *item)
Definition: object.c:2335
#define P_NEED_UPDATE
Definition: map.h:307
uint8_t type
One of operation types.
Definition: sound_ambient.c:45
#define TILED_UP
Definition: global.h:203
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:1691
object * object_owner(object *op)
Definition: object.c:857
uint32_t object_weight_sum(object *op)
Definition: object.c:523
#define FOR_INV_FINISH()
Definition: define.h:1698
#define LL_NORMAL
Object was successfully loaded.
Definition: loader.h:40
#define FLAG_NO_MAGIC
Definition: define.h:1032
#define MAP_ENTER_X(m)
Definition: map.h:129
uint16_t terrain_type
Definition: object.h:298
int object_dir_to_target(object *op, object *target)
Definition: object.c:2310
shstr * path
Definition: map.h:568
int32_t light_value
Definition: map.h:375
double speed_left
Definition: object.h:472
#define SIZEOFFREE1
Definition: define.h:654
mapstruct * get_map_from_coord(mapstruct *m, int *x, int *y)
Definition: map.c:1869
#define FLAG_NO_APPLY
Definition: define.h:1114
uint32_t in_memory
Definition: map.h:627
#define EMERGENCY_MAPPATH
Definition: config.h:134
struct key_value * next
Definition: object.h:88
int16_t last_heal
Definition: object.h:310
#define UP_OBJ_INSERT
Definition: object.h:528
#define SET_ANIMATION(ob, newanim)
Definition: global.h:282
uint8_t item_skill
Definition: object.h:378
struct treasure_list * randomitems
Definition: object.h:231
#define FLAG_CORPSE_FORCED
Definition: define.h:1293
#define FLAG_FLY_ON
Definition: define.h:968
void quest_handle(object *op, object *quest)
Definition: quest.c:377
const char * slaying
Definition: object.h:180
int16_t material_real
Definition: object.h:307
int blocked(object *op, mapstruct *m, int x, int y, int terrain)
Definition: map.c:598
#define FLAG_SOULBOUND
Definition: define.h:1044
void connection_object_remove(object *op)
Definition: connection.c:91
int16_t last_sp
Definition: object.h:313
#define FLAG_SEE_INVISIBLE
Definition: define.h:946
const char * gender_objective[GENDER_MAX]
Definition: object.c:65
#define LAYER_FLOOR
Definition: map.h:49
void object_reverse_inventory(object *op)
Definition: object.c:2901
#define FLAG_PLAYER_ONLY
Definition: define.h:1297
#define GENDER_MAX
Definition: object.h:639
The 'empty_archetype' archetype.
Definition: arch.h:56
#define P_OUT_OF_MAP
Definition: map.h:305
void map_event_obj_init(object *ob)
Definition: plugins.c:370
uint8_t layer
Definition: object.h:405
struct obj * above
Definition: object.h:120
bool object_set_value(object *op, const char *key, const char *value, bool add_key)
Definition: object.c:2635
uint8_t item_quality
Definition: object.h:366
#define OUT_OF_MAP(M, X, Y)
Definition: map.h:240
#define P_FLY_ON
Definition: map.h:296
#define IS_LIVE(op)
Definition: define.h:841
Definition: living.h:67
#define PLAYER
Definition: define.h:122
#define FLAG_NO_DROP
Definition: define.h:1070
void object_weight_sub(object *op, uint32_t weight)
Definition: object.c:600
#define P_FLY_OFF
Definition: map.h:294
uint32_t path_attuned
Definition: object.h:255
#define UP_OBJ_ALL
Definition: object.h:541
#define OBJECT_FREE(_ob_)
Definition: object.h:554
void object_copy_full(object *op, const object *src)
Definition: object.c:970
#define OBJECTS_DESTROYED_BEGIN(...)
Definition: object.h:765
#define FLAG_IS_TURNABLE
Definition: define.h:960
static bool object_can_merge_key_values_one(const object *op, const object *cmp)
Definition: object.c:245
#define P_WALK_OFF
Definition: map.h:292
int map_free_spot(mapstruct *m, int x, int y, int start, int stop, archetype_t *at, object *op)
Definition: map.c:2942
mempool_struct * pool_player
Definition: player.c:52
#define FLAG_IS_FLOOR
Definition: define.h:1118
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
#define EVENT_OBJECT
Definition: define.h:481
uint32_t path_repelled
Definition: object.h:258
shstr * value
Definition: object.h:85
struct archetype * arch
Definition: object.h:225
struct obj * enemy
Definition: object.h:196
struct archetype * other_arch
Definition: object.h:228
void object_save(const object *op, FILE *fp)
Definition: object.c:3305
const char * object_flag_names[NUM_FLAGS+1]
Definition: object.c:153
#define EVENT_FLAG(x)
Definition: plugin.h:170
bool object_enter_map(object *op, object *exit, mapstruct *m, int x, int y, bool fixed_pos)
Definition: object.c:2956
uint8_t quickslot
Definition: object.h:411
object * object_find_type(object *op, uint8_t type)
Definition: object.c:2284
#define MAGIC_MIRROR
Definition: define.h:206
#define FLAG_SLOW_MOVE
Definition: define.h:916
void object_update(object *op, int action)
Definition: object.c:1117
uint8_t attack[NROFATTACKS]
Definition: object.h:436
object * object_get_env(object *op)
Definition: object.c:631
#define P_MAGIC_MIRROR
Definition: map.h:298
#define MEVENT_LEAVE
Definition: plugin.h:121
uint32_t flags[NUM_FLAGS_32]
Definition: object.h:270
#define FLAG_STARTEQUIP
Definition: define.h:1004
char * object_get_name_s(const object *op, const object *caller)
Definition: item.c:398
object * object_stack_get(object *op, uint32_t nrof)
Definition: object.c:2010
int object_move_on(object *op, object *victim, object *originator, int state)
#define FLAG_NO_FIX_PLAYER
Definition: define.h:1036
void update_position(mapstruct *m, int x, int y)
Definition: map.c:1706
#define FLAG_BEEN_APPLIED
Definition: define.h:934
#define P_BLOCKSVIEW
Definition: map.h:250
struct obj * chosen_skill
Definition: object.h:210
const char * title
Definition: object.h:171
#define FLAG_DAMNED
Definition: define.h:1158
int16_t y
Definition: object.h:276
#define P_DOOR_CLOSED
Definition: map.h:272
#define FLAG_OUTDOOR
Definition: define.h:1062
object * object_insert_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1741
uint32_t path_denied
Definition: object.h:261
archetype_t * arches[ARCH_MAX]
Definition: arch.c:45
#define P_IS_PLAYER
Definition: map.h:256
shstr * key
Definition: object.h:82
New_Face * inv_face
Definition: object.h:237
static bool object_set_value_s(object *op, shstr *key, const char *value, bool add_key)
Definition: object.c:2550
uint8_t sub_layer
Definition: object.h:408
#define GENDER_HERMAPHRODITE
Definition: object.h:637
int8_t direction
Definition: object.h:350
Definition: arch.h:40
char * object_get_base_name_s(const object *op, const object *caller)
Definition: item.c:534
uint8_t item_race
Definition: object.h:372
#define INS_FALL_THROUGH
Definition: object.h:575
#define FLAG_IS_ETHEREAL
Definition: define.h:892
uint8_t item_condition
Definition: object.h:369
struct sound_ambient_match * next
Next match rule in a linked list.
Definition: sound_ambient.c:39
uint32_t weight
Definition: object.h:246
#define ST1_CONTAINER_CORPSE_party
Definition: define.h:582
struct archetype * more
Next part of a linked object.
Definition: arch.h:42
#define FLAG_NO_PICK
Definition: define.h:900
int16_t z
Definition: object.h:286
object * object_clone(const object *op)
Definition: object.c:2385
#define GENDER_NEUTER
Definition: object.h:631
uint16_t animation_id
Definition: object.h:322
object * object_insert_into(object *op, object *where, int flag)
Definition: object.c:2158
int load_object(const char *str, object *op, int map_flags)
Definition: object.c:48527
char * object_get_short_name_s(const object *op, const object *caller)
Definition: item.c:453
struct mapdef * map
Definition: object.h:139
#define EVENT_QUEST
Definition: plugin.h:97
void object_free_key_values(object *op)
Definition: object.c:2456
struct obj * active_prev
Definition: object.h:111
#define FLAG_IS_INVISIBLE
Definition: define.h:888
object * object_stack_get_reinsert(object *op, uint32_t nrof)
Definition: object.c:2046
void monster_data_deinit(object *op)
Definition: monster_data.c:62
void object_owner_clear(object *op)
Definition: object.c:741
#define FLAG_UNPAID
Definition: define.h:1251
void object_weight_add(object *op, uint32_t weight)
Definition: object.c:568
#define BLANK_FACE_NAME
Definition: define.h:1480
object * object_load_str(const char *str)
Definition: object.c:2433
#define P_IS_EXIT
Definition: map.h:260
key_value_t * object_get_key_link(const object *op, shstr *key)
Definition: object.c:2487
#define FLAG_IS_MALE
Definition: define.h:1174
#define FLAG_WALK_OFF
Definition: define.h:964
int16_t dam
Definition: living.h:87
int maxfree[SIZEOFFREE]
Definition: object.c:114
uint32_t carrying
Definition: object.h:157
const char * name
Definition: object.h:168
#define SET_FLAG(xyz, p)
Definition: define.h:741
struct obj * env
Definition: object.h:130
#define MAP_PLAYER_MAP
Definition: map.h:40
#define P_OUTDOOR
Definition: map.h:300
static bool object_can_merge_key_values(const object *ob1, const object *ob2)
Definition: object.c:279
object * arch_to_object(archetype_t *at)
Definition: arch.c:446
void object_cb_deinit(object *op)
struct obj * below
Definition: object.h:114
#define REMOVE_NO_WEIGHT
Definition: object.h:585
#define CONTAINER
Definition: define.h:493
#define INS_NO_WALK_ON
Definition: object.h:570
int16_t last_grace
Definition: object.h:316
object * object_create_singularity(const char *name)
Definition: object.c:3281
#define P_NO_MAGIC
Definition: map.h:252
#define ST1_CONTAINER_CORPSE_player
Definition: define.h:577
#define FLAG_CAN_PASS_THRU
Definition: define.h:1058
uint32_t nrof
Definition: object.h:264
int object_blocked(object *op, mapstruct *m, int x, int y)
Definition: object.c:3224
#define MAP_SAVING
Definition: map.h:176
void object_cb_remove_map(object *op)
uint32_t damage_round_tag
Definition: object.h:149
int flags
Definition: map.h:381
int8_t item_power
Definition: object.h:442
#define IS_INVISIBLE(__ob_, __player_)
Definition: define.h:1356
#define OBJECTS_DESTROYED(obj)
Definition: object.h:811
#define ARROW
Definition: define.h:170
#define SPAWN_POINT_MOB
Definition: define.h:365
#define FLAG_FLYING
Definition: define.h:918
int trigger_map_event(int event_id, mapstruct *m, object *activator, object *other, object *other2, const char *text, int parm)
Definition: plugins.c:416
#define GEM
Definition: define.h:296
int freearr_y[SIZEOFFREE]
Definition: object.c:99
#define NUM_LAYERS
Definition: map.h:67
void object_destroy(object *op)
Definition: object.c:1441
#define FLAG_CORPSE
Definition: define.h:1288
#define FOR_MAP_LAYER_END
Definition: define.h:1657
double speed
Definition: object.h:469
#define OBJECT_EXPAND
Definition: config.h:139
void object_cb_insert_map(object *op)
object * object_stack_get_removed(object *op, uint32_t nrof)
Definition: object.c:2078
#define MAP_FIXEDLOGIN(m)
Definition: map.h:112
#define HEAD(op)
Definition: object.h:657
void esrv_del_item(object *op)
Definition: item.c:755
#define FOR_MAP_FINISH()
Definition: define.h:1759
#define ADD_REF_NOT_NULL_HASH(_nv_)
Definition: global.h:153
#define NUGGET
Definition: define.h:477
void object_deinit(void)
Definition: object.c:229
#define MAP_ENTER_Y(m)
Definition: map.h:131
void esrv_send_item(object *op)
Definition: item.c:703
#define P_PLAYER_ONLY
Definition: map.h:267
struct obj * active_next
Definition: object.h:103
#define FLAG_DOOR_CLOSED
Definition: define.h:1314
#define FLAG_NO_SKILL_IDENT
Definition: define.h:1194
int16_t x
Definition: object.h:273
#define NUM_SUB_LAYERS
Definition: map.h:71
void object_remove(object *op, int flags)
Definition: object.c:1623
#define FOR_MAP_LAYER_BEGIN(_m, _x, _y, _layer, _sub_layer, _obj)
Definition: define.h:1630
void object_drop_inventory(object *op)
Definition: object.c:1282
void adjust_light_source(mapstruct *map, int x, int y, int light)
Definition: light.c:257
int16_t last_eat
Definition: object.h:319
#define FLAG_REMOVED
Definition: define.h:930
int Ysize
Definition: random_map.h:77
#define TILED_DOWN
Definition: global.h:205
#define PEARL
Definition: define.h:292
bool object_is_in_inventory(const object *op, const object *inv)
Definition: object.c:655
mapstruct * generate_random_map(char *OutFileName, RMParms *RP)
Definition: random_map.c:72
int freearr_x[SIZEOFFREE]
Definition: object.c:84
#define SIZEOFFREE
Definition: define.h:660
Definition: race.h:36
void object_destruct(object *op)
Definition: object.c:1521
int Xsize
Definition: random_map.h:74
#define FLAG_NO_PVP
Definition: define.h:1166
#define FLAG_BLOCKSVIEW
Definition: define.h:1008
int object_get_gender(const object *op)
Definition: object.c:2877
int32_t timeout
Definition: map.h:617
#define MAP_NAME_SHARED
Definition: map.h:157
char origin_map[RM_SIZE]
Definition: random_map.h:59
#define FLAG_APPLIED
Definition: define.h:1182
object * object_merge(object *op)
Definition: object.c:479
#define GENDER_FEMALE
Definition: object.h:635
int8_t protection[NROFATTACKS]
Definition: object.h:439
void object_copy(object *op, const object *src, bool no_speed)
Definition: object.c:886
static int object_check_move_on(object *op, object *originator, int state)
Definition: object.c:1547
#define OBJECTS_DESTROYED_END()
Definition: object.h:816
#define INS_NO_MERGE
Definition: object.h:564
void object_owner_copy(object *op, object *src)
Definition: object.c:824
#define FLAG_CAN_STACK
Definition: define.h:1016
struct obj * owner
Definition: object.h:207
bool door_try_open(object *op, mapstruct *m, int x, int y, bool test)
Definition: door.c:231
#define NUM_ANIMATIONS(ob)
Definition: global.h:298
uint32_t update_tile
Definition: map.h:366
int object_matches_string(object *op, object *caller, const char *str)
Definition: object.c:2676
#define UP_OBJ_REMOVE
Definition: object.h:530
int origin_y
Definition: random_map.h:113
tag_t count
Definition: object.h:142
living stats
Definition: object.h:481
const char * gender_reflexive[GENDER_MAX]
Definition: object.c:77
void esrv_update_item(int flags, object *op)
Definition: item.c:639
static void object_owner_set_internal(object *op, object *owner)
Definition: object.c:758
#define P_WALK_ON
Definition: map.h:290
int attack_hit(object *op, object *hitter, int dam)
Definition: attack.c:669
#define P_CHECK_INV
Definition: map.h:276
object * active_objects
Definition: object.c:42
void object_update_turnable(object *op)
Definition: object.c:1021
uint8_t type
Definition: object.h:360
#define CLEAR_FLAG(xyz, p)
Definition: define.h:751
#define WEAPON
Definition: define.h:178
#define FLAG_BITMASK(p)
Definition: define.h:732
#define FLAG_OBJECT_WAS_MOVED
Definition: define.h:1339
shstr * name
More definite name, like "kobold".
Definition: arch.h:46
#define MAP_UNIQUE(m)
Definition: map.h:96
uint16_t terrain_flag
Definition: object.h:301
static void object_debugger(object *op, char *buf, size_t size)
Definition: object.c:186
#define FOOD
Definition: define.h:142
object * object_get(void)
Definition: object.c:993
#define FLAG_IS_PLAYER
Definition: define.h:1267
void object_owner_set(object *op, object *owner)
Definition: object.c:788
const char * msg
Definition: object.h:183
object * object_find_arch(object *op, archetype_t *at)
Definition: object.c:2258
int living_update(object *op)
Definition: living.c:1661
#define RUNE
Definition: define.h:522
#define MEVENT_ENTER
Definition: plugin.h:119
#define FLAG_MONSTER
Definition: define.h:922
object * player_first
Definition: map.h:594
#define OBJECT_VALID(_ob_, _count_)
Definition: object.h:548
#define MIN_ACTIVE_SPEED
Definition: define.h:1500
char * object_get_str_r(const object *op, char *buf, size_t bufsize)
Definition: object.c:3175
#define FLAG_IS_MAGICAL
Definition: define.h:1129
void player_save(object *op)
Definition: player.c:2379
int8_t glow_radius
Definition: object.h:338
struct obj * inv
Definition: object.h:123
shstr * artifact
Definition: object.h:187
struct obj * head
Definition: object.h:136
#define P_IS_MONSTER
Definition: map.h:258
const char * gender_possessive[GENDER_MAX]
Definition: object.c:71
shstr * custom_name
Definition: object.h:190
#define FLAG_USE_FIX_POS
Definition: define.h:1247
#define FLAG_WALK_ON
Definition: define.h:904
#define FLAG_NO_PASS
Definition: define.h:908
void object_cb_remove_inv(object *op)
#define DRINK
Definition: define.h:279
int map_free_spot_first(mapstruct *m, int x, int y, archetype_t *at, object *op)
Definition: map.c:3009
mapstruct * ready_map_name(const char *name, mapstruct *originator, int flags)
Definition: map.c:1584
bool arch_in_init
Definition: arch.c:50
#define NUM_FLAGS
Definition: define.h:1347
#define FLAG_IS_FEMALE
Definition: define.h:1178
#define FLAG_INV_LOCKED
Definition: define.h:1186
#define FLAG_PASS_THRU
Definition: define.h:1054
void attack_perform_fall(object *op, int fall_floors)
Definition: attack.c:1435
uint32_t event_flags
Definition: object.h:243
Definition: map.h:536
#define P_NO_PVP
Definition: map.h:280
int freedir[SIZEOFFREE]
Definition: object.c:129
New_Face * face
Definition: object.h:234
#define FREE_ONLY_HASH(_nv_)
Definition: global.h:143
const char * gender_noun[GENDER_MAX]
Definition: object.c:47
int origin_x
Definition: random_map.h:116
#define CHECK_INV
Definition: define.h:308
#define UP_OBJ_FLAGFACE
Definition: object.h:539
#define TERRAIN_ALL
Definition: define.h:692
int8_t level
Definition: object.h:347
#define MAP_EVENT_OBJ
Definition: define.h:506
const char * gender_subjective[GENDER_MAX]
Definition: object.c:53
mapstruct * get_map_from_tiled(mapstruct *m, int tiled)
Definition: map.c:1838
#define UP_OBJ_FLAGS
Definition: object.h:535
mapstruct * first_map
Definition: main.c:59
struct obj * more
Definition: object.h:133
uint16_t inv_animation_id
Definition: object.h:325
int64_t value
Definition: object.h:240
key_value_t * key_values
Definition: object.h:484
int8_t magic
Definition: object.h:341
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:1752
object clone
An object from which to do object_copy().
Definition: arch.h:47
time_t last
Last successful update.
Definition: metaserver.c:47
shstr * object_get_value(const object *op, const char *const key)
Definition: object.c:2515
void set_map_timeout(mapstruct *map)
Definition: main.c:124
void object_init(void)
Definition: object.c:211
#define FREE_AND_CLEAR_HASH2(_nv_)
Definition: global.h:162
void object_destroy_inv(object *op)
Definition: object.c:1414
shstr * glow
Definition: object.h:193
#define FLAG_IDENTIFIED
Definition: define.h:980
const char * gender_subjective_upper[GENDER_MAX]
Definition: object.c:59
int16_t food
Definition: living.h:84
uint8_t sub_type
Definition: object.h:363
void object_dump_rec(const object *op, StringBuffer *sb)
Definition: object.c:711