##############################################################################
#
# Treasure Trove (by due)
#
# Troves are once-only tolled portals to a treasure chamber, most of which
# are weighted acquirement-esque towards your skills.  Of course, there's a
# chance that you'll get rubbish (casters in an weapon/armour room and melee
# fighters in a library), but that's kind of the point.
#
##############################################################################

: crawl_require('dlua/vault.lua')

{{

trove = {}

function trove.get_trove_item(e, value, base_item)
  -- This function should return a table with the following values:
  --  quantity=0 (number of items, 1 unless consumables)
  --  base_type="armour" (armour, weapon, potion, scroll, jewellery, or miscellaneous)
  --  sub_type="robe" (short sword, etc)
  --  ego_type="resistance" (or false)
  --  plus1=4 (or false)
  --  artefact_name=false (setting this will compare artefact names and status
  --                       and will be used as the full title for artefact books
  --                       and so-on. leave as false for non-artefacts.)
  local item = {
    quantity=1,
    base_type="",
    sub_type="",
    ego_type=false,
    plus1=false,
-- start TAG_MAJOR_VERSION == 34
    plus2=false,
-- end TAG_MAJOR_VERSION
    artefact_name=false,
  }

  -- For testing purposes, you can force an item.
  if base_item ~= nil then
    item.quantity = base_item.quantity
    local p1 = base_item.pluses()
    item.plus1 = p1
    item.ego_type = base_item.ego_type
    item.base_type = base_item.base_type
    item.sub_type = base_item.sub_type
    item.artefact_name = base_item.artefact_name
    if (base_item.sub_type == "rune of Zot") then
      item.ego_type = base_item.name()
    end
    return item
  end

  local d = crawl.roll_dice

  -- base is item.base_type, type is item.sub_type, quant is an additional parameter (quantity, charges, etc)
  local prices = {
       {weight=7, base="scroll", type="acquirement", quant=2},
       {weight=10, base="miscellaneous", type="rune of Zot", quant=3, name="slimy rune of Zot"},
       {weight=10, base="miscellaneous", type="rune of Zot", quant=11, name="abyssal rune of Zot"},
       {weight=10, base="miscellaneous", type="horn of Geryon"} }

  -- demon weapon types are interchangeable in trove fees (it will just ask for
  -- 'any demon weapon')
  local wpn = {weight=7, {base="weapon", type="demon whip", quant=2+d(3)+d(2)} }

  if you.race() ~= "Felid" then
    for _, toll in ipairs(wpn) do
      table.insert(prices, toll)
    end
  end

  local arm = {
       {weight=1, base="armour", type="golden dragon scales", quant=1+d(2)},
       {weight=2, base="armour", type="storm dragon scales", quant=d(2)+d(2)},
       {weight=2, base="armour", type="shadow dragon scales", quant=d(2)+d(2)},
       {weight=3, base="armour", type="fire dragon scales", quant=d(3)+d(3)},
       {weight=3, base="armour", type="ice dragon scales", quant=d(3)+d(3)} }

  local is_armour_user = you.race() ~= "Felid"
      and you.race() ~= "Octopode"
      and you.race() ~= "Poltergeist"
      and you.genus() ~= "draconian"

  if is_armour_user then
    for _, toll in ipairs(arm) do
      table.insert(prices, toll)
    end
  end

  local chosen = util.random_weighted_from("weight", prices)
  item.base_type = chosen.base
  item.sub_type = chosen.type
  if chosen.base == "armour" then
    item.plus1 = chosen.quant
  elseif chosen.base == "weapon" then
    item.plus1 = chosen.quant
  elseif chosen.base == "scroll" or chosen.base == "potion" then
    item.quantity = chosen.quant
  end
  if chosen.type == "rune of Zot" then
    item.plus1 = chosen.quant
    item.ego_type = chosen.name -- not an actual ego, just the name of the rune
  end
  return item
end

function trove.get_trove_toll(e)
  if crawl.one_chance_in(2) then
    return trove.get_toll_bane()
  elseif crawl.one_chance_in(4) and you.race() ~= "Demigod"
    and you.god() ~= "Gozag" and you.god() ~= "Xom" then
    return trove.get_toll_nopiety()
  elseif crawl.one_chance_in(6) then
    return trove.get_toll_drain()
  else
    return trove.get_trove_toll_with_item(
        trove.get_trove_item(e, 1000))
  end
end

function trove.get_trove_toll_with_item(item)
  return { type = "item", item = item }
end

function trove.get_toll_nopiety()
  return { type = "nopiety"}
end

function trove.get_toll_bane()
  local bane_type = {"paradox", "mortality", "multiplicity", "claustrophobia",
                     "stumbling", "dilettante", "lethargy"}
  local type = util.random_from(bane_type)
  return { type = "bane", bane = type }
end

function trove.get_toll_drain()
  return { type = "drain"}
end

function trove.portal(e)
    -- dependent on player stats (skills, race, etc) so needs to be isolated
    -- from gameplay rng.
    local toll = crawl.rng_wrap(function () return trove.get_trove_toll(e) end,
                                "subgenerator")

    local function stair ()
        return trove_marker  {
            toll = toll,
            entity = "portal",
            toll_desc = "to enter a treasure trove",
            floor = "expired_portal",
            feat_tile = "dngn_portal_trove_gone",
        }
    end
    e.tags("uniq_trove no_monster_gen chance_trove")
    e.chance("500")
    e.lua_marker("O", stair)
    e.kfeat("O = enter_trove")
    e.colour(". = blue")
    if you.in_branch("Shoals") then
      e.ftile(".12$%OcbG+ = floor_sprouting_ruin")
    else
      e.ftile(".12$%OcbG+ = floor_marble")
    end
    e.colour(".12$% = blue")
    e.tile("c = wall_stone_dark")
end

function trove_weapon_skills (e)
    local weapon_skills = { "Short Blades", "Long Blades", "Axes",
        "Maces & Flails", "Polearms", "Staves", "Ranged Weapons" }
    local max = 0
    for _, skill in ipairs(weapon_skills) do
        max = math.max(you.base_skill(skill), max)
    end
    return max
end

function trove_spell_skills (e)
    local spell_skills = { "Spellcasting", "Conjurations", "Hexes", "Summonings",
        "Necromancy", "Translocations", "Alchemy", "Fire Magic", "Ice Magic",
        "Air Magic", "Earth Magic", "Forgecraft" }
    local sum = 0
    for _, skill in ipairs(spell_skills) do
        sum = sum + you.base_skill(skill)
    end
    return sum
end

function trove_milestone (e, trove_desc)
    crawl.mark_milestone("br.enter", "entered " .. trove_desc .. ".", "parent")
    crawl.take_note("Entered " .. trove_desc)
    crawl.mpr("You've discovered " .. trove_desc .. "!")
end

function trove_setup(e)
    e.tags("no_monster_gen")
    e.tags("no_item_gen")
    e.orient("encompass")
    e.kfeat("< = exit_trove")
end

-- A variety of quick logic checks to make sure troves with otherwise highly
-- specified and themed contents don't place completely unusable items for
-- given characters.
function species_is_undead(e)
  return (you.race() == "Revenant" or you.race() == "Poltergeist" or
          you.race() == "Mummy")
end

function species_has_size_limits(e)
  return you.race() == "Troll" or you.race() == "Oni" or
         you.race() == "Spriggan"
end

-- you.race() returns capitalized strings, you.genus() returns all lowercase.
function no_body_armour_species(e)
  return you.genus() == "draconian" or you.race() == "Octopode" or
         you.race() == "Felid" or you.race() == "Poltergeist"
end

function no_friendlies(e)
  return (you.get_base_mutation_level("hated by all") == 1 or
          you.god() == "Okawaru")
end

function no_evil(e)
  return you.god() == "Elyvilon" or you.god() == "the Shining One" or
         you.god() == "Zin"
end

-- On average, give slightly more acquirement weapons than other weapons,
-- which are top tier and always technically usable but otherwise deliberately
-- mostly blind about one's actual stats and skills and apts situation.
function trove_weap_brand(e, brand, ranged_valid)
  local w = "acquire weapon ego:" .. brand .. " w:32"
  local two_hands = you.race() ~= "Coglin" and you.mutation("missing a hand") ~= 1
  local big_enough = you.race() ~= "Spriggan" and you.race() ~= "Kobold"
  local big_for_small = (you.race() ~= "Spriggan" and you.race() ~= "Kobold") or
                        you.mutation("missing a hand") ~= 1
  local range = ranged_valid and trove_other_weapon_specialty(_G, "Ranged Weapons")
  local wnames = {
    ["eveningstar"] = {2, true},
    ["demon whip"] = {2, not no_evil},
    ["executioner's axe"] = {2, two_hands and big_enough},
    ["broad axe"] = {2, big_for_small},
    ["bardiche"] = {2, two_hands and big_enough},
    ["partisan"] = {1, big_for_small},
    ["demon trident"] = {1, big_for_small and not no_evil},
    ["lajatang"] = {4, two_hands and big_for_small},
    ["quick blade"] = {3, true},
    ["athame"] = {1, true},
    ["triple sword"] = {2, two_hands and big_enough},
    ["double sword"] = {1, big_for_small},
    ["demon blade"] = {1, big_for_small},
    ["longbow"] = {4, range and big_enough and two_hands},
    ["hand cannon"] = {2, range},
    ["triple crossbow"] = {2, range and you.race() ~= "Spriggan" and two_hands},
  }
  for weap, props in pairs(wnames) do
    if props[2] then
      w = w .. " / " .. weap .. " useful good_item ego:" .. brand .. " w:" .. props[1]
    end
  end
  return w
end

-- For troves with brands incompatible with ranged weapons, and for unarmed
-- characters being given talismans, check if one's ranged weapons skill or is
-- higher than any other weapon skill.
function trove_other_weapon_specialty(e, other_sch)
  local weapon_skills = { "Short Blades", "Long Blades", "Axes",
                           "Maces & Flails", "Polearms", "Staves"}
  local other_sk = 0
  for _, skill in ipairs(weapon_skills) do
    other_sk = math.max(you.base_skill(skill), other_sk)
  end
  return you.base_skill(other_sch) > other_sk
end

-- Since there are no full-magic troves any more and troves reward less
-- items overall, book quality has to be pushed up in compensation.
function trove_book(_G, school, secondary)
  if secondary == nil then
    secondary = "conjurations"
  end
  local attr = " splevels:33 numspells:5"
  return "randbook disc:" .. school .. attr .. " w:6 / " ..
         "randbook disc:" .. school .. " disc2:" .. secondary .. attr .. " w:4"
end

-- A repeated function for spellbooks, staves, manuals, and orbs for a school,
-- also meant to handle the disjoint item names across schools.
function trove_standard_magic(e, school, use_staff)
  local inames = {
    ["conjuration"] = {"conjuration", "Conj", "conjurations"},
    ["summoning"] = {"ERROR: set use_staff to false", "Summ", "summonings"},
    ["necromancy"] = {"necromancy", "Necro", "Necromancy"},
    ["translocations"] = {"ERROR: set use_staff to false", "Tloc", "translocations"},
    ["hexes"] = {"ERROR: set use_staff to false", "Hexes", "hexes"},
    ["fire"] = {"fire", "Fire", "fire magic"},
    ["ice"] = {"cold", "Ice", "ice magic"},
    ["earth"] = {"earth", "Earth", "earth magic"},
    ["air"] = {"air", "Air", "air magic"},
    ["alchemy"] = {"alchemy", "Alch", "alchemy"}
  }
  local staff, orb, manual, output, schname, secondary = "", "", "", "", "", ""
  local max_other = 0
  local orbs = {"glass w:1", "mesmerism w:1", "attunement w:1"}
  if you.mutation("hp casting") ~= 1 then
    table.insert(orbs, "energy w:2")
    table.insert(orbs, "stardust w:2")
  end
  for sc, iname in pairs(inames) do
    if school == sc then
      staff = "staff of " .. iname[1]
      orb = "orb randart artprops:" .. iname[2] .. " ego:" ..
            table.concat(orbs, " / orb randart artprops:" .. iname[2] .. " ego:")
      manual = "manual of " .. iname[3] .. " w:8"
      schname = iname[3]
    elseif crawl.game_started() and you.base_skill(iname[3]) > max_other then
      max_other = you.base_skill(iname[3])
      secondary = sc
    end
  end
  if crawl.game_started() and you.base_skill(schname) < 27 then
    output = manual
  elseif you.mutation("innate caster") == 1 and you.mutation("missing a hand") then
    output = "gold good_item"
  end
  if you.mutation("innate caster") ~= 1 then
    output = output .. " / " .. trove_book(_G, school, secondary) .. " w:34 "
  end
  if you.mutation("no armour") ~= 1 and you.race ~= "Coglin" and
   you.mutation("missing a hand") ~= 1 then
    output = output .. " / " .. orb
  end
  if use_staff then
    output = output .. " / " .. staff .. " w:4 / " .. staff .. " randart"
  end
  return output
end

-- Generates the lighter and heavier ends of armour to give properties to.
-- TODO: move this to vault.lua and add an argument for not weighing it
-- base on one's armour skills, then use it in a few other vaults.
function trove_ego_gen_armour(e, ego, artprop)
  local a = {}
  local light = {"troll leather armour w:20", "ring mail"}
  local heavy = {"chain mail", "plate armour", "crystal plate armour"}
  local hw = " w:10"
  local g = " good_item"
  local r = " randart"
  if ego ~= nil then
    g = g .. " ego:" .. ego
  end
  if artprop ~= nil then
    r = r .. " artprops:" .. artprop
  end
  if you.base_skill("Armour") > you.base_skill("Dodging") * 2 then
    hw = " w:24"
  elseif you.base_skill("Dodging") > you.base_skill("Armour") * 2 then
    hw = " w:4"
  end
  arm = table.concat(light, r .. " / ") .. r .. " / " ..
        table.concat(heavy, g .. hw .. " / ") .. g ..  hw .. " / " ..
        table.concat(heavy, r .. hw .. " / ") .. r .. hw
  return arm
end

-- Generates shields to give specified properties to.
-- TODO: also move this to vault.lua. Possibly could be "acquire shield ego:X",
-- but acquirement only knows it's handling armour and not shields as items.
function trove_ego_shield(e, ego, artprop)
  local sh = {}
  local g = "good_item"
  local r = "randart"
  if ego ~= nil then
    g = g .. " ego:" .. ego
  end
  if artprop ~= nil then
    r = r .. " artprops:" .. artprop
  end

  if you.race() ~= "Troll" and you.race() ~= "Oni" and
     (you.race() == "Spriggan" or you.base_skill("Shields") < 18) then
    table.insert(sh, "buckler ".. g)
    table.insert(sh, "buckler ".. r)
  end
  if you.race() ~= "Spriggan" then
    table.insert(sh, "kite shield ".. g)
    table.insert(sh, "kite shield ".. r)
  end
  if you.race() ~= "Kobold" and you.base_skill("Shields") > 0 then
    table.insert(sh, "tower shield ".. g .. " w:5")
    table.insert(sh, "tower shield ".. r .. " w:5")
  end
  if you.race == "Coglin" or you.mutation("missing a hand") == 1 then
    return ""
  else
    return table.concat(sh, " / ")
  end
end

-- Sets up talismans with a given randart property plus extra weight on a
-- specified type. Acquirement doesn't permit artprop controls, and usually
-- downplays the still-usable eel talisman tier.
function trove_good_talisman(e, artprop, extra_weighted_type)
  local r = "randart"
  if artprop ~= nil then
    r = r .. " artprops:" .. artprop
  end
  local t = "eel talisman " .. r .. " / lupine talisman " .. r .. " / " ..
            "serpent talisman " .. r .. " / wellspring talisman " .. r .. " / " ..
            "blade talisman w:4 / blade talisman " .. r .. " w:6 / " ..
            "granite talisman w:4 / granite talisman " .. r .. " w:6 / " ..
            "dragon-coil talisman w:4 / dragon-coil talisman " .. r .. " w:6 / " ..
            "riddle talisman w:4 / riddle talisman " .. r .. " w:6 / " ..
            "storm talisman w:8 / storm talisman " .. r .. " w:2"

  if extra_weighted_type ~= nil then
    t = t .. " / " .. extra_weighted_type .. " w:30"
  end
  if no_body_armour_species(_G) == false then
      t = t .. " / fortress talisman " .. r
  end
  if no_friendlies(_G) == false then
      t = t .. " / hive talisman w:4 / hive talisman " .. r .. " w:6"
  end
  if no_evil(e) == false then
      t = t .. " / sanguine talisman w:4 / sanguine talisman " .. r .. " w:6 / " ..
               "talisman of death w:8 / talisman of death " .. r .. " w:2"
  end
  -- If you're with Zin, there's only one form of shapeshifting allowed:
  if you.god() == "Zin" then
     return "potion of mutation pre_id q:1"
  else
     return t
  end
end

-- Set ups randart jewellery with a given artprop.
function trove_jewel_type(e, artprop)
  local r = "randart"
  if artprop ~= nil then
    r = r .. " artprops:" .. artprop
  end
  return "any ring " .. r .. " / any amulet " .. r
end

-- Set up trove consumables, checking mummies, Ru characters
-- having sacrificed artifice, and item sets.
function trove_cons(e, scrolls, potions, wands, set_wand, set_misc)
  local cons = "scroll of " .. table.concat(scrolls, " pre_id / scroll of ") ..
               " pre_id / scroll of acquirement q:1 pre_id w:1"
  if potions ~= nil and you.mutation("no potions") ~= 1 then
    cons = cons .. " / potion of " .. table.concat(potions, " pre_id / potion of ") ..
           " pre_id"
  end
  if you.mutation("inability to use devices") ~= 1 then
    if wands ~= nil then
      cons = cons .. " / " .. wands
    end
    if set_wand ~= nil and items.pickable(set_wand) then
      cons = cons .. " / " .. set_wand
    end
    if set_misc ~= nil and items.pickable(set_misc) then
      cons = cons .. " / " .. set_misc
    end
  end
  return cons
end

-- This always uses up "d", "e", and "f" glyphs.
function trove_offense(e, weapons, magic, talismans, magic_school)
  e.kitem("d = " .. weapons)
  e.kitem("e = " .. magic)
  e.kitem("f = " .. talismans)

  -- This is a big mess of presuming not every item is useless with enough
  -- pivoting, unless Ru sacrifices or species restrictions are involved, so
  -- given obscure combinations aren't handed that much better troves.
  local no_magic = you.god() == "Trog" or you.mutation("no " .. magic_school) == 1
  local no_forms = you.mutation("no forms") == 1 or species_is_undead(_G)
  local uc_tal = not no_forms and trove_other_weapon_specialty(_G, "Unarmed Combat")
  if you.mutation("no weapons or thrown items") == 1 then
    if no_forms then
      if no_magic then
        e.subst("d = i")
      else
        e.nsubst("d = 2:i / 2:e / * = eeei")
      end
    else
      e.nsubst("d = 2:e / 2:f / * = ef")
    end
  elseif no_forms then
    if no_magic then
      e.nsubst("d = 2:i / *:d")
    else
      e.nsubst("d = 2:d / 2:e / * = de")
    end
  elseif no_magic then
    e.nsubst("d = 2:d / 2:f / * = ddf")
  else
    local f_chance = crawl.x_chance_in_y(5, 6)
    if (uc_tal) then
      if no_magic then
        e.nsubst("d = 2:f / 2:i / * = fi")
      else
        e.nsubst("d = 2:f / 2:e / * = effi")
      end
    elseif no_magic or (trove_weapon_skills(_G) > trove_spell_skills(_G) and f_chance) then
      e.nsubst("d = 2:d / 1:f / * = ddfi")
    elseif trove_weapon_skills(_G) * 2 < trove_spell_skills(_G) and f_chance then
      e.nsubst("d = 1:d / 2:e / 1:f / * = ddeef")
    else
      e.nsubst("d = 2:d / 2:e / 1:f / * = ddeef")
    end
  end
end

-- This always uses up "g", "h", and "i" glyphs.
function trove_defense(e, all_armour, other_armour, jewellery, consumables)
  local arm = all_armour
  if species_has_size_limits(_G) == false then
    arm = arm .. " / " .. other_armour
  end
  e.kitem("g = " .. arm)
  e.kitem("h = " .. jewellery)
  e.kitem("i = " .. consumables)

  if no_body_armour_species(_G) == true then
    e.nsubst("g = 3:h / 2:i / * = hi")
  elseif you.get_base_mutation_level("no jewellery") == 1 then
    e.nsubst("g = 3:g / 2:i / * = gi")
  else
    e.nsubst("g = 2:g / 2:h / 2:gghhi")
  end
end

-- A preformatted way to give 1% chances to place unrands.
function trove_unrand_chances(e, n_glyphs, unrand, criteria, i_glyphs)
  for i in ipairs(unrand) do
    if not criteria[i] and not you.unrands(unrand[i]) and crawl.one_chance_in(100) then
      e.kitem(i_glyphs[i] .. " = " .. unrand[i])
      e.nsubst(n_glyphs .. " = 1:" .. i_glyphs[i])
    end
  end
end
}}

