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

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 root 1.87 static const struct get_typedata
359     {
360     const typedata *data [NUM_TYPES];
361    
362     get_typedata ()
363     {
364     for (int i = 0; i < item_types_size; i++)
365     data [item_types[i].number] = &item_types [i];
366     }
367    
368     const typedata *operator ()(int itemtype) const
369     {
370     return data [itemtype];
371     }
372     } get_typedata_;
373    
374 elmex 1.1 /* returns the typedata that has a number equal to itemtype, if there
375     * isn't one, returns NULL */
376 root 1.4 const typedata *
377     get_typedata (int itemtype)
378     {
379 root 1.87 return get_typedata_ (itemtype);
380 elmex 1.1 }
381    
382     /* returns the typedata that has a name equal to itemtype, if there
383     * isn't one, return the plural name that matches, if there still isn't
384     * one return NULL */
385 root 1.4 const typedata *
386     get_typedata_by_name (const char *name)
387     {
388 root 1.55 for (int i = 0; i < item_types_size; i++)
389 root 1.4 if (!strcmp (item_types[i].name, name))
390     return &item_types[i];
391 root 1.49
392 root 1.55 for (int i = 0; i < item_types_size; i++)
393 root 1.4 if (!strcmp (item_types[i].name_pl, name))
394     {
395     LOG (llevInfo,
396 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);
397 root 1.4 return &item_types[i];
398     }
399 root 1.49
400 root 1.55 return 0;
401 elmex 1.1 }
402 root 1.4
403 elmex 1.1 /* describe_resistance generates the visible naming for resistances.
404     * returns a static array of the description. This can return
405     * a big buffer.
406     * if newline is true, we don't put parens around the description
407     * but do put a newline at the end. Useful when dumping to files
408     */
409 root 1.25 const char *
410 root 1.4 describe_resistance (const object *op, int newline)
411 elmex 1.1 {
412 root 1.60 static dynbuf_text buf; buf.clear ();
413 root 1.4
414 root 1.60 for (int i = 0; i < NROFATTACKS; i++)
415     if (op->resist[i] && (op->type != FLESH || atnr_is_dragon_enabled (i) == 1))
416     buf.printf (newline ? "%s %d\n" : "(%s %+d)", resist_plus[i], op->resist[i]);
417 root 1.55
418 root 1.4 return buf;
419 elmex 1.1 }
420    
421     /*
422     * query_weight(object) returns a character pointer to a static buffer
423     * containing the text-representation of the weight of the given object.
424     * The buffer will be overwritten by the next call to query_weight().
425 root 1.55 *
426     * Seems to be used only by unimportant stuff. Remove?
427 elmex 1.1 */
428 root 1.25 const char *
429 root 1.4 query_weight (const object *op)
430     {
431 elmex 1.1 static char buf[10];
432 root 1.46 sint32 i = op->total_weight ();
433 elmex 1.1
434 root 1.4 if (op->weight < 0)
435 elmex 1.1 return " ";
436 root 1.25
437 root 1.4 if (i % 1000)
438     sprintf (buf, "%6.1f", i / 1000.0);
439 elmex 1.1 else
440 root 1.4 sprintf (buf, "%4d ", i / 1000);
441 root 1.25
442 elmex 1.1 return buf;
443     }
444    
445     /*
446     * Returns the pointer to a static buffer containing
447     * the number requested (of the form first, second, third...)
448     */
449 root 1.25 const char *
450 root 1.81 ordinal (int i)
451 root 1.4 {
452 root 1.81 if (i < 0)
453     return format ("minus %s", ordinal (-i));
454 root 1.4
455 root 1.81 if (i < 21)
456     return ordnumbers[i];
457 root 1.25
458 root 1.81 int digit = i % 10;
459 root 1.55
460 root 1.81 if (i >= 100)
461     return format (
462     digit == 1 ? "%dst"
463     : digit == 2 ? "%dnd"
464     : digit == 3 ? "%drd"
465     : "%dth",
466     i
467     );
468 root 1.25
469 root 1.81 if (digit == 0)
470     return ordnumbers_10[i / 10];
471     else
472     return format ("%s%s", numbers_10[i / 10], ordnumbers[i % 10]);
473 elmex 1.1 }
474    
475     /*
476     * Returns pointer to static buffer containing ring's or amulet's
477     * abilities
478     * These are taken from old query_name(), but it would work better
479     * if describle_item() would be called to get this information and
480     * caller would handle FULL_RING_DESCRIPTION definition.
481     * Or make FULL_RING_DESCRIPTION standard part of a game and let
482     * client handle names.
483     */
484 root 1.4
485 elmex 1.1 /* Aug 95 modified this slightly so that Skill tools don't have magic bonus
486     * from stats.sp - b.t.
487     */
488 root 1.63 static const char *
489 root 1.4 ring_desc (const object *op)
490 elmex 1.1 {
491 root 1.39 static dynbuf_text buf; buf.clear ();
492 root 1.4 int attr, val, len;
493 elmex 1.1
494 root 1.83 if (op->flag [FLAG_IDENTIFIED])
495 root 1.39 {
496     for (attr = 0; attr < NUM_STATS; attr++)
497     if ((val = op->stats.stat (attr)))
498     buf.printf ("(%s%+d)", short_stat_name[attr], val);
499 elmex 1.1
500 root 1.39 if (op->stats.exp) buf.printf ("(speed %+lld)", (long long)op->stats.exp);
501     if (op->stats.wc) buf.printf ("(wc%+d)", op->stats.wc);
502     if (op->stats.dam) buf.printf ("(dam%+d)", op->stats.dam);
503     if (op->stats.ac) buf.printf ("(ac%+d)", op->stats.ac);
504    
505     buf << describe_resistance (op, 0);
506    
507     if (op->stats.food) buf.printf ("(sustenance%+d)", op->stats.food);
508     if (op->stats.grace) buf.printf ("(grace%+d)", op->stats.grace);
509     if (op->stats.sp && op->type != SKILL) buf.printf ("(magic%+d)", op->stats.sp);
510     if (op->stats.hp) buf.printf ("(regeneration%+d)", op->stats.hp);
511     if (op->stats.luck) buf.printf ("(luck%+d)", op->stats.luck);
512    
513 root 1.83 if (op->flag [FLAG_LIFESAVE]) buf << "(lifesaving)";
514     if (op->flag [FLAG_REFL_SPELL]) buf << "(reflect spells)";
515     if (op->flag [FLAG_REFL_MISSILE]) buf << "(reflect missiles)";
516     if (op->flag [FLAG_STEALTH]) buf << "(stealth)";
517 root 1.39
518     buf.add_paths ("Attuned" , op->path_attuned);
519     buf.add_paths ("Repelled", op->path_repelled);
520     buf.add_paths ("Denied" , op->path_denied);
521 root 1.4
522 root 1.39 if (buf.empty ())
523     buf << "of adornment";
524 root 1.4 }
525 root 1.27
526 root 1.4 return buf;
527 elmex 1.1 }
528    
529     /*
530     * query_short_name(object) is similar to query_name, but doesn't
531     * contain any information about object status (worn/cursed/etc.)
532 root 1.55 *
533     * It is sometimes used when printing messages, so should fit well into a sentence.
534 elmex 1.1 */
535 root 1.4 const char *
536     query_short_name (const object *op)
537 elmex 1.1 {
538 root 1.52 if (!op->name)
539 root 1.4 return "(null)";
540 root 1.5
541 root 1.42 if (!op->nrof
542     && !op->weight
543     && !op->title
544     && !is_magical (op)
545     && op->slaying != shstr_money)
546 root 1.4 return op->name; /* To speed things up (or make things slower?) */
547    
548 root 1.42 static dynbuf_text buf; buf.clear ();
549    
550 root 1.39 buf << (op->nrof <= 1 ? op->name : op->name_pl);
551 root 1.4
552 root 1.83 if (op->title && op->flag [FLAG_IDENTIFIED])
553 root 1.39 buf << ' ' << op->title;
554 elmex 1.1
555 root 1.4 switch (op->type)
556     {
557 root 1.39 case SPELLBOOK:
558     case SCROLL:
559     case WAND:
560     case ROD:
561 root 1.83 if (op->flag [FLAG_IDENTIFIED] || op->flag [FLAG_BEEN_APPLIED])
562 root 1.39 {
563     if (!op->title)
564     buf << " of " << (op->inv ? &op->inv->name : "bug, please report");
565    
566     if (op->type != SPELLBOOK)
567     buf.printf (" (lvl %d)", op->level);
568     }
569     break;
570    
571 root 1.53 case ALTAR:
572     case TRIGGER_ALTAR:
573     case IDENTIFY_ALTAR:
574     case CONVERTER:
575     if (op->slaying == shstr_money)
576     {
577     bool wrap = !!buf.size ();
578 root 1.42
579 root 1.53 if (wrap) buf << " [";
580 root 1.42
581 root 1.53 archetype *coin = 0;
582 root 1.42
583 root 1.53 for (char const *const *c = coins; *coins; ++c)
584     if ((coin = archetype::find (*c)))
585     if (op->stats.food % coin->value == 0)
586     break;
587 root 1.42
588 root 1.53 sint32 coins = op->stats.food / coin->value;
589 root 1.42
590 root 1.53 buf.printf ("drop %d %s (or equivalent)", coins, coins == 1 ? &coin->name : &coin->name_pl);
591 root 1.42
592 root 1.53 if (wrap) buf << ']';
593     }
594     break;
595 root 1.42
596 root 1.39 case SKILL:
597     case AMULET:
598     case RING:
599     if (!op->title)
600     {
601     /* If ring has a title, full description isn't so useful */
602     const char *s = ring_desc (op);
603 elmex 1.1
604 root 1.39 if (s && *s)
605     buf << " " << s;
606     }
607     break;
608 root 1.42
609 root 1.39 default:
610 root 1.84 if (op->magic
611     && ((op->flag [FLAG_BEEN_APPLIED] && op->need_identify ())
612     || op->flag [FLAG_IDENTIFIED]))
613 root 1.39 buf.printf (" %+d", op->magic);
614 elmex 1.1 }
615 root 1.39
616 root 1.4 return buf;
617 elmex 1.1 }
618    
619     /*
620     * query_name(object) returns a character pointer pointing to a static
621     * buffer which contains a verbose textual representation of the name
622     * of the given object.
623     * cf 0.92.6: Put in 5 buffers that it will cycle through. In this way,
624     * you can make several calls to query_name before the bufs start getting
625     * overwritten. This may be a bad thing (it may be easier to assume the value
626     * returned is good forever.) However, it makes printing statements that
627     * use several names much easier (don't need to store them to temp variables.)
628     *
629 root 1.55 * It is used extensively within messages, so should return only a prose
630     * and short description of the item.
631 root 1.71 * It is also used by examine/ex and similar functions.
632 elmex 1.1 */
633 root 1.25 const char *
634 root 1.4 query_name (const object *op)
635     {
636 root 1.39 int len = 0;
637     static dynbuf_text bufs[5];
638 root 1.4 static int use_buf = 0;
639 elmex 1.1
640 root 1.4 use_buf++;
641     use_buf %= 5;
642 elmex 1.1
643 root 1.39 dynbuf_text &buf = bufs [use_buf];
644     buf.clear ();
645    
646 root 1.67 #if 0
647     if ((op->is_armor () || op->is_weapon ()) && op->material)
648     buf << op->material->description << ' ';
649     #endif
650 elmex 1.1
651 root 1.39 buf << query_short_name (op);
652 elmex 1.1
653 root 1.83 if (op->flag [FLAG_INV_LOCKED])
654 root 1.39 buf << " *";
655 root 1.61 if (op->is_open_container ())
656 root 1.39 buf << " (open)";
657 root 1.4
658 root 1.83 if (op->flag [FLAG_KNOWN_CURSED])
659 root 1.4 {
660 root 1.83 if (op->flag [FLAG_DAMNED])
661 root 1.39 buf << " (damned)";
662 root 1.83 else if (op->flag [FLAG_CURSED])
663 root 1.39 buf << " (cursed)";
664 root 1.4 }
665 root 1.23
666 root 1.4 /* Basically, if the object is known magical (detect magic spell on it),
667     * and it isn't identified, print out the fact that
668     * it is magical. Assume that the detect magical spell will only set
669     * KNOWN_MAGICAL if the item actually is magical.
670     *
671     * Changed in V 0.91.4 - still print that the object is magical even
672     * if it has been applied. Equipping an item does not tell full
673     * abilities, especially for artifact items.
674     */
675 root 1.83 if (op->flag [FLAG_KNOWN_MAGICAL] && !op->flag [FLAG_IDENTIFIED])
676 root 1.39 buf << " (magic)";
677 elmex 1.1
678     #if 0
679 root 1.55 /* item_power will be returned in describe_item - it shouldn't really
680 root 1.4 * be returned in the name.
681     */
682     if (op->item_power)
683     sprintf (buf[use_buf] + strlen (buf[use_buf]), "(item_power %+d)", op->item_power);
684 elmex 1.1
685     #endif
686    
687 root 1.83 if (op->flag [FLAG_APPLIED])
688 root 1.4 {
689     switch (op->type)
690     {
691 root 1.23 case BOW:
692     case WAND:
693     case ROD:
694     case HORN:
695 root 1.77 buf << " (applied)";
696 root 1.23 break;
697     case WEAPON:
698 root 1.77 buf << " (applied)";
699 root 1.23 break;
700     case ARMOUR:
701     case HELMET:
702     case SHIELD:
703     case RING:
704     case BOOTS:
705     case GLOVES:
706     case AMULET:
707     case GIRDLE:
708     case BRACERS:
709     case CLOAK:
710 root 1.39 buf << " (worn)";
711 root 1.23 break;
712     case CONTAINER:
713 root 1.39 buf << " (active)";
714 root 1.23 break;
715     case SKILL:
716     default:
717 root 1.39 buf << " (applied)";
718 root 1.2 }
719 elmex 1.1 }
720 root 1.23
721 elmex 1.54 switch (op->type)
722     {
723     case LAMP:
724     if (op->glow_radius)
725     buf << " (on)";
726     else if (op->stats.food <= 0)
727     buf << " (empty)";
728     else
729     buf << " (off)";
730     break;
731    
732     case TORCH:
733     if (op->glow_radius)
734     buf << " (burning)";
735     else if (op->stats.food <= 0)
736     buf << " (burned out)";
737     break;
738     }
739    
740 root 1.83 if (op->flag [FLAG_UNPAID])
741 root 1.39 buf << " (unpaid)";
742 elmex 1.1
743 root 1.39 return buf;
744 elmex 1.1 }
745    
746     /*
747     * query_base_name(object) returns a character pointer pointing to a static
748     * buffer which contains a verbose textual representation of the name
749     * of the given object. The buffer will be overwritten at the next
750     * call to query_base_name(). This is a lot like query_name, but we
751     * don't include the item count or item status. Used for inventory sorting
752     * and sending to client.
753     * If plural is set, we generate the plural name of this.
754 root 1.55 *
755     * It is sometimes used to display messages, and usually only used to match stuff,
756     * so maybe this function should be removed.
757 root 1.71 * It is also used for client-side inventory/item descriptions.
758 elmex 1.1 */
759 root 1.4 const char *
760     query_base_name (const object *op, int plural)
761     {
762     if ((!plural && !op->name) || (plural && !op->name_pl))
763     return "(null)";
764 elmex 1.1
765 root 1.71 if (!op->nrof && !op->weight && !op->title && !is_magical (op)
766     && op->type != EXIT)
767 root 1.4 return op->name; /* To speed things up (or make things slower?) */
768 elmex 1.1
769 root 1.39 static dynbuf_text buf; buf.clear ();
770    
771 root 1.67 #if 0
772     if ((op->is_armor () || op->is_weapon ()) && op->material)
773     if (op->arch->material != op->material)
774     buf << op->material->description << ' ';
775     #endif
776 root 1.20
777 root 1.39 buf << (plural ? op->name_pl : op->name);
778 elmex 1.1
779 root 1.83 if (op->title && op->flag [FLAG_IDENTIFIED])
780 root 1.39 buf << ' ' << op->title;
781 elmex 1.1
782 root 1.4 switch (op->type)
783     {
784 root 1.20 case SPELLBOOK:
785     case SCROLL:
786     case WAND:
787     case ROD:
788 root 1.83 if (op->flag [FLAG_IDENTIFIED] || op->flag [FLAG_BEEN_APPLIED])
789 root 1.20 {
790     if (!op->title)
791 root 1.39 buf << " of " << (op->inv ? &op->inv->name : "bug, please report");
792    
793 root 1.20 if (op->type != SPELLBOOK)
794 root 1.39 buf.printf (" (lvl %d)", op->level);
795 root 1.20 }
796     break;
797 elmex 1.1
798    
799 root 1.20 case SKILL:
800     case AMULET:
801     case RING:
802     if (!op->title)
803     {
804     /* If ring has a title, full description isn't so useful */
805 root 1.25 const char *s = ring_desc (op);
806 root 1.4
807 root 1.39 if (s && *s)
808     buf << ' ' << s;
809 root 1.20 }
810     break;
811 root 1.29
812 root 1.72 case EXIT:
813     // random map exits "unfortunately" get patched, so this only works before entering
814 root 1.76 if (EXIT_PATH (op) == shstr_random_map_exit)
815     buf << " (random map)";
816     else if (!EXIT_PATH (op))
817     buf << " (closed)";
818 root 1.72 break;
819    
820 root 1.20 default:
821 root 1.84 if (op->magic
822     && ((op->flag [FLAG_BEEN_APPLIED] && op->need_identify ())
823     || op->flag [FLAG_IDENTIFIED]))
824 root 1.39 buf.printf (" %+d", op->magic);
825 elmex 1.1 }
826 root 1.20
827 root 1.4 return buf;
828 elmex 1.1 }
829    
830     /* Break this off from describe_item - that function was way
831     * too long, making it difficult to read. This function deals
832     * with describing the monsters & players abilities. It should only
833     * be called with monster & player objects. Returns a description
834     * in a static buffer.
835     */
836 root 1.39 static const char *
837 root 1.4 describe_monster (const object *op)
838     {
839 root 1.39 static dynbuf_text buf; buf.clear ();
840 root 1.4
841     /* Note that the resolution this provides for players really isn't
842     * very good. Any player with a speed greater than .67 will
843     * fall into the 'lightning fast movement' category.
844     */
845 elmex 1.16 if (op->has_active_speed ())
846 root 1.68 switch ((int)(op->speed * 15.))
847 root 1.39 {
848     case 0:
849 root 1.51 buf << "(very slow movement)";
850 root 1.39 break;
851     case 1:
852     buf << "(slow movement)";
853     break;
854     case 2:
855     buf << "(normal movement)";
856     break;
857     case 3:
858     case 4:
859     buf << "(fast movement)";
860     break;
861     case 5:
862     case 6:
863     buf << "(very fast movement)";
864     break;
865     case 7:
866     case 8:
867     case 9:
868     case 10:
869     buf << "(extremely fast movement)";
870     break;
871     default:
872     buf << "(lightning fast movement)";
873     break;
874     }
875    
876 root 1.83 if (op->flag [FLAG_UNDEAD]) buf << "(undead)";
877     if (op->flag [FLAG_SEE_INVISIBLE]) buf << "(see invisible)";
878     if (op->flag [FLAG_USE_WEAPON]) buf << "(wield weapon)";
879     if (op->flag [FLAG_USE_BOW]) buf << "(archer)";
880     if (op->flag [FLAG_USE_ARMOUR]) buf << "(wear armour)";
881     if (op->flag [FLAG_USE_RING]) buf << "(wear ring)";
882     if (op->flag [FLAG_USE_SCROLL]) buf << "(read scroll)";
883     if (op->flag [FLAG_USE_RANGE]) buf << "(fires wand/rod/horn)";
884     if (op->flag [FLAG_CAN_USE_SKILL]) buf << "(skill user)";
885     if (op->flag [FLAG_CAST_SPELL]) buf << "(spellcaster)";
886     if (op->flag [FLAG_FRIENDLY]) buf << "(friendly)";
887     if (op->flag [FLAG_UNAGGRESSIVE]) buf << "(unaggressive)";
888     if (op->flag [FLAG_HITBACK]) buf << "(hitback)";
889     if (op->flag [FLAG_STEALTH]) buf << "(stealthy)";
890 root 1.39
891     if (op->randomitems)
892 root 1.4 {
893 root 1.39 bool first = 1;
894 root 1.4
895 root 1.39 for (treasure *t = op->randomitems->items; t; t = t->next)
896 root 1.37 if (t->item && t->item->type == SPELL)
897 root 1.4 {
898     if (first)
899 root 1.39 buf << "(Spell abilities:)";
900    
901     first = 0;
902    
903     buf << '(' << t->item->object::name << ')';
904 root 1.4 }
905     }
906 root 1.39
907 root 1.4 if (op->type == PLAYER)
908     {
909     if (op->contr->digestion)
910 root 1.39 buf.printf ("(sustenance%+d)", op->contr->digestion);
911    
912 root 1.4 if (op->contr->gen_grace)
913 root 1.39 buf.printf ("(grace%+d)", op->contr->gen_grace);
914    
915 root 1.4 if (op->contr->gen_sp)
916 root 1.39 buf.printf ("(magic%+d)", op->contr->gen_sp);
917    
918 root 1.4 if (op->contr->gen_hp)
919 root 1.39 buf.printf ("(regeneration%+d)", op->contr->gen_hp);
920    
921 root 1.4 if (op->stats.luck)
922 root 1.39 buf.printf ("(luck%+d)", op->stats.luck);
923 elmex 1.1 }
924 root 1.4
925     /* describe attacktypes */
926 root 1.69 if (op->is_dragon ())
927 root 1.4 {
928     /* for dragon players display the attacktypes from clawing skill
929     * Break apart the for loop - move the comparison checking down -
930     * this makes it more readable.
931     */
932     object *tmp;
933    
934 root 1.39 for (tmp = op->inv; tmp; tmp = tmp->below)
935     if (tmp->type == SKILL && tmp->name == shstr_clawing)
936 root 1.4 break;
937    
938 root 1.39 if (tmp && tmp->attacktype)
939     buf.add_abilities ("Claws", tmp->attacktype);
940 root 1.4 else
941 root 1.39 buf.add_abilities ("Attacks", op->attacktype);
942 elmex 1.1 }
943 root 1.4 else
944 root 1.39 buf.add_abilities ("Attacks", op->attacktype);
945 root 1.21
946 root 1.39 buf.add_paths ("Attuned" , op->path_attuned);
947     buf.add_paths ("Repelled", op->path_repelled);
948     buf.add_paths ("Denied" , op->path_denied);
949 root 1.22
950 root 1.39 for (int i = 0; i < NROFATTACKS; i++)
951 root 1.22 if (op->resist[i])
952 root 1.39 buf.printf ("(%s %+d)", resist_plus[i], op->resist[i]);
953 root 1.22
954 root 1.39 return buf;
955 elmex 1.1 }
956    
957     /*
958     * Returns a pointer to a static buffer which contains a
959     * description of the given object.
960     * If it is a monster, lots of information about its abilities
961     * will be returned.
962     * If it is an item, lots of information about which abilities
963     * will be gained about its user will be returned.
964     * If it is a player, it writes out the current abilities
965     * of the player, which is usually gained by the items applied.
966     * It would be really handy to actually pass another object
967     * pointer on who is examining this object. Then, you could reveal
968     * certain information depending on what the examiner knows, eg,
969     * wouldn't need to use the SEE_INVISIBLE flag to know it is
970     * a dragon player examining food. Could have things like
971     * a dwarven axe, in which the full abilities are only known to
972     * dwarves, etc.
973     *
974     * Add 'owner' who is the person examining this object.
975     * owner can be null if no one is being associated with this
976     * item (eg, debug dump or the like)
977     */
978 root 1.25 const char *
979 root 1.4 describe_item (const object *op, object *owner)
980     {
981 root 1.83 if (op->flag [FLAG_MONSTER] || op->type == PLAYER)
982 root 1.39 return describe_monster (op);
983    
984     static dynbuf_text buf; buf.clear ();
985 root 1.4 int identified, i;
986    
987     /* figure this out once, instead of making multiple calls to need_identify.
988     * also makes the code easier to read.
989     */
990 root 1.84 identified = !op->need_identify () || op->flag [FLAG_IDENTIFIED];
991 root 1.39 if (!identified)
992     buf << "(unidentified)";
993    
994 root 1.4 switch (op->type)
995     {
996 root 1.39 case BOW:
997     case ARROW:
998     case WAND:
999     case ROD:
1000     case HORN:
1001     case WEAPON:
1002     case ARMOUR:
1003     case HELMET:
1004     case SHIELD:
1005     case BOOTS:
1006     case GLOVES:
1007     case GIRDLE:
1008     case BRACERS:
1009     case CLOAK:
1010     case SKILL_TOOL:
1011     break; /* We have more information to do below this switch */
1012    
1013     case POWER_CRYSTAL:
1014     if (op->stats.maxsp > 1000)
1015     { /*higher capacity crystals */
1016     i = (op->stats.maxsp % 1000) / 100;
1017    
1018     if (i)
1019 root 1.78 buf.printf ("(capacity %d.%dk; it is ", op->stats.maxsp / 1000, i);
1020 root 1.39 else
1021 root 1.78 buf.printf ("(capacity %dk; it is ", op->stats.maxsp / 1000);
1022 root 1.39 }
1023     else
1024 root 1.78 buf.printf ("(capacity %d; it is ", op->stats.maxsp);
1025 root 1.39
1026     i = (op->stats.sp * 10) / op->stats.maxsp;
1027     if (op->stats.sp == 0)
1028 root 1.78 buf << "empty";
1029 root 1.39 else if (i == 0)
1030 root 1.78 buf << "almost empty";
1031 root 1.39 else if (i < 3)
1032 root 1.78 buf << "partially filled";
1033 root 1.39 else if (i < 6)
1034 root 1.78 buf << "half full";
1035 root 1.39 else if (i < 9)
1036 root 1.78 buf << "well charged";
1037 root 1.39 else if (op->stats.sp == op->stats.maxsp)
1038 root 1.78 buf << "fully charged";
1039 root 1.39 else
1040 root 1.78 buf << "almost full";
1041    
1042     buf << ')';
1043 root 1.39 break;
1044    
1045 elmex 1.54 case LAMP:
1046     {
1047     int percent = ((double) 100 / op->arch->stats.food) * op->stats.food;
1048     buf << "(fuel: ";
1049     if (percent == 0)
1050     buf << "empty";
1051     else if (percent < 10)
1052     buf << "very low";
1053     else if (percent < 25)
1054     buf << "low";
1055     else if (percent < 50)
1056     buf << "half empty";
1057     else if (percent < 75)
1058     buf << "half full";
1059     else if (percent < 95)
1060     buf << "well filled";
1061     else if (percent <= 100)
1062     buf << "full";
1063     buf << ")";
1064     }
1065     break;
1066    
1067 root 1.39 case FOOD:
1068     case FLESH:
1069     case DRINK:
1070 root 1.83 if (identified || op->flag [FLAG_BEEN_APPLIED])
1071 root 1.39 {
1072     buf.printf ("(food+%d)", op->stats.food);
1073    
1074     if (op->type == FLESH && op->last_eat > 0 && atnr_is_dragon_enabled (op->last_eat))
1075     buf.printf ("(%s metabolism)", change_resist_msg[op->last_eat]);
1076    
1077 root 1.83 if (!op->flag [FLAG_CURSED])
1078 root 1.39 {
1079     if (op->stats.hp) buf << "(heals)";
1080     if (op->stats.sp) buf << "(spellpoint regen)";
1081     }
1082     else
1083     {
1084     if (op->stats.hp) buf << "(damages)";
1085     if (op->stats.sp) buf << "(spellpoint depletion)";
1086     }
1087     }
1088     break;
1089    
1090     case SKILL:
1091     case RING:
1092     case AMULET:
1093     if (op->item_power)
1094     buf.printf ("(item_power %+d)", op->item_power);
1095 root 1.2
1096 root 1.39 if (op->title)
1097     buf << ring_desc (op);
1098 root 1.2
1099 root 1.39 return buf;
1100 elmex 1.1
1101 root 1.39 default:
1102     return buf;
1103 elmex 1.1 }
1104    
1105 root 1.4 /* Down here, we more further describe equipment type items.
1106     * only describe them if they have been identified or the like.
1107     */
1108 root 1.83 if (identified || op->flag [FLAG_BEEN_APPLIED])
1109 root 1.4 {
1110     int attr, val;
1111    
1112     for (attr = 0; attr < NUM_STATS; attr++)
1113 root 1.39 if ((val = op->stats.stat (attr)))
1114     buf.printf ("(%s%+d)", short_stat_name[attr], val);
1115 root 1.2
1116 root 1.4 if (op->stats.exp)
1117 root 1.39 buf.printf ("(speed %+lld)", (long long) op->stats.exp);
1118    
1119     switch (op->type)
1120 root 1.4 {
1121 root 1.39 case BOW:
1122     case ARROW:
1123     case GIRDLE:
1124     case HELMET:
1125     case SHIELD:
1126     case BOOTS:
1127     case GLOVES:
1128     case WEAPON:
1129     case SKILL:
1130     case RING:
1131     case AMULET:
1132     case ARMOUR:
1133     case BRACERS:
1134     case FORCE:
1135     case CLOAK:
1136     if (op->stats.wc) buf.printf ("(wc%+d)", op->stats.wc);
1137     if (op->stats.dam) buf.printf ("(dam%+d)", op->stats.dam);
1138     if (op->stats.ac) buf.printf ("(ac%+d)", op->stats.ac);
1139 root 1.2
1140 root 1.39 if ((op->type == WEAPON || op->type == BOW) && op->level > 0)
1141     buf.printf ("(improved %d/%d)", op->last_eat, op->level);
1142 root 1.2
1143 root 1.39 break;
1144 root 1.2
1145 root 1.39 default:
1146     break;
1147 root 1.2 }
1148 root 1.39
1149 root 1.83 if (op->flag [FLAG_XRAYS]) buf << "(xray-vision)";
1150     if (op->flag [FLAG_SEE_IN_DARK]) buf << "(infravision)";
1151 root 1.4
1152     /* levitate was what is was before, so we'll keep it */
1153 root 1.39 if (op->move_type & MOVE_FLY_LOW) buf << "(levitate)";
1154     if (op->move_type & MOVE_FLY_HIGH) buf << "(fly)";
1155     if (op->move_type & MOVE_SWIM) buf << "(swim)";
1156 root 1.4
1157     /* walking is presumed as 'normal', so doesn't need mentioning */
1158    
1159     if (op->item_power)
1160 root 1.39 buf.printf ("(item_power %+d)", op->item_power);
1161 root 1.4 } /* End if identified or applied */
1162    
1163     /* This blocks only deals with fully identified object.
1164     * it is intentional that this is not an 'else' from a above -
1165     * in this way, information is added.
1166     */
1167     if (identified)
1168     {
1169     int more_info = 0;
1170    
1171     switch (op->type)
1172     {
1173 root 1.39 case ROD: /* These use stats.sp for spell selection and stats.food */
1174     case HORN: /* and stats.hp for spell-point regeneration... */
1175     case BOW:
1176     case ARROW:
1177     case WAND:
1178     case FOOD:
1179     case FLESH:
1180     case DRINK:
1181     more_info = 0;
1182     break;
1183    
1184     /* Armor type objects */
1185     case ARMOUR:
1186     case HELMET:
1187     case SHIELD:
1188     case BOOTS:
1189     case GLOVES:
1190     case GIRDLE:
1191     case BRACERS:
1192     case CLOAK:
1193     if (ARMOUR_SPEED (op)) buf.printf ("(Max speed %1.2f)", ARMOUR_SPEED (op) / 10.0);
1194     if (ARMOUR_SPELLS (op)) buf.printf ("(Spell regen penalty %d)", ARMOUR_SPELLS (op));
1195     more_info = 1;
1196     break;
1197 root 1.4
1198 root 1.39 case WEAPON:
1199     /* Calculate it the same way fix_player does so the results
1200     * make sense.
1201     */
1202     i = (WEAPON_SPEED (op) * 2 - op->magic) / 2;
1203     if (i < 0)
1204     i = 0;
1205    
1206     buf.printf ("(weapon speed %d)", i);
1207     more_info = 1;
1208     break;
1209 root 1.4 }
1210 root 1.39
1211 root 1.4 if (more_info)
1212     {
1213 root 1.39 if (op->stats.food) buf.printf ("(sustenance%+d)", op->stats.food);
1214     if (op->stats.grace) buf.printf ("(grace%+d)", op->stats.grace);
1215     if (op->stats.sp) buf.printf ("(magic%+d)", op->stats.sp);
1216     if (op->stats.hp) buf.printf ("(regeneration%+d)", op->stats.hp);
1217 root 1.2 }
1218    
1219 root 1.4 if (op->stats.luck)
1220 root 1.39 buf.printf ("(luck%+d)", op->stats.luck);
1221    
1222 root 1.83 if (op->flag [FLAG_LIFESAVE]) buf << "(lifesaving)";
1223     if (op->flag [FLAG_REFL_SPELL]) buf << "(reflect spells)";
1224     if (op->flag [FLAG_REFL_MISSILE]) buf << "(reflect missiles)";
1225     if (op->flag [FLAG_STEALTH]) buf << "(stealth)";
1226 root 1.39
1227     if (op->slaying && op->type != FOOD)
1228     buf.printf ("(slay %s)", &op->slaying);
1229    
1230 root 1.57 if (op->type == SKILL_TOOL && op->skill)
1231     buf.printf ("(%s)", &op->skill);
1232 sf-marcmagus 1.56
1233 root 1.39 buf.add_abilities ("Attacks", op->attacktype);
1234 root 1.4 /* resistance on flesh is only visible for quetzals. If
1235     * non flesh, everyone can see its resistances
1236     */
1237 root 1.69 if (op->type != FLESH || (owner && owner->is_dragon ()))
1238 root 1.39 buf << describe_resistance (op, 0);
1239    
1240     buf.add_paths ("Attuned", op->path_attuned);
1241     buf.add_paths ("Repelled", op->path_repelled);
1242     buf.add_paths ("Denied", op->path_denied);
1243 elmex 1.1 }
1244    
1245 root 1.39 return buf;
1246 elmex 1.1 }
1247    
1248 root 1.26 std::string
1249     object::describe_item (object *who)
1250     {
1251     return std::string (::describe_item (this, who));
1252     }
1253    
1254 root 1.79 static void
1255     describe_dump_object (dynbuf &buf, object *ob)
1256     {
1257     char *txt = dump_object (ob);
1258     for (char *p = txt; *p; ++p) if (*p == '\n') *p = '\r';
1259     buf << "\n" << txt << "\n";
1260    
1261     if (!ob->is_arch ())
1262     describe_dump_object (buf, ob->arch);
1263     }
1264    
1265     std::string
1266     object::describe (object *who)
1267     {
1268     dynbuf_text buf (1024, 1024);
1269    
1270     buf.printf ("That is: %s.\r", long_desc (who).c_str ());
1271    
1272     if (custom_name)
1273     buf.printf ("You call it %s.\r", &custom_name);
1274    
1275     switch (type)
1276     {
1277     case SPELLBOOK:
1278     if (flag [FLAG_IDENTIFIED] && inv)
1279 root 1.81 buf.printf ("%s is a %s level %s spell.\r", &inv->name, ordinal (inv->level), &inv->skill);
1280 root 1.79 break;
1281    
1282     case BOOK:
1283     if (msg)
1284     buf << "Something is written in it.\r";
1285     break;
1286    
1287     case CONTAINER:
1288     if (race)
1289     {
1290     if (weight_limit && stats.Str < 100)
1291     buf.printf ("It can hold only %s and its weight limit is %.1f kg.\r",
1292     &race, weight_limit / (10.0 * (100 - stats.Str)));
1293     else
1294     buf.printf ("It can hold only %s.\r", &race);
1295     }
1296     else if (weight_limit && stats.Str < 100)
1297     buf.printf ("Its weight limit is %.1f kg.\r", weight_limit / (10.0 * (100 - stats.Str)));
1298     break;
1299    
1300     case WAND:
1301     if (flag [FLAG_IDENTIFIED])
1302     buf.printf ("It has %d %s left.\r", stats.food, stats.food == 1 ? "charge" : "charges");
1303     break;
1304     }
1305    
1306     if (material != MATERIAL_NULL && !msg)
1307     buf << (nrof > 1 ? "They are made of " : "It is made of ")
1308     << material->description
1309     << ".\r";
1310    
1311     if (who)
1312     /* Where to wear this item */
1313     for (int i = 0; i < NUM_BODY_LOCATIONS; i++)
1314     if (slot[i].info)
1315     {
1316     buf << (who->slot[i].info ? body_locations[i].use_name : body_locations[i].nonuse_name);
1317    
1318     if (slot[i].info < -1 && who->slot[i].info)
1319     buf.printf ("(%d)", -slot[i].info);
1320    
1321     buf << ".\r";
1322     }
1323    
1324     if (weight)
1325     buf.printf ("%s %3.3f kg.\r", nrof > 1 ? "They weigh" : "It weighs", weight * (nrof ? nrof : 1) / 1000.0);
1326    
1327     if (flag [FLAG_STARTEQUIP])
1328     buf << (nrof > 1 ? "They were" : "It was")
1329     << " given by a god and will vanish when dropped.\r";
1330    
1331     if (value && !flag [FLAG_STARTEQUIP] && !flag [FLAG_NO_PICK] && who)
1332     {
1333     buf.printf ("You reckon %s worth %s.\r", nrof > 1 ? "they are" : "it is", query_cost_string (this, who, F_TRUE | F_APPROX));
1334    
1335     if (who->is_in_shop ())
1336     {
1337     if (flag [FLAG_UNPAID])
1338     buf.printf ("%s would cost you %s.\r", nrof > 1 ? "They" : "It", query_cost_string (this, who, F_BUY | F_SHOP));
1339     else
1340     buf.printf ("You are offered %s for %s.\r", query_cost_string (this, who, F_SELL + F_SHOP), nrof > 1 ? "them" : "it");
1341     }
1342     }
1343    
1344     if (flag [FLAG_MONSTER])
1345     buf << describe_monster (who);
1346    
1347     /* Is this item buildable? */
1348     if (flag [FLAG_IS_BUILDABLE])
1349     buf << "This is a buildable item.\r";
1350    
1351     /* Does the object have a message? Don't show message for all object
1352     * types - especially if the first entry is a match
1353     */
1354     if (msg)
1355     {
1356     if (type != EXIT && type != BOOK && type != CORPSE && !move_on && !has_dialogue ())
1357     {
1358 root 1.84 if (!need_identify ())
1359     buf << '\r' << msg << '\n';
1360     else if (flag [FLAG_IDENTIFIED])
1361     buf << '\r' << "The object has a story:\r" << msg;
1362 root 1.79 }
1363     }
1364 root 1.84 else if (inv
1365     && inv->msg
1366     && inv->type == SPELL
1367     && flag [FLAG_IDENTIFIED]
1368 root 1.79 && (type == SPELLBOOK || type == ROD || type == WAND
1369     || type == ROD || type == POTION || type == SCROLL))
1370     // for spellbooks and other stuff that contains spells, print the spell message,
1371     // unless the object has a custom message handled above.
1372     buf << '\r' << inv->msg << '\n';
1373    
1374     // try to display the duration for some potions and scrolls
1375     // this includes change ability potions and group spells,
1376     // but does not handle protection potions
1377     if (inv && inv->type == SPELL && flag [FLAG_IDENTIFIED]
1378     && (type == POTION || type == SCROLL))
1379     {
1380     object *spell = inv;
1381    
1382     if (spell->subtype == SP_PARTY_SPELL)
1383     spell = spell->other_arch;
1384    
1385     if (spell->subtype == SP_CHANGE_ABILITY)
1386     buf.printf ("\nH<The effect will last about %.10g seconds.>",
1387     TICK2TIME (change_ability_duration (spell, this)));
1388     }
1389    
1390 root 1.80 // some help text for skill tools
1391     if (type == SKILL_TOOL)
1392     buf << "\nH<This item is a skill tool: as long as you have this item applied "
1393     "you can use the " << &skill << " skill as if you had learned it.>";
1394    
1395 root 1.79 // Display a hint about inscribable items [empty books]
1396     // This includes the amount of text they can hold.
1397     if (type == INSCRIBABLE)
1398     {
1399     if (other_arch && other_arch->type == SCROLL)
1400     buf.printf ("\nH<You can use the inscription skill to inscribe a spell into it.>");
1401     else
1402     buf.printf ("\nH<You can use the inscription skill to inscribe text into it. It has room for up to %d characters.>",
1403     weight_limit);
1404     }
1405    
1406     buf << '\n';
1407    
1408     // the dungeon master additionally gets a complete dump
1409     if (who && who->flag [FLAG_WIZLOOK])
1410     {
1411     buf << "\nT<Object>\n";
1412     describe_dump_object (buf, this);
1413    
1414     if (inv)
1415     {
1416     buf << "\nT<Top Inventory>\n";
1417     describe_dump_object (buf, inv);
1418     }
1419     }
1420    
1421     return std::string (buf.linearise (), buf.size ());
1422     }
1423    
1424 root 1.40 void
1425     examine (object *op, object *tmp)
1426     {
1427 root 1.45 std::string info = tmp->describe (op);
1428 root 1.55
1429 root 1.45 op->contr->infobox (MSG_CHANNEL ("examine"), info.c_str ());
1430 root 1.40 }
1431    
1432     /*
1433     * inventory prints object's inventory. If inv==NULL then print player's
1434     * inventory.
1435     * [ Only items which are applied are showed. Tero.Haatanen@lut.fi ]
1436     */
1437     const char *
1438     object::query_inventory (object *who, const char *indent)
1439     {
1440     static dynbuf_text buf; buf.clear ();
1441    
1442     for (object *tmp = inv; tmp; tmp = tmp->below)
1443 root 1.83 if (who && who->flag [FLAG_WIZ])
1444 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 ());
1445 root 1.83 else if (!tmp->invisible && (type == CONTAINER || tmp->flag [FLAG_APPLIED]))
1446 root 1.53 buf.printf ("%s- %-36.36s %-8s\n", indent, tmp->query_name (), tmp->query_weight ());
1447 root 1.40
1448     if (buf.size ())
1449 root 1.53 buf.printf ("%s(total weight: %s)\n", indent, query_weight ());
1450 root 1.40 else
1451     buf.printf ("%s(empty)\n", indent);
1452    
1453     return buf;
1454     }
1455    
1456 elmex 1.1 /* Return true if the item is magical. A magical item is one that
1457     * increases/decreases any abilities, provides a resistance,
1458     * has a generic magical bonus, or is an artifact.
1459     * This function is used by detect_magic to determine if an item
1460     * should be marked as magical.
1461     */
1462 root 1.4 int
1463     is_magical (const object *op)
1464     {
1465     int i;
1466 elmex 1.1
1467 root 1.4 /* living creatures are considered non magical */
1468 root 1.83 if (op->flag [FLAG_ALIVE])
1469 root 1.4 return 0;
1470 elmex 1.1
1471 root 1.4 /* This is a test for it being an artifact, as artifacts have titles */
1472     if (op->title != NULL)
1473     return 1;
1474    
1475     /* Handle rings and amulets specially. If they change any of these
1476     * values, it means they are magical.
1477     */
1478     if ((op->type == AMULET || op->type == RING) &&
1479     (op->stats.ac || op->stats.food || op->stats.exp || op->stats.dam || op->stats.wc || op->stats.sp || op->stats.hp || op->stats.luck))
1480     return 1;
1481    
1482     /* Check for stealty, speed, flying, or just plain magic in the boots */
1483     /* Presume any boots that hvae a move_type are special. */
1484 root 1.83 if (op->type == BOOTS && ((op->flag [FLAG_STEALTH] || op->move_type || op->stats.exp)))
1485 root 1.4 return 1;
1486    
1487     /* Take care of amulet/shield that reflects spells/missiles */
1488 root 1.83 if ((op->type == AMULET || op->type == SHIELD) && (op->flag [FLAG_REFL_SPELL] || op->flag [FLAG_REFL_MISSILE]))
1489 root 1.4 return 1;
1490    
1491     /* Take care of helmet of xrays */
1492 root 1.83 if (op->type == HELMET && op->flag [FLAG_XRAYS])
1493 root 1.4 return 1;
1494    
1495     /* Potions & rods are always magical. Wands/staves are also magical,
1496     * assuming they still have any charges left.
1497     */
1498     if (op->type == POTION || op->type == ROD || (op->type == WAND && op->stats.food))
1499     return 1;
1500    
1501     /* if something gives a protection, either positive or negative, its magical */
1502     /* This is really a pretty bad hack - as of now, ATNR_PHYSICAL is 0,
1503     * so this always works out fine.
1504     */
1505     for (i = ATNR_PHYSICAL + 1; i < NROFATTACKS; i++)
1506     if (op->resist[i])
1507     return 1;
1508    
1509     /* Physical protection is expected on some item types, so they should
1510     * not be considered magical.
1511     */
1512     if (op->resist[ATNR_PHYSICAL] && op->type != HELMET && op->type != SHIELD &&
1513     op->type != BOOTS && op->type != GLOVES && op->type != ARMOUR)
1514     return 1;
1515    
1516     /* power crystal, spellbooks, and scrolls are always magical. */
1517     if (op->magic || op->type == POWER_CRYSTAL || op->type == SPELLBOOK || op->type == SCROLL || op->type == GIRDLE)
1518     return 1;
1519    
1520     /* Check to see if it increases/decreases any stats */
1521     for (i = 0; i < NUM_STATS; i++)
1522 root 1.33 if (op->stats.stat (i))
1523 root 1.4 return 1;
1524    
1525     /* If it doesn't fall into any of the above categories, must
1526     * be non magical.
1527     */
1528     return 0;
1529 elmex 1.1 }
1530    
1531     /*
1532     * Supposed to fix face-values as well here, but later.
1533     */
1534 root 1.4 void
1535     identify (object *op)
1536     {
1537 root 1.83 op->set_flag (FLAG_IDENTIFIED);
1538     op->clr_flag (FLAG_KNOWN_MAGICAL);
1539     op->clr_flag (FLAG_NO_SKILL_IDENT);
1540 root 1.4
1541     /*
1542     * We want autojoining of equal objects:
1543     */
1544 root 1.83 if (op->flag [FLAG_CURSED] || op->flag [FLAG_DAMNED])
1545     op->set_flag (FLAG_KNOWN_CURSED);
1546 root 1.4
1547     if (op->type == POTION)
1548     {
1549     if (op->inv && op->randomitems)
1550     op->title = op->inv->name;
1551     else if (op->arch)
1552     {
1553 root 1.48 op->name = op->arch->object::name;
1554 root 1.37 op->name_pl = op->arch->object::name_pl;
1555 root 1.4 }
1556 elmex 1.1 }
1557    
1558 root 1.4 /* If the object is on a map, make sure we update its face */
1559     if (op->map)
1560 root 1.24 update_object (op, UP_OBJ_CHANGE);
1561 root 1.50
1562     if (object *pl = op->visible_to ())
1563 root 1.48 /* A lot of the values can change from an update - might as well send
1564     * it all.
1565     */
1566     esrv_send_item (pl, op);
1567 elmex 1.1 }
1568 root 1.9