--- deliantra/server/common/item.C 2008/09/07 21:31:23 1.51 +++ deliantra/server/common/item.C 2010/03/26 14:00:28 1.75 @@ -1,22 +1,23 @@ /* * This file is part of Deliantra, the Roguelike Realtime MMORPG. * - * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team - * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team - * Copyright (©) 1992,2007 Frank Tore Johansen + * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team + * Copyright (©) 2002 Mark Wedel & Crossfire Development Team + * Copyright (©) 1992 Frank Tore Johansen * - * Deliantra is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Deliantra is free software: you can redistribute it and/or modify it under + * the terms of the Affero GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the Affero GNU General Public License + * and the GNU General Public License along with this program. If not, see + * . * * The authors can be reached via e-mail to */ @@ -66,12 +67,6 @@ /*{"body_dragon_torso", "your body", "a dragon's body"} */ }; -static char numbers[21][20] = { - "no", "", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", - "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", - "eighteen", "nineteen", "twenty" -}; - static char numbers_10[10][20] = { "zero", "ten", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" @@ -171,7 +166,7 @@ {SPINNER, "spinner", "spinners", 0, 0}, {GATE, "gate", "gates", 0, 0}, {BUTTON, "button", "buttons", 0, 0}, - {CF_HANDLE, "cf handle", "cf handles", 0, 0}, + {T_HANDLE, "cf handle", "cf handles", 0, 0}, {HOLE, "hole", "holes", 0, 0}, {TRAPDOOR, "trapdoor", "trapdoors", 0, 0}, {SIGN, "sign", "signs", 0, 0}, @@ -208,32 +203,7 @@ {ITEM_TRANSFORMER, "item_transformer", "item_transformers", 0, 0}, }; -const int item_types_size = sizeof (item_types) / sizeof (*item_types); - -materialtype_t *materialt; - -/* -materialtype material[NROFMATERIALS] = { - * P M F E C C A D W G P S P T F C D D C C G H B I * - * H A I L O O C R E H O L A U E A E E H O O O L N * - * Y G R E L N I A A O I O R R A N P A A U D L I T * - * S I E C D F D I P S S W A N R C L T O N Y N R * - * I C T U N O T O L E E H S T P D N * - {"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}}, - {"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}}, - {"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}}, - {"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}}, - {"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}}, - {"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}}, - {"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}}, - {"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}}, - {"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}}, - {"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}}, - {"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}}, - {"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}}, - {"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}} -}; -*/ +static const int item_types_size = sizeof (item_types) / sizeof (*item_types); /* This curve may be too steep. But the point is that there should * be tough choices - there is no real point to this if everyone can @@ -254,10 +224,7 @@ int get_power_from_ench (int ench) { - if (ench < 0) ench = 0; - if (ench > 20) ench = 20; - - return enc_to_item_power[ench]; + return enc_to_item_power [clamp (ench, 0, 20)]; } /* This takes an object 'op' and figures out what its item_power @@ -323,29 +290,20 @@ /* Do spell paths now */ for (i = 1; i < NRSPELLPATHS; i++) - { - if (op->path_attuned & (1 << i)) - enc++; - else if (op->path_denied & (1 << i)) - enc -= 2; - else if (op->path_repelled & (1 << i)) - enc--; - } - - if (QUERY_FLAG (op, FLAG_LIFESAVE)) - enc += 5; - if (QUERY_FLAG (op, FLAG_REFL_SPELL)) - enc += 3; - if (QUERY_FLAG (op, FLAG_REFL_MISSILE)) - enc += 2; - if (QUERY_FLAG (op, FLAG_STEALTH)) - enc += 1; - if (QUERY_FLAG (op, FLAG_XRAYS)) - enc += 2; - if (QUERY_FLAG (op, FLAG_SEE_IN_DARK)) - enc += 1; - if (QUERY_FLAG (op, FLAG_MAKE_INVIS)) - enc += 1; + if (op->path_attuned & (1 << i)) + enc++; + else if (op->path_denied & (1 << i)) + enc -= 2; + else if (op->path_repelled & (1 << i)) + enc--; + + if (op->flag [FLAG_LIFESAVE ]) enc += 5; + if (op->flag [FLAG_REFL_SPELL ]) enc += 3; + if (op->flag [FLAG_REFL_MISSILE]) enc += 2; + if (op->flag [FLAG_XRAYS ]) enc += 2; + if (op->flag [FLAG_STEALTH ]) enc += 1; + if (op->flag [FLAG_SEE_IN_DARK ]) enc += 1; + if (op->flag [FLAG_MAKE_INVIS ]) enc += 1; return get_power_from_ench (enc); } @@ -355,9 +313,7 @@ const typedata * get_typedata (int itemtype) { - int i; - - for (i = 0; i < item_types_size; i++) + for (int i = 0; i < item_types_size; i++) if (item_types[i].number == itemtype) return &item_types[i]; @@ -370,13 +326,11 @@ const typedata * get_typedata_by_name (const char *name) { - int i; - - for (i = 0; i < item_types_size; i++) + for (int i = 0; i < item_types_size; i++) if (!strcmp (item_types[i].name, name)) return &item_types[i]; - for (i = 0; i < item_types_size; i++) + for (int i = 0; i < item_types_size; i++) if (!strcmp (item_types[i].name_pl, name)) { LOG (llevInfo, @@ -384,7 +338,7 @@ return &item_types[i]; } - return NULL; + return 0; } /* describe_resistance generates the visible naming for resistances. @@ -396,31 +350,21 @@ const char * describe_resistance (const object *op, int newline) { - static char buf[VERY_BIG_BUF]; - char buf1[VERY_BIG_BUF]; - int tmpvar; + static dynbuf_text buf; buf.clear (); - buf[0] = 0; - for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++) - { - if (op->resist[tmpvar] && (op->type != FLESH || atnr_is_dragon_enabled (tmpvar) == 1)) - { - if (!newline) - sprintf (buf1, "(%s %+d)", resist_plus[tmpvar], op->resist[tmpvar]); - else - sprintf (buf1, "%s %d\n", resist_plus[tmpvar], op->resist[tmpvar]); + for (int i = 0; i < NROFATTACKS; i++) + if (op->resist[i] && (op->type != FLESH || atnr_is_dragon_enabled (i) == 1)) + buf.printf (newline ? "%s %d\n" : "(%s %+d)", resist_plus[i], op->resist[i]); - strcat (buf, buf1); - } - } return buf; } - /* * query_weight(object) returns a character pointer to a static buffer * containing the text-representation of the weight of the given object. * The buffer will be overwritten by the next call to query_weight(). + * + * Seems to be used only by unimportant stuff. Remove? */ const char * query_weight (const object *op) @@ -456,6 +400,7 @@ if (i < 21) return levelnumbers[i]; + if (!(i % 10)) return levelnumbers_10[i / 10]; @@ -465,26 +410,6 @@ } /* - * get_number(integer) returns the text-representation of the given number - * in a static buffer. The buffer might be overwritten at the next - * call to get_number(). - * It is currently only used by the query_name() function. - */ -const char * -get_number (int i) -{ - if (i <= 20) - return numbers[i]; - else - { - static char buf[MAX_BUF]; - - sprintf (buf, "%d", i); - return buf; - } -} - -/* * Returns pointer to static buffer containing ring's or amulet's * abilities * These are taken from old query_name(), but it would work better @@ -497,7 +422,7 @@ /* Aug 95 modified this slightly so that Skill tools don't have magic bonus * from stats.sp - b.t. */ -const char * +static const char * ring_desc (const object *op) { static dynbuf_text buf; buf.clear (); @@ -541,11 +466,13 @@ /* * query_short_name(object) is similar to query_name, but doesn't * contain any information about object status (worn/cursed/etc.) + * + * It is sometimes used when printing messages, so should fit well into a sentence. */ const char * query_short_name (const object *op) { - if (op->name == 0) + if (!op->name) return "(null)"; if (!op->nrof @@ -578,30 +505,30 @@ } break; - case ALTAR: - case TRIGGER_ALTAR: - case IDENTIFY_ALTAR: - case CONVERTER: - if (op->slaying == shstr_money) - { - bool wrap = !!buf.size (); + case ALTAR: + case TRIGGER_ALTAR: + case IDENTIFY_ALTAR: + case CONVERTER: + if (op->slaying == shstr_money) + { + bool wrap = !!buf.size (); - if (wrap) buf << " ["; + if (wrap) buf << " ["; - archetype *coin = 0; + archetype *coin = 0; - for (char const *const *c = coins; *coins; ++c) - if ((coin = archetype::find (*c))) - if (op->stats.food % coin->value == 0) - break; + for (char const *const *c = coins; *coins; ++c) + if ((coin = archetype::find (*c))) + if (op->stats.food % coin->value == 0) + break; - sint32 coins = op->stats.food / coin->value; + sint32 coins = op->stats.food / coin->value; - buf.printf ("drop %d %s (or equivalent)", coins, coins == 1 ? &coin->name : &coin->name_pl); + buf.printf ("drop %d %s (or equivalent)", coins, coins == 1 ? &coin->name : &coin->name_pl); - if (wrap) buf << ']'; - } - break; + if (wrap) buf << ']'; + } + break; case SKILL: case AMULET: @@ -634,6 +561,9 @@ * returned is good forever.) However, it makes printing statements that * use several names much easier (don't need to store them to temp variables.) * + * It is used extensively within messages, so should return only a prose + * and short description of the item. + * It is also used by examine/ex and similar functions. */ const char * query_name (const object *op) @@ -648,15 +578,16 @@ dynbuf_text &buf = bufs [use_buf]; buf.clear (); - if ((op->is_armor () || op->is_weapon ()) && op->materialname) - if (materialtype_t *mt = name_to_material (op->materialname)) - buf << mt->description << ' '; +#if 0 + if ((op->is_armor () || op->is_weapon ()) && op->material) + buf << op->material->description << ' '; +#endif buf << query_short_name (op); if (QUERY_FLAG (op, FLAG_INV_LOCKED)) buf << " *"; - if (op->type == CONTAINER && ((op->env && op->env->container == op) || (!op->env && QUERY_FLAG (op, FLAG_APPLIED)))) + if (op->is_open_container ()) buf << " (open)"; if (QUERY_FLAG (op, FLAG_KNOWN_CURSED)) @@ -680,7 +611,7 @@ buf << " (magic)"; #if 0 - /* item_power will be returned in desribe_item - it shouldn't really + /* item_power will be returned in describe_item - it shouldn't really * be returned in the name. */ if (op->item_power) @@ -722,6 +653,25 @@ } } + switch (op->type) + { + case LAMP: + if (op->glow_radius) + buf << " (on)"; + else if (op->stats.food <= 0) + buf << " (empty)"; + else + buf << " (off)"; + break; + + case TORCH: + if (op->glow_radius) + buf << " (burning)"; + else if (op->stats.food <= 0) + buf << " (burned out)"; + break; + } + if (QUERY_FLAG (op, FLAG_UNPAID)) buf << " (unpaid)"; @@ -736,6 +686,10 @@ * don't include the item count or item status. Used for inventory sorting * and sending to client. * If plural is set, we generate the plural name of this. + * + * It is sometimes used to display messages, and usually only used to match stuff, + * so maybe this function should be removed. + * It is also used for client-side inventory/item descriptions. */ const char * query_base_name (const object *op, int plural) @@ -743,15 +697,17 @@ if ((!plural && !op->name) || (plural && !op->name_pl)) return "(null)"; - if (!op->nrof && !op->weight && !op->title && !is_magical (op)) + if (!op->nrof && !op->weight && !op->title && !is_magical (op) + && op->type != EXIT) return op->name; /* To speed things up (or make things slower?) */ static dynbuf_text buf; buf.clear (); - if ((op->is_armor () || op->is_weapon ()) && op->materialname) - if (materialtype_t *mt = name_to_material (op->materialname)) - if (op->arch->materialname != mt->name) - buf << mt->description << ' '; +#if 0 + if ((op->is_armor () || op->is_weapon ()) && op->material) + if (op->arch->material != op->material) + buf << op->material->description << ' '; +#endif buf << (plural ? op->name_pl : op->name); @@ -788,6 +744,12 @@ } break; + case EXIT: + // random map exits "unfortunately" get patched, so this only works before entering + if (EXIT_PATH (op)) + buf << (EXIT_PATH (op) == shstr_random_map_exit ? " (random map)" : " (entry)"); + break; + default: if (op->magic && ((QUERY_FLAG (op, FLAG_BEEN_APPLIED) && need_identify (op)) || QUERY_FLAG (op, FLAG_IDENTIFIED))) buf.printf (" %+d", op->magic); @@ -812,7 +774,7 @@ * fall into the 'lightning fast movement' category. */ if (op->has_active_speed ()) - switch ((int) ((FABS (op->speed)) * 15)) + switch ((int)(op->speed * 15.)) { case 0: buf << "(very slow movement)"; @@ -892,7 +854,7 @@ } /* describe attacktypes */ - if (is_dragon_pl (op)) + if (op->is_dragon ()) { /* for dragon players display the attacktypes from clawing skill * Break apart the for loop - move the comparison checking down - @@ -940,11 +902,6 @@ * a dwarven axe, in which the full abilities are only known to * dwarves, etc. * - * This function is really much more complicated than it should - * be, because different objects have different meanings - * for the same field (eg, wands use 'food' for charges). This - * means these special cases need to be worked out. - * * Add 'owner' who is the person examining this object. * owner can be null if no one is being associated with this * item (eg, debug dump or the like) @@ -1014,6 +971,28 @@ buf << "almost full."; break; + case LAMP: + { + int percent = ((double) 100 / op->arch->stats.food) * op->stats.food; + buf << "(fuel: "; + if (percent == 0) + buf << "empty"; + else if (percent < 10) + buf << "very low"; + else if (percent < 25) + buf << "low"; + else if (percent < 50) + buf << "half empty"; + else if (percent < 75) + buf << "half full"; + else if (percent < 95) + buf << "well filled"; + else if (percent <= 100) + buf << "full"; + buf << ")"; + } + break; + case FOOD: case FLESH: case DRINK: @@ -1177,11 +1156,14 @@ if (op->slaying && op->type != FOOD) buf.printf ("(slay %s)", &op->slaying); + if (op->type == SKILL_TOOL && op->skill) + buf.printf ("(%s)", &op->skill); + buf.add_abilities ("Attacks", op->attacktype); /* resistance on flesh is only visible for quetzals. If * non flesh, everyone can see its resistances */ - if (op->type != FLESH || (owner && is_dragon_pl (owner))) + if (op->type != FLESH || (owner && owner->is_dragon ())) buf << describe_resistance (op, 0); buf.add_paths ("Attuned", op->path_attuned); @@ -1202,6 +1184,7 @@ examine (object *op, object *tmp) { std::string info = tmp->describe (op); + op->contr->infobox (MSG_CHANNEL ("examine"), info.c_str ()); } @@ -1217,12 +1200,12 @@ for (object *tmp = inv; tmp; tmp = tmp->below) if (who && QUERY_FLAG (who, FLAG_WIZ)) - buf.printf ("%s- %-28.28s (%5d) %-8s\n", indent, query_name (tmp), tmp->count, query_weight (tmp)); + buf.printf ("%s- %-28.28s %-8s (%9d) %s\n", indent, tmp->query_name (), tmp->query_weight (), tmp->count, tmp->uuid.c_str ()); else if (!tmp->invisible && (type == CONTAINER || QUERY_FLAG (tmp, FLAG_APPLIED))) - buf.printf ("%s- %-36.36s %-8s\n", indent, query_name (tmp), query_weight (tmp)); + buf.printf ("%s- %-36.36s %-8s\n", indent, tmp->query_name (), tmp->query_weight ()); if (buf.size ()) - buf.printf ("%s(total weight: %s)\n", indent, query_weight (this)); + buf.printf ("%s(total weight: %s)\n", indent, query_weight ()); else buf.printf ("%s(empty)\n", indent);