default-depth: D:12-, Swamp, Snake, Shoals, Spider

##############################################################################
#
# Relevant entry portals.
#
##############################################################################

NAME:    due_enter_trove_mix
TAGS:    transparent no_descent
SHUFFLE: c+ / c+ / '"
SUBST:   '" = ., H : G.., G : GGG.
: trove.portal(_G)
COLOUR: c = blue
MAP
ccccc
cG.Hc
c.O.c
cH.Gc
cc+cc
ENDMAP

# Of course, not everyone is willing for you to take their treasure...
NAME:   enter_trove_5
TAGS:   transparent no_descent
# Got drafted in from Vaults, while the mages try and close the portal down.
KMONS:  12 = vault guard
: if you.absdepth() >= 15 then
SUBST:  l = 2
: end
: trove.portal(_G)
MAP
ccccc
c...c
c.O.c
c...c
cc+cc
cl.lc
c.2.c
cl.lc
cc+cc
ENDMAP

# Someone left some gold behind for you!
NAME:   enter_trove_6
TAGS:   transparent no_descent
: trove.portal(_G)
MARKER: + = lua: props_marker { connected_exclude="true" }
COLOUR: $+ = blue
MAP
ccccccc
c$$$$$c
c$+++$c
c$+O+$c
c$+++$c
c$$$$$c
ccc+ccc
ENDMAP

