/*
 * File:       makeitem.cc
 * Summary:    Item creation routines.
 * Created by: haranp on Sat Apr 21 11:31:42 2007 UTC
 */

#include "AppHdr.h"

#include <algorithm>

#include "enum.h"
#include "externs.h"
#include "makeitem.h"

#include "artefact.h"
#include "colour.h"
#include "coord.h"
#include "decks.h"
#include "describe.h"
#include "dungeon.h"
#include "food.h"
#include "itemprop.h"
#include "items.h"
#include "misc.h"
#include "mon-util.h"
#include "player.h"
#include "random.h"
#include "spl-book.h"
#include "travel.h"
#include "view.h"

void item_set_appearance(item_def &item);

static bool _got_curare_roll(const int item_level)
{
    return one_chance_in(item_level > 27 ? 6   :
                         item_level < 2  ? 15  :
                         (364 - 7 * item_level) / 25);
}

static bool _got_distortion_roll(const int item_level)
{
    return (one_chance_in(25));
}

static int _exciting_colour()
{
    switch (random2(4))
    {
        case 0:  return YELLOW;
        case 1:  return LIGHTGREEN;
        case 2:  return LIGHTRED;
        case 3:  return LIGHTMAGENTA;
        default: return MAGENTA;
    }
}


static int _newwave_weapon_colour(const item_def &item)
{
    int item_colour = BLACK;
    // fixed artefacts get predefined colours

    std::string itname = item.name(DESC_PLAIN);
    lowercase(itname);

    const bool item_runed = itname.find(" runed ") != std::string::npos;
    const bool heav_runed = itname.find(" heavily ") != std::string::npos;

    if ( is_random_artefact(item) && (!item_runed || heav_runed) )
        return _exciting_colour();

    if (is_range_weapon(item))
    {
        switch (range_skill(item))
        {
        case SK_BOWS:
            item_colour = BLUE;
            break;
        case SK_CROSSBOWS:
            item_colour = LIGHTBLUE;
            break;
        case SK_DARTS:
            item_colour = WHITE;
            break;
        case SK_SLINGS:
            item_colour = BROWN;
            break;
        default:
            // huh?
            item_colour = MAGENTA;
            break;
        }
    }
    else
    {
        switch (weapon_skill(item))
        {
        case SK_SHORT_BLADES:
            item_colour = CYAN;
            break;
        case SK_LONG_BLADES:
            item_colour = LIGHTCYAN;
            break;
        case SK_AXES:
            item_colour = DARKGREY;
            break;
        case SK_MACES_FLAILS:
            item_colour = LIGHTGREY;
            break;
        case SK_POLEARMS:
            item_colour = RED;
            break;
        case SK_STAVES:
            item_colour = GREEN;
            break;
        default:
            // huh?
            item_colour = random_colour();
            break;
        }
    }

    return (item_colour);
}

static int _classic_weapon_colour(const item_def &item)
{
    int item_colour = BLACK;

    if (is_range_weapon(item))
        item_colour = BROWN;
    else
    {
        switch (item.sub_type)
        {
        case WPN_CLUB:
        case WPN_GIANT_CLUB:
        case WPN_GIANT_SPIKED_CLUB:
        case WPN_ANKUS:
        case WPN_WHIP:
        case WPN_QUARTERSTAFF:
            item_colour = BROWN;
            break;
        case WPN_QUICK_BLADE:
            item_colour = LIGHTBLUE;
            break;
        case WPN_EXECUTIONERS_AXE:
            item_colour = RED;
            break;
        default:
            item_colour = LIGHTCYAN;
            if (get_equip_race(item) == ISFLAG_DWARVEN)
                item_colour = CYAN;
            break;
        }
    }

    return (item_colour);
}

static int _weapon_colour(const item_def &item)
{
    return (Options.classic_item_colours ? _classic_weapon_colour(item)
                                         : _newwave_weapon_colour(item));
}

static int _newwave_missile_colour(const item_def &item)
{
    int item_colour = BLACK;
    switch (item.sub_type)
    {
    case MI_STONE:
    case MI_SLING_BULLET:
    case MI_LARGE_ROCK:
        item_colour = BROWN;
        break;
    case MI_ARROW:
        item_colour = BLUE;
        break;
    case MI_NEEDLE:
        item_colour = WHITE;
        break;
    case MI_BOLT:
        item_colour = LIGHTBLUE;
        break;
    case MI_DART:
        item_colour = CYAN;
        break;
    case MI_JAVELIN:
        item_colour = RED;
        break;
    case MI_THROWING_NET:
        item_colour = DARKGREY;
        break;
    default:
        // huh?
        item_colour = LIGHTCYAN;
        if (get_equip_race(item) == ISFLAG_DWARVEN)
            item_colour = CYAN;
        break;
    }
    return (item_colour);
}

static int _classic_missile_colour(const item_def &item)
{
    int item_colour = BLACK;
    switch (item.sub_type)
    {
    case MI_STONE:
    case MI_LARGE_ROCK:
    case MI_ARROW:
        item_colour = BROWN;
        break;
    case MI_SLING_BULLET:
        item_colour = BLUE;
        break;
    case MI_NEEDLE:
        item_colour = WHITE;
        break;
    case MI_THROWING_NET:
        item_colour = DARKGREY;
        break;
    default:
        item_colour = LIGHTCYAN;
        if (get_equip_race(item) == ISFLAG_DWARVEN)
            item_colour = CYAN;
        break;
    }
    return (item_colour);
}

static int _missile_colour(const item_def &item)
{
    return (Options.classic_item_colours ? _classic_missile_colour(item)
                                         : _newwave_missile_colour(item));
}

static int _newwave_armour_colour(const item_def &item)
{
    int item_colour = BLACK;
    std::string itname = item.name(DESC_PLAIN);
    lowercase(itname);

    const bool item_runed = itname.find(" runed ") != std::string::npos;
    const bool heav_runed = itname.find(" heavily ") != std::string::npos;

    if (is_random_artefact(item) && (!item_runed || heav_runed))
        return (_exciting_colour());

    switch (item.sub_type)
    {
      case ARM_CLOAK:
        item_colour = WHITE;
        break;
      case ARM_NAGA_BARDING:
      case ARM_CENTAUR_BARDING:
        item_colour = GREEN;
        break;
      case ARM_ROBE:
        item_colour = RED;
        break;
      case ARM_CAP:
      case ARM_WIZARD_HAT:
        item_colour = MAGENTA;
        break;
      case ARM_HELMET:
        item_colour = DARKGREY;
        break;
      case ARM_BOOTS:
        item_colour = BLUE;
        break;
      case ARM_GLOVES:
        item_colour = LIGHTBLUE;
        break;
      case ARM_LEATHER_ARMOUR:
        item_colour = BROWN;
        break;
      case ARM_ANIMAL_SKIN:
        item_colour = LIGHTGREY;
        break;
      case ARM_CRYSTAL_PLATE_MAIL:
        item_colour = WHITE;
        break;
      case ARM_SHIELD:
      case ARM_LARGE_SHIELD:
      case ARM_BUCKLER:
        item_colour = CYAN;
        break;
      default:
        item_colour = LIGHTCYAN;
        break;
    }

    return (item_colour);
}

static int _classic_armour_colour(const item_def &item)
{
    int item_colour = BLACK;
    switch (item.sub_type)
    {
    case ARM_CLOAK:
    case ARM_ROBE:
    case ARM_NAGA_BARDING:
    case ARM_CENTAUR_BARDING:
    case ARM_CAP:
    case ARM_WIZARD_HAT:
        item_colour = random_colour();
        break;
    case ARM_HELMET:
        item_colour = LIGHTCYAN;
        break;
    case ARM_BOOTS: // maybe more interesting boot colours?
    case ARM_GLOVES:
    case ARM_LEATHER_ARMOUR:
        item_colour = BROWN;
        break;
    case ARM_CRYSTAL_PLATE_MAIL:
        item_colour = LIGHTGREY;
        break;
    case ARM_ANIMAL_SKIN:
        item_colour = BROWN;
        break;
    default:
        item_colour = LIGHTCYAN;
        if (get_equip_race(item) == ISFLAG_DWARVEN)
            item_colour = CYAN;
        break;
    }
    return (item_colour);
}

static int _armour_colour(const item_def &item)
{
    return (Options.classic_item_colours ? _classic_armour_colour(item)
                                         : _newwave_armour_colour(item));
}

void item_colour(item_def &item)
{
    int switchnum = 0;
    int temp_value;

    switch (item.base_type)
    {
    case OBJ_WEAPONS:
        if (is_unrandom_artefact(item))
            break;              // unrandarts already coloured

        if (is_demonic(item))
            item.colour = random_uncommon_colour();
        else
            item.colour = _weapon_colour(item);

        if (is_random_artefact(item) && one_chance_in(5)
            && Options.classic_item_colours)
        {
            item.colour = random_colour();
        }
        break;

    case OBJ_MISSILES:
        item.colour = _missile_colour(item);
        break;

    case OBJ_ARMOUR:
        if (is_unrandom_artefact(item))
            break;              // unrandarts have already been coloured

        switch (item.sub_type)
        {
        case ARM_DRAGON_HIDE:
        case ARM_DRAGON_ARMOUR:
            item.colour = mons_class_colour(MONS_DRAGON);
            break;
        case ARM_TROLL_HIDE:
        case ARM_TROLL_LEATHER_ARMOUR:
            item.colour = mons_class_colour(MONS_TROLL);
            break;
        case ARM_ICE_DRAGON_HIDE:
        case ARM_ICE_DRAGON_ARMOUR:
            item.colour = mons_class_colour(MONS_ICE_DRAGON);
            break;
        case ARM_STEAM_DRAGON_HIDE:
        case ARM_STEAM_DRAGON_ARMOUR:
            item.colour = mons_class_colour(MONS_STEAM_DRAGON);
            break;
        case ARM_MOTTLED_DRAGON_HIDE:
        case ARM_MOTTLED_DRAGON_ARMOUR:
            item.colour = mons_class_colour(MONS_MOTTLED_DRAGON);
            break;
        case ARM_STORM_DRAGON_HIDE:
        case ARM_STORM_DRAGON_ARMOUR:
            item.colour = mons_class_colour(MONS_STORM_DRAGON);
            break;
        case ARM_GOLD_DRAGON_HIDE:
        case ARM_GOLD_DRAGON_ARMOUR:
            item.colour = mons_class_colour(MONS_GOLDEN_DRAGON);
            break;
        case ARM_SWAMP_DRAGON_HIDE:
        case ARM_SWAMP_DRAGON_ARMOUR:
            item.colour = mons_class_colour(MONS_SWAMP_DRAGON);
            break;
        default:
            item.colour = _armour_colour(item);
            break;
        }

        // I don't think this is ever done -- see start of case {dlb}:
        if (is_random_artefact(item) && one_chance_in(5))
            item.colour = random_colour();
        break;

    case OBJ_WANDS:
        item.special = you.item_description[IDESC_WANDS][item.sub_type];

        switch (item.special % 12)
        {
        case 0:         //"iron wand"
            item.colour = CYAN;
            break;
        case 1:         //"brass wand"
        case 5:         //"gold wand"
            item.colour = YELLOW;
            break;
        case 2:         //"bone wand"
        case 8:         //"ivory wand"
        case 9:         //"glass wand"
        case 10:        //"lead wand"
        default:
            item.colour = LIGHTGREY;
            break;
        case 3:         //"wooden wand"
        case 4:         //"copper wand"
        case 7:         //"bronze wand"
            item.colour = BROWN;
            break;
        case 6:         //"silver wand"
            item.colour = WHITE;
            break;
        case 11:        //"fluorescent wand"
            item.colour = random_colour();
            break;
        }

        if (item.special / 12 == 9) // "blackened foo wand"
            item.colour = DARKGREY;

        break;

    case OBJ_POTIONS:
        item.plus = you.item_description[IDESC_POTIONS][item.sub_type];

        switch (item.plus % 14)
        {
        case 0:         //"clear potion"
        default:
            item.colour = LIGHTGREY;
            break;
        case 1:         //"blue potion"
        case 7:         //"inky potion"
            item.colour = BLUE;
            break;
        case 2:         //"black potion"
            item.colour = DARKGREY;
            break;
        case 3:         //"silvery potion"
        case 13:        //"white potion"
            item.colour = WHITE;
            break;
        case 4:         //"cyan potion"
            item.colour = CYAN;
            break;
        case 5:         //"purple potion"
            item.colour = MAGENTA;
            break;
        case 6:         //"orange potion"
            item.colour = LIGHTRED;
            break;
        case 8:         //"red potion"
            item.colour = RED;
            break;
        case 9:         //"yellow potion"
            item.colour = YELLOW;
            break;
        case 10:        //"green potion"
            item.colour = GREEN;
            break;
        case 11:        //"brown potion"
            item.colour = BROWN;
            break;
        case 12:        //"pink potion"
            item.colour = LIGHTMAGENTA;
            break;
        }
        break;

    case OBJ_FOOD:
        switch (item.sub_type)
        {
        case FOOD_BEEF_JERKY:
        case FOOD_BREAD_RATION:
        case FOOD_LYCHEE:
        case FOOD_MEAT_RATION:
        case FOOD_RAMBUTAN:
        case FOOD_SAUSAGE:
        case FOOD_SULTANA:
            item.colour = BROWN;
            break;
        case FOOD_BANANA:
        case FOOD_CHEESE:
        case FOOD_HONEYCOMB:
        case FOOD_LEMON:
        case FOOD_PIZZA:
        case FOOD_ROYAL_JELLY:
            item.colour = YELLOW;
            break;
        case FOOD_PEAR:
            item.colour = LIGHTGREEN;
            break;
        case FOOD_CHOKO:
        case FOOD_SNOZZCUMBER:
            item.colour = GREEN;
            break;
        case FOOD_APRICOT:
        case FOOD_ORANGE:
            item.colour = LIGHTRED;
            break;
        case FOOD_STRAWBERRY:
            item.colour = RED;
            break;
        case FOOD_APPLE:
            item.colour = (coinflip() ? RED : GREEN);
            break;
        case FOOD_GRAPE:
            item.colour = (coinflip() ? MAGENTA : GREEN);
            break;
        case FOOD_CHUNK:
            // Set the appropriate colour of the meat:
            temp_value  = mons_class_colour(item.plus);
            item.colour = (temp_value == BLACK) ? LIGHTRED : temp_value;
            break;
        default:
            item.colour = BROWN;
        }
        break;

    case OBJ_JEWELLERY:
        // unrandarts have already been coloured
        if (is_unrandom_artefact(item))
            break;
        else if (is_random_artefact(item))
        {
            item.colour = random_colour();
            break;
        }

        item.colour  = YELLOW;
        item.special = you.item_description[IDESC_RINGS][item.sub_type];

        switchnum = item.special % 13;

        switch (switchnum)
        {
        case 0:
        case 5:
            item.colour = BROWN;
            break;
        case 1:
        case 8:
        case 11:
            item.colour = LIGHTGREY;
            break;
        case 2:
        case 6:
            item.colour = YELLOW;
            break;
        case 3:
        case 4:
            item.colour = CYAN;
            break;
        case 7:
            item.colour = BROWN;
            break;
        case 9:
        case 10:
            item.colour = WHITE;
            break;
        case 12:
            item.colour = GREEN;
            break;
        case 13:
            item.colour = LIGHTCYAN;
            break;
        }

        if (item.sub_type >= AMU_RAGE)
        {
            switch (switchnum)
            {
            case 0:             // "zirconium amulet"
            case 9:             // "ivory amulet"
            case 11:            // "platinum amulet"
                item.colour = WHITE;
                break;
            case 1:             // "sapphire amulet"
                item.colour = LIGHTBLUE;
                break;
            case 2:             // "golden amulet"
            case 6:             // "brass amulet"
                item.colour = YELLOW;
                break;
            case 3:             // "emerald amulet"
                item.colour = GREEN;
                break;
            case 4:             // "garnet amulet"
            case 8:             // "ruby amulet"
                item.colour = RED;
                break;
            case 5:             // "bronze amulet"
            case 7:             // "copper amulet"
                item.colour = BROWN;
                break;
            case 10:            // "bone amulet"
                item.colour = LIGHTGREY;
                break;
            case 12:            // "jade amulet"
                item.colour = GREEN;
                break;
            case 13:            // "fluorescent amulet"
                item.colour = random_colour();
            }
        }

        // blackened - same for both rings and amulets
        if (item.special / 13 == 5)
            item.colour = DARKGREY;
        break;

    case OBJ_SCROLLS:
        item.colour  = LIGHTGREY;
        item.special = you.item_description[IDESC_SCROLLS][item.sub_type];
        item.plus = you.item_description[IDESC_SCROLLS_II][item.sub_type];
        break;

    case OBJ_BOOKS:
        switch (item.special % 10)
        {
        case 0:
        case 1:
        default:
            item.colour = random_colour();
            break;
        case 2:
            item.colour = (one_chance_in(3) ? BROWN : DARKGREY);
            break;
        case 3:
            item.colour = CYAN;
            break;
        case 4:
            item.colour = LIGHTGREY;
            break;
        }
        break;

    case OBJ_STAVES:
        item.colour  = BROWN;
        item.special = you.item_description[IDESC_STAVES][item.sub_type];
        break;

    case OBJ_ORBS:
        item.colour = ETC_MUTAGENIC;
        break;

    case OBJ_MISCELLANY:
        if (is_deck(item))
            break;

        switch (item.sub_type)
        {
        case MISC_BOTTLED_EFREET:
        case MISC_STONE_OF_EARTH_ELEMENTALS:
            item.colour = BROWN;
            break;

        case MISC_AIR_ELEMENTAL_FAN:
        case MISC_CRYSTAL_BALL_OF_ENERGY:
        case MISC_CRYSTAL_BALL_OF_FIXATION:
        case MISC_CRYSTAL_BALL_OF_SEEING:
        case MISC_DISC_OF_STORMS:
        case MISC_HORN_OF_GERYON:
        case MISC_LANTERN_OF_SHADOWS:
            item.colour = LIGHTGREY;
            break;

        case MISC_LAMP_OF_FIRE:
            item.colour = YELLOW;
            break;

        case MISC_BOX_OF_BEASTS:
            item.colour = DARKGREY;
            break;

        case MISC_RUNE_OF_ZOT:
            switch (item.plus)
            {
            case RUNE_DIS:                      // iron
                item.colour = ETC_IRON;
                break;

            case RUNE_COCYTUS:                  // icy
                item.colour = ETC_ICE;
                break;

            case RUNE_TARTARUS:                 // bone
                item.colour = ETC_BONE;
                break;

            case RUNE_SLIME_PITS:               // slimy
                item.colour = ETC_SLIME;
                break;

            case RUNE_SNAKE_PIT:                // serpentine
                item.colour = ETC_POISON;
                break;

            case RUNE_ELVEN_HALLS:              // elven
                item.colour = ETC_ELVEN;
                break;

            case RUNE_VAULTS:                   // silver
                item.colour = ETC_SILVER;
                break;

            case RUNE_TOMB:                     // golden
                item.colour = ETC_GOLD;
                break;

            case RUNE_SWAMP:                    // decaying
                item.colour = ETC_DECAY;
                break;

            case RUNE_SHOALS:                   // barnacled
                item.colour = ETC_WATER;
                break;

            // This one is hardly unique, but colour isn't used for
            // stacking, so we don't have to worry too much about this. -- bwr
            case RUNE_DEMONIC:             // random pandemonium demonlords
            {
                element_type types[] =
                    {ETC_EARTH, ETC_ELECTRICITY, ETC_ENCHANT, ETC_HEAL,
                     ETC_BLOOD, ETC_DEATH, ETC_UNHOLY, ETC_VEHUMET, ETC_BEOGH,
                     ETC_CRYSTAL, ETC_SMOKE, ETC_DWARVEN, ETC_ORCISH, ETC_GILA};

                item.colour = RANDOM_ELEMENT(types);
                break;
            }

            case RUNE_ABYSSAL:             // random in abyss
                item.colour = ETC_RANDOM;
                break;

            case RUNE_MNOLEG:                   // glowing
                item.colour = ETC_MUTAGENIC;
                break;

            case RUNE_LOM_LOBON:                // magical
                item.colour = ETC_MAGIC;
                break;

            case RUNE_CEREBOV:                  // fiery
                item.colour = ETC_FIRE;
                break;

            case RUNE_GEHENNA:                  // obsidian
            case RUNE_GLOORX_VLOQ:              // dark
            default:
                item.colour = ETC_DARK;
                break;
            }
            break;

        case MISC_EMPTY_EBONY_CASKET:
            item.colour = DARKGREY;
            break;

        default:
            item.colour = random_colour();
            break;
        }
        break;

    case OBJ_CORPSES:
        // Set the appropriate colour of the body:
        temp_value  = mons_class_colour(item.plus);
        item.colour = (temp_value == BLACK) ? LIGHTRED : temp_value;
        break;

    case OBJ_GOLD:
        item.colour = YELLOW;
        break;
    default:
        break;
    }
}

