ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/item.C
Revision: 1.101
Committed: Sat Dec 1 20:22:12 2018 UTC (5 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.100: +1 -1 lines
Log Message:
slight cleanup

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.41 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.96 *
4 root 1.100 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 root 1.98 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 root 1.73 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
7     * Copyright (©) 1992 Frank Tore Johansen
8 root 1.96 *
9 root 1.58 * Deliantra is free software: you can redistribute it and/or modify it under
10     * the terms of the Affero GNU General Public License as published by the
11     * Free Software Foundation, either version 3 of the License, or (at your
12     * option) any later version.
13 root 1.96 *
14 root 1.38 * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18 root 1.96 *
19 root 1.58 * You should have received a copy of the Affero GNU General Public License
20     * and the GNU General Public License along with this program. If not, see
21     * <http://www.gnu.org/licenses/>.
22 root 1.96 *
23 root 1.41 * The authors can be reached via e-mail to <support@deliantra.net>
24 pippijn 1.19 */
25 elmex 1.1
26     #include <global.h>
27     #include <living.h>
28     #include <spells.h>
29    
30 root 1.42 const char *const coins[NUM_COINS + 1] = { "royalty", "platinacoin", "goldcoin", "silvercoin", 0 };
31    
32 elmex 1.1 /* the ordering of this is actually doesn't make a difference
33     * However, for ease of use, new entries should go at the end
34     * so those people that debug the code that get used to something
35     * being in the location 4 don't get confused.
36     *
37     * The ordering in save_name, use_name, nonuse_name.
38     * save_name is the name used to load/save it from files. It should
39     * match that of the doc/Developers/objects. The only
40     * real limitation is that it shouldn't have spaces or other characters
41     * that may mess up the match code. It must also start with body_
42     * use_name is how we describe the location if we can use it.
43     * nonuse_name is how we describe it if we can't use it. I think
44     * the values below will make it pretty clear how those work out
45     * They are basically there to make life a little easier - if a character
46     * examines an item and it says it goes on 'your arm', its pretty clear
47     * they can use it. See the last sample (commented out) for a dragon
48     * Note that using the term 'human' may not be very accurate, humanoid
49     * may be better.
50     * Basically, for the use/nonuse, the code does something like:
51     * "This item goes %s\n", with the use/nonuse values filling in the %s
52     */
53 root 1.77 // see include/object.h
54 elmex 1.1 Body_Locations body_locations[NUM_BODY_LOCATIONS] = {
55 root 1.90 # define def(name, use, nonuse) { # name, KW_body_ ## name, use, nonuse },
56     # include "slotinc.h"
57     # undef def
58 elmex 1.1 };
59    
60     static char numbers_10[10][20] = {
61 root 1.4 "zero", "ten", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy",
62     "eighty", "ninety"
63 elmex 1.1 };
64    
65 root 1.81 static char ordnumbers[21][20] = {
66 root 1.4 "zeroth", "first", "second", "third", "fourth", "fifth", "sixth", "seventh",
67 elmex 1.1 "eighth", "ninth", "tenth", "eleventh", "twelfth", "thirteenth",
68 root 1.81 "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth",
69     "nineteenth", "twentieth"
70 elmex 1.1 };
71    
72 root 1.81 static char ordnumbers_10[11][20] = {
73 root 1.4 "zeroth", "tenth", "twentieth", "thirtieth", "fortieth", "fiftieth", "sixtieth",
74     "seventieth", "eightieth", "ninetieth"
75 elmex 1.1 };
76    
77     /* The following is a large table of item types, the fields are:
78     * item number, item name, item name (plural), and two numbers that are the skills
79     * used to identify them. Anytime a new item type is added or removed, this list
80 root 1.99 * should be altered to reflect that. The defines for the numerical values are in
81     * define.h
82 elmex 1.1 */
83     static const typedata item_types[] = {
84 root 1.4 {PLAYER, "player", "players", 0, 0},
85     {ROD, "rod", "rods", SK_THAUMATURGY, 0},
86     {TREASURE, "treasure", "treasure", 0, 0},
87     {POTION, "potion", "potions", SK_ALCHEMY, 0},
88     {FOOD, "food", "food", SK_WOODSMAN, 0},
89     {POISON, "poison", "poisons", SK_ALCHEMY, 0},
90     {BOOK, "book", "books", SK_LITERACY, 0},
91     {CLOCK, "clock", "clocks", 0, 0},
92     {ARROW, "arrow", "arrows", SK_BOWYER, 0},
93     {BOW, "bow", "bows", SK_BOWYER, 0},
94     {WEAPON, "weapon", "weapons", SK_SMITHERY, 0},
95     {ARMOUR, "armour", "armour", SK_SMITHERY, 0},
96     {PEDESTAL, "pedestal", "pedestals", 0, 0},
97     {ALTAR, "altar", "altars", 0, 0},
98     {LOCKED_DOOR, "locked door", "locked doors", 0, 0},
99     {SPECIAL_KEY, "special key", "special keys", 0, 0},
100     {MAP, "map", "maps", 0, 0},
101     {DOOR, "door", "doors", 0, 0},
102     {KEY, "key", "keys", 0, 0},
103     {TIMED_GATE, "timed_gate", "timed_gates", 0, 0},
104     {TRIGGER, "trigger", "triggers", 0, 0},
105     {GRIMREAPER, "grimreaper", "grimreapers", 0, 0},
106     {MAGIC_EAR, "magic ear", "magic ears", 0, 0},
107     {TRIGGER_BUTTON, "trigger button", "trigger buttons", 0, 0},
108     {TRIGGER_ALTAR, "trigger altar", "trigger altars", 0, 0},
109     {TRIGGER_PEDESTAL, "trigger pedestal", "trigger pedestals", 0, 0},
110     {SHIELD, "shield", "shields", SK_SMITHERY, 0},
111     {HELMET, "helmet", "helmets", SK_SMITHERY, 0},
112     {HORN, "horn", "horns", SK_THAUMATURGY, 0},
113     {MONEY, "money", "money", 0, 0},
114     {CLASS, "class", "classes", 0, 0},
115     {GRAVESTONE, "gravestone", "gravestones", 0, 0},
116     {AMULET, "amulet", "amulets", SK_JEWELER, 0},
117     {PLAYERMOVER, "player mover", "player movers", 0, 0},
118     {TELEPORTER, "teleporter", "teleporters", 0, 0},
119     {CREATOR, "creator", "creators", 0, 0},
120     {SKILL, "skill", "skills", 0, 0},
121     {EARTHWALL, "earthwall", "earthwalls", 0, 0},
122     {GOLEM, "golem", "golems", 0, 0},
123     {THROWN_OBJ, "projectile", "projectiles", 0, 0},
124     {BLINDNESS, "blindness", "blindness", 0, 0},
125     {GOD, "god", "gods", 0, 0},
126     {DETECTOR, "detector", "detectors", 0, 0},
127     {TRIGGER_MARKER, "trigger marker", "trigger markers", 0, 0},
128     {DEAD_OBJECT, "dead object", "dead objects", 0, 0},
129     {DRINK, "drink", "drinks", SK_WOODSMAN, SK_ALCHEMY},
130     {MARKER, "marker", "markers", 0, 0},
131     {HOLY_ALTAR, "holy altar", "holy altars", 0, 0},
132     {PLAYER_CHANGER, "player changer", "player changers", 0, 0},
133     {BATTLEGROUND, "battleground", "battlegrounds", 0, 0},
134     {PEACEMAKER, "peacemaker", "peacemakers", 0, 0},
135     {GEM, "gem", "gems", SK_JEWELER, 0},
136     {FIREWALL, "firewall", "firewalls", 0, 0},
137     {ANVIL, "anvil", "anvils", 0, 0},
138     {CHECK_INV, "inventory checker", "inventory checkers", 0, 0},
139     {MOOD_FLOOR, "mood floor", "mood floors", 0, 0},
140     {EXIT, "exit", "exits", 0, 0},
141     {ENCOUNTER, "encounter", "encounters", 0, 0},
142     {SHOP_FLOOR, "shop floor", "shop floors", 0, 0},
143     {SHOP_MAT, "shop mat", "shop mats", 0, 0},
144     {RING, "ring", "rings", SK_JEWELER, 0},
145 root 1.82 // {FLOOR, "floor", "floors", 0, 0},
146 root 1.4 {FLESH, "flesh", "flesh", SK_WOODSMAN, 0},
147     {INORGANIC, "inorganic", "inorganics", SK_ALCHEMY, 0},
148     {SKILL_TOOL, "skill tool", "skill tools", 0, 0},
149     {LIGHTER, "lighter", "lighters", 0, 0},
150 elmex 1.12 {BUILDABLE_WALL, "buildable wall", "buildable walls", 0, 0},
151 root 1.4 {MISC_OBJECT, "bric-a-brac", "bric-a-brac", 0, 0},
152 root 1.92 {TORCH, "torch", "torches", 0, 0},
153 root 1.4 {LAMP, "lamp", "lamps", 0, 0},
154     {DUPLICATOR, "duplicator", "duplicators", 0, 0},
155     {SPELLBOOK, "spellbook", "spellbooks", SK_LITERACY, 0},
156     {CLOAK, "cloak", "cloaks", SK_SMITHERY, 0},
157     {SPINNER, "spinner", "spinners", 0, 0},
158     {GATE, "gate", "gates", 0, 0},
159     {BUTTON, "button", "buttons", 0, 0},
160 root 1.59 {T_HANDLE, "cf handle", "cf handles", 0, 0},
161 root 1.4 {HOLE, "hole", "holes", 0, 0},
162     {TRAPDOOR, "trapdoor", "trapdoors", 0, 0},
163     {SIGN, "sign", "signs", 0, 0},
164     {BOOTS, "boots", "boots", SK_SMITHERY, 0},
165     {GLOVES, "gloves", "gloves", SK_SMITHERY, 0},
166     {SPELL, "spell", "spells", 0, 0},
167     {SPELL_EFFECT, "spell effect", "spell effects", 0, 0},
168     {CONVERTER, "converter", "converters", 0, 0},
169     {BRACERS, "bracers", "bracers", SK_SMITHERY, 0},
170     {POISONING, "poisoning", "poisonings", 0, 0},
171     {SAVEBED, "savebed", "savebeds", 0, 0},
172     {WAND, "wand", "wands", SK_THAUMATURGY, 0},
173     {SCROLL, "scroll", "scrolls", SK_LITERACY, 0},
174     {DIRECTOR, "director", "directors", 0, 0},
175     {GIRDLE, "girdle", "girdles", SK_SMITHERY, 0},
176     {FORCE, "force", "forces", 0, 0},
177     {POTION_EFFECT, "potion effect", "potion effects", 0, 0},
178     {CLOSE_CON, "closed container", "closed container", 0, 0},
179     {CONTAINER, "container", "containers", SK_ALCHEMY, 0},
180     {ARMOUR_IMPROVER, "armour improver", "armour improvers", 0, 0},
181     {WEAPON_IMPROVER, "weapon improver", "weapon improvers", 0, 0},
182     {SKILLSCROLL, "skillscroll", "skillscrolls", 0, 0},
183     {DEEP_SWAMP, "deep swamp", "deep swamps", 0, 0},
184     {IDENTIFY_ALTAR, "identify altar", "identify altars", 0, 0},
185     {MENU, "inventory list", "inventory lists", 0, 0},
186     {RUNE, "rune", "runes", 0, 0},
187     {TRAP, "trap", "traps", 0, 0},
188     {POWER_CRYSTAL, "power_crystal", "power_crystals", 0, 0},
189     {CORPSE, "corpse", "corpses", 0, 0},
190     {DISEASE, "disease", "diseases", 0, 0},
191     {SYMPTOM, "symptom", "symptoms", 0, 0},
192     {BUILDER, "item builder", "item builders", 0, 0},
193     {MATERIAL, "building material", "building materials", 0, 0},
194     {ITEM_TRANSFORMER, "item_transformer", "item_transformers", 0, 0},
195 elmex 1.1 };
196    
197 root 1.101 static const int item_types_size = ecb_array_length (item_types);
198 elmex 1.1
199     /* This curve may be too steep. But the point is that there should
200     * be tough choices - there is no real point to this if everyone can
201     * wear whatever they want with no worries. Perhaps having the steep
202     * curve is good (maybe even steeper), but allowing players to
203     * have 2 * level instead. Ideally, top level characters should only be
204     * able to use 2-3 of the most powerful items.
205     * note that this table is only really used for program generated items -
206     * custom objects can use whatever they want.
207     */
208     static int enc_to_item_power[21] = {
209 root 1.85 0,
210 root 1.86 0, 1, 2, 3, 4, // 5
211     5, 7, 9, 11, 13, // 10
212     15, 18, 21, 24, 27, // 15
213     30, 35, 40, 45, 50 // 20
214 elmex 1.1 };
215    
216 root 1.4 int
217     get_power_from_ench (int ench)
218 elmex 1.1 {
219 root 1.53 return enc_to_item_power [clamp (ench, 0, 20)];
220 elmex 1.1 }
221    
222 root 1.84 static const struct need_identify_types : typeset
223     {
224     need_identify_types ()
225     {
226     set (RING);
227     set (WAND);
228     set (ROD);
229     set (HORN);
230     set (SCROLL);
231     set (SKILL);
232     set (SKILLSCROLL);
233     set (SPELLBOOK);
234     set (FOOD);
235     set (POTION);
236     set (BOW);
237     set (ARROW);
238     set (WEAPON);
239     set (ARMOUR);
240     set (SHIELD);
241     set (HELMET);
242     set (AMULET);
243     set (BOOTS);
244     set (GLOVES);
245     set (BRACERS);
246     set (GIRDLE);
247     set (CONTAINER);
248     set (DRINK);
249     set (FLESH);
250     set (INORGANIC);
251     set (CLOSE_CON);
252     set (CLOAK);
253     set (GEM);
254     set (POWER_CRYSTAL);
255     set (POISON);
256     set (BOOK);
257     set (SKILL_TOOL);
258     }
259     } need_identify_types;
260    
261     bool
262     object::need_identify () const
263     {
264     return need_identify_types [type];
265     }
266    
267 elmex 1.1 /* This takes an object 'op' and figures out what its item_power
268     * rating should be. This should only really be used by the treasure
269     * generation code, and when loading legacy objects. It returns
270     * the item_power it calculates.
271     * If flag is 1, we return the number of enchantment, and not the
272     * the power. This is used in the treasure code.
273     */
274 root 1.4 int
275     calc_item_power (const object *op, int flag)
276 elmex 1.1 {
277 root 1.4 int i, tmp, enc;
278 elmex 1.1
279 root 1.4 enc = 0;
280     for (i = 0; i < NUM_STATS; i++)
281 root 1.33 enc += op->stats.stat (i);
282 root 1.4
283     /* This protection logic is pretty flawed. 20% fire resistance
284     * is much more valuable than 20% confusion, or 20% slow, or
285     * several others. Start at 1 - ignore physical - all that normal
286 root 1.99 * armour shouldn't be counted against
287 root 1.4 */
288     tmp = 0;
289     for (i = 1; i < NROFATTACKS; i++)
290     tmp += op->resist[i];
291    
292     /* Add/substract 10 so that the rounding works out right */
293     if (tmp > 0)
294     enc += (tmp + 10) / 20;
295     else if (tmp < 0)
296     enc += (tmp - 10) / 20;
297    
298     enc += op->magic;
299    
300     /* For each attacktype a weapon has, one more encantment. Start at 1 -
301     * physical doesn't count against total.
302     */
303     if (op->type == WEAPON)
304     {
305     for (i = 1; i < NROFATTACKS; i++)
306     if (op->attacktype & (1 << i))
307     enc++;
308 root 1.49
309 root 1.4 if (op->slaying)
310     enc += 2; /* What it slays is probably more relevent */
311     }
312 root 1.49
313 root 1.4 /* Items the player can equip */
314     if ((op->type == WEAPON) || (op->type == ARMOUR) || (op->type == HELMET) ||
315     (op->type == SHIELD) || (op->type == RING) ||
316     (op->type == BOOTS) || (op->type == GLOVES) ||
317     (op->type == AMULET) || (op->type == GIRDLE) || (op->type == BRACERS) || (op->type == CLOAK))
318     {
319     enc += op->stats.food; /* sustenance */
320     enc += op->stats.hp; /* hp regen */
321     enc += op->stats.sp; /* mana regen */
322     enc += op->stats.grace; /* grace regen */
323     enc += op->stats.exp; /* speed bonus */
324     }
325 root 1.49
326 root 1.4 enc += op->stats.luck;
327    
328     /* Do spell paths now */
329     for (i = 1; i < NRSPELLPATHS; i++)
330 root 1.66 if (op->path_attuned & (1 << i))
331     enc++;
332     else if (op->path_denied & (1 << i))
333     enc -= 2;
334     else if (op->path_repelled & (1 << i))
335     enc--;
336 root 1.4
337 root 1.55 if (op->flag [FLAG_LIFESAVE ]) enc += 5;
338     if (op->flag [FLAG_REFL_SPELL ]) enc += 3;
339     if (op->flag [FLAG_REFL_MISSILE]) enc += 2;
340     if (op->flag [FLAG_XRAYS ]) enc += 2;
341     if (op->flag [FLAG_STEALTH ]) enc += 1;
342     if (op->flag [FLAG_SEE_IN_DARK ]) enc += 1;
343     if (op->flag [FLAG_MAKE_INVIS ]) enc += 1;
344 elmex 1.1
345 root 1.4 return get_power_from_ench (enc);
346 elmex 1.1 }
347    
348 root 1.87 static const struct get_typedata
349     {
350     const typedata *data [NUM_TYPES];
351    
352     get_typedata ()
353     {
354     for (int i = 0; i < item_types_size; i++)
355     data [item_types[i].number] = &item_types [i];
356     }
357    
358     const typedata *operator ()(int itemtype) const
359     {
360     return data [itemtype];
361     }
362     } get_typedata_;
363    
364 root 1.99 /* returns the typedata that has a number equal to itemtype, if there
365 elmex 1.1 * isn't one, returns NULL */
366 root 1.4 const typedata *
367     get_typedata (int itemtype)
368     {
369 root 1.87 return get_typedata_ (itemtype);
370 elmex 1.1 }
371    
372 root 1.99 /* returns the typedata that has a name equal to itemtype, if there
373 elmex 1.1 * isn't one, return the plural name that matches, if there still isn't
374     * one return NULL */
375 root 1.4 const typedata *
376     get_typedata_by_name (const char *name)
377     {
378 root 1.55 for (int i = 0; i < item_types_size; i++)
379 root 1.4 if (!strcmp (item_types[i].name, name))
380     return &item_types[i];
381 root 1.49
382 root 1.55 for (int i = 0; i < item_types_size; i++)
383 root 1.4 if (!strcmp (item_types[i].name_pl, name))
384     {
385     LOG (llevInfo,
386 root 1.49 "get_typedata_by_name: I have been sent the plural %s, the singular form %s is prefered\n", name, item_types[i].name);
387 root 1.4 return &item_types[i];
388     }
389 root 1.49
390 root 1.55 return 0;
391 elmex 1.1 }
392 root 1.4
393 elmex 1.1 /* describe_resistance generates the visible naming for resistances.
394     * returns a static array of the description. This can return
395     * a big buffer.
396     * if newline is true, we don't put parens around the description
397     * but do put a newline at the end. Useful when dumping to files
398     */
399 root 1.25 const char *
400 root 1.4 describe_resistance (const object *op, int newline)
401 elmex 1.1 {
402 root 1.60 static dynbuf_text buf; buf.clear ();
403 root 1.4
404 root 1.60 for (int i = 0; i < NROFATTACKS; i++)
405     if (op->resist[i] && (op->type != FLESH || atnr_is_dragon_enabled (i) == 1))
406     buf.printf (newline ? "%s %d\n" : "(%s %+d)", resist_plus[i], op->resist[i]);
407 root 1.55
408 root 1.4 return buf;
409 elmex 1.1 }
410    
411     /*
412     * query_weight(object) returns a character pointer to a static buffer
413     * containing the text-representation of the weight of the given object.
414     * The buffer will be overwritten by the next call to query_weight().
415 root 1.55 *
416     * Seems to be used only by unimportant stuff. Remove?
417 elmex 1.1 */
418 root 1.25 const char *
419 root 1.4 query_weight (const object *op)
420     {
421 elmex 1.1 static char buf[10];
422 root 1.46 sint32 i = op->total_weight ();
423 elmex 1.1
424 root 1.4 if (op->weight < 0)
425 elmex 1.1 return " ";
426 root 1.25
427 root 1.4 if (i % 1000)
428     sprintf (buf, "%6.1f", i / 1000.0);
429 elmex 1.1 else
430 root 1.4 sprintf (buf, "%4d ", i / 1000);
431 root 1.25
432 elmex 1.1 return buf;
433     }
434    
435     /*
436     * Returns the pointer to a static buffer containing
437     * the number requested (of the form first, second, third...)
438     */
439 root 1.25 const char *
440 root 1.81 ordinal (int i)
441 root 1.4 {
442 root 1.81 if (i < 0)
443     return format ("minus %s", ordinal (-i));
444 root 1.4
445 root 1.81 if (i < 21)
446     return ordnumbers[i];
447 root 1.25
448 root 1.81 int digit = i % 10;
449 root 1.55
450 root 1.81 if (i >= 100)
451     return format (
452     digit == 1 ? "%dst"
453     : digit == 2 ? "%dnd"
454     : digit == 3 ? "%drd"
455     : "%dth",
456     i
457     );
458 root 1.25
459 root 1.81 if (digit == 0)
460     return ordnumbers_10[i / 10];
461     else
462     return format ("%s%s", numbers_10[i / 10], ordnumbers[i % 10]);
463 elmex 1.1 }
464    
465     /*
466     * Returns pointer to static buffer containing ring's or amulet's
467     * abilities
468     * These are taken from old query_name(), but it would work better
469     * if describle_item() would be called to get this information and
470     * caller would handle FULL_RING_DESCRIPTION definition.
471     * Or make FULL_RING_DESCRIPTION standard part of a game and let
472     * client handle names.
473     */
474 root 1.4
475 elmex 1.1 /* Aug 95 modified this slightly so that Skill tools don't have magic bonus
476     * from stats.sp - b.t.
477     */
478 root 1.63 static const char *
479 root 1.4 ring_desc (const object *op)
480 elmex 1.1 {
481 root 1.39 static dynbuf_text buf; buf.clear ();
482 root 1.94 int attr, val;
483 elmex 1.1
484 root 1.83 if (op->flag [FLAG_IDENTIFIED])
485 root 1.39 {
486     for (attr = 0; attr < NUM_STATS; attr++)
487     if ((val = op->stats.stat (attr)))
488     buf.printf ("(%s%+d)", short_stat_name[attr], val);
489 elmex 1.1
490 root 1.88 if (op->stats.exp) buf.printf ("(speed %+d)", (int)op->stats.exp);
491 root 1.39 if (op->stats.wc) buf.printf ("(wc%+d)", op->stats.wc);
492     if (op->stats.dam) buf.printf ("(dam%+d)", op->stats.dam);
493     if (op->stats.ac) buf.printf ("(ac%+d)", op->stats.ac);
494    
495     buf << describe_resistance (op, 0);
496    
497     if (op->stats.food) buf.printf ("(sustenance%+d)", op->stats.food);
498     if (op->stats.grace) buf.printf ("(grace%+d)", op->stats.grace);
499     if (op->stats.sp && op->type != SKILL) buf.printf ("(magic%+d)", op->stats.sp);
500     if (op->stats.hp) buf.printf ("(regeneration%+d)", op->stats.hp);
501     if (op->stats.luck) buf.printf ("(luck%+d)", op->stats.luck);
502    
503 root 1.83 if (op->flag [FLAG_LIFESAVE]) buf << "(lifesaving)";
504     if (op->flag [FLAG_REFL_SPELL]) buf << "(reflect spells)";
505     if (op->flag [FLAG_REFL_MISSILE]) buf << "(reflect missiles)";
506     if (op->flag [FLAG_STEALTH]) buf << "(stealth)";
507 root 1.39
508     buf.add_paths ("Attuned" , op->path_attuned);
509     buf.add_paths ("Repelled", op->path_repelled);
510     buf.add_paths ("Denied" , op->path_denied);
511 root 1.4
512 root 1.39 if (buf.empty ())
513     buf << "of adornment";
514 root 1.4 }
515 root 1.27
516 root 1.4 return buf;
517 elmex 1.1 }
518    
519     /*
520 root 1.99 * query_short_name(object) is similar to query_name, but doesn't
521 elmex 1.1 * contain any information about object status (worn/cursed/etc.)
522 root 1.55 *
523     * It is sometimes used when printing messages, so should fit well into a sentence.
524 elmex 1.1 */
525 root 1.4 const char *
526     query_short_name (const object *op)
527 elmex 1.1 {
528 root 1.52 if (!op->name)
529 root 1.4 return "(null)";
530 root 1.5
531 root 1.42 if (!op->nrof
532     && !op->weight
533     && !op->title
534     && !is_magical (op)
535     && op->slaying != shstr_money)
536 root 1.4 return op->name; /* To speed things up (or make things slower?) */
537    
538 root 1.42 static dynbuf_text buf; buf.clear ();
539    
540 root 1.39 buf << (op->nrof <= 1 ? op->name : op->name_pl);
541 root 1.4
542 root 1.83 if (op->title && op->flag [FLAG_IDENTIFIED])
543 root 1.39 buf << ' ' << op->title;
544 elmex 1.1
545 root 1.4 switch (op->type)
546     {
547 root 1.39 case SPELLBOOK:
548     case SCROLL:
549     case WAND:
550     case ROD:
551 root 1.83 if (op->flag [FLAG_IDENTIFIED] || op->flag [FLAG_BEEN_APPLIED])
552 root 1.39 {
553     if (!op->title)
554     buf << " of " << (op->inv ? &op->inv->name : "bug, please report");
555    
556     if (op->type != SPELLBOOK)
557     buf.printf (" (lvl %d)", op->level);
558     }
559     break;
560    
561 root 1.53 case ALTAR:
562     case TRIGGER_ALTAR:
563     case IDENTIFY_ALTAR:
564     case CONVERTER:
565     if (op->slaying == shstr_money)
566     {
567     bool wrap = !!buf.size ();
568 root 1.42
569 root 1.53 if (wrap) buf << " [";
570 root 1.42
571 root 1.53 archetype *coin = 0;
572 root 1.42
573 root 1.53 for (char const *const *c = coins; *coins; ++c)
574     if ((coin = archetype::find (*c)))
575     if (op->stats.food % coin->value == 0)
576     break;
577 root 1.42
578 root 1.53 sint32 coins = op->stats.food / coin->value;
579 root 1.42
580 root 1.53 buf.printf ("drop %d %s (or equivalent)", coins, coins == 1 ? &coin->name : &coin->name_pl);
581 root 1.42
582 root 1.53 if (wrap) buf << ']';
583     }
584     break;
585 root 1.42
586 root 1.39 case SKILL:
587     case AMULET:
588     case RING:
589     if (!op->title)
590     {
591     /* If ring has a title, full description isn't so useful */
592     const char *s = ring_desc (op);
593 elmex 1.1
594 root 1.39 if (s && *s)
595     buf << " " << s;
596     }
597     break;
598 root 1.42
599 root 1.39 default:
600 root 1.84 if (op->magic
601     && ((op->flag [FLAG_BEEN_APPLIED] && op->need_identify ())
602     || op->flag [FLAG_IDENTIFIED]))
603 root 1.39 buf.printf (" %+d", op->magic);
604 elmex 1.1 }
605 root 1.39
606 root 1.4 return buf;
607 elmex 1.1 }
608    
609     /*
610     * query_name(object) returns a character pointer pointing to a static
611     * buffer which contains a verbose textual representation of the name
612     * of the given object.
613     * cf 0.92.6: Put in 5 buffers that it will cycle through. In this way,
614     * you can make several calls to query_name before the bufs start getting
615     * overwritten. This may be a bad thing (it may be easier to assume the value
616     * returned is good forever.) However, it makes printing statements that
617     * use several names much easier (don't need to store them to temp variables.)
618     *
619 root 1.55 * It is used extensively within messages, so should return only a prose
620     * and short description of the item.
621 root 1.71 * It is also used by examine/ex and similar functions.
622 elmex 1.1 */
623 root 1.25 const char *
624 root 1.4 query_name (const object *op)
625     {
626 root 1.39 static dynbuf_text bufs[5];
627 root 1.4 static int use_buf = 0;
628 elmex 1.1
629 root 1.4 use_buf++;
630     use_buf %= 5;
631 elmex 1.1
632 root 1.39 dynbuf_text &buf = bufs [use_buf];
633     buf.clear ();
634    
635 root 1.67 #if 0
636     if ((op->is_armor () || op->is_weapon ()) && op->material)
637     buf << op->material->description << ' ';
638     #endif
639 elmex 1.1
640 root 1.39 buf << query_short_name (op);
641 elmex 1.1
642 root 1.83 if (op->flag [FLAG_INV_LOCKED])
643 root 1.39 buf << " *";
644 root 1.61 if (op->is_open_container ())
645 root 1.39 buf << " (open)";
646 root 1.4
647 root 1.83 if (op->flag [FLAG_KNOWN_CURSED])
648 root 1.4 {
649 root 1.83 if (op->flag [FLAG_DAMNED])
650 root 1.39 buf << " (damned)";
651 root 1.83 else if (op->flag [FLAG_CURSED])
652 root 1.39 buf << " (cursed)";
653 root 1.4 }
654 root 1.23
655 root 1.4 /* Basically, if the object is known magical (detect magic spell on it),
656     * and it isn't identified, print out the fact that
657     * it is magical. Assume that the detect magical spell will only set
658     * KNOWN_MAGICAL if the item actually is magical.
659     *
660     * Changed in V 0.91.4 - still print that the object is magical even
661     * if it has been applied. Equipping an item does not tell full
662     * abilities, especially for artifact items.
663     */
664 root 1.83 if (op->flag [FLAG_KNOWN_MAGICAL] && !op->flag [FLAG_IDENTIFIED])
665 root 1.39 buf << " (magic)";
666 elmex 1.1
667     #if 0
668 root 1.55 /* item_power will be returned in describe_item - it shouldn't really
669 root 1.4 * be returned in the name.
670     */
671     if (op->item_power)
672     sprintf (buf[use_buf] + strlen (buf[use_buf]), "(item_power %+d)", op->item_power);
673 elmex 1.1
674     #endif
675    
676 root 1.83 if (op->flag [FLAG_APPLIED])
677 root 1.4 {
678     switch (op->type)
679     {
680 root 1.89 case RANGED:
681 root 1.23 case BOW:
682     case WAND:
683     case ROD:
684     case HORN:
685     case WEAPON:
686 root 1.77 buf << " (applied)";
687 root 1.23 break;
688     case ARMOUR:
689     case HELMET:
690     case SHIELD:
691     case RING:
692     case BOOTS:
693     case GLOVES:
694     case AMULET:
695     case GIRDLE:
696     case BRACERS:
697     case CLOAK:
698 root 1.39 buf << " (worn)";
699 root 1.23 break;
700     case CONTAINER:
701 root 1.39 buf << " (active)";
702 root 1.23 break;
703     case SKILL:
704     default:
705 root 1.39 buf << " (applied)";
706 root 1.2 }
707 elmex 1.1 }
708 root 1.23
709 elmex 1.54 switch (op->type)
710     {
711     case LAMP:
712     if (op->glow_radius)
713     buf << " (on)";
714     else if (op->stats.food <= 0)
715     buf << " (empty)";
716     else
717     buf << " (off)";
718     break;
719    
720     case TORCH:
721     if (op->glow_radius)
722     buf << " (burning)";
723     else if (op->stats.food <= 0)
724     buf << " (burned out)";
725     break;
726     }
727    
728 root 1.83 if (op->flag [FLAG_UNPAID])
729 root 1.39 buf << " (unpaid)";
730 elmex 1.1
731 root 1.39 return buf;
732 elmex 1.1 }
733    
734     /*
735     * query_base_name(object) returns a character pointer pointing to a static
736     * buffer which contains a verbose textual representation of the name
737     * of the given object. The buffer will be overwritten at the next
738     * call to query_base_name(). This is a lot like query_name, but we
739     * don't include the item count or item status. Used for inventory sorting
740     * and sending to client.
741     * If plural is set, we generate the plural name of this.
742 root 1.55 *
743     * It is sometimes used to display messages, and usually only used to match stuff,
744     * so maybe this function should be removed.
745 root 1.71 * It is also used for client-side inventory/item descriptions.
746 elmex 1.1 */
747 root 1.4 const char *
748     query_base_name (const object *op, int plural)
749     {
750     if ((!plural && !op->name) || (plural && !op->name_pl))
751     return "(null)";
752 elmex 1.1
753 root 1.71 if (!op->nrof && !op->weight && !op->title && !is_magical (op)
754     && op->type != EXIT)
755 root 1.4 return op->name; /* To speed things up (or make things slower?) */
756 elmex 1.1
757 root 1.39 static dynbuf_text buf; buf.clear ();
758    
759 root 1.67 #if 0
760     if ((op->is_armor () || op->is_weapon ()) && op->material)
761     if (op->arch->material != op->material)
762     buf << op->material->description << ' ';
763     #endif
764 root 1.20
765 root 1.39 buf << (plural ? op->name_pl : op->name);
766 elmex 1.1
767 root 1.83 if (op->title && op->flag [FLAG_IDENTIFIED])
768 root 1.39 buf << ' ' << op->title;
769 elmex 1.1
770 root 1.4 switch (op->type)
771     {
772 root 1.20 case SPELLBOOK:
773     case SCROLL:
774     case WAND:
775     case ROD:
776 root 1.83 if (op->flag [FLAG_IDENTIFIED] || op->flag [FLAG_BEEN_APPLIED])
777 root 1.20 {
778     if (!op->title)
779 root 1.39 buf << " of " << (op->inv ? &op->inv->name : "bug, please report");
780    
781 root 1.20 if (op->type != SPELLBOOK)
782 root 1.39 buf.printf (" (lvl %d)", op->level);
783 root 1.20 }
784     break;
785 elmex 1.1
786    
787 root 1.20 case SKILL:
788     case AMULET:
789     case RING:
790     if (!op->title)
791     {
792     /* If ring has a title, full description isn't so useful */
793 root 1.25 const char *s = ring_desc (op);
794 root 1.4
795 root 1.39 if (s && *s)
796     buf << ' ' << s;
797 root 1.20 }
798     break;
799 root 1.29
800 root 1.72 case EXIT:
801     // random map exits "unfortunately" get patched, so this only works before entering
802 root 1.76 if (EXIT_PATH (op) == shstr_random_map_exit)
803     buf << " (random map)";
804     else if (!EXIT_PATH (op))
805     buf << " (closed)";
806 root 1.72 break;
807    
808 root 1.20 default:
809 root 1.84 if (op->magic
810     && ((op->flag [FLAG_BEEN_APPLIED] && op->need_identify ())
811     || op->flag [FLAG_IDENTIFIED]))
812 root 1.39 buf.printf (" %+d", op->magic);
813 elmex 1.1 }
814 root 1.20
815 root 1.4 return buf;
816 elmex 1.1 }
817    
818     /* Break this off from describe_item - that function was way
819     * too long, making it difficult to read. This function deals
820     * with describing the monsters & players abilities. It should only
821     * be called with monster & player objects. Returns a description
822     * in a static buffer.
823     */
824 root 1.39 static const char *
825 root 1.4 describe_monster (const object *op)
826     {
827 root 1.39 static dynbuf_text buf; buf.clear ();
828 root 1.4
829     /* Note that the resolution this provides for players really isn't
830     * very good. Any player with a speed greater than .67 will
831     * fall into the 'lightning fast movement' category.
832     */
833 elmex 1.16 if (op->has_active_speed ())
834 root 1.68 switch ((int)(op->speed * 15.))
835 root 1.39 {
836     case 0:
837 root 1.51 buf << "(very slow movement)";
838 root 1.39 break;
839     case 1:
840     buf << "(slow movement)";
841     break;
842     case 2:
843     buf << "(normal movement)";
844     break;
845     case 3:
846     case 4:
847     buf << "(fast movement)";
848     break;
849     case 5:
850     case 6:
851     buf << "(very fast movement)";
852     break;
853     case 7:
854     case 8:
855     case 9:
856     case 10:
857     buf << "(extremely fast movement)";
858     break;
859     default:
860     buf << "(lightning fast movement)";
861     break;
862     }
863    
864 root 1.83 if (op->flag [FLAG_UNDEAD]) buf << "(undead)";
865     if (op->flag [FLAG_SEE_INVISIBLE]) buf << "(see invisible)";
866     if (op->flag [FLAG_USE_WEAPON]) buf << "(wield weapon)";
867     if (op->flag [FLAG_USE_BOW]) buf << "(archer)";
868     if (op->flag [FLAG_USE_ARMOUR]) buf << "(wear armour)";
869     if (op->flag [FLAG_USE_RING]) buf << "(wear ring)";
870     if (op->flag [FLAG_USE_SCROLL]) buf << "(read scroll)";
871     if (op->flag [FLAG_USE_RANGE]) buf << "(fires wand/rod/horn)";
872     if (op->flag [FLAG_CAN_USE_SKILL]) buf << "(skill user)";
873     if (op->flag [FLAG_CAST_SPELL]) buf << "(spellcaster)";
874     if (op->flag [FLAG_FRIENDLY]) buf << "(friendly)";
875     if (op->flag [FLAG_UNAGGRESSIVE]) buf << "(unaggressive)";
876     if (op->flag [FLAG_HITBACK]) buf << "(hitback)";
877     if (op->flag [FLAG_STEALTH]) buf << "(stealthy)";
878 root 1.39
879     if (op->randomitems)
880 root 1.4 {
881 root 1.39 bool first = 1;
882 root 1.4
883 root 1.39 for (treasure *t = op->randomitems->items; t; t = t->next)
884 root 1.37 if (t->item && t->item->type == SPELL)
885 root 1.4 {
886     if (first)
887 root 1.39 buf << "(Spell abilities:)";
888    
889     first = 0;
890    
891     buf << '(' << t->item->object::name << ')';
892 root 1.4 }
893     }
894 root 1.39
895 root 1.4 if (op->type == PLAYER)
896     {
897     if (op->contr->digestion)
898 root 1.39 buf.printf ("(sustenance%+d)", op->contr->digestion);
899    
900 root 1.4 if (op->contr->gen_grace)
901 root 1.39 buf.printf ("(grace%+d)", op->contr->gen_grace);
902    
903 root 1.4 if (op->contr->gen_sp)
904 root 1.39 buf.printf ("(magic%+d)", op->contr->gen_sp);
905    
906 root 1.4 if (op->contr->gen_hp)
907 root 1.39 buf.printf ("(regeneration%+d)", op->contr->gen_hp);
908    
909 root 1.4 if (op->stats.luck)
910 root 1.39 buf.printf ("(luck%+d)", op->stats.luck);
911 elmex 1.1 }
912 root 1.4
913     /* describe attacktypes */
914 root 1.69 if (op->is_dragon ())
915 root 1.4 {
916     /* for dragon players display the attacktypes from clawing skill
917     * Break apart the for loop - move the comparison checking down -
918     * this makes it more readable.
919     */
920     object *tmp;
921    
922 root 1.39 for (tmp = op->inv; tmp; tmp = tmp->below)
923     if (tmp->type == SKILL && tmp->name == shstr_clawing)
924 root 1.4 break;
925    
926 root 1.39 if (tmp && tmp->attacktype)
927     buf.add_abilities ("Claws", tmp->attacktype);
928 root 1.4 else
929 root 1.39 buf.add_abilities ("Attacks", op->attacktype);
930 elmex 1.1 }
931 root 1.4 else
932 root 1.39 buf.add_abilities ("Attacks", op->attacktype);
933 root 1.21
934 root 1.39 buf.add_paths ("Attuned" , op->path_attuned);
935     buf.add_paths ("Repelled", op->path_repelled);
936     buf.add_paths ("Denied" , op->path_denied);
937 root 1.22
938 root 1.39 for (int i = 0; i < NROFATTACKS; i++)
939 root 1.22 if (op->resist[i])
940 root 1.39 buf.printf ("(%s %+d)", resist_plus[i], op->resist[i]);
941 root 1.22
942 root 1.39 return buf;
943 elmex 1.1 }
944    
945     /*
946     * Returns a pointer to a static buffer which contains a
947     * description of the given object.
948     * If it is a monster, lots of information about its abilities
949     * will be returned.
950     * If it is an item, lots of information about which abilities
951     * will be gained about its user will be returned.
952     * If it is a player, it writes out the current abilities
953     * of the player, which is usually gained by the items applied.
954     * It would be really handy to actually pass another object
955     * pointer on who is examining this object. Then, you could reveal
956     * certain information depending on what the examiner knows, eg,
957     * wouldn't need to use the SEE_INVISIBLE flag to know it is
958     * a dragon player examining food. Could have things like
959     * a dwarven axe, in which the full abilities are only known to
960     * dwarves, etc.
961     *
962     * Add 'owner' who is the person examining this object.
963     * owner can be null if no one is being associated with this
964     * item (eg, debug dump or the like)
965     */
966 root 1.25 const char *
967 root 1.4 describe_item (const object *op, object *owner)
968     {
969 root 1.83 if (op->flag [FLAG_MONSTER] || op->type == PLAYER)
970 root 1.39 return describe_monster (op);
971    
972     static dynbuf_text buf; buf.clear ();
973 root 1.4 int identified, i;
974    
975     /* figure this out once, instead of making multiple calls to need_identify.
976     * also makes the code easier to read.
977     */
978 root 1.84 identified = !op->need_identify () || op->flag [FLAG_IDENTIFIED];
979 root 1.39 if (!identified)
980     buf << "(unidentified)";
981    
982 root 1.4 switch (op->type)
983     {
984 root 1.89 case RANGED:
985 root 1.39 case BOW:
986     case ARROW:
987     case WAND:
988     case ROD:
989     case HORN:
990     case WEAPON:
991     case ARMOUR:
992     case HELMET:
993     case SHIELD:
994     case BOOTS:
995     case GLOVES:
996     case GIRDLE:
997     case BRACERS:
998     case CLOAK:
999     case SKILL_TOOL:
1000     break; /* We have more information to do below this switch */
1001    
1002     case POWER_CRYSTAL:
1003     if (op->stats.maxsp > 1000)
1004     { /*higher capacity crystals */
1005     i = (op->stats.maxsp % 1000) / 100;
1006    
1007     if (i)
1008 root 1.78 buf.printf ("(capacity %d.%dk; it is ", op->stats.maxsp / 1000, i);
1009 root 1.39 else
1010 root 1.78 buf.printf ("(capacity %dk; it is ", op->stats.maxsp / 1000);
1011 root 1.39 }
1012     else
1013 root 1.78 buf.printf ("(capacity %d; it is ", op->stats.maxsp);
1014 root 1.39
1015 root 1.97 i = op->stats.sp * 10 / max (op->stats.maxsp, 1);
1016    
1017     if (op->stats.sp == 0) buf << "empty";
1018     else if (i <= 0) buf << "almost empty";
1019     else if (i <= 2) buf << "partially filled";
1020     else if (i <= 5) buf << "half full";
1021     else if (i <= 8) buf << "well charged";
1022     else if (op->stats.sp < op->stats.maxsp) buf << "almost full";
1023     else buf << "fully charged";
1024 root 1.78
1025     buf << ')';
1026 root 1.39 break;
1027    
1028 elmex 1.54 case LAMP:
1029     {
1030     int percent = ((double) 100 / op->arch->stats.food) * op->stats.food;
1031     buf << "(fuel: ";
1032     if (percent == 0)
1033     buf << "empty";
1034     else if (percent < 10)
1035     buf << "very low";
1036     else if (percent < 25)
1037     buf << "low";
1038     else if (percent < 50)
1039     buf << "half empty";
1040     else if (percent < 75)
1041     buf << "half full";
1042     else if (percent < 95)
1043     buf << "well filled";
1044     else if (percent <= 100)
1045     buf << "full";
1046     buf << ")";
1047     }
1048     break;
1049    
1050 root 1.39 case FOOD:
1051     case FLESH:
1052     case DRINK:
1053 root 1.83 if (identified || op->flag [FLAG_BEEN_APPLIED])
1054 root 1.39 {
1055     buf.printf ("(food+%d)", op->stats.food);
1056    
1057     if (op->type == FLESH && op->last_eat > 0 && atnr_is_dragon_enabled (op->last_eat))
1058     buf.printf ("(%s metabolism)", change_resist_msg[op->last_eat]);
1059    
1060 root 1.83 if (!op->flag [FLAG_CURSED])
1061 root 1.39 {
1062     if (op->stats.hp) buf << "(heals)";
1063     if (op->stats.sp) buf << "(spellpoint regen)";
1064     }
1065     else
1066     {
1067     if (op->stats.hp) buf << "(damages)";
1068     if (op->stats.sp) buf << "(spellpoint depletion)";
1069     }
1070     }
1071     break;
1072    
1073     case SKILL:
1074     case RING:
1075     case AMULET:
1076     if (op->item_power)
1077     buf.printf ("(item_power %+d)", op->item_power);
1078 root 1.2
1079 root 1.39 if (op->title)
1080     buf << ring_desc (op);
1081 root 1.2
1082 root 1.39 return buf;
1083 elmex 1.1
1084 root 1.39 default:
1085     return buf;
1086 elmex 1.1 }
1087    
1088 root 1.4 /* Down here, we more further describe equipment type items.
1089     * only describe them if they have been identified or the like.
1090     */
1091 root 1.83 if (identified || op->flag [FLAG_BEEN_APPLIED])
1092 root 1.4 {
1093 root 1.89 for (int attr = 0; attr < NUM_STATS; attr++)
1094     if (int val = op->stats.stat (attr))
1095 root 1.39 buf.printf ("(%s%+d)", short_stat_name[attr], val);
1096 root 1.2
1097 root 1.4 if (op->stats.exp)
1098 root 1.39 buf.printf ("(speed %+lld)", (long long) op->stats.exp);
1099    
1100     switch (op->type)
1101 root 1.4 {
1102 root 1.89 case RANGED:
1103 root 1.39 case BOW:
1104     case ARROW:
1105     case GIRDLE:
1106     case HELMET:
1107     case SHIELD:
1108     case BOOTS:
1109     case GLOVES:
1110     case WEAPON:
1111     case SKILL:
1112     case RING:
1113     case AMULET:
1114     case ARMOUR:
1115     case BRACERS:
1116     case FORCE:
1117     case CLOAK:
1118     if (op->stats.wc) buf.printf ("(wc%+d)", op->stats.wc);
1119     if (op->stats.dam) buf.printf ("(dam%+d)", op->stats.dam);
1120     if (op->stats.ac) buf.printf ("(ac%+d)", op->stats.ac);
1121 root 1.2
1122 root 1.39 if ((op->type == WEAPON || op->type == BOW) && op->level > 0)
1123     buf.printf ("(improved %d/%d)", op->last_eat, op->level);
1124 root 1.2
1125 root 1.39 break;
1126 root 1.2
1127 root 1.39 default:
1128     break;
1129 root 1.2 }
1130 root 1.39
1131 root 1.83 if (op->flag [FLAG_XRAYS]) buf << "(xray-vision)";
1132     if (op->flag [FLAG_SEE_IN_DARK]) buf << "(infravision)";
1133 root 1.4
1134     /* levitate was what is was before, so we'll keep it */
1135 root 1.39 if (op->move_type & MOVE_FLY_LOW) buf << "(levitate)";
1136     if (op->move_type & MOVE_FLY_HIGH) buf << "(fly)";
1137     if (op->move_type & MOVE_SWIM) buf << "(swim)";
1138 root 1.4
1139     /* walking is presumed as 'normal', so doesn't need mentioning */
1140    
1141     if (op->item_power)
1142 root 1.39 buf.printf ("(item_power %+d)", op->item_power);
1143 root 1.4 } /* End if identified or applied */
1144    
1145     /* This blocks only deals with fully identified object.
1146     * it is intentional that this is not an 'else' from a above -
1147     * in this way, information is added.
1148     */
1149     if (identified)
1150     {
1151     int more_info = 0;
1152    
1153     switch (op->type)
1154     {
1155 root 1.89 case RANGED:
1156 root 1.39 case ROD: /* These use stats.sp for spell selection and stats.food */
1157     case HORN: /* and stats.hp for spell-point regeneration... */
1158     case BOW:
1159     case ARROW:
1160     case WAND:
1161     case FOOD:
1162     case FLESH:
1163     case DRINK:
1164     more_info = 0;
1165     break;
1166    
1167     /* Armor type objects */
1168     case ARMOUR:
1169     case HELMET:
1170     case SHIELD:
1171     case BOOTS:
1172     case GLOVES:
1173     case GIRDLE:
1174     case BRACERS:
1175     case CLOAK:
1176     if (ARMOUR_SPEED (op)) buf.printf ("(Max speed %1.2f)", ARMOUR_SPEED (op) / 10.0);
1177     if (ARMOUR_SPELLS (op)) buf.printf ("(Spell regen penalty %d)", ARMOUR_SPELLS (op));
1178     more_info = 1;
1179     break;
1180 root 1.4
1181 root 1.39 case WEAPON:
1182     /* Calculate it the same way fix_player does so the results
1183     * make sense.
1184     */
1185     i = (WEAPON_SPEED (op) * 2 - op->magic) / 2;
1186     if (i < 0)
1187     i = 0;
1188    
1189     buf.printf ("(weapon speed %d)", i);
1190     more_info = 1;
1191     break;
1192 root 1.4 }
1193 root 1.39
1194 root 1.4 if (more_info)
1195     {
1196 root 1.39 if (op->stats.food) buf.printf ("(sustenance%+d)", op->stats.food);
1197     if (op->stats.grace) buf.printf ("(grace%+d)", op->stats.grace);
1198 root 1.99 if (op->stats.sp) buf.printf ("(magic%+d)", op->stats.sp);
1199 root 1.39 if (op->stats.hp) buf.printf ("(regeneration%+d)", op->stats.hp);
1200 root 1.2 }
1201    
1202 root 1.4 if (op->stats.luck)
1203 root 1.39 buf.printf ("(luck%+d)", op->stats.luck);
1204    
1205 root 1.83 if (op->flag [FLAG_LIFESAVE]) buf << "(lifesaving)";
1206     if (op->flag [FLAG_REFL_SPELL]) buf << "(reflect spells)";
1207     if (op->flag [FLAG_REFL_MISSILE]) buf << "(reflect missiles)";
1208     if (op->flag [FLAG_STEALTH]) buf << "(stealth)";
1209 root 1.39
1210     if (op->slaying && op->type != FOOD)
1211     buf.printf ("(slay %s)", &op->slaying);
1212    
1213 root 1.57 if (op->type == SKILL_TOOL && op->skill)
1214     buf.printf ("(%s)", &op->skill);
1215 sf-marcmagus 1.56
1216 root 1.39 buf.add_abilities ("Attacks", op->attacktype);
1217 root 1.4 /* resistance on flesh is only visible for quetzals. If
1218     * non flesh, everyone can see its resistances
1219     */
1220 root 1.69 if (op->type != FLESH || (owner && owner->is_dragon ()))
1221 root 1.39 buf << describe_resistance (op, 0);
1222    
1223     buf.add_paths ("Attuned", op->path_attuned);
1224     buf.add_paths ("Repelled", op->path_repelled);
1225     buf.add_paths ("Denied", op->path_denied);
1226 elmex 1.1 }
1227    
1228 root 1.39 return buf;
1229 elmex 1.1 }
1230    
1231 root 1.26 std::string
1232     object::describe_item (object *who)
1233     {
1234     return std::string (::describe_item (this, who));
1235     }
1236    
1237 root 1.79 static void
1238     describe_dump_object (dynbuf &buf, object *ob)
1239     {
1240     char *txt = dump_object (ob);
1241     for (char *p = txt; *p; ++p) if (*p == '\n') *p = '\r';
1242     buf << "\n" << txt << "\n";
1243    
1244     if (!ob->is_arch ())
1245     describe_dump_object (buf, ob->arch);
1246     }
1247    
1248     std::string
1249     object::describe (object *who)
1250     {
1251     dynbuf_text buf (1024, 1024);
1252    
1253     buf.printf ("That is: %s.\r", long_desc (who).c_str ());
1254    
1255     if (custom_name)
1256     buf.printf ("You call it %s.\r", &custom_name);
1257    
1258     switch (type)
1259     {
1260     case SPELLBOOK:
1261     if (flag [FLAG_IDENTIFIED] && inv)
1262 root 1.81 buf.printf ("%s is a %s level %s spell.\r", &inv->name, ordinal (inv->level), &inv->skill);
1263 root 1.79 break;
1264    
1265     case BOOK:
1266     if (msg)
1267     buf << "Something is written in it.\r";
1268     break;
1269    
1270     case CONTAINER:
1271     if (race)
1272     {
1273     if (weight_limit && stats.Str < 100)
1274     buf.printf ("It can hold only %s and its weight limit is %.1f kg.\r",
1275     &race, weight_limit / (10.0 * (100 - stats.Str)));
1276     else
1277     buf.printf ("It can hold only %s.\r", &race);
1278     }
1279     else if (weight_limit && stats.Str < 100)
1280     buf.printf ("Its weight limit is %.1f kg.\r", weight_limit / (10.0 * (100 - stats.Str)));
1281     break;
1282    
1283     case WAND:
1284     if (flag [FLAG_IDENTIFIED])
1285     buf.printf ("It has %d %s left.\r", stats.food, stats.food == 1 ? "charge" : "charges");
1286     break;
1287     }
1288    
1289     if (material != MATERIAL_NULL && !msg)
1290     buf << (nrof > 1 ? "They are made of " : "It is made of ")
1291     << material->description
1292     << ".\r";
1293    
1294     if (who)
1295     /* Where to wear this item */
1296     for (int i = 0; i < NUM_BODY_LOCATIONS; i++)
1297     if (slot[i].info)
1298     {
1299     buf << (who->slot[i].info ? body_locations[i].use_name : body_locations[i].nonuse_name);
1300    
1301     if (slot[i].info < -1 && who->slot[i].info)
1302     buf.printf ("(%d)", -slot[i].info);
1303    
1304     buf << ".\r";
1305     }
1306    
1307     if (weight)
1308     buf.printf ("%s %3.3f kg.\r", nrof > 1 ? "They weigh" : "It weighs", weight * (nrof ? nrof : 1) / 1000.0);
1309    
1310     if (flag [FLAG_STARTEQUIP])
1311     buf << (nrof > 1 ? "They were" : "It was")
1312     << " given by a god and will vanish when dropped.\r";
1313    
1314     if (value && !flag [FLAG_STARTEQUIP] && !flag [FLAG_NO_PICK] && who)
1315     {
1316     buf.printf ("You reckon %s worth %s.\r", nrof > 1 ? "they are" : "it is", query_cost_string (this, who, F_TRUE | F_APPROX));
1317    
1318     if (who->is_in_shop ())
1319     {
1320     if (flag [FLAG_UNPAID])
1321     buf.printf ("%s would cost you %s.\r", nrof > 1 ? "They" : "It", query_cost_string (this, who, F_BUY | F_SHOP));
1322     else
1323     buf.printf ("You are offered %s for %s.\r", query_cost_string (this, who, F_SELL + F_SHOP), nrof > 1 ? "them" : "it");
1324     }
1325     }
1326    
1327     if (flag [FLAG_MONSTER])
1328     buf << describe_monster (who);
1329    
1330     /* Is this item buildable? */
1331     if (flag [FLAG_IS_BUILDABLE])
1332     buf << "This is a buildable item.\r";
1333    
1334     /* Does the object have a message? Don't show message for all object
1335     * types - especially if the first entry is a match
1336     */
1337     if (msg)
1338     {
1339     if (type != EXIT && type != BOOK && type != CORPSE && !move_on && !has_dialogue ())
1340     {
1341 root 1.84 if (!need_identify ())
1342     buf << '\r' << msg << '\n';
1343     else if (flag [FLAG_IDENTIFIED])
1344     buf << '\r' << "The object has a story:\r" << msg;
1345 root 1.79 }
1346     }
1347 root 1.84 else if (inv
1348     && inv->msg
1349     && inv->type == SPELL
1350     && flag [FLAG_IDENTIFIED]
1351 root 1.79 && (type == SPELLBOOK || type == ROD || type == WAND
1352 root 1.95 || type == POTION || type == SCROLL))
1353 root 1.79 // for spellbooks and other stuff that contains spells, print the spell message,
1354     // unless the object has a custom message handled above.
1355     buf << '\r' << inv->msg << '\n';
1356    
1357     // try to display the duration for some potions and scrolls
1358     // this includes change ability potions and group spells,
1359     // but does not handle protection potions
1360     if (inv && inv->type == SPELL && flag [FLAG_IDENTIFIED]
1361     && (type == POTION || type == SCROLL))
1362     {
1363     object *spell = inv;
1364    
1365     if (spell->subtype == SP_PARTY_SPELL)
1366     spell = spell->other_arch;
1367    
1368     if (spell->subtype == SP_CHANGE_ABILITY)
1369     buf.printf ("\nH<The effect will last about %.10g seconds.>",
1370     TICK2TIME (change_ability_duration (spell, this)));
1371     }
1372    
1373 root 1.80 // some help text for skill tools
1374     if (type == SKILL_TOOL)
1375     buf << "\nH<This item is a skill tool: as long as you have this item applied "
1376     "you can use the " << &skill << " skill as if you had learned it.>";
1377    
1378 root 1.79 // Display a hint about inscribable items [empty books]
1379     // This includes the amount of text they can hold.
1380     if (type == INSCRIBABLE)
1381     {
1382     if (other_arch && other_arch->type == SCROLL)
1383     buf.printf ("\nH<You can use the inscription skill to inscribe a spell into it.>");
1384     else
1385     buf.printf ("\nH<You can use the inscription skill to inscribe text into it. It has room for up to %d characters.>",
1386     weight_limit);
1387     }
1388    
1389     buf << '\n';
1390    
1391     // the dungeon master additionally gets a complete dump
1392     if (who && who->flag [FLAG_WIZLOOK])
1393     {
1394     buf << "\nT<Object>\n";
1395     describe_dump_object (buf, this);
1396    
1397     if (inv)
1398     {
1399     buf << "\nT<Top Inventory>\n";
1400     describe_dump_object (buf, inv);
1401     }
1402     }
1403    
1404     return std::string (buf.linearise (), buf.size ());
1405     }
1406    
1407 root 1.40 void
1408     examine (object *op, object *tmp)
1409     {
1410 root 1.45 std::string info = tmp->describe (op);
1411 root 1.55
1412 root 1.45 op->contr->infobox (MSG_CHANNEL ("examine"), info.c_str ());
1413 root 1.40 }
1414    
1415     /*
1416     * inventory prints object's inventory. If inv==NULL then print player's
1417 root 1.99 * inventory.
1418 root 1.40 * [ Only items which are applied are showed. Tero.Haatanen@lut.fi ]
1419     */
1420     const char *
1421     object::query_inventory (object *who, const char *indent)
1422     {
1423     static dynbuf_text buf; buf.clear ();
1424    
1425     for (object *tmp = inv; tmp; tmp = tmp->below)
1426 root 1.83 if (who && who->flag [FLAG_WIZ])
1427 elmex 1.70 buf.printf ("%s- %-28.28s %-8s (%9d) %s\n", indent, tmp->query_name (), tmp->query_weight (), tmp->count, tmp->uuid.c_str ());
1428 root 1.83 else if (!tmp->invisible && (type == CONTAINER || tmp->flag [FLAG_APPLIED]))
1429 root 1.53 buf.printf ("%s- %-36.36s %-8s\n", indent, tmp->query_name (), tmp->query_weight ());
1430 root 1.40
1431     if (buf.size ())
1432 root 1.53 buf.printf ("%s(total weight: %s)\n", indent, query_weight ());
1433 root 1.40 else
1434     buf.printf ("%s(empty)\n", indent);
1435    
1436     return buf;
1437     }
1438    
1439 elmex 1.1 /* Return true if the item is magical. A magical item is one that
1440     * increases/decreases any abilities, provides a resistance,
1441     * has a generic magical bonus, or is an artifact.
1442     * This function is used by detect_magic to determine if an item
1443     * should be marked as magical.
1444     */
1445 root 1.4 int
1446     is_magical (const object *op)
1447     {
1448     int i;
1449 elmex 1.1
1450 root 1.4 /* living creatures are considered non magical */
1451 root 1.83 if (op->flag [FLAG_ALIVE])
1452 root 1.4 return 0;
1453 elmex 1.1
1454 root 1.4 /* This is a test for it being an artifact, as artifacts have titles */
1455     if (op->title != NULL)
1456     return 1;
1457    
1458     /* Handle rings and amulets specially. If they change any of these
1459     * values, it means they are magical.
1460     */
1461     if ((op->type == AMULET || op->type == RING) &&
1462     (op->stats.ac || op->stats.food || op->stats.exp || op->stats.dam || op->stats.wc || op->stats.sp || op->stats.hp || op->stats.luck))
1463     return 1;
1464    
1465     /* Check for stealty, speed, flying, or just plain magic in the boots */
1466     /* Presume any boots that hvae a move_type are special. */
1467 root 1.83 if (op->type == BOOTS && ((op->flag [FLAG_STEALTH] || op->move_type || op->stats.exp)))
1468 root 1.4 return 1;
1469    
1470     /* Take care of amulet/shield that reflects spells/missiles */
1471 root 1.83 if ((op->type == AMULET || op->type == SHIELD) && (op->flag [FLAG_REFL_SPELL] || op->flag [FLAG_REFL_MISSILE]))
1472 root 1.4 return 1;
1473    
1474     /* Take care of helmet of xrays */
1475 root 1.83 if (op->type == HELMET && op->flag [FLAG_XRAYS])
1476 root 1.4 return 1;
1477    
1478     /* Potions & rods are always magical. Wands/staves are also magical,
1479     * assuming they still have any charges left.
1480     */
1481     if (op->type == POTION || op->type == ROD || (op->type == WAND && op->stats.food))
1482     return 1;
1483    
1484     /* if something gives a protection, either positive or negative, its magical */
1485     /* This is really a pretty bad hack - as of now, ATNR_PHYSICAL is 0,
1486     * so this always works out fine.
1487     */
1488     for (i = ATNR_PHYSICAL + 1; i < NROFATTACKS; i++)
1489     if (op->resist[i])
1490     return 1;
1491    
1492     /* Physical protection is expected on some item types, so they should
1493     * not be considered magical.
1494     */
1495     if (op->resist[ATNR_PHYSICAL] && op->type != HELMET && op->type != SHIELD &&
1496     op->type != BOOTS && op->type != GLOVES && op->type != ARMOUR)
1497     return 1;
1498    
1499     /* power crystal, spellbooks, and scrolls are always magical. */
1500     if (op->magic || op->type == POWER_CRYSTAL || op->type == SPELLBOOK || op->type == SCROLL || op->type == GIRDLE)
1501     return 1;
1502    
1503     /* Check to see if it increases/decreases any stats */
1504     for (i = 0; i < NUM_STATS; i++)
1505 root 1.33 if (op->stats.stat (i))
1506 root 1.4 return 1;
1507    
1508     /* If it doesn't fall into any of the above categories, must
1509     * be non magical.
1510     */
1511     return 0;
1512 elmex 1.1 }
1513    
1514     /*
1515     * Supposed to fix face-values as well here, but later.
1516     */
1517 root 1.4 void
1518     identify (object *op)
1519     {
1520 root 1.83 op->set_flag (FLAG_IDENTIFIED);
1521     op->clr_flag (FLAG_KNOWN_MAGICAL);
1522     op->clr_flag (FLAG_NO_SKILL_IDENT);
1523 root 1.4
1524     /*
1525     * We want autojoining of equal objects:
1526     */
1527 root 1.83 if (op->flag [FLAG_CURSED] || op->flag [FLAG_DAMNED])
1528     op->set_flag (FLAG_KNOWN_CURSED);
1529 root 1.4
1530     if (op->type == POTION)
1531     {
1532     if (op->inv && op->randomitems)
1533     op->title = op->inv->name;
1534     else if (op->arch)
1535     {
1536 root 1.48 op->name = op->arch->object::name;
1537 root 1.37 op->name_pl = op->arch->object::name_pl;
1538 root 1.4 }
1539 elmex 1.1 }
1540    
1541 root 1.4 /* If the object is on a map, make sure we update its face */
1542     if (op->map)
1543 root 1.24 update_object (op, UP_OBJ_CHANGE);
1544 root 1.50
1545     if (object *pl = op->visible_to ())
1546 root 1.48 /* A lot of the values can change from an update - might as well send
1547     * it all.
1548     */
1549     esrv_send_item (pl, op);
1550 elmex 1.1 }
1551 root 1.9