NAME: nicolae_trove_entry_columns
TAGS: transparent no_descent
: trove.portal(_G)
MAP
cccccccccccc
c.........cc
c.c.c.c.c.cc
+.........Oc
c.c.c.c.c.cc
c.........cc
cccccccccccc
ENDMAP

NAME: nicolae_trove_entry_crossroad
TAGS: transparent no_descent
: trove.portal(_G)
FTILE: b = floor_marble
MAP
cccc+cccccc
cc.c.c.cccc
c.......bbc
+.......Obc
c.......bbc
cc.c.c.cccc
cccc+cccccc
ENDMAP

NAME: nicolae_trove_entry_diagonal_crystal
TAGS: transparent no_descent
: trove.portal(_G)
MAP
   c
  ccc
 cbbbc
ccbO.cc
 cb...cc
  cc...cc
   cc...cc
    cc...cc
     cc...cc
      cc.+c
       ccc@
        c
ENDMAP

NAME: nicolae_trove_entry_free_sample
TAGS: transparent no_descent
: trove.portal(_G)
MAP
%.%
.O.
%.%
ENDMAP

NAME: nicolae_trove_entry_isolated
TAGS: no_pool_fixup transparent no_descent
KPROP: .O = no_tele_into
KMASK: .O = opaque
: trove.portal(_G)
MAP
'''''''
'wwwww'
'w...w'
'w.O.w'
'w...w'
'wwwww'
'''''''
ENDMAP

NAME: nicolae_trove_entry_path_of_doom
TAGS: transparent no_descent
KMONS: O1 = patrolling guardian mummy
SUBST: 1 = 1..
: trove.portal(_G)
MAP
  ccccc
 cc.O.cc
cc.....cc
c$.G.G.$c
c$..1..$c
c$.G.G.$c
cc.....cc
 cc...cc
  cc+cc
ENDMAP

NAME:   trove_entry_hex_spiral
TAGS:   transparent no_descent
WEIGHT: 5
: trove.portal(_G)
MAP
             @cc
    ccccccccc..cc
   cc.......cc..cc
  cc..ccccc..cc..cc
 cc..cc..Occ..cc..cc
cc..cc..ccc..cc..cc
 cc..cc.....cc..cc
  cc..ccccccc..cc
   cc.........cc
    ccccccccccc
ENDMAP

##############################################################################
#
# The portal vaults. As of 0.34:
#  * Troves should have a unique name linked to a spell or unrand.
#  * Troves should use a variety of wall tile, floor tile, and decorative
#    feature arrangements to convey a distinct place.
#  * Most troves should strive to both place unique and flavourful items
#    as well as items given various checks and clauses to minimize the
#    potential absolute uselessness of a given item.
#
##############################################################################

default-depth: Trove

# The Name-Rending Infernalists' Reservoir: the fiery equipment / magic trove.
# (Fire Magic is the only spell school without any mages's names in the spells.
# This is a sort of interesting accidental flavour, so here we're experimentally
# leaning into it instead.)
NAME:   regret_index_trove_nameless_infernalists
: trove_setup(_G)
KMONS:    F = fire vortex
KMONS:    L = generate_awake creeping inferno
{{
local aux = ""
local magic = trove_standard_magic(_G, "fire", true)
if you.mutation("claws") ~= 3 and you.mutation("demonic touch") < 1 then
  aux = " / pair of gloves ego:fire good_item w:2 / " ..
           "pair of gloves ego:fire randart w:2"
end
if you.mutation("weakness stinger") < 1 then
  aux = " / scarf ego:resistance w:4 / scarf ego:resistance randart w:2 / " ..
           "scarf ego:harm w:4 / scarf ego:harm randart w:2"
end
if you.mutation("no conjurations magic") ~= 1 then
  magic = magic .. " / manual of conjurations w:4"
end
trove_offense(_G, trove_weap_brand(_G, "flaming", true),
                  trove_standard_magic(_G, "fire", true),
                  trove_good_talisman(_G, "rF", nil), "fire magic")
trove_defense(_G, "robe ego:resistance good_item w:8 / \
                   fire dragon scales good_item / \
                   fire dragon scales randart" .. aux,
                   trove_ego_gen_armour(_G, "fire_resistance", "rF"),
                   trove_jewel_type(_G, "rF"),
                   trove_cons(_G, {"immolation q:3", "fog q:3 w:5"},
                              {"resistance q:2 w:5", "magic q:2 w:5"},
                              nil, nil, nil))
local small = you.race() == "Spriggan" or you.race() == "Kobold" or
              you.race() == "Felid"
trove_unrand_chances(_G, "def", {"firestarter"}, {small}, {"?"})
}}
KFEAT:    FL = l
KFEAT:    y = x
: vault_metal_statue_setup(_G, "G", "fiery conduit")
NSUBST:   l = 4:LLF / 4:LLFll / *:l
KFEAT:    ~ = l
TILE:     c = wall_stone_scorched
TILE:     m = dngn_transparent_wall_red
TILE:     o = wall_permarock_clear_darkgray
TILE:     x = wall_pebble_darkgray
FTILE:    defghi?$'G = floor_pebble_darkgray
KPROP:    FLl = no_tele_into
epilogue{{
            trove_milestone(_G, "The Name-Rending Infernalists' Reservoir")
}}
MAP
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxlxllllllllllllllllllllllllx
xlxlxlllllllllllllllllllllllx
xllxlxllllllllllllllllllllllx
xlllxlxlllllllllllllllllllllx
xllllxlxlllllllllllllllllllxx
xlllllxlxllllllllllllllllllxx
xllllllxloooooooooolllllllxlx
xlllllllooccxmyxxxolllllllxlxxxxxxxxxx
xllllllloccgmmm.Axollllllxlllllllllxlx
xlllllllocgg'm...xollllllxlllllllllxlx
xllllllloxm'....myolllllxlllllllllxllx
xlllllllommm.<.mmmolllllxllllllllxlllx
xllllllloym.....mxoooooolllllllllxlllx
xlllllllox...m...xxxxxxollllllllxllllx
xllllllloxA.mmm..dxy~~xolllllllxlllllx
xllllllloxxxymxxd'W'G~xolllllllxlllllx
xllllllloooooooxxWdW'yxollllllxllllllx
xllllllxlllllloxy'WdWxxooooooolllllllx
xlllllxlllllllox~G'W'dxxmyxxxolllllllx
xlllllxlllllllox~~yxd'.mmm.Axolllllllx
xllllxlllllllloxxxxxx...m...xolllllllx
xlllxlllllllllooooooxm.....myolllllllx
xlllxllllllllxlllllommm.<.mmmolllllllx
xllxlllllllllxllllloym....'mxolllllllx
xlxlllllllllxllllllox...m'ggcolllllllx
xlxlllllllllxlllllloxA.mmmgccolllllllx
xxxxxxxxxxlxllllllloxxxymxccoolllllllx
         xlxllllllloooooooooolxllllllx
         xxllllllllllllllllllxlxlllllx
         xxlllllllllllllllllllxlxllllx
         xlllllllllllllllllllllxlxlllx
         xllllllllllllllllllllllxlxllx
         xlllllllllllllllllllllllxlxlx
         xllllllllllllllllllllllllxlxx
         xlllllllllllllllllllllllllxlx
         xllllllllllllllllllllllllllxx
         xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ENDMAP

