ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/item.C
Revision: 1.86
Committed: Fri Apr 30 20:43:17 2010 UTC (14 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.85: +5 -5 lines
Log Message:
indent

File Contents

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