--- deliantra/server/common/item.C 2008/04/20 18:48:51 1.45
+++ deliantra/server/common/item.C 2010/03/26 14:00:28 1.75
@@ -1,28 +1,28 @@
/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
*
- * Copyright (©) 2005,2006,2007 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
*/
#include
-#include
#include
#include
@@ -67,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"
@@ -172,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},
@@ -209,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
@@ -255,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
@@ -302,9 +268,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) ||
@@ -317,33 +285,25 @@
enc += op->stats.grace; /* grace regen */
enc += op->stats.exp; /* speed bonus */
}
+
enc += op->stats.luck;
/* 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);
}
@@ -353,11 +313,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;
}
@@ -367,19 +326,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.
@@ -391,37 +350,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 " ";
@@ -451,6 +400,7 @@
if (i < 21)
return levelnumbers[i];
+
if (!(i % 10))
return levelnumbers_10[i / 10];
@@ -460,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
@@ -492,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 ();
@@ -536,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
@@ -573,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:
@@ -629,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)
@@ -643,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))
@@ -675,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)
@@ -717,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)";
@@ -731,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)
@@ -738,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);
@@ -783,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);
@@ -807,10 +774,10 @@
* 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";
+ buf << "(very slow movement)";
break;
case 1:
buf << "(slow movement)";
@@ -887,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 -
@@ -935,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)
@@ -1009,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:
@@ -1172,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);
@@ -1197,6 +1184,7 @@
examine (object *op, object *tmp)
{
std::string info = tmp->describe (op);
+
op->contr->infobox (MSG_CHANNEL ("examine"), info.c_str ());
}
@@ -1212,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);
@@ -1359,8 +1347,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);
@@ -1377,7 +1363,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;
}
}
@@ -1385,14 +1371,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);
}