# Ozocubu's Refrigerator: the cold equipment and ice magic trove.
# Layout directly adjusting due's trove_library.
NAME:   regret_index_trove_ozocubu
: trove_setup(_G)
MONS:   dream sheep-shaped block of ice / hell hog-shaped block of ice / \
        anaconda-shaped block of ice / alligator-shaped block of ice / \
        hydra-shaped block of ice / caustic shrike-shaped block of ice w:2
NSUBST: d = 6:d / *:?, g = 6:g / *:?
{{
local armour = "robe ego:resistance good_item / " ..
               "ice dragon scales good_item w:15 / ice dragon scales randart / " ..
               trove_ego_shield(_G, "cold_resistance", "rC")
if you.mutation("antennae") < 3 and you.mutation("horns") < 3 then
   armour = armour .. " / hat ego:ice good_item w:2"
end
if you.mutation("antennae") == 0 and you.mutation("horns") == 0 and
  species_has_size_limits(_G) == false then
   armour = armour .. " / helmet ego:ice good_item w:2"
end
if you.mutation("weakness stinger") < 1 then
  armour = armour .. " / scarf ego:resistance w:8"
end
-- Not really armour, but close enough to defenses. Meant to round out how
-- the earth trove gets Armour and the air trove gets Shields.
if you.base_skill("dodging") < 27 and you.mutation("inability to train dodging") ~= 1 then
  armour = armour .. " / manual of dodging w:4"
end

trove_offense(_G, trove_weap_brand(_G, "freezing", true),
                  trove_standard_magic(_G, "ice", true),
                  trove_good_talisman(_G, "rC"), "ice magic")
trove_defense(_G, armour, trove_ego_gen_armour(_G, "cold_resistance", "rC"),
                  trove_jewel_type(_G, "rC"),
                  trove_cons(_G, {"identify w:1 q:4"},
                             {"resistance q:2 w:5", "ambrosia q:3 w:5",
                              "magic q:2 w:5"}, nil,
                              "wand of iceblast charges:8", "phial of floods"))
-- maybe this should also have Prune?
local small = you.race() == "Spriggan" or you.race() == "Kobold" or
              you.race() == "Felid"
trove_unrand_chances(_G, "defghi", {"frostbite", "skin of zhor"},
                         {small, no_body_armour_species(_G)}, {"y", "z"})
}}
KFEAT:   ? = cache_of_meat / cache_of_fruit / cache_of_baked_goods
KFEAT:   + = closed_clear_door
KFEAT:   X = x
: vault_metal_statue_setup(_G, "G", "icy conduit")
: decorative_floor(_G, '!', "set of bottled spirits")
TILE:    x = wall_ice_block
TILE:    v = dngn_metal_wall_blue
FTILE:   .<defghiyz?!1+G = floor_frozen
epilogue{{
            trove_milestone(_G, "Ozocubu's Refrigerator")
}}
MAP
xxxxxxxxxxxxxxx
x..v!v!v!v!v..x
x.............x
xd...........gx
xv..xvx.xvx..vx
xd..dvg.dvg..gx
xv..xvx.xvx..vx
xd..dvg.dvg..gx
xv..xvx.xvx..vx
xd...........gx
x.............x
xxxxxx+++xxxxxx
x1G1xx...xx1G1x
x.1.xx...xx.1.x
x1.1xx.<.xx1.1x
x.1.x.....x.1.x
xx+xx.'''.xx+xx
 x..+''A''+..x
 xxxXXXXXXXxxx
ENDMAP

# The Storm Queen's Palace Crash-Site: electricity, shields, and Air Magic.
# Map re-use of nicolae_trove_salty.
NAME:   regret_index_trove_storm_queen
: trove_setup(_G)
NSUBST: d = 6:d / 6:g / *:.
{{
local arm = "steam dragon scales randart artprops:rElec / " ..
            "storm dragon scales good_item / storm dragon scales randart "
if you.mutation("weakness stinger") < 1 then
  arm = arm .. " / cloak ego:air w:4 / scarf ego:repulsion randart w:2"
end
if you.mutation("no armour") < 1 and you.race ~= "Coglin" and
   you.mutation("missing a hand") < 1 and you.base_skill("Shields") < 27 then
  arm = arm .. " / manual of shields w:4 / " .. trove_ego_shield(_G, nil, "rElec")
end
trove_offense(_G, trove_weap_brand(_G, "electrocution", true),
                  trove_standard_magic(_G, "air", true),
                  trove_good_talisman(_G, "rElec",
                  "eel talisman / storm talisman"), "air magic")
trove_defense(_G, arm, "pair of gloves randart artprops:rElec w:2",
                  trove_jewel_type(_G, "rElec"),
                  trove_cons(_G, {"enchant armour q:2"},
                            {"resistance q:2 w:5", "attraction q:3 w:5"},
                             nil, nil, "lightning rod w:5"))
local sh = you.race() == "Spriggan" or you.race() == "Kobold" or
           you.race() == "Felid" or you.mutation("missing a hand") == 1
trove_unrand_chances(_G, "dgh", {"storm_queen's_shield", "storm_bow"},
                         {sh, sh and you.race("Formicid") == false}, {"?", "!"})
}}
MARKER:  V = lua:fog_machine { cloud_type = "thunder",  walk_dist=2, \
             pow_min=18, pow_max=26, delay=180, size=4, spread_rate=1 }
KFEAT:   z = x
: vault_metal_statue_setup(_G, "I", "iron statue")
SUBST:   ` = x`, v = v:90 x
FTILE:   .defghi?!VGIm = floor_salt
FTILE:   `" = floor_w_marble
TILE:    x = wall_zot_cyan
TILE:    z = wall_pebble_cyan
TILE:    G = dngn_crumbled_column
TILE:    v = dngn_metal_wall_cyan
TILE:    I = dngn_oka_iron_statue
epilogue{{
            trove_milestone(_G, "The Storm Queen's Palace Crash-Site")
}}
MAP
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzz...................................zzzzz
zzz................................m......zzz
zz..................................V......zz
zz...................................m.....zz
z...........................................z
z...........................................z
z...............``.............`x`x`........z
z...............`.....vvvv...v.vvvvv........z
z....m............``.`v.........x...........z
z...V.............`xx`..d.d.d..dxd.d.`......z
z..m...............x.....x......xx...x......z
z....................xv.d.d.x..d.d.d.v......z
z.....................vx...`x.......xv......z
z.....................vv.xvx....`v.vvv......z
z............G..G..G..x...v......v.`xx`.....z
z.....'''''."..".."...................x.....z
z.....'<'A'....mVm...........I......`x`.....z
z.....'''''...".."..".......................z
z............G..G..G.....`v......v`.........z
z....................`vvv.v....`xxvxx.......z
z....................`v......x.x`...`.......z
z.................`..```d.d.x..d.d.d.x......z
z..m.............`x`..x`.............v......z
z...V............xx`..v.d.dxd..d.d.d........z
z....m...........``..xv..x.x................z
z...................x..v..vvvv.....vvv......z
z...................xx......................z
z...............`...........................z
z...............`.`.........................z
zz..............................m..........zz
zz.............................V...........zz
zzz...........................m...........zzz
zzzzzz..................................zzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
ENDMAP

# Leda's Sunken Stockpile: a trove of Earth Magic and strong slowing equipment.
# The layout is somewhat based off of nicolae_trove_exclusive_bardings.
NAME:   regret_index_trove_leda
{{
trove_setup(_G)
local pon = "ego:ponderousness plus:" .. crawl.random_range(7, 10) .. " w:4"
local lim_armour = "any useful armour randart artprops:Str:4 w:5 / "
if you.base_skill("Armour") < 27 and you.mutation("inability to train armour") ~= 1 then
  lim_armour = lim_armour .. " / manual of armour w:2"
end
local gen_armour = ""
if species_has_size_limits(_G) == false and
 you.base_skill("Armour") > you.base_skill("Dodging") * 3 then
  gen_armour = "plate armour " .. pon .. " / crystal plate armour " .. pon
end
if you.race() == "Anemocentaur" or you.race() == "Naga" then
  gen_armour = gen_armour .. " / barding good_item w:20 / barding randart w:4"
elseif you.mutation("hooves") ~= 3 and you.mutation("talons") ~= 3 then
  gen_armour = gen_armour .. " / pair of boots good_item w:6 " ..
                             " / pair of boots ego:earth good_item w:12" ..
                             " / pair of boots randart w:2"
end
trove_offense(_G, trove_weap_brand(_G, "heavy", true),
                  trove_standard_magic(_G, "earth", true),
                  trove_good_talisman(_G, nil, "granite talisman"),
                  "earth magic")
trove_defense(_G, lim_armour, gen_armour,
                  trove_jewel_type(_G, "Str:4 w:5") .. " / " ..
                   trove_jewel_type(_G, "*Slow&AC:4&Str:4"),
                   trove_cons(_G, {"enchant armour"}, nil,
                              "wand of digging charges:9 w:30 / " ..
                              "any blast wand w:20 charges:8",
                              nil, "tin of tremorstones"))
local small = you.race() == "Spriggan" or you.race() == "Kobold" or
              you.race() == "Felid"
trove_unrand_chances(_G, "def", {"dark maul"}, {small}, {"!"})
}}
KITEM:   D = seismosaurus skeleton
KITEM:   s = stone q:1
KFEAT:   defghi!Ds' = mud
KFEAT:   y = x
SUBST:   ? = ?G
: decorative_floor(_G, '?', "mop and bucket")
TILE:    x = wall_pebble_brown
TILE:    G = dngn_statue_mermaid / dngn_statue_hydra / dngn_statue_princess / \
             dngn_statue_snail / dngn_statue_orb / dngn_statue_ancient_hero w:2
epilogue{{
            trove_milestone(_G, "Leda's Sunken Stockpile")
}}
MAP
xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxyyyxxxxxxxxyyyxxxxxxx
xxxxysdsyxxxxxxysgsyxxxxxx
xxxyd'''dyxxxxyg'''gyxxxxx
xxxys'''syxxxxys'''syxxxxx
xxy'''''''yxxy'''''''yxxxx
xy'''''D'''yy..''''D''yyyx
y...'''''..'....''''''...y
y.<.''''.T..'.G..'''''.?.y
y.G.'''''..G.'..T.''''.A.y
y...''''''....'..'''''...y
xyyy''D''''..yy'''D'''''yx
xxxxy'''''''yxxy'''''''yxx
xxxxxys'''syxxxxys'''syxxx
xxxxxyg'''gyxxxxyd'''dyxxx
xxxxxxysgsyxxxxxxysdsyxxxx
xxxxxxxyyyxxxxxxxxyyyxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
ENDMAP

# Eringya's Secret Bog: an Alchemy, summoning, and swampy trove.
# The layout is directly based off of due's trove_garden.
NAME:    index_due_trove_eringya
TAGS:    no_pool_fixup
: trove_setup(_G)
KMONS:   12 = plant / bush w:1
KMONS:   CZ = crocodile att:good_neutral
{{
local scroll = {"poison q:3"}
local box = nil
local talis = nil
local magic = trove_standard_magic(_G, "alchemy", true)
if no_friendlies(_G) == false then
  table.insert(scroll, "any ally scroll q:2")
  box = "box of beasts w:5"
  talis = "hive talisman"
  if you.mutation("no summoning magic") ~= 1 then
    magic = magic .. " / " .. trove_standard_magic(_G, "summoning", false)
  end
else
  subst("C = ;")
  subst("? = Z")
end

-- No spectral ranged weapons, so just offer longbows as suits the forest.
local weapon = trove_weap_brand(_G, "spectral", false)
if trove_other_weapon_specialty(_G, "Ranged Weapons") then
  weapon = "longbow good_item / longbow randart"
end

trove_offense(_G, weapon, magic, trove_good_talisman(_G, "rPois", talis),
                  "alchemy magic")
trove_defense(_G, "swamp dragon scales good_item / swamp dragon scales randart",
                   trove_ego_gen_armour(_G, "poison_resistance", "rPois"),
                   trove_jewel_type(_G, "rPois") .. " / amulet of chemistry randart",
                   trove_cons(_G, scroll, {"lignification q:3 w:5"},
                              "any beam wand charges:8",
                              "wand of roots charges:8 w:5", box))
local n_wield = you.mutation("no weapons or thrown items") == 1
trove_unrand_chances(_G, "defg", {"robe of vines", "punk"},
                         {no_body_armour_species(_G), n_wield}, {"y", "z"})
}}
KFEAT:   t = mangrove
KFEAT:   CZ? = W
KFEAT:   1 = W / . w:30
KFEAT:   ~ = toxic_bog
SUBST:   1 = 1 t:2
NSUBST:  1. = 24:1 / * = . 1:1
SUBST:   ' = ' 2:3, " = '22, V = ~', ; = wwW```
SUBST:   1 = 1 o:1, 2 = 2 p:2
COLOUR:  n = green
TILE:    n = dngn_transparent_stone_green
FTILE:   .-1ot<QR = floor_grass_dark
FTILE:   '2p = floor_swamp
: decorative_floor(_G, 'op', "flower patch")
KPROP:   Z? = no_tele_into
MARKER:  P = lua:transp_loc("trove_eringya_entry")
MARKER:  Q = lua:transp_dest_loc("trove_eringya_entry")
MARKER:  R = lua:transp_loc("trove_eringya_exit")
MARKER:  S = lua:transp_dest_loc("trove_eringya_exit")
: set_border_fill_type('mangrove')
epilogue{{
            trove_milestone(_G, "Eringya's Secret Bog")
}}
MAP
'"V~~V'"'  1  .1  .1      .1.1.1.1.
"'"~~V"'".1.1.1.1.1.1.  1.1.1.1.1.1.1.1
 "'"~~'"'1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1
 '"'~~"'".1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1
  '"V~V"'".1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.
 ."'"~~'"'1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1
.1'"'~~~'"'m.1.1.1.1m1.1.1.1.1.1.1.1.1.1.
1."'"V~~"'".1.1.1.1.1.1.1.1.<.m.1.1.1.1.1.
.1."'"~~'"'1.nnnnnnnnnnnnnnn.1.1.1.1.1.1.1
1.1'"'~~V'".1n`````````````n1.1.1.1.1.1.1.
.1."'"~~V''1.n`t`````````t`n.1.1.1.1.1.1.1
 .1'"'V~~'m'1n``xxxx+nnnn``n1.1.1.1.1.1.1
  .1'"'~~V'''n``xddx`n??n``n.1.m.1.1.1.1.
  1."'"V~~'''n``xddx`nZ?n``n1.1.1.1.1.1.
  .1."'"V~~'`n``x``x-n?Zn``n.1.1.1.1.1.1
 .1.1."'"V~`Sn``xxx+-nnnn``n1.1.1.1.1.1.1
.1.1.1."'"~~`n``+`--o--`+``n.1.m.1.1.1.1.1
 .1.1.1'"'m~Vn-`xxx+-+xxx``n1.1.1.1.1.1.1.
  .1.1.1'"'~~nR-x``x-x``x``n.1.1.1.1.1.1.1
  1.1.1."'"V~n-`xgdx`xggx``n1.1.1.1.1.1.1
 1.1.1.1.1'"'nwWxdgx`xggx``n.1.1.1.1.1.1.1
