From 4f631b1d8e69e1ad1b743fc101441eb55d557b38 Mon Sep 17 00:00:00 2001 From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54> Date: Tue, 4 Dec 2012 21:19:30 +0000 Subject: [PATCH] Restless Night now deals damage over five turns instead of all at once Inner Demon health will be lower when used on higher ranked targets Sleep effects now can be resisted with confusion or sleep immunity, which ever is higher git-svn-id: http://svn.net-core.org/repos/t-engine4@5919 51575b47-30f0-44d4-a5cc-537603b46e54 --- .../default/engine/interface/ActorTalents.lua | 18 ++++++++-- .../engine/interface/ObjectActivable.lua | 11 +++--- game/modules/tome/class/Actor.lua | 6 ++-- game/modules/tome/class/FortressPC.lua | 4 +-- game/modules/tome/class/Object.lua | 21 ++++++----- game/modules/tome/class/Trap.lua | 4 +-- .../tome/data/birth/classes/wilder.lua | 2 +- game/modules/tome/data/chats/escort-quest.lua | 2 +- .../tome/data/talents/cunning/survival.lua | 35 +++++++++++------- .../tome/data/talents/psionic/nightmare.lua | 4 +-- .../tome/data/talents/psionic/slumber.lua | 9 +++-- .../tome/data/timed_effects/mental.lua | 36 +++++++++++++++---- 12 files changed, 105 insertions(+), 47 deletions(-) diff --git a/game/engines/default/engine/interface/ActorTalents.lua b/game/engines/default/engine/interface/ActorTalents.lua index bcd8344f67..daf2f6c756 100644 --- a/game/engines/default/engine/interface/ActorTalents.lua +++ b/game/engines/default/engine/interface/ActorTalents.lua @@ -339,8 +339,8 @@ function _M:unlearnTalent(t_id, nb) if t.on_unlearn then local p = nil - if self.talents_learn_vals[t.id] and self.talents_learn_vals[t.id][self.talents[t_id] + 1] then - p = self.talents_learn_vals[t.id][self.talents[t_id] + 1] + if self.talents_learn_vals[t.id] and self.talents_learn_vals[t.id][(self.talents[t_id] or 0) + 1] then + p = self.talents_learn_vals[t.id][(self.talents[t_id] or 0) + 1] if p.__tmpvals then for i = 1, #p.__tmpvals do self:removeTemporaryValue(p.__tmpvals[i][1], p.__tmpvals[i][2]) @@ -522,10 +522,24 @@ function _M:getTalentTypeMastery(tt) return (self.talents_types_mastery[tt] or 0) + 1 end +--- Return talent type mastery for this talent +function _M:getTalentMastery(t) + local tt = t.type[1] + return self:getTalentTypeMastery(tt) +end + --- Sets talent type mastery function _M:setTalentTypeMastery(tt, v) -- "v - 1" because a mastery is expressed as x + 1, not x, so that 0 is the default value (thus getting 1) self.talents_types_mastery[tt] = v - 1 + + for i, t in pairs(self.talents_types_def[tt].talents) do + if t.auto_relearn_passive then + local lvl = self:getTalentLevelRaw(t) + self:unlearnTalent(t.id, lvl) + self:learnTalent(t.id, true, lvl) + end + end end --- Return talent definition from id diff --git a/game/engines/default/engine/interface/ObjectActivable.lua b/game/engines/default/engine/interface/ObjectActivable.lua index ddc961cccb..c86782861b 100644 --- a/game/engines/default/engine/interface/ObjectActivable.lua +++ b/game/engines/default/engine/interface/ObjectActivable.lua @@ -65,15 +65,18 @@ function _M:useObject(who, ...) -- Make sure the object is registered with the game, if need be if not game:hasEntity(self) then game:addEntity(self) end + local reduce = 100 - util.bound(who:attr("use_object_cooldown_reduce") or 0, 0, 100) + local usepower = function(power) return math.ceil(power * reduce / 100) end + if self.use_power then if (self.talent_cooldown and not who:isTalentCoolingDown(self.talent_cooldown)) or (not self.talent_cooldown and self.power >= self.use_power.power) then local ret = self.use_power.use(self, who, ...) or {} local no_power = not ret.used or ret.no_power if not no_power then if self.talent_cooldown then - who.talents_cd[self.talent_cooldown] = self.use_power.power + who.talents_cd[self.talent_cooldown] = usepower(self.use_power.power) else - self.power = self.power - self.use_power.power + self.power = self.power - usepower(self.use_power.power) end end return ret @@ -97,9 +100,9 @@ function _M:useObject(who, ...) if ret then if self.talent_cooldown then - who.talents_cd[self.talent_cooldown] = self.use_talent.power + who.talents_cd[self.talent_cooldown] = usepower(self.use_talent.power) else - self.power = self.power - self.use_talent.power + self.power = self.power - usepower(self.use_talent.power) end end diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 7b793709d7..5f159938e0 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -972,8 +972,8 @@ function _M:move(x, y, force) self.did_energy = nil -- Try to detect traps - if self:knowTalent(self.T_TRAP_HANDLING) then - local power = self:getTalentLevel(self.T_TRAP_HANDLING) * self:getCun(25, true) + if self:knowTalent(self.T_HEIGHTENED_SENSES) then + local power = self:getTalentLevel(self.T_HEIGHTENED_SENSES) * self:getCun(25, true) local grids = core.fov.circle_grids(self.x, self.y, 1, true) for x, yy in pairs(grids) do for y, _ in pairs(yy) do local trap = game.level.map(x, y, Map.TRAP) @@ -4200,7 +4200,7 @@ function _M:canBe(what) if what == "disarm" and rng.percent(100 * (self:attr("disarm_immune") or 0)) then return false end if what == "pin" and rng.percent(100 * (self:attr("pin_immune") or 0)) and not self:attr("levitation") then return false end if what == "stun" and rng.percent(100 * (self:attr("stun_immune") or 0)) then return false end - if what == "sleep" and rng.percent(100 * (self:attr("sleep_immune") or 0)) then return false end + if what == "sleep" and rng.percent(100 * math.max((self:attr("sleep_immune") or 0), (self:attr("confusion_immune") or 0))) then return false end if what == "fear" and rng.percent(100 * (self:attr("fear_immune") or 0)) then return false end if what == "knockback" and (rng.percent(100 * (self:attr("knockback_immune") or 0)) or self:attr("never_move")) then return false end if what == "stone" and rng.percent(100 * (self:attr("stone_immune") or 0)) then return false end diff --git a/game/modules/tome/class/FortressPC.lua b/game/modules/tome/class/FortressPC.lua index f9f3d1332d..2cf7a035b8 100644 --- a/game/modules/tome/class/FortressPC.lua +++ b/game/modules/tome/class/FortressPC.lua @@ -155,8 +155,8 @@ function _M:moveModActor(x, y, force) self.did_energy = nil -- Try to detect traps - if self:knowTalent(self.T_TRAP_HANDLING) then - local power = self:getTalentLevel(self.T_TRAP_HANDLING) * self:getCun(25, true) + if self:knowTalent(self.T_HEIGHTENED_SENSES) then + local power = self:getTalentLevel(self.T_HEIGHTENED_SENSES) * self:getCun(25, true) local grids = core.fov.circle_grids(self.x, self.y, 1, true) for x, yy in pairs(grids) do for y, _ in pairs(yy) do local trap = game.level.map(x, y, Map.TRAP) diff --git a/game/modules/tome/class/Object.lua b/game/modules/tome/class/Object.lua index 1d9ff7d1bf..3fdd0cbed6 100644 --- a/game/modules/tome/class/Object.lua +++ b/game/modules/tome/class/Object.lua @@ -174,15 +174,16 @@ function _M:descAttribute(attr) elseif attr == "CHARM" then return (" [power %d]"):format(self:getCharmPower()) elseif attr == "CHARGES" then + local reduce = 100 - util.bound(game.player:attr("use_object_cooldown_reduce") or 0, 0, 100) if self.talent_cooldown and (self.use_power or self.use_talent) then local cd = game.player.talents_cd[self.talent_cooldown] if cd and cd > 0 then - return " ("..cd.."/"..(self.use_power or self.use_talent).power.." cooldown)" + return " ("..cd.."/"..(math.ceil((self.use_power or self.use_talent).power * reduce / 100)).." cooldown)" else - return " ("..(self.use_power or self.use_talent).power.." cooldown)" + return " ("..(math.ceil((self.use_power or self.use_talent).power * reduce / 100)).." cooldown)" end elseif self.use_power or self.use_talent then - return (" (%d/%d)"):format(math.floor(self.power / (self.use_power or self.use_talent).power), math.floor(self.max_power / (self.use_power or self.use_talent).power)) + return (" (%d/%d)"):format(math.floor(self.power / (math.ceil((self.use_power or self.use_talent).power * reduce / 100))), math.floor(self.max_power / (math.ceil((self.use_power or self.use_talent).power * reduce / 100)))) else return "" end @@ -1192,23 +1193,25 @@ end function _M:getUseDesc() local ret = tstring{} + local reduce = 100 - util.bound(game.player:attr("use_object_cooldown_reduce") or 0, 0, 100) + local usepower = function(power) return math.ceil(power * reduce / 100) end if self.use_power then if self.show_charges then - ret = tstring{{"color","YELLOW"}, ("It can be used to %s, with %d charges out of %d."):format(util.getval(self.use_power.name, self), math.floor(self.power / self.use_power.power), math.floor(self.max_power / self.use_power.power)), {"color","LAST"}} + ret = tstring{{"color","YELLOW"}, ("It can be used to %s, with %d charges out of %d."):format(util.getval(self.use_power.name, self), math.floor(self.power / usepower(self.use_power.power)), math.floor(self.max_power / usepower(self.use_power.power))), {"color","LAST"}} elseif self.talent_cooldown then - ret = tstring{{"color","YELLOW"}, ("It can be used to %s, placing all other charms into a %d cooldown."):format(util.getval(self.use_power.name, self):format(self:getCharmPower()), self.use_power.power), {"color","LAST"}} + ret = tstring{{"color","YELLOW"}, ("It can be used to %s, placing all other charms into a %d cooldown."):format(util.getval(self.use_power.name, self):format(self:getCharmPower()), usepower(self.use_power.power)), {"color","LAST"}} else - ret = tstring{{"color","YELLOW"}, ("It can be used to %s, costing %d power out of %d/%d."):format(util.getval(self.use_power.name, self), self.use_power.power, self.power, self.max_power), {"color","LAST"}} + ret = tstring{{"color","YELLOW"}, ("It can be used to %s, costing %d power out of %d/%d."):format(util.getval(self.use_power.name, self), usepower(self.use_power.power), self.power, self.max_power), {"color","LAST"}} end elseif self.use_simple then ret = tstring{{"color","YELLOW"}, ("It can be used to %s."):format(self.use_simple.name), {"color","LAST"}} elseif self.use_talent then local t = game.player:getTalentFromId(self.use_talent.id) - local desc = game.player:getTalentFullDescription(t, nil, {force_level=self.use_talent.level, ignore_cd=true, ignore_ressources=true, ignore_use_time=true, ignore_mode=true, custom=self.use_talent.power and tstring{{"color",0x6f,0xff,0x83}, "Power cost: ", {"color",0x7f,0xff,0xd4},("%d out of %d/%d."):format(self.use_talent.power, self.power, self.max_power)}}) + local desc = game.player:getTalentFullDescription(t, nil, {force_level=self.use_talent.level, ignore_cd=true, ignore_ressources=true, ignore_use_time=true, ignore_mode=true, custom=self.use_talent.power and tstring{{"color",0x6f,0xff,0x83}, "Power cost: ", {"color",0x7f,0xff,0xd4},("%d out of %d/%d."):format(usepower(self.use_talent.power), self.power, self.max_power)}}) if self.talent_cooldown then - ret = tstring{{"color","YELLOW"}, "It can be used to activate talent ", t.name,", placing all other charms into a ", tostring(math.floor(self.use_talent.power)) ," cooldown :", {"color","LAST"}, true} + ret = tstring{{"color","YELLOW"}, "It can be used to activate talent ", t.name,", placing all other charms into a ", tostring(math.floor(usepower(self.use_talent.power))) ," cooldown :", {"color","LAST"}, true} else - ret = tstring{{"color","YELLOW"}, "It can be used to activate talent ", t.name," (costing ", tostring(math.floor(self.use_talent.power)), " power out of ", tostring(math.floor(self.power)), "/", tostring(math.floor(self.max_power)), ") :", {"color","LAST"}, true} + ret = tstring{{"color","YELLOW"}, "It can be used to activate talent ", t.name," (costing ", tostring(math.floor(usepower(self.use_talent.power))), " power out of ", tostring(math.floor(self.power)), "/", tostring(math.floor(self.max_power)), ") :", {"color","LAST"}, true} end ret:merge(desc) end diff --git a/game/modules/tome/class/Trap.lua b/game/modules/tome/class/Trap.lua index 88e101bf08..06bb26186c 100644 --- a/game/modules/tome/class/Trap.lua +++ b/game/modules/tome/class/Trap.lua @@ -68,8 +68,8 @@ function _M:canDisarm(x, y, who) if not engine.Trap.canDisarm(self, x, y, who) then return false end -- do we know how to disarm? - if (who:getTalentLevel(who.T_TRAP_HANDLING) >= 3) or who:attr("can_disarm") then - local power = who:getTalentLevel(who.T_TRAP_HANDLING) * who:getCun(25, true) + (who:attr("disarm_bonus") or 0) + if (who:getTalentLevel(who.T_HEIGHTENED_SENSES) >= 3) or who:attr("can_disarm") then + local power = who:getTalentLevel(who.T_HEIGHTENED_SENSES) * who:getCun(25, true) + (who:attr("disarm_bonus") or 0) if who:checkHit(power, self.disarm_power) and (not self.faction or who:reactionToward(self) < 0) then return true end diff --git a/game/modules/tome/data/birth/classes/wilder.lua b/game/modules/tome/data/birth/classes/wilder.lua index 4730169abc..2ea74f28c3 100644 --- a/game/modules/tome/data/birth/classes/wilder.lua +++ b/game/modules/tome/data/birth/classes/wilder.lua @@ -88,7 +88,7 @@ newBirthDescriptor{ [ActorTalents.T_WAR_HOUND] = 1, [ActorTalents.T_RITCH_FLAMESPITTER] = 1, [ActorTalents.T_MEDITATION] = 1, - [ActorTalents.T_TRAP_HANDLING] = 1, + [ActorTalents.T_HEIGHTENED_SENSES] = 1, }, copy = { max_life = 90, diff --git a/game/modules/tome/data/chats/escort-quest.lua b/game/modules/tome/data/chats/escort-quest.lua index 2f12a2403a..00cab4fc0e 100644 --- a/game/modules/tome/data/chats/escort-quest.lua +++ b/game/modules/tome/data/chats/escort-quest.lua @@ -98,7 +98,7 @@ local reward_types = { }, talents = { [Talents.T_HEIGHTENED_SENSES] = 1, - [Talents.T_TRAP_HANDLING] = 1, + [Talents.T_CHARM_MASTERY] = 1, [Talents.T_PIERCING_SIGHT] = 1, }, stats = { diff --git a/game/modules/tome/data/talents/cunning/survival.lua b/game/modules/tome/data/talents/cunning/survival.lua index 02f270074a..c495f7fe01 100644 --- a/game/modules/tome/data/talents/cunning/survival.lua +++ b/game/modules/tome/data/talents/cunning/survival.lua @@ -18,38 +18,47 @@ -- darkgod@te4.org newTalent{ - name = "Trap Handling", + name = "Heightened Senses", type = {"cunning/survival", 1}, require = cuns_req1, mode = "passive", points = 5, + on_learn = function(self, t) + self.heightened_senses = 4 + math.ceil(self:getTalentLevel(t)) + end, + on_unlearn = function(self, t) + if self:knowTalent(t) then + self.heightened_senses = 4 + math.ceil(self:getTalentLevel(t)) + else + self.heightened_senses = nil + end + end, info = function(self, t) - return ([[Your attention to detail allows you to detect traps around you (%d detection 'power'). + return ([[You notice the small things others do not notice, allowing you to "see" creatures in a %d radius even outside of light radius. + This is not telepathy though, and is still limited to line of sight. + Also, your attention to detail allows you to detect traps around you (%d detection 'power'). At level 3 you learn to disarm known traps (%d disarm 'power').]]): - format(self:getTalentLevel(t) * self:getCun(25, true), self:getTalentLevel(t) * self:getCun(25, true)) + format(4 + math.ceil(self:getTalentLevel(t)), self:getTalentLevel(t) * self:getCun(25, true), self:getTalentLevel(t) * self:getCun(25, true)) end, } newTalent{ - name = "Heightened Senses", + name = "Charm Mastery", type = {"cunning/survival", 2}, require = cuns_req2, mode = "passive", points = 5, + auto_relearn_passive = true, on_learn = function(self, t) - self.heightened_senses = 4 + math.ceil(self:getTalentLevel(t)) + local ret = {} + self:talentTemporaryValue(ret, "use_object_cooldown_reduce", math.floor(self:getTalentMastery(t) * 8)) + return ret end, on_unlearn = function(self, t) - if self:knowTalent(t) then - self.heightened_senses = 4 + math.ceil(self:getTalentLevel(t)) - else - self.heightened_senses = nil - end end, info = function(self, t) - return ([[You notice the small things others do not notice, allowing you to "see" creatures in a %d radius even outside of light radius. - This is not telepathy though, and is still limited to line of sight.]]): - format(4 + math.ceil(self:getTalentLevel(t))) + return ([[Your cunning allows you to use charms (wands, totems and torques) more efficiently, reducing their cooldowns by %d%%.]]): + format(self:getTalentLevelRaw(t) * math.floor(self:getTalentMastery(t) * 8)) end, } diff --git a/game/modules/tome/data/talents/psionic/nightmare.lua b/game/modules/tome/data/talents/psionic/nightmare.lua index bf71dc1cac..397a7595e0 100644 --- a/game/modules/tome/data/talents/psionic/nightmare.lua +++ b/game/modules/tome/data/talents/psionic/nightmare.lua @@ -130,7 +130,7 @@ newTalent{ m.exp_worth = 0 m.energy.value = 0 m.player = nil - m.max_life = m.max_life / 4 + m.max_life = m.max_life / 2 / m.rank m.life = util.bound(m.life, 0, m.max_life) m.inc_damage.all = (m.inc_damage.all or 0) - 50 m.forceLevelup = function() end @@ -212,7 +212,7 @@ newTalent{ local chance = t.getChance(self, t) return ([[Brings the target's inner demons to the surface. Each turn for %d turns there's a %d%% chance that the a demon will surface, requiring the target to make a mental save to keep it from manifesting. If the target is sleeping the chance will be doubled and fear immunity will be ignored. Otherwise if the summoning is resisted the effect will end early. - The summon chance will scale with your mindpower.]]):format(duration, chance) + The summon chance will scale with your mindpower and the demon's life will scale with the target's rank.]]):format(duration, chance) end, } diff --git a/game/modules/tome/data/talents/psionic/slumber.lua b/game/modules/tome/data/talents/psionic/slumber.lua index 088699ab5b..ac2a347c9c 100644 --- a/game/modules/tome/data/talents/psionic/slumber.lua +++ b/game/modules/tome/data/talents/psionic/slumber.lua @@ -84,10 +84,15 @@ newTalent{ points = 5, require = psi_wil_req2, mode = "passive", - getDamage = function(self, t) return self:combatTalentMindDamage(t, 20, 200) end, + getDamage = function(self, t) return self:combatTalentMindDamage(t, 5, 40) end, + doRestlessNight = function (self, target, damage) + local dam = self:mindCrit(damage) + target:setEffect(target.EFF_RESTLESS_NIGHT, 5, {power=dam, src=self, no_ct_effect=true}) + game.level.map:particleEmitter(target.x, target.y, 1, "generic_discharge", {rm=180, rM=200, gm=100, gM=120, bm=30, bM=50, am=70, aM=180}) + end, info = function(self, t) local damage = t.getDamage(self, t) - return([[Targets you have slept now take %0.2f mind damage upon waking. + return([[Targets you have slept now take %0.2f mind damage each turn for five turns upon waking. The damage will scale with your mindpower.]]):format(damDesc(self, DamageType.MIND, (damage))) end, } diff --git a/game/modules/tome/data/timed_effects/mental.lua b/game/modules/tome/data/timed_effects/mental.lua index 20e73d53e8..7e0bb11962 100644 --- a/game/modules/tome/data/timed_effects/mental.lua +++ b/game/modules/tome/data/timed_effects/mental.lua @@ -2499,8 +2499,8 @@ newEffect{ deactivate = function(self, eff) self:removeTemporaryValue("sleep", eff.sid) if not self:attr("sleep") and not self.dead and game.level:hasEntity(self) and eff.waking > 0 then - DamageType:get(DamageType.MIND).projector(eff.src or self, self.x, self.y, DamageType.MIND, eff.src:mindCrit(eff.waking)) - game.level.map:particleEmitter(self.x, self.y, 1, "generic_discharge", {rm=180, rM=200, gm=100, gM=120, bm=30, bM=50, am=70, aM=180}) + local t = eff.src:getTalentFromId(self.T_RESTLESS_NIGHT) + t.doRestlessNight(eff.src, self, eff.waking) end if eff.particle then self:removeParticles(eff.particle) @@ -2549,8 +2549,8 @@ newEffect{ deactivate = function(self, eff) self:removeTemporaryValue("sleep", eff.sid) if not self:attr("sleep") and not self.dead and game.level:hasEntity(self) and eff.waking > 0 then - DamageType:get(DamageType.MIND).projector(eff.src or self, self.x, self.y, DamageType.MIND, eff.src:mindCrit(eff.waking)) - game.level.map:particleEmitter(self.x, self.y, 1, "generic_discharge", {rm=180, rM=200, gm=100, gM=120, bm=30, bM=50, am=70, aM=180}) + local t = eff.src:getTalentFromId(self.T_RESTLESS_NIGHT) + t.doRestlessNight(eff.src, self, eff.waking) end if eff.particle then self:removeParticles(eff.particle) @@ -2608,8 +2608,8 @@ newEffect{ deactivate = function(self, eff) self:removeTemporaryValue("sleep", eff.sid) if not self:attr("sleep") and not self.dead and game.level:hasEntity(self) and eff.waking > 0 then - DamageType:get(DamageType.MIND).projector(eff.src or self, self.x, self.y, DamageType.MIND, eff.src:mindCrit(eff.waking)) - game.level.map:particleEmitter(self.x, self.y, 1, "generic_discharge", {rm=180, rM=200, gm=100, gM=120, bm=30, bM=50, am=70, aM=180}) + local t = eff.src:getTalentFromId(self.T_RESTLESS_NIGHT) + t.doRestlessNight(eff.src, self, eff.waking) end if eff.particle then self:removeParticles(eff.particle) @@ -2617,6 +2617,30 @@ newEffect{ end, } +newEffect{ + name = "RESTLESS_NIGHT", image = "talents/restless_night.png", + desc = "Restless Night", + long_desc = function(self, eff) return ("Fatigue from poor sleep, dealing %0.2f mind damage per turn."):format(eff.power) end, + type = "mental", + subtype = { psionic=true}, + status = "detrimental", + parameters = { power=1 }, + on_gain = function(self, err) return "#Target# had a restless night.", "+Restless Night" end, + on_lose = function(self, err) return "#Target# has recovered from poor sleep.", "-Restless Night" end, + on_merge = function(self, old_eff, new_eff) + -- Merge the flames! + local olddam = old_eff.power * old_eff.dur + local newdam = new_eff.power * new_eff.dur + local dur = math.ceil((old_eff.dur + new_eff.dur) / 2) + old_eff.dur = dur + old_eff.power = (olddam + newdam) / dur + return old_eff + end, + on_timeout = function(self, eff) + DamageType:get(DamageType.MIND).projector(eff.src or self, self.x, self.y, DamageType.MIND, eff.power) + end, +} + newEffect{ name = "INSOMNIA", image = "effects/insomnia.png", desc = "Insomnia", -- GitLab