Skip to content
Snippets Groups Projects
zone.lua 11.7 KiB
Newer Older
dg's avatar
dg committed
-- ToME - Tales of Maj'Eyal
-- Copyright (C) 2009, 2010, 2011, 2012 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
dg's avatar
dg committed
		if game.level.level == 2 then return "Dream of loss" end
dg's avatar
dg committed
		return "Dream ???"
	end,
	variable_zone_name = true,
dg's avatar
dg committed
	level_range = {1, 1},
dg's avatar
dg committed
	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",
dg's avatar
dg committed
					nb_npc = {20, 20},
dg's avatar
dg committed
					filters = {{type="feline"}},
dg's avatar
dg committed
					randelite = 0,
				},
				object = {
					class = "engine.generator.object.Random",
					nb_object = {0, 0},
				},
				trap = {
					class = "engine.generator.trap.Random",
					nb_trap = {0, 0},
				},
dg's avatar
dg committed
			},
			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,
dg's avatar
dg committed
		},
dg's avatar
dg committed
		[2] = {
			motionblur = 3,
			width = 50, height = 50,
			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,
dg's avatar
dg committed
					floor = function() if rng.chance(20) then return "DREAM_STONE" else return "BAMBOO_HUT_FLOOR" end end,
dg's avatar
dg committed
					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",
dg's avatar
dg committed
					nb_npc = {25, 25},
					filters = {{name="yeek illusion"}},
dg's avatar
dg committed
					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)
dg's avatar
dg committed
				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

dg's avatar
dg committed
				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
dg's avatar
dg committed
				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,
		},
dg's avatar
dg committed
	},

	on_enter = function(lev, old_lev)
		-- Dream of vulnerability
		if lev == 1 then
			local f = require("mod.class.Player").new{
dg's avatar
dg committed
				name = "frail mouse", image = "npc/vermin_rodent_giant_white_mouse.png",
dg's avatar
dg committed
				type = "vermin", subtype = "rodent",
				display = "r", color=colors.WHITE,
				body = { INVEN = 10 },
				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,
				no_inventory_access = true,
dg's avatar
dg committed
				size_category = 1,
				level_range = {1, 1}, exp_worth = 1,
				max_life = 10,
dg's avatar
dg committed
				mouse_turn = game.turn,
dg's avatar
dg committed
				resolvers.talents{
dg's avatar
dg committed
					T_SHADOWSTRIKE = 5,
					T_HIDE_IN_PLAIN_SIGHT = 15,
					T_EVASION = 30,
					T_NIMBLE_MOVEMENTS = 3,
					T_PIERCING_SIGHT = 30,
				},
				on_die = function(self)
					local danger = game.level.data.real_death
dg's avatar
dg committed
					game.level:addEntity(self.summoner)
					game:onTickEnd(function()
dg's avatar
dg committed
						local x, y, z = game.level.data.caldera_x, game.level.data.caldera_y, game.level.data.caldera_z
						game:changeLevel(z, "noxious-caldera")
dg's avatar
dg committed
						game.player:move(x, y, true)
dg's avatar
dg committed
						if self.success then
							require("engine.ui.Dialog"):simpleLongPopup("Deep slumber...", [[As your mind-mouse enters the dream portal you suddenly wake up.
You feel good!]], 600)
							game.player:setEffect(game.player.EFF_VICTORY_RUSH_ZIGUR, 4, {})
dg's avatar
dg committed
							world:gainAchievement("ALL_DREAMS", self.summoner, "mice")
						else
							if not danger then
								game.player:takeHit(game.player.life * 2 / 3, game.player)
							else
								game.player:die(game.player)
							end
dg's avatar
dg committed
						end
					end)
				end,
			}
			f:resolve()
			f:resolve(nil, true)
			f.summoner = game.player

			local oldp = game.player
			game.party:addMember(f, {temporary_level=1, control="full"})
			f.x = game.player.x
			f.y = game.player.y
			game.party:setPlayer(f, true)
			game.level:addEntity(f)
			game.level.map:remove(f.x, f.y, engine.Map.ACTOR)
			game.level:removeEntity(oldp)
			f:move(f.x, f.y, true)
			f.energy.value = 1000
			game.paused = true
			game.player:updateMainShader()
dg's avatar
dg committed
			require("engine.ui.Dialog"):simpleLongPopup("Deep slumber...", [[The noxious fumes have invaded all your body, you suddenty fall into a deep slumber...
dg's avatar
dg committed
... you feel weak ...
... you feel unimportant ...
... you feel like ... food ...
You feel like running away!]], 600)
dg's avatar
dg committed
		end
dg's avatar
dg committed

		-- Dream of loss
		if lev == 2 then
			local f = require("mod.class.Player").new{
				name = "lost man", image = "npc/humanoid_human_townsfolk_meanlooking_mercenary01_64.png",
				type = "humanoid", subtype = "human",
				display = "h", color=colors.VIOLET,
				body = { INVEN = 10 },
				infravision = 10,
				stats = { str=12, dex=12, mag=3, con=10, cun=10, },
dg's avatar
dg committed
				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 },
dg's avatar
dg committed
				combat_armor = 5, combat_def = 5,
				level_range = {1, 1}, exp_worth = 1,
dg's avatar
dg committed
				max_life = 100, life_regen = 0,
				no_inventory_access = true,
dg's avatar
dg committed
				resolvers.talents{
				},
				on_die = function(self)
					local danger = game.level.data.real_death
dg's avatar
dg committed
					game.level:addEntity(self.summoner)
					game:onTickEnd(function()
dg's avatar
dg committed
						local x, y, z = game.level.data.caldera_x, game.level.data.caldera_y, game.level.data.caldera_z
						game:changeLevel(z, "noxious-caldera")
dg's avatar
dg committed
						game.player:move(x, y, true)
dg's avatar
dg committed
						if self.success then
							require("engine.ui.Dialog"):simpleLongPopup("Deep slumber...", [[As you enter the dream portal you suddenly wake up.
You feel good!]], 600)
							game.player:setEffect(game.player.EFF_VICTORY_RUSH_ZIGUR, 4, {})
							world:gainAchievement("ALL_DREAMS", self.summoner, "lost")
						else
							if not danger then
								game.player:takeHit(game.player.life * 2 / 3, game.player)
							else
								game.player:die(game.player)
							end
dg's avatar
dg committed
						end
					end)
				end,
			}
			f:resolve()
			f:resolve(nil, true)
			f.summoner = game.player

			local oldp = game.player
			game.party:addMember(f, {temporary_level=1, control="full"})
			f.x = game.player.x
			f.y = game.player.y
			game.party:setPlayer(f, true)
			game.level:addEntity(f)
			game.level.map:remove(f.x, f.y, engine.Map.ACTOR)
			game.level:removeEntity(oldp)
			f:move(f.x, f.y, true)
			f.energy.value = 1000
			game.paused = true
			game.player:updateMainShader()

			require("engine.ui.Dialog"):simpleLongPopup("Deep slumber...", [[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!]], 600)
		end
dg's avatar
dg committed
	end,
}