// Does Xom consider an item boring?
static bool _is_boring_item(int type, int sub_type)
{
    switch (type)
    {
    case OBJ_POTIONS:
        return (sub_type == POT_CURE_MUTATION);
    case OBJ_SCROLLS:
        // These scrolls increase knowledge and thus reduce risk.
        switch (sub_type)
        {
        case SCR_DETECT_CURSE:
        case SCR_REMOVE_CURSE:
        case SCR_IDENTIFY:
        case SCR_MAGIC_MAPPING:
            return (true);
        default:
            break;
        }
        break;
    case OBJ_JEWELLERY:
        return (sub_type == RING_TELEPORT_CONTROL
                || sub_type == AMU_RESIST_MUTATION);
    default:
        break;
    }
    return (false);
}

static weapon_type _determine_weapon_subtype(int item_level)
{
    weapon_type rc = WPN_UNKNOWN;

    const weapon_type common_subtypes[] = {
        WPN_KNIFE, WPN_QUARTERSTAFF, WPN_SLING,
        WPN_SPEAR, WPN_HAND_AXE, WPN_MACE,
        WPN_DAGGER, WPN_DAGGER, WPN_CLUB,
        WPN_HAMMER, WPN_WHIP, WPN_SABRE
    };

    const weapon_type rare_subtypes[] = {
        WPN_LAJATANG, WPN_DEMON_WHIP, WPN_DEMON_BLADE,
        WPN_DEMON_TRIDENT, WPN_DOUBLE_SWORD, WPN_EVENINGSTAR,
        WPN_EXECUTIONERS_AXE, WPN_KATANA, WPN_QUICK_BLADE,
        WPN_TRIPLE_SWORD
    };

    if (item_level > 6 && one_chance_in(30)
        && x_chance_in_y(10 + item_level, 100))
    {
        rc = RANDOM_ELEMENT(rare_subtypes);
    }
    else if (x_chance_in_y(20 - item_level, 20))
        rc = RANDOM_ELEMENT(common_subtypes);
    else
    {
        // Pick a weapon based on rarity.
        while (true)
        {
            const int wpntype = random2(NUM_WEAPONS);

            if (x_chance_in_y(weapon_rarity(wpntype), 10))
            {
                rc = static_cast<weapon_type>(wpntype);
                break;
            }
        }
    }
    return rc;
}

static bool _try_make_item_special_unrand(item_def& item, int force_type,
                                          int item_level)
{
#ifdef DEBUG_DIAGNOSTICS
    mprf(MSGCH_DIAGNOSTICS, "Making special unrand artefact.");
#endif

    bool abyss = item_level == level_id(LEVEL_ABYSS).absdepth();
    int idx = find_okay_unrandart(item.base_type, force_type,
                                  UNRANDSPEC_SPECIAL, abyss);

    if (idx != -1 && make_item_unrandart(item, idx))
        return (true);

    return (false);
}

// Return whether we made an artefact.
static bool _try_make_weapon_artefact(item_def& item, int force_type,
                                      int item_level)
{
    if (item.sub_type != WPN_CLUB && item_level > 2
        && x_chance_in_y(101 + item_level * 3, 4000))
    {
        // Make a randart or unrandart.

        // 1 in 50 randarts are unrandarts.
        if (you.level_type != LEVEL_ABYSS
            && you.level_type != LEVEL_PANDEMONIUM
            && one_chance_in(50))
        {
            const int idx = find_okay_unrandart(OBJ_WEAPONS, force_type,
                                                UNRANDSPEC_NORMAL);
            if (idx != -1)
            {
                make_item_unrandart(item, idx);
                return (true);
            }
        }

        // The other 98% are normal randarts.
        make_item_randart(item);
        item.plus  = random2(7);
        item.plus2 = random2(7);

        if (one_chance_in(3))
            item.plus += random2(7);

        if (one_chance_in(3))
            item.plus2 += random2(7);

        if (one_chance_in(9))
            item.plus -= random2(7);

        if (one_chance_in(9))
            item.plus2 -= random2(7);

        if (one_chance_in(4))
        {
            do_curse_item(item);
            item.plus  = -random2(6);
            item.plus2 = -random2(6);
        }
        else if ((item.plus < 0 || item.plus2 < 0)
                 && !one_chance_in(3))
        {
            do_curse_item(item);
        }
        return (true);
    }

    // If it isn't an artefact yet, try to make a special unrand artefact.
    if (item_level > 6
        && one_chance_in(12)
        && x_chance_in_y(31 + item_level * 3, 3000))
    {
        return (_try_make_item_special_unrand(item, force_type, item_level));
    }

    return (false);
}

static item_status_flag_type _determine_weapon_race(const item_def& item,
                                                    int item_race)
{
    item_status_flag_type rc = ISFLAG_NO_RACE;
    switch (item_race)
    {
    case MAKE_ITEM_ELVEN:
        rc = ISFLAG_ELVEN;
        break;

    case MAKE_ITEM_DWARVEN:
        rc = ISFLAG_DWARVEN;
        break;

    case MAKE_ITEM_ORCISH:
        rc = ISFLAG_ORCISH;
        break;

    case MAKE_ITEM_RANDOM_RACE:
        if (coinflip())
            break;

        switch (item.sub_type)
        {
        case WPN_CLUB:
            if (coinflip())
                rc = ISFLAG_ORCISH;
            break;

        case WPN_WHIP:
            if (one_chance_in(4))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(4))
                rc = ISFLAG_ELVEN;
            break;

        case WPN_MACE:
        case WPN_FLAIL:
        case WPN_SPIKED_FLAIL:
        case WPN_GREAT_MACE:
        case WPN_DIRE_FLAIL:
            if (one_chance_in(4))
                rc = ISFLAG_DWARVEN;
            if (one_chance_in(3))
                rc = ISFLAG_ORCISH;
            break;

        case WPN_MORNINGSTAR:
        case WPN_HAMMER:
            if (one_chance_in(3))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(3))
                rc = ISFLAG_DWARVEN;
            break;

        case WPN_EVENINGSTAR:
            if (one_chance_in(5))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(5))
                rc = ISFLAG_DWARVEN;
            break;

        case WPN_DAGGER:
            if (one_chance_in(3))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(4))
                rc = ISFLAG_DWARVEN;
            if (one_chance_in(4))
                rc = ISFLAG_ELVEN;
            break;

        case WPN_SHORT_SWORD:
        case WPN_SABRE:
            if (one_chance_in(3))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(3))
                rc = ISFLAG_DWARVEN;
            if (one_chance_in(3))
                rc = ISFLAG_ELVEN;
            break;

        case WPN_FALCHION:
            if (one_chance_in(5))
                rc = ISFLAG_DWARVEN;
            if (one_chance_in(3))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(3))
                rc = ISFLAG_ELVEN;
            break;

        case WPN_LONG_SWORD:
            if (one_chance_in(6))
                rc = ISFLAG_DWARVEN;
            if (one_chance_in(4))
                rc = ISFLAG_ORCISH;
            if (coinflip())
                rc = ISFLAG_ELVEN;
            break;

        case WPN_GREAT_SWORD:
            if (one_chance_in(3))
                rc = ISFLAG_ORCISH;
            break;

        case WPN_SCIMITAR:
            if (one_chance_in(5))
                rc = ISFLAG_ELVEN;
            if (coinflip())
                rc = ISFLAG_ORCISH;
            break;

        case WPN_WAR_AXE:
        case WPN_HAND_AXE:
        case WPN_BROAD_AXE:
        case WPN_BATTLEAXE:
            if (one_chance_in(3))
                rc = ISFLAG_ORCISH;
            if (coinflip())
                rc = ISFLAG_DWARVEN;
            break;

        case WPN_SPEAR:
        case WPN_TRIDENT:
            if (one_chance_in(4))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(4))
                rc = ISFLAG_ELVEN;
            break;

        case WPN_HALBERD:
        case WPN_GLAIVE:
        case WPN_BARDICHE:
            if (one_chance_in(5))
                rc = ISFLAG_ORCISH;
            break;

        case WPN_EXECUTIONERS_AXE:
            if (one_chance_in(5))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(4))
                rc = ISFLAG_DWARVEN;
            break;

        case WPN_QUICK_BLADE:
            if (one_chance_in(4))
                rc = ISFLAG_ELVEN;
            break;

        case WPN_BOW:
            if (one_chance_in(6))
                rc = ISFLAG_ORCISH;
            if (coinflip())
                rc = ISFLAG_ELVEN;
            break;

        case WPN_LONGBOW:
            if (one_chance_in(3))
                rc = ISFLAG_ELVEN;
            break;

        case WPN_CROSSBOW:
            if (one_chance_in(4))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(4))
                rc = ISFLAG_DWARVEN;
            break;

        case WPN_HAND_CROSSBOW:
            if (one_chance_in(3))
                rc = ISFLAG_ELVEN;
            break;

        case WPN_BLOWGUN:
            if (one_chance_in(6))
                rc = ISFLAG_ELVEN;
            if (one_chance_in(4))
                rc = ISFLAG_ORCISH;
            break;
        }
        break;
    }
    return rc;
}

static void _weapon_add_racial_modifiers(item_def& item)
{
    switch (get_equip_race(item))
    {
    case ISFLAG_ORCISH:
        if (coinflip())
            item.plus--;
        if (coinflip())
            item.plus2++;
        break;

    case ISFLAG_ELVEN:
        item.plus += random2(3);
        break;

    case ISFLAG_DWARVEN:
        if (coinflip())
            item.plus++;
        if (coinflip())
            item.plus2++;
        break;
    }
}

