ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/item.C
Revision: 1.17
Committed: Wed Jan 3 02:30:51 2007 UTC (17 years, 4 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.16: +1 -1 lines
Log Message:
implemented proper support for empty treasures, which
sadly occur in empty treasure lists. fixing treasurelists
to have no entries at all would be even more complicated,
but even when this is fixed, the current changes only make the
server more crash robust to bad treasures.
Also removed the 'NONE' specialcase for treasure lists. Developers
should use 'none' instead now.

File Contents

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