Crossfire Server, Branches 1.12  R18729
item.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_item_c =
3  * "$Id: item.c 13899 2010-09-26 16:25:57Z ryo_saeba $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2006 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28 
37 #include <stdio.h>
38 #include <global.h>
39 #include <living.h>
40 #include <spells.h>
41 
65  { "body_range", "in your range slot", "in a human's range slot" },
66  { "body_arm", "on your arm", "on a human's arm" },
67  { "body_torso", "on your body", "on a human's torso" },
68  { "body_head", "on your head", "on a human's head" },
69  { "body_neck", "around your neck", "around a humans neck" },
70  { "body_skill", "in your skill slot", "in a human's skill slot" },
71  { "body_finger", "on your finger", "on a human's finger" },
72  { "body_shoulder", "around your shoulders", "around a human's shoulders" },
73  { "body_foot", "on your feet", "on a human's feet" },
74  { "body_hand", "on your hands", "on a human's hands" },
75  { "body_wrist", "around your wrists", "around a human's wrist" },
76  { "body_waist", "around your waist", "around a human's waist" },
77  { "body_leg", "around your legs", "around a human's legs" },
78 
79  /*{"body_dragon_torso", "your body", "a dragon's body"} */
80 };
81 
83 static const char numbers_10[10][20] = {
84  "zero", "ten", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy",
85  "eighty", "ninety"
86 };
87 
89 static const char levelnumbers[21][20] = {
90  "zeroth", "first", "second", "third", "fourth", "fifth", "sixth", "seventh",
91  "eighth", "ninth", "tenth", "eleventh", "twelfth", "thirteenth",
92  "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteen",
93  "nineteen", "twentieth"
94 };
95 
97 static const char levelnumbers_10[11][20] = {
98  "zeroth", "tenth", "twentieth", "thirtieth", "fortieth", "fiftieth", "sixtieth",
99  "seventieth", "eightieth", "ninetieth"
100 };
101 
109 static const typedata item_types[] = {
110  { PLAYER, "player", "players", 0, 0 },
111  { ROD, "rod", "rods", SK_THAUMATURGY, 0 },
112  { TREASURE, "treasure", "treasure", 0, 0 },
113  { POTION, "potion", "potions", SK_ALCHEMY, 0 },
114  { FOOD, "food", "food", SK_WOODSMAN, 0 },
115  { POISON, "poison", "poisons", SK_ALCHEMY, 0 },
116  { BOOK, "book", "books", SK_LITERACY, 0 },
117  { CLOCK, "clock", "clocks", 0, 0 },
118  { ARROW, "arrow", "arrows", SK_BOWYER, 0 },
119  { BOW, "bow", "bows", SK_BOWYER, 0 },
120  { WEAPON, "weapon", "weapons", SK_SMITHERY, 0 },
121  { ARMOUR, "armour", "armour", SK_SMITHERY, 0 },
122  { PEDESTAL, "pedestal", "pedestals", 0, 0 },
123  { ALTAR, "altar", "altars", 0, 0 },
124  { LOCKED_DOOR, "locked door", "locked doors", 0, 0 },
125  { SPECIAL_KEY, "special key", "special keys", 0, 0 },
126  { MAP, "map", "maps", 0, 0 },
127  { DOOR, "door", "doors", 0, 0 },
128  { KEY, "key", "keys", 0, 0 },
129  { TIMED_GATE, "timed_gate", "timed_gates", 0, 0 },
130  { TRIGGER, "trigger", "triggers", 0, 0 },
131  { GRIMREAPER, "grimreaper", "grimreapers", 0, 0 },
132  { MAGIC_EAR, "magic ear", "magic ears", 0, 0 },
133  { TRIGGER_BUTTON, "trigger button", "trigger buttons", 0, 0 },
134  { TRIGGER_ALTAR, "trigger altar", "trigger altars", 0, 0 },
135  { TRIGGER_PEDESTAL, "trigger pedestal", "trigger pedestals", 0, 0 },
136  { SHIELD, "shield", "shields", SK_SMITHERY, 0 },
137  { HELMET, "helmet", "helmets", SK_SMITHERY, 0 },
138  { HORN, "horn", "horns", SK_THAUMATURGY, 0 },
139  { MONEY, "money", "money", 0, 0 },
140  { CLASS, "class", "classes", 0, 0 },
141  { AMULET, "amulet", "amulets", SK_JEWELER, 0 },
142  { PLAYERMOVER, "player mover", "player movers", 0, 0 },
143  { TELEPORTER, "teleporter", "teleporters", 0, 0 },
144  { CREATOR, "creator", "creators", 0, 0 },
145  { SKILL, "skill", "skills", 0, 0 },
146  { EXPERIENCE, "experience", "experience", 0, 0 },
147  { EARTHWALL, "earthwall", "earthwalls", 0, 0 },
148  { GOLEM, "golem", "golems", 0, 0 },
149  { THROWN_OBJ, "projectile", "projectiles", 0, 0 },
150  { BLINDNESS, "blindness", "blindness", 0, 0 },
151  { GOD, "god", "gods", 0, 0 },
152  { DETECTOR, "detector", "detectors", 0, 0 },
153  { TRIGGER_MARKER, "trigger marker", "trigger markers", 0, 0 },
154  { DEAD_OBJECT, "dead object", "dead objects", 0, 0 },
155  { DRINK, "drink", "drinks", SK_WOODSMAN, SK_ALCHEMY },
156  { MARKER, "marker", "markers", 0, 0 },
157  { HOLY_ALTAR, "holy altar", "holy altars", 0, 0 },
158  { PLAYER_CHANGER, "player changer", "player changers", 0, 0 },
159  { BATTLEGROUND, "battleground", "battlegrounds", 0, 0 },
160  { PEACEMAKER, "peacemaker", "peacemakers", 0, 0 },
161  { GEM, "gem", "gems", SK_JEWELER, 0 },
162  { FIREWALL, "firewall", "firewalls", 0, 0 },
163  { CHECK_INV, "inventory checker", "inventory checkers", 0, 0 },
164  { MOOD_FLOOR, "mood floor", "mood floors", 0, 0 },
165  { EXIT, "exit", "exits", 0, 0 },
166  { ENCOUNTER, "encounter", "encounters", 0, 0 },
167  { SHOP_FLOOR, "shop floor", "shop floors", 0, 0 },
168  { SHOP_MAT, "shop mat", "shop mats", 0, 0 },
169  { RING, "ring", "rings", SK_JEWELER, 0 },
170  { FLOOR, "floor", "floors", 0, 0 },
171  { FLESH, "flesh", "flesh", SK_WOODSMAN, 0 },
172  { INORGANIC, "inorganic", "inorganics", SK_ALCHEMY, 0 },
173  { SKILL_TOOL, "skill tool", "skill tools", 0, 0 },
174  { LIGHTER, "lighter", "lighters", 0, 0 },
175  { WALL, "wall", "walls", 0, 0 },
176  { MISC_OBJECT, "bric-a-brac", "bric-a-brac", 0, 0 },
177  { MONSTER, "monster", "monsters", 0, 0 },
178  { LAMP, "lamp", "lamps", 0, 0 },
179  { DUPLICATOR, "duplicator", "duplicators", 0, 0 },
180  { SPELLBOOK, "spellbook", "spellbooks", SK_LITERACY, 0 },
181  { CLOAK, "cloak", "cloaks", SK_SMITHERY, 0 },
182  { SPINNER, "spinner", "spinners", 0, 0 },
183  { GATE, "gate", "gates", 0, 0 },
184  { BUTTON, "button", "buttons", 0, 0 },
185  { CF_HANDLE, "cf handle", "cf handles", 0, 0 },
186  { HOLE, "hole", "holes", 0, 0 },
187  { TRAPDOOR, "trapdoor", "trapdoors", 0, 0 },
188  { SIGN, "sign", "signs", 0, 0 },
189  { BOOTS, "boots", "boots", SK_SMITHERY, 0 },
190  { GLOVES, "gloves", "gloves", SK_SMITHERY, 0 },
191  { SPELL, "spell", "spells", 0, 0 },
192  { SPELL_EFFECT, "spell effect", "spell effects", 0, 0 },
193  { CONVERTER, "converter", "converters", 0, 0 },
194  { BRACERS, "bracers", "bracers", SK_SMITHERY, 0 },
195  { POISONING, "poisoning", "poisonings", 0, 0 },
196  { SAVEBED, "savebed", "savebeds", 0, 0 },
197  { WAND, "wand", "wands", SK_THAUMATURGY, 0 },
198  { SCROLL, "scroll", "scrolls", SK_LITERACY, 0 },
199  { DIRECTOR, "director", "directors", 0, 0 },
200  { GIRDLE, "girdle", "girdles", SK_SMITHERY, 0 },
201  { FORCE, "force", "forces", 0, 0 },
202  { POTION_EFFECT, "potion effect", "potion effects", 0, 0 },
203  { CLOSE_CON, "closed container", "closed container", 0, 0 },
204  { CONTAINER, "container", "containers", SK_ALCHEMY, 0 },
205  { ARMOUR_IMPROVER, "armour improver", "armour improvers", 0, 0 },
206  { WEAPON_IMPROVER, "weapon improver", "weapon improvers", 0, 0 },
207  { SKILLSCROLL, "skillscroll", "skillscrolls", 0, 0 },
208  { DEEP_SWAMP, "deep swamp", "deep swamps", 0, 0 },
209  { IDENTIFY_ALTAR, "identify altar", "identify altars", 0, 0 },
210  { SHOP_INVENTORY, "inventory list", "inventory lists", 0, 0 },
211  { RUNE, "rune", "runes", 0, 0 },
212  { TRAP, "trap", "traps", 0, 0 },
213  { POWER_CRYSTAL, "power_crystal", "power_crystals", 0, 0 },
214  { CORPSE, "corpse", "corpses", 0, 0 },
215  { DISEASE, "disease", "diseases", 0, 0 },
216  { SYMPTOM, "symptom", "symptoms", 0, 0 },
217  { BUILDER, "item builder", "item builders", 0, 0 },
218  { MATERIAL, "building material", "building materials", 0, 0 },
219 };
220 
222 static const int item_types_size = sizeof(item_types)/sizeof(*item_types);
223 
233 static const int enc_to_item_power[21] = {
234  0, 0, 1, 2, 3, 4, /* 5 */
235  5, 7, 9, 11, 13, /* 10 */
236  15, 18, 21, 24, 27, /* 15 */
237  30, 35, 40, 45, 50 /* 20 */
238 };
239 
240 int get_power_from_ench(int ench) {
241  if (ench < 0)
242  ench = 0;
243  if (ench > 20)
244  ench = 20;
245  return enc_to_item_power[ench];
246 }
247 
264 int calc_item_power(const object *op, int flag) {
265  int i, tmp, enc;
266 
267  enc = 0;
268  for (i = 0; i < NUM_STATS; i++)
269  enc += get_attr_value(&op->stats, i);
270 
271  /* This protection logic is pretty flawed. 20% fire resistance
272  * is much more valuable than 20% confusion, or 20% slow, or
273  * several others. Start at 1 - ignore physical - all that normal
274  * armour shouldn't be counted against
275  */
276  tmp = 0;
277  for (i = 1; i < NROFATTACKS; i++)
278  tmp += op->resist[i];
279 
280  /* Add/substract 10 so that the rounding works out right */
281  if (tmp > 0)
282  enc += (tmp+10)/20;
283  else if (tmp < 0)
284  enc += (tmp-10)/20;
285 
286  enc += op->magic;
287 
288  /* For each attacktype a weapon has, one more encantment. Start at 1 -
289  * physical doesn't count against total.
290  */
291  if (op->type == WEAPON) {
292  for (i = 1; i < NROFATTACKS; i++)
293  if (op->attacktype&(1<<i))
294  enc++;
295  if (op->slaying)
296  enc += 2; /* What it slays is probably more relevent */
297  }
298  /* Items the player can equip */
299  if ((op->type == WEAPON)
300  || (op->type == ARMOUR)
301  || (op->type == HELMET)
302  || (op->type == SHIELD)
303  || (op->type == RING)
304  || (op->type == BOOTS)
305  || (op->type == GLOVES)
306  || (op->type == AMULET)
307  || (op->type == GIRDLE)
308  || (op->type == BRACERS)
309  || (op->type == CLOAK)) {
310  enc += op->stats.food; /* sustenance */
311  enc += op->stats.hp; /* hp regen */
312  enc += op->stats.sp; /* mana regen */
313  enc += op->stats.grace; /* grace regen */
314  enc += op->stats.exp; /* speed bonus */
315  }
316  enc += op->stats.luck;
317 
318  /* Do spell paths now */
319  for (i = 1; i < NRSPELLPATHS; i++) {
320  if (op->path_attuned&(1<<i))
321  enc++;
322  else if (op->path_denied&(1<<i))
323  enc -= 2;
324  else if (op->path_repelled&(1<<i))
325  enc--;
326  }
327 
328  if (QUERY_FLAG(op, FLAG_LIFESAVE))
329  enc += 5;
330  if (QUERY_FLAG(op, FLAG_REFL_SPELL))
331  enc += 3;
332  if (QUERY_FLAG(op, FLAG_REFL_MISSILE))
333  enc += 2;
334  if (QUERY_FLAG(op, FLAG_STEALTH))
335  enc += 1;
336  if (QUERY_FLAG(op, FLAG_XRAYS))
337  enc += 2;
338  if (QUERY_FLAG(op, FLAG_SEE_IN_DARK))
339  enc += 1;
340  if (QUERY_FLAG(op, FLAG_MAKE_INVIS))
341  enc += 1;
342 
343  return get_power_from_ench(enc);
344 }
345 
352 const typedata *get_typedata(int itemtype) {
353  int i;
354 
355  for (i = 0; i < item_types_size; i++)
356  if (item_types[i].number == itemtype)
357  return &item_types[i];
358  return NULL;
359 }
360 
372 const typedata *get_typedata_by_name(const char *name) {
373  int i;
374 
375  for (i = 0; i < item_types_size; i++)
376  if (!strcmp(item_types[i].name, name))
377  return &item_types[i];
378  for (i = 0; i < item_types_size; i++)
379  if (!strcmp(item_types[i].name_pl, name)) {
380  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);
381  return &item_types[i];
382  }
383  return NULL;
384 }
385 
399 void describe_resistance(const object *op, int newline, char *buf, size_t size) {
400  char *p;
401  int tmpvar;
402 
403  p = buf;
404  for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++) {
405  if (op->resist[tmpvar] && (op->type != FLESH || atnr_is_dragon_enabled(tmpvar) == 1)) {
406  if (!newline)
407  snprintf(p, buf+size-p, "(%s %+d)", resist_plus[tmpvar], op->resist[tmpvar]);
408  else
409  snprintf(p, buf+size-p, "%s %d\n", resist_plus[tmpvar], op->resist[tmpvar]);
410  p = strchr(p, '\0');
411  }
412  }
413 }
414 
424 void query_weight(const object *op, char *buf, size_t size) {
425  sint32 i = (op->nrof ? op->nrof : 1)*op->weight+op->carrying;
426 
427  if (op->weight < 0)
428  snprintf(buf, size, " ");
429  else if (i%1000)
430  snprintf(buf, size, "%6.1f", i/1000.0);
431  else
432  snprintf(buf, size, "%4d ", i/1000);
433 }
434 
444 void get_levelnumber(int i, char *buf, size_t size) {
445  if (i > 99 || i < 0) {
446  snprintf(buf, size, "%d.", i);
447  return;
448  }
449  if (i < 21) {
450  snprintf(buf, size, "%s", levelnumbers[i]);
451  return;
452  }
453  if (!(i%10)) {
454  snprintf(buf, size, "%s", levelnumbers_10[i/10]);
455  return;
456  }
457  snprintf(buf, size, "%s%s", numbers_10[i/10], levelnumbers[i%10]);
458  return;
459 }
460 
483 static void ring_desc(const object *op, char *buf, size_t size) {
484  int attr, val;
485  size_t len;
486 
487  buf[0] = 0;
488 
489  if (!QUERY_FLAG(op, FLAG_IDENTIFIED))
490  return;
491 
492  for (attr = 0; attr < NUM_STATS; attr++) {
493  if ((val = get_attr_value(&(op->stats), attr)) != 0) {
494  snprintf(buf+strlen(buf), size-strlen(buf), "(%s%+d)", short_stat_name[attr], val);
495  }
496  }
497  if (op->stats.exp)
498  snprintf(buf+strlen(buf), size-strlen(buf), "(speed %+"FMT64")", op->stats.exp);
499  if (op->stats.wc)
500  snprintf(buf+strlen(buf), size-strlen(buf), "(wc%+d)", op->stats.wc);
501  if (op->stats.dam)
502  snprintf(buf+strlen(buf), size-strlen(buf), "(dam%+d)", op->stats.dam);
503  if (op->stats.ac)
504  snprintf(buf+strlen(buf), size-strlen(buf), "(ac%+d)", op->stats.ac);
505 
506  describe_resistance(op, 0, buf+strlen(buf), size-strlen(buf));
507 
508  if (op->stats.food != 0)
509  snprintf(buf+strlen(buf), size-strlen(buf), "(sustenance%+d)", op->stats.food);
510 /* else if (op->stats.food < 0)
511  snprintf(buf+strlen(buf), size-strlen(buf), "(hunger%+d)", op->stats.food); */
512  if (op->stats.grace)
513  snprintf(buf+strlen(buf), size-strlen(buf), "(grace%+d)", op->stats.grace);
514  if (op->stats.sp && op->type != SKILL)
515  snprintf(buf+strlen(buf), size-strlen(buf), "(magic%+d)", op->stats.sp);
516  if (op->stats.hp)
517  snprintf(buf+strlen(buf), size-strlen(buf), "(regeneration%+d)", op->stats.hp);
518  if (op->stats.luck)
519  snprintf(buf+strlen(buf), size-strlen(buf), "(luck%+d)", op->stats.luck);
520  if (QUERY_FLAG(op, FLAG_LIFESAVE))
521  snprintf(buf+strlen(buf), size-strlen(buf), "(lifesaving)");
522  if (QUERY_FLAG(op, FLAG_REFL_SPELL))
523  snprintf(buf+strlen(buf), size-strlen(buf), "(reflect spells)");
524  if (QUERY_FLAG(op, FLAG_REFL_MISSILE))
525  snprintf(buf+strlen(buf), size-strlen(buf), "(reflect missiles)");
526  if (QUERY_FLAG(op, FLAG_STEALTH))
527  snprintf(buf+strlen(buf), size-strlen(buf), "(stealth)");
528  /* Shorten some of the names, so they appear better in the windows */
529  len = strlen(buf);
530  DESCRIBE_PATH_SAFE(buf, op->path_attuned, "Attuned", &len, size);
531  DESCRIBE_PATH_SAFE(buf, op->path_repelled, "Repelled", &len, size);
532  DESCRIBE_PATH_SAFE(buf, op->path_denied, "Denied", &len, size);
533 
534 /* if (op->item_power)
535  snprintf(buf+strlen(buf), size-strlen(buf), "(item_power %+d)", op->item_power);*/
536  if (buf[0] == 0 && op->type != SKILL)
537  snprintf(buf, size, "of adornment");
538 }
539 
551 void query_short_name(const object *op, char *buf, size_t size) {
552  size_t len = 0;
553 
554  if (op->name == NULL) {
555  snprintf(buf, size, "(null)");
556  return;
557  }
558  if (!op->nrof && !op->weight && !op->title && !is_magical(op)) {
559  snprintf(buf, size, "%s", op->name); /* To speed things up (or make things slower?) */
560  return;
561  }
562  buf[0] = '\0';
563 
564  if (op->nrof <= 1)
565  safe_strcat(buf, op->name, &len, size);
566  else
567  safe_strcat(buf, op->name_pl, &len, size);
568 
569  if (op->title && QUERY_FLAG(op, FLAG_IDENTIFIED)) {
570  safe_strcat(buf, " ", &len, size);
571  safe_strcat(buf, op->title, &len, size);
572  }
573 
574  switch (op->type) {
575  case SPELLBOOK:
576  case SCROLL:
577  case WAND:
578  case ROD:
580  if (!op->title) {
581  safe_strcat(buf, " of ", &len, size);
582  if (op->inv)
583  safe_strcat(buf, op->inv->name, &len, size);
584  else
585  LOG(llevError, "Spellbook %s lacks inventory\n", op->name);
586  }
587  if (op->type != SPELLBOOK) {
588  snprintf(buf+len, size-len, " (lvl %d)", op->level);
589  len += strlen(buf+len);
590  }
591  }
592  break;
593 
594  case SKILL:
595  case AMULET:
596  case RING:
597  if (!op->title) {
598  /* If ring has a title, full description isn't so useful */
599  char desc[VERY_BIG_BUF];
600 
601  ring_desc(op, desc, VERY_BIG_BUF);
602  if (desc[0]) {
603  safe_strcat(buf, " ", &len, size);
604  safe_strcat(buf, desc, &len, size);
605  }
606  }
607  break;
608 
609  default:
610  if (op->magic
612  snprintf(buf+len, size-len, " %+d", op->magic);
613  len += strlen(buf+len);
614  }
615  }
616 }
617 
628 void query_name(const object *op, char *buf, size_t size) {
629  size_t len = 0;
630 #ifdef NEW_MATERIAL_CODE
631  materialtype_t *mt;
632 #endif
633 
634  buf[0] = '\0';
635 
636 #ifdef NEW_MATERIAL_CODE
637  if ((IS_ARMOR(op) || IS_WEAPON(op) || IS_SHIELD(op)) && op->materialname) {
638  mt = name_to_material(op->materialname);
639  if (mt) {
640  safe_strcat(buf, mt->description, &len, size);
641  safe_strcat(buf, " ", &len, size);
642  }
643  }
644 #endif
645 
646  query_short_name(op, buf+len, size-len);
647  len += strlen(buf+len);
648 
649  if (QUERY_FLAG(op, FLAG_INV_LOCKED))
650  safe_strcat(buf, " *", &len, size);
651  if (op->type == CONTAINER
652  && ((op->env && op->env->container == op) || (!op->env && QUERY_FLAG(op, FLAG_APPLIED))))
653  safe_strcat(buf, " (open)", &len, size);
654 
655  if (QUERY_FLAG(op, FLAG_KNOWN_CURSED)) {
656  if (QUERY_FLAG(op, FLAG_DAMNED))
657  safe_strcat(buf, " (damned)", &len, size);
658  else if (QUERY_FLAG(op, FLAG_CURSED))
659  safe_strcat(buf, " (cursed)", &len, size);
660  }
662  safe_strcat(buf, " (blessed)", &len, size);
663 
664  /* Basically, if the object is known magical (detect magic spell on it),
665  * and it isn't identified, print out the fact that
666  * it is magical. Assume that the detect magical spell will only set
667  * KNOWN_MAGICAL if the item actually is magical.
668  *
669  * Changed in V 0.91.4 - still print that the object is magical even
670  * if it has been applied. Equipping an item does not tell full
671  * abilities, especially for artifact items.
672  */
674  safe_strcat(buf, " (magic)", &len, size);
675 
676  if (QUERY_FLAG(op, FLAG_APPLIED)) {
677  switch (op->type) {
678  case BOW:
679  case WAND:
680  case ROD:
681  case HORN:
682  safe_strcat(buf, " (readied)", &len, size);
683  break;
684 
685  case WEAPON:
686  safe_strcat(buf, " (wielded)", &len, size);
687  break;
688 
689  case ARMOUR:
690  case HELMET:
691  case SHIELD:
692  case RING:
693  case BOOTS:
694  case GLOVES:
695  case AMULET:
696  case GIRDLE:
697  case BRACERS:
698  case CLOAK:
699  safe_strcat(buf, " (worn)", &len, size);
700  break;
701 
702  case CONTAINER:
703  safe_strcat(buf, " (active)", &len, size);
704  break;
705 
706  case SKILL:
707  default:
708  safe_strcat(buf, " (applied)", &len, size);
709  }
710  }
711  if (QUERY_FLAG(op, FLAG_UNPAID))
712  safe_strcat(buf, " (unpaid)", &len, size);
713 }
714 
732 void query_base_name(const object *op, int plural, char *buf, size_t size) {
733  size_t len;
734 #ifdef NEW_MATERIAL_CODE
735  materialtype_t *mt;
736 #endif
737 
738  if ((!plural && !op->name)
739  || (plural && !op->name_pl)) {
740  strncpy(buf, "(null)", size);
741  return;
742  }
743 
744  if (!op->nrof && !op->weight && !op->title && !is_magical(op)) {
745  strncpy(buf, op->name, size); /* To speed things up (or make things slower?) */
746  return;
747  }
748 
749  buf[0] = '\0';
750 
751 #ifdef NEW_MATERIAL_CODE
752  if ((IS_ARMOR(op) || IS_WEAPON(op)) && op->materialname)
753  mt = name_to_material(op->materialname);
754  else
755  mt = NULL;
756 
757  if (mt
758  && op->arch->clone.materialname != mt->name
759  && !(op->material&M_SPECIAL)) {
760  snprintf(buf, size, "%s", mt->description);
761  len = strlen(buf);
762  safe_strcat(buf, " ", &len, size);
763  safe_strcat(buf, plural ? op->name_pl : op->name, &len, size);
764  } else {
765 #endif
766  snprintf(buf, size, "%s", plural ? op->name_pl : op->name);
767  len = strlen(buf);
768 #ifdef NEW_MATERIAL_CODE
769  }
770 #endif
771 
772  if (op->title && QUERY_FLAG(op, FLAG_IDENTIFIED)) {
773  safe_strcat(buf, " ", &len, size);
774  safe_strcat(buf, op->title, &len, size);
775  }
776 
777  switch (op->type) {
778  case SPELLBOOK:
779  case SCROLL:
780  case WAND:
781  case ROD:
783  if (!op->title) {
784  safe_strcat(buf, " of ", &len, size);
785  if (op->inv)
786  safe_strcat(buf, op->inv->name, &len, size);
787  else
788  LOG(llevError, "Spellbook %s lacks inventory\n", op->name);
789  }
790  if (op->type != SPELLBOOK) {
791  snprintf(buf+len, size-len, " (lvl %d)", op->level);
792  len += strlen(buf+len);
793  }
794  }
795  break;
796 
797  case SKILL:
798  case AMULET:
799  case RING:
800  if (!op->title) {
801  /* If ring has a title, full description isn't so useful */
802  char s[MAX_BUF];
803 
804  ring_desc(op, s, MAX_BUF);
805  if (s[0]) {
806  safe_strcat(buf, " ", &len, size);
807  safe_strcat(buf, s, &len, size);
808  }
809  }
810  break;
811 
812  default:
813  if (op->magic
815  snprintf(buf+strlen(buf), size-strlen(buf), " %+d", op->magic);
816  }
817  }
818 }
819 
840 void describe_monster(const object *op, char *retbuf, size_t size) {
841  int i;
842  size_t len;
843 
844  retbuf[0] = '\0';
845 
846  /* Note that the resolution this provides for players really isn't
847  * very good. Any player with a speed greater than .67 will
848  * fall into the 'lightning fast movement' category.
849  */
850  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
851  switch ((int)((FABS(op->speed))*15)) {
852  case 0:
853  snprintf(retbuf, size, "(very slow movement)");
854  break;
855 
856  case 1:
857  snprintf(retbuf, size, "(slow movement)");
858  break;
859 
860  case 2:
861  snprintf(retbuf, size, "(normal movement)");
862  break;
863 
864  case 3:
865  case 4:
866  snprintf(retbuf, size, "(fast movement)");
867  break;
868 
869  case 5:
870  case 6:
871  snprintf(retbuf, size, "(very fast movement)");
872  break;
873 
874  case 7:
875  case 8:
876  case 9:
877  case 10:
878  snprintf(retbuf, size, "(extremely fast movement)");
879  break;
880 
881  default:
882  snprintf(retbuf, size, "(lightning fast movement)");
883  break;
884  }
885  }
886  if (QUERY_FLAG(op, FLAG_UNDEAD))
887  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(undead)");
889  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(see invisible)");
890  if (QUERY_FLAG(op, FLAG_USE_WEAPON))
891  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(wield weapon)");
892  if (QUERY_FLAG(op, FLAG_USE_BOW))
893  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(archer)");
894  if (QUERY_FLAG(op, FLAG_USE_ARMOUR))
895  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(wear armour)");
896  if (QUERY_FLAG(op, FLAG_USE_RING))
897  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(wear ring)");
898  if (QUERY_FLAG(op, FLAG_USE_SCROLL))
899  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(read scroll)");
900  if (QUERY_FLAG(op, FLAG_USE_RANGE))
901  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(fires wand/rod/horn)");
903  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(skill user)");
904  if (QUERY_FLAG(op, FLAG_CAST_SPELL))
905  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(spellcaster)");
906  if (QUERY_FLAG(op, FLAG_FRIENDLY))
907  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(friendly)");
908  if (QUERY_FLAG(op, FLAG_UNAGGRESSIVE))
909  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(unaggressive)");
910  if (QUERY_FLAG(op, FLAG_HITBACK))
911  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(hitback)");
912  if (QUERY_FLAG(op, FLAG_STEALTH))
913  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(stealthy)");
914  if (op->randomitems != NULL) {
915  treasure *t;
916  int first = 1;
917 
918  for (t = op->randomitems->items; t != NULL; t = t->next)
919  if (t->item && (t->item->clone.type == SPELL)) {
920  if (first) {
921  first = 0;
922  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(Spell abilities:)");
923  }
924  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(%s)", t->item->clone.name);
925  }
926  }
927  if (op->type == PLAYER) {
928  if (op->contr->digestion) {
929  if (op->contr->digestion != 0)
930  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(sustenance%+d)", op->contr->digestion);
931  }
932  if (op->contr->gen_grace) {
933  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(grace%+d)", op->contr->gen_grace);
934  }
935  if (op->contr->gen_sp) {
936  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(magic%+d)", op->contr->gen_sp);
937  }
938  if (op->contr->gen_hp) {
939  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(regeneration%+d)", op->contr->gen_hp);
940  }
941  if (op->stats.luck) {
942  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(luck%+d)", op->stats.luck);
943  }
944  }
945 
946  /* describe attacktypes */
947  len = strlen(retbuf);
948  if (is_dragon_pl(op)) {
949  /* for dragon players display the attacktypes from clawing skill
950  * Break apart the for loop - move the comparison checking down -
951  * this makes it more readable.
952  */
953  object *tmp;
954 
955  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
956  if (tmp->type == SKILL && !strcmp(tmp->name, "clawing"))
957  break;
958 
959  if (tmp && tmp->attacktype != 0) {
960  DESCRIBE_ABILITY_SAFE(retbuf, tmp->attacktype, "Claws", &len, size);
961  } else {
962  DESCRIBE_ABILITY_SAFE(retbuf, op->attacktype, "Attacks", &len, size);
963  }
964  } else {
965  DESCRIBE_ABILITY_SAFE(retbuf, op->attacktype, "Attacks", &len, size);
966  }
967  DESCRIBE_PATH_SAFE(retbuf, op->path_attuned, "Attuned", &len, size);
968  DESCRIBE_PATH_SAFE(retbuf, op->path_repelled, "Repelled", &len, size);
969  DESCRIBE_PATH_SAFE(retbuf, op->path_denied, "Denied", &len, size);
970  for (i = 0; i < NROFATTACKS; i++) {
971  if (op->resist[i]) {
972  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(%s %+d)", resist_plus[i], op->resist[i]);
973  }
974  }
975 }
976 
1018 void describe_item(const object *op, const object *owner, char *retbuf, size_t size) {
1019  int identified, i;
1020 
1021  retbuf[0] = '\0';
1022  if (QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER) {
1023  describe_monster(op, retbuf, size);
1024  return;
1025  }
1026  /* figure this out once, instead of making multiple calls to need_identify.
1027  * also makes the code easier to read.
1028  */
1029  if (!need_identify(op) || QUERY_FLAG(op, FLAG_IDENTIFIED))
1030  identified = 1;
1031  else {
1032  snprintf(retbuf, size, "(unidentified)");
1033  identified = 0;
1034  }
1035  switch (op->type) {
1036  case BOW:
1037  case ARROW:
1038  case WAND:
1039  case ROD:
1040  case HORN:
1041  case WEAPON:
1042  case ARMOUR:
1043  case HELMET:
1044  case SHIELD:
1045  case BOOTS:
1046  case GLOVES:
1047  case GIRDLE:
1048  case BRACERS:
1049  case CLOAK:
1050  case SKILL_TOOL:
1051  break; /* We have more information to do below this switch */
1052 
1053  case LAMP:
1054  break; /* just so we get the "glowing" part. */
1055 
1056  case POWER_CRYSTAL:
1057  /* Avoid division by zero... */
1058  if (op->stats.maxsp == 0) {
1059  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(capacity %d).", op->stats.maxsp);
1060  } else {
1061  if (op->stats.maxsp > 1000) { /*higher capacity crystals*/
1062  i = (op->stats.maxsp%1000)/100;
1063  if (i)
1064  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(capacity %d.%dk). It is ", op->stats.maxsp/1000, i);
1065  else
1066  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(capacity %dk). It is ", op->stats.maxsp/1000);
1067  } else
1068  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(capacity %d). It is ", op->stats.maxsp);
1069  i = (op->stats.sp*10)/op->stats.maxsp;
1070  if (op->stats.sp == 0)
1071  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "empty.");
1072  else if (i == 0)
1073  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "almost empty.");
1074  else if (i < 3)
1075  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "partially filled.");
1076  else if (i < 6)
1077  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "half full.");
1078  else if (i < 9)
1079  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "well charged.");
1080  else if (op->stats.sp == op->stats.maxsp)
1081  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "fully charged.");
1082  else
1083  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "almost full.");
1084  }
1085  break;
1086 
1087  case FOOD:
1088  case FLESH:
1089  case DRINK:
1090  if (identified || QUERY_FLAG(op, FLAG_BEEN_APPLIED)) {
1091  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(food+%d)", op->stats.food);
1092 
1093  if (op->type == FLESH && op->last_eat > 0 && atnr_is_dragon_enabled(op->last_eat)) {
1094  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(%s metabolism)", change_resist_msg[op->last_eat]);
1095  }
1096 
1097  if (!QUERY_FLAG(op, FLAG_CURSED)) {
1098  if (op->stats.hp)
1099  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(heals)");
1100  if (op->stats.sp)
1101  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(spellpoint regen)");
1102  } else {
1103  if (op->stats.hp)
1104  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(damages)");
1105  if (op->stats.sp)
1106  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(spellpoint depletion)");
1107  }
1108  }
1109  break;
1110 
1111  case SKILL:
1112  case RING:
1113  case AMULET:
1114  if (op->item_power) {
1115  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(item_power %+d)", op->item_power);
1116  }
1117  if (op->title) {
1118  ring_desc(op, retbuf+strlen(retbuf), size-strlen(retbuf));
1119  }
1120  return;
1121 
1122  default:
1123  return;
1124  }
1125 
1126  /* Down here, we more further describe equipment type items.
1127  * only describe them if they have been identified or the like.
1128  */
1129  if (identified || QUERY_FLAG(op, FLAG_BEEN_APPLIED)) {
1130  int attr, val;
1131 
1132  for (attr = 0; attr < NUM_STATS; attr++) {
1133  if ((val = get_attr_value(&(op->stats), attr)) != 0) {
1134  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(%s%+d)", short_stat_name[attr], val);
1135  }
1136  }
1137  if (op->glow_radius)
1138  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(glowing)");
1139 
1140  switch (op->type) {
1141  case FLESH:
1142  break;
1143 
1144  default:
1145  if (op->stats.exp) {
1146  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(speed %+"FMT64")", op->stats.exp);
1147  }
1148  break;
1149  }
1150  switch (op->type) {
1151  case BOW:
1152  case ARROW:
1153  case GIRDLE:
1154  case HELMET:
1155  case SHIELD:
1156  case BOOTS:
1157  case GLOVES:
1158  case WEAPON:
1159  case SKILL:
1160  case RING:
1161  case AMULET:
1162  case ARMOUR:
1163  case BRACERS:
1164  case FORCE:
1165  case CLOAK:
1166  if (op->stats.wc) {
1167  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(wc%+d)", op->stats.wc);
1168  }
1169  if (op->stats.dam) {
1170  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(dam%+d)", op->stats.dam);
1171  }
1172  if (op->stats.ac) {
1173  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(ac%+d)", op->stats.ac);
1174  }
1175  if ((op->type == WEAPON || op->type == BOW) && op->level > 0) {
1176  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(improved %d/%d)", op->last_eat, op->level);
1177  }
1178  break;
1179 
1180  default:
1181  break;
1182  }
1183  if (QUERY_FLAG(op, FLAG_XRAYS))
1184  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(xray-vision)");
1185  if (QUERY_FLAG(op, FLAG_SEE_IN_DARK))
1186  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(infravision)");
1187 
1188  /* levitate was what is was before, so we'll keep it */
1189  if (op->move_type&MOVE_FLY_LOW)
1190  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(levitate)");
1191 
1192  if (op->move_type&MOVE_FLY_HIGH)
1193  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(fly)");
1194 
1195  if (op->move_type&MOVE_SWIM)
1196  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(swim)");
1197 
1198  /* walking is presumed as 'normal', so doesn't need mentioning */
1199 
1200  if (op->item_power) {
1201  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(item_power %+d)", op->item_power);
1202  }
1203  } /* End if identified or applied */
1204 
1205  /* This blocks only deals with fully identified object.
1206  * it is intentional that this is not an 'else' from a above -
1207  * in this way, information is added.
1208  */
1209  if (identified) {
1210  int more_info = 0;
1211  size_t len;
1212 
1213  switch (op->type) {
1214  case ROD: /* These use stats.sp for spell selection and stats.food */
1215  case HORN: /* and stats.hp for spell-point regeneration... */
1216  case BOW:
1217  case ARROW:
1218  case WAND:
1219  case FOOD:
1220  case FLESH:
1221  case DRINK:
1222  more_info = 0;
1223  break;
1224 
1225  /* Armor type objects */
1226  case ARMOUR:
1227  case HELMET:
1228  case SHIELD:
1229  case BOOTS:
1230  case GLOVES:
1231  case GIRDLE:
1232  case BRACERS:
1233  case CLOAK:
1234  if (ARMOUR_SPEED(op)) {
1235  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(Max speed %1.2f)", ARMOUR_SPEED(op)/10.0);
1236  }
1237  if (ARMOUR_SPELLS(op)) {
1238  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(Spell regen penalty %d)", ARMOUR_SPELLS(op));
1239  }
1240  more_info = 1;
1241  break;
1242 
1243  case WEAPON:
1244  /* Calculate it the same way fix_object does so the results
1245  * make sense.
1246  */
1247  i = (WEAPON_SPEED(op)*2-op->magic)/2;
1248  if (i < 0)
1249  i = 0;
1250 
1251  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(weapon speed %d)", i);
1252  more_info = 1;
1253  break;
1254  }
1255  if (more_info) {
1256  if (op->stats.food) {
1257  if (op->stats.food != 0)
1258  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(sustenance%+d)", op->stats.food);
1259  }
1260  if (op->stats.grace) {
1261  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(grace%+d)", op->stats.grace);
1262  }
1263  if (op->stats.sp) {
1264  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(magic%+d)", op->stats.sp);
1265  }
1266  if (op->stats.hp) {
1267  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(regeneration%+d)", op->stats.hp);
1268  }
1269  }
1270 
1271  if (op->stats.luck) {
1272  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(luck%+d)", op->stats.luck);
1273  }
1274  if (QUERY_FLAG(op, FLAG_LIFESAVE))
1275  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(lifesaving)");
1276  if (QUERY_FLAG(op, FLAG_REFL_SPELL))
1277  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(reflect spells)");
1278  if (QUERY_FLAG(op, FLAG_REFL_MISSILE))
1279  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(reflect missiles)");
1280  if (QUERY_FLAG(op, FLAG_STEALTH))
1281  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(stealth)");
1282  if (op->slaying != NULL && op->type != FOOD) {
1283  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "(slay %s)", op->slaying);
1284  }
1285  len = strlen(retbuf);
1286  DESCRIBE_ABILITY_SAFE(retbuf, op->attacktype, "Attacks", &len, size);
1287  /* resistance on flesh is only visible for dragons. If
1288  * non flesh, everyone can see its resistances
1289  */
1290  if (op->type != FLESH || (owner && is_dragon_pl(owner))) {
1291  describe_resistance(op, 0, retbuf+strlen(retbuf), size-strlen(retbuf));
1292  }
1293  len = strlen(retbuf);
1294  DESCRIBE_PATH_SAFE(retbuf, op->path_attuned, "Attuned", &len, size);
1295  DESCRIBE_PATH_SAFE(retbuf, op->path_repelled, "Repelled", &len, size);
1296  DESCRIBE_PATH_SAFE(retbuf, op->path_denied, "Denied", &len, size);
1297  }
1298 }
1299 
1312 int is_magical(const object *op) {
1313  int i;
1314 
1315  /* living creatures are considered non magical */
1316  if (QUERY_FLAG(op, FLAG_ALIVE))
1317  return 0;
1318 
1319  /* This is a test for it being an artifact, as artifacts have titles */
1320  if (op->title != NULL)
1321  return 1;
1322 
1323  /* Handle rings and amulets specially. If they change any of these
1324  * values, it means they are magical.
1325  */
1326  if ((op->type == AMULET || op->type == RING)
1327  && (op->stats.ac || op->stats.food || op->stats.exp || op->stats.dam || op->stats.wc || op->stats.sp || op->stats.hp || op->stats.luck))
1328  return 1;
1329 
1330  /* Check for stealty, speed, flying, or just plain magic in the boots */
1331  /* Presume any boots that have a move_type are special. */
1332  if (op->type == BOOTS
1333  && ((QUERY_FLAG(op, FLAG_STEALTH) || op->move_type || op->stats.exp)))
1334  return 1;
1335 
1336  /* Take care of amulet/shield that reflects spells/missiles */
1337  if ((op->type == AMULET || op->type == SHIELD)
1339  return 1;
1340 
1341  /* Take care of helmet of xrays */
1342  if (op->type == HELMET
1343  && QUERY_FLAG(op, FLAG_XRAYS))
1344  return 1;
1345 
1346  /* Potions & rods are always magical. Wands/staves are also magical,
1347  * assuming they still have any charges left.
1348  */
1349  if (op->type == POTION || op->type == ROD || (op->type == WAND && op->stats.food))
1350  return 1;
1351 
1352  /* if something gives a protection, either positive or negative, its magical */
1353  /* This is really a pretty bad hack - as of now, ATNR_PHYSICAL is 0,
1354  * so this always works out fine.
1355  */
1356  for (i = ATNR_PHYSICAL+1; i < NROFATTACKS; i++)
1357  if (op->resist[i])
1358  return 1;
1359 
1360  /* Physical protection is expected on some item types, so they should
1361  * not be considered magical.
1362  */
1363  if (op->resist[ATNR_PHYSICAL]
1364  && op->type != HELMET
1365  && op->type != SHIELD
1366  && op->type != BOOTS
1367  && op->type != GLOVES
1368  && op->type != ARMOUR)
1369  return 1;
1370 
1371  /* power crystal, spellbooks, and scrolls are always magical. */
1372  if (op->magic
1373  || op->type == POWER_CRYSTAL
1374  || op->type == SPELLBOOK
1375  || op->type == SCROLL
1376  || op->type == GIRDLE)
1377  return 1;
1378 
1379  /* Check to see if it increases/decreases any stats */
1380  for (i = 0; i < NUM_STATS; i++)
1381  if (get_attr_value(&(op->stats), i) != 0)
1382  return 1;
1383 
1384  /* If it doesn't fall into any of the above categories, must
1385  * be non magical.
1386  */
1387  return 0;
1388 }
1389 
1401 int need_identify(const object *op) {
1402  switch (op->type) {
1403  case RING:
1404  case WAND:
1405  case ROD:
1406  case HORN:
1407  case SCROLL:
1408  case SKILL:
1409  case SKILLSCROLL:
1410  case SPELLBOOK:
1411  case FOOD:
1412  case POTION:
1413  case BOW:
1414  case ARROW:
1415  case WEAPON:
1416  case ARMOUR:
1417  case SHIELD:
1418  case HELMET:
1419  case AMULET:
1420  case BOOTS:
1421  case GLOVES:
1422  case BRACERS:
1423  case GIRDLE:
1424  case CONTAINER:
1425  case DRINK:
1426  case FLESH:
1427  case INORGANIC:
1428  case CLOSE_CON:
1429  case CLOAK:
1430  case GEM:
1431  case POWER_CRYSTAL:
1432  case POISON:
1433  case BOOK:
1434  case SKILL_TOOL:
1435  return 1;
1436  }
1437  return 0;
1438 }
1439 
1447 void identify(object *op) {
1448  object *pl;
1449 
1453 
1454  /*
1455  * We want autojoining of equal objects:
1456  */
1457  if (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED))
1459 
1460  if (QUERY_FLAG(op, FLAG_BLESSED))
1462 
1463  if (op->type == POTION) {
1464  if (op->inv && op->randomitems) {
1465  if (op->title)
1466  free_string(op->title);
1467  op->title = add_refcount(op->inv->name);
1468  } else if (op->arch) {
1469  free_string(op->name);
1470  op->name = add_refcount(op->arch->clone.name);
1471  free_string(op->name_pl);
1472  op->name_pl = add_refcount(op->arch->clone.name_pl);
1473  }
1474  }
1475 
1476  if (op->map) {
1477  /* If the object is on a map, make sure we update its face.
1478  * Also send name and such information to a player standing on it.
1479  */
1480  object *player = present(PLAYER, op->map, op->x, op->y);
1481  if (player)
1482  esrv_update_item(UPD_FACE | UPD_NAME, player, op);
1484  } else {
1485  pl = get_player_container(op->env);
1486  if (pl)
1487  /* A lot of the values can change from an update - might as well send
1488  * it all.
1489  */
1490  esrv_update_item(UPD_ALL, pl, op);
1491  }
1492 }
#define FLAG_KNOWN_BLESSED
Definition: define.h:675
#define SKILLSCROLL
Definition: define.h:313
#define FOOD
Definition: define.h:118
#define RING
Definition: define.h:232
#define NUM_BODY_LOCATIONS
Definition: object.h:41
Definition: player.h:146
#define FLAG_SEE_IN_DARK
Definition: define.h:634
#define WEAPON_SPEED(xyz)
Definition: define.h:790
#define FLAG_DAMNED
Definition: define.h:614
#define FLAG_UNPAID
Definition: define.h:532
sint8 ac
Definition: living.h:79
#define UP_OBJ_FACE
Definition: object.h:356
#define DISEASE
Definition: define.h:331
#define CHECK_INV
Definition: define.h:206
MoveType move_type
Definition: object.h:277
#define BUTTON
Definition: define.h:274
#define DEAD_OBJECT
Definition: define.h:186
#define TRAPDOOR
Definition: define.h:277
#define TELEPORTER
Definition: define.h:155
materialtype_t * name_to_material(const char *name)
Definition: utils.c:262
int is_magical(const object *op)
Definition: item.c:1312
#define FLAG_HITBACK
Definition: define.h:563
#define EARTHWALL
Definition: define.h:167
#define FLAG_USE_SCROLL
Definition: define.h:588
static const char levelnumbers_10[11][20]
Definition: item.c:97
#define SET_FLAG(xyz, p)
Definition: define.h:510
const char * name
Definition: material.h:63
sstring add_refcount(sstring str)
Definition: shstr.c:202
#define ARMOUR_SPELLS(xyz)
Definition: define.h:789
#define CLOSE_CON
Definition: define.h:303
int get_power_from_ench(int ench)
Definition: item.c:240
#define FABS(x)
Definition: define.h:61
#define ENCOUNTER
Definition: define.h:229
signed int sint32
Definition: global.h:64
#define TRAP
Definition: define.h:326
#define WAND
Definition: define.h:291
uint16 material
Definition: object.h:198
#define MISC_OBJECT
Definition: define.h:248
#define FLAG_USE_ARMOUR
Definition: define.h:592
void get_levelnumber(int i, char *buf, size_t size)
Definition: item.c:444
#define UPD_NAME
Definition: newclient.h:258
#define CORPSE
Definition: define.h:329
struct obj * container
Definition: object.h:149
#define FLAG_FRIENDLY
Definition: define.h:542
#define MONEY
Definition: define.h:148
#define LIGHTER
Definition: define.h:237
sint16 digestion
Definition: player.h:166
#define DOOR
Definition: define.h:135
sint8 get_attr_value(const living *stats, int attr)
Definition: living.c:377
void free_string(sstring str)
Definition: shstr.c:272
#define MAP
Definition: define.h:134
struct treasureliststruct * randomitems
Definition: object.h:236
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:732
object clone
Definition: object.h:326
#define SK_BOWYER
Definition: skills.h:51
#define POTION
Definition: define.h:117
void query_weight(const object *op, char *buf, size_t size)
Definition: item.c:424
const char * slaying
Definition: object.h:172
#define IS_WEAPON(op)
Definition: define.h:449
#define SK_THAUMATURGY
Definition: skills.h:76
static const int enc_to_item_power[21]
Definition: item.c:233
#define SCROLL
Definition: define.h:293
#define FLAG_STEALTH
Definition: define.h:609
void update_object(object *op, int action)
Definition: object.c:1112
#define EXPERIENCE
Definition: define.h:158
#define FLAG_USE_WEAPON
Definition: define.h:593
sint64 exp
Definition: living.h:88
#define RUNE
Definition: define.h:325
static const char numbers_10[10][20]
Definition: item.c:83
#define SK_SMITHERY
Definition: skills.h:50
static void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: define.h:924
#define BOOTS
Definition: define.h:281
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
Definition: item.c:64
#define GOLEM
Definition: define.h:168
static const typedata item_types[]
Definition: item.c:109
#define CLOAK
Definition: define.h:268
sint16 x
Definition: object.h:179
#define GIRDLE
Definition: define.h:295
uint32 path_attuned
Definition: object.h:194
const typedata * get_typedata_by_name(const char *name)
Definition: item.c:372
#define PEACEMAKER
Definition: define.h:197
sint16 sp
Definition: living.h:83
uint32 path_repelled
Definition: object.h:195
#define ARMOUR
Definition: define.h:128
#define FLAG_USE_RING
Definition: define.h:594
sint16 gen_hp
Definition: player.h:167
#define PLAYER
Definition: define.h:113
#define POTION_EFFECT
Definition: define.h:297
struct archt * item
Definition: treasure.h:93
sint16 maxsp
Definition: living.h:84
sint16 hp
Definition: living.h:81
#define MAGIC_EAR
Definition: define.h:141
#define FLAG_KNOWN_MAGICAL
Definition: define.h:616
sint16 gen_grace
Definition: player.h:170
#define SPECIAL_KEY
Definition: define.h:133
const typedata * get_typedata(int itemtype)
Definition: item.c:352
#define POISONING
Definition: define.h:287
static void ring_desc(const object *op, char *buf, size_t size)
Definition: item.c:483
#define FLAG_SEE_INVISIBLE
Definition: define.h:549
#define AMULET
Definition: define.h:153
#define FLAG_UNDEAD
Definition: define.h:566
#define SPINNER
Definition: define.h:272
const char * title
Definition: object.h:170
#define POISON
Definition: define.h:119
void describe_resistance(const object *op, int newline, char *buf, size_t size)
Definition: item.c:399
static const int item_types_size
Definition: item.c:222
uint32 path_denied
Definition: object.h:196
#define SHOP_FLOOR
Definition: define.h:230
#define FLAG_ALIVE
Definition: define.h:526
#define SYMPTOM
Definition: define.h:332
#define FLAG_REFL_SPELL
Definition: define.h:571
#define CREATOR
Definition: define.h:156
const char * name_pl
Definition: object.h:168
object * get_player_container(object *op)
Definition: object.c:356
#define WEAPON_IMPROVER
Definition: define.h:308
#define MOVE_SWIM
Definition: define.h:704
const char * materialname
Definition: object.h:197
sint32 weight
Definition: object.h:216
#define FLAG_CAN_USE_SKILL
Definition: define.h:618
#define MOVE_FLY_LOW
Definition: define.h:701
#define WALL
Definition: define.h:244
#define FLAG_UNAGGRESSIVE
Definition: define.h:568
struct mapdef * map
Definition: object.h:155
int is_dragon_pl(const object *op)
Definition: player.c:125
#define KEY
Definition: define.h:136
#define HORN
Definition: define.h:147
#define MOOD_FLOOR
Definition: define.h:207
#define FLAG_IDENTIFIED
Definition: define.h:557
void identify(object *op)
Definition: item.c:1447
#define GRIMREAPER
Definition: define.h:140
sint16 dam
Definition: living.h:87
sint32 carrying
Definition: object.h:218
const char * name
Definition: object.h:167
struct obj * env
Definition: object.h:151
#define SPELL
Definition: define.h:283
#define SK_LITERACY
Definition: skills.h:55
#define ARMOUR_SPEED(xyz)
Definition: define.h:788
#define FLESH
Definition: define.h:234
#define PEDESTAL
Definition: define.h:129
#define DEEP_SWAMP
Definition: define.h:316
object * present(uint8 type, mapstruct *m, int x, int y)
Definition: object.c:2782
struct obj * below
Definition: object.h:145
#define BATTLEGROUND
Definition: define.h:195
uint32 nrof
Definition: object.h:184
#define SK_WOODSMAN
Definition: skills.h:68
EXTERN const char *const change_resist_msg[NROFATTACKS]
Definition: attack.h:163
#define BLINDNESS
Definition: define.h:171
#define UPD_ALL
Definition: newclient.h:262
#define GOD
Definition: define.h:172
sint16 y
Definition: object.h:179
struct pl * contr
Definition: object.h:134
#define LOCKED_DOOR
Definition: define.h:132
#define SHOP_MAT
Definition: define.h:231
sint8 item_power
Definition: object.h:213
#define WEAPON
Definition: define.h:127
#define MARKER
Definition: define.h:188
#define TRIGGER_MARKER
Definition: define.h:181
#define FLAG_XRAYS
Definition: define.h:597
#define ATNR_PHYSICAL
Definition: attack.h:77
#define TRIGGER_PEDESTAL
Definition: define.h:144
sint8 luck
Definition: living.h:80
float speed
Definition: object.h:181
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
#define SK_ALCHEMY
Definition: skills.h:53
#define CLEAR_FLAG(xyz, p)
Definition: define.h:512
#define TRIGGER
Definition: define.h:139
#define TRIGGER_BUTTON
Definition: define.h:142
#define GEM
Definition: define.h:202
#define FLAG_BEEN_APPLIED
Definition: define.h:620
#define EXIT
Definition: define.h:228
#define MAX_BUF
Definition: define.h:81
#define NRSPELLPATHS
Definition: spells.h:68
#define GLOVES
Definition: define.h:282
#define IS_SHIELD(op)
Definition: define.h:456
#define FLAG_CAST_SPELL
Definition: define.h:587
#define M_SPECIAL
Definition: material.h:57
#define BUILDER
Definition: define.h:334
#define BOOK
Definition: define.h:120
#define BRACERS
Definition: define.h:286
struct treasurestruct * items
Definition: treasure.h:119
#define DUPLICATOR
Definition: define.h:264
sint32 last_eat
Definition: object.h:207
#define SIGN
Definition: define.h:280
sint8 wc
Definition: living.h:79
#define SHOP_INVENTORY
Definition: define.h:319
#define CLASS
Definition: define.h:149
#define LAMP
Definition: define.h:263
#define TIMED_GATE
Definition: define.h:138
#define THROWN_OBJ
Definition: define.h:170
#define FLOOR
Definition: define.h:233
sint16 resist[NROFATTACKS]
Definition: object.h:192
#define FLAG_KNOWN_CURSED
Definition: define.h:617
int need_identify(const object *op)
Definition: item.c:1401
#define TRIGGER_ALTAR
Definition: define.h:143
#define DESCRIBE_PATH_SAFE(retbuf, variable, name, len, maxlen)
Definition: define.h:986
#define FLAG_CURSED
Definition: define.h:613
#define SHIELD
Definition: define.h:145
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
#define FORCE
Definition: define.h:296
#define SAVEBED
Definition: define.h:288
void esrv_update_item(int flags, object *pl, object *op)
Definition: item.c:359
#define INORGANIC
Definition: define.h:235
uint32 attacktype
Definition: object.h:193
#define ALTAR
Definition: define.h:130
#define NUM_STATS
Definition: living.h:48
#define CONTAINER
Definition: define.h:306
#define VERY_BIG_BUF
Definition: define.h:82
sint16 grace
Definition: living.h:85
#define FIREWALL
Definition: define.h:204
living stats
Definition: object.h:219
#define DETECTOR
Definition: define.h:174
struct archt * arch
Definition: object.h:263
#define PLAYERMOVER
Definition: define.h:154
#define SKILL
Definition: define.h:157
#define CF_HANDLE
Definition: define.h:275
#define ARMOUR_IMPROVER
Definition: define.h:307
#define CLOCK
Definition: define.h:121
#define SPELL_EFFECT
Definition: define.h:284
#define FLAG_APPLIED
Definition: define.h:531
#define NROFATTACKS
Definition: attack.h:45
EXTERN const char *const resist_plus[NROFATTACKS]
Definition: attack.h:164
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:551
#define FLAG_LIFESAVE
Definition: define.h:602
#define FLAG_MAKE_INVIS
Definition: define.h:625
#define MONSTER
Definition: define.h:261
void describe_monster(const object *op, char *retbuf, size_t size)
Definition: item.c:840
#define DESCRIBE_ABILITY_SAFE(retbuf, variable, name, len, maxlen)
Definition: define.h:939
void describe_item(const object *op, const object *owner, char *retbuf, size_t size)
Definition: item.c:1018
#define BOW
Definition: define.h:126
#define DRINK
Definition: define.h:187
sint16 gen_sp
Definition: player.h:168
#define MIN_ACTIVE_SPEED
Definition: define.h:1063
sint8 glow_radius
Definition: object.h:215
#define FLAG_MONSTER
Definition: define.h:541
#define TREASURE
Definition: define.h:116
struct obj * inv
Definition: object.h:148
#define HELMET
Definition: define.h:146
#define MOVE_FLY_HIGH
Definition: define.h:702
#define SPELLBOOK
Definition: define.h:266
#define DIRECTOR
Definition: define.h:294
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
#define FLAG_USE_RANGE
Definition: define.h:589
#define ARROW
Definition: define.h:125
#define ROD
Definition: define.h:115
#define IS_ARMOR(op)
Definition: define.h:452
#define IDENTIFY_ALTAR
Definition: define.h:317
#define HOLE
Definition: define.h:276
#define SKILL_TOOL
Definition: define.h:236
int calc_item_power(const object *op, int flag)
Definition: item.c:264
#define UPD_FACE
Definition: newclient.h:257
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:628
#define FLAG_BLESSED
Definition: define.h:674
#define HOLY_ALTAR
Definition: define.h:193
#define MATERIAL
Definition: define.h:337
#define FLAG_NO_SKILL_IDENT
Definition: define.h:632
const char *const short_stat_name[NUM_STATS]
Definition: living.c:278
struct treasurestruct * next
Definition: treasure.h:95
#define FLAG_REFL_MISSILE
Definition: define.h:569
sint16 level
Definition: object.h:202
#define FLAG_INV_LOCKED
Definition: define.h:626
#define GATE
Definition: define.h:273
sint8 magic
Definition: object.h:199
#define PLAYER_CHANGER
Definition: define.h:194
#define CONVERTER
Definition: define.h:285
#define FLAG_USE_BOW
Definition: define.h:590
uint8 type
Definition: object.h:189
#define POWER_CRYSTAL
Definition: define.h:328
int atnr_is_dragon_enabled(int attacknr)
Definition: player.c:106
#define SK_JEWELER
Definition: skills.h:52
sint32 food
Definition: living.h:89
const char * description
Definition: material.h:64
static const char levelnumbers[21][20]
Definition: item.c:89