static brand_type _determine_weapon_brand(const item_def& item, int item_level)
{
    // Forced ego.
    if (item.special != 0)
        return static_cast<brand_type>(item.special);

    const bool force_good = (item_level == MAKE_GOOD_ITEM);
    const int tries       = force_good ? 5 : 1;
    brand_type rc         = SPWPN_NORMAL;

    for (int count = 0; count < tries && rc == SPWPN_NORMAL; ++count)
    {
        if (!force_good && !is_demonic(item)
            && !x_chance_in_y(101 + item_level, 300))
        {
            continue;
        }

        // We are not guaranteed to have a special set by the end of
        // this.
        switch (item.sub_type)
        {
        case WPN_EVENINGSTAR:
            if (coinflip())
                rc = SPWPN_DRAINING;
            // **** intentional fall through here ****
        case WPN_MORNINGSTAR:
            if (one_chance_in(4))
                rc = SPWPN_VENOM;

            if (one_chance_in(4))
                rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;

            if (one_chance_in(20))
                rc = SPWPN_VAMPIRICISM;
            // **** intentional fall through here ****
        case WPN_MACE:
        case WPN_GREAT_MACE:
        case WPN_FLAIL:
        case WPN_SPIKED_FLAIL:
        case WPN_DIRE_FLAIL:
        case WPN_HAMMER:
            if (one_chance_in(25))
                rc = SPWPN_PAIN;

            if (_got_distortion_roll(item_level))
                rc = SPWPN_DISTORTION;

            if (one_chance_in(3) && (rc == SPWPN_NORMAL || one_chance_in(5)))
                rc = SPWPN_VORPAL;

            if (one_chance_in(4))
                rc = SPWPN_HOLY_WRATH;

            if (one_chance_in(3))
                rc = SPWPN_PROTECTION;

            if (one_chance_in(10))
                rc = SPWPN_DRAINING;
            break;


        case WPN_DAGGER:
            if (one_chance_in(4))
                rc = SPWPN_RETURNING;

            if (one_chance_in(10))
                rc = SPWPN_PAIN;

            if (one_chance_in(3))
                rc = SPWPN_VENOM;
            // **** intentional fall through here ****

        case WPN_SHORT_SWORD:
        case WPN_SABRE:
            if (_got_distortion_roll(item_level))
                rc = SPWPN_DISTORTION;

            if (one_chance_in(10))
                rc = SPWPN_VAMPIRICISM;

            if (one_chance_in(8))
                rc = SPWPN_ELECTROCUTION;

            if (one_chance_in(8))
                rc = SPWPN_PROTECTION;

            if (one_chance_in(8))
                rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;

            if (one_chance_in(12))
                rc = SPWPN_HOLY_WRATH;

            if (one_chance_in(8))
                rc = SPWPN_DRAINING;

            if (one_chance_in(8))
                rc = SPWPN_SPEED;

            if (one_chance_in(6))
                rc = SPWPN_VENOM;
            break;

        case WPN_FALCHION:
        case WPN_LONG_SWORD:
            if (one_chance_in(12))
                rc = SPWPN_VENOM;
            // **** intentional fall through here ****
        case WPN_SCIMITAR:
            if (one_chance_in(25))
                rc = SPWPN_PAIN;

            if (one_chance_in(7))
                rc = SPWPN_SPEED;
            // **** intentional fall through here ****
        case WPN_GREAT_SWORD:
        case WPN_DOUBLE_SWORD:
        case WPN_TRIPLE_SWORD:
            if (one_chance_in(10))
                rc = SPWPN_VAMPIRICISM;

            if (_got_distortion_roll(item_level))
                rc = SPWPN_DISTORTION;

            if (one_chance_in(5))
                rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;

            if (one_chance_in(7))
                rc = SPWPN_PROTECTION;

            if (one_chance_in(12))
                rc = SPWPN_DRAINING;

            if (one_chance_in(7))
                rc = SPWPN_ELECTROCUTION;

            if (one_chance_in(4))
                rc = SPWPN_HOLY_WRATH;

            if (one_chance_in(4) && (rc == SPWPN_NORMAL || one_chance_in(3)))
                rc = SPWPN_VORPAL;
            break;

        case WPN_WAR_AXE:
        case WPN_BROAD_AXE:
        case WPN_BATTLEAXE:
        case WPN_EXECUTIONERS_AXE:
            if (one_chance_in(25))
                rc = SPWPN_HOLY_WRATH;

            if (one_chance_in(14))
                rc = SPWPN_DRAINING;
            // **** intentional fall through here ****
        case WPN_HAND_AXE:
            if (one_chance_in(30))
                rc = SPWPN_PAIN;

            if (one_chance_in(10))
                rc = SPWPN_VAMPIRICISM;

            if (item.sub_type == WPN_HAND_AXE && one_chance_in(10))
                rc = SPWPN_RETURNING;

            if (_got_distortion_roll(item_level))
                rc = SPWPN_DISTORTION;

            if (one_chance_in(3) && (rc == SPWPN_NORMAL || one_chance_in(5)))
                rc = SPWPN_VORPAL;

            if (one_chance_in(4))
                rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;

            if (one_chance_in(8))
                rc = SPWPN_ELECTROCUTION;

            if (one_chance_in(12))
                rc = SPWPN_VENOM;
            break;

        case WPN_WHIP:
            if (one_chance_in(10))
                rc = SPWPN_PAIN;

            if (_got_distortion_roll(item_level))
                rc = SPWPN_DISTORTION;

            if (one_chance_in(6))
                rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;

            if (one_chance_in(6))
                rc = SPWPN_VENOM;

            if (one_chance_in(3))
                rc = SPWPN_REACHING;

            if (one_chance_in(5))
                rc = SPWPN_SPEED;

            if (one_chance_in(5))
                rc = SPWPN_ELECTROCUTION;
            break;

        case WPN_HALBERD:
        case WPN_GLAIVE:
        case WPN_SCYTHE:
        case WPN_TRIDENT:
        case WPN_BARDICHE:
            if (one_chance_in(30))
                rc = SPWPN_HOLY_WRATH;

            if (one_chance_in(4))
                rc = SPWPN_PROTECTION;
            // **** intentional fall through here ****
            if (one_chance_in(5))
                rc = SPWPN_SPEED;
            // **** intentional fall through here ****
        case WPN_SPEAR:
            if (one_chance_in(25))
                rc = SPWPN_PAIN;

            if (one_chance_in(10))
                rc = SPWPN_VAMPIRICISM;

            if (item.sub_type == WPN_SPEAR && one_chance_in(6))
                rc = SPWPN_RETURNING;

            if (_got_distortion_roll(item_level))
                rc = SPWPN_DISTORTION;

            if (one_chance_in(5) && (rc == SPWPN_NORMAL || one_chance_in(6)))
                rc = SPWPN_VORPAL;

            if (one_chance_in(6))
                rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;

            if (one_chance_in(6))
                rc = SPWPN_VENOM;

            if (one_chance_in(5))
                rc = SPWPN_DRAGON_SLAYING;

            if (one_chance_in(3))
                rc = SPWPN_REACHING;
            break;


        case WPN_SLING:
        case WPN_HAND_CROSSBOW:
            if (coinflip())
                break;
            // **** possible intentional fall through here ****
        case WPN_BOW:
        case WPN_LONGBOW:
        case WPN_CROSSBOW:
        {
            const int tmp = random2(1000);
            if (tmp < 250)
                rc = SPWPN_FLAME;
            else if (tmp < 500)
                rc = SPWPN_FROST;
            else if (tmp < 650)
                rc = SPWPN_PENETRATION;
            else if (tmp < 800)
                rc = SPWPN_REAPING;
            else if (tmp < 920)
                rc = SPWPN_PROTECTION;
            else if (tmp < 980)
                rc = SPWPN_VORPAL;
            else
                rc = SPWPN_SPEED;
            break;
        }

        // Quarterstaff - not powerful, as this would make
        // the 'staves' skill just too good.
        case WPN_QUARTERSTAFF:
            if (one_chance_in(30))
                rc = SPWPN_PAIN;

            if (_got_distortion_roll(item_level))
                rc = SPWPN_DISTORTION;

            if (one_chance_in(5))
                rc = SPWPN_SPEED;

            if (one_chance_in(10))
                rc = SPWPN_VORPAL;

            if (one_chance_in(5))
                rc = SPWPN_PROTECTION;
            break;

        case WPN_LAJATANG:
            if (one_chance_in(8))
                rc = SPWPN_SPEED;
            else if (one_chance_in(12))
                rc = SPWPN_PAIN;
            else if (_got_distortion_roll(item_level))
                rc = SPWPN_DISTORTION;
            else if (one_chance_in(9))
                rc = SPWPN_PROTECTION;
            else if (one_chance_in(6))
                rc = SPWPN_ELECTROCUTION;
            else if (one_chance_in(5))
                rc = SPWPN_VAMPIRICISM;
            else if (one_chance_in(6))
                rc = SPWPN_VENOM;
            break;

        case WPN_DEMON_WHIP:
        case WPN_DEMON_BLADE:
        case WPN_DEMON_TRIDENT:
            if (one_chance_in(10))
                rc = SPWPN_PAIN;

            if (one_chance_in(3)
                && (item.sub_type == WPN_DEMON_WHIP
                    || item.sub_type == WPN_DEMON_TRIDENT))
            {
                rc = SPWPN_REACHING;
            }

            if (one_chance_in(5))
                rc = SPWPN_DRAINING;

            if (one_chance_in(5))
                rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;

            if (one_chance_in(5))
                rc = SPWPN_ELECTROCUTION;

            if (one_chance_in(5))
                rc = SPWPN_VAMPIRICISM;

            if (one_chance_in(5))
                rc = SPWPN_VENOM;
            break;

        case WPN_BLESSED_FALCHION:     // special gifts of TSO
        case WPN_BLESSED_LONG_SWORD:
        case WPN_BLESSED_SCIMITAR:
        case WPN_BLESSED_KATANA:
        case WPN_BLESSED_EUDEMON_BLADE:
        case WPN_BLESSED_DOUBLE_SWORD:
        case WPN_BLESSED_GREAT_SWORD:
        case WPN_BLESSED_TRIPLE_SWORD:
            rc = SPWPN_HOLY_WRATH;
            break;

        default:
            // unlisted weapons have no associated, standard ego-types {dlb}
            break;
        }
    }

    return (rc);
}

static void _generate_weapon_item(item_def& item, bool allow_uniques,
                                  int force_type, int item_level,
                                  int item_race)
{
    // Determine weapon type.
    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
        item.sub_type = _determine_weapon_subtype(item_level);

    // If we make the unique roll, no further generation necessary.
    if (allow_uniques
        && _try_make_weapon_artefact(item, force_type, item_level))
    {
        return;
    }

    ASSERT(!is_artefact(item));

    // Artefacts handled, let's make a normal item.
    const bool force_good = (item_level == MAKE_GOOD_ITEM);
    const bool forced_ego = item.special > 0;
    const bool no_brand   = item.special == SPWPN_FORBID_BRAND;

    if (no_brand)
        set_item_ego_type(item, OBJ_WEAPONS, SPWPN_NORMAL);

    // If it's forced to be a good item, upgrade the worst weapons.
    if (force_good
        && force_type == OBJ_RANDOM
        && (item.sub_type == WPN_CLUB || item.sub_type == WPN_SLING))
    {
        item.sub_type = WPN_LONG_SWORD;
    }

    item.plus  = 0;
    item.plus2 = 0;

    set_equip_race(item, _determine_weapon_race(item, item_race));

    // If we allow acquirement-type items to be orcish, then there's a
    // good chance that we'll just strip them of their ego type at the
    // bottom of this function. - bwr
    if (force_good && !forced_ego && get_equip_race(item) == ISFLAG_ORCISH)
        set_equip_race(item, ISFLAG_NO_RACE);

    _weapon_add_racial_modifiers(item);

    if (item_level < 0)
    {
        // Thoroughly damaged, could had been good once.
        if (!no_brand && (forced_ego || one_chance_in(4)))
        {
            // Brand is set as for "good" items.
            set_item_ego_type(item, OBJ_WEAPONS,
                              _determine_weapon_brand(item, 2+2*you.your_level));
        }
        item.plus  -= 1 + random2(3);
        item.plus2 -= 1 + random2(3);

        if (item_level == -5)
            do_curse_item(item);
    }
    else if ((force_good || is_demonic(item) || forced_ego
                    || x_chance_in_y(51 + item_level, 200))
                && !item_is_mundane(item))
    {
        // Make a better item (possibly ego).
        if (!no_brand)
        {
            set_item_ego_type(item, OBJ_WEAPONS,
                              _determine_weapon_brand(item, item_level));
        }

        // if acquired item still not ego... enchant it up a bit.
        if (force_good && item.special == SPWPN_NORMAL)
        {
            item.plus  += 2 + random2(3);
            item.plus2 += 2 + random2(3);
        }

        const int chance = (force_good ? 200 : item_level);

        // Odd-looking, but this is how the algorithm compacts {dlb}.
        for (int i = 0; i < 4; ++i)
        {
            item.plus += random2(3);

            if (random2(350) > 20 + chance)
                break;
        }

        // Odd-looking, but this is how the algorithm compacts {dlb}.
        for (int i = 0; i < 4; ++i)
        {
            item.plus2 += random2(3);

            if (random2(500) > 50 + chance)
                break;
        }
    }
    else
    {
        if (one_chance_in(12))
        {
            // Make a cursed item.
            do_curse_item(item);
            item.plus  -= random2(4);
            item.plus2 -= random2(4);
            set_item_ego_type(item, OBJ_WEAPONS, SPWPN_NORMAL);
        }
    }

    if (get_equip_race(item) == ISFLAG_ORCISH
        && !(item_race == MAKE_ITEM_ORCISH && forced_ego))
    {
        // No orc slaying, and no ego at all half the time.
        const int brand = get_weapon_brand(item);
        if (brand == SPWPN_ORC_SLAYING
            || (brand != SPWPN_NORMAL && !forced_ego && coinflip()))
        {
            set_item_ego_type(item, OBJ_WEAPONS, SPWPN_NORMAL);
        }
    }
}

static item_status_flag_type _determine_missile_race(const item_def& item,
                                                     int item_race)
{
    item_status_flag_type rc = ISFLAG_NO_RACE;
    switch (item_race)
    {
    case MAKE_ITEM_ELVEN:
        rc = ISFLAG_ELVEN;
        break;

    case MAKE_ITEM_DWARVEN:
        rc = ISFLAG_DWARVEN;
        break;

    case MAKE_ITEM_ORCISH:
        rc = ISFLAG_ORCISH;
        break;

    case MAKE_ITEM_RANDOM_RACE:
        // Elves don't make bolts, sling bullets, or throwing nets.
        if ((item.sub_type == MI_ARROW
                || item.sub_type == MI_DART
                || item.sub_type == MI_JAVELIN)
            && one_chance_in(4))
        {
            rc = ISFLAG_ELVEN;
        }

        // Orcs don't make sling bullets or throwing nets.
        if ((item.sub_type == MI_ARROW
                || item.sub_type == MI_BOLT
                || item.sub_type == MI_DART
                || item.sub_type == MI_JAVELIN)
            && one_chance_in(4))
        {
            rc = ISFLAG_ORCISH;
        }

        // Dwarves don't make arrows, sling bullets, javelins, or
        // throwing nets.
        if ((item.sub_type == MI_DART || item.sub_type == MI_BOLT)
            && one_chance_in(6))
        {
            rc = ISFLAG_DWARVEN;
        }

        // Dwarves don't make needles.
        if (item.sub_type == MI_NEEDLE)
        {
            if (one_chance_in(10))
                rc = ISFLAG_ELVEN;
            if (one_chance_in(6))
                rc = ISFLAG_ORCISH;
        }
        break;
    }
    return rc;
}

static special_missile_type _determine_missile_brand(const item_def& item,
                                                     int item_level)
{
    // Forced ego.
    if (item.special != 0)
        return static_cast<special_missile_type>(item.special);

    const bool force_good = (item_level == MAKE_GOOD_ITEM);
    special_missile_type rc = SPMSL_NORMAL;

    // All needles are either poison or curare.
    if (item.sub_type == MI_NEEDLE)
        rc = _got_curare_roll(item_level) ? SPMSL_CURARE : SPMSL_POISONED;
    else
    {
        const int temp_rand =
            (force_good ? random2(150) : random2(2000 - 55 * item_level));

        if (temp_rand < 30)
            rc = SPMSL_FLAME;
        else if (temp_rand < 60)
            rc = SPMSL_FROST;
        else if (temp_rand < 80)
            rc = SPMSL_POISONED;
        else if (temp_rand < 90)
            rc = SPMSL_PENETRATION;
        else if (temp_rand < 100)
            rc = SPMSL_REAPING;
        else if (temp_rand < 110)
            rc = SPMSL_SILVER;
        else if (temp_rand < 120)
            rc = SPMSL_STEEL;
        else if (temp_rand < 130)
            rc = SPMSL_DISPERSAL;
        else if (temp_rand < 150)
            rc = SPMSL_EXPLODING;
        else
            rc = SPMSL_NORMAL;
    }

    // Javelins can be returning.
    if (item.sub_type == MI_JAVELIN && one_chance_in(25))
        rc = SPMSL_RETURNING;

    // Orcish ammo gets poisoned a lot more often.
    if (get_equip_race(item) == ISFLAG_ORCISH && one_chance_in(3))
        rc = SPMSL_POISONED;

    // Un-poison sling bullets, and unbrand throwing nets.
    if (item.sub_type == MI_SLING_BULLET && rc == SPMSL_POISONED
        || item.sub_type == MI_THROWING_NET)
    {
        rc = SPMSL_NORMAL;
    }

    return rc;
}

static void _generate_missile_item(item_def& item, int force_type,
                                   int item_level, int item_race)
{
    const bool no_brand = (item.special == SPMSL_FORBID_BRAND);
    if (no_brand)
        item.special = SPMSL_NORMAL;

    item.plus = 0;

    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
    {
        item.sub_type =
            random_choose_weighted(30, MI_STONE,
                                   20, MI_DART,
                                   20, MI_ARROW,
                                   12, MI_BOLT,
                                   10, MI_NEEDLE,
                                   5,  MI_SLING_BULLET,
                                   2,  MI_JAVELIN,
                                   1,  MI_THROWING_NET,
                                   0);
    }

    // No fancy rocks -- break out before we get to racial/special stuff.
    if (item.sub_type == MI_LARGE_ROCK)
    {
        item.quantity = 2 + random2avg(5,2);
        return;
    }
    else if (item.sub_type == MI_STONE)
    {
        item.quantity = 1 + random2(9) + random2(12) + random2(15) + random2(12);
        return;
    }
    else if (item.sub_type == MI_THROWING_NET) // no fancy nets, either
    {
        item.quantity = 1 + one_chance_in(4); // and only one, rarely two
        return;
    }

    set_equip_race(item, _determine_missile_race(item, item_race));

    if (!no_brand)
    {
        set_item_ego_type( item, OBJ_MISSILES,
                           _determine_missile_brand(item, item_level) );
    }

    // Reduced quantity if special.
    if (item.sub_type == MI_JAVELIN
        || get_ammo_brand( item ) == SPMSL_CURARE
        || get_ammo_brand( item ) == SPMSL_RETURNING)
    {
        item.quantity = random_range(2, 8);
    }
    else if (get_ammo_brand( item ) != SPMSL_NORMAL)
        item.quantity = 1 + random2(9) + random2(12) + random2(12);
    else
        item.quantity = 1 + random2(9) + random2(12) + random2(12) + random2(15);

    if (x_chance_in_y(11 + item_level, 100))
        item.plus += random2(5);

    // Elven arrows and dwarven bolts are quality items.
    if (get_equip_race(item) == ISFLAG_ELVEN && item.sub_type == MI_ARROW
        || get_equip_race(item) == ISFLAG_DWARVEN && item.sub_type == MI_BOLT)
    {
        item.plus += random2(3);
    }
}

static bool _try_make_armour_artefact(item_def& item, int force_type,
                                      int item_level)
{
    if (item_level > 2 && x_chance_in_y(101 + item_level * 3, 4000))
    {
        // Make a randart or unrandart.

        // 1 in 50 randarts are unrandarts.
        if (you.level_type != LEVEL_ABYSS
            && you.level_type != LEVEL_PANDEMONIUM
            && one_chance_in(50))
        {
            // The old generation code did not respect force_type here.
            const int idx = find_okay_unrandart(OBJ_ARMOUR, force_type,
                                                UNRANDSPEC_NORMAL);
            if (idx != -1)
            {
                make_item_unrandart(item, idx);
                return (true);
            }
        }

        // The other 98% are normal randarts.

        // 10% of boots become barding.
        if (item.sub_type == ARM_BOOTS && one_chance_in(10))
        {
            item.sub_type = coinflip() ? ARM_NAGA_BARDING
                                       : ARM_CENTAUR_BARDING;
        }
        else
            hide2armour(item); // No randart hides.

        // Needs to be done after the barding chance else we get randart
        // bardings named Boots of xy.
        make_item_randart(item);

        // Determine enchantment and cursedness.
        if (one_chance_in(5))
        {
            do_curse_item(item);
            item.plus = -random2(6);
        }
        else
        {
            item.plus = random2(4);

            if (one_chance_in(5))
                item.plus += random2(4);

            if (one_chance_in(6))
                item.plus -= random2(8);

            if (item.plus < 0 && !one_chance_in(3))
                do_curse_item(item);
        }

        return (true);
    }

    // If it isn't an artefact yet, try to make a special unrand artefact.
    if (item_level > 6
        && one_chance_in(12)
        && x_chance_in_y(31 + item_level * 3, 3000))
    {
        return (_try_make_item_special_unrand(item, force_type, item_level));
    }

    return (false);
}

