### # V for Volcano! # # A combined effort of ideas, execution and tweaking by Jude, dpeg, and Zaba! ### # # i. Threats # # Initial threat is the volcano itself; while there is quite a # delay between explosions, the flame clouds are quite powerful # and cover quite a large area; this could kill an early level # character easily, so beware! # # Loot-guard threats are defined in the fiery_guardians function. # Please see the comments there for explanations, and lists of # possible threats. # # Extra threats will be listed as MONS: lines. # # ii. Loot # # All volcanoes have a combination of the following items, though # the amounts of each usually vary. In addition, they also have # whatever armour or weapons have been created for the monsters that # populate the level. # # Fire resistance ego armour (any type of armour; this also # includes dragon armour, which is not # given extra rF+) # Flaming ego weapons (a selection of high-damage weapons) # Gold # "Good" potions with fire themes (see setup_loot() for the list) # # In addition, some volcanos have extra items taken from: # "Random item" # "Bad items" (see setup_loot() for the list) # "Fruit" (only in volano_6) # # See setup_loot() for more information. # ### # Index: # volcano_grotto - forgotten grotto "temple" volcano; a temple to # the side of a volcano, line 472-523 # volcano_lake - lava lake "temple" volcano; a temple suspended # in the middle of a volcano, line 531-591 # volcano_pools - many pools "pyramid"; some caves off a central # chamber, but no pyramid?, line 599-658 # volcano_tomb - volcano "tomb"; based of Tutankhamun's burial # chamber, has mummies and fire. Line 666-709. # volcano_aerie - "aerie"; two paths to the loot, including lindwurm # island! Line 717-775. # volcano_bunker - "hidden bunker"; "science"-ish portal vault with # golems and a "conservatory". Line 783-823. # volcano_caves - "collapsing caverns", you can choose which one you # want! maybe more than one? Line 830-902. # volcano_village - by zaba! villagerrs are kinda scary, actually! # Line 912-967. # volcano_overflow - overflowing lava! idea by dpeg, code by Jude. # Line 1034+. ### {{ -- #### -- # General setup and design functions: (head to line 382 for the maps) function volcano_portal (e) local desc_long = "Leading directly into the rock is a dark and " .. "forbidding tunnel. Every so often air, hot enough " .. "to singe your face, blasts from within, and, as " .. "though triggered by the air, rocks fall from the roof " .. "and sides of the tunnel, slowly filling the entry." local timeout_turns = crawl.random_range(1200, 1700) local messager = timed_msg { visible = true, -- $F{xxx} will be substituted with the 'entity' property of the timed -- marker, or with the desc property (if entity is not set). messages = time_messages(timeout_turns, "Rocks fall inside $F{the}.", "Debris falls inside $F{the}, filling the entry.", "More rocks fall inside $F{the}, blocking the entry.", "Rocks have almost completely blocked $F{the}.") } e.lua_marker('O', timed_marker { disappear = "There is a deep roar from within the tunnel. Moments " .. "later, a river of lava pours forth, sealing it permanently.", desc = "A dark tunnel", desc_long = desc_long, entity = 'tunnel', dst = "volcano", dstname_abbrev = "Volcano", dstorigin = "in a volcano", overmap = "dark tunnel", turns = timeout_turns, floor = "floor", msg = messager }) e.kfeat("O = enter_portal_vault") e.kfeat("S = .") e.colour("O = red") e.tags("layout_caves") end function volcano_feat_descs() dgn.set_feature_desc_short("gate leading back to the Dungeon", "rocky tunnel") dgn.set_feature_desc_short("empty arch of ancient stone", "rock-blocked tunnel") end dgn.set_lt_callback("volcano", "volcano_feat_descs") -- Destinations: function volcano_setup (e, metal) setup_loot(e) e.kfeat("< = exit_portal_vault") e.kfeat("I = exit_portal_vault") e.kfeat("^ = known alarm trap") e.subst("L : LLL.l") e.subst("L = lll.") e.subst("y : yyy.x") e.subst("y = xxx.") e.colour("< = red") e.lrockcol("red") e.lrocktile("wall_pebble_red") if metal == nil then e.colour("c = lightred") e.colour("G = lightred") e.colour("= = lightred") e.lfloorcol("red") e.lfloortile("floor_rough_red") end e.set_random_mon_list([[hog / fire elemental / fire vortex / giant ant / bumblebee / fire drake / lindwurm / imp / redback / manticore / hell hound / hell hog / ghoul / flayed ghost / pulsating lump / toenail golem / efreet / vampire]]) crawl.mark_milestone("br.enter", "entered a Volcano.") end -- "Volcano" functions. While the sizes may appear extreme, they are carefully -- weighted and balanced and have been tested extensively. local function in_radius_12 (x, y) return dgn.point_in_radius(dgn.point(x, y), dgn.point(you.pos()), 12) end local large_warning = tw_machine(3, "The air gets thick with the scent of sulphur.", "In the distance, the volcano erupts with a roar.", "The volcano comes to life with a roar!") local small_warning = tw_machine(3, nil, nil, nil, "The volcano roars to life, " .. "belching forth lava!", "The air gets thick with " .. "the scent of sulphur.", in_radius_12) function place_large_volcano(e) e.kfeat("V = l") e.lua_marker('V', fog_machine { cloud_type = "flame", walk_dist=15, pow_max=6, delay = 300, size = 10000, spread_rate = 30, listener = large_warning}) end function place_chained_volcano(e) e.kfeat("V = l") e.lua_marker('V', chained_fog_machine { cloud_type = "flame", walk_dist=15, pow_max=6, delay = 300, size = 3000, spread_rate = 30, listener = large_warning } ) end function place_small_volcano(e) e.kfeat("V = l") e.lua_marker('V', fog_machine { cloud_type = "flame", walk_dist=15, pow_max=6, delay = 300, size = 800, spread_rate = 30, listener = small_warning}) end function place_lake_volcanoes (e, glyphs) for _, glyph in ipairs(glyphs) do place_lake_volcano(e, glyph) end end function place_lake_volcano (e, glyph) e.kfeat(glyph .. " = l") e.lua_marker(glyph, chained_fog_machine { cloud_type = "flame", walk_dist=0, pow_max=6, delay_min = 300, delay_max = 800, size = 300, spread_rate = 5, listener = small_warning}) end function place_tiny_volcano(e) e.kfeat("V = l") e.lua_marker('V', fog_machine { cloud_type = "flame", walk_dist=10, pow_max=6, delay = 800, size = 80, spread_rate = 10, listener = large_warning}) end -- # -- ### -- ### -- # Loot functions: function make_fiery_armour (e, armour) local armour_string = "" for _, at in ipairs(armour) do armour_string = armour_string .. " / " .. at .. " ego:fire_resistance good_item" end return string.gsub(armour_string, "%s*\/$", "") end function make_fiery_weapon (e, weapon) local weapon_string = "" for _, wt in ipairs(weapon) do if string.find(wt, "bow") == nil then weapon_string = weapon_string .. " / " .. wt .. " ego:flaming good_item" else weapon_string = weapon_string .. " / " .. wt .. " ego:flame good_item" end end local n_weapon = string.gsub(weapon_string, "%s*\/$", "") e.item(n_weapon) end function setup_loot (e) e.item(make_fiery_armour(e, {"robe w:30", "animal skin w:30", "leather armour w:30", "ring mail w:30", "scale mail w:20", "chain mail w:20", "banded mail w:20", "plate mail w:10", "pair of gloves w:5", "helmet w:6", "pair of boots w:3", "cap w:2", "wizard hat w:2", "shield w:1", "buckler w:3"}) .. " / dragon armour w:5") e.item([[potion of berserk rage w:20 / potion of poison w:2 / potion of might w:5 / potion of brilliance w:5 / potion of agility w:5 / potion of experience w:1 / potion of resistance]]) e.item(make_fiery_weapon(e, {"demon whip w:2", "dire flail w:4", "ankus w:20", "dagger w:20", "sabre w:20", "scimitar w:20", "katana w:1", "demon blade w:1", "triple sword w:1", "broad axe w:20", "battleaxe w:10", "executioner's axe w:1", "spear w:20", "trident w:20", "demon " .. "trident w:1", "glaive w:1", "halberd w:10", "lajatang w:10", "longbow w:5", "crossbow w:5"})) e.item("any") e.item([[potion of decay / potion of degeneration / potion of mutation / scroll of immolation / scroll of curse weapon / scroll of curse armour / potion of confusion / potion of paralysis / scroll of paper / scroll of random uselessness]]) end -- # -- ### -- ### -- # Monster functions: -- This function sets up two slots of monsters: in general, the first -- slot (say, 1) is the "surrounding" guardians, while the third slot -- is a "levelled" up version of the 1s. It's currently balanced for -- two or three 1s, and one 2. -- -- Packs are basically as follows: -- ("intelligent" packs; packs involving uniques) -- orc warrior, orc warrior, orc warrior, Urug; orc warrior, orc warrior, -- orc warrior, Blork the orc; orc warrior, orc warrior, orc warrior, -- orc warrior/orc knight. -- human, human, human, Edmund; human, human, human, human. -- big kobold, big kobold, big kobold, Sonja; big kobold, big kobold, -- big kobold, big kobold. -- gnoll, gnoll, gnoll, Grum + war dogs; gnoll, gnoll, gnoll, gnoll. -- (in "Tomb") mummy, mummy, mummy, Menkaure; mummy, mummy, mummy, -- guardian mummy. -- (no-unique packs, but still "intelligent") -- deep elf fighter, deep elf fighter, deep elf fighter, deep elf -- knight; -- nothing, minotuar (all on its lonesome) -- -- Natural "packs" usually consist of a few fire/red-themed monsters -- surrounding either a lindwurm, fire drake, or manticore. -- -- Demonic "packs" usually consist high chance of imps, toenail golems -- and pulsating lumps, lower chance of red devils, hell hounds and ghouls -- which are then surrounding either a hell hog, a hell knight (with -- watered-down equipment), flayed ghost or flaming corpse. -- -- Mixed demonic/natural packs consist of mixes of the above. -- -- Non-living packs consist of fire vortices and elementals, and are usually -- mixed in with the above demonic packs. local urug = "Urug ; spear ego:flaming race:orcish . leather armour ego:fire_resistance race:orcish" local blork = "Blork the orc ; short sword race:orcish ego:flaming . leather armour ego:fire_resistance race:orcish" local edmund = "Edmund ; flail ego:flaming . leather armour ego:fire_resistance" local grum = "Grum ; animal skin ego:fire_resistance" local hellknight = "hell knight w:1 ; hand axe ego:flaming . ring mail ego:fire_resistance" function fiery_humans (e) -- This is for the village! Wargs and orcs if you came from orc if you.in_branch("orc") then local orc = "orc warrior ; ring mail ego:fire_resistance race:orcish | leather armour ego:fire_resistance \ race:orcish" e.mons("warg / " .. orc) e.mons(orc) -- But hogs and humans if you came from anywhere else. else local human = "human ; short sword ego:flaming | long sword ego:flaming . ring mail ego:fire_resistance" e.mons("hog / " .. human) e.mons(human) end end function fiery_guardians (e) local guard_type = "" local main_guard = "" -- If we came from orc, we expect to only see orcs. if you.in_branch("orc") then -- We did, and maybe we'll place a unique. if crawl.one_chance_in(9) then e.mons("orc warrior ; spear race:orcish ego:flaming . leather armour ego:fire_resistance") e.mons(urug .. " / " .. blork .. " / orc warrior ; trident race:orcish ego:flaming . ring mail ego:fire_resistance") return end -- We didn't, and maybe we'll place a unique. elseif crawl.one_chance_in(9) then -- We decided to use a unique. local unq_weight = crawl.random2(40) if unq_weight < 10 then e.mons("human ; scimitar ego:flaming . leather armour ego:fire_resistance") e.mons(edmund .. " / human ; falchion ego:flaming . scale mail ego:fire_resistance") elseif unq_weight < 20 then e.mons("big kobold ; short sword ego:flaming . leather armour ego:fire_resistance") e.mons("Sonja / big kobold ; long sword ego:flaming . ring mail ego:fire_resistance") elseif unq_weight <= 40 then e.mons("gnoll ; halberd ego:flaming | w:2 scythe ego:flaming . scale mail ego:fire_resistance | \ banded mail ego:fire_resistance") e.mons(grum .. " / gnoll ; glaive ego:flaming . banded mail \ ego:fire_resistance | plate mail ego:fire_resistance") end end -- No unique, orcs! if you.in_branch("orc") then e.mons("orc warrior ; spear race:orcish ego:flaming . leather armour ego:fire_resistance") e.mons("orc warrior ; trident race:orcish ego:flaming . ring mail ego:fire_resistance / \ orc knight ; scythe race:orcish ego:flaming . banded mail ego:fire_resistance") return end -- No unique, minotaur! if crawl.one_chance_in(10) then -- It's a lone minotaur! labyrinth-esque. e.mons("nothing") e.mons("minotaur ; trident ego:flaming . banded mail ego:fire_resistance") return end if crawl.one_chance_in(4) then if crawl.coinflip() then e.mons("big kobold ; short sword ego:flaming . leather armour ego:fire_resistance") e.mons("big kobold ; long sword ego:flaming . ring mail ego:fire_resistance / kobold demonologist w:2") else e.mons("deep elf fighter ; sabre ego:flaming race:elven") e.mons("deep elf fighter ; sabre ego:flaming race:elven . chain mail ego:fire_resistance \ race:elven / deep elf knight w:3 ; sabre ego:flaming race:elven . chain mail \ ego:fire_resistance race:elven") end return end -- Unintelligent map! -- We are now going to use a mixed pack. if crawl.one_chance_in(3) then -- "Lair"-esque fire-themed monster pack. e.mons("hog / giant ant / redback w:1 / bumblebee w:1 / manticore") e.mons("fire drake / lindwurm w:1") return end if crawl.one_chance_in(3) then -- "Demonic" fire-themed monster pack. e.mons("imp w:20 / pulsating lump / toenail golem / hell hound w:9 / \ ghoul w:9 / red devil ; trident ego:flaming") e.mons("efreet / flaming corpse / flayed ghost / hell hog / vampire / " .. hellknight) return end if crawl.coinflip() then -- Demonic/unliving themed pack. e.mons("imp / fire elemental / toenail golem / pulsating lump / hell hound / fire vortex") e.mons("efreet / vampire / " .. hellknight) return end -- Finally, if we reach this stage, let's go all out. e.mons("hell hound / hog / toenail golem / fire elemental / imp") e.mons(hellknight) return end }} default-depth: Lair:1-8, Orc:1-4, Hive:1 ############################################################################### # Entries: # [ds] A dummy entry that's a proof-of-concept for synchronized fog machines # that trigger at multiple places at the same instant, but still have a random # delay. NAME: enter_volcano_snarktest101 TAGS: uniq_volcano ORIENT: float WEIGHT: 0 {{ local fog = chained_fog_machine { cloud_type = 'flame', size = 3, pow_min=2, pow_max = 5, delay_min = 22, delay_max = 120 } lua_marker('m', fog) }} SUBST: m = . : volcano_portal(_G) MAP ....... ...m... ....... .m.O.m. ....... ...m... ....... ENDMAP NAME: enter_volcano_1 TAGS: uniq_volcano ORIENT: float COLOUR: X = red COLOUR: S = red : volcano_portal(_G) MAP xx xXX.. XXS..@ XOSS... XXSS... xXXx.xx xxxxxx ENDMAP NAME: enter_volcano_2 TAGS: uniq_volcano ORIENT: float COLOUR: X = red COLOUR: S = red : volcano_portal(_G) MAP xxxxx xXXXx xXOXx xSSSx xx.Sxx x.S.xx xx.@.x ENDMAP NAME: enter_volcano_3 TAGS: uniq_volcano ORIENT: float MONS: patrolling fire drake # His name is Robby. COLOUR: X = red COLOUR: S = red : volcano_portal(_G) MAP xxxxx xxXXXxx xXXOXXx xxSSSxx xx.1xx xx...x x..xxx. xx....@ xxxxx. ENDMAP # This is the "large" one. You might get a clear path, but then again... NAME: enter_volcano_4 TAGS: uniq_volcano ORIENT: float COLOUR: X = red COLOUR: S = red NSUBST: L = 4:. / *:l : volcano_portal(_G) MAP xxxxx xXXXx xXOXx xxSSSxx xxxSxxx xxx.xx xxx.x xxLxx xxLlLxx xxLlllLxx xLlllllLx xxLlllLxx xxLlLxx x.@.x ENDMAP ############################################################################### default-depth: ############################################################################### # "Forgotten grotto Temple" # # In the bowels of a volcano, some renegade priests of # makhleb/trog/vehumet have built a temple, which has # since been forgotten... the temple guardians still remain # and are ready to fight to the death. NAME: volcano_grotto WEIGHT: 60 ORIENT: encompass TAGS: volcano no_item_gen no_monster_gen KFEAT: _ = altar_makhleb / altar_trog / altar_vehumet KMONS: l = lava snake w:2 / lava fish w:5 / nothing w:120 KFEAT: l = l # Sets up the temple guardians. : fiery_guardians(_G) MONS: clay golem w:50 / molten gargoyle w:2 # Loot: 9 items, 8 gold. : volcano_setup(_G) : place_large_volcano(_G) MAP xxxx xxxxxxyyxxxx xxxxy......yyyxx xxxxyyy.LLLLL....yxxx xxxyyy...LlllllL.....Gxxxxxxxx xxxyy....LLlllllllL...........yxxx xxxyy....LLlllllllllL....Gxxxyy..yyxx xxyy.....LllllllllllllL..yxx xxy.y..yxx xxy......LlllllllllllllL..yxxx xxyxx.yyx xxy......LlllllllllllllllL..yyxx xxy..yxx xxy.....LllllllllllllllllllL..yyxxxxxy.xx xxy.....LllllllllllllllllllllL....yx xxy.xx xxy....LllllllllllVlllllllllllL...yxx xxy.x xy....LlllllllllllllllllllllLL...yxx xx.x xxy....LlllllllllllllllllllL....yxx xx.xx xy.....LlllllllllllllllllLL...yxx xx.x xy.y...LllllllllllllllllLL...yxx x.yx xxyxy...LllllllllllllllL...yyxx xx+xx xxxxy...LllllllllllllL...yxxx xx...xx xxy...LL....LlllllL..yxx cccccx.....xccccc xxy....xxx..LlllL...yx ccd$ecc..<..ccd$fcc xy.yxxx