Skip to content
Snippets Groups Projects
slumber.lua 9.71 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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
    
    newTalent{
    
    	name = "Slumber",
    
    dg's avatar
    dg committed
    	type = {"psionic/slumber", 1},
    
    dg's avatar
    dg committed
    	points = 5,
    
    dg's avatar
    dg committed
    	require = psi_wil_req1,
    
    	psi = 10,
    	tactical = { DISABLE = {sleep = 2} },
    
    dg's avatar
    dg committed
    	direct_hit = true,
    	requires_target = true,
    
    	range = 7,
    
    	target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end,
    
    	getDuration = function(self, t) return 2 + math.ceil(self:getTalentLevel(t)/2) end,
    
    dg's avatar
    dg committed
    	getInsomniaPower = function(self, t)
    
    		local t = self:getTalentFromId(self.T_SANDMAN)
    
    dg's avatar
    dg committed
    		local reduction = t.getInsomniaPower(self, t)
    
    		return 20 - reduction
    
    dg's avatar
    dg committed
    	getSleepPower = function(self, t)
    
    		local power = self:combatTalentMindDamage(t, 10, 100)
    
    		if self:knowTalent(self.T_SANDMAN) then
    			local t = self:getTalentFromId(self.T_SANDMAN)
    
    dg's avatar
    dg committed
    			power = power * t.getSleepPowerBonus(self, t)
    
    dg's avatar
    dg committed
    		end
    
    dg's avatar
    dg committed
    		return math.ceil(power)
    
    dg's avatar
    dg committed
    	action = function(self, t)
    		local tg = self:getTalentTarget(t)
    
    		local x, y, target = self:getTarget(tg)
    
    		local _ _, x, y = self:canProject(tg, x, y)
    		target = game.level.map(x, y, Map.ACTOR)
    		if not target then return nil end
    
    		--Restless?
    		local is_waking =0
    		if self:knowTalent(self.T_RESTLESS_NIGHT) then
    			local t = self:getTalentFromId(self.T_RESTLESS_NIGHT)
    			is_waking = t.getDamage(self, t)
    		end
    
    dg's avatar
    dg committed
    
    
    		local power = self:mindCrit(t.getSleepPower(self, t))
    
    		if target:canBe("sleep") then
    
    dg's avatar
    dg committed
    			target:setEffect(target.EFF_SLUMBER, t.getDuration(self, t), {src=self, power=power, waking=is_waking, insomnia=t.getInsomniaPower(self, t), no_ct_effect=true, apply_power=self:combatMindpower()})
    
    dg's avatar
    dg committed
    			game.level.map:particleEmitter(target.x, target.y, 1, "generic_charge", {rm=180, rM=200, gm=100, gM=120, bm=30, bM=50, am=70, aM=180})
    
    		else
    			game.logSeen(self, "%s resists the sleep!", target.name:capitalize())
    		end
    
    		game:playSoundNear(self, "talents/dispel")
    
    dg's avatar
    dg committed
    		return true
    	end,
    	info = function(self, t)
    
    		local duration = t.getDuration(self, t)
    		local power = t.getSleepPower(self, t)
    
    dg's avatar
    dg committed
    		local insomnia = t.getInsomniaPower(self, t)
    
    		return([[Puts the target into a deep sleep for %d turns, rendering it unable to act.  Every %d points of damage the target suffers will reduce the effect duration by one turn.
    
    dg's avatar
    dg committed
    		When Slumber ends the target will suffer from Insomnia for a number of turns equal to the amount of time it was asleep (up to ten turns max), granting it %d%% sleep immunity for each turn of the Insomnia effect.
    
    		The damage threshold will scale with your mindpower.]]):format(duration, power, insomnia)
    
    dg's avatar
    dg committed
    	end,
    }
    
    newTalent{
    
    	name = "Restless Night",
    
    dg's avatar
    dg committed
    	type = {"psionic/slumber", 2},
    
    dg's avatar
    dg committed
    	points = 5,
    
    dg's avatar
    dg committed
    	require = psi_wil_req2,
    
    	getDamage = function(self, t) return self:combatTalentMindDamage(t, 20, 200) end,
    
    dg's avatar
    dg committed
    	info = function(self, t)
    
    		local damage = t.getDamage(self, t)
    		return([[Targets you have slept now take %0.2f mind damage upon waking.
    		The damage will scale with your mindpower.]]):format(damDesc(self, DamageType.MIND, (damage)))
    
    dg's avatar
    dg committed
    	end,
    }
    
    newTalent{
    
    	name = "Sandman",
    
    dg's avatar
    dg committed
    	type = {"psionic/slumber", 3},
    
    dg's avatar
    dg committed
    	points = 5,
    
    dg's avatar
    dg committed
    	require = psi_wil_req3,
    
    	mode = "passive",
    
    dg's avatar
    dg committed
    	getSleepPowerBonus = function(self, t) return 1 + math.min(1, self:getTalentLevel(t)/10) end,
    	getInsomniaPower = function(self, t) return math.min(10, self:getTalentLevelRaw(t) * 2) end,
    
    dg's avatar
    dg committed
    	info = function(self, t)
    
    dg's avatar
    dg committed
    		local power_bonus = t.getSleepPowerBonus(self, t) - 1
    
    dg's avatar
    dg committed
    		local insomnia = t.getInsomniaPower(self, t)
    
    dg's avatar
    dg committed
    		return([[Increases the amount of damage you can deal to sleeping targets before reducing the effect duration by %d%% and reduces the sleep immunity of your Insomnia effects by %d%%.
    
    		These effects will be directly reflected in the appropriate talent descriptions.
    
    dg's avatar
    dg committed
    		The damage threshold bonus will scale with your mindpower.]]):format(power_bonus * 100, insomnia)
    
    dg's avatar
    dg committed
    	end,
    }
    
    newTalent{
    
    	name = "Dreamscape",
    
    dg's avatar
    dg committed
    	type = {"psionic/slumber", 4},
    
    dg's avatar
    dg committed
    	points = 5,
    
    dg's avatar
    dg committed
    	require = psi_wil_req4,
    
    	cooldown = 24,
    	psi = 40,
    
    dg's avatar
    dg committed
    	random_boss_rarity = 10,
    
    dg's avatar
    dg committed
    	tactical = { DISABLE = function(self, t, target) if target and target.game_ender and target:attr("sleep") then return 4 else return 0 end end},
    
    	direct_hit = true,
    	requires_target = true,
    
    	range = 7,
    
    	target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end,
    
    	getDuration = function(self, t) return 4 + math.ceil(self:getTalentLevel(t) * 2) end,
    
    	getPower = function(self, t) return self:combatTalentMindDamage(t, 10, 100) end,
    	on_pre_use = function(self, t, silent) if self:attr("is_psychic_projection") then if not silent then game.logPlayer(self, "You feel it unwise to travel to the dreamscape in such a fragile form.") end return false end return true end,
    	action = function(self, t)
    		if game.zone.is_dream_scape then
    			game.logPlayer(self, "This talent can not be used from within the Dreamscape.")
    			return
    
    dg's avatar
    dg committed
    		end
    
    		if game.zone.no_planechange then
    			game.logPlayer(self, "This talent can not be used here.")
    			return
    
    dg's avatar
    dg committed
    		end
    
    		if not self:canBe("planechange") then
    			game.logPlayer(self, "The effect fizzles...")
    			return
    		end
    
    dg's avatar
    dg committed
    
    
    		local tg = {type="hit", range=self:getTalentRange(t), talent=t}
    		local tx, ty, target = self:getTarget(tg)
    		if not tx or not ty or not target then return nil end
    		local _ _, tx, ty = self:canProject(tg, tx, ty)
    		if not tx or not ty or not target then return nil end
    		target = game.level.map(tx, ty, Map.ACTOR)
    		if not tx or not ty or not target then return nil end
    		if not (target.player and target.game_ender) and not (self.player and self.game_ender) then return nil end
    		if target == self then return end
    
    		if target:attr("negative_status_effect_immune") or target:attr("status_effect_immune") then return nil end
    
    dg's avatar
    dg committed
    		if not (target and target:attr("sleep")) then
    
    			game.logPlayer(self, "Your target must be sleeping in order to enter it's dreamscape.")
    			return nil
    		end
    
    		if self:reactionToward(target) >= 0 then
    			game.logPlayer(self, "You can't cast this on friendly targets.")
    			return nil
    		end
    
    dg's avatar
    dg committed
    
    
    		game:onTickEnd(function()
    			if self:attr("dead") then return end
    			local oldzone = game.zone
    			local oldlevel = game.level
    
    dg's avatar
    dg committed
    
    
    			-- Clean up thought-forms
    			cancelThoughtForms(self)
    
    dg's avatar
    dg committed
    
    
    			-- Remove them before making the new elvel, this way party memebrs are not removed from the old
    			if oldlevel:hasEntity(self) then oldlevel:removeEntity(self) end
    			if oldlevel:hasEntity(target) then oldlevel:removeEntity(target) end
    
    dg's avatar
    dg committed
    
    
    			oldlevel.no_remove_entities = true
    			local zone = mod.class.Zone.new("dreamscape-talent")
    			local level = zone:getLevel(game, 1, 0)
    			oldlevel.no_remove_entities = nil
    
    dg's avatar
    dg committed
    
    
    			level:addEntity(self)
    			level:addEntity(target)
    
    			level.source_zone = oldzone
    			level.source_level = oldlevel
    			game.zone = zone
    			game.level = level
    			game.zone_name_s = nil
    
    dg's avatar
    dg committed
    
    
    			local x1, y1 = util.findFreeGrid(4, 6, 20, true, {[Map.ACTOR]=true})
    			if x1 then
    				self:move(x1, y1, true)
    
    dg's avatar
    dg committed
    				game.level.map:particleEmitter(x1, y1, 1, "generic_teleport", {rm=0, rM=0, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
    
    			end
    			local x2, y2 = util.findFreeGrid(8, 6, 20, true, {[Map.ACTOR]=true})
    			if x2 then
    				target:move(x2, y2, true)
    			end
    
    dg's avatar
    dg committed
    
    
    			target:setTarget(self)
    			target.dream_plane_trapper = self
    			target.dream_plane_on_die = target.on_die
    			target.on_die = function(self, ...)
    				self.dream_plane_trapper:removeEffect(self.EFF_DREAMSCAPE)
    				local args = {...}
    				game:onTickEnd(function()
    					if self.dream_plane_on_die then self:dream_plane_on_die(unpack(args)) end
    					self.on_die, self.dream_plane_on_die = self.dream_plane_on_die, nil
    				end)
    			end
    
    			self.dream_plane_on_die = self.on_die
    			self.on_die = function(self, ...)
    				self:removeEffect(self.EFF_DREAMSCAPE)
    				local args = {...}
    				game:onTickEnd(function()
    					if self.dream_plane_on_die then self:dream_plane_on_die(unpack(args)) end
    					self.on_die, self.dream_plane_on_die = self.dream_plane_on_die, nil
    				--	if not game.party:hasMember(self) then world:gainAchievement("FEARSCAPE", game:getPlayer(true)) end
    				end)
    			end
    
    			game.logPlayer(game.player, "#LIGHT_BLUE#You are taken to the Dreamscape!")
    
    
    			if game.party:hasMember(target) then game.player:learnLore("dreamscape-entry") end
    
    dg's avatar
    dg committed
    
    
    		local power = self:mindCrit(t.getPower(self, t))
    		self:setEffect(self.EFF_DREAMSCAPE, t.getDuration(self, t), {target=target, power=power, projections_killed=0, x=self.x, y=self.y, tx=target.x, ty=target.y})
    
    		game:playSoundNear(self, "talents/teleport")
    
    dg's avatar
    dg committed
    		return true
    	end,
    	info = function(self, t)
    
    		local duration = t.getDuration(self, t)
    		local power = t.getPower(self, t)
    
    		return([[Enter a sleeping target's dreams for %d turns.  While in the dreamscape you'll encounter the target's invulnerable sleeping form as well as dream projections that it will spawn every other turn to defend it's mind.
    		Projections inflict 50%% less damage then the original, unless the target has Lucid Dreamer active.
    		When the dreamscape ends the target's life will be reduced by 10%% and it will to be brainlocked for one turn for each projection destroyed.
    
    		In the dreamscape your damage will be improved by %d%%.
    		The damage bonus will improve with your mindpower.]]):format(duration, power)
    
    dg's avatar
    dg committed
    	end,