static item_status_flag_type _determine_armour_race(const item_def& item,
                                                    int item_race)
{
    item_status_flag_type rc = ISFLAG_NO_RACE;
    switch (item_race)
    {
    case MAKE_ITEM_ELVEN:
        rc = ISFLAG_ELVEN;
        break;

    case MAKE_ITEM_DWARVEN:
        rc = ISFLAG_DWARVEN;
        break;

    case MAKE_ITEM_ORCISH:
        rc = ISFLAG_ORCISH;
        break;

    case MAKE_ITEM_RANDOM_RACE:
        if (coinflip())
            break;

        switch (item.sub_type)
        {
        case ARM_SHIELD:
        case ARM_BUCKLER:
        case ARM_LARGE_SHIELD:
            if (one_chance_in(4))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(4))
                rc = ISFLAG_ELVEN;
            if (one_chance_in(3))
                rc = ISFLAG_DWARVEN;
            break;

        case ARM_CLOAK:
            if (one_chance_in(4))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(4))
                rc = ISFLAG_DWARVEN;
            if (one_chance_in(4))
                rc = ISFLAG_ELVEN;
            break;

        case ARM_GLOVES:
        case ARM_BOOTS:
            if (one_chance_in(4))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(4))
                rc = ISFLAG_ELVEN;
            if (one_chance_in(6))
                rc = ISFLAG_DWARVEN;
            break;

        case ARM_CAP:
        case ARM_WIZARD_HAT:
            if (one_chance_in(6))
                rc = ISFLAG_ELVEN;
            break;

        case ARM_HELMET:
            if (one_chance_in(6))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(5))
                rc = ISFLAG_DWARVEN;
            break;

        case ARM_ROBE:
            if (one_chance_in(6))
                rc = ISFLAG_ORCISH;
            if (one_chance_in(4))
                rc = ISFLAG_ELVEN;
            break;

        case ARM_LEATHER_ARMOUR:
        case ARM_RING_MAIL:
        case ARM_SCALE_MAIL:
        case ARM_CHAIN_MAIL:
        case ARM_SPLINT_MAIL:
        case ARM_BANDED_MAIL:
        case ARM_PLATE_MAIL:
            if (item.sub_type <= ARM_CHAIN_MAIL && one_chance_in(6))
                rc = ISFLAG_ELVEN;
            if (item.sub_type >= ARM_RING_MAIL && one_chance_in(5))
                rc = ISFLAG_DWARVEN;
            if (one_chance_in(5))
                rc = ISFLAG_ORCISH;

        default:
            break;
        }
    }

    return (rc);
}

static special_armour_type _determine_armour_ego(const item_def& item,
                                                 int force_type, int item_level)
{
    if (item.special != 0)
        return static_cast<special_armour_type>(item.special);

    special_armour_type rc = SPARM_NORMAL;
    switch (item.sub_type)
    {
    case ARM_SHIELD:
    case ARM_LARGE_SHIELD:
    case ARM_BUCKLER:
        rc = static_cast<special_armour_type>(
            random_choose_weighted(40, SPARM_RESISTANCE,
                                   120, SPARM_FIRE_RESISTANCE,
                                   120, SPARM_COLD_RESISTANCE,
                                   120, SPARM_POISON_RESISTANCE,
                                   120, SPARM_POSITIVE_ENERGY,
                                   480, SPARM_PROTECTION,
                                   1000, SPARM_REFLECTION, //XXX: Testing
                                   0));
        break;

    case ARM_CLOAK:
    {
        const special_armour_type cloak_egos[] = {
            SPARM_POISON_RESISTANCE, SPARM_DARKNESS,
            SPARM_MAGIC_RESISTANCE, SPARM_PRESERVATION
        };

        rc = RANDOM_ELEMENT(cloak_egos);
        break;
    }

    case ARM_WIZARD_HAT:
        if (coinflip())
        {
            rc = (one_chance_in(3) ? SPARM_MAGIC_RESISTANCE
                                   : SPARM_INTELLIGENCE);
        }
        break;

    case ARM_CAP:
        if (one_chance_in(10))
        {
            rc = SPARM_SPIRIT_SHIELD;
            break;
        }
    case ARM_HELMET:
        rc = coinflip() ? SPARM_SEE_INVISIBLE : SPARM_INTELLIGENCE;
        break;

    case ARM_GLOVES:
        rc = coinflip() ? SPARM_DEXTERITY : SPARM_STRENGTH;
        break;

    case ARM_BOOTS:
    case ARM_NAGA_BARDING:
    case ARM_CENTAUR_BARDING:
    {
        const int tmp = random2(600) + 200 * (item.sub_type != ARM_BOOTS);

        rc = (tmp < 200) ? SPARM_RUNNING :
             (tmp < 400) ? SPARM_LEVITATION :
             (tmp < 600) ? SPARM_STEALTH :
             (tmp < 700) ? SPARM_COLD_RESISTANCE
                         : SPARM_FIRE_RESISTANCE;
        break;
    }

    case ARM_ROBE:
        switch (random2(4))
        {
        case 0:
            rc = coinflip() ? SPARM_COLD_RESISTANCE : SPARM_FIRE_RESISTANCE;
            break;

        case 1:
            rc = SPARM_MAGIC_RESISTANCE;
            break;

        case 2:
            rc = coinflip() ? SPARM_POSITIVE_ENERGY : SPARM_RESISTANCE;
            break;
        case 3:
            // This is an odd limitation, but I'm not changing it yet.
            if (force_type == OBJ_RANDOM && x_chance_in_y(11 + item_level, 50))
                rc = SPARM_ARCHMAGI;
            break;
        }
        break;

    default:
        rc = coinflip() ? SPARM_COLD_RESISTANCE : SPARM_FIRE_RESISTANCE;

        if (one_chance_in(9))
            rc = SPARM_POSITIVE_ENERGY;

        if (one_chance_in(5))
            rc = SPARM_MAGIC_RESISTANCE;

        if (one_chance_in(5))
            rc = SPARM_POISON_RESISTANCE;

        if (item.sub_type == ARM_PLATE_MAIL && one_chance_in(15))
            rc = SPARM_PONDEROUSNESS;
        break;
    }

    return (rc);
}

static void _generate_armour_item(item_def& item, bool allow_uniques,
                                  int force_type, int item_level,
                                  int item_race)
{
    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
        item.sub_type = get_random_armour_type(item_level);

    if (allow_uniques
        && _try_make_armour_artefact(item, force_type, item_level))
    {
        return;
    }

    // If we get here the item is not an artefact.
    if (is_helmet(item) && one_chance_in(3))
        set_helmet_random_desc(item);

    if (item_race == MAKE_ITEM_RANDOM_RACE && item.sub_type == ARM_BOOTS)
    {
        if (one_chance_in(8))
            item.sub_type = ARM_NAGA_BARDING;
        else if (one_chance_in(7))
            item.sub_type = ARM_CENTAUR_BARDING;
    }

    set_equip_race(item, _determine_armour_race(item, item_race));

    // Dwarven armour is high-quality.
    if (get_equip_race(item) == ISFLAG_DWARVEN && coinflip())
        item.plus++;

    const bool force_good = (item_level == MAKE_GOOD_ITEM);
    const bool forced_ego = (item.special > 0);
    const bool no_ego     = (item.special == SPARM_FORBID_EGO);

    if (no_ego)
        item.special = SPARM_NORMAL;

    if (item_level < 0)
    {
        // Thoroughly damaged, could have been good once.
        if (!no_ego && (forced_ego || one_chance_in(4)))
        {
            // Brand is set as for "good" items.
            set_item_ego_type(item, OBJ_ARMOUR,
                _determine_armour_ego(item, item.sub_type, 2+2*you.your_level));
        }

        item.plus -= 1 + random2(3);

        if (item_level == -5)
            do_curse_item(item);
    }
    else if ((force_good || forced_ego || item.sub_type == ARM_WIZARD_HAT
                    || x_chance_in_y(51 + item_level, 250))
                && !item_is_mundane(item))
    {
        // Make a good item...
        item.plus += random2(3);

        if (item.sub_type <= ARM_PLATE_MAIL
            && x_chance_in_y(21 + item_level, 300))
        {
            item.plus += random2(3);
        }

        if (!no_ego
            && x_chance_in_y(31 + item_level, 350)
            && (force_good
                || forced_ego
                || get_equip_race(item) != ISFLAG_ORCISH
                || item.sub_type <= ARM_PLATE_MAIL && coinflip()))
        {
            // ...an ego item, in fact.
            set_item_ego_type(item, OBJ_ARMOUR,
                              _determine_armour_ego(item, force_type,
                                                    item_level));

            if (get_armour_ego_type(item) == SPARM_PONDEROUSNESS)
                item.plus += 3 + random2(4);
        }
    }
    else if (one_chance_in(12))
    {
        // Make a bad (cursed) item.
        do_curse_item(item);

        if (one_chance_in(5))
            item.plus -= random2(3);

        set_item_ego_type(item, OBJ_ARMOUR, SPARM_NORMAL);
    }

    // Make sure you don't get a hide from acquirement (since that
    // would be an enchanted item which somehow didn't get converted
    // into armour).
    if (force_good)
        hide2armour(item);

    // Skin armours and crystal plate mail normally don't get egos, but
    // can be randarts.
    if (armour_is_hide(item, true)
        || item.sub_type == ARM_ANIMAL_SKIN
        || item.sub_type == ARM_CRYSTAL_PLATE_MAIL)
    {
        if (!forced_ego)
            set_item_ego_type(item, OBJ_ARMOUR, SPARM_NORMAL);
    }

    // Don't overenchant items.
    if (item.plus > armour_max_enchant(item))
        item.plus = armour_max_enchant(item);

    if (armour_is_hide(item))
        item.plus = 0;
}

static monster_type _choose_random_monster_corpse()
{
    for (int count = 0; count < 1000; ++count)
    {
        monster_type spc = mons_species(random2(NUM_MONSTERS));
        if (mons_weight(spc) > 0)        // drops a corpse
            return spc;
    }

    return (MONS_RAT);          // if you can't find anything else...
}

static int _random_wand_subtype()
{
    int rc = random2( NUM_WANDS );

    // Adjusted distribution here -- bwr
    // Wands used to be uniform (5.26% each)
    //
    // Now:
    // invis, hasting, healing  (1.11% each)
    // fireball, teleportaion   (3.74% each)
    // others                   (6.37% each)
    if (rc == WAND_INVISIBILITY || rc == WAND_HASTING || rc == WAND_HEALING
        || (rc == WAND_FIREBALL || rc == WAND_TELEPORTATION) && coinflip())
    {
        rc = random2( NUM_WANDS );
    }
    return rc;
}

static int _wand_max_charges(int subtype)
{
    switch (subtype)
    {
    case WAND_HEALING: case WAND_HASTING: case WAND_INVISIBILITY:
        return 8;

    case WAND_FLAME: case WAND_FROST: case WAND_MAGIC_DARTS:
    case WAND_RANDOM_EFFECTS:
        return 28;

    default:
        return 16;
    }
}

static void _generate_wand_item(item_def& item, int force_type)
{
    // Determine sub_type.
    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
        item.sub_type = _random_wand_subtype();

    // Generate charges randomly...
    item.plus = random2avg(_wand_max_charges(item.sub_type), 3);

    // ...but 0 charges is silly
    if (item.plus == 0)
        item.plus++;

    // plus2 tracks how many times the player has zapped it.
    // If it is -1, then the player knows it's empty.
    // If it is -2, then the player has messed with it somehow
    // (presumably by recharging), so don't bother to display
    // the count.
    item.plus2 = 0;
}

static void _generate_food_item(item_def& item, int force_quant, int force_type)
{
    // Determine sub_type:
    if (force_type == OBJ_RANDOM)
    {
        item.sub_type = random_choose_weighted( 250, FOOD_MEAT_RATION,
                                                300, FOOD_BREAD_RATION,
                                                100, FOOD_PEAR,
                                                100, FOOD_APPLE,
                                                100, FOOD_CHOKO,
                                                 10, FOOD_CHEESE,
                                                 10, FOOD_PIZZA,
                                                 10, FOOD_SNOZZCUMBER,
                                                 10, FOOD_APRICOT,
                                                 10, FOOD_ORANGE,
                                                 10, FOOD_BANANA,
                                                 10, FOOD_STRAWBERRY,
                                                 10, FOOD_RAMBUTAN,
                                                 10, FOOD_LEMON,
                                                 10, FOOD_GRAPE,
                                                 10, FOOD_SULTANA,
                                                 10, FOOD_LYCHEE,
                                                 10, FOOD_BEEF_JERKY,
                                                 10, FOOD_SAUSAGE,
                                                  5, FOOD_HONEYCOMB,
                                                  5, FOOD_ROYAL_JELLY,
                                                  0);
    }
    else
        item.sub_type = force_type;

    // Happens with ghoul food acquirement -- use place_chunks() outherwise
    if (item.sub_type == FOOD_CHUNK)
    {
        // Set chunk flavour (default to common dungeon rat steaks):
        item.plus = _choose_random_monster_corpse();
        // Set duration.
        item.special = (10 + random2(11)) * 10;
    }

    // Determine quantity.
    if (force_quant > 1)
        item.quantity = force_quant;
    else
    {
        item.quantity = 1;

        if (item.sub_type != FOOD_MEAT_RATION
            && item.sub_type != FOOD_BREAD_RATION)
        {
            if (one_chance_in(80))
                item.quantity += random2(3);

            if (item.sub_type == FOOD_STRAWBERRY
                || item.sub_type == FOOD_GRAPE
                || item.sub_type == FOOD_SULTANA)
            {
                item.quantity += 3 + random2avg(15,2);
            }
        }
    }
}

static void _generate_potion_item(item_def& item, int force_type,
                                  int item_level, int agent)
{
    item.quantity = 1;

    if (one_chance_in(18))
        item.quantity++;

    if (one_chance_in(25))
        item.quantity++;

    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
    {
        int stype;
        do
        {
            stype = random_choose_weighted( 2815, POT_HEALING,
                                            1407, POT_HEAL_WOUNDS,
                                             900, POT_RESTORE_ABILITIES,
                                             648, POT_POISON,
                                             612, POT_SPEED,
                                             612, POT_MIGHT,
                                             612, POT_AGILITY,
                                             612, POT_BRILLIANCE,
                                             340, POT_INVISIBILITY,
                                             340, POT_LEVITATION,
                                             340, POT_RESISTANCE,
                                             324, POT_MUTATION,
                                             324, POT_SLOWING,
                                             324, POT_PARALYSIS,
                                             324, POT_CONFUSION,
                                             278, POT_DEGENERATION,
                                             222, POT_CURE_MUTATION,
                                             162, POT_STRONG_POISON,
                                             140, POT_MAGIC,
                                             136, POT_BERSERK_RAGE,
                                             111, POT_BLOOD,
                                              70, POT_PORRIDGE,
                                              38, POT_GAIN_STRENGTH,
                                              38, POT_GAIN_DEXTERITY,
                                              38, POT_GAIN_INTELLIGENCE,
                                              13, POT_EXPERIENCE,
                                              10, POT_DECAY,
                                               0);
        }
        while (stype == POT_POISON && item_level < 1
               || stype == POT_STRONG_POISON && item_level < 11
               || agent == GOD_XOM && _is_boring_item(OBJ_POTIONS, stype));

        if (stype == POT_GAIN_STRENGTH || stype == POT_GAIN_DEXTERITY
            || stype == POT_GAIN_INTELLIGENCE || stype == POT_EXPERIENCE
            || stype == POT_MAGIC || stype == POT_RESTORE_ABILITIES)
        {
            item.quantity = 1;
        }

        item.sub_type = stype;
    }

    if (is_blood_potion(item))
        init_stack_blood_potions(item);
}