1.1.1.1.1.1'"nWwxxxx+xxxx``n1.1.1.1.1.1.1.
.1.1.1.1.m.1'n`www;``````t`n.1.m.1.1.1.1.1
 .1.1.1.1.1.1n`wwwwww``````n1.1.1.1.1.1.1
  .1.1.1.1.1.n``wwwwwwC```-n.1.1.1.1.1.1
  1.1.1.1.1.1n``;wwwwwww`-Qn1.1.1.1.1.1.
  .1.1.1.1.1.n````Cwwwwww`-n.1.1.1.1.1.1
 .1.1.1.1.1.1n````````;wwwWn"'1.1.1.1.1.1
.1.1.1.1.1.1.nnnnnnnnnnnnnnn'"'1.1.1.1.1.1
1.1.1.1.1.1.1.1.1.1.1`P`"V~~"'".1.1.1.1.1.
.1.1.1.1.1.m.1.1.1.m.1`1'"'V~~V"'".1.1.1.1
 .1.1.1.1.1.1.1.1.1.1.1.1'"'V~mV"'".1.1.1.
 1.1<1.1.1.1.1.1.1.1.1.1.1'"'~~~V"'".1.1.1
 .`.1.1.1.1.1.1.1.1.1.1.1.1."'"V~V~'"'1.1
 `A`.1.1.1.1.1.1.1.1.1.1.1.1.1'"'~V~V"'"
  `.1.1.1.1 1.1.1  .1.1.1.1.1.1."'"V~~~V
      .1.1  .1.1    .1.   .1.   .1."'"V~V
ENDMAP

# Who said hidden doors were removed, anyway?
# Rutra's Hidden Sanctum: a stealth and Hexes trove.
# Lowered weight due to the gimmick and narrow nature of rewards.
NAME:   pf_index_trove_rutra
veto {{ return crawl.game_started() and you.base_skill("Stealth") < 1 }}
: trove_setup(_G)
WEIGHT: 5
KITEM:  ? = gold q:1
KITEM:  D = stone mimic
KITEM:  E = wand of flame mimic / potion of moonshine mimic / \
            potion of attraction mimic / scroll of noise mimic / \
            scroll of torment mimic
KITEM:  F = any weapon damaged pre_id mimic / any armour damaged pre_id mimic
KFEAT:  X = rock_wall mimic
{{
local aux1 = ""
local aux2 = ""
local talis = "spider talisman"
if you.mutation("weakness stinger") < 1 then
  aux1 = " / cloak ego:stealth good_item / " ..
            "scarf ego:shadows randart artprops:Stlth:2 w:4 / " ..
            "scarf ego:invisibility randart w:4"
end
if you.mutation("hooves") ~= 3 and you.mutation("talons") ~= 3 then
  aux2 = " / pair of boots ego:stealth good_item w:4 / " ..
            "pair of boots randart artprops:Stlth w:2 / " ..
            "pair of boots ego:rampaging good_item w:2"
end
if not no_evil(e) then
  talis = " w:30 / sanguine talisman"
end

trove_offense(_G, trove_weap_brand(_G, "venom", false) .. " / quick blade randart / " ..
                  "athame randart w:8 / quick blade ego:devious w:4 / " ..
                  "manual of Stealth w:8",
                  trove_standard_magic(_G, "Hexes", false) .. " / " ..
                  "orb ego:guile randart artprops:Hexes w:1",
                  trove_good_talisman(_G, "Stlth:2", talis),
                  "hexes magic")
trove_defense(_G, "shadow dragon scales good_item w:20 / \
                   shadow dragon scales randart w:20" .. aux1,
                  "robe randart artprops:Stlth:2 plus:2" .. aux2,
                   trove_jewel_type(_G, "Stlth"),
                   trove_cons(_G, {"fog q:2"},
                              {"invisibility q:3 w:5", "attraction q:3 w:1"},
                              "any hex wand w:4",
                              "wand of light charges:8", nil))
local no_jewel = you.mutation("no jewellery") == 1
trove_unrand_chances(_G, "df", {"robe of night", "ring of shadows"},
                         {no_body_armour_species(_G), no_jewel}, {"z", "Z"})
}}
: decorative_floor(_G, 'V', "mourning vase")
TILE:    m = dngn_transparent_wall_blue
TILE:    c = dngn_stone_dark
MARKER:  ~ = lua:fog_machine { cloud_type = "black smoke", \
                pow_min = 10, pow_max = 30, delay = 50, \
                size = 12, walk_dist = 2, start_clouds = 1 }
epilogue{{
            trove_milestone(_G, "Rutra's Hidden Sanctum")
}}
MAP
xxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxmxxccccccx
xxDDD?X+.x.~.xcg..gcx
xxFEEDxx.x.m.xmgT<gmx
xxEFEDxx.x.x.xcg..gcx
xxDEFDxx.x.x.xcc..ccx
xxx++xxx.x.x.xcc..cxx
xxx..xxx.xXx.xcc..cxx
xxx..xxx.x?x.xcc++ccx
xxx..xxx.x.x.xc...Vcx
xx....xx.x.x.xc..ddcx
xm.<A.mx.m.x.xc..ddcx
xx....xx.~.x.+...ddcx
xxxxxxxxxmxxxxccccccx
xxxxxxxxxxxxxxxxxxxxx
ENDMAP

# The Dread Knight's Derelict Chapel: the main evil trove.
# Layout mostly taken from trove_trog_arena, though Trog might approve.
# Lowered weight due to the lack of spellcaster support and the potentially
# build-clashing offering of reaping weapons.
NAME:   regret_index_trove_dread_knight
TAGS:   no_species_fe
veto {{ return crawl.game_started() and no_evil(_G) }}
: trove_setup(_G)
WEIGHT: 5
{{
local scroll = {"silence q:3 w:3"}
local weap = trove_weap_brand(_G, "draining", true)
local manual = "manual of fighting w:4"
local jewelery = trove_jewel_type(_G, "Will") .. " / " ..
                 trove_jewel_type(_G, "Slay:4") .. " / " ..
                 "amulet of regeneration randart artprops:*Silence&Will w:3"
if no_friendlies(_G) == false and
trove_other_weapon_specialty(_G, "Ranged Weapons") == false then
  weap = weap .. " / " .. weap .. " / " .. trove_weap_brand(_G, "reaping", false)
  subst("? = f")
else
  subst("? = i")
end
if no_body_armour_species(_G) == false then
  manual = manual .. " / manual of armour"
end
if you.species() ~= "Demigod" then
  manual = manual .. " / manual of invocations w:4"
  jewelery = jewelery .. " / amulet of faith randart artprops:*Silence&Will w:3"
end
kitem('d = ' .. weap)
kitem('e = ' .. manual)
kitem('f = any ally scroll q:2')
trove_defense(_G, "pearl dragon scales good_item / \
                   pearl dragon scales randart artprops:*Silence&Will w:5",
                   trove_ego_gen_armour(_G, "willpower", "Will"), jewelery,
                   trove_cons(_G, scroll,
                              {"might q:2 w:5", "berserk rage q:3 w:5"},
                              nil, "wand of quicksilver charges:8",
                              "phial of floods w:2"))
local s_or_m = you.race() == "Spriggan" or you.race() == "Kobold" or
               you.race() == "Felid" or
               trove_spell_skills(_G) > trove_weapon_skills(_G) * 4
trove_unrand_chances(_G, "df", {"sword of the dread knight"}, {s_or_m}, {"?"})
}}
KFEAT:   m = iron_grate
KFEAT:   yz = x
KFEAT:   _ = altar_yredelemnul
KITEM:   " = elf skeleton / tengu skeleton w:6 / \
             spriggan skeleton w:2 / gnoll skeleton w:2
TILE:    y = wall_undead_darkgray
TILE:    z = wall_hall_magenta
TILE:    c = wall_stone_dark
TILE:    n = dngn_transparent_stone_darkgray
FTILE:   ' = floor_marble
FTILE:   defghi?$"m = floor_pebble_red
KPROP:   m = bloody
epilogue{{
            trove_milestone(_G, "The Dread Knight's Derelict Chapel")
}}
MAP
         zzzzz
       zzz'''zzz
       zn'''''nz
       zn''<''nz
      zzz'''''zzz
     zz'''''''''zz
     y'''''''''''y
     z'''mmmmm'''z
cccccc''mmd"dmm''cccccc
cgg$.c''m""e""m''c.$ggc
cg$..+''+"""""+''+..$gc
c$...c''m""d""m''c...$c
cccccc''mm?"imm''cccccc
     z'''mmmmm'''z
     y'''''''''''y
     zz'''''''''zz
      zzz'''''zzz
       zn''_''nz
       zn'''''nz
       zzz'''zzz
     xxxxxx+xxxxxx
     x...x...x...x
     x.A.+.A.+.A.x
     x...x...x...x
     xxxxxxxxxxxxx
ENDMAP

# The First Justicar's Armoury: a soft "holy" equipment trove.
# Layout very loosely based off of minmay_trove_alchemists_storehouse.
NAME:   regret_index_trove_justicar
: trove_setup(_G)
{{
kitem("d = " .. trove_weap_brand(_G, "holy_wrath", true))
local arm = "pearl dragon scales good_item w:20 / \
             pearl dragon scales randart w:5 "
if species_has_size_limits(_G) == false then
  arm = arm .. " / scale mail randart plus:5"
end
kitem("e = " .. arm)
kitem("f = " .. trove_ego_shield(_G, "positive_energy", "rN"))
kitem("g = " .. trove_jewel_type(_G, "rN") .. " / amulet of regeneration randart")
local cons = "scroll of enchant weapon w:2"
if you.mutation("no potions") ~= 1 then
  cons = cons .. " / potion of curing q:3 pre_id w:12 / \
                     potion of heal wounds pre_id q:2"
end
if no_friendlies(_G) == false then
  cons = cons .. " / any ally scroll q:4 w:2"
end
kitem("h = " .. cons)
kitem("i = scroll of brand weapon q:2 pre_id")

if trove_other_weapon_specialty(_G, "Unarmed Combat") then
  subst("d = e")
end
if you.mutation("no armour") == 1 then
  subst("de = g")
else
  if you.mutation("missing a hand") == 1 then
    if no_body_armour_species(_G) then
      subst("e = ddgh")
    elseif you.mutation("no jewellery") == 1 then
      subst("f = d")
      subst("g = e h:15")
    else
      subst("e = e:45 fg")
    end
  else
    if no_body_armour_species(_G) then
      subst("e = f")
    elseif you.mutation("no jewellery") == 1 then
      subst("f = d")
      subst("g = e h:15")
    else
      subst("e = e:25 f:20")
    end
  end
end
if you.god() == "Yredelemnul" then
  subst("h = i")
end

trove_unrand_chances(_G, "defij", {"justicar's regalia", "zealot's_sword"},
                     {no_body_armour_species(_G) or species_has_size_limits(_G),
                     you.mutation("no weapons or thrown items") == 1 or
                     species_is_undead(_G)}, {"Y", "Z"})
}}
KITEM: ~ = large rock q:1
KFEAT: C = c
: vault_metal_statue_setup(_G, "G", "golden statue")
: decorative_floor(_G, 'V', "floral vase")
SUBST: ` = ``~x, " = `
KPROP: `~ = no_tele_into
TILE:  c = wall_church
TILE:  C = wall_studio
FTILE: 'TG = floor_limestone
FTILE: `~ = floor_pebble_darkgray
epilogue {{
            trove_milestone(_G, "The First Justicar's Armoury")
}}
MAP
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
x```````ccccccccccccc```````x
x```````cdddc.V.cgh.c```````x
x```````c.hCc...cC..c```"```x
x```"```c..Cc.'.cC..c`ccncc`x
x`ccncccc+ccc.T.ccc+ccc.C.c`x
x`c.A.ccc...c.'.c...ccc...c`x
x`c...+...'...G...'...+..Cc`x
x`c.<.ccc...c.'.c...ccc...c`x
x`ccncccc+ccc.T.ccc+ccc.C.c`x
x```"```c..Cc.'.cC..c`ccncc`x
x```````c..Cc...cCe.c```"```x
x```````c.ggc.V.ceeec```````x
x```````ccccccccccccc```````x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ENDMAP

