From 0e15bf654bd477f216bcac5923dd0682eb9527ba Mon Sep 17 00:00:00 2001 From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54> Date: Mon, 25 Apr 2011 01:22:00 +0000 Subject: [PATCH] Overhauled Frozen effect: You now get to act every turns but can not teleport, heal or move. The ice now has HP which can be damaged to make it go away. All your attacks can only damage the ice (not creatures) and creature attacks damage you for half their value and the ice for half git-svn-id: http://svn.net-core.org/repos/t-engine4@3271 51575b47-30f0-44d4-a5cc-537603b46e54 --- .../default/engine/interface/ActorProject.lua | 28 ++++++++++-------- game/modules/tome/class/Actor.lua | 29 ++++++++++++++++++- game/modules/tome/class/Game.lua | 5 ++-- game/modules/tome/class/NPC.lua | 8 +++++ game/modules/tome/class/Player.lua | 6 +++- game/modules/tome/class/interface/Combat.lua | 4 +-- game/modules/tome/data/damage_types.lua | 20 +++++++++++-- .../tome/data/talents/spells/water.lua | 5 ++-- game/modules/tome/data/timed_effects.lua | 19 ++++++++++-- 9 files changed, 98 insertions(+), 26 deletions(-) diff --git a/game/engines/default/engine/interface/ActorProject.lua b/game/engines/default/engine/interface/ActorProject.lua index 28cab2af18..63cb1adcbd 100644 --- a/game/engines/default/engine/interface/ActorProject.lua +++ b/game/engines/default/engine/interface/ActorProject.lua @@ -126,6 +126,8 @@ function _M:project(t, x, y, damtype, dam, particles) return end + self:check("on_project_grids", grids) + -- Now project on each grid, one type local tmp = {} local stop = false @@ -292,11 +294,11 @@ function _M:projectDoStop(typ, tg, damtype, dam, particles, lx, ly, tmp, rx, ry) if typ.ball and typ.ball > 0 then core.fov.calc_circle( - rx, - ry, - game.level.map.w, - game.level.map.h, - typ.ball, + rx, + ry, + game.level.map.w, + game.level.map.h, + typ.ball, function(_, px, py) if typ.block_radius and typ:block_radius(px, py) then return true end end, @@ -310,13 +312,13 @@ function _M:projectDoStop(typ, tg, damtype, dam, particles, lx, ly, tmp, rx, ry) local initial_dir = lx and util.getDir(lx, ly, x, y) or 5 local dir_angle = math.deg(math.atan2(ly - typ.source_actor.y, lx - typ.source_actor.x)) core.fov.calc_beam_any_angle( - rx, - ry, - game.level.map.w, - game.level.map.h, - typ.cone, - dir_angle, - typ.cone_angle, + rx, + ry, + game.level.map.w, + game.level.map.h, + typ.cone, + dir_angle, + typ.cone_angle, function(_, px, py) if typ.block_radius and typ:block_radius(px, py) then return true end end, @@ -331,6 +333,8 @@ function _M:projectDoStop(typ, tg, damtype, dam, particles, lx, ly, tmp, rx, ry) addGrid(lx, ly) end + self:check("on_project_grids", grids) + for px, ys in pairs(grids) do for py, _ in pairs(ys) do if self:projectDoAct(typ, tg, damtype, dam, particles, px, py, tmp) then break end diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 28c6effee3..0a5f5b48e8 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -354,7 +354,6 @@ function _M:act() game.logSeen(self, "%s temporarily fights the stun.", self.name:capitalize()) end end - if self:attr("encased_in_ice") then self.energy.value = 0 end if self:attr("stoned") then self.energy.value = 0 end if self:attr("dazed") then self.energy.value = 0 end if self:attr("time_stun") then self.energy.value = 0 end @@ -580,6 +579,7 @@ end --- Blink through walls function _M:probabilityTravel(x, y, dist) if game.zone.wilderness then return true end + if self:attr("encased_in_ice") then return end local dirx, diry = x - self.x, y - self.y local tx, ty = x, y @@ -605,6 +605,7 @@ end -- @param min_dist the minimum radius of of the effect, will never teleport closer. Defaults to 0 if not set -- @return true if the teleport worked function _M:teleportRandom(x, y, dist, min_dist) + if self:attr("encased_in_ice") then return end if game.level.data.no_teleport_south and y + dist > self.y then y = self.y - dist end @@ -671,6 +672,8 @@ end --- What is our reaction toward the target -- This can modify faction reaction using specific actor to actor reactions function _M:reactionToward(target, no_reflection) + if target == self and self:attr("encased_in_ice") then return -100 end + local v = engine.Actor.reactionToward(self, target) if self.reaction_actor and self.reaction_actor[target.unique or target.name] then v = v + self.reaction_actor[target.unique or target.name] end @@ -789,6 +792,10 @@ function _M:tooltip(x, y, seen_by) ts:add({"color", 0, 255, 255}, ("Level: %d"):format(self.level), {"color", "WHITE"}, true) ts:add(("Exp: %d/%d"):format(self.exp, self:getExpChart(self.level+1) or "---"), true) ts:add({"color", 255, 0, 0}, ("HP: %d (%d%%)"):format(self.life, self.life * 100 / self.max_life), {"color", "WHITE"}, true) + if self:attr("encased_in_ice") then + local eff = self:hasEffect(self.EFF_FROZEN) + ts:add({"color", 0, 255, 128}, ("Iceblock: %d"):format(eff.hp), {"color", "WHITE"}, true) + end ts:add(("Stats: %d / %d / %d / %d / %d / %d"):format(self:getStr(), self:getDex(), self:getCon(), self:getMag(), self:getWil(), self:getCun()), true) ts:add("Resists: ", table.concat(resists, ','), true) ts:add("Armour/Defense: ", tostring(math.floor(self:combatArmor())), ' / ', tostring(math.floor(self:combatDefense())), true) @@ -828,6 +835,9 @@ function _M:onHeal(value, src) if self:hasEffect(self.EFF_UNSTOPPABLE) then return 0 end + if self:attr("encased_in_ice") then + return 0 + end value = value * util.bound((self.healing_factor or 1), 0, 2.5) print("[HEALING]", self.uid, self.name, "for", value) return value @@ -1054,6 +1064,14 @@ function _M:onTakeHit(value, src) game.logSeen(self, "%s shatters into pieces!", self.name:capitalize()) end + -- Frozen: absorb some damage into the iceblock + if self:attr("encased_in_ice") then + local eff = self:hasEffect(self.EFF_FROZEN) + value = value / 2 + eff.hp = eff.hp - value + if eff.hp < 0 then self:removeEffect(self.EFF_FROZEN) end + end + -- Adds hate if self:knowTalent(self.T_HATE_POOL) then local hateGain = 0 @@ -2459,6 +2477,15 @@ function _M:on_projectile_target(x, y, p) end end +--- Called when we have acquired grids +function _M:on_project_grids(grids) + if self:attr("encased_in_ice") then + -- Only hit yourself + while next(grids) do grids[next(grids)] = nil end + grids[self.x] = {[self.y]=true} + end +end + --- Call when added to a level -- Used to make escorts and such function _M:addedToLevel(level, x, y) diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 05b488cb19..1d22892605 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -922,8 +922,9 @@ function _M:setupCommands() end end, [{"_g","ctrl"}] = function() if config.settings.cheat then -- self.state:debugRandomZone() - local m = game.zone:makeEntity(game.level, "actor", {random_boss=true}, nil, true) - if m then game.zone:addEntity(game.level, m, "actor", game.player.x, game.player.y + 1) end +-- local m = game.zone:makeEntity(game.level, "actor", {random_boss=true}, nil, true) +-- if m then game.zone:addEntity(game.level, m, "actor", game.player.x, game.player.y + 1) end + self.player:setEffect(self.player.EFF_FROZEN, 10, {}) end end, } diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua index f19e498033..b938276185 100644 --- a/game/modules/tome/class/NPC.lua +++ b/game/modules/tome/class/NPC.lua @@ -227,6 +227,14 @@ function _M:tooltip(x, y, seen_by) return str end +function _M:getTarget(typ) + if self:attr("encased_in_ice") then + return self.x, self.y, self + else + return mod.class.Actor.getTarget(self, typ) + end +end + --- Make emotes appear in the log too function _M:setEmote(e) game.logSeen(self, "%s says: '%s'", self.name:capitalize(), e.text) diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index 4258c89493..4cd5b4b703 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -463,7 +463,11 @@ end --- Tries to get a target from the user function _M:getTarget(typ) - return game:targetGetForPlayer(typ) + if self:attr("encased_in_ice") then + return self.x, self.y, self + else + return game:targetGetForPlayer(typ) + end end --- Sets the current target diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua index 5864630dae..c6cc5114f4 100644 --- a/game/modules/tome/class/interface/Combat.lua +++ b/game/modules/tome/class/interface/Combat.lua @@ -493,12 +493,12 @@ function _M:combatDefense() local t = self:getTalentFromId(self.T_STEADY_MIND) add = add + t.getDefense(self, t) end - return self.combat_def + (self:getDex() - 10) * 0.35 + add + (self:getLck() - 50) * 0.4 + return math.max(0, self.combat_def + (self:getDex() - 10) * 0.35 + add + (self:getLck() - 50) * 0.4) end --- Gets the defense ranged function _M:combatDefenseRanged() - return self:combatDefense() + (self.combat_def_ranged or 0) + return math.max(0, self:combatDefense() + (self.combat_def_ranged or 0)) end --- Gets the armor diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua index 183f504cf3..5f683445d8 100644 --- a/game/modules/tome/data/damage_types.lua +++ b/game/modules/tome/data/damage_types.lua @@ -44,6 +44,20 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) dam = dam + (dam * inc / 100) end + -- Blast the iceblock + if src.attr and src:attr("encased_in_ice") then + local eff = src:hasEffect(src.EFF_FROZEN) + eff.hp = eff.hp - dam + local srcname = src.x and src.y and game.level.map.seens(src.x, src.y) and src.name:capitalize() or "Something" + if eff.hp < 0 then + game.logSeen(src, "%s forces the iceblock to shatter.", src.name:capitalize()) + src:removeEffect(src.EFF_FROZEN) + else + game:delayedLogDamage(src, {name="Iceblock", x=src.x, y=src.y}, dam, ("%s%d %s#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", math.ceil(dam), DamageType:get(type).name)) + end + return 0 + end + -- dark vision increases damage done in the dark if src.knowTalent and src:knowTalent(src.T_DARK_VISION) then local t = src:getTalentFromId(src.T_DARK_VISION) @@ -461,7 +475,7 @@ newDamageType{ projector = function(src, x, y, type, dam) local realdam = DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam) if rng.percent(25) then - DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, 2) + DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, {dur=2, hp=70+dam*1.5}) end return realdam end, @@ -490,7 +504,7 @@ newDamageType{ -- Freeze it, if we pass the test local sx, sy = game.level.map:getTileToScreen(x, y) if target:checkHit(src:combatSpellpower(), target:combatSpellResist(), 0, 95, 15) and target:canBe("stun") then - target:setEffect(target.EFF_FROZEN, dam, {src=src}) + target:setEffect(target.EFF_FROZEN, dam.dur, {hp=dam.hp * 1.5}) game.flyers:add(sx, sy, 30, (rng.range(0,2)-1) * 0.5, -3, "Frozen!", {0,255,155}) else @@ -1228,7 +1242,7 @@ newDamageType{ -- Freeze it, if we pass the test local sx, sy = game.level.map:getTileToScreen(x, y) if target:checkHit(src:combatMindpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("stun") then - target:setEffect(target.EFF_FROZEN, dam, {src=src}) + target:setEffect(target.EFF_FROZEN, dam, {hp=70 + src:combatMindpower() * 10}) else game.logSeen(target, "%s resists!", target.name:capitalize()) end diff --git a/game/modules/tome/data/talents/spells/water.lua b/game/modules/tome/data/talents/spells/water.lua index 51086a3c56..6b5fdd7fd1 100644 --- a/game/modules/tome/data/talents/spells/water.lua +++ b/game/modules/tome/data/talents/spells/water.lua @@ -79,8 +79,9 @@ newTalent{ local tg = {type="hit", range=self:getTalentRange(t), talent=t} local x, y = self:getTarget(tg) if not x or not y then return nil end - self:project(tg, x, y, DamageType.COLD, self:spellCrit(t.getDamage(self, t)), {type="freeze"}) - self:project(tg, x, y, DamageType.FREEZE, 3) + local dam = self:spellCrit(t.getDamage(self, t)) + self:project(tg, x, y, DamageType.COLD, dam, {type="freeze"}) + self:project(tg, x, y, DamageType.FREEZE, {dur=3, hp=70 + dam * 1.5}) game:playSoundNear(self, "talents/ice") return true end, diff --git a/game/modules/tome/data/timed_effects.lua b/game/modules/tome/data/timed_effects.lua index c0e8a73420..723a1e3f7f 100644 --- a/game/modules/tome/data/timed_effects.lua +++ b/game/modules/tome/data/timed_effects.lua @@ -21,6 +21,8 @@ local Stats = require "engine.interface.ActorStats" local Particles = require "engine.Particles" local Entity = require "engine.Entity" local Chat = require "engine.Chat" +local Map = require "engine.Map" +local Level = require "engine.Level" newEffect{ name = "INFUSION_COOLDOWN", @@ -258,7 +260,7 @@ newEffect{ newEffect{ name = "FROZEN", desc = "Frozen", - long_desc = function(self, eff) return "The target is encased in ice, completely unable to act. The ice increases all your resistances by 20%." end, + long_desc = function(self, eff) return ("The target is encased in ice. All damage done to you will be split in half, a part absorbed by the ice. Your defense is nullified while in the ice and you may only attack the ice. %d HP on the iceblock remaining."):format(eff.hp) end, type = "magical", status = "detrimental", parameters = {}, @@ -279,21 +281,32 @@ newEffect{ if self._mo then self._mo:invalidate() self._mo = nil end game.level.map:updateMap(self.x, self.y) + eff.hp = eff.hp or 100 eff.tmpid = self:addTemporaryValue("encased_in_ice", 1) + eff.moveid = self:addTemporaryValue("never_move", 1) eff.frozid = self:addTemporaryValue("frozen", 1) + eff.defid = self:addTemporaryValue("combat_def", -1000) + eff.rdefid = self:addTemporaryValue("combat_def_ranged", -1000) eff.dur = self:updateEffectDuration(eff.dur, "freeze") - eff.resistsid = self:addTemporaryValue("resists", {all=20}) + + self:setTarget(self) + end, + on_timeout = function(self, eff) + self:setTarget(self) end, deactivate = function(self, eff) self:removeTemporaryValue("encased_in_ice", eff.tmpid) + self:removeTemporaryValue("never_move", eff.moveid) self:removeTemporaryValue("frozen", eff.frozid) - self:removeTemporaryValue("resists", eff.resistsid) + self:removeTemporaryValue("combat_def", eff.defid) + self:removeTemporaryValue("combat_def_ranged", eff.rdefid) self.color_r = eff.old_r self.color_g = eff.old_g self.color_b = eff.old_b if eff.added_display then self.add_displays = nil end if self._mo then self._mo:invalidate() self._mo = nil end game.level.map:updateMap(self.x, self.y) + self:setTarget(nil) end, } -- GitLab