diff --git a/crawl-ref/source/dgn-overview.cc b/crawl-ref/source/dgn-overview.cc
index 6f716d64de5..2a6ac0180f4 100644
--- a/crawl-ref/source/dgn-overview.cc
+++ b/crawl-ref/source/dgn-overview.cc
@@ -167,6 +167,7 @@ static string shoptype_to_string(shop_type s)
case SHOP_BOOK: return ":";
case SHOP_DISTILLERY: return "!";
case SHOP_SCROLL: return "?";
+ case SHOP_EVOKABLES: return "}";
default: return "x";
}
}
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 3221c0b0f4d..bb27473e4ac 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -5995,7 +5995,7 @@ void place_spec_shop(const coord_def& where, shop_type force_type)
int greed_for_shop_type(shop_type shop, int level_number)
{
- if (!shoptype_identifies_stock(shop))
+ if (!shoptype_identifies_stock(shop) || shop == SHOP_EVOKABLES)
{
const int rand = random2avg(19, 2);
return 15 + rand + random2(level_number);
@@ -6090,6 +6090,22 @@ static int _choose_shop_item_level(shop_type shop_type_, int level_number)
return min(base_level + bazaar_bonus, level_number * 5);
}
+static int _item_in_shop_subtype(shop_type shop_type,
+ object_class_type base_type)
+{
+ switch (shop_type)
+ {
+ // We'd almost never roll an orb from the armour subtypes so force it here
+ case SHOP_EVOKABLES:
+ if (base_type == OBJ_ARMOUR)
+ return ARM_ORB;
+ // All other shops and base types are happy with any sub type
+ // (orbs will be evicted from armour shops later in _valid_item_for_shop)
+ default:
+ return OBJ_RANDOM;
+ }
+}
+
/**
* Is the given item valid for placement in the given shop?
*
@@ -6098,8 +6114,7 @@ static int _choose_shop_item_level(shop_type shop_type_, int level_number)
* @param spec The specification for the shop.
* @return Whether the item is valid.
*/
-static bool _valid_item_for_shop(int item_index, shop_type shop_type_,
- shop_spec &spec)
+static bool _valid_item_for_shop(int item_index, shop_type shop_type_)
{
if (item_index == NON_ITEM)
return false;
@@ -6113,15 +6128,15 @@ static bool _valid_item_for_shop(int item_index, shop_type shop_type_,
return false;
// Don't place missiles or books in general antique shops...
- if (shop_type_ == SHOP_GENERAL_ANTIQUE
- && (item.base_type == OBJ_MISSILES
- || item.base_type == OBJ_BOOKS))
- {
- // ...unless they're specified by the item spec.
- return !spec.items.empty();
- }
-
- return true;
+ return !(shop_type_ == SHOP_GENERAL_ANTIQUE
+ && (item.base_type == OBJ_MISSILES
+ || item.base_type == OBJ_BOOKS)
+ // Orb "shields" aren't really armour
+ || (shop_type_ == SHOP_ARMOUR || shop_type_ == SHOP_ARMOUR_ANTIQUE)
+ && item.sub_type == ARM_ORB
+ // But instead count as gadgets
+ || (shop_type_ == SHOP_EVOKABLES)
+ && item.base_type == OBJ_ARMOUR && item.sub_type != ARM_ORB);
}
/**
@@ -6155,7 +6170,6 @@ static void _stock_shop_item(int j, shop_type shop_type_,
while (true)
{
object_class_type basetype = item_in_shop(shop_type_);
- int subtype = OBJ_RANDOM;
if (!spec.items.empty() && !spec.use_all)
{
@@ -6176,6 +6190,7 @@ static void _stock_shop_item(int j, shop_type shop_type_,
// gozag shop items are better
const bool good_item = spec.gozag || one_chance_in(4);
const int level = good_item ? ISPEC_GOOD_ITEM : item_level;
+ const int subtype = _item_in_shop_subtype(shop_type_, basetype);
item_index = items(true, basetype, subtype, level);
}
@@ -6190,8 +6205,12 @@ static void _stock_shop_item(int j, shop_type shop_type_,
}
}
- if (_valid_item_for_shop(item_index, shop_type_, spec))
+ // Exit loop if we found a valid item or one from the item spec
+ if (item_index != NON_ITEM && !spec.items.empty()
+ || _valid_item_for_shop(item_index, shop_type_))
+ {
break;
+ }
// Reset object and try again.
if (item_index != NON_ITEM)
@@ -6224,11 +6243,10 @@ static shop_type _random_shop()
{
return random_choose(SHOP_WEAPON, SHOP_ARMOUR, SHOP_WEAPON_ANTIQUE,
SHOP_ARMOUR_ANTIQUE, SHOP_GENERAL_ANTIQUE,
- SHOP_JEWELLERY, SHOP_BOOK,
+ SHOP_JEWELLERY, SHOP_BOOK, SHOP_EVOKABLES,
SHOP_DISTILLERY, SHOP_SCROLL, SHOP_GENERAL);
}
-
/**
* Attempt to place a shop in a given location.
*
@@ -6256,6 +6274,11 @@ void place_spec_shop(const coord_def& where, shop_spec &spec, int shop_level)
shop.type = spec.sh_type;
if (shop.type == SHOP_RANDOM)
shop.type = _random_shop();
+ // Re-roll if we got a gadget shop below level 10; you need to roll it
+ // twice in a row to get one here. They're *really* rare. Level 10 means
+ // they could start showing up in Orc end vaults.
+ if (shop.type == SHOP_EVOKABLES && level_number < 10)
+ shop.type = _random_shop();
shop.greed = _shop_greed(shop.type, level_number, spec.greed);
shop.pos = where;
@@ -6292,8 +6315,6 @@ object_class_type item_in_shop(shop_type shop_type)
return OBJ_RANDOM;
case SHOP_JEWELLERY:
- if (one_chance_in(10))
- return OBJ_TALISMANS;
return OBJ_JEWELLERY;
case SHOP_BOOK:
@@ -6305,6 +6326,20 @@ object_class_type item_in_shop(shop_type shop_type)
case SHOP_SCROLL:
return OBJ_SCROLLS;
+ case SHOP_EVOKABLES:
+ {
+ // Gadget shops are rather a grab bag of stuff that doesn't fit elsewhere.
+ // They are very nice shops so are quite rare.
+ return random_choose_weighted(
+ 100, OBJ_WANDS,
+ 50, OBJ_MISCELLANY,
+ 30, OBJ_TALISMANS, // Evoked even if they don't use evo
+ 20, OBJ_STAVES, // Since they use evocations skill too
+ // (and aren't covered by OBJ_WEAPONS)
+ 20, OBJ_ARMOUR // Only for orbs
+ );
+ }
+
default:
die("unknown shop type %d", shop_type);
}
diff --git a/crawl-ref/source/god-abil.cc b/crawl-ref/source/god-abil.cc
index 6684957e583..30bd624549b 100644
--- a/crawl-ref/source/god-abil.cc
+++ b/crawl-ref/source/god-abil.cc
@@ -3662,9 +3662,10 @@ static bool _shop_type_valid(shop_type type)
{
#if TAG_MAJOR_VERSION == 34
case SHOP_FOOD:
- case SHOP_EVOKABLES:
return false;
#endif
+ case SHOP_EVOKABLES:
+ return !you.has_mutation(MUT_NO_ARTIFICE);
case SHOP_DISTILLERY:
return !you.has_mutation(MUT_NO_DRINK);
case SHOP_WEAPON:
diff --git a/crawl-ref/source/shop-type.h b/crawl-ref/source/shop-type.h
index f7791aa3eb8..7537878ad4e 100644
--- a/crawl-ref/source/shop-type.h
+++ b/crawl-ref/source/shop-type.h
@@ -10,9 +10,7 @@ enum shop_type
SHOP_ARMOUR_ANTIQUE,
SHOP_GENERAL_ANTIQUE,
SHOP_JEWELLERY,
-#if TAG_MAJOR_VERSION == 34
- SHOP_EVOKABLES, // wands, rods, and misc items
-#endif
+ SHOP_EVOKABLES, // wands, evokers, and other miscellany
SHOP_BOOK,
#if TAG_MAJOR_VERSION == 34
SHOP_FOOD,
diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc
index c9f009d53a7..2cfbab12df7 100644
--- a/crawl-ref/source/shopping.cc
+++ b/crawl-ref/source/shopping.cc
@@ -1535,9 +1535,9 @@ string shop_type_name(shop_type type)
return "Jewellery";
case SHOP_BOOK:
return "Book";
-#if TAG_MAJOR_VERSION == 34
case SHOP_EVOKABLES:
return "Gadget";
+#if TAG_MAJOR_VERSION == 34
case SHOP_FOOD:
return "Removed Food";
#endif
@@ -1639,9 +1639,7 @@ static const char *shop_types[] =
"antique armour",
"antiques",
"jewellery",
-#if TAG_MAJOR_VERSION == 34
- "removed gadget",
-#endif
+ "gadget",
"book",
#if TAG_MAJOR_VERSION == 34
"removed food",
diff --git a/crawl-ref/source/tilepick.cc b/crawl-ref/source/tilepick.cc
index 560195ad782..57729e9762d 100644
--- a/crawl-ref/source/tilepick.cc
+++ b/crawl-ref/source/tilepick.cc
@@ -151,9 +151,9 @@ tileidx_t tileidx_shop(const shop_struct *shop)
return TILE_SHOP_ARMOUR;
case SHOP_JEWELLERY:
return TILE_SHOP_JEWELLERY;
-#if TAG_MAJOR_VERSION == 34
case SHOP_EVOKABLES:
return TILE_SHOP_GADGETS;
+#if TAG_MAJOR_VERSION == 34
case SHOP_FOOD:
return TILE_SHOP_FOOD;
#endif