# The Octopus King's Forgotten Garden: the main remaining jewellery trove,
# though alongside eight rings it gives a hat, amulet, shield, and talisman.
# Layout directly using nicolae_trove_octotrove.
# Slightly higher weight as the main jewellery trove.
NAME:   nicolae_trove_octopus_king
TAGS:   no_species_co no_pool_fixup
WEIGHT: 12
: trove_setup(_G)
KMONS:  p = plant
KMONS:  B = bush
KMONS:  S = sacred lotus
KITEM:  d = useful hat good_item / hat randart / hat w:2
KITEM:  e = any useful amulet good_item / any randart amulet / any amulet w:2
: kitem("f = " .. trove_ego_shield(_G, nil, nil))
: kitem("g = " .. trove_good_talisman(_G))
KITEM:  h = any useful ring good_item / any randart ring w:12
KFEAT:  defgh?p = shallow_water
KFEAT:  BS = deep_water
KFEAT:  ~ = open_sea
: if species_is_undead(_G) or you.mutation("no forms") == 1 then
SUBST:  g = df
: elseif you.mutation("no armour") == 1 and
:  you.mutation("no weapons or thrown items") == 1 then
SUBST:  df = egg
: elseif you.mutation("antennae") == 3 or you.mutation("horns") == 3 then
SUBST:  d = eff
: end
: if you.mutation("missing a hand") == 1 then
SUBST:  f = e
: end
: trove_unrand_chances(_G, "h", {"ring of the octopus king"},
:                      {you.mutation("no jewellery") == 1}, {"?"})
TILE:   defghp?W = shoals_shallow_water
TILE:   wBS = shoals_deep_water
FTILE:  .A< = floor_vines
: set_border_fill_type('open_sea')
epilogue{{
            trove_milestone(_G, "The Octopus King's Forgotten Garden")
}}
MAP
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~wwwwwwwwwwwwwxwwSwwxwwwwwwwwwwwww~
~wwwwwwwwwwwBwwwwwwwwwBwwwwwwwwwww~
~wwwwwwwSwwwwwwwwwwwwwwwwwSwwwwwww~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~wwwwwwwww...ww.WdW.wwh..wwwwwwwww~
~wwwwwBwww.w.w.pepfp.www.wwwBwwwww~
~wwwwwwwwwhw....WgW......wwwwwwwww~
~wwwwwwwwwwwww.......wwwwwwwwwwwww~
~wwwSwwwwww....A.p.<......wwwwSwww~
~wwwwwwww...ww.......wwww.wwwwwwww~
~wwwwwwww.wwww.w...w...wh.wwwwwwww~
~wwwwBwwwhwwww.w.w.www.wwwwwwBwwww~
~wwwwwwwwwwh.w.w.w.www..wwwwwwwwww~
~wwwwwwwwwww...w.w...ww.hwwwwwwwww~
~wwwwwSwwwwwwwww.www.wwwwwwwSwwwww~
~wwwwwwwwwwwwh...wwh.wwwwwwwwwwwww~
~wwwwwwwwBwwwwwwwwwwwwwwwBwwwwwwww~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~wwwwwwwwwwwSwwwwwwwwwSwwwwwwwwwww~
~wwwwwwwwwwwwwxwwBwwxwwwwwwwwwwwww~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ENDMAP