static void _generate_scroll_item(item_def& item, int force_type,
                                  int item_level, int agent)
{
    // determine sub_type:
    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
    {
        const int depth_mod = random2(1 + item_level);

        do
        {
            // total weight: 10000
            item.sub_type = random_choose_weighted(
                1797, SCR_IDENTIFY,
                1305, SCR_REMOVE_CURSE,
                 802, SCR_TELEPORTATION,
                 642, SCR_DETECT_CURSE,
                 321, SCR_FEAR,
                 321, SCR_NOISE,
                 321, SCR_MAGIC_MAPPING,
                 321, SCR_FOG,
                 321, SCR_RANDOM_USELESSNESS,
                 321, SCR_CURSE_WEAPON,
                 321, SCR_CURSE_ARMOUR,
                 321, SCR_RECHARGING,
                 321, SCR_BLINKING,
                 321, SCR_ENCHANT_ARMOUR,
                 321, SCR_ENCHANT_WEAPON_I,
                 321, SCR_ENCHANT_WEAPON_II,

                 // Don't create ?oImmolation at low levels (encourage read-ID).
                 321, (item_level < 4 ? SCR_TELEPORTATION : SCR_IMMOLATION),

                 161, SCR_PAPER,

                 // Medium-level scrolls.
                 140, (depth_mod < 4 ? SCR_TELEPORTATION : SCR_ACQUIREMENT),
                 140, (depth_mod < 4 ? SCR_TELEPORTATION : SCR_ENCHANT_WEAPON_III),
                 140, (depth_mod < 4 ? SCR_DETECT_CURSE  : SCR_SUMMONING),
                 140, (depth_mod < 4 ? SCR_PAPER :         SCR_VULNERABILITY),
                 140, (depth_mod < 4 ? SCR_PAPER :         SCR_SILENCE),

                 // High-level scrolls.
                 140, (depth_mod < 7 ? SCR_TELEPORTATION : SCR_VORPALISE_WEAPON),
                 140, (depth_mod < 7 ? SCR_DETECT_CURSE  : SCR_TORMENT),
                 140, (depth_mod < 7 ? SCR_DETECT_CURSE  : SCR_HOLY_WORD),
                   0);
        }
        while (agent == GOD_XOM && _is_boring_item(OBJ_SCROLLS, item.sub_type));
    }

    // determine quantity
    if (item.sub_type == SCR_VORPALISE_WEAPON
        || item.sub_type == SCR_ENCHANT_WEAPON_III
        || item.sub_type == SCR_ACQUIREMENT
        || item.sub_type == SCR_TORMENT
        || item.sub_type == SCR_HOLY_WORD
        || item.sub_type == SCR_SILENCE)
    {
        item.quantity = 1;
    }
    else
    {
        if (one_chance_in(24))
            item.quantity = (coinflip() ? 2 : 3);
        else
            item.quantity = 1;
    }

    item.plus = 0;
}

static void _generate_book_item(item_def& item, int allow_uniques,
                                int force_type, int item_level)
{
    // determine special (description)
    item.special = random2(5);

    if (one_chance_in(10))
        item.special += random2(8) * 10;

    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
    {
        do
        {
            item.sub_type = random2(NUM_FIXED_BOOKS);

            if (book_rarity(item.sub_type) != 100
                && one_chance_in(10))
            {
                item.sub_type = coinflip() ? BOOK_WIZARDRY : BOOK_POWER;
            }

            if (!one_chance_in(100)
                && x_chance_in_y(book_rarity(item.sub_type)-1, item_level+1))
            {
                // If this book is really rare for this depth, continue trying.
                continue;
            }
        }
        while (book_rarity(item.sub_type) == 100);

        // Tome of destruction: rare!
        if (item_level > 10 && x_chance_in_y(21 + item_level, 7000))
            item.sub_type = BOOK_DESTRUCTION;

        // Skill manuals - also rare.
        if (item_level > 6 && x_chance_in_y(21 + item_level, 4000))
            item.sub_type = BOOK_MANUAL;
    }

    // Determine which skill for a manual.
    if (item.sub_type == BOOK_MANUAL)
    {
        if (one_chance_in(4))
            item.plus = SK_SPELLCASTING + random2(NUM_SKILLS - SK_SPELLCASTING);
        else
        {
            item.plus = random2(SK_UNARMED_COMBAT);

            if (item.plus == SK_UNUSED_1)
                item.plus = SK_UNARMED_COMBAT;
        }
        // Set number of reads possible before it "crumbles to dust".
        item.plus2 = 3 + random2(15);
    }

    // Manuals and books of destruction are rare enough without replacing
    // them with randart books.
    if (item.sub_type == BOOK_MANUAL || item.sub_type == BOOK_DESTRUCTION)
        return;

    // Only randomly generate randart books for OBJ_RANDOM, since randart
    // spellbooks aren't merely of-the-same-type-but-better, but
    // have an entirely different set of spells.
    if (allow_uniques && item_level > 2 && force_type == OBJ_RANDOM
        && x_chance_in_y(101 + item_level * 3, 4000))
    {
        int choice = random_choose_weighted(
            58, BOOK_RANDART_THEME,
             2, BOOK_RANDART_LEVEL, // 1/30
             0);

        item.sub_type = choice;
    }

    if (item.sub_type == BOOK_RANDART_THEME)
        make_book_theme_randart(item, 0, 0, 5 + coinflip(), 20);
    else if (item.sub_type == BOOK_RANDART_LEVEL)
    {
        int max_level  = std::min( 9, std::max(1, item_level / 3) );
        int spl_level  = random_range(1, max_level);
        int max_spells = 5 + spl_level/3;
        make_book_level_randart(item, spl_level, max_spells);
    }
}

static void _generate_staff_item(item_def& item, int force_type)
{
    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
    {
        item.sub_type = random2(STAFF_FIRST_ROD);

        // rods are rare (10% of all staves)
        if (one_chance_in(10))
            item.sub_type = random_rod_subtype();

        // staves of energy/channeling are 25% less common, wizardry/power
        // are more common
        if ((item.sub_type == STAFF_ENERGY
                || item.sub_type == STAFF_CHANNELING)
            && one_chance_in(4))
        {
            item.sub_type = coinflip() ? STAFF_WIZARDRY : STAFF_POWER;
        }
    }

    if (item_is_rod(item))
        init_rod_mp(item);
}

static bool _try_make_jewellery_unrandart(item_def& item, int force_type,
                                          int item_level)
{
    bool rc = false;

    if (item_level > 2
        && you.level_type != LEVEL_ABYSS
        && you.level_type != LEVEL_PANDEMONIUM
        && one_chance_in(20)
        && x_chance_in_y(101 + item_level * 3, 2000))
    {
        // The old generation code did not respect force_type here.
        const int idx = find_okay_unrandart(OBJ_JEWELLERY, force_type,
                                            UNRANDSPEC_NORMAL);
        if (idx != -1)
        {
            make_item_unrandart(item, idx);
            rc = true;
        }
    }

    return (rc);
}

static int _determine_ring_plus(int subtype)
{
    int rc = 0;

    switch (subtype)
    {
    case RING_PROTECTION:
    case RING_STRENGTH:
    case RING_SLAYING:
    case RING_EVASION:
    case RING_DEXTERITY:
    case RING_INTELLIGENCE:
        if (one_chance_in(5))       // 20% of such rings are cursed {dlb}
        {
            rc = (coinflip() ? -2 : -3);

            if (one_chance_in(3))
                rc -= random2(4);
        }
        else
            rc = 1 + (one_chance_in(3) ? random2(3) : random2avg(6, 2));
        break;

    default:
        break;
    }
    return rc;
}

static void _generate_jewellery_item(item_def& item, bool allow_uniques,
                                     int force_type, int item_level,
                                     int agent)
{
    if (allow_uniques
        && _try_make_jewellery_unrandart(item, force_type, item_level))
    {
        return;
    }

    // Determine subtype.
    // Note: removed double probability reduction for some subtypes
    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
    {
        do
        {
            item.sub_type = (one_chance_in(4) ? get_random_amulet_type()
                                              : get_random_ring_type());
        }
        while (agent == GOD_XOM
               && _is_boring_item(OBJ_JEWELLERY, item.sub_type));
    }

    // Everything begins as uncursed, unenchanted jewellery {dlb}:
    item.plus  = 0;
    item.plus2 = 0;

    item.plus = _determine_ring_plus(item.sub_type);
    if (item.plus < 0)
        do_curse_item(item);

    if (item.sub_type == RING_SLAYING ) // requires plus2 too
    {
        if (item_cursed(item) && !one_chance_in(20))
            item.plus2 = -1 - random2avg(6, 2);
        else
        {
            item.plus2 = 1 + (one_chance_in(3) ? random2(3) : random2avg(6, 2));

            if (x_chance_in_y(9, 25))        // 36% of such rings {dlb}
            {
                // make "ring of damage"
                do_uncurse_item(item);
                item.plus   = 0;
                item.plus2 += 2;
            }
        }
    }

    // All jewellery base types should now work. - bwr
    if (allow_uniques && item_level > 2
        && x_chance_in_y(101 + item_level * 3, 4000))
    {
        make_item_randart(item);
    }
    // If it isn't an artefact yet, try to make a special unrand artefact.
    else if (item_level > 6
             && one_chance_in(12)
             && x_chance_in_y(31 + item_level * 3, 3000))
    {
        _try_make_item_special_unrand(item, force_type, item_level);
    }
    else if (item.sub_type == RING_HUNGER || item.sub_type == RING_TELEPORTATION
             || one_chance_in(50))
    {
        // Rings of hunger and teleportation are always cursed {dlb}:
        do_curse_item(item);
    }
}

static void _generate_misc_item(item_def& item, int force_type, int item_race)
{
    if (force_type != OBJ_RANDOM)
        item.sub_type = force_type;
    else
    {
        do
            item.sub_type = random2(NUM_MISCELLANY);
        while
            // never randomly generated
            (item.sub_type == MISC_RUNE_OF_ZOT
             || item.sub_type == MISC_HORN_OF_GERYON
             || item.sub_type == MISC_DECK_OF_PUNISHMENT
             // Pure decks are rare in the dungeon.
             || (item.sub_type == MISC_DECK_OF_ESCAPE
                    || item.sub_type == MISC_DECK_OF_DESTRUCTION
                    || item.sub_type == MISC_DECK_OF_DUNGEONS
                    || item.sub_type == MISC_DECK_OF_SUMMONING
                    || item.sub_type == MISC_DECK_OF_WONDERS)
                 && !one_chance_in(5));

        // filling those silly empty boxes -- bwr
        if (item.sub_type == MISC_EMPTY_EBONY_CASKET && !one_chance_in(20))
            item.sub_type = MISC_BOX_OF_BEASTS;
    }

    if ( is_deck(item) )
    {
        item.plus = 4 + random2(10);
        item.special = random_choose_weighted( 8, DECK_RARITY_LEGENDARY,
                                              20, DECK_RARITY_RARE,
                                              72, DECK_RARITY_COMMON,
                                               0);
        init_deck(item);
    }

    if (item.sub_type == MISC_RUNE_OF_ZOT)
        item.plus = item_race;
}

// Returns item slot or NON_ITEM if it fails.
int items(int allow_uniques,       // not just true-false,
                                   // because of BCR acquirement hack
          object_class_type force_class, // desired OBJECTS class {dlb}
          int force_type,          // desired SUBTYPE - enum varies by OBJ
          bool dont_place,         // don't randomly place item on level
          int item_level,          // level of the item, can differ from global
          int item_race,           // weapon / armour racial categories
                                   // item_race also gives type of rune!
          unsigned mapmask,
          int force_ego,           // desired ego/brand
          int agent)               // acquirement agent, if not -1
{
    // TODO: Allow a combination of force_ego > 0 and
    // force_type == OBJ_RANDOM, so that (for example) you could have
    // force_class = OBJ_WEAPON, force_type = OBJ_RANDOM and
    // force_ego = SPWPN_VORPAL, and a random weapon of a type
    // appropriate for the vorpal brand will be chosen.
    ASSERT(force_ego <= 0
           || force_type != OBJ_RANDOM
              && (force_class == OBJ_WEAPONS || force_class == OBJ_ARMOUR
                  || force_class == OBJ_MISSILES));

    // Find an empty slot for the item (with culling if required).
    int p = get_item_slot(10);
    if (p == NON_ITEM)
        return (NON_ITEM);

    item_def& item(mitm[p]);

    // make_item_randart() might do things differently based upon the
    // acquirement agent, especially for god gifts.
    if (agent != -1)
        origin_acquired(item, agent);

    const bool force_good = (item_level == MAKE_GOOD_ITEM);

    if (force_ego != 0)
        allow_uniques = false;

    item.special = force_ego;

    // cap item_level unless an acquirement-level item {dlb}:
    if (item_level > 50 && !force_good)
        item_level = 50;

    // determine base_type for item generated {dlb}:
    if (force_class != OBJ_RANDOM)
        item.base_type = force_class;
    else
    {
        item.base_type = static_cast<object_class_type>(
            random_choose_weighted(  5, OBJ_STAVES,
                                    15, OBJ_BOOKS,
                                    25, OBJ_JEWELLERY,
                                    35, OBJ_WANDS,
                                    70, OBJ_FOOD,
                                   100, OBJ_ARMOUR,
                                   100, OBJ_WEAPONS,
                                   100, OBJ_POTIONS,
                                   150, OBJ_MISSILES,
                                   200, OBJ_SCROLLS,
                                   200, OBJ_GOLD,
                                     0));

        // misc items placement wholly dependent upon current depth {dlb}:
        if (item_level > 7 && x_chance_in_y(21 + item_level, 3500))
            item.base_type = OBJ_MISCELLANY;

        if (item_level < 7
            && (item.base_type == OBJ_BOOKS
                || item.base_type == OBJ_STAVES
                || item.base_type == OBJ_WANDS)
            && random2(7) >= item_level)
        {
            item.base_type = coinflip() ? OBJ_POTIONS : OBJ_SCROLLS;
        }
    }

    item.quantity = 1;          // generally the case

    if (force_ego < SP_FORBID_EGO)
    {
        force_ego = -force_ego;
        if (get_unique_item_status(force_ego) == UNIQ_NOT_EXISTS)
        {
            make_item_unrandart(mitm[p], force_ego);
            return (p);
        }
        // the base item otherwise
        item.special = SPWPN_NORMAL;
        force_ego = 0;
    }

    // Determine sub_type accordingly. {dlb}
    switch (item.base_type)
    {
    case OBJ_WEAPONS:
        _generate_weapon_item(item, allow_uniques, force_type,
                              item_level, item_race);
        break;

    case OBJ_MISSILES:
        _generate_missile_item(item, force_type, item_level, item_race);
        break;

    case OBJ_ARMOUR:
        _generate_armour_item(item, allow_uniques, force_type,
                              item_level, item_race);
        break;

    case OBJ_WANDS:
        _generate_wand_item(item, force_type);
        break;

    case OBJ_FOOD:
        _generate_food_item(item, allow_uniques, force_type);
        break;

    case OBJ_POTIONS:
        _generate_potion_item(item, force_type, item_level, agent);
        break;

    case OBJ_SCROLLS:
        _generate_scroll_item(item, force_type, item_level, agent);
        break;

    case OBJ_JEWELLERY:
        _generate_jewellery_item(item, allow_uniques, force_type, item_level,
                                 agent);
        break;

    case OBJ_BOOKS:
        _generate_book_item(item, allow_uniques, force_type, item_level);
        break;

    case OBJ_STAVES:
        _generate_staff_item(item, force_type);
        break;

    case OBJ_ORBS:              // always forced in current setup {dlb}
        item.sub_type = force_type;
        break;

    case OBJ_MISCELLANY:
        _generate_misc_item(item, force_type, item_race);
        break;

    // that is, everything turns to gold if not enumerated above, so ... {dlb}
    default:
        item.base_type = OBJ_GOLD;
        if (force_good)
        {
            item.quantity = 150 + random2(150)
                            + random2(random2(random2(2000)));
        }
        else
            item.quantity = 1 + random2avg(19, 2) + random2(item_level);
        break;
    }

    // Colour the item.
    item_colour(item);

    // Set brand appearance.
    item_set_appearance(item);

    if (dont_place)
    {
        item.pos.reset();
        item.link = NON_ITEM;
    }
    else
    {
        coord_def itempos;
        bool found = false;
        for (int i = 0; i < 500 && !found; ++i)
        {
            itempos = random_in_bounds();
            found = (grd(itempos) == DNGN_FLOOR
                     && unforbidden(itempos, mapmask));
        }
        if (!found)
        {
            // Couldn't find a single good spot!
            destroy_item(p);
            return (NON_ITEM);
        }
        move_item_to_grid(&p, itempos);
    }

    // Note that item might be invalidated now, since p could have changed.
    ASSERT(is_valid_item(mitm[p]));
    return (p);
}

void init_rod_mp(item_def &item, int ncharges)
{
    if (!item_is_rod(item))
        return;

    if (ncharges != -1)
        item.plus2 = ncharges * ROD_CHARGE_MULT;
    else
    {
        if (item.sub_type == STAFF_STRIKING)
            item.plus2 = random_range(6, 9) * ROD_CHARGE_MULT;
        else
            item.plus2 = random_range(9, 14) * ROD_CHARGE_MULT;
    }

    item.plus = item.plus2;
}

static bool _weapon_is_visibly_special(const item_def &item)
{
    const int brand = get_weapon_brand(item);
    const bool visibly_branded = (brand != SPWPN_NORMAL);

    if (get_equip_desc(item) != ISFLAG_NO_DESC)
        return (false);

    if (visibly_branded || is_artefact(item))
        return (true);

    if (item_is_mundane(item))
        return (false);

    if ((item.plus || item.plus2)
        && (one_chance_in(3) || get_equip_race(item) && one_chance_in(7)))
    {
        return (true);
    }

    return (false);
}

