--- deliantra/server/common/item.C 2006/09/10 16:00:23 1.4 +++ deliantra/server/common/item.C 2007/05/27 23:56:21 1.35 @@ -1,32 +1,27 @@ - /* - * static char *rcsid_item_c = - * "$Id: item.C,v 1.4 2006/09/10 16:00:23 root Exp $"; + * CrossFire, A Multiplayer game + * + * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team + * Copyright (C) 2002 Mark Wedel & Crossfire Development Team + * Copyright (C) 1992 Frank Tore Johansen + * + * This program 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * The authors can be reached via e-mail at */ -/* - CrossFire, A Multiplayer game for X-windows - - Copyright (C) 2002 Mark Wedel & Crossfire Development Team - Copyright (C) 1992 Frank Tore Johansen - - This program 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - The authors can be reached via e-mail at crossfire-devel@real-time.com -*/ - #include #include #include @@ -54,31 +49,20 @@ * "This item goes %s\n", with the use/nonuse values filling in the %s */ Body_Locations body_locations[NUM_BODY_LOCATIONS] = { - {"body_range", "in your range slot", "in a human's range slot"} - , - {"body_arm", "on your arm", "on a human's arm"} - , - {"body_torso", "on your body", "on a human's torso"} - , - {"body_head", "on your head", "on a human's head"} - , - {"body_neck", "around your neck", "around a humans neck"} - , - {"body_skill", "in your skill slot", "in a human's skill slot"} - , - {"body_finger", "on your finger", "on a human's finger"} - , - {"body_shoulder", "around your shoulders", "around a human's shoulders"} - , - {"body_foot", "on your feet", "on a human's feet"} - , - {"body_hand", "on your hands", "on a human's hands"} - , - {"body_wrist", "around your wrists", "around a human's wrist"} - , - {"body_waist", "around your waist", "around a human's waist"} - , - + {KW_body_skill , "You can use it as your skill" , "It is used as a skill"}, + {KW_body_combat , "You can wield it as your weapon" , "It is used as a combat weapon"}, + {KW_body_range , "You can use it as your range weapon" , "It is used as a range weapon"}, + {KW_body_shield , "You can wield it as a shield" , "It is used as a shield"}, + {KW_body_arm , "You can put it on your arm" , "It goes on a human's arm"}, + {KW_body_torso , "You can wear it on your body" , "It goes on a human's torso"}, + {KW_body_head , "You can wear it on your head" , "It goes on a human's head"}, + {KW_body_neck , "You can wear it around your neck" , "It goes around a human's neck"}, + {KW_body_finger , "You can wear it on your finger" , "It goes on a human's finger"} , + {KW_body_shoulder, "You can wear it around your shoulders", "It goes around a human's shoulders"}, + {KW_body_foot , "You can put it on your foot" , "It goes on a human's foot"}, + {KW_body_hand , "You can put it on your hand" , "It goes on a human's hand"}, + {KW_body_wrist , "You can wear it around your wrist" , "It goes around a human's wrist"}, + {KW_body_waist , "You can wear it around your waist" , "It goes around a human's waist"}, /*{"body_dragon_torso", "your body", "a dragon's body"} */ }; @@ -120,7 +104,6 @@ {POISON, "poison", "poisons", SK_ALCHEMY, 0}, {BOOK, "book", "books", SK_LITERACY, 0}, {CLOCK, "clock", "clocks", 0, 0}, - {LIGHTNING, "lightning", "lightning", 0, 0}, {ARROW, "arrow", "arrows", SK_BOWYER, 0}, {BOW, "bow", "bows", SK_BOWYER, 0}, {WEAPON, "weapon", "weapons", SK_SMITHERY, 0}, @@ -150,7 +133,6 @@ {TELEPORTER, "teleporter", "teleporters", 0, 0}, {CREATOR, "creator", "creators", 0, 0}, {SKILL, "skill", "skills", 0, 0}, - {EXPERIENCE, "experience", "experience", 0, 0}, {EARTHWALL, "earthwall", "earthwalls", 0, 0}, {GOLEM, "golem", "golems", 0, 0}, {THROWN_OBJ, "projectile", "projectiles", 0, 0}, @@ -180,17 +162,11 @@ {INORGANIC, "inorganic", "inorganics", SK_ALCHEMY, 0}, {SKILL_TOOL, "skill tool", "skill tools", 0, 0}, {LIGHTER, "lighter", "lighters", 0, 0}, - {TRAP_PART, "trap part", "trap parts", 0, 0}, - {WALL, "wall", "walls", 0, 0}, - {LIGHT_SOURCE, "light source", "light sources", 0, 0}, + {BUILDABLE_WALL, "buildable wall", "buildable walls", 0, 0}, {MISC_OBJECT, "bric-a-brac", "bric-a-brac", 0, 0}, - {MONSTER, "monster", "monsters", 0, 0}, - {SPAWN_GENERATOR, "monster generator", "monster generators", 0, 0}, {LAMP, "lamp", "lamps", 0, 0}, {DUPLICATOR, "duplicator", "duplicators", 0, 0}, - {TOOL, "tool", "tools", 0, 0}, {SPELLBOOK, "spellbook", "spellbooks", SK_LITERACY, 0}, - {BUILDFAC, "building facility", "building facilities", 0, 0}, {CLOAK, "cloak", "cloaks", SK_SMITHERY, 0}, {SPINNER, "spinner", "spinners", 0, 0}, {GATE, "gate", "gates", 0, 0}, @@ -207,8 +183,6 @@ {BRACERS, "bracers", "bracers", SK_SMITHERY, 0}, {POISONING, "poisoning", "poisonings", 0, 0}, {SAVEBED, "savebed", "savebeds", 0, 0}, - {POISONCLOUD, "poison cloud", "poison clouds", 0, 0}, - {FIREHOLES, "fireholes", "fireholes", 0, 0}, {WAND, "wand", "wands", SK_THAUMATURGY, 0}, {SCROLL, "scroll", "scrolls", SK_LITERACY, 0}, {DIRECTOR, "director", "directors", 0, 0}, @@ -280,10 +254,9 @@ int get_power_from_ench (int ench) { - if (ench < 0) - ench = 0; - if (ench > 20) - ench = 20; + if (ench < 0) ench = 0; + if (ench > 20) ench = 20; + return enc_to_item_power[ench]; } @@ -301,7 +274,7 @@ enc = 0; for (i = 0; i < NUM_STATS; i++) - enc += get_attr_value (&op->stats, i); + enc += op->stats.stat (i); /* This protection logic is pretty flawed. 20% fire resistance * is much more valuable than 20% confusion, or 20% slow, or @@ -372,12 +345,10 @@ enc += 1; return get_power_from_ench (enc); - } /* returns the typedata that has a number equal to itemtype, if there * isn't one, returns NULL */ - const typedata * get_typedata (int itemtype) { @@ -392,7 +363,6 @@ /* returns the typedata that has a name equal to itemtype, if there * isn't one, return the plural name that matches, if there still isn't * one return NULL */ - const typedata * get_typedata_by_name (const char *name) { @@ -417,7 +387,7 @@ * if newline is true, we don't put parens around the description * but do put a newline at the end. Useful when dumping to files */ -char * +const char * describe_resistance (const object *op, int newline) { static char buf[VERY_BIG_BUF]; @@ -446,8 +416,7 @@ * containing the text-representation of the weight of the given object. * The buffer will be overwritten by the next call to query_weight(). */ - -char * +const char * query_weight (const object *op) { static char buf[10]; @@ -455,10 +424,12 @@ if (op->weight < 0) return " "; + if (i % 1000) sprintf (buf, "%6.1f", i / 1000.0); else sprintf (buf, "%4d ", i / 1000); + return buf; } @@ -466,8 +437,7 @@ * Returns the pointer to a static buffer containing * the number requested (of the form first, second, third...) */ - -char * +const char * get_levelnumber (int i) { static char buf[MAX_BUF]; @@ -477,24 +447,24 @@ sprintf (buf, "%d.", i); return buf; } + if (i < 21) return levelnumbers[i]; if (!(i % 10)) return levelnumbers_10[i / 10]; + strcpy (buf, numbers_10[i / 10]); strcat (buf, levelnumbers[i % 10]); return buf; } - /* * 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. */ - -char * +const char * get_number (int i) { if (i <= 20) @@ -521,7 +491,7 @@ /* Aug 95 modified this slightly so that Skill tools don't have magic bonus * from stats.sp - b.t. */ -char * +const char * ring_desc (const object *op) { static char buf[VERY_BIG_BUF]; @@ -534,11 +504,10 @@ for (attr = 0; attr < NUM_STATS; attr++) { - if ((val = get_attr_value (&(op->stats), attr)) != 0) - { - sprintf (buf + strlen (buf), "(%s%+d)", short_stat_name[attr], val); - } + if ((val = op->stats.stat (attr))) + sprintf (buf + strlen (buf), "(%s%+d)", short_stat_name[attr], val); } + if (op->stats.exp) sprintf (buf + strlen (buf), "(speed %+lld)", (long long) op->stats.exp); if (op->stats.wc) @@ -570,6 +539,7 @@ strcat (buf, "(reflect missiles)"); if (QUERY_FLAG (op, FLAG_STEALTH)) strcat (buf, "(stealth)"); + /* Shorten some of the names, so they appear better in the windows */ len = strlen (buf); DESCRIBE_PATH_SAFE (buf, op->path_attuned, "Attuned", &len, VERY_BIG_BUF); @@ -599,6 +569,7 @@ if (op->name == NULL) return "(null)"; + if (!op->nrof && !op->weight && !op->title && !is_magical (op)) return op->name; /* To speed things up (or make things slower?) */ @@ -643,7 +614,7 @@ if (!op->title) { /* If ring has a title, full description isn't so useful */ - char *s = ring_desc (op); + const char *s = ring_desc (op); if (s[0]) { @@ -673,10 +644,10 @@ * use several names much easier (don't need to store them to temp variables.) * */ -char * +const char * query_name (const object *op) { - static char buf[5][HUGE_BUF]; + static char buf[5][HUGE_BUF]; // OMFG static int use_buf = 0; int len = 0; @@ -688,7 +659,7 @@ use_buf %= 5; #ifdef NEW_MATERIAL_CODE - if ((IS_ARMOR (op) || IS_WEAPON (op)) && op->materialname) + if ((op->is_armor () || op->is_weapon ()) && op->materialname) { mt = name_to_material (op->materialname); if (mt) @@ -713,6 +684,7 @@ else if (QUERY_FLAG (op, FLAG_CURSED)) safe_strcat (buf[use_buf], " (cursed)", &len, HUGE_BUF); } + /* Basically, if the object is known magical (detect magic spell on it), * and it isn't identified, print out the fact that * it is magical. Assume that the detect magical spell will only set @@ -738,39 +710,40 @@ { switch (op->type) { - case BOW: - case WAND: - case ROD: - case HORN: - safe_strcat (buf[use_buf], " (readied)", &len, HUGE_BUF); - break; - case WEAPON: - safe_strcat (buf[use_buf], " (wielded)", &len, HUGE_BUF); - break; - case ARMOUR: - case HELMET: - case SHIELD: - case RING: - case BOOTS: - case GLOVES: - case AMULET: - case GIRDLE: - case BRACERS: - case CLOAK: - safe_strcat (buf[use_buf], " (worn)", &len, HUGE_BUF); - break; - case CONTAINER: - safe_strcat (buf[use_buf], " (active)", &len, HUGE_BUF); - break; - case SKILL: - default: - safe_strcat (buf[use_buf], " (applied)", &len, HUGE_BUF); + case BOW: + case WAND: + case ROD: + case HORN: + safe_strcat (buf[use_buf], op->env && op->env->current_weapon == op ? " (readied)" : " (applied)", &len, HUGE_BUF); + break; + case WEAPON: + safe_strcat (buf[use_buf], op->env && op->env->current_weapon == op ? " (wielded)" : " (applied)", &len, HUGE_BUF); + break; + case ARMOUR: + case HELMET: + case SHIELD: + case RING: + case BOOTS: + case GLOVES: + case AMULET: + case GIRDLE: + case BRACERS: + case CLOAK: + safe_strcat (buf[use_buf], " (worn)", &len, HUGE_BUF); + break; + case CONTAINER: + safe_strcat (buf[use_buf], " (active)", &len, HUGE_BUF); + break; + case SKILL: + default: + safe_strcat (buf[use_buf], " (applied)", &len, HUGE_BUF); } } + if (QUERY_FLAG (op, FLAG_UNPAID)) safe_strcat (buf[use_buf], " (unpaid)", &len, HUGE_BUF); - return buf[use_buf]; + return buf [use_buf]; } /* @@ -795,11 +768,11 @@ if (!op->nrof && !op->weight && !op->title && !is_magical (op)) return op->name; /* To speed things up (or make things slower?) */ - if ((IS_ARMOR (op) || IS_WEAPON (op)) && op->materialname) + if ((op->is_armor () || op->is_weapon ()) && op->materialname) mt = name_to_material (op->materialname); #ifdef NEW_MATERIAL_CODE - if ((IS_ARMOR (op) || IS_WEAPON (op)) && op->materialname && mt && + if ((op->is_armor () || op->is_weapon ()) && op->materialname && mt && op->arch->clone.materialname != mt->name && !(op->material & M_SPECIAL)) { strcpy (buf, mt->description); @@ -814,9 +787,10 @@ { #endif if (!plural) - strcpy (buf, op->name); + assign (buf, op->name); else - strcpy (buf, op->name_pl); + assign (buf, op->name_pl); + len = strlen (buf); #ifdef NEW_MATERIAL_CODE } @@ -830,50 +804,50 @@ switch (op->type) { - case SPELLBOOK: - case SCROLL: - case WAND: - case ROD: - if (QUERY_FLAG (op, FLAG_IDENTIFIED) || QUERY_FLAG (op, FLAG_BEEN_APPLIED)) - { - if (!op->title) - { - safe_strcat (buf, " of ", &len, MAX_BUF); - if (op->inv) - safe_strcat (buf, op->inv->name, &len, MAX_BUF); - else - LOG (llevError, "Spellbook %s lacks inventory\n", &op->name); - } - if (op->type != SPELLBOOK) - { - sprintf (buf2, " (lvl %d)", op->level); - safe_strcat (buf, buf2, &len, MAX_BUF); - } - } - break; + case SPELLBOOK: + case SCROLL: + case WAND: + case ROD: + if (QUERY_FLAG (op, FLAG_IDENTIFIED) || QUERY_FLAG (op, FLAG_BEEN_APPLIED)) + { + if (!op->title) + { + safe_strcat (buf, " of ", &len, MAX_BUF); + if (op->inv) + safe_strcat (buf, op->inv->name, &len, MAX_BUF); + else + LOG (llevError, "Spellbook %s lacks inventory\n", &op->name); + } + if (op->type != SPELLBOOK) + { + sprintf (buf2, " (lvl %d)", op->level); + safe_strcat (buf, buf2, &len, MAX_BUF); + } + } + break; - case SKILL: - case AMULET: - case RING: - if (!op->title) - { - /* If ring has a title, full description isn't so useful */ - char *s = ring_desc (op); + case SKILL: + case AMULET: + case RING: + if (!op->title) + { + /* If ring has a title, full description isn't so useful */ + const char *s = ring_desc (op); - if (s[0]) - { - safe_strcat (buf, " ", &len, MAX_BUF); - safe_strcat (buf, s, &len, MAX_BUF); - } - } - break; - default: - if (op->magic && ((QUERY_FLAG (op, FLAG_BEEN_APPLIED) && need_identify (op)) || QUERY_FLAG (op, FLAG_IDENTIFIED))) - { - sprintf (buf + strlen (buf), " %+d", op->magic); - } + if (s[0]) + { + safe_strcat (buf, " ", &len, MAX_BUF); + safe_strcat (buf, s, &len, MAX_BUF); + } + } + break; + + default: + if (op->magic && ((QUERY_FLAG (op, FLAG_BEEN_APPLIED) && need_identify (op)) || QUERY_FLAG (op, FLAG_IDENTIFIED))) + sprintf (buf + strlen (buf), " %+d", op->magic); } + return buf; } @@ -883,7 +857,6 @@ * be called with monster & player objects. Returns a description * in a static buffer. */ - static char * describe_monster (const object *op) { @@ -897,7 +870,7 @@ * very good. Any player with a speed greater than .67 will * fall into the 'lightning fast movement' category. */ - if (FABS (op->speed) > MIN_ACTIVE_SPEED) + if (op->has_active_speed ()) { switch ((int) ((FABS (op->speed)) * 15)) { @@ -963,7 +936,7 @@ int first = 1; for (t = op->randomitems->items; t != NULL; t = t->next) - if (t->item && (t->item->clone.type == SPELL)) + if (t->item && t->item->clone.type == SPELL) { if (first) { @@ -1019,29 +992,24 @@ break; if (tmp && tmp->attacktype != 0) - { - DESCRIBE_ABILITY (retbuf, tmp->attacktype, "Claws"); - } + { DESCRIBE_ABILITY (retbuf, tmp->attacktype, "Claws") } else - { - DESCRIBE_ABILITY (retbuf, op->attacktype, "Attacks"); - } + { DESCRIBE_ABILITY (retbuf, op->attacktype, "Attacks") } } else - { - DESCRIBE_ABILITY (retbuf, op->attacktype, "Attacks"); - } + { DESCRIBE_ABILITY (retbuf, op->attacktype, "Attacks") } + DESCRIBE_PATH (retbuf, op->path_attuned, "Attuned"); DESCRIBE_PATH (retbuf, op->path_repelled, "Repelled"); DESCRIBE_PATH (retbuf, op->path_denied, "Denied"); + for (i = 0; i < NROFATTACKS; i++) - { - if (op->resist[i]) - { - sprintf (buf, "(%s %+d)", resist_plus[i], op->resist[i]); - strcat (retbuf, buf); - } - } + if (op->resist[i]) + { + sprintf (buf, "(%s %+d)", resist_plus[i], op->resist[i]); + strcat (retbuf, buf); + } + return retbuf; } @@ -1072,8 +1040,7 @@ * owner can be null if no one is being associated with this * item (eg, debug dump or the like) */ - -char * +const char * describe_item (const object *op, object *owner) { char buf[MAX_BUF]; @@ -1117,14 +1084,16 @@ case POWER_CRYSTAL: if (op->stats.maxsp > 1000) { /*higher capacity crystals */ - i = (op->stats.maxsp % 100) / 10; + i = (op->stats.maxsp % 1000) / 100; + if (i) - snprintf (buf, MAX_BUF, "(capacity %d.%dk). It is ", op->stats.maxsp / 100, i); + snprintf (buf, MAX_BUF, "(capacity %d.%dk). It is ", op->stats.maxsp / 1000, i); else - snprintf (buf, MAX_BUF, "(capacity %dk). It is ", op->stats.maxsp / 100); + snprintf (buf, MAX_BUF, "(capacity %dk). It is ", op->stats.maxsp / 1000); } else snprintf (buf, MAX_BUF, "(capacity %d). It is ", op->stats.maxsp); + strcat (retbuf, buf); i = (op->stats.sp * 10) / op->stats.maxsp; if (op->stats.sp == 0) @@ -1199,7 +1168,7 @@ for (attr = 0; attr < NUM_STATS; attr++) { - if ((val = get_attr_value (&(op->stats), attr)) != 0) + if ((val = op->stats.stat (attr))) { sprintf (buf, "(%s%+d)", short_stat_name[attr], val); strcat (retbuf, buf); @@ -1393,6 +1362,12 @@ return retbuf; } +std::string +object::describe_item (object *who) +{ + return std::string (::describe_item (this, who)); +} + /* 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. @@ -1460,7 +1435,7 @@ /* Check to see if it increases/decreases any stats */ for (i = 0; i < NUM_STATS; i++) - if (get_attr_value (&(op->stats), i) != 0) + if (op->stats.stat (i)) return 1; /* If it doesn't fall into any of the above categories, must @@ -1479,40 +1454,41 @@ { switch (op->type) { - case RING: - case WAND: - case ROD: - case HORN: - case SCROLL: - case SKILL: - case SKILLSCROLL: - case SPELLBOOK: - case FOOD: - case POTION: - case BOW: - case ARROW: - case WEAPON: - case ARMOUR: - case SHIELD: - case HELMET: - case AMULET: - case BOOTS: - case GLOVES: - case BRACERS: - case GIRDLE: - case CONTAINER: - case DRINK: - case FLESH: - case INORGANIC: - case CLOSE_CON: - case CLOAK: - case GEM: - case POWER_CRYSTAL: - case POISON: - case BOOK: - case SKILL_TOOL: - return 1; + case RING: + case WAND: + case ROD: + case HORN: + case SCROLL: + case SKILL: + case SKILLSCROLL: + case SPELLBOOK: + case FOOD: + case POTION: + case BOW: + case ARROW: + case WEAPON: + case ARMOUR: + case SHIELD: + case HELMET: + case AMULET: + case BOOTS: + case GLOVES: + case BRACERS: + case GIRDLE: + case CONTAINER: + case DRINK: + case FLESH: + case INORGANIC: + case CLOSE_CON: + case CLOAK: + case GEM: + case POWER_CRYSTAL: + case POISON: + case BOOK: + case SKILL_TOOL: + return 1; } + /* Try to track down some stuff that may show up here. Thus, the * archetype file can be updated, and this function removed. */ @@ -1522,11 +1498,9 @@ return 0; } - /* * Supposed to fix face-values as well here, but later. */ - void identify (object *op) { @@ -1555,10 +1529,10 @@ /* If the object is on a map, make sure we update its face */ if (op->map) - update_object (op, UP_OBJ_FACE); + update_object (op, UP_OBJ_CHANGE); else { - pl = is_player_inv (op->env); + pl = op->in_player (); if (pl) /* A lot of the values can change from an update - might as well send * it all. @@ -1566,3 +1540,4 @@ esrv_send_item (pl, op); } } +