# The Lost Hoard of Erebora: a dragon-themed trove.
# Based off of due's trove_jewel_1 and the like, sort of.
# (The namesake for this trove is in the Mask of the Dragon's description.)
NAME:    regret_index_trove_erebora
TAGS:    no_species_dr no_species_fe
: trove_setup(_G)
MONS:    spectral golden dragon, spectral quicksilver dragon
{{
-- All dragon scales, some elemental books, some elemental / slay jewellery,
-- hats and a manual of invocations to match the Mask, some consumables,
-- and some decoration.
local dg = "dragon_scales good_item"
local dr = "dragon scales randart"
kitem("d = steam " .. dr .. " / acid " .. dr .. " / swamp " .. dg .. " w:7 / \
           swamp" .. dr .. " / quicksilver dragon scales w:2 / \
           quicksilver " .. dr .. " w:1")
kitem("e = fire " .. dg .. " w:6 / fire " .. dr .. " w:2 / \
           ice " .. dg .. " w:6 / ice " .. dr .. " w:2 / \
           pearl " .. dg .. " w:8 / pearl " .. dr .. " w:2")
kitem("f = storm " .. dg .. " w:6 / storm " .. dr .. " w:4 / \
           shadow " .. dg .. " w:6 / shadow " .. dr .. " w:4 / \
           golden " .. dg .. " w:4 / golden " .. dr .. " w:2")
kitem("g = serpent tailsman randart w:2 / dragon-coil talisman w:6 / \
           dragon-coil talisman randart w:12")
local book = trove_book(_G, "fire disc2:ice") .. " / " ..
             trove_book(_G, "air disc2:earth")
if no_friendlies == false then
  book = book .. trove_book(_G, "summoning spells:dragon's_call") .. " w:25"
end
kitem("h = " .. book)
kitem("i = ring of slaying randart w:15 / any amulet randart artprops:rF / \
           any amulet randart artprops:rC / any amulet randart artprops:rPois")
kitem("j = useful hat ego:see_invisible good_item w:4 / \
           useful hat ego_willpower good_item w:4 / \
           hat randart artprops:Will / hat randart artprops:Slay")
kitem("k = " .. trove_cons(_G, {"fear q:2", "enchant armour w:15 q:2"},
                          {"berserk rage q:2", "enlightenment q:2"},
                           "any beam wand charges:8", nil, nil))
kitem("l = manual of invocations")
kitem("$ = gold q:1")
kitem("? = mundane spear")
nsubst("d = 1:d / 1:e / 1:f / 1:defll / 1:g / 1:h / 2:i / 1:j / 1:k / \
            1:ijll / 1:hiijj / *:.")
-- Various checks to filter through useless item drops.
if no_body_armour_species(_G) then
  nsubst("def = 2:g / * = iik")
end
if species_is_undead(_G) or you.mutation("no forms") == 1 then
 subst("g = defkl")
end
if you.god() == "Trog" or you.mutation("innate caster") == 1 then
  subst("h = defk")
end
if you.mutation("no jewellery") == 1 then
  subst("i = defkl")
end
if you.species() == "Demigod" then
  subst("l = defk")
end
if you.mutation("antennae") == 3 or you.mutation("horns") == 1 or
   you.mutation("no armour") == 1 then
  subst("j = defk")
end
trove_unrand_chances(_G, "defij", {"scales of the dragon king", "mask of the dragon"},
                     {no_body_armour_species(_G), n_hat}, {"Y", "Z"})

-- Decorative dragon skeletons under matching element clouds.
local dr = {"steam", "acid", "swamp", "fire", "ice", "storm", "shadow", "pearl"}
local cl = {"steam", "acidic fog", "poison gas", "flame", "freezing vapour",
            "thunder", "excruciating misery", "blessed fire" }
local gl = {"H", "I", "J", "K", "L", "M", "N", "O"}
for i = 1, 8, 1 do
  kitem(gl[i] .. " = " .. dr[i] .. " dragon skeleton")
  single_cloud(_G, gl[i], cl[i], false)
end
}}
KPROP:   12' = no_tele_into
TILE:    G = dngn_statue_dragon
: tile("c = " .. crackle_def(_G))
TILE:    v = dngn_metal_zot
TILE:    o = wall_permarock_clear_blue
FTILE:   '"12GHIJKLMNOo = floor_rough_blue
epilogue{{
            trove_milestone(_G, "The Lost Hoard of Erebora")
}}
MAP
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxcccxcccxxxxxxxxxxxx
xxxxxxxxxxcccIcvcJcccxxxxxxxxxx
xxxxxxxxxxcH"""""""Kcxxxxxxxxxx
xxxxxxxxxxcc"""G"""ccxxxxxxxxxx
xxxxccccccxccc"x"cccxccccccxxxx
xxxxcdccdcxxxx.x.xxxxcdccdcxxxx
xcc$$?$$?$+.x.....x.+$?$$?$$ccx
xcd?ooooooo.x..A..x.ooooooo?dcx
xcc$o'''''o.+.....+.o2''''o$ccx
xcc$o''''1o.+.....+.o'''''o$ccx
xcd?ooooooo.x..<..x.ooooooo?dcx
xcc$$?$$?$+.x.....x.+$?$$?$$ccx
xxxxcdccdcxxxx.x.xxxxcdccdcxxxx
xxxxcccccccccc"x"cccxccccccxxxx
xxxxxxxxxxcc"""G"""ccxxxxxxxxxx
xxxxxxxxxxcO"""""""Lcxxxxxxxxxx
xxxxxxxxxxcccNcvcMcccxxxxxxxxxx
xxxxxxxxxxxxcccxcccxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ENDMAP

