--- deliantra/server/common/item.C 2007/11/08 19:43:23 1.41 +++ deliantra/server/common/item.C 2009/11/06 13:03:34 1.63 @@ -1,31 +1,33 @@ /* * This file is part of Deliantra, the Roguelike Realtime MMORPG. * - * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Deliantra 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 * - * 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 */ #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 @@ -170,7 +172,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}, @@ -207,7 +209,7 @@ {ITEM_TRANSFORMER, "item_transformer", "item_transformers", 0, 0}, }; -const int item_types_size = sizeof (item_types) / sizeof (*item_types); +static const int item_types_size = sizeof (item_types) / sizeof (*item_types); materialtype_t *materialt; @@ -253,10 +255,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 +299,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 +316,7 @@ enc += op->stats.grace; /* grace regen */ enc += op->stats.exp; /* speed bonus */ } + enc += op->stats.luck; /* Do spell paths now */ @@ -328,20 +330,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 +346,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 +359,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. @@ -389,37 +383,27 @@ 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) { 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 +433,7 @@ if (i < 21) return levelnumbers[i]; + if (!(i % 10)) return levelnumbers_10[i / 10]; @@ -463,7 +448,7 @@ * call to get_number(). * It is currently only used by the query_name() function. */ -const char * +static const char * get_number (int i) { if (i <= 20) @@ -490,7 +475,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 (); @@ -534,18 +519,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 +558,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 +595,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 +614,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) @@ -619,7 +638,7 @@ 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)) @@ -643,7 +662,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 +704,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 +737,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 +819,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 +944,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 +1013,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: @@ -1140,6 +1198,9 @@ 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 @@ -1164,9 +1225,9 @@ void examine (object *op, object *tmp) { - std::string s = tmp->describe (op); + std::string info = tmp->describe (op); - new_draw_info (NDI_UNIQUE, 0, op, s.c_str ()); + op->contr->infobox (MSG_CHANNEL ("examine"), info.c_str ()); } /* @@ -1181,12 +1242,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 (%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, 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); @@ -1328,8 +1389,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); @@ -1346,7 +1405,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; } } @@ -1354,14 +1413,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); }