--- deliantra/server/common/item.C 2007/07/10 05:51:37 1.39 +++ deliantra/server/common/item.C 2009/09/16 22:50:50 1.55 @@ -1,11 +1,11 @@ /* - * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. + * This file is part of Deliantra, the Roguelike Realtime MMORPG. * - * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team + * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team * Copyright (©) 1992,2007 Frank Tore Johansen * - * Crossfire TRT is free software: you can redistribute it and/or modify + * 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. @@ -18,14 +18,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * The authors can be reached via e-mail to + * The authors can be reached via e-mail to */ #include -#include #include #include +const char *const coins[NUM_COINS + 1] = { "royalty", "platinacoin", "goldcoin", "silvercoin", 0 }; + /* the ordering of this is actually doesn't make a difference * However, for ease of use, new entries should go at the end * so those people that debug the code that get used to something @@ -253,10 +254,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 @@ -300,9 +298,11 @@ for (i = 1; i < NROFATTACKS; i++) if (op->attacktype & (1 << i)) enc++; + if (op->slaying) enc += 2; /* What it slays is probably more relevent */ } + /* Items the player can equip */ if ((op->type == WEAPON) || (op->type == ARMOUR) || (op->type == HELMET) || (op->type == SHIELD) || (op->type == RING) || @@ -315,6 +315,7 @@ enc += op->stats.grace; /* grace regen */ enc += op->stats.exp; /* speed bonus */ } + enc += op->stats.luck; /* Do spell paths now */ @@ -328,20 +329,13 @@ 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->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); } @@ -351,11 +345,10 @@ 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]; + return NULL; } @@ -365,19 +358,19 @@ 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, - "get_typedata_by_name: I have been sent the plural %s, the singular form %s is preffered\n", name, item_types[i].name); + "get_typedata_by_name: I have been sent the plural %s, the singular form %s is prefered\n", name, item_types[i].name); return &item_types[i]; } - return NULL; + + return 0; } /* describe_resistance generates the visible naming for resistances. @@ -406,6 +399,7 @@ strcat (buf, buf1); } } + return buf; } @@ -414,12 +408,14 @@ * 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) { static char buf[10]; - sint32 i = (op->nrof ? op->nrof : 1) * op->weight + op->carrying; + sint32 i = op->total_weight (); if (op->weight < 0) return " "; @@ -449,6 +445,7 @@ if (i < 21) return levelnumbers[i]; + if (!(i % 10)) return levelnumbers_10[i / 10]; @@ -534,18 +531,24 @@ /* * 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) { - static dynbuf_text buf; buf.clear (); - - if (op->name == NULL) + if (!op->name) return "(null)"; - if (!op->nrof && !op->weight && !op->title && !is_magical (op)) + if (!op->nrof + && !op->weight + && !op->title + && !is_magical (op) + && op->slaying != shstr_money) return op->name; /* To speed things up (or make things slower?) */ + static dynbuf_text buf; buf.clear (); + buf << (op->nrof <= 1 ? op->name : op->name_pl); if (op->title && QUERY_FLAG (op, FLAG_IDENTIFIED)) @@ -567,6 +570,31 @@ } break; + case ALTAR: + case TRIGGER_ALTAR: + case IDENTIFY_ALTAR: + case CONVERTER: + if (op->slaying == shstr_money) + { + bool wrap = !!buf.size (); + + if (wrap) buf << " ["; + + archetype *coin = 0; + + 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; + + buf.printf ("drop %d %s (or equivalent)", coins, coins == 1 ? &coin->name : &coin->name_pl); + + if (wrap) buf << ']'; + } + break; + case SKILL: case AMULET: case RING: @@ -579,6 +607,7 @@ buf << " " << s; } break; + default: if (op->magic && ((QUERY_FLAG (op, FLAG_BEEN_APPLIED) && need_identify (op)) || QUERY_FLAG (op, FLAG_IDENTIFIED))) buf.printf (" %+d", op->magic); @@ -597,6 +626,8 @@ * 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. */ const char * query_name (const object *op) @@ -643,7 +674,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) @@ -685,6 +716,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)"; @@ -699,6 +749,9 @@ * 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. */ const char * query_base_name (const object *op, int plural) @@ -778,7 +831,7 @@ switch ((int) ((FABS (op->speed)) * 15)) { case 0: - buf << "(very slow movement"; + buf << "(very slow movement)"; break; case 1: buf << "(slow movement)"; @@ -903,11 +956,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) @@ -977,6 +1025,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: @@ -1161,6 +1231,38 @@ return std::string (::describe_item (this, who)); } +void +examine (object *op, object *tmp) +{ + std::string info = tmp->describe (op); + + op->contr->infobox (MSG_CHANNEL ("examine"), info.c_str ()); +} + +/* + * inventory prints object's inventory. If inv==NULL then print player's + * inventory. + * [ Only items which are applied are showed. Tero.Haatanen@lut.fi ] + */ +const char * +object::query_inventory (object *who, const char *indent) +{ + static dynbuf_text buf; buf.clear (); + + for (object *tmp = inv; tmp; tmp = tmp->below) + if (who && QUERY_FLAG (who, FLAG_WIZ)) + buf.printf ("%s- %-28.28s (%5d) %-8s\n", indent, tmp->query_name (), tmp->count, tmp->query_weight ()); + else if (!tmp->invisible && (type == CONTAINER || QUERY_FLAG (tmp, FLAG_APPLIED))) + 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 ()); + else + buf.printf ("%s(empty)\n", indent); + + return buf; +} + /* Return true if the item is magical. A magical item is one that * increases/decreases any abilities, provides a resistance, * has a generic magical bonus, or is an artifact. @@ -1296,8 +1398,6 @@ void identify (object *op) { - object *pl; - SET_FLAG (op, FLAG_IDENTIFIED); CLEAR_FLAG (op, FLAG_KNOWN_MAGICAL); CLEAR_FLAG (op, FLAG_NO_SKILL_IDENT); @@ -1314,7 +1414,7 @@ op->title = op->inv->name; else if (op->arch) { - op->name = op->arch->object::name; + op->name = op->arch->object::name; op->name_pl = op->arch->object::name_pl; } } @@ -1322,14 +1422,11 @@ /* If the object is on a map, make sure we update its face */ if (op->map) update_object (op, UP_OBJ_CHANGE); - else - { - pl = op->in_player (); - if (pl) - /* A lot of the values can change from an update - might as well send - * it all. - */ - esrv_send_item (pl, op); - } + + if (object *pl = op->visible_to ()) + /* A lot of the values can change from an update - might as well send + * it all. + */ + esrv_send_item (pl, op); }