static bool _armour_is_visibly_special(const item_def &item)
{
    const int brand = get_armour_ego_type(item);
    const bool visibly_branded = (brand != SPARM_NORMAL);

    if (get_equip_desc(item) != ISFLAG_NO_DESC)
        return (false);

    if (visibly_branded || is_artefact(item))
        return (true);

    if (item_is_mundane(item))
        return (false);

    if (item.plus && !one_chance_in(3))
        return (true);

    return (false);
}

static void _give_monster_item(monsters *mon, int thing,
                               bool force_item = false,
                               bool (monsters::*pickupfn)(item_def&, int) = NULL)
{
    if (thing == NON_ITEM || thing == -1)
        return;

    item_def &mthing = mitm[thing];
    ASSERT(is_valid_item(mthing));

#ifdef DEBUG_DIAGNOSTICS
    mprf(MSGCH_DIAGNOSTICS,
         "Giving %s to %s...", mthing.name(DESC_PLAIN).c_str(),
         mon->name(DESC_PLAIN, true).c_str());
#endif

    mthing.pos.reset();
    mthing.link = NON_ITEM;
    unset_ident_flags(mthing, ISFLAG_IDENT_MASK);

    if (mon->is_unholy()
        && (is_blessed_blade(mthing)
            || get_weapon_brand(mthing) == SPWPN_HOLY_WRATH))
    {
        if (is_blessed_blade(mthing))
            convert2bad(mthing);
        if (get_weapon_brand(mthing) == SPWPN_HOLY_WRATH)
            set_item_ego_type(mthing, OBJ_WEAPONS, SPWPN_NORMAL);
    }

    unwind_var<int> save_speedinc(mon->speed_increment);
    if (!(pickupfn ? (mon->*pickupfn)(mthing, false)
                   : mon->pickup_item(mthing, false, true)))
    {
#ifdef DEBUG_DIAGNOSTICS
        mprf(MSGCH_DIAGNOSTICS, "Destroying %s because %s doesn't want it!",
             mthing.name(DESC_PLAIN, false, true).c_str(),
             mon->name(DESC_PLAIN, true).c_str());
#endif
        destroy_item(thing, true);
        return;
    }
    ASSERT(is_valid_item(mthing));
    ASSERT(mthing.holding_monster() == mon);

    if (!force_item || mthing.colour == BLACK)
        item_colour(mthing);
}

static void _give_scroll(monsters *mon, int level)
{
    int thing_created = NON_ITEM;

    if (mon->type == MONS_ROXANNE)
    {
        // Not a scroll, but this comes closest.
        int which_book = (one_chance_in(3) ? BOOK_TRANSFIGURATIONS
                                           : BOOK_EARTH);

        thing_created = items(0, OBJ_BOOKS, which_book, true, level, 0);

        if (thing_created != NON_ITEM && coinflip())
        {
            // Give Roxanne a random book containing Statue Form instead.
            item_def &item(mitm[thing_created]);
            make_book_Roxanne_special(&item);
            _give_monster_item(mon, thing_created, true);
            return;
        }
    }
    else if (mons_is_unique(mon->type) && one_chance_in(3))
        thing_created = items(0, OBJ_SCROLLS, OBJ_RANDOM, true, level, 0);

    if (thing_created == NON_ITEM)
        return;

    mitm[thing_created].flags = 0;
    _give_monster_item(mon, thing_created, true);
}

static void _give_wand(monsters *mon, int level)
{
    if (mons_is_unique(mon->type) && mon->type != MONS_GASTRONOK
        && (one_chance_in(5) || mon->type == MONS_MAURICE && one_chance_in(3)))
    {
        const int idx = items(0, OBJ_WANDS, OBJ_RANDOM, true, level, 0);

        if (idx == NON_ITEM)
            return;

        item_def& wand = mitm[idx];

        // Don't give top-tier wands before 5 HD.
        if (mon->hit_dice < 5)
        {
            // Technically these wands will be undercharged, but it
            // doesn't really matter.
            if (wand.sub_type == WAND_FIRE)
                wand.sub_type = WAND_FLAME;

            if (wand.sub_type == WAND_COLD)
                wand.sub_type = WAND_FROST;

            if (wand.sub_type == WAND_LIGHTNING)
                wand.sub_type = (coinflip() ? WAND_FLAME : WAND_FROST);
        }

        wand.flags = 0;
        _give_monster_item(mon, idx);
    }
}

static void _give_potion(monsters *mon, int level)
{
    if (mons_species(mon->type) == MONS_VAMPIRE && one_chance_in(5))
    {
        // This handles initialization of stack timer.
        const int thing_created =
            items(0, OBJ_POTIONS, POT_BLOOD, true, level, 0);

        if (thing_created == NON_ITEM)
            return;

        mitm[thing_created].flags = 0;
        _give_monster_item(mon, thing_created);
    }
    else if (mons_is_unique(mon->type) && one_chance_in(3))
    {
        const int thing_created =
            items(0, OBJ_POTIONS, OBJ_RANDOM, true, level, 0);

        if (thing_created == NON_ITEM)
            return;

        mitm[thing_created].flags = 0;
        _give_monster_item(mon, thing_created, false,
                           &monsters::pickup_potion);
    }
}

static item_make_species_type _give_weapon(monsters *mon, int level,
                                           bool melee_only = false,
                                           bool give_aux_melee = true)
{
    bool force_item = false;

    item_def               item;
    item_make_species_type item_race = MAKE_ITEM_RANDOM_RACE;

    item.base_type = OBJ_UNASSIGNED;

    if (mon->type == MONS_DANCING_WEAPON
        && player_in_branch( BRANCH_HALL_OF_BLADES ))
    {
        level = MAKE_GOOD_ITEM;
    }

    // moved setting of quantity here to keep it in mind {dlb}
    item.quantity = 1;

    switch (mon->type)
    {
    case MONS_KOBOLD:
        // A few of the smarter kobolds have blowguns.
        if (one_chance_in(10) && level > 1)
        {
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = WPN_BLOWGUN;
            break;
        }
        // intentional fallthrough
    case MONS_BIG_KOBOLD:
        if (x_chance_in_y(3, 5))     // give hand weapon
        {
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = random_choose(WPN_DAGGER,      WPN_DAGGER,
                                           WPN_SHORT_SWORD, WPN_SHORT_SWORD,
                                           WPN_CLUB,        WPN_WHIP,       -1);
        }
        else
            return (item_race);
        break;

    case MONS_HOBGOBLIN:
        if (one_chance_in(3))
            item_race = MAKE_ITEM_ORCISH;

        if (x_chance_in_y(3, 5))     // give hand weapon
        {
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = WPN_CLUB;
        }
        else
            return (item_race);
        break;

    case MONS_GOBLIN:
        if (one_chance_in(3))
            item_race = MAKE_ITEM_ORCISH;

        if (!melee_only && one_chance_in(12) && level)
        {
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = WPN_SLING;
            break;
        }
        // deliberate fall through {dlb}
    case MONS_JESSICA:
    case MONS_IJYB:
        if (x_chance_in_y(3, 5))     // give hand weapon
        {
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = (coinflip() ? WPN_DAGGER : WPN_CLUB);
        }
        else
            return (item_race);
        break;

    case MONS_WIGHT:
    case MONS_NORRIS:
        item.base_type = OBJ_WEAPONS;

        if (one_chance_in(6))
        {
            item.sub_type = random_choose(WPN_SPIKED_FLAIL, WPN_GREAT_MACE,
                                          WPN_WAR_AXE,      WPN_TRIDENT,   -1);
        }
        else
        {
            item.sub_type = random_choose(
                WPN_MACE,      WPN_FLAIL,       WPN_MORNINGSTAR,
                WPN_DAGGER,    WPN_SHORT_SWORD, WPN_LONG_SWORD,
                WPN_SCIMITAR,  WPN_GREAT_SWORD, WPN_HAND_AXE,
                WPN_BATTLEAXE, WPN_SPEAR,       WPN_HALBERD,
                -1);
        }

        if (coinflip())
        {
            force_item  = true;
            item.plus  += 1 + random2(3);
            item.plus2 += 1 + random2(3);

            if (one_chance_in(5))
                set_item_ego_type(item, OBJ_WEAPONS, SPWPN_FREEZING);
        }

        if (one_chance_in(3))
            do_curse_item( item );
        break;

    case MONS_GNOLL:
    case MONS_OGRE_MAGE:
    case MONS_NAGA_WARRIOR:
    case MONS_GREATER_NAGA:
    case MONS_EDMUND:
    case MONS_DUANE:
        item_race = MAKE_ITEM_NO_RACE;
        if (!one_chance_in(5))
        {
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = random_choose(WPN_SPEAR, WPN_SPEAR, WPN_HALBERD,
                                           WPN_CLUB,  WPN_WHIP,  WPN_FLAIL, -1);
        }
        break;

    case MONS_GRUM:
        force_item = true; // guaranteed reaching
        item_race  = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = random_choose(WPN_WHIP,    WPN_WHIP,   WPN_SPEAR,
                                       WPN_HALBERD, WPN_GLAIVE, -1);
        set_item_ego_type(item, OBJ_WEAPONS, SPWPN_REACHING);
        item.plus  += -2 + random2(4);
        item.plus2 += -1 + random2(2);
        break;

    case MONS_ORC:
    case MONS_ORC_PRIEST:
        item_race = MAKE_ITEM_ORCISH;
        // deliberate fall through {gdl}

    case MONS_DRACONIAN:
    case MONS_DRACONIAN_ZEALOT:
        if (!one_chance_in(5))
        {
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = random_choose_weighted(
                30, WPN_DAGGER,      30, WPN_CLUB,
                27, WPN_FLAIL,       24, WPN_HAND_AXE,
                20, WPN_HAMMER,      20, WPN_SHORT_SWORD,
                20, WPN_MACE,        10, WPN_WHIP,
                10, WPN_TRIDENT,     10, WPN_FALCHION,
                10, WPN_MORNINGSTAR, 6,  WPN_WAR_AXE,
                3, WPN_SPIKED_FLAIL,
                0);
        }
        else
            return (item_race);
        break;

    case MONS_TERENCE:
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = random_choose_weighted( 30, WPN_FLAIL,
                                                 20, WPN_HAND_AXE,
                                                 20, WPN_SHORT_SWORD,
                                                 20, WPN_MACE,
                                                 10, WPN_TRIDENT,
                                                 10, WPN_FALCHION,
                                                 10, WPN_MORNINGSTAR,
                                                  3, WPN_SPIKED_FLAIL,
                                                  0);
        break;

    case MONS_DUVESSA:
        item_race = MAKE_ITEM_ELVEN;
        item.base_type = OBJ_WEAPONS;
        item.sub_type = random_choose_weighted(30, WPN_SHORT_SWORD,
                                               10, WPN_SABRE,
                                               0);
        break;

    case MONS_DEEP_ELF_FIGHTER:
    case MONS_DEEP_ELF_HIGH_PRIEST:
    case MONS_DEEP_ELF_KNIGHT:
    case MONS_DEEP_ELF_PRIEST:
    case MONS_DEEP_ELF_SOLDIER:
        item_race = MAKE_ITEM_ELVEN;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = random_choose_weighted(
            20, WPN_LONG_SWORD, 20, WPN_SHORT_SWORD, 14, WPN_SCIMITAR,
            14, WPN_MACE,       13, WPN_BOW,         13, WPN_HAND_CROSSBOW,
            5,  WPN_LONGBOW,
            0);
        break;

    case MONS_DEEP_ELF_BLADEMASTER:
    {
        item_race = MAKE_ITEM_ELVEN;
        item.base_type = OBJ_WEAPONS;

        // If the blademaster already has a weapon, give him the exact same
        // sub_type to match.

        const item_def *weap = mon->mslot_item(MSLOT_WEAPON);
        if (weap && weap->base_type == OBJ_WEAPONS)
            item.sub_type = weap->sub_type;
        else
        {
            item.sub_type = random_choose_weighted(40, WPN_SABRE,
                                                   10, WPN_SHORT_SWORD,
                                                   2,  WPN_QUICK_BLADE,
                                                   0);
        }
        break;
    }

    case MONS_DEEP_ELF_MASTER_ARCHER:
        item_race = MAKE_ITEM_ELVEN;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_LONGBOW;
        break;

    case MONS_DEEP_ELF_ANNIHILATOR:
    case MONS_DEEP_ELF_CONJURER:
    case MONS_DEEP_ELF_DEATH_MAGE:
    case MONS_DEEP_ELF_DEMONOLOGIST:
    case MONS_DEEP_ELF_MAGE:
    case MONS_DEEP_ELF_SORCERER:
    case MONS_DEEP_ELF_SUMMONER:
        item_race = MAKE_ITEM_ELVEN;
        // deliberate fall-through

    case MONS_DRACONIAN_SHIFTER:
    case MONS_DRACONIAN_SCORCHER:
    case MONS_DRACONIAN_ANNIHILATOR:
    case MONS_DRACONIAN_CALLER:
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = random_choose(WPN_LONG_SWORD,  WPN_LONG_SWORD,
                                       WPN_SHORT_SWORD, WPN_SABRE,
                                       WPN_DAGGER,      WPN_WHIP,
                                       -1);
        break;

    case MONS_ORC_WARRIOR:
    case MONS_ORC_HIGH_PRIEST:
    case MONS_BLORK_THE_ORC:
        item_race = MAKE_ITEM_ORCISH;
        // deliberate fall-through {dlb}

    case MONS_DANCING_WEAPON:   // give_level may have been adjusted above
    case MONS_FRANCES:
    case MONS_FRANCIS:
    case MONS_HAROLD:
    case MONS_JOSEPH:
    case MONS_LOUISE:
    case MONS_MICHAEL:
    case MONS_NAGA:
    case MONS_NAGA_MAGE:
    case MONS_RUPERT:
    case MONS_SKELETAL_WARRIOR:
    case MONS_WAYNE:
    case MONS_PALE_DRACONIAN:
    case MONS_RED_DRACONIAN:
    case MONS_WHITE_DRACONIAN:
    case MONS_GREEN_DRACONIAN:
    case MONS_MOTTLED_DRACONIAN:
    case MONS_BLACK_DRACONIAN:
    case MONS_YELLOW_DRACONIAN:
    case MONS_PURPLE_DRACONIAN:
    case MONS_TIAMAT:
        if (mons_genus(mon->type) == MONS_NAGA)
            item_race = MAKE_ITEM_NO_RACE;

        item.base_type = OBJ_WEAPONS;
        item.sub_type  = random_choose_weighted(
            10, WPN_LONG_SWORD, 10, WPN_SHORT_SWORD,
            10, WPN_SCIMITAR,   10, WPN_BATTLEAXE,
            10, WPN_HAND_AXE,   10, WPN_HALBERD,
            10, WPN_GLAIVE,     10, WPN_MORNINGSTAR,
            10, WPN_GREAT_MACE, 10, WPN_TRIDENT,
            9,  WPN_WAR_AXE,     9, WPN_FLAIL,
            1,  WPN_BROAD_AXE,   1, WPN_SPIKED_FLAIL,
            0);
        break;

    case MONS_ORC_WARLORD:
    case MONS_SAINT_ROKA:
        // being at the top has its privileges
        if (one_chance_in(3))
            level = MAKE_GOOD_ITEM;
        // deliberate fall-through

    case MONS_ORC_KNIGHT:
        item_race = MAKE_ITEM_ORCISH;
        // Occasionally get crossbows.
        if (!melee_only && one_chance_in(9))
        {
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = WPN_CROSSBOW;
            break;
        }
        // deliberate fall-through

    case MONS_URUG:
        item_race = MAKE_ITEM_ORCISH;
        // deliberate fall-through

    case MONS_NORBERT:
    case MONS_JOZEF:
    case MONS_VAULT_GUARD:
    case MONS_VAMPIRE_KNIGHT:
    case MONS_DRACONIAN_KNIGHT:
    {
        item.base_type = OBJ_WEAPONS;

        item.sub_type = random_choose_weighted(
            4, WPN_GREAT_SWORD, 4, WPN_LONG_SWORD,
            4, WPN_BATTLEAXE,   4, WPN_WAR_AXE,
            3, WPN_GREAT_MACE,  2, WPN_DIRE_FLAIL,
            1, WPN_BARDICHE,    1, WPN_GLAIVE,
            1, WPN_BROAD_AXE,   1, WPN_HALBERD,
            0);

        if (one_chance_in(4))
            item.plus += 1 + random2(3);
        break;
    }

    case MONS_POLYPHEMUS:
    case MONS_CYCLOPS:
    case MONS_STONE_GIANT:
        item.base_type = OBJ_MISSILES;
        item.sub_type  = MI_LARGE_ROCK;
        break;

    case MONS_TWO_HEADED_OGRE:
    case MONS_ETTIN:
        item_race = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = (one_chance_in(3) ? WPN_GIANT_SPIKED_CLUB
                                           : WPN_GIANT_CLUB);

        if (one_chance_in(10) || mon->type == MONS_ETTIN)
        {
            item.sub_type = (one_chance_in(10) ? WPN_DIRE_FLAIL
                                               : WPN_GREAT_MACE);
        }
        break;

    case MONS_REAPER:
        level = MAKE_GOOD_ITEM;
        // intentional fall-through...

    case MONS_SIGMUND:
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_SCYTHE;
        break;

    case MONS_BALRUG:
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_DEMON_WHIP;
        break;

    case MONS_RED_DEVIL:
        if (!one_chance_in(3))
        {
            item_race = MAKE_ITEM_NO_RACE;
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = (one_chance_in(3) ? WPN_DEMON_TRIDENT
                                               : WPN_TRIDENT);
        }
        break;

    case MONS_OGRE:
    case MONS_HILL_GIANT:
    case MONS_EROLCHA:
        item_race = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = (one_chance_in(3) ? WPN_GIANT_SPIKED_CLUB
                                           : WPN_GIANT_CLUB);

        if (one_chance_in(10))
        {
            item.sub_type = (one_chance_in(10) ? WPN_DIRE_FLAIL
                                               : WPN_GREAT_MACE);
        }
        break;

    case MONS_MERFOLK:
        if (one_chance_in(3))
        {
            item_race = MAKE_ITEM_NO_RACE;
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = WPN_TRIDENT;
            break;
        }
        // intentionally fall through

    case MONS_MERMAID:
        if (one_chance_in(3))
        {
            item_race = MAKE_ITEM_NO_RACE;
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = WPN_SPEAR;
        }
        break;

    case MONS_CENTAUR:
    case MONS_CENTAUR_WARRIOR:
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_BOW;
        if (mon->type == MONS_CENTAUR_WARRIOR && one_chance_in(3))
            item.sub_type = WPN_LONGBOW;
        break;

    case MONS_NESSOS:
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_LONGBOW;
        item.special   = SPWPN_FLAME;
        item.plus     += 1 + random2(3);
        item.plus2    += 1 + random2(3);
        item.colour    = DARKGREY;
        force_item     = true;
        break;

    case MONS_YAKTAUR:
    case MONS_YAKTAUR_CAPTAIN:
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_CROSSBOW;
        break;

    case MONS_EFREET:
    case MONS_ERICA:
    case MONS_AZRAEL:
        force_item     = true;
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_SCIMITAR;
        item.plus      = random2(5);
        item.plus2     = random2(5);
        item.colour    = RED;  // forced by force_item above {dlb}
        set_item_ego_type( item, OBJ_WEAPONS, SPWPN_FLAMING );
        break;

    case MONS_ANGEL:
        force_item     = true;
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.colour    = YELLOW;       // forced by force_item above {dlb}

        item.sub_type  = (one_chance_in(4) ? WPN_GREAT_MACE
                                           : WPN_MACE);

        set_equip_desc(item, ISFLAG_GLOWING);
        set_item_ego_type(item, OBJ_WEAPONS, SPWPN_HOLY_WRATH);
        item.plus  = 1 + random2(3);
        item.plus2 = 1 + random2(3);
        break;

    case MONS_DAEVA:
        force_item     = true;
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.colour    = YELLOW;       // forced by force_item above {dlb}

        item.sub_type  = (one_chance_in(4) ? WPN_BLESSED_EUDEMON_BLADE
                                           : WPN_LONG_SWORD);

        set_equip_desc(item, ISFLAG_GLOWING);
        set_item_ego_type(item, OBJ_WEAPONS, SPWPN_HOLY_WRATH);
        item.plus  = 1 + random2(3);
        item.plus2 = 1 + random2(3);
        break;

    case MONS_HELL_KNIGHT:
    case MONS_MAUD:
    case MONS_FREDERICK:
    case MONS_MARGERY:
        force_item = true;
        item.base_type = OBJ_WEAPONS;
        item.sub_type = (one_chance_in(3) ? WPN_LONG_SWORD :
                         coinflip()       ? WPN_SCIMITAR
                                          : WPN_GREAT_SWORD);

        if (one_chance_in(7))
            item.sub_type = WPN_HALBERD;
        if (one_chance_in(7))
            item.sub_type = WPN_GLAIVE;
        if (one_chance_in(7))
            item.sub_type = WPN_GREAT_MACE;
        if (one_chance_in(7))
            item.sub_type = WPN_BATTLEAXE;
        if (one_chance_in(7))
            item.sub_type = WPN_WAR_AXE;
        if (one_chance_in(7))
            item.sub_type = WPN_BROAD_AXE;
        if (one_chance_in(7))
            item.sub_type = WPN_DEMON_WHIP;
        if (one_chance_in(7))
            item.sub_type = WPN_DEMON_BLADE;
        if (one_chance_in(7))
            item.sub_type = WPN_DEMON_TRIDENT;

        if (one_chance_in(3))
            set_item_ego_type( item, OBJ_WEAPONS, SPWPN_FLAMING );
        else if (one_chance_in(3))
        {
            set_item_ego_type(item, OBJ_WEAPONS,
                              random_choose(SPWPN_DRAINING, SPWPN_VORPAL,
                                            SPWPN_PAIN,     SPWPN_DISTORTION,
                                            SPWPN_SPEED,    -1));
        }

        item.plus  += random2(6);
        item.plus2 += random2(6);

        item.colour = RED;  // forced by force_item above {dlb}

        if (one_chance_in(3))
            item.colour = DARKGREY;
        if (one_chance_in(5))
            item.colour = CYAN;
        break;

    case MONS_FIRE_GIANT:
        force_item = true;
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_GREAT_SWORD;
        item.plus      = 0;
        item.plus2     = 0;
        set_item_ego_type( item, OBJ_WEAPONS, SPWPN_FLAMING );

        item.colour = RED;  // forced by force_item above {dlb}
        if (one_chance_in(3))
            item.colour = DARKGREY;
        if (one_chance_in(5))
            item.colour = CYAN;
        break;

    case MONS_FROST_GIANT:
        force_item = true;
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_BATTLEAXE;
        item.plus      = 0;
        item.plus2     = 0;
        set_item_ego_type( item, OBJ_WEAPONS, SPWPN_FREEZING );

        // forced by force_item above {dlb}
        item.colour = (one_chance_in(3) ? WHITE : CYAN);
        break;

    case MONS_ORC_WIZARD:
    case MONS_ORC_SORCERER:
    case MONS_NERGALLE:
        item_race = MAKE_ITEM_ORCISH;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_DAGGER;
        break;

    case MONS_DOWAN:
        item_race = MAKE_ITEM_ELVEN;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_DAGGER;
        break;

    case MONS_KOBOLD_DEMONOLOGIST:
    case MONS_NECROMANCER:
    case MONS_WIZARD:
    case MONS_PSYCHE:
    case MONS_DONALD:
    case MONS_JOSEPHINE:
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_DAGGER;

        if (mon->type == MONS_PSYCHE)
        {
            set_item_ego_type(item, OBJ_WEAPONS,
                              random_choose_weighted(3, SPWPN_CHAOS,
                                                     1, SPWPN_DISTORTION,
                                                     0));
        }
        break;

    case MONS_AGNES:
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = WPN_LAJATANG;
        if (!one_chance_in(3))
            level = MAKE_GOOD_ITEM;
        break;

    case MONS_SONJA:
        if (!melee_only)
        {
            item.base_type = OBJ_WEAPONS;
            item.sub_type  = WPN_BLOWGUN;
            item_race = MAKE_ITEM_NO_RACE;
            break;
        }
        force_item = true;
        item_race  = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = coinflip() ? WPN_DAGGER : WPN_SHORT_SWORD;
        set_item_ego_type(item, OBJ_WEAPONS,
                          random_choose_weighted(3, SPWPN_DISTORTION,
                                                 2, SPWPN_VENOM,
                                                 1, SPWPN_DRAINING,
                                                 0));
        break;

    case MONS_MAURICE:
        item_race = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = coinflip() ? WPN_DAGGER : WPN_SHORT_SWORD;
        break;

    case MONS_EUSTACHIO:
        item_race = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = (one_chance_in(3) ? WPN_FALCHION : WPN_SABRE);
        break;

    case MONS_CEREBOV:
        force_item = true;
        make_item_unrandart( item, UNRAND_CEREBOV ); break;

    case MONS_DISPATER:
        force_item = true;
        make_item_unrandart( item, UNRAND_DISPATER );
        break;

    case MONS_ASMODEUS:
        force_item = true;
        make_item_unrandart( item, UNRAND_ASMODEUS );
        break;

    case MONS_GERYON:
        //mv: Probably should be moved out of this switch, but it's not
        //worth it, unless we have more monsters with misc. items.
        item.base_type = OBJ_MISCELLANY;
        item.sub_type  = MISC_HORN_OF_GERYON;
        break;

    case MONS_SALAMANDER: //mv: new 8 Aug 2001
                          //Yes, they've got really nice items, but
                          //it's almost impossible to get them
        force_item = true;
        item_race  = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_WEAPONS;
        item.sub_type  = random_choose(WPN_GREAT_SWORD, WPN_TRIDENT,
                                       WPN_SPEAR,       WPN_GLAIVE,
                                       WPN_BOW,         WPN_HALBERD,
                                       -1);

        set_item_ego_type(item, OBJ_WEAPONS, is_range_weapon(item) ?
                          SPWPN_FLAME : SPWPN_FLAMING);

        item.plus   = random2(5);
        item.plus2  = random2(5);
        item.colour = RED;  // forced by force_item above {dlb}
        break;

    default:
        break;
    }

    // Only happens if something in above switch doesn't set it. {dlb}
    if (item.base_type == OBJ_UNASSIGNED)
        return (item_race);

    if (!force_item && mons_is_unique( mon->type ))
    {
        if (x_chance_in_y(10 + mon->hit_dice, 100))
            level = MAKE_GOOD_ITEM;
        else if (level != MAKE_GOOD_ITEM)
            level += 5;
    }

    const object_class_type xitc = item.base_type;
    const int xitt = item.sub_type;

    // Note this mess, all the work above doesn't mean much unless
    // force_item is set... otherwise we're just going to take the
    // base and subtypes and create a new item. -- bwr
    const int thing_created =
        ((force_item) ? get_item_slot() : items(0, xitc, xitt, true,
                                                level, item_race));

    if (thing_created == NON_ITEM)
        return (item_race);

    // Copy temporary item into the item array if were forcing it, since
    // items() won't have done it for us.
    if (force_item)
        mitm[thing_created] = item;

    item_def &i = mitm[thing_created];
    if (melee_only && (i.base_type != OBJ_WEAPONS || is_range_weapon(i)))
    {
        destroy_item(thing_created);
        return (item_race);
    }

    if (force_item)
        item_set_appearance(i);

    _give_monster_item(mon, thing_created, force_item);

    if (give_aux_melee && (i.base_type != OBJ_WEAPONS || is_range_weapon(i)))
        _give_weapon(mon, level, true, false);

    return (item_race);
}