# A Devouring Rift: the main chaos and translocations trove.
# XXX: maybe this should be named after Lugonu, instead? I do like the more
# subtle concerning tone this gifts to the current namesake, though.
NAME:   regret_index_trove_rift
: trove_setup(_G)
KMONS:  p = demonic plant
KMONS:  V = spatial vortex
NSUBST: ? = 6:d / 6:g / *:'
{{
local weap = ""
local aux1 = ""
local magic = trove_standard_magic(_G, "translocations", false)
local extra = "any manual w:1"
if no_evil(_G) then
  weap = "acquire weapon / any useful weapon good_item"
else
  weap = trove_weap_brand(_G, "chaos", true) .. " / " ..
         trove_weap_brand(_G, "distortion", false)
  if no_friendlies(_G) == false and you.mutation("innate caster") ~= 1 then
    magic = magic .. " / grand grimoire"
  end
end
if you.mutation("weakness stinger") < 1 then
  aux1 = " / cloak randart / scarf ego:shadows w:2 / \
          scarf ego:shadows randart w:2"
end
if you.species() ~= "Formicid" then
  extra = extra .. " / scroll of teleportation q:2 pre_id w:30 / \
                       scroll of blinking q:1 w:15 pre_id"
end
if species_is_undead(_G) == false then
  extra = extra .. " / potion of mutation w:12 q:3 pre_id"
end
if you.mutation("inability to use devices") ~= 1 then
  extra = extra .. " / any misc w:12"
end
trove_offense(_G, weap, magic,
                  trove_good_talisman(_G, nil, nil), "translocations magic")
trove_defense(_G, "acquire armour / any useful armour randart" .. aux1,
                  "robe randart artprops:Stlth:2 plus:2 w:5",
                   trove_jewel_type(_G, "+Blink&^Contam") .. " / " ..
                   "any amulet randart artprops:Stlth:2",
                   trove_cons(_G, {"fog q:3"},
                              {"enlightenment q:2 w:5", "attraction q:3 w:5"},
                              "", "wand of warping charges:8", nil))
kitem("! = " .. extra)
local small = you.race() == "Spriggan" or you.race() == "Kobold" or
              you.race() == "Felid"
local n_rift = you.race() == "Felid" or (small and you.mutation("missing a hand") == 1)
trove_unrand_chances(_G, "def", {"mace of variability", "rift"},
                     {small or no_evil(_G), n_rift or no_evil(_G)}, {"y", "Y"})
}}
KFEAT:   t = demonic_tree
KFEAT:   ^ = permanent teleport trap
KFEAT:   FV = w
KFEAT:   X = x
KFEAT:   Z = v
NSUBST:  defghi = 2:!
SUBST:   x = ctp x:15 ^:5 .:35 ':15, z = ccv
MARKER:  P = lua:transp_loc("trove_rift_entry")
MARKER:  Q = lua:transp_dest_loc("trove_rift_entry")
MARKER:  R = lua:transp_loc("trove_rift_exit")
MARKER:  S = lua:transp_dest_loc("trove_rift_exit")
TILE:    x = wall_abyss_magenta / wall_abyss_yellow / wall_vault w:5
TILE:    c : stone_wall_abyss_a / stone_wall_abyss_c
TILE:    v = dngn_metal_wall_magenta / dngn_metal_wall_yellow
TILE:    n = dngn_transparent_stone_magenta
TILE:    wFV = dngn_starwater
TILE:    t = dngn_demonic_tree_2 / dngn_demonic_tree_3 / \
             dngn_demonic_tree_8 / dngn_demonic_tree_9 / \
             dngn_demonic_tree_15 / dngn_demonic_tree_1
FTILE:   'defghi!tp = floor_nerves_magenta / floor_nerves_darkgray
: single_cloud(_G, "F", "seething chaos", true)
KPROP:   wFV = no_tele_into
epilogue{{
  trove_milestone(_G, "a devouring Rift")
}}
MAP
                    zzzzzzz
                   zzxxxxxzz
                  zzxx'''xxzz
                 zzxx?????xxzz
                zzxx''nnn''xxzz
               zzxx'<'nFn'R'xxzz
               zxx?''nnwnn''?xxz
               zx'?nnnwwVnnn?'xz
               zx'?nFwwwwwFn?'xz
               zx'?nnnVwwnnn?'xz
               zxx?''nnwnn''?xxz
               zzxx'Q'nFn'<'xxzz
                zzxx''nnn''xxzz
                 zzxx?????xxzz
                  zzxx'''xxzz
  zzzzzzz zzzz     zzxxxxxzz
 zzxxxxxzzzxxzzz    zzzzzzz
zzxx`x'zzzxx'zPz
zxx`x'x'zxx'''zzz
zx`x'xzz'x'x'''xz
zzxSxzzxx'xxx'xxz
 zzxzzxx'xxx'xxzz
  zzzxx'xxx'xxzz
  zzxx'xxx'xxzz
 zzxx'xxx'xxzzz
zzXX.xxx'xxzzxzz
zXX...x.xxzzx`xzz
zX.....x'zzx'x`xz
ZZZ...Xxz'x'x`xxz
 ZAZ.XXzzz'x`xxzz
 ZZZXXzzzxxxxxzz
   ZZZz zzzzzzz
ENDMAP

# An Orange Crystal Hatchery: an antimagic versus magic trove.
# Layout loosely based off of nicolae_trove_general_collection.
# This one stretches the new conceit of trove items being somewhat good for all
# characters, so it gets more consumables than other troves. The name is also
# waiting on a second orange crystal monster....
NAME:   nicolae_index_trove_orange_crystal
: trove_setup(_G)
{{
local magic = trove_standard_magic(_G, "earth", true)
local aux = ""
local extra = ""
if no_friendlies(_G) == false then
  extra = extra .. " / any ally scroll q:2"
  if you.mutation("no summoning magic") ~= 1 then
    magic = magic .. " / " .. trove_standard_magic(_G, "summoning", false) ..
            " / any magical staff randart artprops:Summ&Will w:5"
  end
end
if you.mutation("inability to train armour") ~= 1 and
 no_body_armour_species(_G) == false then
  extra = extra .. " / manual of armour w:5"
end
if you.race ~= "Coglin" and you.mutation("missing a hand") ~= 1
 and you.mutation("no armour") ~= 1 then
  extra = extra .. " / orb ego:guile randart artprops:Summ w:5"
  if you.mutation("innate caster") ~= 1 then
    extra = extra .. " / orb ego:energy randart artprops:Earth"
  end
end
if you.mutation("antennae") ~= 3 and you.mutation("horns") ~= 3 then
  aux = " / helmet randart artprops:Int w:15 / helmet randart artprops:Will w:15"
end
trove_offense(_G, trove_weap_brand(_G, "antimagic", true), magic,
                  trove_good_talisman(_G, "Int:3", "granite talisman"),
                  "earth magic")
trove_defense(_G, "robe ego:archmagi w:1", "crystal plate armour good_item w:30 / \
                   crystal plate armour randart w:29" .. aux,
                   trove_jewel_type(_G, "Int:3") .. " / " ..
                   trove_jewel_type(_G, "MP:6") ..
                   " / amulet of magic regeneration randart w:5",
                   trove_cons(_G, {"amnesia q:3 w:5", "vulnerability q:2 w:5"},
                              {"magic q:2 w:5", "ambrosia q:3 w:5"},
                              "any hex wand w:5 charges:8", nil, nil))
if extra ~= "" then
  kitem("k = " .. extra)
end
trove_unrand_chances(_G, "def", {"orange crystal plate armour"},
                     {no_body_armour_species(_G) or species_has_size_limits(_G)}, {"!"})
}}
SUBST:  ? = iik
TILE:   G = dngn_statue_demonic_bust / dngn_statue_maw / dngn_statue_wraith
TILE:   b = dngn_crystal_lightred
TILE:   m = dngn_transparent_stone_red
FTILE:  'G = floor_pebble_lightred
epilogue{{
  trove_milestone(_G, "an orange crystal hatchery")
}}
MAP
     bbb     bbb     bbb
    bb.bb   bbgbb   bb.bb
   bb.''xbbbb...bbbbx''.bb
  bx'''G'..bdb.bdb..'G'''xb
 bb'G''''...........''''G'bb
bb.'''...bgb?bdb.bgb...'''.bb
b.....A..mmmmmmmmmmm..<.....b
bb.'''...bgb.bdb?bgb...'''.bb
 bb'G''''...........''''G'bb
  bx'''G'..bdb.bdb..'G'''xb
   bb.''xbbbb...bbbbx''.bb
    bb.bb   bbgbb   bb.bb
     bbb     bbb     bbb
ENDMAP
