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