// Hands out ammunition fitting the monster's launcher (if any), or else any
// throwable weapon depending on the monster type.
static void _give_ammo(monsters *mon, int level,
                       item_make_species_type item_race,
                       bool mons_summoned)
{
    // Note that item_race is not reset for this section.
    if (const item_def *launcher = mon->launcher())
    {
        const object_class_type xitc = OBJ_MISSILES;
        int xitt = fires_ammo_type(*launcher);

        if (xitt == MI_STONE && one_chance_in(15))
            xitt = MI_SLING_BULLET;

        const int thing_created = items(0, xitc, xitt, true, level, item_race);

        if (thing_created == NON_ITEM)
            return;

        if (xitt == MI_NEEDLE)
        {
            if (mon->type == MONS_SONJA)
            {
                set_item_ego_type(mitm[thing_created], OBJ_MISSILES,
                                  SPMSL_CURARE);

                mitm[thing_created].quantity = random_range(4, 10);
            }
            else
            {
                set_item_ego_type(mitm[thing_created], OBJ_MISSILES,
                                  _got_curare_roll(level) ? SPMSL_CURARE
                                                          : SPMSL_POISONED);

                if (get_ammo_brand( mitm[thing_created] ) == SPMSL_CURARE)
                    mitm[thing_created].quantity = random_range(2, 8);
            }
        }
        else
        {
            // Sanity check to avoid useless brands.
            const int bow_brand  = get_weapon_brand(*launcher);
            const int ammo_brand = get_ammo_brand(mitm[thing_created]);
            if (ammo_brand != SPMSL_NORMAL
                && (bow_brand == SPWPN_FLAME || bow_brand == SPWPN_FROST))
            {
                mitm[thing_created].special = SPMSL_NORMAL;
            }
        }

        // Master archers get double ammo - archery is their only attack.
        if (mon->type == MONS_DEEP_ELF_MASTER_ARCHER)
            mitm[thing_created].quantity *= 2;
        else if (mon->type == MONS_NESSOS)
            mitm[thing_created].special = SPMSL_POISONED;

        _give_monster_item(mon, thing_created);
    }
    else
    {
        // Give some monsters throwing weapons.
        int weap_type = -1;
        object_class_type weap_class = OBJ_WEAPONS;
        int qty = 0;
        switch (mon->type)
        {
        case MONS_KOBOLD:
        case MONS_BIG_KOBOLD:
            if (x_chance_in_y(2, 5))
            {
                item_race  = MAKE_ITEM_NO_RACE;
                weap_class = OBJ_MISSILES;
                weap_type  = MI_DART;
                qty = 1 + random2(5);
            }
            break;

        case MONS_ORC_WARRIOR:
            if (one_chance_in(
                    you.where_are_you == BRANCH_ORCISH_MINES? 9 : 20))
            {
                weap_type = random_choose(WPN_HAND_AXE, WPN_SPEAR, -1);
                qty       = random_range(4, 8);
                item_race = MAKE_ITEM_ORCISH;
            }
            break;

        case MONS_ORC:
            if (one_chance_in(20))
            {
                weap_type = random_choose(WPN_HAND_AXE, WPN_SPEAR, -1);
                qty       = random_range(2, 5);
                item_race = MAKE_ITEM_ORCISH;
            }
            break;

        case MONS_URUG:
            weap_type  = MI_JAVELIN;
            weap_class = OBJ_MISSILES;
            item_race  = MAKE_ITEM_ORCISH;
            qty = random_range(4, 7);
            break;

        case MONS_MERFOLK:
            if (!one_chance_in(3))
            {
                item_race = MAKE_ITEM_NO_RACE;
                if (coinflip())
                {
                    weap_type = WPN_SPEAR;
                    qty       = 1 + random2(3);
                }
                else
                {
                    weap_class = OBJ_MISSILES;
                    weap_type = MI_JAVELIN;
                    qty       = 3 + random2(6);
                }
            }
            if (one_chance_in(6) && !mons_summoned)
            {
                weap_class = OBJ_MISSILES;
                weap_type  = MI_THROWING_NET;
                qty        = 1;
                if (one_chance_in(4))
                    qty += random2(3); // up to three nets
            }
            break;

        case MONS_DRACONIAN_KNIGHT:
        case MONS_GNOLL:
        case MONS_HILL_GIANT:
            if (!one_chance_in(20))
                break;
            // deliberate fall-through

        case MONS_HAROLD: // bounty hunters
        case MONS_JOZEF:  // up to 5 nets
            if (mons_summoned)
                break;

            weap_class = OBJ_MISSILES;
            weap_type  = MI_THROWING_NET;
            qty        = 1;
            if (one_chance_in(3))
                qty++;
            if (mon->type == MONS_HAROLD || mon->type == MONS_JOZEF)
                qty += random2(4);

            break;

        default:
            break;
        }

        if (weap_type == -1)
            return;

        const int thing_created =
            items(0, weap_class, weap_type, true, level, item_race);

        if (thing_created != NON_ITEM)
        {
            item_def& w(mitm[thing_created]);

            // Limit returning brand to only one.
            if (weap_type == OBJ_WEAPONS
                && get_weapon_brand(w) == SPWPN_RETURNING)
            {
                qty = 1;
            }

            w.quantity = qty;

            _give_monster_item(mon, thing_created, false,
                               &monsters::pickup_throwable_weapon);
        }
    }
}

static bool make_item_for_monster(
    monsters *mons,
    object_class_type base,
    int subtype,
    int level,
    item_make_species_type race = MAKE_ITEM_NO_RACE,
    int allow_uniques = 0)
{
    const int bp = get_item_slot();
    if (bp == NON_ITEM)
        return (false);

    const int thing_created =
        items(allow_uniques, base, subtype, true, level, race);

    if (thing_created == NON_ITEM)
        return (false);

    _give_monster_item(mons, thing_created);
    return (true);
}

