diff --git a/game/modules/tome/class/Party.lua b/game/modules/tome/class/Party.lua index 0717c1f063ec5227ead2d02b71065d03776d36f8..5abf95a91e69db3b55a1ff322aedf0d3e60f3c63 100644 --- a/game/modules/tome/class/Party.lua +++ b/game/modules/tome/class/Party.lua @@ -195,9 +195,10 @@ end function _M:findSuitablePlayer(type) for i, actor in ipairs(self.m_list) do local def = self.members[actor] - if def.control == "full" and (not type or def.type == type) and not actor.dead then - self:setPlayer(actor) - return true + if def.control == "full" and (not type or def.type == type) and not actor.dead and game.level:hasEntity(actor) then + if self:setPlayer(actor, true) then + return true + end end end return false diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index ee5db97d558717de18188cd49f22347abc022e2b..edf1ea6b97bb5ce27a938e96470aed3a450f8ed9 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -243,6 +243,7 @@ function _M:updateMainShader() elseif self:attr("invisible") then game.fbo_shader:setUniform("colorize", {0.4,0.5,0.7}) elseif self:attr("unstoppable") then game.fbo_shader:setUniform("colorize", {1,0.2,0}) elseif self:attr("lightning_speed") then game.fbo_shader:setUniform("colorize", {0.2,0.3,1}) + elseif game.level and game.level.data.is_eidolon_plane then game.fbo_shader:setUniform("colorize", {1,1,1}) -- elseif game:hasDialogUp() then game.fbo_shader:setUniform("colorize", {0.9,0.9,0.9}) else game.fbo_shader:setUniform("colorize", {0,0,0}) -- Disable end diff --git a/game/modules/tome/class/interface/PartyDeath.lua b/game/modules/tome/class/interface/PartyDeath.lua index bfabef4cca2d9892a096744bdbd5230273a6c1da..c81fba546d549cb36f8df16cd3be217249f8607b 100644 --- a/game/modules/tome/class/interface/PartyDeath.lua +++ b/game/modules/tome/class/interface/PartyDeath.lua @@ -48,7 +48,10 @@ function _M:onPartyDeath(src) game.player.killedBy = src game.player.died_times[#game.player.died_times+1] = {name=src.name, level=game.player.level, turn=game.turn} game.player:registerDeath(game.player.killedBy) - game:registerDialog(require("mod.dialogs."..(game.player.death_dialog or "DeathDialog")).new(game.player)) + local dialog = require("mod.dialogs."..(game.player.death_dialog or "DeathDialog")).new(game.player) + if not dialog.dont_show then + game:registerDialog(dialog) + end game.player:saveUUID() end end diff --git a/game/modules/tome/data/achievements/player.lua b/game/modules/tome/data/achievements/player.lua index e7985f5d938c3c349c6d41c45d93f4f45d3e3446..9076baaa045285f4539c08194ac547fce79920c4 100644 --- a/game/modules/tome/data/achievements/player.lua +++ b/game/modules/tome/data/achievements/player.lua @@ -43,6 +43,11 @@ newAchievement{ desc = [[Has returned from the dead.]], } +newAchievement{ + name = "Utterly Destroyed", id = "EIDOLON_DEATH", + desc = [[Died on the Eidolon Plane.]], +} + newAchievement{ name = "Emancipation", id = "EMANCIPATION", desc = [[Have the golem kill a boss while its master is already dead.]], diff --git a/game/modules/tome/data/chats/eidolon-plane.lua b/game/modules/tome/data/chats/eidolon-plane.lua new file mode 100644 index 0000000000000000000000000000000000000000..3c6bc7afd0ca0cb95e8f25def56f3d71d7a33df1 --- /dev/null +++ b/game/modules/tome/data/chats/eidolon-plane.lua @@ -0,0 +1,33 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010 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 + +newChat{ id="welcome", + text = [[#LIGHT_GREEN#*Before you stands an humanoid shape filled with 'nothing'. It seems to stare at you.*#WHITE# +I have brought you here on the instant of your death. I am the Eidolon. +I have deemed you worthy of my 'interrest', I will watch your future steps with interrest +You may rest here, when you are ready I will send you back to the material plane. +But do not abuse my help, I am not your servant, someday I might just let you die. +As for your probable many questions, they will stay unanswered, I may help, but I am not here to explain why.]], + answers = { + {"Thank you, I will rest for a while."}, + {"Thank you, I am ready to go back!", action=function() game.level.data.eidolon_exit() end}, + } +} + +return "welcome" diff --git a/game/modules/tome/data/general/objects/quest-artifacts.lua b/game/modules/tome/data/general/objects/quest-artifacts.lua index 4943713e39921bc990d7056ec1a69140778da73f..d00bd23602624780b08b1010ad2f646665b71f87 100644 --- a/game/modules/tome/data/general/objects/quest-artifacts.lua +++ b/game/modules/tome/data/general/objects/quest-artifacts.lua @@ -265,7 +265,7 @@ newEntity{ define_as = "ORB_DESTRUCTION", -- Scrying newEntity{ define_as = "ORB_SCRYING", power_source = {unknown=true}, - unique = true, quest=true, + unique = true, quest=true, no_unique_lore=true, type = "jewelry", subtype="orb", unided_name = "orb of scrying", name = "Orb of Scrying", diff --git a/game/modules/tome/data/zones/eidolon-plane/grids.lua b/game/modules/tome/data/zones/eidolon-plane/grids.lua new file mode 100644 index 0000000000000000000000000000000000000000..d9d3ec59dd841e14ab7b0eb8949086d5110a0b74 --- /dev/null +++ b/game/modules/tome/data/zones/eidolon-plane/grids.lua @@ -0,0 +1,20 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010 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 + +load("/data/general/grids/void.lua") diff --git a/game/modules/tome/data/zones/eidolon-plane/npcs.lua b/game/modules/tome/data/zones/eidolon-plane/npcs.lua new file mode 100644 index 0000000000000000000000000000000000000000..714a90f3ece2e73a216b3984321e0ba793727b69 --- /dev/null +++ b/game/modules/tome/data/zones/eidolon-plane/npcs.lua @@ -0,0 +1,34 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010 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 + +newEntity{ define_as = "EIDOLON", + type = "unknown", subtype = "unknown", + name = "The Eidolon", + display = "@", color=colors.GREY, + desc = [[Void seems more... alive, this creature stares at you with interrest.]], + faction = "neutral", + blood_color = colors.DARK, + level_range = {200, nil}, exp_worth = 0, + rank = 5, + never_move = 1, + invulnerable = 1, + never_angry = 1, + + can_talk = "eidolon-plane", +} diff --git a/game/modules/tome/data/zones/eidolon-plane/objects.lua b/game/modules/tome/data/zones/eidolon-plane/objects.lua new file mode 100644 index 0000000000000000000000000000000000000000..4e7b8c6c6405bb629806f2279b08ee9e45700cf7 --- /dev/null +++ b/game/modules/tome/data/zones/eidolon-plane/objects.lua @@ -0,0 +1,20 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010 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 + +load("/data/general/objects/objects.lua") diff --git a/game/modules/tome/data/zones/eidolon-plane/traps.lua b/game/modules/tome/data/zones/eidolon-plane/traps.lua new file mode 100644 index 0000000000000000000000000000000000000000..578363287a5ed6c725ad560b116eebc2cab48273 --- /dev/null +++ b/game/modules/tome/data/zones/eidolon-plane/traps.lua @@ -0,0 +1,20 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010 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 + +load("/data/general/traps/natural_forest.lua") diff --git a/game/modules/tome/data/zones/eidolon-plane/zone.lua b/game/modules/tome/data/zones/eidolon-plane/zone.lua new file mode 100644 index 0000000000000000000000000000000000000000..1df9d3768759c559631ba4a667d53d5d656917c8 --- /dev/null +++ b/game/modules/tome/data/zones/eidolon-plane/zone.lua @@ -0,0 +1,115 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010 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 = "Eidolon Plane", + level_range = {1, 1}, + level_scheme = "player", + max_level = 1, + width = 10, height = 10, + all_remembered = true, + all_lited = true, + no_worldport = true, + is_eidolon_plane = true, + ambient_music = "Anne_van_Schothorst_-_Passed_Tense.ogg", + generator = { + map = { + class = "engine.generator.map.Forest", + noise = "fbm_perlin", + floor = "VOID", + wall = "VOID", + up = "VOID", + down = "VOID", + }, + actor = { + class = "engine.generator.actor.Random", + nb_npc = {0, 0}, + guardian = "EIDOLON", + }, + }, + + post_process = function(level) + if level.level == 1 then + local Map = require "engine.Map" + level.background_particle = require("engine.Particles").new("starfield", 1, {width=Map.viewport.width, height=Map.viewport.height}) + end + + game.state:makeWeather(level, 6, {max_nb=1, chance=200, dir=120, speed={0.1, 0.9}, r=0.2, g=0.2, b=0.2, alpha={0.2, 0.4}, particle_name="weather/grey_cloud_%02d"}) + + -- Can drop anything on the eidolon plane + for x = 0, level.map.w - 1 do for y = 0, level.map.h - 1 do + level.map.attrs(x, y, "on_drop", function(...) game.level.data.process_drops(...) end) + end end + end, + + background = function(level, x, y, nb_keyframes) + if level.level ~= 1 then return end + + local Map = require "engine.Map" + + for i = 1, nb_keyframes do + level.background_particle:update() + level.background_particle.ps:update() + end + level.background_particle.ps:toScreen(x, y, true, 1) + end, + + -- Handle drops + process_drops = function(who, dx, dy, idx, o) + local map = game.level.map + map:removeObject(dx, dy, idx) + + game.logPlayer(who, "The Eidolon Plane seems to not physicaly exists in the same way the normal world does, you can not seem to drop anything here. %s comes back into your backpack.", o:getName{do_color=true}) + who:addObject(who.INVEN_INVEN, o) + end, + + eidolon_exit = function() + game:onTickEnd(function() + local oldzone = game.zone + local oldlevel = game.level + local zone = game.level.source_zone + local level = game.level.source_level + + local acts = {} + for act, _ in pairs(game.party.members) do + if not act.dead then + acts[#acts+1] = act + if oldlevel:hasEntity(act) then oldlevel:removeEntity(act) end + end + end + + game.zone = zone + game.level = level + game.zone_name_s = nil + + for _, act in ipairs(acts) do + local x, y = util.findFreeGrid(oldlevel.data.eidolon_exit_x or 1, oldlevel.data.eidolon_exit_y or 1, 20, true, {[engine.Map.ACTOR]=true}) + if x then + level:addEntity(act) + act:move(x, y, true) + act.changed = true + game.level.map:particleEmitter(x, y, 1, "teleport") + end + end + + game.logPlayer(game.player, "#LIGHT_RED#You are sent back to the material plane!") + game.player:updateMainShader() + end) + end, +} diff --git a/game/modules/tome/dialogs/DeathDialog.lua b/game/modules/tome/dialogs/DeathDialog.lua index cb372b4c34bcdf472e5e0984d3c94634ae7a9414..4b151b0d610ab95a27e893b11de2eded8924fb6b 100644 --- a/game/modules/tome/dialogs/DeathDialog.lua +++ b/game/modules/tome/dialogs/DeathDialog.lua @@ -106,8 +106,46 @@ function _M:resurrectBasic(actor) actor.energy.value = game.energy_to_act actor.changed = true game.paused = true +end + +--- Send the party to the Eidolon Plane +function _M:eidolonPlane() + game:onTickEnd(function() + local oldzone = game.zone + local oldlevel = game.level + local zone = engine.Zone.new("eidolon-plane") + local level = zone:getLevel(game, 1, 0) + level.data.eidolon_exit_x = self.actor.x + level.data.eidolon_exit_y = self.actor.y + + local acts = {} + for act, _ in pairs(game.party.members) do + if not act.dead then + acts[#acts+1] = act + if oldlevel:hasEntity(act) then oldlevel:removeEntity(act) end + end + end - world:gainAchievement("UNSTOPPABLE", actor) + level.source_zone = oldzone + level.source_level = oldlevel + game.zone = zone + game.level = level + game.zone_name_s = nil + + for _, act in ipairs(acts) do + local x, y = util.findFreeGrid(5, 5, 20, true, {[Map.ACTOR]=true}) + if x then + level:addEntity(act) + act:move(x, y, true) + act.changed = true + game.level.map:particleEmitter(x, y, 1, "teleport") + end + end + + game.log("#LIGHT_RED#As you are on the brink of death you seem to be yanked to an other plane.") + game.player:updateMainShader() + end) + return true end function _M:use(item) @@ -139,18 +177,22 @@ function _M:use(item) self:cleanActor(self.actor) self:restoreResources(self.actor) self:resurrectBasic(self.actor) + world:gainAchievement("UNSTOPPABLE", actor) elseif act == "easy_mode" then self.actor:attr("easy_mode_lifes", -1) - game.logPlayer(self.actor, "#LIGHT_RED#You resurrect!") - self.actor.x = self.actor.entered_level.x - self.actor.y = self.actor.entered_level.y self:cleanActor(self.actor) self:resurrectBasic(self.actor) - for uid, e in pairs(game.level.entities) do - self:restoreResources(e) + if not game.party:hasMember(e) then + self:restoreResources(e) + else + e.life = math.max(e.life, 1) + e.changed = true + end end + self:eidolonPlane() + game.log("#LIGHT_RED#You have %s left.", self.actor:attr("easy_mode_lifes") and (self.actor:attr("easy_mode_lifes").." life(s)" or "no more lifes")) elseif act == "skeleton" then self.actor:attr("re-assembled", 1) game.logPlayer(self.actor, "#YELLOW#Your bones magically come back together. You are once more able to dish out pain to your foes!") @@ -158,6 +200,7 @@ function _M:use(item) self:cleanActor(self.actor) self:restoreResources(self.actor) self:resurrectBasic(self.actor) + world:gainAchievement("UNSTOPPABLE", actor) elseif act:find("^consume") then local inven, item, o = item.inven, item.item, item.object self.actor:removeObject(inven, item) @@ -166,15 +209,33 @@ function _M:use(item) self:cleanActor(self.actor) self:restoreResources(self.actor) self:resurrectBasic(self.actor) + world:gainAchievement("UNSTOPPABLE", actor) end end function _M:generateList() local list = {} + local allow_res = true + + -- Pause the game + game:onTickEnd(function() + game.paused = true + game.player.energy.value = game.energy_to_act + end) + + if game.zone.is_eidolon_plane then + game.logPlayer(self, "You managed to die on the eidolon plane! DIE!") + game:onTickEnd(function() world:gainAchievement("EIDOLON_DEATH", self.actor) end) + allow_res = false + end if config.settings.cheat then list[#list+1] = {name="Resurrect by cheating", action="cheat"} end - if not self.actor.no_resurrect then - if self.actor:attr("easy_mode_lifes") then list[#list+1] = {name=("Resurrect (%d left)"):format(self.actor.easy_mode_lifes), action="easy_mode"} end + if not self.actor.no_resurrect and allow_res then + if self.actor:attr("easy_mode_lifes") then + self:use{action="easy_mode"} + self.dont_show = true + return + end if self.actor:attr("blood_life") and not self.actor:attr("undead") then list[#list+1] = {name="Resurrect with the Blood of Life", action="blood_life"} end if self.actor:getTalentLevelRaw(self.actor.T_SKELETON_REASSEMBLE) >= 5 and not self.actor:attr("re-assembled") then list[#list+1] = {name="Re-assemble your bones and resurrect (Skeleton ability)", action="skeleton"} end diff --git a/ideas/setting.ods b/ideas/setting.ods index 141d269e0ff4bf289b463180caab7f7a6f4b46f0..f3d218e09311632a274a580e50834ca83daee06c 100644 Binary files a/ideas/setting.ods and b/ideas/setting.ods differ