Forked from
tome / Tales of MajEyal
5329 commits behind the upstream repository.
zone.lua 11.54 KiB
-- ToME - Tales of Maj'Eyal
-- Copyright (C) 2009 - 2015 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
return {
name = "Dreams",
display_name = function(x, y)
if game.level.level == 1 then return "Dream of vulnerability" end
if game.level.level == 2 then return "Dream of loss" end
return "Dream ???"
end,
variable_zone_name = true,
level_range = {1, 1},
level_scheme = "player",
max_level = 1,
decay = {300, 800},
actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end,
ambient_music = "Woods of Eremae.ogg",
min_material_level = 3,
max_material_level = 3,
generator = {
},
levels =
{
[1] = {
motionblur = 2,
width = 48, height = 48,
color_shown = {0.9, 0.7, 0.4, 1},
color_obscure = {0.9*0.6, 0.7*0.6, 0.4*0.6, 0.6},
generator = {
map = {
class = "engine.generator.map.Maze",
up = "FLOOR",
down = "DREAM_END",
wall = "JUNGLE_TREE",
floor = "JUNGLE_GRASS",
widen_w = 3, widen_h = 3,
force_last_stair = true,
},
actor = {
class = "mod.class.generator.actor.Random",
nb_npc = {20, 20},
filters = {{subtype="feline"}},
randelite = 0,
},
object = {
class = "engine.generator.object.Random",
nb_object = {0, 0},
},
trap = {
class = "engine.generator.trap.Random",
nb_trap = {0, 0},
},
},
post_process = function(level)
-- Add mouse tunnels
local Map = require "engine.Map"
local dirs = {}
for i = 1, level.map.w - 2 do for j = 1, level.map.h - 2 do
while true do -- Breakable
if level.map:checkEntity(i, j, Map.TERRAIN, "block_move") then break end
local g4 = level.map:checkEntity(i - 1, j, Map.TERRAIN, "block_move")
local g6 = level.map:checkEntity(i + 1, j, Map.TERRAIN, "block_move")
local g8 = level.map:checkEntity(i, j - 1, Map.TERRAIN, "block_move")
local g2 = level.map:checkEntity(i, j + 1, Map.TERRAIN, "block_move")
if g4 then for z = i - 1, 1, -1 do
if not level.map:checkEntity(z, j, Map.TERRAIN, "block_move") then
dirs[#dirs+1] = {dir=4, x1=i-1, y1=j, x2=z+1, y2=j}
break
end
end end
if g6 then for z = i + 1, level.map.w - 2 do
if not level.map:checkEntity(z, j, Map.TERRAIN, "block_move") then
dirs[#dirs+1] = {dir=6, x1=i+1, y1=j, x2=z-1, y2=j}
break
end
end end
if g8 then for z = j - 1, 1, -1 do
if not level.map:checkEntity(i, z, Map.TERRAIN, "block_move") then
dirs[#dirs+1] = {dir=8, x1=i, y1=j-1, x2=i, y2=z+1}
break
end
end end
if g2 then for z = j + 1, level.map.h - 2 do
if not level.map:checkEntity(i, z, Map.TERRAIN, "block_move") then
dirs[#dirs+1] = {dir=2, x1=i, y1=j+1, x2=i, y2=z-1}
break
end
end end
break -- break the while
end
end end
local nb = 0
while nb < 15 and #dirs > 0 do
local spot = rng.tableRemove(dirs)
if not level.map:checkEntity(spot.x1, spot.y1, Map.TERRAIN, "mouse_hole") and not level.map:checkEntity(spot.x2, spot.y2, Map.TERRAIN, "mouse_hole") then
local t1, t2
if spot.dir == 4 then t1, t2 = {z=5, display_x=-1.5, display_w=2, image="terrain/road_going_left_01.png"}, {z=5, display_x=-0.5, display_w=2, image="terrain/road_going_right_01.png"}
elseif spot.dir == 6 then t1, t2 = {z=5, display_x=-0.5, display_w=2, image="terrain/road_going_right_01.png"}, {z=5, display_x=-1.5, display_w=2, image="terrain/road_going_left_01.png"}
elseif spot.dir == 8 then t1, t2 = {z=5, display_y=-1.5, display_h=2, image="terrain/road_upwards_01.png"}, {z=5, display_y=-0.5, display_h=2, image="terrain/road_downwards_01.png"}
elseif spot.dir == 2 then t1, t2 = {z=5, display_y=-0.5, display_h=2, image="terrain/road_downwards_01.png"}, {z=5, display_y=-1.5, display_h=2, image="terrain/road_upwards_01.png"}
end
local g = game.zone.grid_list.DREAM_MOUSE_HOLE:clone()
g.add_displays[#g.add_displays+1] = mod.class.Grid.new(t1)
g.mouse_hole = {x=spot.x2, y=spot.y2}
game.zone:addEntity(level, g, "terrain", spot.x1, spot.y1)
local g = game.zone.grid_list.DREAM_MOUSE_HOLE:clone()
g.add_displays[#g.add_displays+1] = mod.class.Grid.new(t2)
g.mouse_hole = {x=spot.x1, y=spot.y1}
game.zone:addEntity(level, g, "terrain", spot.x2, spot.y2)
nb = nb + 1
end
end
end,
},
[2] = {
motionblur = 3,
width = 30, height = 30,
color_shown = {0.9, 0.7, 0.4, 1},
color_obscure = {0.9*0.6, 0.7*0.6, 0.4*0.6, 0.6},
generator = {
map = {
class = "engine.generator.map.Building",
max_block_w = 15, max_block_h = 15,
max_building_w = 5, max_building_h = 5,
floor = function() if rng.chance(22) then return "DREAM_STONE" else return "BAMBOO_HUT_FLOOR" end end,
external_floor = "BAMBOO_HUT_FLOOR",
wall = "BAMBOO_HUT_WALL",
up = "BAMBOO_HUT_FLOOR",
down = "BAMBOO_HUT_FLOOR",
door = "BAMBOO_HUT_DOOR",
force_last_stair = true,
lite_room_chance = 100,
},
actor = {
class = "mod.class.generator.actor.Random",
nb_npc = {10, 10},
filters = {{name="yeek illusion"}},
randelite = 0,
},
object = {
class = "engine.generator.object.Random",
nb_object = {0, 0},
},
trap = {
class = "engine.generator.trap.Random",
nb_trap = {0, 0},
},
},
post_process = function(level)
local list = {}
for uid, e in pairs(level.entities) do
if e.subtype == "yeek" then list[#list+1] = e end
end
local wife = rng.table(list)
wife.is_wife = true
level.back_shader = require("engine.Shader").new("funky_bubbles", {})
end,
background = function(level, x, y, nb_keyframes)
if not level.back_shader or not level.back_shader.shad then return end
local sx, sy = level.map._map:getScroll()
local mapcoords = {(-sx + level.map.mx * level.map.tile_w) / level.map.viewport.width , (-sy + level.map.my * level.map.tile_h) / level.map.viewport.height}
level.back_shader:setUniform("xy", mapcoords)
level.back_shader.shad:use(true)
core.display.drawQuad(x, y, level.map.viewport.width, level.map.viewport.height, 255, 255, 255, 255)
level.back_shader.shad:use(false)
end,
},
},
on_enter = function(lev, old_lev)
-- Dream of vulnerability
if lev == 1 then
game.level.data.enter_dreams{
name = "frail mouse", image = "npc/vermin_rodent_giant_white_mouse.png",
type = "vermin", subtype = "rodent",
display = "r", color=colors.WHITE,
infravision = 10,
sound_moam = {"creatures/rats/rat_hurt_%d", 1, 2},
sound_die = {"creatures/rats/rat_die_%d", 1, 2},
sound_random = {"creatures/rats/rat_%d", 1, 3},
stats = { str=8, dex=15, mag=3, con=5, cun=15, },
combat = {sound="creatures/rats/rat_attack", dam=5, atk=0, apr=10 },
combat_armor = 1, combat_def = 1,
rank = 1,
movement_speed = 1.4,
perfect_evasion = 1,
size_category = 1,
level_range = {1, 1}, exp_worth = 1,
max_life = 10,
mouse_turn = game.turn,
talent_cd_reduction={
T_EVASION=17,
T_NIMBLE_MOVEMENTS=15,
T_HIDE_IN_PLAIN_SIGHT=30,
T_STEALTH=5,
},
resolvers.talents{
T_STEALTH = 12,
T_SHADOWSTRIKE = 5,
T_HIDE_IN_PLAIN_SIGHT = 15,
T_EVASION = 30,
T_NIMBLE_MOVEMENTS = 3,
T_PIERCING_SIGHT = 30,
},
msg = [[The noxious fumes have invaded all your body, you suddenty fall into a deep slumber...
... you feel weak ...
... you feel unimportant ...
... you feel like ... food ...
You feel like running away!]],
success_msg = [[As your mind-mouse enters the dream portal you suddenly wake up.
You feel good!]],
dream = "mice",
}
end
-- Dream of loss
if lev == 2 then
game.level.data.enter_dreams{
name = "lost man", image = "npc/humanoid_human_townsfolk_meanlooking_mercenary01_64.png",
type = "humanoid", subtype = "human",
display = "h", color=colors.VIOLET,
infravision = 10,
stats = { str=12, dex=12, mag=3, con=10, cun=10, },
combat = {sound = {"actions/melee", pitch=0.6, vol=1.2}, sound_miss = {"actions/melee", pitch=0.6, vol=1.2}, dam=90, atk=15, apr=3 },
combat_armor = 5, combat_def = 5,
max_life = 100, life_regen = 0,
resolvers.talents{
},
msg = [[The noxious fumes have invaded all your body, you suddenty fall into a deep slumber...
... you feel you forgot something ...
... you feel lost ...
... you feel sad ...
You forgot your wife! Find her!]],
success_msg = [[As you enter the dream portal you suddenly wake up.
You feel good!]],
dream = "lost",
}
end
end,
enter_dreams = function(t)
local Player = require "mod.class.Player"
table.update(t, {
__no_save_json = true,
body = {INVEN=10},
no_inventory_access = true,
level_range = {1, 1}, exp_worth = 1,
on_die = function(self)
local msg = self.success_msg
local dream = self.dream
game.level.data.leave_dreams(self, msg, dream)
end,
})
local f = Player.new(t)
f:resolve() f:resolve(nil, true)
f.unused_talents = 0 f.unused_generics = 0
if f.unused_stats > 0 then
game.log("%s has %d stat point(s) to spend. Press p to use them.", f.name:capitalize(), f.unused_stats)
end
f.summoner = game:getPlayer(true)
f.x = game.player.x
f.y = game.player.y
for pmem, def in pairs(game.party.members) do
game.level.map:remove(pmem.x, pmem.y, engine.Map.ACTOR)
if game.level:hasEntity(pmem) then game.level:removeEntity(pmem) end
end
game.party:addMember(f, {temporary_level=1, control="full"})
game.party:setPlayer(f, true)
game.level:addEntity(f)
f:move(f.x, f.y, true)
f.energy.value = 1000
game.paused = true
game.player:updateMainShader()
require("engine.ui.Dialog"):simpleLongPopup("Deep slumber...", t.msg, 600)
end,
leave_dreams = function(self, msg, dream)
local danger = game.level.data.danger
game.level:addEntity(self.summoner)
game:onTickEnd(function()
game:changeLevel(game.level.data.caldera_lev, "noxious-caldera", {direct_switch=true})
for pmem, def in pairs(game.party.members) do
if pmem.caldera_x and pmem.caldera_y then
pmem:move(pmem.caldera_x, pmem.caldera_y, true)
if not game.level:hasEntity(pmem) then game.level:addEntity(pmem) end
end
end
game.party:setPlayer(game:getPlayer(true))
if self.success and danger then
require("engine.ui.Dialog"):simpleLongPopup("Deep slumber...", msg, 600)
game.logPlayer(game.player, msg:gsub("\n", " "))
game.player:setEffect(game.player.EFF_VICTORY_RUSH_ZIGUR, 4, {})
world:gainAchievement("ALL_DREAMS", self.summoner, dream)
elseif danger then
local msg = [[As you die in a dream you suddenly wake up.
Posionous fumes take their toll on your body!]]
game.logPlayer(game.player)
require("engine.ui.Dialog"):simpleLongPopup("Deep slumber...", msg, 600)
local hit = math.max(0, game.player.life * 2 / 3)
game:onTickEnd(game.player:setEffect(game.player.EFF_DEATH_DREAM, 4, {power=hit/4}))
end
end)
end,
}