diff options
Diffstat (limited to 'lib/scpt/s_geom.lua')
-rw-r--r-- | lib/scpt/s_geom.lua | 656 |
1 files changed, 656 insertions, 0 deletions
diff --git a/lib/scpt/s_geom.lua b/lib/scpt/s_geom.lua new file mode 100644 index 00000000..b9730318 --- /dev/null +++ b/lib/scpt/s_geom.lua @@ -0,0 +1,656 @@ +-- Geomancy school + +function geomancy_random_wall(y, x) + local c_ptr = cave(y, x) + + -- Do not destroy permanent things + if cave_is(c_ptr, FF1_PERMANENT) ~= FALSE then return end + + local feat = nil + local table = + { + [1] = { SKILL_FIRE, FEAT_SANDWALL, 1}, + + [2] = { SKILL_WATER, FEAT_TREES, 1}, + [3] = { SKILL_WATER, FEAT_ICE_WALL, 12}, + + [4] = { SKILL_EARTH, FEAT_WALL_EXTRA, 1}, + } + + while feat == nil do + local t = table[randint(getn(table))] + + -- Do we meet the requirements ? + -- And then select the features based on skill proportions + if get_skill(t[1]) >= t[3] and magik(get_skill_scale(t[1], 100)) == TRUE then + feat = t[2] + end + end + + cave_set_feat(y, x, feat) +end + + +GF_ELEMENTAL_WALL = add_spell_type +{ + ["color"] = { TERM_GREEN, 0 }, + ["angry"] = function() return TRUE, FALSE end, + ["grid"] = function(who, dam, rad, y, x) + if player.py ~= y or player.px ~= x then + geomancy_random_wall(y, x) + end + end, +} + +function geomancy_random_floor(y, x, kill_wall) + local c_ptr = cave(y, x) + + -- Do not destroy permanent things + if cave_is(c_ptr, FF1_PERMANENT) ~= FALSE then return end + if not kill_wall then + if cave_is(c_ptr, FF1_FLOOR) ~= TRUE then return end + end + + local feat = nil + local table = + { + [1] = { SKILL_FIRE, FEAT_SAND, 1}, + [2] = { SKILL_FIRE, FEAT_SHAL_LAVA, 8}, + [3] = { SKILL_FIRE, FEAT_DEEP_LAVA, 18}, + + [4] = { SKILL_WATER, FEAT_SHAL_WATER, 1}, + [5] = { SKILL_WATER, FEAT_DEEP_WATER, 8}, + [6] = { SKILL_WATER, FEAT_ICE, 18}, + + [7] = { SKILL_EARTH, FEAT_GRASS, 1}, + [8] = { SKILL_EARTH, FEAT_FLOWER, 8}, + [9] = { SKILL_EARTH, FEAT_DARK_PIT, 18}, + } + + while feat == nil do + local t = table[randint(getn(table))] + + -- Do we meet the requirements ? + -- And then select the features based on skill proportions + if get_skill(t[1]) >= t[3] and magik(get_skill_scale(t[1], 100)) == TRUE then + feat = t[2] + end + end + + cave_set_feat(y, x, feat) +end + + +GF_ELEMENTAL_GROWTH = add_spell_type +{ + ["color"] = { TERM_GREEN, 0 }, + ["angry"] = function() return TRUE, FALSE end, + ["grid"] = function(who, dam, rad, y, x) + geomancy_random_floor(y, x) + end, +} + +CALL_THE_ELEMENTS = add_spell +{ + ["name"] = "Call the Elements", + ["school"] = {SCHOOL_GEOMANCY}, + ["level"] = 1, + ["mana"] = 2, + ["mana_max"] = 20, + ["fail"] = 10, + -- Unnafected by blindness + ["blind"] = FALSE, + ["random"] = 0, + ["spell"] = function() + local ret, dir = 0, 0 + + if get_level(CALL_THE_ELEMENTS) >= 17 then + ret, dir = get_aim_dir() + if ret == FALSE then return end + end + + fire_ball(GF_ELEMENTAL_GROWTH, dir, 1, 1 + get_level(CALL_THE_ELEMENTS, 5, 0)) + return TRUE + end, + ["info"] = function() + return "rad "..(1 + get_level(CALL_THE_ELEMENTS, 5, 0)) + end, + ["desc"] = { + "Randomly creates various elements around you", + "Each type of element chance is controlled by your level", + "in the corresponding skill", + "At level 17 it can be targeted", + } +} + +-- Seperate function because an other spell needs it +function channel_the_elements(y, x, level, silent) + local t = + { + -- Earth stuff + [FEAT_GRASS] = function() + hp_player(player.mhp * (5 + get_skill_scale(SKILL_EARTH, 20)) / 100) + end, + [FEAT_FLOWER] = function() + hp_player(player.mhp * (5 + get_skill_scale(SKILL_EARTH, 30)) / 100) + end, + [FEAT_DARK_PIT] = function() + local ret, dir = get_aim_dir() + if ret == FALSE then return end + + local type = GF_DARK + if get_skill(SKILL_EARTH) >= 18 then type = GF_NETHER end + fire_bolt(type, dir, damroll(10, get_skill(SKILL_EARTH))) + end, + + -- Water stuff + [FEAT_SHAL_WATER] = function() + local ret, dir = get_aim_dir() + if ret == FALSE then return end + + local type = GF_WATER + if get_skill(SKILL_WATER) >= 18 then type = GF_WAVE end + + if get_skill(SKILL_WATER) >= 8 then + fire_beam(type, dir, damroll(3, get_skill(SKILL_WATER))) + else + fire_bolt(type, dir, damroll(3, get_skill(SKILL_WATER))) + end + end, + [FEAT_DEEP_WATER] = function() + local ret, dir = get_aim_dir() + if ret == FALSE then return end + + local type = GF_WATER + if get_skill(SKILL_WATER) >= 18 then type = GF_WAVE end + + if get_skill(SKILL_WATER) >= 8 then + fire_beam(type, dir, damroll(5, get_skill(SKILL_WATER))) + else + fire_bolt(type, dir, damroll(5, get_skill(SKILL_WATER))) + end + end, + [FEAT_ICE] = function() + local ret, dir = get_aim_dir() + if ret == FALSE then return end + + if get_skill(SKILL_WATER) >= 12 then + fire_ball(GF_ICE, dir, get_skill_scale(SKILL_WATER, 340), 3) + else + fire_bolt(GF_ICE, dir, damroll(3, get_skill(SKILL_WATER))) + end + end, + + -- Fire stuff + [FEAT_SAND] = function() + local type + if (get_level(FIERYAURA, 50) >= 8) then + type = SHIELD_GREAT_FIRE + else + type = SHIELD_FIRE + end + local dur = randint(20) + %level + get_skill(SKILL_AIR) + set_shield(dur, 0, type, 5 + get_skill_scale(SKILL_FIRE, 20), 5 + get_skill_scale(SKILL_FIRE, 14)) + set_blind(dur) + end, + [FEAT_SHAL_LAVA] = function() + local ret, dir = get_aim_dir() + if ret == FALSE then return end + + if get_skill(SKILL_FIRE) >= 15 then + fire_bolt(GF_HELL_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15)) + else + fire_bolt(GF_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15)) + end + end, + [FEAT_DEEP_LAVA] = function() + local ret, dir = get_aim_dir() + if ret == FALSE then return end + + if get_skill(SKILL_FIRE) >= 15 then + fire_ball(GF_HELL_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15), 3) + else + fire_ball(GF_FIRE, dir, damroll(get_skill_scale(SKILL_FIRE, 30), 15), 3) + end + end, + } + + if t[cave(y, x).feat] then + t[cave(y, x).feat]() + + if magik(100 - level) == TRUE then + if cave(y, x).feat == FEAT_FLOWER then + cave_set_feat(y, x, FEAT_GRASS) + else + cave_set_feat(y, x, FEAT_FLOOR) + end + msg_print("The area is drained.") + end + elseif not silent then + msg_print("You cannot channel this area.") + end +end + +CHANNEL_ELEMENTS = add_spell +{ + ["name"] = "Channel Elements", + ["school"] = {SCHOOL_GEOMANCY}, + ["level"] = 3, + ["mana"] = 3, + ["mana_max"] = 30, + ["fail"] = 20, + -- Unnafected by blindness + ["blind"] = FALSE, + ["random"] = 0, + ["spell"] = function() + channel_the_elements(player.py, player.px, get_level(CHANNEL_ELEMENTS), nil) + return TRUE + end, + ["info"] = function() + return "" + end, + ["desc"] = { + "Draws on the caster's immediate environs to form an attack or other effect.", + "Grass/Flower heals.", + "Water creates water bolt attacks.", + "Ice creates ice bolt attacks.", + "Sand creates a wall of thick, blinding, burning sand around you.", + "Lava creates fire bolt attacks.", + "Deep lava creates fire ball attacks.", + "Chasm creates darkness bolt attacks.", + "At Earth level 18, darkness becomes nether.", + "At Water level 8, water attacks become beams with a striking effect.", + "At Water level 12, ice attacks become balls of ice shards.", + "At Water level 18, water attacks push monsters back.", + "At Fire level 15, fire become hellfire.", + } +} + +ELEMENTAL_WAVE = add_spell +{ + ["name"] = "Elemental Wave", + ["school"] = {SCHOOL_GEOMANCY}, + ["level"] = 15, + ["mana"] = 15, + ["mana_max"] = 50, + ["fail"] = 20, + -- Unnafected by blindness + ["blind"] = FALSE, + ["random"] = 0, + ["spell"] = function() + local ret, dir = get_rep_dir() + if ret == FALSE then return end + + local y, x = explode_dir(dir) + y = y + player.py + x = x + player.px + + local t = + { + -- Earth stuff + [FEAT_GRASS] = { GF_POIS, GF_POIS, 10 + get_skill_scale(SKILL_EARTH, 200) }, + [FEAT_FLOWER] = { GF_POIS, GF_POIS, 10 + get_skill_scale(SKILL_EARTH, 300) }, + -- cannot turn chasm into a wave + + -- Water stuff + [FEAT_SHAL_WATER] = { GF_WATER, GF_WATER, 10 + get_skill_scale(SKILL_WATER, 200) }, + [FEAT_DEEP_WATER] = { GF_WATER, GF_WATER, 10 + get_skill_scale(SKILL_WATER, 300) }, + [FEAT_ICE] = { GF_ICE, GF_ICE, 10 + get_skill_scale(SKILL_WATER, 200) }, + + -- Fire stuff + [FEAT_SAND] = { GF_LITE, GF_LITE, 10 + get_skill_scale(SKILL_FIRE, 400) }, + [FEAT_SHAL_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 10 + get_skill_scale(SKILL_FIRE, 200) }, + [FEAT_DEEP_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 10 + get_skill_scale(SKILL_FIRE, 300) }, + } + + + local effect = t[cave(y, x).feat] + if not effect then + msg_print("You cannot channel this area.") + else + local typ = effect[1] + if get_level(ELEMENTAL_WAVE) >= 20 then typ = effect[2] end + + cave_set_feat(y, x, FEAT_FLOOR) + + fire_wave(typ, 0, effect[3], 0, 6 + get_level(ELEMENTAL_WAVE, 20), EFF_WAVE + EFF_LAST + getglobal("EFF_DIR"..dir)) + end + + return TRUE + end, + ["info"] = function() + return "" + end, + ["desc"] = { + "Draws on an adjacent special square to project a slow-moving", + "wave of that element in that direction", + "Abyss squares cannot be channeled into a wave.", + } +} + +VAPORIZE = add_spell +{ + ["name"] = "Vaporize", + ["school"] = {SCHOOL_GEOMANCY}, + ["level"] = 4, + ["mana"] = 3, + ["mana_max"] = 30, + ["fail"] = 15, + -- Unnafected by blindness + ["blind"] = FALSE, + -- Must have at least 4 Air + ["random"] = 0, + ["depend"] = function() + if get_skill(SKILL_AIR) >= 4 then return TRUE end + end, + ["spell"] = function() + local t = + { + -- Earth stuff + [FEAT_GRASS] = { GF_POIS, GF_POIS, 5 + get_skill_scale(SKILL_EARTH, 100) }, + [FEAT_FLOWER] = { GF_POIS, GF_POIS, 5 + get_skill_scale(SKILL_EARTH, 150) }, + [FEAT_DARK_PIT] = { GF_DARK, GF_DARK, 5 + get_skill_scale(SKILL_EARTH, 200) }, + + -- Water stuff + [FEAT_SHAL_WATER] = { GF_WATER, GF_WATER, 5 + get_skill_scale(SKILL_WATER, 100) }, + [FEAT_DEEP_WATER] = { GF_WATER, GF_WATER, 5 + get_skill_scale(SKILL_WATER, 150) }, + [FEAT_ICE] = { GF_ICE, GF_ICE, 5 + get_skill_scale(SKILL_WATER, 100) }, + + -- Fire stuff + [FEAT_SAND] = { GF_LITE, GF_LITE, 5 + get_skill_scale(SKILL_FIRE, 200) }, + [FEAT_SHAL_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 5 + get_skill_scale(SKILL_FIRE, 100) }, + [FEAT_DEEP_LAVA] = { GF_FIRE, GF_HOLY_FIRE, 5 + get_skill_scale(SKILL_FIRE, 150) }, + } + + local effect = t[cave(player.py, player.px).feat] + if not effect then + msg_print("You cannot channel this area.") + else + local typ = effect[1] + if get_level(VAPORIZE) >= 20 then typ = effect[2] end + + cave_set_feat(player.py, player.px, FEAT_FLOOR) + + fire_cloud(typ, 0, effect[3], 1 + get_level(VAPORIZE, 4), 10 + get_level(VAPORIZE, 20)) + end + + return TRUE + end, + ["info"] = function() + return "rad "..(1 + get_level(VAPORIZE, 4)).." dur "..(10 + get_level(VAPORIZE, 20)) + end, + ["desc"] = { + "Draws upon your immediate environs to form a cloud of damaging vapors", + } +} + +geomancy_can_tunnel = +{ + [FEAT_WALL_EXTRA] = TRUE, + [FEAT_WALL_OUTER] = TRUE, + [FEAT_WALL_INNER] = TRUE, + [FEAT_WALL_SOLID] = TRUE, + + [FEAT_MAGMA] = TRUE, + [FEAT_QUARTZ] = TRUE, + [FEAT_MAGMA_H] = TRUE, + [FEAT_QUARTZ_H] = TRUE, + [FEAT_MAGMA_K] = TRUE, + [FEAT_QUARTZ_K] = TRUE, + + [FEAT_TREES] = TRUE, + [FEAT_DEAD_TREE] = TRUE, + + [FEAT_SANDWALL] = TRUE, + [FEAT_SANDWALL_H] = TRUE, + [FEAT_SANDWALL_K] = TRUE, + + [FEAT_ICE_WALL] = TRUE, +} + +-- Dig & sprew +function geomancy_dig(oy, ox, dir, length) + local dy, dx = explode_dir(dir) + local y = dy + oy + local x = dx + ox + + for i = 1, length do + local c_ptr = cave(y, x) + local ox = x - dx + local oy = y - dy + + -- stop at the end of tunnelable things + if not geomancy_can_tunnel[c_ptr.feat] then break end + + if geomancy_can_tunnel[cave(y - 1, x - 1).feat] then geomancy_random_wall(y - 1, x - 1) end + if geomancy_can_tunnel[cave(y - 1, x).feat] then geomancy_random_wall(y - 1, x) end + if geomancy_can_tunnel[cave(y - 1, x + 1).feat] then geomancy_random_wall(y - 1, x + 1) end + + if geomancy_can_tunnel[cave(y, x - 1).feat] then geomancy_random_wall(y, x - 1) end + if geomancy_can_tunnel[cave(y, x + 1).feat] then geomancy_random_wall(y, x + 1) end + + if geomancy_can_tunnel[cave(y + 1, x - 1).feat] then geomancy_random_wall(y + 1, x - 1) end + if geomancy_can_tunnel[cave(y + 1, x).feat] then geomancy_random_wall(y + 1, x) end + if geomancy_can_tunnel[cave(y + 1, x + 1).feat] then geomancy_random_wall(y + 1, x + 1) end + + y = y + dy + x = x + dx + end + + y = y - dy + x = x - dx + while (y ~= oy) or (x ~= ox) do + geomancy_random_floor(y, x, TRUE) + + -- Should we branch ? + if magik(20) == TRUE then + local rot = 1 + if magik(50) == TRUE then rot = -1 end + geomancy_dig(y, x, rotate_dir(dir, rot), length / 3) + end + + y = y - dy + x = x - dx + end +end + +GEOLYSIS = add_spell +{ + ["name"] = "Geolysis", + ["school"] = {SCHOOL_GEOMANCY}, + ["level"] = 7, + ["mana"] = 15, + ["mana_max"] = 40, + ["fail"] = 15, + -- Unnafected by blindness + ["blind"] = FALSE, + ["random"] = 0, + -- Must have at least 7 Earth + ["depend"] = function() + if get_skill(SKILL_EARTH) >= 7 then return TRUE end + end, + ["spell"] = function() + local ret, dir = get_rep_dir() + if ret == FALSE then return end + + msg_print("Elements recombine before you, laying down an open path.") + geomancy_dig(player.py, player.px, dir, 5 + get_level(GEOLYSIS, 12)) + + return TRUE + end, + ["info"] = function() + return "length "..(5 + get_level(GEOLYSIS, 12)) + end, + ["desc"] = { + "Burrows deeply and slightly at random into a wall,", + "leaving behind tailings of various different sorts of walls in the passage.", + } +} + +player.dripping_tread = 0 +add_loadsave("player.dripping_tread", 0) +add_hooks +{ + [HOOK_MOVED] = function(oy, ox) + if player.dripping_tread > 0 then + geomancy_random_floor(oy, ox) + player.dripping_tread = player.dripping_tread - 1 + if player.dripping_tread == 0 then + msg_print("You stop dripping raw elemental energies.") + end + end + end +} +DRIPPING_TREAD = add_spell +{ + ["name"] = "Dripping Tread", + ["school"] = {SCHOOL_GEOMANCY}, + ["level"] = 10, + ["mana"] = 15, + ["mana_max"] = 25, + ["fail"] = 15, + -- Unnafected by blindness + ["blind"] = FALSE, + ["random"] = 0, + -- Must have at least 10 Water + ["depend"] = function() + if get_skill(SKILL_WATER) >= 10 then return TRUE end + end, + ["spell"] = function() + if player.dripping_tread == 0 then + player.dripping_tread = randint(15) + 10 + get_level(DRIPPING_TREAD) + msg_print("You start dripping raw elemental energies.") + else + player.dripping_tread = 0 + msg_print("You stop dripping raw elemental energies.") + end + return TRUE + end, + ["info"] = function() + return "dur "..(10 + get_level(DRIPPING_TREAD)).."+d15 movs" + end, + ["desc"] = { + "Causes you to leave random elemental forms behind as you walk", + } +} + +GROW_BARRIER = add_spell +{ + ["name"] = "Grow Barrier", + ["school"] = {SCHOOL_GEOMANCY}, + ["level"] = 12, + ["mana"] = 30, + ["mana_max"] = 40, + ["fail"] = 15, + -- Unnafected by blindness + ["blind"] = FALSE, + ["random"] = 0, + -- Must have at least 12 Earth + ["depend"] = function() + if get_skill(SKILL_EARTH) >= 12 then return TRUE end + end, + ["spell"] = function() + local ret, dir = 0, 0 + + if get_level(GROW_BARRIER) >= 20 then + ret, dir = get_aim_dir() + if ret == FALSE then return end + end + + fire_ball(GF_ELEMENTAL_WALL, dir, 1, 1) + return TRUE + end, + ["info"] = function() + return "" + end, + ["desc"] = { + "Creates impassable terrain (walls, trees, etc.) around you.", + "At level 20 it can be projected around another area.", + } +} + +ELEMENTAL_MINION = add_spell +{ + ["name"] = "Elemental Minion", + ["school"] = {SCHOOL_GEOMANCY}, + ["level"] = 20, + ["mana"] = 40, + ["mana_max"] = 80, + ["fail"] = 25, + -- Unnafected by blindness + ["random"] = 0, + -- Must have at least 12 Earth + ["spell"] = function() + local ret, dir = 0, 0 + + ret, dir = get_rep_dir() + if ret == FALSE then return end + + local t = + { + [FEAT_WALL_EXTRA] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + [FEAT_WALL_OUTER] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + [FEAT_WALL_INNER] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + [FEAT_WALL_SOLID] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + [FEAT_MAGMA] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + [FEAT_QUARTZ] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + [FEAT_MAGMA_H] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + [FEAT_QUARTZ_H] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + [FEAT_MAGMA_K] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + [FEAT_QUARTZ_K] = { SKILL_EARTH, { "Earth elemental", "Xorn", "Xaren" } }, + + [FEAT_DARK_PIT] = { SKILL_AIR, { "Air elemental", "Ancient blue dragon", "Great Storm Wyrm", "Sky Drake" } }, + + [FEAT_SANDWALL] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } }, + [FEAT_SANDWALL_H] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } }, + [FEAT_SANDWALL_K] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } }, + [FEAT_SHAL_LAVA] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } }, + [FEAT_DEEP_LAVA] = { SKILL_FIRE, { "Fire elemental", "Ancient red dragon" } }, + + [FEAT_ICE_WALL] = { SKILL_WATER, { "Water elemental", "Water troll", "Water demon" } }, + [FEAT_SHAL_WATER] = { SKILL_WATER, { "Water elemental", "Water troll", "Water demon" } }, + [FEAT_DEEP_WATER] = { SKILL_WATER, { "Water elemental", "Water troll", "Water demon" } }, + } + + local y, x = explode_dir(dir) + y = y + player.py + x = x + player.px + + local effect = t[cave(y, x).feat] + if not effect then + msg_print("You cannot summon from this area.") + else + local skill = effect[1] + local types = effect[2] + + local max = get_skill_scale(skill, getn(types)) + if max == 0 then max = 1 end + + local r_idx = test_monster_name(types[rand_range(1, max)]) + + -- Summon it + local my, mx = find_position(y, x) + local m_idx = place_monster_one(my, mx, r_idx, 0, FALSE, MSTATUS_FRIEND) + + -- level it + if m_idx ~= 0 then + monster_set_level(m_idx, 10 + get_level(ELEMENTAL_MINION, 120)) + end + + cave_set_feat(y, x, FEAT_FLOOR) + end + + return TRUE + end, + ["info"] = function() + return "min level "..(10 + get_level(ELEMENTAL_MINION, 120)) + end, + ["desc"] = { + "Summons a minion from a nearby element.", + "Walls can summon Earth elmentals, Xorns and Xarens", + "Dark Pits can summon Air elementals, Ancient blue dragons, Great Storm Wyrms", + "and Sky Drakes", + "Sandwalls and lava can summon Fire elementals and Ancient red dragons", + "Icewall, and water can summon Water elementals, Water trolls and Water demons", + } +} |