summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/itemprop.cc
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-11-22 08:41:20 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-11-22 08:41:20 +0000
commit1d0f57cbceb778139ca215cc4fcfd1584951f6dd (patch)
treecafd60c944c51fcce778aa5d6912bc548c518339 /crawl-ref/source/itemprop.cc
parent6f5e187a9e5cd348296dba2fd89d2e206e775a01 (diff)
downloadcrawl-ref-1d0f57cbceb778139ca215cc4fcfd1584951f6dd.tar.gz
crawl-ref-1d0f57cbceb778139ca215cc4fcfd1584951f6dd.zip
Merged stone_soup r15:451 into trunk.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@452 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/itemprop.cc')
-rw-r--r--crawl-ref/source/itemprop.cc2085
1 files changed, 2085 insertions, 0 deletions
diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc
new file mode 100644
index 0000000000..e3a70c440b
--- /dev/null
+++ b/crawl-ref/source/itemprop.cc
@@ -0,0 +1,2085 @@
+/*
+ * File: itemprop.cc
+ * Summary: Misc functions.
+ * Written by: Brent Ross
+ *
+ * Modified for Crawl Reference by $Author$ on $Date$
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- BWR Created
+ */
+
+#include "AppHdr.h"
+#include "itemname.h"
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "items.h"
+#include "itemprop.h"
+#include "macro.h"
+#include "mon-util.h"
+#include "notes.h"
+#include "player.h"
+#include "randart.h"
+#include "skills2.h"
+#include "stuff.h"
+#include "transfor.h"
+#include "view.h"
+
+
+// XXX: name strings in most of the following are currently unused!
+struct armour_def
+{
+ armour_type id;
+ const char *name;
+ int ac;
+ int ev;
+ int mass;
+
+ bool light;
+ equipment_type slot;
+ size_type fit_min;
+ size_type fit_max;
+};
+
+// Note: the Little-Giant range is used to make armours which are very
+// flexible and adjustable and can be worn by any player character...
+// providing they also pass the shape test, of course.
+static int Armour_index[NUM_ARMOURS];
+static armour_def Armour_prop[NUM_ARMOURS] =
+{
+ { ARM_ANIMAL_SKIN, "animal skin", 2, 0, 100,
+ true, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_ROBE, "robe", 2, 0, 60,
+ true, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_BIG },
+ { ARM_LEATHER_ARMOUR, "leather armour", 3, -1, 150,
+ true, EQ_BODY_ARMOUR, SIZE_SMALL, SIZE_MEDIUM },
+ { ARM_STUDDED_LEATHER_ARMOUR,"studded leather armour",4, -1, 180,
+ true, EQ_BODY_ARMOUR, SIZE_SMALL, SIZE_MEDIUM },
+
+ { ARM_RING_MAIL, "ring mail", 4, -2, 250,
+ false, EQ_BODY_ARMOUR, SIZE_SMALL, SIZE_MEDIUM },
+ { ARM_SCALE_MAIL, "scale mail", 5, -3, 350,
+ false, EQ_BODY_ARMOUR, SIZE_SMALL, SIZE_MEDIUM },
+ { ARM_CHAIN_MAIL, "chain mail", 6, -4, 400,
+ false, EQ_BODY_ARMOUR, SIZE_SMALL, SIZE_MEDIUM },
+ { ARM_BANDED_MAIL, "banded mail", 7, -5, 500,
+ false, EQ_BODY_ARMOUR, SIZE_MEDIUM, SIZE_MEDIUM },
+ { ARM_SPLINT_MAIL, "splint mail", 8, -5, 550,
+ false, EQ_BODY_ARMOUR, SIZE_MEDIUM, SIZE_MEDIUM },
+ { ARM_PLATE_MAIL, "plate mail", 10, -6, 650,
+ false, EQ_BODY_ARMOUR, SIZE_MEDIUM, SIZE_MEDIUM },
+ { ARM_CRYSTAL_PLATE_MAIL, "crystal plate mail", 14, -8, 1200,
+ false, EQ_BODY_ARMOUR, SIZE_MEDIUM, SIZE_MEDIUM },
+
+ { ARM_TROLL_HIDE, "troll hide", 2, -1, 220,
+ true, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_TROLL_LEATHER_ARMOUR, "troll leather armour", 4, -1, 220,
+ true, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_STEAM_DRAGON_HIDE, "steam dragon hide", 2, 0, 120,
+ true, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_STEAM_DRAGON_ARMOUR, "steam dragon armour", 4, 0, 120,
+ true, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_MOTTLED_DRAGON_HIDE, "mottled dragon hide", 2, -1, 150,
+ true, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_MOTTLED_DRAGON_ARMOUR,"mottled dragon armour", 5, -1, 150,
+ true, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+
+ { ARM_SWAMP_DRAGON_HIDE, "swamp dragon hide", 3, -2, 200,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_SWAMP_DRAGON_ARMOUR, "swamp dragon armour", 5, -2, 200,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_DRAGON_HIDE, "dragon hide", 3, -3, 350,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_DRAGON_ARMOUR, "dragon armour", 6, -3, 350,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_ICE_DRAGON_HIDE, "ice dragon hide", 3, -3, 350,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_ICE_DRAGON_ARMOUR, "ice dragon armour", 6, -3, 350,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_STORM_DRAGON_HIDE, "storm dragon hide", 4, -5, 600,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_STORM_DRAGON_ARMOUR, "storm dragon armour", 8, -5, 600,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_GOLD_DRAGON_HIDE, "gold dragon hide", 5, -8, 1100,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+ { ARM_GOLD_DRAGON_ARMOUR, "gold dragon armour", 10, -8, 1100,
+ false, EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT },
+
+ { ARM_CLOAK, "cloak", 1, 0, 40,
+ true, EQ_CLOAK, SIZE_LITTLE, SIZE_BIG },
+ { ARM_GLOVES, "gloves", 1, 0, 20,
+ true, EQ_GLOVES, SIZE_SMALL, SIZE_MEDIUM },
+
+ { ARM_HELMET, "helmet", 1, 0, 80,
+ false, EQ_HELMET, SIZE_SMALL, SIZE_MEDIUM },
+ { ARM_CAP, "cap", 0, 0, 40,
+ true, EQ_HELMET, SIZE_LITTLE, SIZE_LARGE },
+
+ // Note that barding size is compared against torso so it currently
+ // needs to fit medium, but that doesn't matter as much as race
+ // and shapeshift status.
+ { ARM_BOOTS, "boots", 1, 0, 30,
+ true, EQ_BOOTS, SIZE_SMALL, SIZE_MEDIUM },
+ { ARM_CENTAUR_BARDING, "centaur barding", 4, -2, 100,
+ true, EQ_BOOTS, SIZE_MEDIUM, SIZE_MEDIUM },
+ { ARM_NAGA_BARDING, "naga barding", 4, -2, 100,
+ true, EQ_BOOTS, SIZE_MEDIUM, SIZE_MEDIUM },
+
+ // Note: shields use ac-value as sh-value, EV pen is used for heavy_shield
+ { ARM_BUCKLER, "buckler", 3, 0, 90,
+ true, EQ_SHIELD, SIZE_LITTLE, SIZE_MEDIUM },
+ { ARM_SHIELD, "shield", 5, -1, 150,
+ false, EQ_SHIELD, SIZE_SMALL, SIZE_BIG },
+ { ARM_LARGE_SHIELD, "large shield", 7, -2, 230,
+ false, EQ_SHIELD, SIZE_MEDIUM, SIZE_GIANT },
+};
+
+struct weapon_def
+{
+ int id;
+ const char *name;
+ int dam;
+ int hit;
+ int speed;
+ int mass;
+ int str_weight;
+
+ skill_type skill;
+ hands_reqd_type hands;
+ size_type fit_size; // actual size is one size smaller
+ missile_type ammo; // MI_NONE for non-launchers
+ bool throwable;
+
+ int dam_type;
+};
+
+static int Weapon_index[NUM_WEAPONS];
+static weapon_def Weapon_prop[NUM_WEAPONS] =
+{
+ // Maces & Flails
+ { WPN_WHIP, "whip", 4, 2, 13, 30, 2,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_SLASHING },
+ { WPN_CLUB, "club", 5, 3, 13, 50, 7,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_SMALL, MI_NONE, true,
+ DAMV_CRUSHING },
+ { WPN_HAMMER, "hammer", 7, 3, 13, 90, 7,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_SMALL, MI_NONE, false,
+ DAMV_CRUSHING },
+ { WPN_MACE, "mace", 8, 3, 14, 120, 8,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_SMALL, MI_NONE, false,
+ DAMV_CRUSHING },
+ { WPN_FLAIL, "flail", 9, 2, 15, 130, 8,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_SMALL, MI_NONE, false,
+ DAMV_CRUSHING },
+ { WPN_ANCUS, "ancus", 9, 2, 14, 120, 8,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_CRUSHING },
+ { WPN_MORNINGSTAR, "morningstar", 10, -1, 15, 140, 8,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_PIERCING | DAM_BLUDGEON },
+ { WPN_DEMON_WHIP, "demon whip", 10, 1, 13, 30, 2,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_SLASHING },
+ { WPN_SPIKED_FLAIL, "spiked flail", 12, -2, 16, 190, 8,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_PIERCING | DAM_BLUDGEON },
+ { WPN_EVENINGSTAR, "eveningstar", 12, -1, 15, 180, 8,
+ SK_MACES_FLAILS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_PIERCING | DAM_BLUDGEON },
+ { WPN_DIRE_FLAIL, "dire flail", 13, -3, 14, 240, 9,
+ SK_MACES_FLAILS, HANDS_DOUBLE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_PIERCING | DAM_BLUDGEON },
+ { WPN_GREAT_MACE, "great mace", 16, -4, 18, 270, 9,
+ SK_MACES_FLAILS, HANDS_TWO, SIZE_LARGE, MI_NONE, false,
+ DAMV_CRUSHING },
+ { WPN_GIANT_CLUB, "giant club", 18, -6, 19, 330, 10,
+ SK_MACES_FLAILS, HANDS_TWO, SIZE_BIG, MI_NONE, false,
+ DAMV_CRUSHING },
+ { WPN_GIANT_SPIKED_CLUB, "giant spiked club", 20, -7, 20, 350, 10,
+ SK_MACES_FLAILS, HANDS_TWO, SIZE_BIG, MI_NONE, false,
+ DAMV_PIERCING | DAM_BLUDGEON },
+
+ // Short blades
+ { WPN_KNIFE, "knife", 3, 5, 10, 10, 1,
+ SK_SHORT_BLADES, HANDS_ONE, SIZE_LITTLE, MI_NONE, false,
+ DAMV_STABBING | DAM_SLICE },
+ { WPN_DAGGER, "dagger", 4, 6, 10, 20, 1,
+ SK_SHORT_BLADES, HANDS_ONE, SIZE_LITTLE, MI_NONE, true,
+ DAMV_STABBING | DAM_SLICE },
+ { WPN_QUICK_BLADE, "quick blade", 5, 6, 7, 50, 0,
+ SK_SHORT_BLADES, HANDS_ONE, SIZE_LITTLE, MI_NONE, false,
+ DAMV_STABBING | DAM_SLICE },
+ { WPN_SHORT_SWORD, "short sword", 6, 4, 11, 80, 2,
+ SK_SHORT_BLADES, HANDS_ONE, SIZE_SMALL, MI_NONE, false,
+ DAMV_SLICING | DAM_PIERCE },
+ { WPN_SABRE, "sabre", 7, 4, 12, 90, 2,
+ SK_SHORT_BLADES, HANDS_ONE, SIZE_SMALL, MI_NONE, false,
+ DAMV_SLICING | DAM_PIERCE },
+
+ // Long swords
+ { WPN_FALCHION, "falchion", 8, 2, 13, 170, 4,
+ SK_LONG_SWORDS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_SLICING }, // or perhaps DAMV_CHOPPING is more apt?
+ { WPN_LONG_SWORD, "long sword", 10, 1, 14, 160, 3,
+ SK_LONG_SWORDS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_SLICING },
+ { WPN_SCIMITAR, "scimitar", 11, -1, 14, 170, 3,
+ SK_LONG_SWORDS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_SLICING },
+ { WPN_KATANA, "katana", 13, 2, 13, 160, 3,
+ SK_LONG_SWORDS, HANDS_HALF, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_SLICING },
+ { WPN_DEMON_BLADE, "demon blade", 13, -1, 15, 200, 4,
+ SK_LONG_SWORDS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_SLICING },
+ { WPN_BLESSED_BLADE, "blessed blade", 14, 0, 14, 200, 4,
+ SK_LONG_SWORDS, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_SLICING },
+ { WPN_DOUBLE_SWORD, "double sword", 15, -2, 16, 220, 5,
+ SK_LONG_SWORDS, HANDS_HALF, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_SLICING },
+ { WPN_GREAT_SWORD, "great sword", 16, -3, 17, 250, 6,
+ SK_LONG_SWORDS, HANDS_TWO, SIZE_LARGE, MI_NONE, false,
+ DAMV_SLICING },
+ { WPN_TRIPLE_SWORD, "triple sword", 19, -4, 19, 260, 6,
+ SK_LONG_SWORDS, HANDS_TWO, SIZE_LARGE, MI_NONE, false,
+ DAMV_SLICING },
+
+ // Axes
+ { WPN_HAND_AXE, "hand axe", 7, 3, 13, 80, 6,
+ SK_AXES, HANDS_ONE, SIZE_SMALL, MI_NONE, true,
+ DAMV_CHOPPING },
+ { WPN_WAR_AXE, "war axe", 11, 0, 16, 180, 7,
+ SK_AXES, HANDS_ONE, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_CHOPPING },
+ { WPN_BROAD_AXE, "broad axe", 14, -2, 17, 230, 8,
+ SK_AXES, HANDS_HALF, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_CHOPPING },
+ { WPN_BATTLEAXE, "battleaxe", 17, -4, 18, 250, 8,
+ SK_AXES, HANDS_TWO, SIZE_LARGE, MI_NONE, false,
+ DAMV_CHOPPING },
+ { WPN_EXECUTIONERS_AXE, "executioner\'s axe", 20, -6, 20, 280, 9,
+ SK_AXES, HANDS_TWO, SIZE_LARGE, MI_NONE, false,
+ DAMV_CHOPPING },
+
+ // Polearms
+ { WPN_SPEAR, "spear", 6, 3, 12, 50, 3,
+ SK_POLEARMS, HANDS_HALF, SIZE_SMALL, MI_NONE, true,
+ DAMV_PIERCING },
+ { WPN_TRIDENT, "trident", 9, 2, 14, 160, 4,
+ SK_POLEARMS, HANDS_HALF, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_PIERCING },
+ { WPN_DEMON_TRIDENT, "demon trident", 13, 0, 14, 160, 4,
+ SK_POLEARMS, HANDS_HALF, SIZE_MEDIUM, MI_NONE, false,
+ DAMV_PIERCING },
+ { WPN_HALBERD, "halberd", 13, -3, 16, 200, 5,
+ SK_POLEARMS, HANDS_TWO, SIZE_LARGE, MI_NONE, false,
+ DAMV_CHOPPING | DAM_PIERCE },
+ { WPN_SCYTHE, "scythe", 14, -4, 20, 220, 7,
+ SK_POLEARMS, HANDS_TWO, SIZE_LARGE, MI_NONE, false,
+ DAMV_SLICING },
+ { WPN_GLAIVE, "glaive", 15, -3, 18, 200, 6,
+ SK_POLEARMS, HANDS_TWO, SIZE_LARGE, MI_NONE, false,
+ DAMV_CHOPPING },
+ { WPN_LOCHABER_AXE, "lochaber axe", 18, -6, 20, 200, 8,
+ SK_POLEARMS, HANDS_TWO, SIZE_LARGE, MI_NONE, false,
+ DAMV_CHOPPING },
+
+ { WPN_QUARTERSTAFF, "quarterstaff", 9, 2, 12, 180, 7,
+ SK_STAVES, HANDS_DOUBLE, SIZE_LARGE, MI_NONE, false,
+ DAMV_CRUSHING },
+ { WPN_LAJATANG, "lajatang", 14, -3, 14, 200, 3,
+ SK_STAVES, HANDS_DOUBLE, SIZE_LARGE, MI_NONE, false,
+ DAMV_SLICING },
+
+ // Range weapons
+ // Notes:
+ // - HANDS_HALF means a reloading time penalty if using shield
+ // - damage field is used for bonus strength damage (string tension)
+ // - slings get a bonus from dex, not str (as tension is meaningless)
+ // - str weight is used for speed and applying dex to skill
+ { WPN_BLOWGUN, "blowgun", 0, 2, 10, 20, 0,
+ SK_DARTS, HANDS_HALF, SIZE_LITTLE, MI_NEEDLE, false,
+ DAMV_NON_MELEE },
+ { WPN_SLING, "sling", 0, 2, 11, 20, 1,
+ SK_SLINGS, HANDS_HALF, SIZE_LITTLE, MI_STONE, false,
+ DAMV_NON_MELEE },
+ { WPN_HAND_CROSSBOW, "hand crossbow", 3, 4, 15, 70, 5,
+ SK_CROSSBOWS, HANDS_HALF, SIZE_SMALL, MI_DART, false,
+ DAMV_NON_MELEE },
+ { WPN_CROSSBOW, "crossbow", 5, 4, 15, 150, 8,
+ SK_CROSSBOWS, HANDS_TWO, SIZE_MEDIUM, MI_BOLT, false,
+ DAMV_NON_MELEE },
+ { WPN_BOW, "bow", 4, 1, 11, 90, 2,
+ SK_BOWS, HANDS_TWO, SIZE_MEDIUM, MI_ARROW, false,
+ DAMV_NON_MELEE },
+ { WPN_LONGBOW, "longbow", 5, 0, 12, 120, 3,
+ SK_BOWS, HANDS_TWO, SIZE_LARGE, MI_ARROW, false,
+ DAMV_NON_MELEE },
+};
+
+struct missile_def
+{
+ int id;
+ const char *name;
+ int dam;
+ int mass;
+ bool throwable;
+};
+
+static int Missile_index[NUM_MISSILES];
+static missile_def Missile_prop[NUM_MISSILES] =
+{
+ { MI_NEEDLE, "needle", 0, 1, false },
+ { MI_STONE, "stone", 4, 2, true },
+ { MI_DART, "dart", 5, 3, true },
+ { MI_ARROW, "arrow", 6, 5, false },
+ { MI_BOLT, "bolt", 8, 5, false },
+ { MI_LARGE_ROCK, "large rock", 20, 1000, true },
+};
+
+struct food_def
+{
+ int id;
+ const char *name;
+ int value;
+ int carn_mod;
+ int herb_mod;
+ int mass;
+ int turns;
+};
+
+// NOTE: Any food with special random messages or side effects
+// currently only takes one turn to eat (except ghouls and chunks)...
+// if this changes then those items will have to have special code
+// (like ghoul chunks) to guarantee that the special thing is only
+// done once. See the ghoul eating code over in food.cc.
+static int Food_index[NUM_FOODS];
+static food_def Food_prop[NUM_FOODS] =
+{
+ { FOOD_MEAT_RATION, "meat ration", 5000, 500, -1500, 80, 4 },
+ { FOOD_SAUSAGE, "sausage", 1500, 150, -400, 40, 1 },
+ { FOOD_CHUNK, "chunk", 1000, 100, -500, 100, 3 },
+ { FOOD_BEEF_JERKY, "beef jerky", 800, 100, -250, 20, 1 },
+
+ { FOOD_BREAD_RATION, "bread ration", 4400, -1500, 750, 80, 4 },
+ { FOOD_SNOZZCUMBER, "snozzcumber", 1500, -500, 500, 50, 1 },
+ { FOOD_ORANGE, "orange", 1000, -350, 400, 20, 1 },
+ { FOOD_BANANA, "banana", 1000, -350, 400, 20, 1 },
+ { FOOD_LEMON, "lemon", 1000, -350, 400, 20, 1 },
+ { FOOD_PEAR, "pear", 700, -250, 300, 20, 1 },
+ { FOOD_APPLE, "apple", 700, -250, 300, 20, 1 },
+ { FOOD_APRICOT, "apricot", 700, -250, 300, 15, 1 },
+ { FOOD_CHOKO, "choko", 600, -200, 250, 30, 1 },
+ { FOOD_RAMBUTAN, "rambutan", 600, -200, 250, 10, 1 },
+ { FOOD_LYCHEE, "lychee", 600, -200, 250, 10, 1 },
+ { FOOD_STRAWBERRY, "strawberry", 200, -80, 100, 5, 1 },
+ { FOOD_GRAPE, "grape", 100, -40, 50, 2, 1 },
+ { FOOD_SULTANA, "sultana", 70, -30, 30, 1, 1 },
+
+ { FOOD_ROYAL_JELLY, "royal jelly", 4000, 0, 0, 55, 1 },
+ { FOOD_HONEYCOMB, "honeycomb", 2000, 0, 0, 40, 1 },
+ { FOOD_PIZZA, "pizza", 1500, 0, 0, 40, 1 },
+ { FOOD_CHEESE, "cheese", 1200, 0, 0, 40, 1 },
+};
+
+// Must call this functions early on so that the above tables can
+// be accessed correctly.
+void init_properties(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_ARMOURS; i++)
+ Armour_index[ Armour_prop[i].id ] = i;
+
+ for (i = 0; i < NUM_WEAPONS; i++)
+ Weapon_index[ Weapon_prop[i].id ] = i;
+
+ for (i = 0; i < NUM_MISSILES; i++)
+ Missile_index[ Missile_prop[i].id ] = i;
+
+ for (i = 0; i < NUM_FOODS; i++)
+ Food_index[ Food_prop[i].id ] = i;
+}
+
+
+// Some convenient functions to hide the bit operations and create
+// an interface layer between the code and the data in case this
+// gets changed again. -- bwr
+
+//
+// Item cursed status functions:
+//
+bool item_cursed( const item_def &item )
+{
+ return (item.flags & ISFLAG_CURSED);
+}
+
+bool item_known_cursed( const item_def &item )
+{
+ return ((item.flags & ISFLAG_KNOW_CURSE) && (item.flags & ISFLAG_CURSED));
+}
+
+bool item_known_uncursed( const item_def &item )
+{
+ return ((item.flags & ISFLAG_KNOW_CURSE) && !(item.flags & ISFLAG_CURSED));
+}
+
+void do_curse_item( item_def &item )
+{
+ item.flags |= ISFLAG_CURSED;
+}
+
+void do_uncurse_item( item_def &item )
+{
+ item.flags &= (~ISFLAG_CURSED);
+}
+
+//
+// Item identification status:
+//
+bool item_ident( const item_def &item, unsigned long flags )
+{
+ return ((item.flags & flags) == flags);
+}
+
+void set_ident_flags( item_def &item, unsigned long flags )
+{
+ bool known_before = fully_identified(item);
+ item.flags |= flags;
+ if ( !known_before && fully_identified(item) ) {
+ /* make a note of it */
+ if ( is_interesting_item(item) ) {
+ char buf[ITEMNAME_SIZE];
+ char buf2[ITEMNAME_SIZE];
+ item_name( item, DESC_NOCAP_A, buf );
+ strcpy(buf2, origin_desc(item).c_str());
+ take_note(Note(NOTE_ID_ITEM, 0, 0, buf, buf2));
+ }
+ }
+}
+
+void unset_ident_flags( item_def &item, unsigned long flags )
+{
+ item.flags &= (~flags);
+}
+
+//
+// Equipment race and description:
+//
+unsigned long get_equip_race( const item_def &item )
+{
+ return (item.flags & ISFLAG_RACIAL_MASK);
+}
+
+unsigned long get_equip_desc( const item_def &item )
+{
+ return (item.flags & ISFLAG_COSMETIC_MASK);
+}
+
+void set_equip_race( item_def &item, unsigned long flags )
+{
+ ASSERT( (flags & ~ISFLAG_RACIAL_MASK) == 0 );
+
+ // first check for base-sub pairs that can't ever have racial types
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ if (item.sub_type == WPN_GIANT_CLUB
+ || item.sub_type == WPN_GIANT_SPIKED_CLUB
+ || item.sub_type == WPN_KATANA
+ || item.sub_type == WPN_LAJATANG
+ || item.sub_type == WPN_SLING
+ || item.sub_type == WPN_KNIFE
+ || item.sub_type == WPN_QUARTERSTAFF
+ || item.sub_type == WPN_DEMON_BLADE
+ || item.sub_type == WPN_DEMON_WHIP
+ || item.sub_type == WPN_DEMON_TRIDENT)
+ {
+ return;
+ }
+ break;
+
+ case OBJ_ARMOUR:
+ // not hides, dragon armour, crystal plate, or barding
+ if (item.sub_type >= ARM_DRAGON_HIDE
+ && item.sub_type <= ARM_SWAMP_DRAGON_ARMOUR
+ && item.sub_type != ARM_CENTAUR_BARDING
+ && item.sub_type != ARM_NAGA_BARDING)
+ {
+ return;
+ }
+ break;
+
+ case OBJ_MISSILES:
+ if (item.sub_type == MI_STONE || item.sub_type == MI_LARGE_ROCK)
+ return;
+ break;
+
+ default:
+ return;
+ }
+
+ // check that item is appropriate for racial type
+ switch (flags)
+ {
+ case ISFLAG_ELVEN:
+ if (item.base_type == OBJ_ARMOUR
+ && (item.sub_type == ARM_SPLINT_MAIL
+ || item.sub_type == ARM_BANDED_MAIL
+ || item.sub_type == ARM_PLATE_MAIL))
+ {
+ return;
+ }
+ break;
+
+ case ISFLAG_DWARVEN:
+ if (item.base_type == OBJ_ARMOUR
+ && (item.sub_type == ARM_ROBE
+ || item.sub_type == ARM_LEATHER_ARMOUR
+ || item.sub_type == ARM_STUDDED_LEATHER_ARMOUR))
+ {
+ return;
+ }
+ break;
+
+ case ISFLAG_ORCISH:
+ default:
+ break;
+ }
+
+ item.flags &= ~ISFLAG_RACIAL_MASK; // delete previous
+ item.flags |= flags;
+}
+
+void set_equip_desc( item_def &item, unsigned long flags )
+{
+ ASSERT( (flags & ~ISFLAG_COSMETIC_MASK) == 0 );
+
+ item.flags &= ~ISFLAG_COSMETIC_MASK; // delete previous
+ item.flags |= flags;
+}
+
+//
+// These functions handle the description and subtypes for helmets/caps
+//
+short get_helmet_type( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR
+ && get_armour_slot( item ) == EQ_HELMET );
+
+ return (item.plus2 & THELM_TYPE_MASK);
+}
+
+short get_helmet_desc( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR
+ && get_armour_slot( item ) == EQ_HELMET );
+
+ return (item.plus2 & THELM_DESC_MASK);
+}
+
+void set_helmet_type( item_def &item, short type )
+{
+ ASSERT( (type & ~THELM_TYPE_MASK) == 0 );
+ ASSERT( item.base_type == OBJ_ARMOUR
+ && get_armour_slot( item ) == EQ_HELMET );
+
+ // make sure we have the right sub_type (to get properties correctly)
+ if (type == THELM_HELMET || type == THELM_HELM)
+ item.sub_type = ARM_HELMET;
+
+ // [dshaligram] FIXME: This is for when we import caps
+ // else
+ // item.sub_type = ARM_CAP;
+
+ item.plus2 &= ~THELM_TYPE_MASK;
+ item.plus2 |= type;
+}
+
+void set_helmet_desc( item_def &item, short type )
+{
+ ASSERT( (type & ~THELM_DESC_MASK) == 0 );
+ ASSERT( item.base_type == OBJ_ARMOUR
+ && get_armour_slot( item ) == EQ_HELMET );
+
+ const int helmtype = get_helmet_type(item);
+ if ((helmtype == THELM_CAP || helmtype == THELM_WIZARD_HAT)
+ && type > THELM_DESC_PLUMED)
+ type = THELM_DESC_PLAIN;
+
+ item.plus2 &= ~THELM_DESC_MASK;
+ item.plus2 |= type;
+}
+
+bool is_hard_helmet(const item_def &item)
+{
+ return (item.base_type == OBJ_ARMOUR
+ && item.sub_type == ARM_HELMET
+ && (get_helmet_type(item) == THELM_HELM
+ || get_helmet_type(item) == THELM_HELMET));
+}
+
+void set_helmet_random_desc( item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR
+ && get_armour_slot( item ) == EQ_HELMET );
+
+ item.plus2 &= ~THELM_DESC_MASK;
+
+ if (is_hard_helmet(item))
+ item.plus2 |= (random2(8) << 8);
+ else
+ item.plus2 |= (random2(5) << 8);
+
+}
+
+bool is_helmet_type( const item_def &item, short val )
+{
+ if (item.base_type != OBJ_ARMOUR || get_armour_slot( item ) != EQ_HELMET)
+ return (false);
+
+ return (get_helmet_type( item ) == val);
+}
+
+//
+// Ego item functions:
+//
+bool set_item_ego_type( item_def &item, int item_type, int ego_type )
+{
+ if (item.base_type == item_type
+ && !is_random_artefact( item )
+ && !is_fixed_artefact( item ))
+ {
+ item.special = ego_type;
+ return (true);
+ }
+
+ return (false);
+}
+
+int get_weapon_brand( const item_def &item )
+{
+ // Weapon ego types are "brands", so we do the randart lookup here.
+
+ // Staves "brands" handled specially
+ if (item.base_type != OBJ_WEAPONS)
+ return (SPWPN_NORMAL);
+
+ if (is_fixed_artefact( item ))
+ {
+ switch (item.special)
+ {
+ case SPWPN_SWORD_OF_CEREBOV:
+ return (SPWPN_FLAMING);
+
+ case SPWPN_STAFF_OF_OLGREB:
+ return (SPWPN_VENOM);
+
+ case SPWPN_VAMPIRES_TOOTH:
+ return (SPWPN_VAMPIRICISM);
+
+ default:
+ return (SPWPN_NORMAL);
+ }
+ }
+ else if (is_random_artefact( item ))
+ {
+ return (randart_wpn_property( item, RAP_BRAND ));
+ }
+
+ return (item.special);
+}
+
+int get_ammo_brand( const item_def &item )
+{
+ // no artefact arrows yet -- bwr
+ if (item.base_type != OBJ_MISSILES || is_random_artefact( item ))
+ return (SPMSL_NORMAL);
+
+ return (item.special);
+}
+
+int get_armour_ego_type( const item_def &item )
+{
+ // artefact armours have no ego type, must look up powers separately
+ if (item.base_type != OBJ_ARMOUR
+ || (is_random_artefact( item ) && !is_unrandom_artefact( item )))
+ {
+ return (SPARM_NORMAL);
+ }
+
+ return (item.special);
+}
+
+//
+// Armour information and checking functions
+//
+bool hide2armour( item_def &item )
+{
+ if (item.base_type != OBJ_ARMOUR)
+ return (false);
+
+ switch (item.sub_type)
+ {
+ default:
+ return (false);
+
+ case ARM_DRAGON_HIDE:
+ item.sub_type = ARM_DRAGON_ARMOUR;
+ break;
+
+ case ARM_TROLL_HIDE:
+ item.sub_type = ARM_TROLL_LEATHER_ARMOUR;
+ break;
+
+ case ARM_ICE_DRAGON_HIDE:
+ item.sub_type = ARM_ICE_DRAGON_ARMOUR;
+ break;
+
+ case ARM_MOTTLED_DRAGON_HIDE:
+ item.sub_type = ARM_MOTTLED_DRAGON_ARMOUR;
+ break;
+
+ case ARM_STORM_DRAGON_HIDE:
+ item.sub_type = ARM_STORM_DRAGON_ARMOUR;
+ break;
+
+ case ARM_GOLD_DRAGON_HIDE:
+ item.sub_type = ARM_GOLD_DRAGON_ARMOUR;
+ break;
+
+ case ARM_SWAMP_DRAGON_HIDE:
+ item.sub_type = ARM_SWAMP_DRAGON_ARMOUR;
+ break;
+
+ case ARM_STEAM_DRAGON_HIDE:
+ item.sub_type = ARM_STEAM_DRAGON_ARMOUR;
+ break;
+ }
+
+ return (true);
+} // end hide2armour()
+
+// Return the enchantment limit of a piece of armour
+int armour_max_enchant( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR );
+
+ const int eq_slot = get_armour_slot( item );
+
+ int max_plus = MAX_SEC_ENCHANT;
+ if (eq_slot == EQ_BODY_ARMOUR || eq_slot == EQ_SHIELD)
+ max_plus = MAX_ARM_ENCHANT;
+
+ return (max_plus);
+}
+
+// doesn't include animal skin (only skins we can make and enchant)
+bool armour_is_hide( const item_def &item, bool inc_made )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR );
+
+ switch (item.sub_type)
+ {
+ case ARM_TROLL_LEATHER_ARMOUR:
+ case ARM_DRAGON_ARMOUR:
+ case ARM_ICE_DRAGON_ARMOUR:
+ case ARM_STEAM_DRAGON_ARMOUR:
+ case ARM_MOTTLED_DRAGON_ARMOUR:
+ case ARM_STORM_DRAGON_ARMOUR:
+ case ARM_GOLD_DRAGON_ARMOUR:
+ case ARM_SWAMP_DRAGON_ARMOUR:
+ return (inc_made);
+
+ case ARM_TROLL_HIDE:
+ case ARM_DRAGON_HIDE:
+ case ARM_ICE_DRAGON_HIDE:
+ case ARM_STEAM_DRAGON_HIDE:
+ case ARM_MOTTLED_DRAGON_HIDE:
+ case ARM_STORM_DRAGON_HIDE:
+ case ARM_GOLD_DRAGON_HIDE:
+ case ARM_SWAMP_DRAGON_HIDE:
+ return (true);
+
+ default:
+ break;
+ }
+
+ return (false);
+}
+
+// used to distinguish shiny and embroidered
+bool armour_not_shiny( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR );
+
+ switch (item.sub_type)
+ {
+ case ARM_ROBE:
+ case ARM_CLOAK:
+ case ARM_GLOVES:
+ case ARM_BOOTS:
+ case ARM_NAGA_BARDING:
+ case ARM_CENTAUR_BARDING:
+ case ARM_CAP:
+ case ARM_LEATHER_ARMOUR:
+ case ARM_STUDDED_LEATHER_ARMOUR:
+ case ARM_ANIMAL_SKIN:
+ case ARM_TROLL_HIDE:
+ case ARM_TROLL_LEATHER_ARMOUR:
+ return (true);
+
+ case ARM_HELMET:
+ {
+ const int helmtype = get_helmet_type(item);
+ return (helmtype == THELM_CAP || helmtype == THELM_WIZARD_HAT);
+ }
+ default:
+ break;
+ }
+
+ return (false);
+}
+
+int armour_str_required( const item_def &arm )
+{
+ ASSERT (arm.base_type == OBJ_ARMOUR );
+
+ int ret = 0;
+
+ const equipment_type slot = get_armour_slot( arm );
+ const int mass = item_mass( arm );
+
+ switch (slot)
+ {
+ case EQ_BODY_ARMOUR:
+ ret = mass / 35;
+ break;
+
+ case EQ_SHIELD:
+ ret = mass / 15;
+ break;
+
+ default:
+ break;
+ }
+
+ return ((ret < STR_REQ_THRESHOLD) ? 0 : ret);
+}
+
+equipment_type get_armour_slot( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR );
+
+ return (Armour_prop[ Armour_index[item.sub_type] ].slot);
+}
+
+bool jewellery_is_amulet( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_JEWELLERY );
+
+ return (item.sub_type >= AMU_RAGE);
+}
+
+bool check_jewellery_size( const item_def &item, size_type size )
+{
+ ASSERT( item.base_type == OBJ_JEWELLERY );
+
+ // Currently assuming amulets are always wearable (only needs
+ // to be held over head or heart... giants can strap it on with
+ // a bit of binder twine). However, rings need to actually fit
+ // around the ring finger to work, and so the big cannot use them.
+ return (size <= SIZE_LARGE || jewellery_is_amulet( item ));
+}
+
+// Returns the basic light status of an armour, ignoring things like the
+// elven bonus... you probably want is_light_armour() most times.
+bool base_armour_is_light( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR );
+
+ return (Armour_prop[ Armour_index[item.sub_type] ].light);
+}
+
+// returns number of sizes off
+int fit_armour_size( const item_def &item, size_type size )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR );
+
+ const size_type min = Armour_prop[ Armour_index[item.sub_type] ].fit_min;
+ const size_type max = Armour_prop[ Armour_index[item.sub_type] ].fit_max;
+
+ if (size < min)
+ return (min - size); // -'ve means levels too small
+ else if (size > max)
+ return (max - size); // +'ve means levels too large
+
+ return (0);
+}
+
+// returns true if armour fits size (shape needs additional verification)
+bool check_armour_size( const item_def &item, size_type size )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR );
+
+ return (fit_armour_size( item, size ) == 0);
+}
+
+// Note that this function is used to check validity of equipment
+// coming out of transformations... so it shouldn't contain any
+// wield/unwield only checks like two-handed weapons and shield.
+bool check_armour_shape( const item_def &item, bool quiet )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR );
+
+ const int slot = get_armour_slot( item );
+
+ if (!player_is_shapechanged())
+ {
+ switch (slot)
+ {
+ case EQ_BOOTS:
+ switch (you.species)
+ {
+ case SP_NAGA:
+ if (item.sub_type != ARM_NAGA_BARDING)
+ {
+ if (!quiet)
+ mpr( "You can't wear that!" );
+
+ return (false);
+ }
+ break;
+
+ case SP_CENTAUR:
+ if (item.sub_type != ARM_CENTAUR_BARDING)
+ {
+ if (!quiet)
+ mpr( "You can't wear that!" );
+
+ return (false);
+ }
+ break;
+
+ case SP_KENKU:
+ if (!quiet)
+ {
+ if (item.sub_type == ARM_BOOTS)
+ mpr( "Boots don't fit your feet!" );
+ else
+ mpr( "You can't wear barding!" );
+ }
+ return (false);
+
+ case SP_MERFOLK:
+ if (player_in_water() && item.sub_type == ARM_BOOTS)
+ {
+ if (!quiet)
+ mpr( "You don't currently have feet!" );
+
+ return (false);
+ }
+ // intentional fall-through
+ default:
+ if (item.sub_type == ARM_NAGA_BARDING
+ || item.sub_type == ARM_CENTAUR_BARDING)
+ {
+ if (!quiet)
+ mpr( "You can't wear barding!" );
+
+ return (false);
+ }
+
+ if (you.mutation[MUT_HOOVES] >= 2)
+ {
+ if (!quiet)
+ mpr( "You can't wear boots with hooves!" );
+
+ return (false);
+ }
+ break;
+ }
+ break;
+
+ case EQ_HELMET:
+ if (item.sub_type == ARM_CAP
+ || get_helmet_type(item) == THELM_CAP
+ || get_helmet_type(item) == THELM_WIZARD_HAT)
+ break;
+
+ if (you.species == SP_KENKU)
+ {
+ if (!quiet)
+ mpr( "That helmet does not fit your head!" );
+
+ return (false);
+ }
+
+ if (you.species == SP_MINOTAUR || you.mutation[MUT_HORNS])
+ {
+ if (!quiet)
+ mpr( "You can't wear that with your horns!" );
+
+ return (false);
+ }
+ break;
+
+ case EQ_GLOVES:
+ if (you.mutation[MUT_CLAWS] >= 3)
+ {
+ if (!quiet)
+ mpr( "You can't wear gloves with your huge claws!" );
+
+ return (false);
+ }
+ break;
+
+ case EQ_BODY_ARMOUR:
+ // Cannot swim in heavy armour
+ if (player_is_swimming() && !is_light_armour( item ))
+ {
+ if (!quiet)
+ mpr("You can't swim in that!");
+
+ return (false);
+ }
+
+ // Draconians are human-sized, but have wings that cause problems
+ // with most body armours (only very flexible fit allowed).
+ if (player_genus( GENPC_DRACONIAN )
+ && !check_armour_size( item, SIZE_BIG ))
+ {
+ if (!quiet)
+ mpr( "That armour doesn't fit your wings." );
+
+ return (false);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // Note: some transformation include all of the above as well
+ if (item.sub_type == ARM_NAGA_BARDING
+ || item.sub_type == ARM_CENTAUR_BARDING)
+ {
+ if (!quiet)
+ mpr( "You can't wear barding in your current form!" );
+
+ return (false);
+ }
+ }
+
+ // Note: This need to be checked after all the special cases
+ // above, and in addition to shapechanged or not. This is
+ // a simple check against the armour types that are forced off.
+
+ // FIXME FIXME FIXME
+ /*
+ if (!transform_can_equip_type( slot ))
+ {
+ if (!quiet)
+ mpr( "You can't wear that in your current form!" );
+
+ return (false);
+ }
+ */
+
+ return (true);
+}
+
+//
+// Weapon information and checking functions:
+//
+
+// Checks how rare a weapon is. Many of these have special routines for
+// placement, especially those with a rarity of zero. Chance is out of 10.
+int weapon_rarity( int w_type )
+{
+ switch (w_type)
+ {
+ case WPN_CLUB:
+ case WPN_DAGGER:
+ return (10);
+
+ case WPN_HAND_AXE:
+ case WPN_MACE:
+ case WPN_QUARTERSTAFF:
+ return (9);
+
+ case WPN_BOW:
+ case WPN_FLAIL:
+ case WPN_HAMMER:
+ case WPN_SABRE:
+ case WPN_SHORT_SWORD:
+ case WPN_SLING:
+ case WPN_SPEAR:
+ return (8);
+
+ case WPN_FALCHION:
+ case WPN_LONG_SWORD:
+ case WPN_MORNINGSTAR:
+ case WPN_WAR_AXE:
+ return (7);
+
+ case WPN_BATTLEAXE:
+ case WPN_CROSSBOW:
+ case WPN_GREAT_SWORD:
+ case WPN_SCIMITAR:
+ case WPN_TRIDENT:
+ return (6);
+
+ case WPN_GLAIVE:
+ case WPN_HALBERD:
+ case WPN_BLOWGUN:
+ return (5);
+
+ case WPN_BROAD_AXE:
+ case WPN_HAND_CROSSBOW:
+ case WPN_SPIKED_FLAIL:
+ case WPN_WHIP:
+ return (4);
+
+ case WPN_GREAT_MACE:
+ return (3);
+
+ case WPN_ANCUS:
+ case WPN_DIRE_FLAIL:
+ case WPN_SCYTHE:
+ case WPN_LONGBOW:
+ return (2);
+
+ case WPN_GIANT_CLUB:
+ case WPN_GIANT_SPIKED_CLUB:
+ case WPN_LOCHABER_AXE:
+ return (1);
+
+ case WPN_DOUBLE_SWORD:
+ case WPN_EVENINGSTAR:
+ case WPN_EXECUTIONERS_AXE:
+ case WPN_KATANA:
+ case WPN_LAJATANG:
+ case WPN_KNIFE:
+ case WPN_QUICK_BLADE:
+ case WPN_TRIPLE_SWORD:
+ case WPN_DEMON_TRIDENT:
+ case WPN_DEMON_WHIP:
+ case WPN_DEMON_BLADE:
+ case WPN_BLESSED_BLADE:
+ // zero value weapons must be placed specially -- see make_item() {dlb}
+ return (0);
+
+ default:
+ break;
+ }
+
+ return (0);
+} // end rare_weapon()
+
+int get_vorpal_type( const item_def &item )
+{
+ int ret = DVORP_NONE;
+
+ if (item.base_type == OBJ_WEAPONS)
+ ret = (Weapon_prop[ Weapon_index[item.sub_type] ].dam_type & DAMV_MASK);
+
+ return (ret);
+} // end vorpal_type()
+
+int get_damage_type( const item_def &item )
+{
+ int ret = DAM_BASH;
+
+ if (item.base_type == OBJ_WEAPONS)
+ ret = (Weapon_prop[ Weapon_index[item.sub_type] ].dam_type & DAM_MASK);
+
+ return (ret);
+} // end damage_type()
+
+bool does_damage_type( const item_def &item, int dam_type )
+{
+ return (get_damage_type( item ) & dam_type);
+} // end does_damage_type()
+
+
+hands_reqd_type hands_reqd(int base_type, int sub_type, size_type size)
+{
+ item_def item;
+ item.base_type = base_type;
+ item.sub_type = sub_type;
+ return hands_reqd(item, size);
+}
+
+// give hands required to wield weapon for a torso of "size"
+hands_reqd_type hands_reqd( const item_def &item, size_type size )
+{
+ int ret = HANDS_ONE;
+ int fit;
+ bool doub = false;
+
+ switch (item.base_type)
+ {
+ case OBJ_STAVES:
+ case OBJ_WEAPONS:
+ // Merging staff with magical staves for consistency... doing
+ // as a special case because we want to be very flexible with
+ // these useful objects (we want spriggans and ogre magi to
+ // be able to use them).
+ if (item.base_type == OBJ_STAVES || item.sub_type == WPN_QUARTERSTAFF)
+ {
+ if (size < SIZE_SMALL)
+ ret = HANDS_TWO;
+ else if (size > SIZE_LARGE)
+ ret = HANDS_ONE;
+ else
+ ret = HANDS_HALF;
+ break;
+ }
+
+ ret = Weapon_prop[ Weapon_index[item.sub_type] ].hands;
+
+ // size is the level where we can use one hand for one end
+ if (ret == HANDS_DOUBLE)
+ {
+ doub = true;
+ ret = HANDS_HALF;
+ }
+
+ // adjust handedness for size only for non-whip melee weapons
+ if (!is_range_weapon( item )
+ && item.sub_type != WPN_WHIP
+ && item.sub_type != WPN_DEMON_WHIP)
+ {
+ fit = cmp_weapon_size( item, size );
+
+ // Adjust handedness for non-medium races:
+ // (XX values don't matter, see fit_weapon_wieldable_size)
+ //
+ // Spriggan Kobold Human Ogre Big Giant
+ // Little 0 0 0 XX XX XX
+ // Small +1 0 0 -2 XX XX
+ // Medium XX +1 0 -1 -2 XX
+ // Large XX XX 0 0 -1 -2
+ // Big XX XX XX 0 0 -1
+ // Giant XX XX XX XX 0 0
+
+ // Note the stretching of double weapons for larger characters
+ // by one level since they tend to be larger weapons.
+ if (size < SIZE_MEDIUM && fit > 0)
+ ret += fit;
+ else if (size > SIZE_MEDIUM && fit < 0)
+ ret += (fit + doub);
+ }
+ break;
+
+ case OBJ_CORPSES: // unwieldy
+ ret = HANDS_TWO;
+ break;
+
+ case OBJ_ARMOUR: // barding and body armours are unwieldy
+ if (item.sub_type == ARM_NAGA_BARDING
+ || item.sub_type == ARM_CENTAUR_BARDING
+ || get_armour_slot( item ) == EQ_BODY_ARMOUR)
+ {
+ ret = HANDS_TWO;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (ret > HANDS_TWO)
+ ret = HANDS_TWO;
+ else if (ret < HANDS_ONE)
+ ret = HANDS_ONE;
+
+ return (static_cast< hands_reqd_type >( ret ));
+}
+
+bool is_double_ended( const item_def &item )
+{
+ if (item.base_type == OBJ_STAVES)
+ return (true);
+ else if (item.base_type != OBJ_WEAPONS)
+ return (false);
+
+ return (Weapon_prop[ Weapon_index[item.sub_type] ].hands == HANDS_DOUBLE);
+}
+
+int double_wpn_awkward_speed( const item_def &item )
+{
+ ASSERT( is_double_ended( item ) );
+
+ const int base = property( item, PWPN_SPEED );
+
+ return ((base * 30 + 10) / 20 + 2);
+}
+
+
+bool is_demonic( const item_def &item )
+{
+ if (item.base_type == OBJ_WEAPONS)
+ {
+ switch (item.sub_type)
+ {
+ case WPN_DEMON_BLADE:
+ case WPN_DEMON_WHIP:
+ case WPN_DEMON_TRIDENT:
+ return (true);
+
+ default:
+ break;
+ }
+ }
+
+ return (false);
+} // end is_demonic()
+
+int weapon_str_weight( const item_def &wpn )
+{
+ ASSERT (wpn.base_type == OBJ_WEAPONS || wpn.base_type == OBJ_STAVES);
+
+ if (wpn.base_type == OBJ_STAVES)
+ return (Weapon_prop[ Weapon_index[WPN_QUARTERSTAFF] ].str_weight);
+
+ return (Weapon_prop[ Weapon_index[wpn.sub_type] ].str_weight);
+}
+
+int weapon_dex_weight( const item_def &wpn )
+{
+ return (10 - weapon_str_weight( wpn ));
+}
+
+int weapon_impact_mass( const item_def &wpn )
+{
+ ASSERT (wpn.base_type == OBJ_WEAPONS || wpn.base_type == OBJ_STAVES);
+
+ return ((weapon_str_weight( wpn ) * item_mass( wpn ) + 5) / 10);
+}
+
+int weapon_str_required( const item_def &wpn, bool hand_half )
+{
+ ASSERT (wpn.base_type == OBJ_WEAPONS || wpn.base_type == OBJ_STAVES);
+
+ const int req = weapon_impact_mass( wpn ) / ((hand_half) ? 11 : 10);
+
+ return ((req < STR_REQ_THRESHOLD) ? 0 : req);
+}
+
+// returns melee skill of item
+skill_type weapon_skill( const item_def &item )
+{
+ if (item.base_type == OBJ_WEAPONS && !is_range_weapon( item ))
+ return (Weapon_prop[ Weapon_index[item.sub_type] ].skill);
+ else if (item.base_type == OBJ_STAVES)
+ return (SK_STAVES);
+
+ // this is used to mark that only fighting applies.
+ return (SK_FIGHTING);
+}
+
+// front function for the above when we don't have a physical item to check
+skill_type weapon_skill( int wclass, int wtype )
+{
+ item_def wpn;
+
+ wpn.base_type = wclass;
+ wpn.sub_type = wtype;
+
+ return (weapon_skill( wpn ));
+} // end weapon_skill()
+
+// returns range skill of the item
+skill_type range_skill( const item_def &item )
+{
+ if (item.base_type == OBJ_WEAPONS && is_range_weapon( item ))
+ return (Weapon_prop[ Weapon_index[item.sub_type] ].skill);
+ else if (item.base_type == OBJ_MISSILES && item.sub_type == MI_DART)
+ return (SK_DARTS);
+
+ return (SK_RANGED_COMBAT);
+}
+
+// front function for the above when we don't have a physical item to check
+skill_type range_skill( int wclass, int wtype )
+{
+ item_def wpn;
+
+ wpn.base_type = wclass;
+ wpn.sub_type = wtype;
+
+ return (range_skill( wpn ));
+} // end weapon_skill()
+
+
+// Calculate the bonus to melee EV for using "wpn", with "skill" and "dex"
+// to protect a body of size "body".
+int weapon_ev_bonus( const item_def &wpn, int skill, size_type body, int dex,
+ bool hide_hidden )
+{
+ ASSERT( wpn.base_type == OBJ_WEAPONS || wpn.base_type == OBJ_STAVES );
+
+ int ret = 0;
+
+ // Note: ret currently measured in halves (see skill factor)
+ if (wpn.sub_type == WPN_WHIP || wpn.sub_type == WPN_DEMON_WHIP)
+ ret = 3 + (dex / 5);
+ else if (weapon_skill( wpn ) == SK_POLEARMS)
+ ret = 2 + (dex / 5);
+
+ // weapons of reaching are naturally a bit longer/flexier
+ if (!hide_hidden || item_ident( wpn, ISFLAG_KNOW_TYPE ))
+ {
+ if (get_weapon_brand( wpn ) == SPWPN_REACHING)
+ ret += 1;
+ }
+
+ // only consider additional modifications if we have a positive base:
+ if (ret > 0)
+ {
+ // Size factors:
+ // - large characters can't cover their flanks as well
+ // - note that not all weapons are available to small characters
+ if (body > SIZE_LARGE)
+ ret -= (4 * (body - SIZE_LARGE) - 2);
+ else if (body < SIZE_MEDIUM)
+ ret += 1;
+
+ // apply skill (and dividing by 2)
+ ret = (ret * (skill + 10)) / 20;
+
+ // make sure things can't get too insane
+ if (ret > 8)
+ ret = 8 + (ret - 8) / 2;
+ }
+
+ // Note: this is always a bonus
+ return ((ret > 0) ? ret : 0);
+}
+
+static size_type weapon_size( const item_def &item )
+{
+ ASSERT (item.base_type == OBJ_WEAPONS || item.base_type == OBJ_STAVES);
+
+ if (item.base_type == OBJ_STAVES)
+ return (Weapon_prop[ Weapon_index[WPN_QUARTERSTAFF] ].fit_size);
+
+ return (Weapon_prop[ Weapon_index[item.sub_type] ].fit_size);
+}
+
+// returns number of sizes off
+int cmp_weapon_size( const item_def &item, size_type size )
+{
+ ASSERT( item.base_type == OBJ_WEAPONS || item.base_type == OBJ_STAVES );
+
+ return (weapon_size( item ) - size);
+}
+
+// Returns number of sizes away from being a usable weapon
+int fit_weapon_wieldable_size( const item_def &item, size_type size )
+{
+ ASSERT( item.base_type == OBJ_WEAPONS || item.base_type == OBJ_STAVES );
+
+ const int fit = cmp_weapon_size( item, size );
+
+ return ((fit < -2) ? fit + 2 : (fit > 1) ? fit - 1 : 0);
+}
+
+// Returns number of sizes away from being throwable... the window
+// is currently [size - 5, size - 1].
+int fit_item_throwable_size( const item_def &item, size_type size )
+{
+ int ret = item_size( item ) - size;
+
+ return ((ret >= 0) ? ret + 1 : (ret > -6) ? 0 : ret + 5);
+}
+
+// Returns true if weapon is usable as a tool
+// Note that we assume that tool usable >= wieldable
+bool check_weapon_tool_size( const item_def &item, size_type size )
+{
+ ASSERT( item.base_type == OBJ_WEAPONS || item.base_type == OBJ_STAVES );
+
+ // Staves are currently usable for everyone just to be nice.
+ if (item.base_type == OBJ_STAVES || item.sub_type == WPN_QUARTERSTAFF)
+ return (true);
+
+ const int fit = cmp_weapon_size( item, size );
+
+ return (fit >= -3 && fit <= 1);
+}
+
+// Returns true if weapon is usable as a weapon
+bool check_weapon_wieldable_size( const item_def &item, size_type size )
+{
+ ASSERT( item.base_type == OBJ_WEAPONS || item.base_type == OBJ_STAVES );
+
+ return (fit_weapon_wieldable_size( item, size ) == 0);
+}
+
+// Note that this function is used to check validity of equipment
+// coming out of transformations... so it shouldn't contain any
+// wield/unwield only checks like two-handed weapons and shield.
+// check_id is only used for descriptions, where we don't want to
+// give away any information the player doesn't have yet.
+bool check_weapon_shape( const item_def &item, bool quiet, bool check_id )
+{
+ const int brand = get_weapon_brand( item );
+
+ if ((!check_id || item_ident( item, ISFLAG_KNOW_TYPE ))
+ && ((item.base_type == OBJ_WEAPONS
+ && item.sub_type == WPN_BLESSED_BLADE)
+ || brand == SPWPN_HOLY_WRATH
+ || brand == SPWPN_DISRUPTION)
+ && (you.is_undead || you.species == SP_DEMONSPAWN))
+ {
+ if (!quiet)
+ mpr( "This weapon will not allow you to wield it." );
+
+ return (false);
+ }
+
+ // Note: this should always be done last, see check_armour_shape()
+ // FIXME FIXME FIXME
+ /*
+ if (!transform_can_equip_type( EQ_WEAPON ))
+ {
+ if (!quiet)
+ mpr( "You can't wield anything in your current form!" );
+
+ return (false);
+ }
+ */
+
+ return (true);
+}
+
+// Returns the you.inv[] index of our wielded weapon or -1 (no item, not wield)
+int get_inv_wielded( void )
+{
+ return (player_weapon_wielded() ? you.equip[EQ_WEAPON] : -1);
+}
+
+// Returns the you.inv[] index of our hand tool or -1 (no item, not usable)
+// Note that we don't count armour and such as "tools" here because
+// this function is used to judge if the item will sticky curse to
+// our hands.
+int get_inv_hand_tool( void )
+{
+ const int tool = you.equip[EQ_WEAPON];
+
+ // FIXME
+ /*
+ if (tool == -1 || !is_tool( you.inv[tool] ))
+ return (-1);
+
+ if (you.inv[tool].base_type == OBJ_WEAPONS
+ || you.inv[tool].base_type == OBJ_STAVES)
+ {
+ // assuring that bad "shape" weapons aren't in hand
+ ASSERT( check_weapon_shape( you.inv[tool], false ) );
+
+ if (!check_weapon_tool_size( you.inv[tool], player_size() ))
+ return (-1);
+ }
+ */
+
+ return (tool);
+}
+
+// Returns the you.inv[] index of the thing in our hand... this is provided
+// as a service to specify that both of the above are irrelevant.
+// Do not use this for low level functions dealing with wielding directly.
+int get_inv_in_hand( void )
+{
+ return (you.equip[EQ_WEAPON]);
+}
+
+//
+// Launcher and ammo functions:
+//
+missile_type fires_ammo_type( const item_def &item )
+{
+ if (item.base_type != OBJ_WEAPONS)
+ return (MI_NONE);
+
+ return (Weapon_prop[ Weapon_index[item.sub_type] ].ammo);
+}
+
+missile_type fires_ammo_type( weapon_type wtype )
+{
+ item_def wpn;
+ wpn.base_type = OBJ_WEAPONS;
+ wpn.sub_type = wtype;
+
+ return (fires_ammo_type(wpn));
+}
+
+bool is_range_weapon( const item_def &item )
+{
+ return (fires_ammo_type( item ) != MI_NONE);
+}
+
+bool is_range_weapon_type( weapon_type wtype )
+{
+ item_def wpn;
+
+ wpn.base_type = OBJ_WEAPONS;
+ wpn.sub_type = wtype;
+
+ return (is_range_weapon( wpn ));
+}
+
+const char * ammo_name( const item_def &bow )
+{
+ ASSERT( is_range_weapon( bow ) );
+
+ const int ammo = fires_ammo_type( bow );
+
+ return (Missile_prop[ Missile_index[ammo] ].name);
+}
+
+// returns true if item can be reasonably thrown without a launcher
+bool is_throwable( const item_def &wpn )
+{
+ if (wpn.base_type == OBJ_WEAPONS)
+ return (Weapon_prop[ Weapon_index[wpn.sub_type] ].throwable);
+ else if (wpn.base_type == OBJ_MISSILES)
+ return (Missile_prop[ Missile_index[wpn.sub_type] ].throwable);
+
+ return (false);
+}
+
+// FIXME
+#if 0
+// decide if "being" is launching or throwing "ammo"
+launch_retval is_launched( int being_id, const item_def &ammo, bool msg )
+{
+ ASSERT( being_id != MHITNOT );
+
+ launch_retval ret = LRET_FUMBLED;
+
+ const item_def * lnch = 0;
+ int fit = 0;
+
+ if (being_id == MHITYOU)
+ {
+ const int wpn = get_inv_wielded();
+ lnch = (wpn == -1) ? 0 : &you.inv[wpn];
+ fit = fit_item_throwable_size( ammo, player_size() );
+ }
+ else // monster case
+ {
+ const int wpn = menv[being_id].inv[MSLOT_WEAPON];
+ lnch = (wpn == NON_ITEM) ? 0 : &mitm[wpn];
+ fit = fit_item_throwable_size( ammo, mons_size( menv[being_id].type ) );
+ }
+
+ if (lnch
+ && lnch->base_type == OBJ_WEAPONS
+ && is_range_weapon( *lnch )
+ && ammo.base_type == OBJ_MISSILES
+ && ammo.sub_type == fires_ammo_type( *lnch ))
+ {
+ ret = LRET_LAUNCHED;
+ }
+ else if (is_throwable( ammo ))
+ {
+ if (fit == 0)
+ ret = LRET_THROWN;
+ else
+ {
+ ret = LRET_FUMBLED;
+
+ if (being_id == MHITYOU && msg)
+ {
+ mpr( MSGCH_WARN, "It's difficult to throw such a%s object.",
+ (fit > 0) ? " large" : (fit < 0) ? " small" : "n awkward" );
+ }
+ }
+ }
+
+ return (ret);
+}
+#endif
+
+//
+// Staff/rod functions:
+//
+bool item_is_rod( const item_def &item )
+{
+ return (item.base_type == OBJ_STAVES
+ && item.sub_type >= STAFF_SMITING && item.sub_type < STAFF_AIR);
+}
+
+bool item_is_staff( const item_def &item )
+{
+ // Isn't De Morgan's law wonderful. -- bwr
+ return (item.base_type == OBJ_STAVES
+ && (item.sub_type < STAFF_SMITING || item.sub_type >= STAFF_AIR));
+}
+
+//
+// Ring functions:
+//
+// Returns number of pluses on jewellery (always none for amulets yet).
+int ring_has_pluses( const item_def &item )
+{
+ ASSERT (item.base_type == OBJ_JEWELLERY);
+
+ switch (item.sub_type)
+ {
+ case RING_SLAYING:
+ return (2);
+
+ case RING_PROTECTION:
+ case RING_EVASION:
+ case RING_STRENGTH:
+ case RING_INTELLIGENCE:
+ case RING_DEXTERITY:
+ return (1);
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+//
+// Food functions:
+//
+bool food_is_meat( const item_def &item )
+{
+ ASSERT( is_valid_item( item ) && item.base_type == OBJ_FOOD );
+
+ return (Food_prop[ Food_index[item.sub_type] ].carn_mod > 0);
+}
+
+bool food_is_veg( const item_def &item )
+{
+ ASSERT( is_valid_item( item ) && item.base_type == OBJ_FOOD );
+
+ return (Food_prop[ Food_index[item.sub_type] ].herb_mod > 0);
+}
+
+// returns food value for one turn of eating
+int food_value( const item_def &item )
+{
+ ASSERT( is_valid_item( item ) && item.base_type == OBJ_FOOD );
+
+ const int herb = you.mutation[MUT_HERBIVOROUS];
+
+ // XXX: this needs to be better merged with the mutation system
+ const int carn = (you.species == SP_KOBOLD || you.species == SP_GHOUL) ? 3
+ : you.mutation[MUT_CARNIVOROUS];
+
+ const food_def &food = Food_prop[ Food_index[item.sub_type] ];
+
+ int ret = food.value;
+
+ ret += (carn * food.carn_mod);
+ ret += (herb * food.herb_mod);
+
+ return ((ret > 0) ? div_rand_round( ret, food.turns ) : 0);
+}
+
+int food_turns( const item_def &item )
+{
+ ASSERT( is_valid_item( item ) && item.base_type == OBJ_FOOD );
+
+ return (Food_prop[ Food_index[item.sub_type] ].turns);
+}
+
+bool can_cut_meat( const item_def &item )
+{
+ return (does_damage_type( item, DAM_SLICE ));
+}
+
+// returns true if item counts as a tool for tool size comparisons and msgs
+bool is_tool( const item_def &item )
+{
+ // Currently using OBJ_WEAPONS instead of can_cut_meat() as almost
+ // any weapon might be an evocable artefact.
+ return (item.base_type == OBJ_WEAPONS
+ || item.base_type == OBJ_STAVES
+ || (item.base_type == OBJ_MISCELLANY
+ && item.sub_type != MISC_RUNE_OF_ZOT));
+}
+
+
+//
+// Generic item functions:
+//
+int property( const item_def &item, int prop_type )
+{
+ switch (item.base_type)
+ {
+ case OBJ_ARMOUR:
+ if (prop_type == PARM_AC)
+ return (Armour_prop[ Armour_index[item.sub_type] ].ac);
+ else if (prop_type == PARM_EVASION)
+ return (Armour_prop[ Armour_index[item.sub_type] ].ev);
+ break;
+
+ case OBJ_WEAPONS:
+ if (prop_type == PWPN_DAMAGE)
+ return (Weapon_prop[ Weapon_index[item.sub_type] ].dam);
+ else if (prop_type == PWPN_HIT)
+ return (Weapon_prop[ Weapon_index[item.sub_type] ].hit);
+ else if (prop_type == PWPN_SPEED)
+ return (Weapon_prop[ Weapon_index[item.sub_type] ].speed);
+ break;
+
+ case OBJ_MISSILES:
+ if (prop_type == PWPN_DAMAGE)
+ return (Missile_prop[ Missile_index[item.sub_type] ].dam);
+ break;
+
+ case OBJ_STAVES:
+ if (prop_type == PWPN_DAMAGE)
+ return (Weapon_prop[ Weapon_index[WPN_QUARTERSTAFF] ].dam);
+ else if (prop_type == PWPN_HIT)
+ return (Weapon_prop[ Weapon_index[WPN_QUARTERSTAFF] ].hit);
+ else if (prop_type == PWPN_SPEED)
+ return (Weapon_prop[ Weapon_index[WPN_QUARTERSTAFF] ].speed);
+ break;
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int item_mass( const item_def &item )
+{
+ int unit_mass = 0;
+
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ unit_mass = Weapon_prop[ Weapon_index[item.sub_type] ].mass;
+ break;
+
+ case OBJ_ARMOUR:
+ unit_mass = Armour_prop[ Armour_index[item.sub_type] ].mass;
+
+ if (get_equip_race( item ) == ISFLAG_ELVEN)
+ {
+ const int reduc = (unit_mass >= 25) ? unit_mass / 5 : 5;
+
+ // truncate to the nearest 5 and reduce the item mass:
+ unit_mass -= ((reduc / 5) * 5);
+ unit_mass = MAXIMUM( unit_mass, 5 );
+ }
+ break;
+
+ case OBJ_MISSILES:
+ unit_mass = Missile_prop[ Missile_index[item.sub_type] ].mass;
+ break;
+
+ case OBJ_FOOD:
+ unit_mass = Food_prop[ Food_index[item.sub_type] ].mass;
+ break;
+
+ case OBJ_WANDS:
+ unit_mass = 100;
+ break;
+
+ case OBJ_UNKNOWN_I:
+ unit_mass = 200; // labeled "books"
+ break;
+
+ case OBJ_SCROLLS:
+ unit_mass = 20;
+ break;
+
+ case OBJ_JEWELLERY:
+ unit_mass = 10;
+ break;
+
+ case OBJ_POTIONS:
+ unit_mass = 40;
+ break;
+
+ case OBJ_UNKNOWN_II:
+ unit_mass = 5; // labeled "gems"
+ break;
+
+ case OBJ_BOOKS:
+ unit_mass = 70;
+ break;
+
+ case OBJ_STAVES:
+ unit_mass = 130;
+ break;
+
+ case OBJ_ORBS:
+ unit_mass = 300;
+ break;
+
+ case OBJ_MISCELLANY:
+ switch (item.sub_type)
+ {
+ case MISC_BOTTLED_EFREET:
+ case MISC_CRYSTAL_BALL_OF_SEEING:
+ case MISC_CRYSTAL_BALL_OF_ENERGY:
+ case MISC_CRYSTAL_BALL_OF_FIXATION:
+ unit_mass = 150;
+ break;
+
+ default:
+ unit_mass = 100;
+ break;
+ }
+ break;
+
+ case OBJ_CORPSES:
+ unit_mass = mons_weight( item.plus );
+
+ if (item.sub_type == CORPSE_SKELETON)
+ unit_mass /= 10;
+ break;
+
+ default:
+ case OBJ_GOLD:
+ unit_mass = 0;
+ break;
+ }
+
+ return ((unit_mass > 0) ? unit_mass : 0);
+}
+
+// Note that this function, an item sizes in general aren't quite on the
+// same scale as PCs and monsters.
+size_type item_size( const item_def &item )
+{
+ int size = SIZE_TINY;
+
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ case OBJ_STAVES:
+ size = Weapon_prop[ Weapon_index[item.sub_type] ].fit_size - 1;
+ break;
+
+ case OBJ_ARMOUR:
+ size = SIZE_MEDIUM;
+ switch (item.sub_type)
+ {
+ case ARM_GLOVES:
+ case ARM_HELMET:
+ case ARM_CAP:
+ case ARM_BOOTS:
+ case ARM_BUCKLER:
+ // tiny armour
+ break;
+
+ case ARM_SHIELD:
+ size = SIZE_LITTLE;
+ break;
+
+ case ARM_LARGE_SHIELD:
+ size = SIZE_SMALL;
+ break;
+
+ default: // body armours and bardings
+ size = SIZE_MEDIUM;
+ break;
+ }
+ break;
+
+ case OBJ_MISSILES:
+ if (item.sub_type == MI_LARGE_ROCK)
+ size = SIZE_SMALL;
+ break;
+
+ case OBJ_MISCELLANY:
+ if (item.sub_type == MISC_PORTABLE_ALTAR_OF_NEMELEX)
+ {
+ size = SIZE_SMALL;
+ }
+ break;
+
+ case OBJ_CORPSES:
+ // FIXME
+ // size = mons_size( item.plus, PSIZE_BODY );
+ size = SIZE_SMALL;
+ break;
+
+ default: // sundry tiny items
+ break;
+ }
+
+ if (size < SIZE_TINY)
+ size = SIZE_TINY;
+ else if (size > SIZE_HUGE)
+ size = SIZE_HUGE;
+
+ return (static_cast<size_type>( size ));
+}
+
+// returns true if we might be interested in dumping the colour
+bool is_colourful_item( const item_def &item )
+{
+ bool ret = false;
+
+ switch (item.base_type)
+ {
+ case OBJ_ARMOUR:
+ if (item.sub_type == ARM_ROBE
+ || item.sub_type == ARM_CLOAK
+ || item.sub_type == ARM_CAP
+ || item.sub_type == ARM_NAGA_BARDING
+ || item.sub_type == ARM_CENTAUR_BARDING)
+ {
+ ret = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return (ret);
+}
+
+bool is_shield(const item_def &item)
+{
+ return item.base_type == OBJ_ARMOUR
+ && (item.sub_type == ARM_SHIELD
+ || item.sub_type == ARM_BUCKLER
+ || item.sub_type == ARM_LARGE_SHIELD);
+}
+
+// Returns true if the given item cannot be wielded with the given shield.
+// The currently equipped shield is used if no shield is passed in.
+bool is_shield_incompatible(const item_def &weapon, const item_def *shield)
+{
+ // If there's no shield, there's no problem.
+ if (!shield && !(shield = player_shield()))
+ return (false);
+
+ hands_reqd_type hand = hands_reqd(weapon, player_size());
+ return hand == HANDS_TWO
+ && !item_is_rod(weapon)
+ && !is_range_weapon(weapon);
+}