void give_shield(monsters *mon, int level)
{
    const item_def *main_weap = mon->mslot_item(MSLOT_WEAPON);
    const item_def *alt_weap  = mon->mslot_item(MSLOT_ALT_WEAPON);

    // If the monster is already wielding/carrying a two-handed weapon, it
    // doesn't get a shield. (Monsters always prefer raw damage to protection!)
    if (main_weap && hands_reqd(*main_weap, mon->body_size()) == HANDS_TWO
        || alt_weap && hands_reqd(*alt_weap, mon->body_size()) == HANDS_TWO)
    {
        return;
    }

    switch (mon->type)
    {
    case MONS_DAEVA:
        make_item_for_monster(mon, OBJ_ARMOUR, ARM_LARGE_SHIELD,
                              level * 2 + 1, MAKE_ITEM_NO_RACE, 1);
        break;

    case MONS_DEEP_ELF_SOLDIER:
    case MONS_DEEP_ELF_FIGHTER:
        if (one_chance_in(6))
        {
            make_item_for_monster(mon, OBJ_ARMOUR, ARM_BUCKLER,
                                  level, MAKE_ITEM_ELVEN);
        }
        break;
    case MONS_NAGA_WARRIOR:
    case MONS_VAULT_GUARD:
        if (one_chance_in(3))
        {
            make_item_for_monster(mon, OBJ_ARMOUR,
                                  one_chance_in(3) ? ARM_LARGE_SHIELD
                                                   : ARM_SHIELD,
                                  level, MAKE_ITEM_NO_RACE);
        }
        break;
    case MONS_DRACONIAN_KNIGHT:
        if (coinflip())
        {
            make_item_for_monster(mon, OBJ_ARMOUR,
                                  coinflip()? ARM_LARGE_SHIELD : ARM_SHIELD,
                                  level, MAKE_ITEM_NO_RACE);
        }
        break;
    case MONS_DEEP_ELF_KNIGHT:
        if (one_chance_in(3))
        {
            make_item_for_monster(mon, OBJ_ARMOUR, ARM_BUCKLER,
                                  level, MAKE_ITEM_ELVEN);
        }
        break;
    case MONS_NORRIS:
        make_item_for_monster(mon, OBJ_ARMOUR, ARM_BUCKLER,
                              level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
        break;
    case MONS_NORBERT:
    case MONS_LOUISE:
        make_item_for_monster(mon, OBJ_ARMOUR, ARM_LARGE_SHIELD,
                              level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
        break;
    case MONS_DONALD:
        make_item_for_monster(mon, OBJ_ARMOUR, ARM_SHIELD,
                              level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
        break;

    default:
        break;
    }
}

void give_armour(monsters *mon, int level)
{
    item_make_species_type item_race = MAKE_ITEM_RANDOM_RACE;

    int force_colour = 0; // mv: Important!!! Items with force_colour = 0
                          // are colored by default after following
                          // switch. Others will get force_colour.

    item_def item;

    switch (mon->type)
    {
    case MONS_DEEP_ELF_BLADEMASTER:
    case MONS_DEEP_ELF_MASTER_ARCHER:
        item_race      = MAKE_ITEM_ELVEN;
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_LEATHER_ARMOUR;
        break;

    case MONS_DUVESSA:
    case MONS_DEEP_ELF_ANNIHILATOR:
    case MONS_DEEP_ELF_CONJURER:
    case MONS_DEEP_ELF_DEATH_MAGE:
    case MONS_DEEP_ELF_DEMONOLOGIST:
    case MONS_DEEP_ELF_FIGHTER:
    case MONS_DEEP_ELF_HIGH_PRIEST:
    case MONS_DEEP_ELF_KNIGHT:
    case MONS_DEEP_ELF_MAGE:
    case MONS_DEEP_ELF_PRIEST:
    case MONS_DEEP_ELF_SOLDIER:
    case MONS_DEEP_ELF_SORCERER:
    case MONS_DEEP_ELF_SUMMONER:
        if (item_race == MAKE_ITEM_RANDOM_RACE)
            item_race = MAKE_ITEM_ELVEN;
        // deliberate fall through {dlb}

    case MONS_IJYB:
    case MONS_ORC:
    case MONS_ORC_HIGH_PRIEST:
    case MONS_ORC_PRIEST:
    case MONS_ORC_SORCERER:
        if (item_race == MAKE_ITEM_RANDOM_RACE)
            item_race = MAKE_ITEM_ORCISH;
        // deliberate fall through {dlb}

    case MONS_ERICA:
    case MONS_HAROLD:
    case MONS_JOSEPH:
    case MONS_JOSEPHINE:
    case MONS_JOZEF:
    case MONS_NORBERT:
    case MONS_PSYCHE:
        if (x_chance_in_y(2, 5))
        {
            item.base_type = OBJ_ARMOUR;

            const int temp_rand = random2(8);
            item.sub_type = ((temp_rand  < 4) ? ARM_LEATHER_ARMOUR :
                             (temp_rand  < 6) ? ARM_RING_MAIL :
                             (temp_rand == 6) ? ARM_SCALE_MAIL
                                              : ARM_CHAIN_MAIL);
        }
        else
            return;
        break;

    case MONS_TERENCE:
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = random_choose_weighted(1, ARM_RING_MAIL,
                                                3, ARM_SCALE_MAIL,
                                                2, ARM_CHAIN_MAIL,
                                                0);
        break;

    case MONS_GRUM:
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_ANIMAL_SKIN;
        break;

    case MONS_URUG:
        item_race = MAKE_ITEM_ORCISH;
        // deliberate fall through {dlb}

    case MONS_DUANE:
    case MONS_EDMUND:
    case MONS_RUPERT:
    case MONS_WAYNE:
    {
        item.base_type = OBJ_ARMOUR;

        const int temp_rand = random2(4);
        item.sub_type = ((temp_rand == 0) ? ARM_LEATHER_ARMOUR :
                         (temp_rand == 1) ? ARM_RING_MAIL :
                         (temp_rand == 2) ? ARM_SCALE_MAIL
                                          : ARM_CHAIN_MAIL);
        break;
    }

    case MONS_ORC_WARLORD:
    case MONS_SAINT_ROKA:
        // Being at the top has its privileges. :)
        if (one_chance_in(3))
            level = MAKE_GOOD_ITEM;
        // deliberate fall through

    case MONS_ORC_KNIGHT:
    case MONS_ORC_WARRIOR:
        item_race = MAKE_ITEM_ORCISH;
        // deliberate fall through {dlb}

    case MONS_FREDERICK:
    case MONS_HELL_KNIGHT:
    case MONS_LOUISE:
    case MONS_MARGERY:
    case MONS_MAUD:
    case MONS_VAMPIRE_KNIGHT:
    case MONS_VAULT_GUARD:
    {
        item.base_type = OBJ_ARMOUR;

        const int temp_rand = random2(4);
        item.sub_type = ((temp_rand == 0) ? ARM_CHAIN_MAIL :
                         (temp_rand == 1) ? ARM_SPLINT_MAIL :
                         (temp_rand == 2) ? ARM_BANDED_MAIL
                                          : ARM_PLATE_MAIL);
        break;
    }

    case MONS_ANGEL:
    case MONS_SIGMUND:
    case MONS_WIGHT:
        item_race = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_ROBE;
        force_colour   = WHITE;
        break;

    // Centaurs sometimes wear barding.
    case MONS_CENTAUR:
    case MONS_CENTAUR_WARRIOR:
    case MONS_YAKTAUR:
    case MONS_YAKTAUR_CAPTAIN:
        if ( one_chance_in( mon->type == MONS_CENTAUR              ? 1000 :
                            mon->type == MONS_CENTAUR_WARRIOR      ?  500 :
                            mon->type == MONS_YAKTAUR              ?  300
                         /* mon->type == MONS_YAKTAUR_CAPTAIN ? */ :  200))
        {
            item.base_type = OBJ_ARMOUR;
            item.sub_type  = ARM_CENTAUR_BARDING;
        }
        else
            return;
        break;

    case MONS_NAGA:
    case MONS_NAGA_MAGE:
    case MONS_NAGA_WARRIOR:
    case MONS_GREATER_NAGA:
        if ( one_chance_in( mon->type == MONS_NAGA         ?  800 :
                            mon->type == MONS_NAGA_WARRIOR ?  300 :
                            mon->type == MONS_NAGA_MAGE    ?  200
                                                           :  100 ))
        {
            item_race      = MAKE_ITEM_NO_RACE;
            item.base_type = OBJ_ARMOUR;
            item.sub_type  = ARM_NAGA_BARDING;
        }
        else if (mon->type == MONS_GREATER_NAGA || one_chance_in(3))
        {
            item_race      = MAKE_ITEM_NO_RACE;
            item.base_type = OBJ_ARMOUR;
            item.sub_type  = ARM_ROBE;
        }
        else
            return;
        break;

    case MONS_GASTRONOK:
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_WIZARD_HAT;
        break;

    case MONS_MAURICE:
        item_race      = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_CLOAK;
        force_colour   = DARKGREY;
        break;

    case MONS_DOWAN:
        item_race = MAKE_ITEM_ELVEN;
        // intentional fall-through
    case MONS_DONALD:
    case MONS_JESSICA:
    case MONS_KOBOLD_DEMONOLOGIST:
    case MONS_OGRE_MAGE:
    case MONS_EROLCHA:
    case MONS_DRACONIAN:
    case MONS_RED_DRACONIAN:
    case MONS_WHITE_DRACONIAN:
    case MONS_GREEN_DRACONIAN:
    case MONS_PALE_DRACONIAN:
    case MONS_MOTTLED_DRACONIAN:
    case MONS_BLACK_DRACONIAN:
    case MONS_YELLOW_DRACONIAN:
    case MONS_PURPLE_DRACONIAN:
    case MONS_DRACONIAN_SHIFTER:
    case MONS_DRACONIAN_SCORCHER:
    case MONS_DRACONIAN_ANNIHILATOR:
    case MONS_DRACONIAN_CALLER:
    case MONS_DRACONIAN_MONK:
    case MONS_DRACONIAN_ZEALOT:
    case MONS_DRACONIAN_KNIGHT:
    case MONS_WIZARD:
    case MONS_ILSUIW:
        if (item_race == MAKE_ITEM_RANDOM_RACE)
            item_race = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_ROBE;
        break;

    case MONS_TIAMAT:
        item_race = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_GOLD_DRAGON_ARMOUR;
        break;

    case MONS_ORC_WIZARD:
    case MONS_BLORK_THE_ORC:
    case MONS_NERGALLE:
        item_race = MAKE_ITEM_ORCISH;
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_ROBE;
        break;

    case MONS_BORIS:
        level = MAKE_GOOD_ITEM;
        // fall-through
    case MONS_AGNES:
    case MONS_FRANCES:
    case MONS_FRANCIS:
    case MONS_NECROMANCER:
    case MONS_VAMPIRE_MAGE:
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_ROBE;
        force_colour   = DARKGREY;
        break;

    case MONS_EUSTACHIO:
        item_race = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_ARMOUR;
        item.sub_type = ARM_LEATHER_ARMOUR;
        break;

    case MONS_NESSOS:
        item_race = MAKE_ITEM_NO_RACE;
        item.base_type = OBJ_ARMOUR;
        item.sub_type  = ARM_CENTAUR_BARDING;
        force_colour   = DARKGREY;
        break;

    default:
        return;
    }

    const object_class_type xitc = item.base_type;
    const int xitt = item.sub_type;

    if (mons_is_unique( mon->type ) && level != MAKE_GOOD_ITEM)
    {
        if (x_chance_in_y(9 + mon->hit_dice, 100))
            level = MAKE_GOOD_ITEM;
        else
            level = level * 2 + 5;
    }

    const int thing_created = items(0, xitc, xitt, true, level, item_race);

    if (thing_created == NON_ITEM)
        return;

    _give_monster_item(mon, thing_created);

    //mv: All items with force_colour = 0 are colored via items().
    if (force_colour)
        mitm[thing_created].colour = force_colour;
}

static void _give_gold(monsters *mon, int level)
{
    const int idx = items(0, OBJ_GOLD, 0, true, level, 0);
    _give_monster_item(mon, idx);
}

void give_item(int mid, int level_number, bool mons_summoned)
{
    monsters *mons = &menv[mid];

    if (mons->type == MONS_MAURICE)
        _give_gold(mons, level_number);

    _give_scroll(mons, level_number);
    _give_wand(mons, level_number);
    _give_potion(mons, level_number);

    const item_make_species_type item_race = _give_weapon(mons, level_number);

    _give_ammo(mons, level_number, item_race, mons_summoned);

    give_armour(mons, 1 + level_number / 2);
    give_shield(mons, 1 + level_number / 2);
}

jewellery_type get_random_amulet_type()
{
    return (jewellery_type)
                (AMU_FIRST_AMULET + random2(NUM_JEWELLERY - AMU_FIRST_AMULET));
}

static jewellery_type _get_raw_random_ring_type()
{
    return (jewellery_type) (RING_REGENERATION + random2(NUM_RINGS));
}

jewellery_type get_random_ring_type()
{
    const jewellery_type j = _get_raw_random_ring_type();
    // Adjusted distribution here. - bwr
    if ((j == RING_INVISIBILITY
           || j == RING_REGENERATION
           || j == RING_TELEPORT_CONTROL
           || j == RING_SLAYING)
        && !one_chance_in(3))
    {
        return (_get_raw_random_ring_type());
    }

    return (j);
}

armour_type get_random_body_armour_type(int item_level)
{
    for (int tries = 100; tries > 0; --tries)
    {
        const armour_type tr = get_random_armour_type(item_level);
        if (get_armour_slot(tr) == EQ_BODY_ARMOUR)
            return (tr);
    }
    return (ARM_ROBE);
}

// FIXME: Need to clean up this mess.
armour_type get_random_armour_type(int item_level)
{
    // Default (lowest-level) armours.
    const armour_type defarmours[] = { ARM_ROBE, ARM_LEATHER_ARMOUR,
                                       ARM_RING_MAIL };

    int armtype = RANDOM_ELEMENT(defarmours);

    if (x_chance_in_y(11 + item_level, 35))
    {
        // Low-level armours.
        const armour_type lowarmours[] = { ARM_ROBE, ARM_LEATHER_ARMOUR,
                                           ARM_RING_MAIL, ARM_SCALE_MAIL,
                                           ARM_CHAIN_MAIL };

        armtype = RANDOM_ELEMENT(lowarmours);

        if (one_chance_in(4))
            armtype = ARM_ANIMAL_SKIN;
    }

    if (x_chance_in_y(11 + item_level, 60))
    {
        // Medium-level armours.
        const armour_type medarmours[] = { ARM_ROBE, ARM_LEATHER_ARMOUR,
                                           ARM_RING_MAIL, ARM_SCALE_MAIL,
                                           ARM_CHAIN_MAIL, ARM_SPLINT_MAIL,
                                           ARM_BANDED_MAIL, ARM_PLATE_MAIL };

        armtype = RANDOM_ELEMENT(medarmours);
    }

    if (one_chance_in(20) && x_chance_in_y(11 + item_level, 400))
    {
        // High-level armours, including troll and some dragon armours.
        const armour_type hiarmours[] = { ARM_CRYSTAL_PLATE_MAIL,
                                          ARM_TROLL_HIDE,
                                          ARM_TROLL_LEATHER_ARMOUR,
                                          ARM_DRAGON_HIDE, ARM_DRAGON_ARMOUR,
                                          ARM_ICE_DRAGON_HIDE,
                                          ARM_ICE_DRAGON_ARMOUR };

        armtype = RANDOM_ELEMENT(hiarmours);
    }

    if (one_chance_in(20) && x_chance_in_y(11 + item_level, 500))
    {
        // Animal skins and high-level armours, including the rest of
        // the dragon armours.
        const armour_type morehiarmours[] = { ARM_ANIMAL_SKIN,
                                              ARM_STEAM_DRAGON_HIDE,
                                              ARM_STEAM_DRAGON_ARMOUR,
                                              ARM_MOTTLED_DRAGON_HIDE,
                                              ARM_MOTTLED_DRAGON_ARMOUR,
                                              ARM_STORM_DRAGON_HIDE,
                                              ARM_STORM_DRAGON_ARMOUR,
                                              ARM_GOLD_DRAGON_HIDE,
                                              ARM_GOLD_DRAGON_ARMOUR,
                                              ARM_SWAMP_DRAGON_HIDE,
                                              ARM_SWAMP_DRAGON_ARMOUR };

        armtype = RANDOM_ELEMENT(morehiarmours);

        if (armtype == ARM_ANIMAL_SKIN && one_chance_in(20))
            armtype = ARM_CRYSTAL_PLATE_MAIL;
    }

    // Secondary armours.
    if (one_chance_in(5))
    {
        const armour_type secarmours[] = { ARM_SHIELD, ARM_CLOAK, ARM_HELMET,
                                           ARM_GLOVES, ARM_BOOTS };

        armtype = RANDOM_ELEMENT(secarmours);

        if (armtype == ARM_HELMET && one_chance_in(3))
        {
            const armour_type hats[] = { ARM_CAP, ARM_WIZARD_HAT, ARM_HELMET };

            armtype = RANDOM_ELEMENT(hats);
        }
        else if (armtype == ARM_SHIELD)
        {
            armtype = random_choose_weighted(333, ARM_SHIELD,
                                             500, ARM_BUCKLER,
                                             167, ARM_LARGE_SHIELD,
                                               0);
        }
    }

    return static_cast<armour_type>(armtype);
}

// Sets item appearance to match brands, if any.
void item_set_appearance(item_def &item)
{
    if (get_equip_desc(item) != ISFLAG_NO_DESC)
        return;

    switch (item.base_type)
    {
    case OBJ_WEAPONS:
        if (_weapon_is_visibly_special(item))
        {
            set_equip_desc(item,
                           (coinflip() ? ISFLAG_GLOWING : ISFLAG_RUNED));
        }
        break;

    case OBJ_ARMOUR:
        if (_armour_is_visibly_special(item))
        {
            const item_status_flag_type descs[] = { ISFLAG_GLOWING,
                                                    ISFLAG_RUNED,
                                                    ISFLAG_EMBROIDERED_SHINY };

            set_equip_desc(item, RANDOM_ELEMENT(descs));
        }
        break;

    default:
        break;
    }
}