Newer
Older
--
-- 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
--- Interface to add ToME combat system
module(..., package.seeall, class.make)
--- Checks what to do with the target
-- Talk ? attack ? displace ?
function _M:bumpInto(target, x, y)
local reaction = self:reactionToward(target)
if reaction < 0 then
if target.encounterAttack and self.player then self:onWorldEncounter(target, x, y) return end
if game.player == self and ((not config.settings.tome.actor_based_movement_mode and game.bump_attack_disabled) or (config.settings.tome.actor_based_movement_mode and self.bump_attack_disabled)) then return end
return self:useTalent(self.T_ATTACK, nil, nil, nil, target)
-- Talk ? Bump ?
if self.player and target.on_bump then
target:on_bump(self)
elseif self.player and target.can_talk then
if target.can_talk_only_once then target.can_talk = nil end
if target.can_talk_only_once then target.can_talk = nil end
elseif self.move_others and not target.cant_be_moved then
if target.move_others and self ~= game.player then return end
dg
committed
-- Check we can both walk in the tile we will end up in
local blocks = game.level.map:checkAllEntitiesLayersNoStop(target.x, target.y, "block_move", self)
for kind, v in pairs(blocks) do if kind[1] ~= Map.ACTOR and v then return end end
blocks = game.level.map:checkAllEntitiesLayersNoStop(self.x, self.y, "block_move", target)
for kind, v in pairs(blocks) do if kind[1] ~= Map.ACTOR and v then return end end
local tx, ty, sx, sy = target.x, target.y, self.x, self.y
target:move(sx, sy, true)
self:move(tx, ty, true)
if target.describeFloor then target:describeFloor(target.x, target.y, true) end
if self.describeFloor then self:describeFloor(self.x, self.y, true) end
local energy = game.energy_to_act * self:combatMovementSpeed(x, y)
energy = energy / self:attr("bump_swap_speed_divide")
self:useEnergy(energy)
self.did_energy = true
end
end
end
--- Makes the death happen!
- attack: increases chances to hit against high defense
- defense: increases chances to miss against high attack power
- armor: direct reduction of damage done
- armor penetration: reduction of target's armor
- damage: raw damage done
]]
-- Attempts to attack a target with all melee weapons (calls self:attackTargetWith for each)
-- @param target - target actor
-- @param damtype a damage type ID <PHYSICAL>
-- @param mult a damage multiplier <1>
-- @noenergy if true the attack uses no energy
-- @force_unarmed if true the attacker uses unarmed (innate) combat parameters
-- @return true if an attack hit the target, false otherwise
function _M:attackTarget(target, damtype, mult, noenergy, force_unarmed)
-- Break before we do the blow, because it might start step up, we dont want to insta-cancel it
self:breakStepUp()
self:useEnergy(game.energy_to_act)
self.did_energy = true
end
game.logSeen(self, "%s is too afraid to attack.", self.name:capitalize())
return false
end
dg
committed
if self:attr("terrified") and rng.percent(self:attr("terrified")) then
if not noenergy then
self:useEnergy(game.energy_to_act)
self.did_energy = true
end
game.logSeen(self, "%s is too terrified to attack.", self.name:capitalize())
return false
end
-- Cancel stealth early if we are noticed
if self:isTalentActive(self.T_STEALTH) and target:canSee(self) then
self:useTalent(self.T_STEALTH)
self.changed = true
if self.player then self:logCombat(target, "#Target# notices you at the last moment!") end
DarkGod
committed
if target:isTalentActive(target.T_INTUITIVE_SHOTS) and rng.percent(target:callTalent(target.T_INTUITIVE_SHOTS, "getChance")) then
local ret = target:callTalent(target.T_INTUITIVE_SHOTS, "proc", self)
if ret then return false end
end
if not target.turn_procs.warding_weapon and target:knowTalent(target.T_WARDING_WEAPON) and target:getTalentLevelRaw(target.T_WARDING_WEAPON) >= 5
and rng.percent(target:callTalent(target.T_WARDING_WEAPON, "getChance")) then
local t = self:getTalentFromId(self.T_WARDING_WEAPON)
if target:getPsi() >= t.psi then
target:setEffect(target.EFF_WEAPON_WARDING, 1, {})
target.turn_procs.warding_weapon = true
target:incPsi(-t.psi)
end
DarkGod
committed
-- Change attack type if using gems
if not damtype and self:getInven(self.INVEN_GEM) then
local gems = self:getInven(self.INVEN_GEM)
local types = {}
for i = 1, #gems do
local damtype = table.get(gems[i], 'color_attributes', 'damage_type')
if damtype then table.insert(types, damtype) end
elseif not damtype and self:attr("force_melee_damage_type") then
damtype = self:attr("force_melee_damage_type")
local hd = {"Combat:attackTarget", target=target, damtype=damtype, mult=mult, noenergy=noenergy}
if self:triggerHook(hd) then
speed, hit, damtype, mult = hd.speed, hd.hit, hd.damtype, hd.mult
end
if not speed and self:isTalentActive(self.T_GESTURE_OF_PAIN) then
if self.no_gesture_of_pain_recurse then return false end
dg
committed
print("[ATTACK] attacking with Gesture of Pain")
local t = self:getTalentFromId(self.T_GESTURE_OF_PAIN)
dg
committed
speed, hit = t.attack(self, t, target)
dg
committed
break_stealth = true
end
if not speed and not self:attr("disarmed") and not self:isUnarmed() and not force_unarmed then
local double_weapon
-- All weapons in main hands
if self:getInven(self.INVEN_MAINHAND) then
for i, o in ipairs(self:getInven(self.INVEN_MAINHAND)) do
local combat = self:getObjectCombat(o, "mainhand")
if combat and not o.archery then
if o.double_weapon and not double_weapon then double_weapon = o end
print("[ATTACK] attacking with (mainhand)", o.name)
speed = math.max(speed or 0, s)
hit = hit or h
if hit and not sound then sound = combat.sound
elseif not hit and not sound_miss then sound_miss = combat.sound_miss end
if not combat.no_stealth_break then break_stealth = true end
local oh_weaps, offhand = table.clone(self:getInven(self.INVEN_OFFHAND)) or {}, false
-- Offhand attacks are with a damage penalty, that can be reduced by talents
if double_weapon then oh_weaps[#oh_weaps+1] = double_weapon end -- use double weapon as OFFHAND if there are no others
for i = 1, #oh_weaps do
if i == #oh_weaps and double_weapon and offhand then break end
local o = oh_weaps[i]
local offmult = self:getOffHandMult(o.combat, mult)
local combat = self:getObjectCombat(o, "offhand")
Loading
Loading full blame...