Crossfire Server, Trunk
item.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 
22 #include "global.h"
23 
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "living.h"
30 #include "spells.h"
31 
55  { "body_range", "in your range slot", "in a human's range slot" },
56  { "body_arm", "on your arm", "on a human's arm" },
57  { "body_torso", "on your body", "on a human's torso" },
58  { "body_head", "on your head", "on a human's head" },
59  { "body_neck", "around your neck", "around a human's neck" },
60  { "body_skill", "in your skill slot", "in a human's skill slot" },
61  { "body_finger", "on your finger", "on a human's finger" },
62  { "body_shoulder", "around your shoulders", "around a human's shoulders" },
63  { "body_foot", "on your feet", "on a human's feet" },
64  { "body_hand", "on your hands", "on a human's hands" },
65  { "body_wrist", "around your wrists", "around a human's wrist" },
66  { "body_waist", "around your waist", "around a human's waist" },
67  { "body_leg", "around your legs", "around a human's legs" },
68  /*{"body_dragon_torso", "your body", "a dragon's body"} */
69 };
70 
78 static const typedata item_types[] = {
79  { 0, "none", "none", 0, 0 },
80  { PLAYER, "player", "players", 0, 0 },
81  { TRANSPORT, "transport", "transports", 0, 0 },
82  { ROD, "rod", "rods", SK_THAUMATURGY, 0 },
83  { TREASURE, "treasure", "treasure", 0, 0 },
84  { POTION, "potion", "potions", SK_ALCHEMY, 0 },
85  { FOOD, "food", "food", SK_WOODSMAN, 0 },
86  { POISON, "poison", "poisons", SK_ALCHEMY, 0 },
87  { BOOK, "book", "books", SK_LITERACY, 0 },
88  { CLOCK, "clock", "clocks", 0, 0 },
89  { ARROW, "arrow", "arrows", SK_BOWYER, 0 },
90  { BOW, "bow", "bows", SK_BOWYER, 0 },
91  { WEAPON, "weapon", "weapons", SK_SMITHERY, 0 },
92  { ARMOUR, "armour", "armour", SK_SMITHERY, 0 },
93  { PEDESTAL, "pedestal", "pedestals", 0, 0 },
94  { ALTAR, "altar", "altars", 0, 0 },
95  { LOCKED_DOOR, "locked door", "locked doors", 0, 0 },
96  { SPECIAL_KEY, "special key", "special keys", 0, 0 },
97  { MAP, "map", "maps", 0, 0 },
98  { DOOR, "door", "doors", 0, 0 },
99  { KEY, "key", "keys", 0, 0 },
100  { TIMED_GATE, "timed_gate", "timed_gates", 0, 0 },
101  { TRIGGER, "trigger", "triggers", 0, 0 },
102  { GRIMREAPER, "grimreaper", "grimreapers", 0, 0 },
103  { MAGIC_EAR, "magic ear", "magic ears", 0, 0 },
104  { TRIGGER_BUTTON, "trigger button", "trigger buttons", 0, 0 },
105  { TRIGGER_ALTAR, "trigger altar", "trigger altars", 0, 0 },
106  { TRIGGER_PEDESTAL, "trigger pedestal", "trigger pedestals", 0, 0 },
107  { SHIELD, "shield", "shields", SK_SMITHERY, 0 },
108  { HELMET, "helmet", "helmets", SK_SMITHERY, 0 },
109  { MONEY, "money", "money", 0, 0 },
110  { CLASS, "class", "classes", 0, 0 },
111  { AMULET, "amulet", "amulets", SK_JEWELER, 0 },
112  { PLAYERMOVER, "player mover", "player movers", 0, 0 },
113  { TELEPORTER, "teleporter", "teleporters", 0, 0 },
114  { CREATOR, "creator", "creators", 0, 0 },
115  { SKILL, "skill", "skills", 0, 0 },
116  { EARTHWALL, "earthwall", "earthwalls", 0, 0 },
117  { GOLEM, "golem", "golems", 0, 0 },
118  { THROWN_OBJ, "projectile", "projectiles", 0, 0 },
119  { BLINDNESS, "blindness", "blindness", 0, 0 },
120  { GOD, "god", "gods", 0, 0 },
121  { DETECTOR, "detector", "detectors", 0, 0 },
122  { TRIGGER_MARKER, "trigger marker", "trigger markers", 0, 0 },
123  { DEAD_OBJECT, "dead object", "dead objects", 0, 0 },
124  { DRINK, "drink", "drinks", SK_WOODSMAN, SK_ALCHEMY },
125  { MARKER, "marker", "markers", 0, 0 },
126  { HOLY_ALTAR, "holy altar", "holy altars", 0, 0 },
127  { PLAYER_CHANGER, "player changer", "player changers", 0, 0 },
128  { BATTLEGROUND, "battleground", "battlegrounds", 0, 0 },
129  { PEACEMAKER, "peacemaker", "peacemakers", 0, 0 },
130  { GEM, "gem", "gems", SK_JEWELER, 0 },
131  { FIREWALL, "firewall", "firewalls", 0, 0 },
132  { CHECK_INV, "inventory checker", "inventory checkers", 0, 0 },
133  { MOOD_FLOOR, "mood floor", "mood floors", 0, 0 },
134  { EXIT, "exit", "exits", 0, 0 },
135  { ENCOUNTER, "encounter", "encounters", 0, 0 },
136  { SHOP_FLOOR, "shop floor", "shop floors", 0, 0 },
137  { SHOP_MAT, "shop mat", "shop mats", 0, 0 },
138  { RING, "ring", "rings", SK_JEWELER, 0 },
139  { FLOOR, "floor", "floors", 0, 0 },
140  { FLESH, "flesh", "flesh", SK_WOODSMAN, 0 },
141  { INORGANIC, "inorganic", "inorganics", SK_ALCHEMY, 0 },
142  { SKILL_TOOL, "skill tool", "skill tools", 0, 0 },
143  { LIGHTER, "lighter", "lighters", 0, 0 },
144  { WALL, "wall", "walls", 0, 0 },
145  { MISC_OBJECT, "bric-a-brac", "bric-a-brac", 0, 0 },
146  { MONSTER, "monster", "monsters", 0, 0 },
147  { LAMP, "lamp", "lamps", 0, 0 },
148  { DUPLICATOR, "duplicator", "duplicators", 0, 0 },
149  { SPELLBOOK, "spellbook", "spellbooks", SK_LITERACY, 0 },
150  { CLOAK, "cloak", "cloaks", SK_SMITHERY, 0 },
151  { SPINNER, "spinner", "spinners", 0, 0 },
152  { GATE, "gate", "gates", 0, 0 },
153  { BUTTON, "button", "buttons", 0, 0 },
154  { CF_HANDLE, "cf handle", "cf handles", 0, 0 },
155  { HOLE, "hole", "holes", 0, 0 },
156  { TRAPDOOR, "trapdoor", "trapdoors", 0, 0 },
157  { SIGN, "sign", "signs", 0, 0 },
158  { BOOTS, "boots", "boots", SK_SMITHERY, 0 },
159  { GLOVES, "gloves", "gloves", SK_SMITHERY, 0 },
160  { SPELL, "spell", "spells", 0, 0 },
161  { SPELL_EFFECT, "spell effect", "spell effects", 0, 0 },
162  { CONVERTER, "converter", "converters", 0, 0 },
163  { BRACERS, "bracers", "bracers", SK_SMITHERY, 0 },
164  { POISONING, "poisoning", "poisonings", 0, 0 },
165  { SAVEBED, "savebed", "savebeds", 0, 0 },
166  { WAND, "wand", "wands", SK_THAUMATURGY, 0 },
167  { SCROLL, "scroll", "scrolls", SK_LITERACY, 0 },
168  { DIRECTOR, "director", "directors", 0, 0 },
169  { GIRDLE, "girdle", "girdles", SK_SMITHERY, 0 },
170  { FORCE, "force", "forces", 0, 0 },
171  { POTION_RESIST_EFFECT, "potion effect", "potion effects", 0, 0 },
172  { CLOSE_CON, "closed container", "closed container", SK_ALCHEMY, 0 },
173  { CONTAINER, "container", "containers", SK_ALCHEMY, 0 },
174  { ARMOUR_IMPROVER, "armour improver", "armour improvers", SK_LITERACY, 0 },
175  { WEAPON_IMPROVER, "weapon improver", "weapon improvers", SK_LITERACY, 0 },
176  { SKILLSCROLL, "skillscroll", "skillscrolls", SK_LITERACY, 0 },
177  { DEEP_SWAMP, "deep swamp", "deep swamps", 0, 0 },
178  { IDENTIFY_ALTAR, "identify altar", "identify altars", 0, 0 },
179  { SHOP_INVENTORY, "inventory list", "inventory lists", 0, 0 },
180  { RUNE, "rune", "runes", 0, 0 },
181  { TRAP, "trap", "traps", 0, 0 },
182  { POWER_CRYSTAL, "power_crystal", "power_crystals", SK_THAUMATURGY, 0 },
183  { CORPSE, "corpse", "corpses", 0, 0 },
184  { DISEASE, "disease", "diseases", 0, 0 },
185  { SYMPTOM, "symptom", "symptoms", 0, 0 },
186  { BUILDER, "item builder", "item builders", 0, 0 },
187  { MATERIAL, "building material", "building materials", 0, 0 },
188  { MIMIC, "mimic", "mimics", SK_ALCHEMY, 0 },
189  { LIGHTABLE, "lightable", "lightables", 0, 0 },
190 };
191 
193 static const int item_types_size = sizeof(item_types)/sizeof(*item_types);
194 
204 static const int enc_to_item_power[] = {
205  0, 0, 1, 2, 3, 4, /* 5 */
206  5, 7, 9, 11, 13, /* 10 */
207  15, 18, 21, 24, 27, /* 15 */
208  30, 35, 40, 45, 50 /* 20 */
209 };
210 
211 int get_power_from_ench(int ench) {
212  if (ench < 0)
213  ench = 0;
214  if (ench > (int)(sizeof(enc_to_item_power)/sizeof(*enc_to_item_power)-1))
215  ench = sizeof(enc_to_item_power)/sizeof(*enc_to_item_power)-1;
216  return enc_to_item_power[ench];
217 }
218 
219 static int bits_set(uint32_t x, int start, int end) {
220  int enc = 0;
221  for (int i = start; i < end; i++) {
222  if (x&(1<<i)) {
223  enc++;
224  }
225  }
226  return enc;
227 }
228 
239 int calc_item_power(const object *op) {
240  int i, tmp, enc;
241 
242  // If we get, for example, a pile of gypsum here,
243  // don't give it an item power. Nothing in the inorganic
244  // type can be applied; their resistances are just to avoid
245  // or encourage destruction by specific attacktypes.
246  if (op->type == INORGANIC)
247  return 0;
248 
249  enc = 0;
250  for (i = 0; i < NUM_STATS; i++)
251  enc += get_attr_value(&op->stats, i);
252 
253  /* This protection logic is pretty flawed. 20% fire resistance
254  * is much more valuable than 20% confusion, or 20% slow, or
255  * several others. Start at 1 - ignore physical - all that normal
256  * armour shouldn't be counted against
257  */
258  tmp = 0;
259  for (i = 1; i < NROFATTACKS; i++)
260  tmp += op->resist[i];
261 
262  /* Add/substract 10 so that the rounding works out right */
263  if (tmp > 0)
264  enc += (tmp+10)/20;
265  else if (tmp < 0)
266  enc += (tmp-10)/20;
267 
268  enc += op->magic;
269 
270  /* For each attacktype a weapon has, one more encantment. Start at 1 -
271  * physical doesn't count against total.
272  */
273  if (op->type == WEAPON) {
274  enc += bits_set(op->attacktype, 1, NROFATTACKS);
275  if (op->slaying)
276  enc += 2; /* What it slays is probably more relevent */
277  }
278  /* Items the player can equip */
279  if ((op->type == WEAPON)
280  || (op->type == ARMOUR)
281  || (op->type == HELMET)
282  || (op->type == SHIELD)
283  || (op->type == RING)
284  || (op->type == BOOTS)
285  || (op->type == GLOVES)
286  || (op->type == AMULET)
287  || (op->type == GIRDLE)
288  || (op->type == BRACERS)
289  || (op->type == CLOAK)) {
290  enc += op->stats.food; /* sustenance */
291  enc += op->stats.hp; /* hp regen */
292  enc += op->stats.sp; /* mana regen */
293  enc += op->stats.grace; /* grace regen */
294  enc += op->stats.exp; /* speed bonus */
295  }
296  enc += op->stats.luck;
297 
298  /* Do spell paths now */
299  enc += bits_set(op->path_attuned, 1, NRSPELLPATHS);
300  enc -= bits_set(op->path_repelled, 1, NRSPELLPATHS);
301  enc -= 2*bits_set(op->path_denied, 1, NRSPELLPATHS);
302 
304  enc += 5;
306  enc += 3;
308  enc += 2;
309  if (QUERY_FLAG(op, FLAG_STEALTH))
310  enc += 1;
311  if (QUERY_FLAG(op, FLAG_XRAYS))
312  enc += 2;
314  enc += 1;
316  enc += 1;
317 
318  return get_power_from_ench(enc);
319 }
320 
327 const typedata *get_typedata(int itemtype) {
328  int i;
329 
330  for (i = 0; i < item_types_size; i++)
331  if (item_types[i].number == itemtype)
332  return &item_types[i];
333  return NULL;
334 }
335 
347 const typedata *get_typedata_by_name(const char *name) {
348  int i;
349 
350  for (i = 0; i < item_types_size; i++)
351  if (!strcmp(item_types[i].name, name))
352  return &item_types[i];
353  for (i = 0; i < item_types_size; i++)
354  if (!strcmp(item_types[i].name_pl, name)) {
355  LOG(llevInfo, "get_typedata_by_name: I have been sent the plural %s, the singular form %s is preffered\n", name, item_types[i].name);
356  return &item_types[i];
357  }
358  return NULL;
359 }
360 
376 StringBuffer *describe_resistance(const object *op, int newline, int use_media_tags, StringBuffer *buf) {
377  int tmpvar;
378 
379  if (buf == NULL)
380  buf = stringbuffer_new();
381 
382  for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++) {
383  if (op->resist[tmpvar] && (op->type != FLESH || atnr_is_dragon_enabled(tmpvar) == 1)) {
384  if (use_media_tags) {
385  if (resist_color[tmpvar] != NULL) {
386  stringbuffer_append_printf(buf, "[color=%s]", resist_color[tmpvar]);
387  }
388  if (op->resist[tmpvar] == 100 || op->resist[tmpvar] == -100) {
390  }
391  }
392  if (!newline)
393  stringbuffer_append_printf(buf, "(%s %+d)", resist_plus[tmpvar], op->resist[tmpvar]);
394  else
395  stringbuffer_append_printf(buf, "%s %d\n", resist_plus[tmpvar], op->resist[tmpvar]);
396  if (use_media_tags) {
397  if (op->resist[tmpvar] == 100 || op->resist[tmpvar] == -100) {
399  }
400  if (resist_color[tmpvar] != NULL) {
401  stringbuffer_append_string(buf, "[/color]");
402  }
403  }
404  }
405  }
406 
407  return buf;
408 }
409 
419 void query_weight(const object *op, char *buf, size_t size) {
420  int32_t i = NROF(op)*op->weight+op->carrying;
421 
422  if (op->weight < 0)
423  snprintf(buf, size, " ");
424  else if (i%1000)
425  snprintf(buf, size, "%6.1f", i/1000.0);
426  else
427  snprintf(buf, size, "%4d ", i/1000);
428 }
429 
442 static StringBuffer *ring_desc(const object *op, int use_media_tags, StringBuffer *buf) {
443  int attr, val;
444  size_t len;
445 
446  assert(op != NULL);
447  assert(op->type == RING || op->type == AMULET || op->type == SKILL);
448 
449  if (buf == NULL)
450  buf = stringbuffer_new();
451  len = stringbuffer_length(buf);
452 
454  return buf;
455 
456  for (attr = 0; attr < NUM_STATS; attr++) {
457  if ((val = get_attr_value(&(op->stats), attr)) != 0) {
458  stringbuffer_append_printf(buf, "(%s%+d)", short_stat_name[attr], val);
459  }
460  }
461  if (op->stats.exp)
462  stringbuffer_append_printf(buf, "(speed %+" FMT64 ")", op->stats.exp);
463  if (op->stats.wc)
464  stringbuffer_append_printf(buf, "(wc%+d)", op->stats.wc);
465  if (op->stats.dam)
466  stringbuffer_append_printf(buf, "(dam%+d)", op->stats.dam);
467  if (op->stats.ac)
468  stringbuffer_append_printf(buf, "(ac%+d)", op->stats.ac);
469 
470  describe_resistance(op, 0, use_media_tags, buf);
471 
472  if (op->stats.food != 0)
473  stringbuffer_append_printf(buf, "(sustenance%+d)", op->stats.food);
474  if (op->stats.grace)
475  stringbuffer_append_printf(buf, "(grace%+d)", op->stats.grace);
476  if (op->stats.sp && op->type != SKILL)
477  stringbuffer_append_printf(buf, "(magic%+d)", op->stats.sp);
478  if (op->stats.hp)
479  stringbuffer_append_printf(buf, "(regeneration%+d)", op->stats.hp);
480  if (op->stats.luck)
481  stringbuffer_append_printf(buf, "(luck%+d)", op->stats.luck);
483  stringbuffer_append_printf(buf, "(lifesaving)");
485  stringbuffer_append_printf(buf, "(reflect spells)");
487  stringbuffer_append_printf(buf, "(reflect missiles)");
488  if (QUERY_FLAG(op, FLAG_STEALTH))
489  stringbuffer_append_printf(buf, "(stealth)");
490  if (op->glow_radius)
491  stringbuffer_append_string(buf, "(glowing)");
492 
493  describe_spellpath_attenuation("Attuned", op->path_attuned, buf);
494  describe_spellpath_attenuation("Repelled", op->path_repelled, buf);
495  describe_spellpath_attenuation("Denied", op->path_denied, buf);
496 
497  /* item_power is done by the caller */
498  /* if (op->item_power)
499  snprintf(buf+strlen(buf), size-strlen(buf), "(item_power %+d)", op->item_power);*/
500  if (stringbuffer_length(buf) == len && op->type != SKILL)
501  stringbuffer_append_string(buf, "of adornment");
502 
503  return buf;
504 }
505 
517 void query_short_name(const object *op, char *buf, size_t size) {
518  size_t len = 0;
519 
520  if (op->name == NULL) {
521  snprintf(buf, size, "(null)");
522  return;
523  }
524  if (!op->nrof && !op->weight && !op->title && !is_magical(op)) {
525  strlcpy(buf, op->name, size); /* To speed things up (or make things slower?) */
526  return;
527  }
528  buf[0] = '\0';
529 
530  if (op->nrof <= 1)
531  safe_strcat(buf, op->name, &len, size);
532  else
533  safe_strcat(buf, op->name_pl, &len, size);
534 
535  if (op->title && QUERY_FLAG(op, FLAG_IDENTIFIED)) {
536  safe_strcat(buf, " ", &len, size);
537  safe_strcat(buf, op->title, &len, size);
538  }
539 
540  switch (op->type) {
541  case SPELLBOOK:
542  case SCROLL:
543  case WAND:
544  case ROD:
546  if (!op->title && (op->inv)) {
547  safe_strcat(buf, " of ", &len, size);
548  safe_strcat(buf, op->inv->name, &len, size);
549  }
550  if (op->type != SPELLBOOK) {
551  snprintf(buf+len, size-len, " (lvl %d)", op->level);
552  len += strlen(buf+len);
553  }
554  }
555  break;
556 
557  case SKILL:
558  case AMULET:
559  case RING:
560  if (!op->title) {
561  /* If ring has a title, full description isn't so useful */
562  char* desc;
563 
564  desc = stringbuffer_finish(ring_desc(op, 0, NULL));
565  if (desc[0]) {
566  safe_strcat(buf, " ", &len, size);
567  safe_strcat(buf, desc, &len, size);
568  }
569  free(desc);
570  }
571  break;
572 
573  default:
574  if (op->magic
576  snprintf(buf+len, size-len, " %+d", op->magic);
577  len += strlen(buf+len);
578  }
579  }
580 }
581 
592 void query_name(const object *op, char *buf, size_t size) {
593  size_t len = 0;
594 
595  buf[0] = '\0';
596  /*
597  * Since len is initialized to zero, but is not changed
598  * up to this point, I see no reason to have buf+len and size-len;
599  * buf and size should suffice, since we're just adding and
600  * subtracting zero here, anyway.
601  *
602  * SilverNexus 2014-06-04
603  */
604  query_short_name(op, buf, size);
605  len = strlen(buf);
606 
608  safe_strcat(buf, " *", &len, size);
609  if (op->type == CONTAINER
610  && ((op->env && op->env->container == op) || (!op->env && QUERY_FLAG(op, FLAG_APPLIED))))
611  safe_strcat(buf, " (open)", &len, size);
612 
614  if (QUERY_FLAG(op, FLAG_DAMNED))
615  safe_strcat(buf, " (damned)", &len, size);
616  else if (QUERY_FLAG(op, FLAG_CURSED))
617  safe_strcat(buf, " (cursed)", &len, size);
618  }
620  safe_strcat(buf, " (blessed)", &len, size);
621 
622  /* Basically, if the object is known magical (detect magic spell on it),
623  * and it isn't identified, print out the fact that
624  * it is magical. Assume that the detect magical spell will only set
625  * KNOWN_MAGICAL if the item actually is magical.
626  *
627  * Changed in V 0.91.4 - still print that the object is magical even
628  * if it has been applied. Equipping an item does not tell full
629  * abilities, especially for artifact items.
630  */
632  safe_strcat(buf, " (magic)", &len, size);
633 
634  if (QUERY_FLAG(op, FLAG_APPLIED)) {
635  switch (op->type) {
636  case BOW:
637  case WAND:
638  case ROD:
639  safe_strcat(buf, " (readied)", &len, size);
640  break;
641 
642  case WEAPON:
643  safe_strcat(buf, " (wielded)", &len, size);
644  break;
645 
646  case ARMOUR:
647  case HELMET:
648  case SHIELD:
649  case RING:
650  case BOOTS:
651  case GLOVES:
652  case AMULET:
653  case GIRDLE:
654  case BRACERS:
655  case CLOAK:
656  safe_strcat(buf, " (worn)", &len, size);
657  break;
658 
659  case CONTAINER:
660  safe_strcat(buf, " (active)", &len, size);
661  break;
662 
663  case SKILL:
664  default:
665  safe_strcat(buf, " (applied)", &len, size);
666  }
667  }
668  // NO_SKILL_IDENT is set when identification fails or when the book is read. So the book is read only when it is
669  // both identified and NO_SKILL_IDENT.
671  safe_strcat(buf, " (read)", &len, size);
672  if (QUERY_FLAG(op, FLAG_UNPAID))
673  safe_strcat(buf, " (unpaid)", &len, size);
674 }
675 
693 void query_base_name(const object *op, int plural, char *buf, size_t size) {
694  size_t len;
695 
696  if ((!plural && !op->name)
697  || (plural && !op->name_pl)) {
698  strncpy(buf, "(null)", size);
699  return;
700  }
701 
702  if (!op->nrof && !op->weight && !op->title && !is_magical(op)) {
703  strncpy(buf, op->name, size); /* To speed things up (or make things slower?) */
704  return;
705  }
706 
707  buf[0] = '\0';
708 
709  strlcpy(buf, plural ? op->name_pl : op->name, size);
710  len = strlen(buf);
711 
712  if (op->title && QUERY_FLAG(op, FLAG_IDENTIFIED)) {
713  safe_strcat(buf, " ", &len, size);
714  safe_strcat(buf, op->title, &len, size);
715  }
716 
717  switch (op->type) {
718  case SPELLBOOK:
719  case SCROLL:
720  case WAND:
721  case ROD:
723  if (!op->title && (op->inv)) {
724  safe_strcat(buf, " of ", &len, size);
725  // If, for some reason, a spell on a scroll were to stop existing as an arch,
726  // we would get here. The scroll will hold an inventory object with no name.
727  // So, to prevent a segfault, only print the spell name if it exists.
728  if (op->inv->name)
729  safe_strcat(buf, op->inv->name, &len, size);
730  // scroll of nothing seems like a good replacement for when the name does not exist.
731  else
732  safe_strcat(buf, "nothing", &len, size);
733  }
734  if (op->type != SPELLBOOK) {
735  snprintf(buf+len, size-len, " (lvl %d)", op->level);
736  len += strlen(buf+len);
737  }
738  }
739  break;
740 
741  case SKILL:
742  case AMULET:
743  case RING:
744  if (!op->title) {
745  /* If ring has a title, full description isn't so useful */
746  char* s;
747 
748  s = stringbuffer_finish(ring_desc(op, 0, NULL));
749  if (s[0]) {
750  safe_strcat(buf, " ", &len, size);
751  safe_strcat(buf, s, &len, size);
752  }
753  free(s);
754  }
755  break;
756 
757  default:
758  if (op->magic
760  snprintf(buf+strlen(buf), size-strlen(buf), " %+d", op->magic);
761  }
762  }
763 }
764 
781 StringBuffer *describe_monster(const object *op, int use_media_tags, StringBuffer *buf) {
782  assert(op != NULL);
783  assert(QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER);
784 
785  if (buf == NULL)
786  buf = stringbuffer_new();
787 
788  /* Note that the resolution this provides for players really isn't
789  * very good. Any player with a speed greater than .67 will
790  * fall into the 'lightning fast movement' category.
791  */
792  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
793  switch ((int)((FABS(op->speed))*15)) {
794  case 0:
795  stringbuffer_append_string(buf, "(very slow movement)");
796  break;
797 
798  case 1:
799  stringbuffer_append_string(buf, "(slow movement)");
800  break;
801 
802  case 2:
803  stringbuffer_append_string(buf, "(normal movement)");
804  break;
805 
806  case 3:
807  case 4:
808  stringbuffer_append_string(buf, "(fast movement)");
809  break;
810 
811  case 5:
812  case 6:
813  stringbuffer_append_string(buf, "(very fast movement)");
814  break;
815 
816  case 7:
817  case 8:
818  case 9:
819  case 10:
820  stringbuffer_append_string(buf, "(extremely fast movement)");
821  break;
822 
823  default:
824  stringbuffer_append_string(buf, "(lightning fast movement)");
825  break;
826  }
827  }
828  if (QUERY_FLAG(op, FLAG_UNDEAD))
829  stringbuffer_append_string(buf, "(undead)");
831  stringbuffer_append_string(buf, "(see invisible)");
833  stringbuffer_append_string(buf, "(wield weapon)");
834  if (QUERY_FLAG(op, FLAG_USE_BOW))
835  stringbuffer_append_string(buf, "(archer)");
837  stringbuffer_append_string(buf, "(wear armour)");
839  stringbuffer_append_string(buf, "(wear ring)");
841  stringbuffer_append_string(buf, "(read scroll)");
843  stringbuffer_append_string(buf, "(fires wand/rod/horn)");
845  stringbuffer_append_string(buf, "(skill user)");
847  stringbuffer_append_string(buf, "(spellcaster)");
849  stringbuffer_append_string(buf, "(friendly)");
851  stringbuffer_append_string(buf, "(unaggressive)");
852  if (QUERY_FLAG(op, FLAG_HITBACK))
853  stringbuffer_append_string(buf, "(hitback)");
854  if (QUERY_FLAG(op, FLAG_STEALTH))
855  stringbuffer_append_string(buf, "(stealthy)");
856  if (op->randomitems != NULL) {
857  treasure *t;
858  int first = 1;
859 
860  for (t = op->randomitems->items; t != NULL; t = t->next)
861  if (t->item && (t->item->clone.type == SPELL)) {
862  if (first) {
863  first = 0;
864  stringbuffer_append_string(buf, "(Spell abilities:)");
865  }
866  stringbuffer_append_printf(buf, "(%s)", t->item->clone.name);
867  }
868  }
869  if (op->type == PLAYER) {
870  if (op->contr->digestion) {
871  if (op->contr->digestion != 0)
872  stringbuffer_append_printf(buf, "(sustenance%+d)", op->contr->digestion);
873  }
874  if (op->contr->gen_grace) {
875  stringbuffer_append_printf(buf, "(grace%+d)", op->contr->gen_grace);
876  }
877  if (op->contr->gen_sp) {
878  stringbuffer_append_printf(buf, "(magic%+d)", op->contr->gen_sp);
879  }
880  if (op->contr->gen_hp) {
881  stringbuffer_append_printf(buf, "(regeneration%+d)", op->contr->gen_hp);
882  }
883  if (op->stats.luck) {
884  stringbuffer_append_printf(buf, "(luck%+d)", op->stats.luck);
885  }
886  }
887 
888  /* describe attacktypes */
889  if (is_dragon_pl(op)) {
890  /* for dragon players display the attacktypes from clawing skill
891  * Break apart the for loop - move the comparison checking down -
892  * this makes it more readable.
893  */
894  object *tmp;
895 
896  tmp = object_find_by_type_and_name(op, SKILL, "clawing");
897  if (tmp && tmp->attacktype != 0) {
898  describe_attacktype("Claws", tmp->attacktype, buf);
899  } else {
900  describe_attacktype("Attacks", op->attacktype, buf);
901  }
902  } else {
903  describe_attacktype("Attacks", op->attacktype, buf);
904  }
905  describe_spellpath_attenuation("Attuned", op->path_attuned &~ op->path_denied, buf);
906  describe_spellpath_attenuation("Repelled", op->path_repelled &~ op->path_denied, buf );
907  describe_spellpath_attenuation("Denied", op->path_denied, buf);
908  describe_resistance(op, 0, use_media_tags, buf);
909 
910  return buf;
911 }
912 
955 StringBuffer *describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf) {
956  int identified, i;
957 
958  if (buf == NULL)
959  buf = stringbuffer_new();
960 
961  if (QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER) {
962  return describe_monster(op, use_media_tags, buf);
963  }
964 
965  /* figure this out once, instead of making multiple calls to is_identified.
966  * also makes the code easier to read.
967  */
968  if (is_identified(op)) {
969  identified = 1;
970  } else {
971  stringbuffer_append_string(buf, "(unidentified)");
972  identified = 0;
973  }
974  switch (op->type) {
975  case BOW:
976  case ARROW:
977  case WAND:
978  case ROD:
979  case WEAPON:
980  case ARMOUR:
981  case HELMET:
982  case SHIELD:
983  case BOOTS:
984  case GLOVES:
985  case GIRDLE:
986  case BRACERS:
987  case CLOAK:
988  case SKILL_TOOL:
989  break; /* We have more information to do below this switch */
990 
991  case LAMP:
992  break; /* just so we get the "glowing" part. */
993 
994  case FOOD:
995  case FLESH:
996  case DRINK:
997  if (identified || QUERY_FLAG(op, FLAG_BEEN_APPLIED)) {
998  stringbuffer_append_printf(buf, "(food+%d)", op->stats.food);
999 
1000  if (op->type == FLESH && op->last_eat > 0 && atnr_is_dragon_enabled(op->last_eat)) {
1001  stringbuffer_append_printf(buf, "(%s metabolism)", change_resist_msg[op->last_eat]);
1002  }
1003 
1004  if (!QUERY_FLAG(op, FLAG_CURSED)) {
1005  if (op->stats.hp)
1006  stringbuffer_append_string(buf, "(heals)");
1007  if (op->stats.sp)
1008  stringbuffer_append_string(buf, "(spellpoint regen)");
1009  } else {
1010  if (op->stats.hp)
1011  stringbuffer_append_string(buf, "(damages)");
1012  if (op->stats.sp)
1013  stringbuffer_append_string(buf, "(spellpoint depletion)");
1014  }
1015  }
1016  break;
1017 
1018  case SKILL:
1019  case RING:
1020  case AMULET:
1021  if (op->item_power) {
1022  stringbuffer_append_printf(buf, "(item_power %+d)", op->item_power);
1023  }
1024  if (op->title) {
1025  ring_desc(op, use_media_tags, buf);
1026  }
1027  return buf;
1028 
1029  default:
1030  return buf;
1031  }
1032 
1033  /* Down here, we more further describe equipment type items.
1034  * only describe them if they have been identified or the like.
1035  */
1036  if (identified || QUERY_FLAG(op, FLAG_BEEN_APPLIED)) {
1037  int attr, val;
1038 
1039  for (attr = 0; attr < NUM_STATS; attr++) {
1040  if ((val = get_attr_value(&(op->stats), attr)) != 0) {
1041  stringbuffer_append_printf(buf, "(%s%+d)", short_stat_name[attr], val);
1042  }
1043  }
1044  if (op->glow_radius)
1045  stringbuffer_append_string(buf, "(glowing)");
1046 
1047  switch (op->type) {
1048  case FLESH:
1049  break;
1050 
1051  default:
1052  if (op->stats.exp) {
1053  stringbuffer_append_printf(buf, "(speed %+" FMT64 ")", op->stats.exp);
1054  }
1055  break;
1056  }
1057  switch (op->type) {
1058  case BOW:
1059  case ARROW:
1060  case GIRDLE:
1061  case HELMET:
1062  case SHIELD:
1063  case BOOTS:
1064  case GLOVES:
1065  case WEAPON:
1066  case SKILL:
1067  case RING:
1068  case AMULET:
1069  case ARMOUR:
1070  case BRACERS:
1071  case FORCE:
1072  case CLOAK:
1073  if (op->stats.wc) {
1074  stringbuffer_append_printf(buf, "(wc%+d)", op->stats.wc);
1075  }
1076  if (op->stats.dam) {
1077  stringbuffer_append_printf(buf, "(dam%+d)", op->stats.dam);
1078  }
1079  if (op->stats.ac) {
1080  stringbuffer_append_printf(buf, "(ac%+d)", op->stats.ac);
1081  }
1082  if ((op->type == WEAPON || op->type == BOW) && op->level > 0) {
1083  stringbuffer_append_printf(buf, "(improved %d/%d)", op->last_eat, op->level);
1084  }
1085  break;
1086 
1087  default:
1088  break;
1089  }
1090  if (QUERY_FLAG(op, FLAG_XRAYS))
1091  stringbuffer_append_string(buf, "(xray-vision)");
1093  stringbuffer_append_string(buf, "(infravision)");
1094 
1095  /* levitate was what is was before, so we'll keep it */
1096  if (op->move_type&MOVE_FLY_LOW)
1097  stringbuffer_append_string(buf, "(levitate)");
1098 
1099  if (op->move_type&MOVE_FLY_HIGH)
1100  stringbuffer_append_string(buf, "(fly)");
1101 
1102  if (op->move_type&MOVE_SWIM)
1103  stringbuffer_append_string(buf, "(swim)");
1104 
1105  /* walking is presumed as 'normal', so doesn't need mentioning */
1106 
1107  if (op->item_power) {
1108  stringbuffer_append_printf(buf, "(item_power %+d)", op->item_power);
1109  }
1110  } /* End if identified or applied */
1111 
1112  /* This blocks only deals with fully identified object.
1113  * it is intentional that this is not an 'else' from a above -
1114  * in this way, information is added.
1115  */
1116  if (identified) {
1117  int more_info = 0;
1118 
1119  switch (op->type) {
1120  case ROD: /* These use stats.sp for spell selection and stats.food */
1121  /* and stats.hp for spell-point regeneration... */
1122  case ARROW:
1123  case WAND:
1124  case FOOD:
1125  case FLESH:
1126  case DRINK:
1127  more_info = 0;
1128  break;
1129 
1130  /* Bows use sp for firing rate. Per fire_bow(), the bow can be fired every 100/firing rate
1131  * character movements. It also makes sure it calculates the speed at no less than 1, to avoid floating point errors
1132  */
1133  case BOW:
1134  if (op->stats.sp) {
1135  stringbuffer_append_printf(buf, "(Firing delay %.2f)", 100./op->stats.sp);
1136  }
1137  more_info = 0;
1138  break;
1139 
1140  /* Armor type objects */
1141  case ARMOUR:
1142  case HELMET:
1143  case SHIELD:
1144  case BOOTS:
1145  case GLOVES:
1146  case GIRDLE:
1147  case BRACERS:
1148  case CLOAK:
1149  if (ARMOUR_SPEED(op)) {
1150  stringbuffer_append_printf(buf, "(Max speed %1.2f)", ARMOUR_SPEED(op)/10.0);
1151  }
1152  if (ARMOUR_SPELLS(op)) {
1153  stringbuffer_append_printf(buf, "(Spell regen penalty %d)", ARMOUR_SPELLS(op));
1154  }
1155  more_info = 1;
1156  break;
1157 
1158  case WEAPON:
1159  /* Calculate it the same way fix_object does so the results
1160  * make sense.
1161  */
1162  i = (WEAPON_SPEED(op)*2-op->magic)/2;
1163  if (i < 0)
1164  i = 0;
1165 
1166  stringbuffer_append_printf(buf, "(weapon speed %d)", i);
1167  /* If the reflecting flag is set, the weapon will bounce off walls when thrown. */
1168  if (QUERY_FLAG(op, FLAG_REFLECTING)) {
1169  stringbuffer_append_string(buf, "(ricochet)");
1170  }
1171  more_info = 1;
1172  break;
1173  }
1174  if (more_info) {
1175  if (op->stats.food) {
1176  if (op->stats.food != 0)
1177  stringbuffer_append_printf(buf, "(sustenance%+d)", op->stats.food);
1178  }
1179  if (op->stats.grace) {
1180  stringbuffer_append_printf(buf, "(grace%+d)", op->stats.grace);
1181  }
1182  if (op->stats.sp) {
1183  stringbuffer_append_printf(buf, "(magic%+d)", op->stats.sp);
1184  }
1185  if (op->stats.hp) {
1186  stringbuffer_append_printf(buf, "(regeneration%+d)", op->stats.hp);
1187  }
1188  }
1189 
1190  if (op->stats.luck) {
1191  stringbuffer_append_printf(buf, "(luck%+d)", op->stats.luck);
1192  }
1193  if (QUERY_FLAG(op, FLAG_LIFESAVE))
1194  stringbuffer_append_string(buf, "(lifesaving)");
1196  stringbuffer_append_string(buf, "(reflect spells)");
1198  stringbuffer_append_string(buf, "(reflect missiles)");
1199  if (QUERY_FLAG(op, FLAG_STEALTH))
1200  stringbuffer_append_string(buf, "(stealth)");
1201  if (op->slaying != NULL && op->type != FOOD) {
1202  stringbuffer_append_printf(buf, "(slay %s)", op->slaying);
1203  }
1204  describe_attacktype("Attacks", op->attacktype, buf);
1205  /* resistance on flesh is only visible for dragons. If
1206  * non flesh, everyone can see its resistances
1207  */
1208  if (op->type != FLESH || (owner && is_dragon_pl(owner))) {
1209  describe_resistance(op, 0, 1, buf);
1210  }
1211  describe_spellpath_attenuation("Attuned", op->path_attuned &~ op->path_denied, buf);
1212  describe_spellpath_attenuation("Repelled", op->path_repelled &~ op->path_denied, buf);
1213  describe_spellpath_attenuation("Denied", op->path_denied, buf);
1214  }
1215 
1216  return buf;
1217 }
1218 
1231 int is_magical(const object *op) {
1232  int i;
1233 
1234  /* living creatures are considered non magical */
1235  if (QUERY_FLAG(op, FLAG_ALIVE))
1236  return 0;
1237 
1238  /* This is a test for it being an artifact, as artifacts have titles */
1239  if (op->title != NULL)
1240  return 1;
1241 
1242  /* Handle rings and amulets specially. If they change any of these
1243  * values, it means they are magical.
1244  */
1245  if ((op->type == AMULET || op->type == RING)
1246  && (op->stats.ac || op->stats.food || op->stats.exp || op->stats.dam || op->stats.wc || op->stats.grace || op->stats.sp || op->stats.hp || op->stats.luck))
1247  return 1;
1248 
1249  /* Check for stealty, speed, flying, or just plain magic in the boots */
1250  /* Presume any boots that have a move_type are special. */
1251  if (op->type == BOOTS
1252  && ((QUERY_FLAG(op, FLAG_STEALTH) || op->move_type || op->stats.exp)))
1253  return 1;
1254 
1255  /* Take care of amulet/shield that reflects spells/missiles */
1256  if ((op->type == AMULET || op->type == SHIELD)
1258  return 1;
1259 
1260  /* Take care of helmet of xrays */
1261  if (op->type == HELMET
1262  && QUERY_FLAG(op, FLAG_XRAYS))
1263  return 1;
1264 
1265  /* Potions & rods are always magical. Wands/staves are also magical,
1266  * assuming they still have any charges left.
1267  */
1268  if (op->type == POTION || op->type == ROD || (op->type == WAND && op->stats.food))
1269  return 1;
1270 
1271  /* if something gives a protection, either positive or negative, its magical */
1272  /* This is really a pretty bad hack - as of now, ATNR_PHYSICAL is 0,
1273  * so this always works out fine.
1274  */
1275  for (i = ATNR_PHYSICAL+1; i < NROFATTACKS; i++)
1276  if (op->resist[i])
1277  return 1;
1278 
1279  /* Physical protection is expected on some item types, so they should
1280  * not be considered magical.
1281  */
1282  if (op->resist[ATNR_PHYSICAL]
1283  && op->type != HELMET
1284  && op->type != SHIELD
1285  && op->type != BOOTS
1286  && op->type != GLOVES
1287  && op->type != ARMOUR)
1288  return 1;
1289 
1290  /* power crystal, spellbooks, and scrolls are always magical. */
1291  if (op->magic
1292  || op->type == POWER_CRYSTAL
1293  || op->type == SPELLBOOK
1294  || op->type == SCROLL
1295  || op->type == GIRDLE)
1296  return 1;
1297 
1298  /* Check to see if it increases/decreases any stats */
1299  for (i = 0; i < NUM_STATS; i++)
1300  if (get_attr_value(&(op->stats), i) != 0)
1301  return 1;
1302 
1303  /* If it doesn't fall into any of the above categories, must
1304  * be non magical.
1305  */
1306  return 0;
1307 }
1308 
1328 int is_identifiable_type(const object *op) {
1329  /* Special case -- skill tools don't have an associated identification
1330  * skill but still need IDing. TODO: we should probably have per-tool ID
1331  * skills, e.g. thievery for lockpicks and thaumaturgy for talismans, but
1332  * currently there's no good way to do this because the identifyskill is
1333  * tied to the itemtype rather than to the arch. */
1334  if (op->type == SKILL_TOOL) return true;
1335 
1336  /* Sometimes an itemtype has no associated typedata?! */
1337  const typedata *td = get_typedata(op->type);
1338  return td && td->identifyskill;
1339 }
1340 
1352 int is_identified(const object *op) {
1354 }
1355 
1361  sstring key;
1362 
1363  key = object_get_value(op, "identified_face");
1364  if (key != NULL) {
1365  op->face = try_find_face(key, op->face);
1366  /* if the face is defined, clean the animation, because else
1367  * the face can be lost ; if an animation is defined, it'll be
1368  * processed later on */
1371  op->anim_speed = 0;
1372  op->animation = 0;
1373  object_set_value(op, "identified_face", NULL, 0);
1374  }
1375 
1376  if (object_get_value(op, "identified_anim_random") != NULL) {
1378  object_set_value(op, "identified_anim_random", NULL, 0);
1379  }
1380 
1381  key = object_get_value(op, "identified_anim_speed");
1382  if (key != NULL) {
1383  op->anim_speed = atoi(key);
1384  op->last_anim = 1;
1385  object_set_value(op, "identified_anim_speed", NULL, 0);
1386  }
1387 
1388  key = object_get_value(op, "identified_animation");
1389  if (key != NULL) {
1391  if (anim) {
1392  op->animation = anim;
1395  animate_object(op, op->facing);
1396  }
1397  object_set_value(op, "identified_animation", NULL, 0);
1398  }
1399 
1400  key = object_get_value(op, "identified_name");
1401  if (key != NULL) {
1402  FREE_AND_COPY(op->name, key);
1403  object_set_value(op, "identified_name", NULL, 0);
1404  }
1405  key = object_get_value(op, "identified_name_pl");
1406  if (key != NULL) {
1407  FREE_AND_COPY(op->name_pl, key);
1408  object_set_value(op, "identified_name_pl", NULL, 0);
1409  }
1410 }
1411 
1425 object *identify(object *op) {
1426  object *pl, *op1;
1427 
1430 
1432 
1433  /*
1434  * We want autojoining of equal objects:
1435  */
1438 
1439  if (QUERY_FLAG(op, FLAG_BLESSED))
1441 
1442  if (op->type == POTION) {
1443  if (op->inv && op->randomitems) {
1444  if (op->title)
1445  free_string(op->title);
1446  op->title = add_refcount(op->inv->name);
1447  } else if (op->arch) {
1448  free_string(op->name);
1449  op->name = add_refcount(op->arch->clone.name);
1450  free_string(op->name_pl);
1451  op->name_pl = add_refcount(op->arch->clone.name_pl);
1452  }
1453  }
1454 
1455  if (op->map) {
1456  /* If the object is on a map, make sure we update its face.
1457  * Also send name and such information to a player standing on it.
1458  */
1459  object *player = map_find_by_type(op->map, op->x, op->y, PLAYER);
1460 
1462  op1 = object_merge(op, GET_MAP_TOP(op->map, op->x, op->y));
1463  if (op1) op = op1;
1464 
1465  if (player)
1467 
1468  } else if (op->env) {
1469  /* If the object is in an inventory, merge it.
1470  */
1472  op1 = object_merge(op, op->env->inv);
1473  if (op1) op = op1;
1474 
1475  if (pl)
1476  /* Item is directly in the player's inventory
1477  * A lot of the values can change from an update - might as well send
1478  * it all.
1479  */
1481  else if (op->env->map &&
1482  (pl = map_find_by_type(op->env->map, op->env->x, op->env->y, PLAYER))
1483  && (pl->container == op->env)) {
1484  /* The item is in a container (on the ground) opened by a player, update */
1486  }
1487  }
1488  /* There is a third option where we do nothing extra:
1489  * identifying a created item as it is created. */
1490  return op;
1491 }
CLASS
@ CLASS
Definition: object.h:143
FLAG_USE_BOW
#define FLAG_USE_BOW
Definition: define.h:293
UP_OBJ_FACE
#define UP_OBJ_FACE
Definition: object.h:524
TRIGGER
@ TRIGGER
Definition: object.h:134
MIMIC
@ MIMIC
Definition: object.h:254
PLAYER
@ PLAYER
Definition: object.h:112
global.h
UPD_FACE
#define UPD_FACE
Definition: newclient.h:306
CF_HANDLE
@ CF_HANDLE
Definition: object.h:213
stringbuffer_length
size_t stringbuffer_length(StringBuffer *sb)
Definition: stringbuffer.cpp:218
MAP
@ MAP
Definition: object.h:130
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Definition: object.h:15
MONSTER
@ MONSTER
Definition: object.h:205
BOW
@ BOW
Definition: object.h:123
BRACERS
@ BRACERS
Definition: object.h:222
GET_MAP_TOP
#define GET_MAP_TOP(M, X, Y)
Definition: map.h:173
CLOSE_CON
@ CLOSE_CON
Definition: object.h:234
FABS
#define FABS(x)
Definition: define.h:22
FLAG_CLIENT_ANIM_RANDOM
#define FLAG_CLIENT_ANIM_RANDOM
Definition: define.h:241
ARMOUR_IMPROVER
@ ARMOUR_IMPROVER
Definition: object.h:237
SYMPTOM
@ SYMPTOM
Definition: object.h:250
WAND
@ WAND
Definition: object.h:225
FLAG_USE_RING
#define FLAG_USE_RING
Definition: define.h:297
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
FLAG_UNDEAD
#define FLAG_UNDEAD
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
FLESH
@ FLESH
Definition: object.h:192
ENCOUNTER
@ ENCOUNTER
Definition: object.h:187
SK_ALCHEMY
@ SK_ALCHEMY
Definition: skills.h:25
player
Definition: player.h:105
GLOVES
@ GLOVES
Definition: object.h:218
GIRDLE
@ GIRDLE
Definition: object.h:228
safe_strcat
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: porting.cpp:202
BUTTON
@ BUTTON
Definition: object.h:212
diamondslots.x
x
Definition: diamondslots.py:15
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
FLAG_REFL_MISSILE
#define FLAG_REFL_MISSILE
Definition: define.h:273
TRIGGER_PEDESTAL
@ TRIGGER_PEDESTAL
Definition: object.h:139
FLAG_IS_TURNABLE
#define FLAG_IS_TURNABLE
Definition: define.h:256
object_merge
object * object_merge(object *op, object *top)
Definition: object.cpp:2046
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.cpp:138
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
Definition: define.h:337
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
SHOP_FLOOR
@ SHOP_FLOOR
Definition: object.h:188
GEM
@ GEM
Definition: object.h:172
TRAP
@ TRAP
Definition: object.h:246
ARMOUR
@ ARMOUR
Definition: object.h:125
WEAPON
@ WEAPON
Definition: object.h:124
TIMED_GATE
@ TIMED_GATE
Definition: object.h:133
typedata::identifyskill
int identifyskill
Definition: define.h:93
bits_set
static int bits_set(uint32_t x, int start, int end)
Definition: item.cpp:219
FLAG_SEE_INVISIBLE
#define FLAG_SEE_INVISIBLE
Definition: define.h:253
AMULET
@ AMULET
Definition: object.h:144
CHECK_INV
@ CHECK_INV
Definition: object.h:174
TREASURE
@ TREASURE
Definition: object.h:115
SKILL
@ SKILL
Definition: object.h:148
get_power_from_ench
int get_power_from_ench(int ench)
Definition: item.cpp:211
Ice.tmp
int tmp
Definition: Ice.py:207
ARMOUR_SPELLS
#define ARMOUR_SPELLS(xyz)
Definition: define.h:467
RUNE
@ RUNE
Definition: object.h:245
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: item.cpp:414
CREATOR
@ CREATOR
Definition: object.h:147
FLAG_BLESSED
#define FLAG_BLESSED
Definition: define.h:369
TRANSPORT
@ TRANSPORT
Definition: object.h:113
ATNR_PHYSICAL
#define ATNR_PHYSICAL
Definition: attack.h:49
POTION_RESIST_EFFECT
@ POTION_RESIST_EFFECT
Definition: object.h:230
FLOOR
@ FLOOR
Definition: object.h:191
ARMOUR_SPEED
#define ARMOUR_SPEED(xyz)
Definition: define.h:466
SIGN
@ SIGN
Definition: object.h:216
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
TRIGGER_BUTTON
@ TRIGGER_BUTTON
Definition: object.h:137
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4337
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
FLAG_STEALTH
#define FLAG_STEALTH
Definition: define.h:312
POWER_CRYSTAL
@ POWER_CRYSTAL
Definition: object.h:247
buf
StringBuffer * buf
Definition: readable.cpp:1552
POISONING
@ POISONING
Definition: object.h:223
describe_attacktype
StringBuffer * describe_attacktype(const char *attack, int value, StringBuffer *buf)
Definition: utils.cpp:535
item_types
static const typedata item_types[]
Definition: item.cpp:78
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
short_stat_name
const char *const short_stat_name[NUM_STATS]
Definition: living.cpp:194
TRIGGER_MARKER
@ TRIGGER_MARKER
Definition: object.h:158
typedata
Definition: define.h:89
CLOAK
@ CLOAK
Definition: object.h:209
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
object_update
void object_update(object *op, int action)
Definition: object.cpp:1429
FMT64
#define FMT64
Definition: compat.h:16
NROF
static uint32_t NROF(const object *const ob)
Definition: object.h:616
HELMET
@ HELMET
Definition: object.h:141
POISON
@ POISON
Definition: object.h:118
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.cpp:210
DEEP_SWAMP
@ DEEP_SWAMP
Definition: object.h:241
describe_resistance
StringBuffer * describe_resistance(const object *op, int newline, int use_media_tags, StringBuffer *buf)
Definition: item.cpp:376
SK_JEWELER
@ SK_JEWELER
Definition: skills.h:24
MARKER
@ MARKER
Definition: object.h:163
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:327
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:592
SAVEBED
@ SAVEBED
Definition: object.h:224
FLAG_USE_RANGE
#define FLAG_USE_RANGE
Definition: define.h:292
FLAG_KNOWN_BLESSED
#define FLAG_KNOWN_BLESSED
Definition: define.h:370
map_find_by_type
object * map_find_by_type(mapstruct *m, int x, int y, uint8_t type)
Definition: object.cpp:3136
LIGHTABLE
@ LIGHTABLE
Definition: object.h:255
POTION
@ POTION
Definition: object.h:116
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
Definition: define.h:320
BUILDER
@ BUILDER
Definition: object.h:251
SK_LITERACY
@ SK_LITERACY
Definition: skills.h:27
SK_BOWYER
@ SK_BOWYER
Definition: skills.h:23
ROD
@ ROD
Definition: object.h:114
CONTAINER
@ CONTAINER
Definition: object.h:236
INORGANIC
@ INORGANIC
Definition: object.h:193
object_find_by_type_and_name
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.cpp:4099
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.cpp:517
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:128
ring_desc
static StringBuffer * ring_desc(const object *op, int use_media_tags, StringBuffer *buf)
Definition: item.cpp:442
PLAYERMOVER
@ PLAYERMOVER
Definition: object.h:145
FLAG_MAKE_INVIS
#define FLAG_MAKE_INVIS
Definition: define.h:328
change_resist_msg
const char *const change_resist_msg[NROFATTACKS]
Definition: init.cpp:70
is_identified
int is_identified(const object *op)
Definition: item.cpp:1352
SPECIAL_KEY
@ SPECIAL_KEY
Definition: object.h:129
HOLE
@ HOLE
Definition: object.h:214
PEACEMAKER
@ PEACEMAKER
Definition: object.h:169
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:204
CONVERTER
@ CONVERTER
Definition: object.h:221
SKILLSCROLL
@ SKILLSCROLL
Definition: object.h:239
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:304
LAMP
@ LAMP
Definition: object.h:206
GOLEM
@ GOLEM
Definition: object.h:150
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
body_locations
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
Definition: item.cpp:54
MOOD_FLOOR
@ MOOD_FLOOR
Definition: object.h:175
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
Definition: define.h:296
ARROW
@ ARROW
Definition: object.h:122
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.cpp:95
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
Definition: define.h:321
animate.anim
string anim
Definition: animate.py:20
BOOK
@ BOOK
Definition: object.h:119
RING
@ RING
Definition: object.h:190
BLINDNESS
@ BLINDNESS
Definition: object.h:152
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
get_typedata_by_name
const typedata * get_typedata_by_name(const char *name)
Definition: item.cpp:347
CLOCK
@ CLOCK
Definition: object.h:120
FLAG_HITBACK
#define FLAG_HITBACK
Definition: define.h:267
resist_plus
const char *const resist_plus[NROFATTACKS]
Definition: init.cpp:49
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
SHOP_MAT
@ SHOP_MAT
Definition: object.h:189
describe_item
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
Definition: item.cpp:955
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
item_types_size
static const int item_types_size
Definition: item.cpp:193
try_find_animation
Animations * try_find_animation(const char *name)
Definition: assets.cpp:278
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Definition: define.h:393
FLAG_CLIENT_ANIM_SYNC
#define FLAG_CLIENT_ANIM_SYNC
Definition: define.h:240
EXIT
@ EXIT
Definition: object.h:186
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
Definition: define.h:319
MAGIC_EAR
@ MAGIC_EAR
Definition: object.h:136
FLAG_REFL_SPELL
#define FLAG_REFL_SPELL
Definition: define.h:275
describe_spellpath_attenuation
StringBuffer * describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf)
Definition: utils.cpp:507
llevInfo
@ llevInfo
Definition: logger.h:12
SK_WOODSMAN
@ SK_WOODSMAN
Definition: skills.h:40
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
query_weight
void query_weight(const object *op, char *buf, size_t size)
Definition: item.cpp:419
BATTLEGROUND
@ BATTLEGROUND
Definition: object.h:168
WEAPON_SPEED
#define WEAPON_SPEED(xyz)
Definition: define.h:468
is_dragon_pl
int is_dragon_pl(const object *op)
Definition: player.cpp:122
GRIMREAPER
@ GRIMREAPER
Definition: object.h:135
KEY
@ KEY
Definition: object.h:132
FLAG_USE_ARMOUR
#define FLAG_USE_ARMOUR
Definition: define.h:295
FLAG_CAST_SPELL
#define FLAG_CAST_SPELL
Definition: define.h:290
EARTHWALL
@ EARTHWALL
Definition: object.h:149
DUPLICATOR
@ DUPLICATOR
Definition: object.h:207
is_magical
int is_magical(const object *op)
Definition: item.cpp:1231
DISEASE
@ DISEASE
Definition: object.h:249
FIREWALL
@ FIREWALL
Definition: object.h:173
is_identifiable_type
int is_identifiable_type(const object *op)
Definition: item.cpp:1328
TRIGGER_ALTAR
@ TRIGGER_ALTAR
Definition: object.h:138
PLAYER_CHANGER
@ PLAYER_CHANGER
Definition: object.h:167
sstring
const typedef char * sstring
Definition: sstring.h:2
LIGHTER
@ LIGHTER
Definition: object.h:195
give.op
op
Definition: give.py:33
Floor.t
t
Definition: Floor.py:62
animate_object
void animate_object(object *op, int dir)
Definition: anim.cpp:44
MATERIAL
@ MATERIAL
Definition: object.h:253
FLAG_REFLECTING
#define FLAG_REFLECTING
Definition: define.h:262
SPINNER
@ SPINNER
Definition: object.h:210
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:220
SKILL_TOOL
@ SKILL_TOOL
Definition: object.h:194
SHOP_INVENTORY
@ SHOP_INVENTORY
Definition: object.h:243
PEDESTAL
@ PEDESTAL
Definition: object.h:126
FLAG_BEEN_APPLIED
#define FLAG_BEEN_APPLIED
Definition: define.h:323
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
atnr_is_dragon_enabled
int atnr_is_dragon_enabled(int attacknr)
Definition: player.cpp:103
enc_to_item_power
static const int enc_to_item_power[]
Definition: item.cpp:204
resist_color
const char *const resist_color[NROFATTACKS]
Definition: init.cpp:61
object_give_identified_properties
void object_give_identified_properties(object *op)
Definition: item.cpp:1360
DEAD_OBJECT
@ DEAD_OBJECT
Definition: object.h:161
DIRECTOR
@ DIRECTOR
Definition: object.h:227
CORPSE
@ CORPSE
Definition: object.h:248
castle_read.key
key
Definition: castle_read.py:64
MIN_ACTIVE_SPEED
#define MIN_ACTIVE_SPEED
Definition: define.h:639
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
UPD_NAME
#define UPD_NAME
Definition: newclient.h:307
SK_SMITHERY
@ SK_SMITHERY
Definition: skills.h:22
FOOD
@ FOOD
Definition: object.h:117
MOVE_FLY_HIGH
#define MOVE_FLY_HIGH
Definition: define.h:394
first
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at first
Definition: protocol.txt:20
ALTAR
@ ALTAR
Definition: object.h:127
DOOR
@ DOOR
Definition: object.h:131
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:286
SK_THAUMATURGY
@ SK_THAUMATURGY
Definition: skills.h:48
DRINK
@ DRINK
Definition: object.h:162
UPD_ALL
#define UPD_ALL
Definition: newclient.h:311
WALL
@ WALL
Definition: object.h:196
WEAPON_IMPROVER
@ WEAPON_IMPROVER
Definition: object.h:238
SCROLL
@ SCROLL
Definition: object.h:226
FLAG_XRAYS
#define FLAG_XRAYS
Definition: define.h:300
describe_monster
StringBuffer * describe_monster(const object *op, int use_media_tags, StringBuffer *buf)
Definition: item.cpp:781
Animations
Definition: face.h:25
body_locations_struct
Definition: object.h:22
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.cpp:693
treasure
Definition: treasure.h:63
MOVE_SWIM
#define MOVE_SWIM
Definition: define.h:396
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.cpp:4490
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.cpp:313
calc_item_power
int calc_item_power(const object *op)
Definition: item.cpp:239
BOOTS
@ BOOTS
Definition: object.h:217
StringBuffer
Definition: stringbuffer.cpp:25
IDENTIFY_ALTAR
@ IDENTIFY_ALTAR
Definition: object.h:242
SPELL
@ SPELL
Definition: object.h:219
SHIELD
@ SHIELD
Definition: object.h:140
FLAG_NO_SKILL_IDENT
#define FLAG_NO_SKILL_IDENT
Definition: define.h:335
FLAG_USE_SCROLL
#define FLAG_USE_SCROLL
Definition: define.h:291
FLAG_CURSED
#define FLAG_CURSED
Definition: define.h:316
TELEPORTER
@ TELEPORTER
Definition: object.h:146
object_get_player_container
object * object_get_player_container(object *op)
Definition: object.cpp:607
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
living.h
if
if(!(yy_init))
Definition: loader.c:2626
THROWN_OBJ
@ THROWN_OBJ
Definition: object.h:151
SPELLBOOK
@ SPELLBOOK
Definition: object.h:208
NUM_STATS
@ NUM_STATS
Definition: living.h:18
FORCE
@ FORCE
Definition: object.h:229
HOLY_ALTAR
@ HOLY_ALTAR
Definition: object.h:166
TRAPDOOR
@ TRAPDOOR
Definition: object.h:215
DETECTOR
@ DETECTOR
Definition: object.h:154
GOD
@ GOD
Definition: object.h:153
FLAG_LIFESAVE
#define FLAG_LIFESAVE
Definition: define.h:305
MISC_OBJECT
@ MISC_OBJECT
Definition: object.h:198
MONEY
@ MONEY
Definition: object.h:142
NRSPELLPATHS
#define NRSPELLPATHS
Definition: spells.h:40
GATE
@ GATE
Definition: object.h:211
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:261
identify
object * identify(object *op)
Definition: item.cpp:1425