Forked from
tome / Tales of MajEyal
738 commits behind the upstream repository.
-
Otowa Kotori authoredOtowa Kotori authored
assassination.lua 8.35 KiB
-- ToME - Tales of Maj'Eyal
-- Copyright (C) 2009 - 2019 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
local DamageType = require "engine.DamageType"
local Object = require "engine.Object"
local Map = require "engine.Map"
newTalent{
name = "Coup de Grace",
type = {"technique/assassination", 1},
points = 5,
random_ego = "attack",
cooldown = 8,
stamina = 24,
require = techs_dex_req_high1,
getDamage = function (self, t) return self:combatTalentWeaponDamage(t, 1.0, 1.5) end,
getPercent = function(self, t) return self:combatTalentLimit(t, 0.3, 0.1, 0.25) end,
target = function(self, t) return {type="hit", range=self:getTalentRange(t)} end,
range = 1,
requires_target = true,
tactical = { ATTACK = { weapon = 2 } },
on_pre_use = function(self, t, silent) if not self:hasDualWeapon() then if not silent then game.logPlayer(self, "You require two weapons to use this talent.") end return false end return true end,
action = function(self, t)
local weapon, offweapon = self:hasDualWeapon()
if not weapon then
game.logPlayer(self, "You cannot use Coup de Grace without dual wielding!")
return nil
end
local tg = self:getTalentTarget(t)
local x, y, target = self:getTargetLimited(tg)
if not x or not y or not target then return nil end
local mult = t.getDamage(self,t)
if (target.life / target.max_life <= 0.3) then mult = mult * 1.5 end
-- Attack with offhand first
local hits = 0
hits = hits + (self:attackTargetWith(target, offweapon.combat, nil, self:getOffHandMult(offweapon.combat, mult)) and 1 or 0)
hits = hits + (self:attackTargetWith(target, weapon.combat, nil, mult) and 1 or 0)
if hits > 0 then
if target:checkHit(self:combatAttack(), target:combatPhysicalResist(), 0, 95) and target:canBe("instakill") and target.life < target.max_life * 0.2 then
-- KILL IT !
self:logCombat(target, "#Source# delivers a Coup de Grace against #Target#!")
target:die(self)
elseif target.life > 0 and target.life < target.max_life * 0.2 then
game.logSeen(target, "%s resists the Coup de Grace!", target:getName():capitalize())
end
end
if target.dead and self:knowTalent(self.T_STEALTH) then
game:onTickEnd(function()
if not self:isTalentActive(self.T_STEALTH) then
self.hide_chance = 1000
self.talents_cd["T_STEALTH"] = 0
game.logSeen(self, "#GREY#%s slips into shadow.", self:getName():capitalize())
self:forceUseTalent(self.T_STEALTH, {ignore_energy=true, silent = true})
self.hide_chance = nil
end
end)
end
return true
end,
info = function(self, t)
dam = t.getDamage(self,t)*100
perc = t.getPercent(self,t)*100
return ([[Attempt to finish off a wounded enemy, striking them with both weapons for %d%% increased by 50%% if their life is below 30%%. A target brought below 20%% of its maximum life must make a physical save against your Accuracy or be instantly slain.
You may take advantage of finishing your foe this way to activate stealth (if known).]]):
tformat(dam, perc)
end,
}
newTalent{
name = "Terrorize",
type = {"technique/assassination", 2},
require = techs_dex_req_high2,
points = 5,
mode = "passive",
radius = function(self, t) return math.floor(self:combatTalentLimit(t, 10, 2, 5.5)) end,
range = 0,
getDuration = function(self, t) return self:combatTalentScale(t, 3, 5) end,
target = function(self, t)
return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t}
end,
terrorize = function(self, t)
local tg = self:getTalentTarget(t)
self:project(tg, self.x, self.y, DamageType.TERROR, {dur=t.getDuration(self,t)})
end,
info = function(self, t)
local radius = self:getTalentRadius(t)
local duration = t.getDuration(self,t)
return ([[When you exit stealth, you reveal yourself dramatically, intimidating foes around you.
All foes within radius %d that witness you leaving stealth will be stricken with terror, which randomly inflicts stun, slow (40%% power), or confusion (50%% power) for %d turns.
The chance to terrorize improves with your combat accuracy.]])
:tformat(radius, duration)
end,
}
newTalent{
name = "Garrote",
type = {"technique/assassination", 3},
require = techs_dex_req_high3,
points = 5,
random_ego = "attack",
cooldown = 6,
mode = "passive",
requires_target = true,
getDamage = function (self, t) return self:combatTalentWeaponDamage(t, 0.2, 0.6) end,
getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 3, 7)) end,
target = function(self, t) return {type="hit", range=self:getTalentRange(t)} end,
range = 1,
passives = function(self, t, p)
self:talentTemporaryValue(p, "show_gloves_combat", 1)
end,
callbackOnMeleeAttack = function(self, t, target, hitted, crit, weapon, damtype, mult, dam)
local dam = t.getDamage(self,t)
if weapon.no_garrote then return end
if target and not target.dead and self:isTalentActive(self.T_STEALTH) and not self:isTalentCoolingDown(t) and core.fov.distance(self.x, self.y, target.x, target.y) <= 1 then
self:startTalentCooldown(t)
-- check takes the place of normal melee hit chance
if not self:checkHit(self:combatAttack(), target:combatPhysicalResist()) or not target:canBe("pin") then
self:logCombat(target, "#Target# avoids a garrote from #Source#!")
return
end
local silence = target:canBe("silence") and math.ceil(t.getDuration(self, t)/2) or 0
target:setEffect(target.EFF_GARROTE, t.getDuration(self, t), {power=dam, src=self, silence=silence})
end
end,
info = function(self, t)
local damage = t.getDamage(self, t)*100
local dur = t.getDuration(self,t)
local sdur = math.ceil(t.getDuration(self,t)/2)
return ([[When attacking from stealth, you slip a garrote over the target’s neck (or other vulnerable part). This strangles for %d turns and silences for %d turns. Strangled targets are pinned and suffer an automatic unarmed attack for %d%% damage each turn.
Your chance to apply the garrote increases with your Accuracy and you must stay adjacent to your target to maintain it.
This talent has a cooldown.]])
:tformat(dur, sdur, damage)
end,
}
newTalent{
name = "Marked for Death",
type = {"technique/assassination", 4},
require = techs_dex_req_high4,
points = 5,
cooldown = 25,
range = 10,
stamina = 30,
requires_target = true,
no_break_stealth = true,
no_npc_use = true, -- lol
getPower = function(self, t) return self:combatTalentScale(t, 15, 40) end,
getPercent = function(self, t) return self:combatTalentLimit(t, 50, 20, 40) end,
getDamage = function(self,t) return self:combatTalentStatDamage(t, "dex", 15, 180) end,
target = function(self, t)
return {type="hit", range=self:getTalentRange(t), talent=t}
end,
action = function(self, t)
local tg = self:getTalentTarget(t)
local x, y, target = self:getTarget(tg)
if not (x and y) or not self:canProject(tg, x, y) then return nil end
self:project(tg, x, y, function(px, py)
target = game.level.map(px, py, engine.Map.ACTOR)
if not target then return end
target:setEffect(target.EFF_MARKED_FOR_DEATH, 4, {src=self, power=t.getPower(self,t), perc=t.getPercent(self,t)/100, dam = t.getDamage(self,t), stam = t.stamina, max_dur=4})
end)
return true
end,
info = function(self, t)
power = t.getPower(self,t)
perc = t.getPercent(self,t)
dam = t.getDamage(self,t)
return ([[You mark a target for death for 4 turns, causing them to take %d%% increased damage from all sources. When this effect ends they will immediately take physical damage equal to %0.2f plus %d%% of all damage taken while marked.
If a target dies while marked, the cooldown of this ability is reset and the cost refunded.
This ability can be used without breaking stealth.
The base damage dealt will increase with your Dexterity.]]):
tformat(power, damDesc(self, DamageType.PHYSICAL, dam), perc)
end,
}