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)
elseif reaction >= 0 then
-- Talk ?
if 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.x = nil target.y = nil
self.x = nil self.y = nil
target:move(sx, sy, true)
self:move(tx, ty, 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
]]
function _M:attackTarget(target, damtype, mult, noenergy)
-- Break before we do the blow, because it might start step up, we dont want to insta-cancel it
self:breakStepUp()
if self:attr("feared") then
if not noenergy then
self:useEnergy(game.energy_to_act * speed)
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
game.logPlayer(self, "%s notices you at the last moment!", target.name:capitalize())
end
-- 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
if gems[i] and gems[i].attack_type then types[#types+1] = gems[i].attack_type end
end
if #types > 0 then
damtype = rng.table(types)
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
if ht.stop then return hit end
end
if not speed and self:isTalentActive(self.T_GESTURE_OF_PAIN) then
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)
break_stealth = true
end
if not speed and not self:attr("disarmed") and not self:isUnarmed() then
-- All weapons in main hands
if self:getInven(self.INVEN_MAINHAND) then
for i, o in ipairs(self:getInven(self.INVEN_MAINHAND)) do
print("[ATTACK] attacking with", o.name)
local s, h = self:attackTargetWith(target, o.combat, damtype, mult)
speed = math.max(speed or 0, s)
hit = hit or h
if hit and not sound then sound = o.combat.sound
elseif not hit and not sound_miss then sound_miss = o.combat.sound_miss end
-- All weapons in off hands
-- Offhand attacks are with a damage penalty, that can be reduced by talents
for i, o in ipairs(self:getInven(self.INVEN_OFFHAND)) do
local combat = o.combat
if o.special_combat and o.subtype == "shield" and self:knowTalent(self.T_STONESHIELD) then combat = o.special_combat end
if combat and not o.archery then
local s, h = self:attackTargetWith(target, combat, damtype, offmult)
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 s, h = self:attackTargetWith(target, self.combat, damtype, mult)
speed = math.max(speed or 0, s)
hit = hit or h
if hit and not sound then sound = self.combat.sound
elseif not hit and not sound_miss then sound_miss = self.combat.sound_miss end
if speed and not noenergy then
self:useEnergy(game.energy_to_act * speed)
self.did_energy = true
end
if sound then game:playSoundNear(self, sound)
elseif sound_miss then game:playSoundNear(self, sound_miss) end
game:playSoundNear(self, self.on_hit_sound or "actions/melee_hit_squish")
if self.sound_moam and rng.chance(7) then game:playSoundNear(self, self.sound_moam) end
if self:isTalentActive(self.T_CLEAVE) then
Loading
Loading full blame...