Skip to content
Snippets Groups Projects
Commit c2eed404 authored by dg's avatar dg
Browse files

More traps are avoided by Feather Wind (and the new Light of Foot talent)

New class: Marauder, a more thug-like rogue focusing on damage and movement


git-svn-id: http://svn.net-core.org/repos/t-engine4@4254 51575b47-30f0-44d4-a5cc-537603b46e54
parent 039e83d0
No related branches found
No related tags found
No related merge requests found
Showing with 121 additions and 142 deletions
......@@ -73,7 +73,7 @@ end
--- Called when triggered
function _M:canTrigger(x, y, who, no_random)
if self.safe_levitation and who:attr("levitation") then return false end
if self.pressure_trap and who:attr("avoid_pressure_traps") then return false end
if self.faction and who:reactionToward(self) >= 0 then return false end
if not no_random and who.trap_avoidance and rng.percent(who.trap_avoidance) then
if self:knownBy(who) then
......
......@@ -213,14 +213,14 @@ function _M:checkEvasion(target)
end
--- Attacks with one weapon
function _M:attackTargetWith(target, weapon, damtype, mult)
damtype = damtype or weapon.damtype or DamageType.PHYSICAL
function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
damtype = damtype or (weapon and weapon.damtype) or DamageType.PHYSICAL
mult = mult or 1
-- Does the blow connect? yes .. complex :/
local atk, def = self:combatAttack(weapon), target:combatDefense()
if not self:canSee(target) then atk = atk / 3 end
local dam, apr, armor = self:combatDamage(weapon), self:combatAPR(weapon), target:combatArmor()
local dam, apr, armor = force_dam or self:combatDamage(weapon), self:combatAPR(weapon), target:combatArmor()
print("[ATTACK] to ", target.name, " :: ", dam, apr, armor, def, "::", mult)
if target:knowTalent(target.T_DUCK_AND_DODGE) then
......@@ -249,7 +249,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult)
dam = dam * mult
print("[ATTACK] after mult", dam)
if weapon.inc_damage_type then
if weapon and weapon.inc_damage_type then
for t, idt in pairs(weapon.inc_damage_type) do
if target.type.."/"..target.subtype == t or target.type == t then dam = dam + dam * idt / 100 break end
end
......@@ -272,7 +272,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult)
end
-- Melee project
if hitted and not target.dead and weapon.melee_project then for typ, dam in pairs(weapon.melee_project) do
if hitted and not target.dead and weapon and weapon.melee_project then for typ, dam in pairs(weapon.melee_project) do
if dam > 0 then
DamageType:get(typ).projector(self, target.x, target.y, typ, dam)
end
......@@ -317,7 +317,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult)
end
-- On hit talent
if hitted and not target.dead and weapon.talent_on_hit and next(weapon.talent_on_hit) then
if hitted and not target.dead and weapon and weapon.talent_on_hit and next(weapon.talent_on_hit) then
for tid, data in pairs(weapon.talent_on_hit) do
if rng.percent(data.chance) then
self:forceUseTalent(tid, {ignore_cd=true, ignore_energy=true, force_target=target, force_level=data.level, ignore_ressources=true})
......@@ -394,7 +394,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult)
end
-- Special effect
if hitted and not target.dead and weapon.special_on_hit and weapon.special_on_hit.fct then
if hitted and not target.dead and weapon and weapon.special_on_hit and weapon.special_on_hit.fct then
weapon.special_on_hit.fct(weapon, self, target)
end
......@@ -412,6 +412,10 @@ function _M:attackTargetWith(target, weapon, damtype, mult)
if hitted and not target.dead and target:attr("mana_regen_on_hit") then target:incMana(target.mana_regen_on_hit) end
if hitted and not target.dead and target:attr("equilibrium_regen_on_hit") then target:incEquilibrium(-target.equilibrium_regen_on_hit) end
if hitted and self:attr("stamina_use_on_hit") then
self:incStamina(-self.stamina_use_on_hit)
end
if hitted and not target.dead and target:knowTalent(target.T_STONESHIELD) then
local t = target:getTalentFromId(target.T_STONESHIELD)
local m, mm, e, em = t.getValues(self, t)
......@@ -454,7 +458,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult)
-- Greater Weapon Focus
local gwf = self:hasEffect(self.EFF_GREATER_WEAPON_FOCUS)
if hitted and not target.dead and gwf and not gwf.inside and rng.percent(gwf.chance) then
if hitted and not target.dead and weapon and gwf and not gwf.inside and rng.percent(gwf.chance) then
gwf.inside = true
game.logSeen(self, "%s focuses and gains an extra blow!", self.name:capitalize())
self:attackTargetWith(target, weapon, damtype, mult)
......
......@@ -29,6 +29,7 @@ newEntity{ base = "TRAP_ALARM",
rarity = 3, level_range = {1, 50},
color=colors.UMBER,
message = "@Target@ triggers an alarm!",
pressure_trap = true,
triggered = function(self, x, y, who)
for i = x - 20, x + 20 do for j = y - 20, y + 20 do if game.level.map:isBound(i, j) then
local actor = game.level.map(i, j, game.level.map.ACTOR)
......
......@@ -52,6 +52,7 @@ newEntity{ base = "TRAP_ANNOY",
color=colors.ORCHID,
message = "@Target@ triggers a burning curse!",
dam = resolvers.mbonus(80, 5),
pressure_trap = true,
triggered = function(self, x, y, who)
who:setEffect(who.EFF_BURNING_HEX, 7, {src=self, dam=self.dam})
return true, true
......
......@@ -32,6 +32,7 @@ newEntity{ base = "TRAP_COMPLEX",
rarity = 3, level_range = {1, 30},
color_r=40, color_g=220, color_b=0,
message = "@Target@ walks on a trap, there is a loud noise.",
pressure_trap = true,
on_added = function(self, level, x, y)
local walls = {}
for i, dir in ipairs{4,6,8,2} do
......
......@@ -20,6 +20,7 @@
newEntity{ define_as = "TRAP_ELEMENTAL",
type = "elemental", id_by_type=true, unided_name = "trap",
display = '^',
pressure_trap = true,
triggered = function(self, x, y, who)
self:project({type="hit",x=x,y=y}, x, y, self.damtype, self.dam, self.particles and {type=self.particles})
return true
......
......@@ -31,7 +31,7 @@ newEntity{ base = "TRAP_NATURAL_FOREST",
detect_power = 6, disarm_power = 16,
rarity = 3, level_range = {1, 50},
color=colors.UMBER,
safe_levitation = true,
pressure_trap = true,
message = "@Target@ slides on a rock!",
triggered = function(self, x, y, who)
if who:checkHit(self.disarm_power + 5, who:combatPhysicalResist(), 0, 95, 15) and who:canBe("stun") then
......
......@@ -30,6 +30,7 @@ newEntity{ base = "TRAP_TELEPORT",
rarity = 5, level_range = {5, 50},
color=colors.UMBER,
message = "@Target@ is teleported away.",
pressure_trap = true,
triggered = function(self, x, y, who)
who:teleportRandom(x, y, 100)
return true
......
......@@ -152,6 +152,7 @@ newTalent{
encumb = self:addTemporaryValue("max_encumber", t.getEncumberance(self, t)),
def = self:addTemporaryValue("combat_def_ranged", t.getRangedDefence(self, t)),
lev = self:addTemporaryValue("levitation", 1),
traps = self:addTemporaryValue("avoid_pressure_traps", 1),
}
self:checkEncumbrance()
return ret
......@@ -160,6 +161,7 @@ newTalent{
self:removeTemporaryValue("max_encumber", p.encumb)
self:removeTemporaryValue("combat_def_ranged", p.def)
self:removeTemporaryValue("levitation", p.lev)
self:removeTemporaryValue("avoid_pressure_traps", p.traps)
self:checkEncumbrance()
return true
end,
......
......@@ -26,7 +26,7 @@ newTalent{
cooldown = 14,
stamina = 30,
tactical = { ESCAPE = 1, ATTACK = 0.5 },
require = cuns_req1,
require = techs_dex_req1,
requires_target = true,
getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.4, 1) end,
getDist = function(self, t) return 1 + math.ceil(self:getTalentLevel(t) / 2) end,
......@@ -56,7 +56,7 @@ newTalent{
type = {"technique/mobility", 2},
mode = "passive",
points = 5,
require = cuns_req2,
require = techs_dex_req2,
getDef = function(self, t) return self:getTalentLevel(t) * 0.08 end,
getHardiness = function(self, t) return self:getTalentLevel(t) * 0.06 end,
info = function(self, t)
......@@ -70,15 +70,18 @@ newTalent{
type = {"technique/mobility", 3},
mode = "passive",
points = 5,
require = cuns_req3,
require = techs_dex_req3,
on_learn = function(self, t)
self.fatigue = (self.fatigue or 0) - 1.5
if self:getTalentLevelRaw(t) == 3 then self:attr("avoid_pressure_traps", 1) end
end,
on_unlearn = function(self, t)
self.fatigue = (self.fatigue or 0) + 1.5
if self:getTalentLevelRaw(t) == 2 then self:attr("avoid_pressure_traps", -1) end
end,
info = function(self, t)
return ([[You are light on foot, handling your armour better. Each step you take regenerates %0.2f stamina and your fatigue is permanently reduced by %d%%.]]):
return ([[You are light on foot, handling your armour better. Each step you take regenerates %0.2f stamina and your fatigue is permanently reduced by %d%%.
At level 3 you are able to walk so lightly that you never trigger traps that require pressure.]]):
format(self:getTalentLevelRaw(t) * 0.2, self:getTalentLevelRaw(t) * 1.5)
end,
}
......@@ -86,48 +89,25 @@ newTalent{
newTalent{
name = "Strider",
type = {"technique/mobility", 4},
mode = "passive",
points = 5,
random_ego = "attack",
cooldown = 25,
stamina = 30,
require = cuns_req4,
requires_target = true,
tactical = { DISABLE = 2, ATTACK = 2 },
getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.9, 1.4) end,
getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end,
getAttackPenalty = function(self, t) return 10 + self:getTalentLevel(t) * 3 end,
getDamagePenalty = function(self, t) return 10 + self:getTalentLevel(t) * 4 end,
action = function(self, t)
local tg = {type="hit", range=self:getTalentRange(t)}
local x, y, target = self:getTarget(tg)
if not x or not y or not target then return nil end
if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end
local hitted = self:attackTarget(target, nil, t.getDamage(self, t), true)
if hitted then
if target:checkHit(self:combatAttackDex(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) then
local tw = target:getInven("MAINHAND")
if tw then
tw = tw[1] and tw[1].combat
end
tw = tw or target.combat
local atk = target:combatAttack(tw) * (t.getAttackPenalty(self, t)) / 100
local dam = target:combatDamage(tw) * (t.getDamagePenalty(self, t)) / 100
target:setEffect(target.EFF_CRIPPLE, t.getDuration(self, t), {atk=atk, dam=dam})
else
game.logSeen(target, "%s is not crippled!", target.name:capitalize())
end
end
return true
require = techs_dex_req4,
on_learn = function(self, t)
self.movement_speed = self.movement_speed + 0.02
self.talent_cd_reduction[Talents.T_RUSH] = (self.talent_cd_reduction[Talents.T_RUSH] or 0) + 1
self.talent_cd_reduction[Talents.T_HACK_N_BACK] = (self.talent_cd_reduction[Talents.T_HACK_N_BACK] or 0) + 1
self.talent_cd_reduction[Talents.T_DISENGAGE] = (self.talent_cd_reduction[Talents.T_DISENGAGE] or 0) + 1
self.talent_cd_reduction[Talents.T_EVASION] = (self.talent_cd_reduction[Talents.T_EVASION] or 0) + 1
end,
on_unlearn = function(self, t)
self.movement_speed = self.movement_speed - 0.02
self.talent_cd_reduction[Talents.T_RUSH] = (self.talent_cd_reduction[Talents.T_RUSH] or 0) - 1
self.talent_cd_reduction[Talents.T_HACK_N_BACK] = (self.talent_cd_reduction[Talents.T_HACK_N_BACK] or 0) - 1
self.talent_cd_reduction[Talents.T_DISENGAGE] = (self.talent_cd_reduction[Talents.T_DISENGAGE] or 0) - 1
self.talent_cd_reduction[Talents.T_EVASION] = (self.talent_cd_reduction[Talents.T_EVASION] or 0) - 1
end,
info = function(self, t)
local damage = t.getDamage(self, t)
local duration = t.getDuration(self, t)
local attackpen = t.getAttackPenalty(self, t)
local damagepen = t.getDamagePenalty(self, t)
return ([[You hit your target doing %d%% damage. If your attack hits, the target is crippled for %d turns, losing %d%% accuracy and %d%% damage.
Hit chance improves with talent level and your Dexterity stat.]]):
format(100 * damage, duration, attackpen, damagepen)
return ([[You literaly danse around your foes, increasing movement speed by %d%% and reducing the cooldown of Hack'n'Back, Rush, Disengage and Evasion by %d turns.]]):
format(self:getTalentLevelRaw(t) * 0.02, self:getTalentLevelRaw(t))
end,
}
......@@ -23,37 +23,54 @@ newTalent{
name = "Skullcracker",
type = {"technique/thuggery", 1},
points = 5,
random_ego = "attack",
cooldown = 12,
stamina = 10,
tactical = { DISABLE = 2, ATTACK = 0.5 },
require = cuns_req1,
stamina = 20,
tactical = { DISABLE = 2, ATTACK = 1 },
require = techs_req1,
requires_target = true,
getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.2, 0.7) end,
getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end,
getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t) / 2) end,
getDamage = function(self, t)
local o = self:getInven(self.INVEN_HEAD) and self:getInven(self.INVEN_HEAD)[1]
local add = 0
if o then
add = 15 + o:getPriceFlags() * 0.6 * math.sqrt(o:getPowerRank() + 1) * (o:attr("metallic") and 1 or 0.5)
end
local totstat = self:getStat("str")
local talented_mod = math.sqrt((self:getTalentLevel(t) + (o and o.material_level or 1)) / 10) + 1
local power = math.max(self.combat_dam + add, 1)
power = (math.sqrt(power / 10) - 1) * 0.8 + 1
-- print(("[COMBAT HEAD DAMAGE] power(%f) totstat(%f) talent_mod(%f)"):format(power, totstat, talented_mod))
return self:rescaleDamage(totstat / 1.5 * power * talented_mod)
end,
action = function(self, t)
local tg = {type="hit", range=self:getTalentRange(t)}
local x, y, target = self:getTarget(tg)
if not x or not y or not target then return nil end
if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end
local hitted = self:attackTarget(target, nil, t.getDamage(self, t), true)
local dam = t.getDamage(self, t)
local _, hitted = self:attackTargetWith(target, nil, nil, nil, dam)
if hitted then
if target:checkHit(self:combatAttackDex(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("stun") then
target:setEffect(target.EFF_STUNNED, t.getDuration(self, t), {})
if target:checkHit(self:combatAttackDex(), target:combatPhysicalResist(), 0, 95) and target:canBe("confusion") then
target:setEffect(target.EFF_CONFUSED, t.getDuration(self, t), {power=30 + self:getDex(70)})
else
game.logSeen(target, "%s resists the stun!", target.name:capitalize())
game.logSeen(target, "%s resists the headblow!", target.name:capitalize())
end
end
return true
end,
info = function(self, t)
local damage = t.getDamage(self, t)
local dam = t.getDamage(self, t)
local duration = t.getDuration(self, t)
return ([[You hit your target doing %d%% damage, trying to stun it instead of damaging it. If your attack hits, the target is stunned for %d turns.
Stun chance increase with talent level and your Dexterity stat.]]):
format(100 * damage, duration)
return ([[You smack your forehead against your enemy's head (or whatever sensitive part you can find), causing %0.2f physical damage. If the attack hits the target is confused for %d turns.
Damage done increases with the quality of your headgear, your strength and your physical damage bonuses.
Confusion power and chance increase with your Dexterity stat.]]):
format(dam, duration)
end,
}
......@@ -62,52 +79,36 @@ newTalent{
type = {"technique/thuggery", 2},
mode = "passive",
points = 5,
require = cuns_req2,
getCriticalChance = function(self, t) return self:getTalentLevel(t) * 10 end,
require = techs_req2,
on_learn = function(self, t)
self.stun_immune = (self.stun_immune or 0) + 0.1
self.confusion_immune = (self.confusion_immune or 0) + 0.1
end,
on_unlearn = function(self, t)
self.stun_immune = (self.stun_immune or 0) - 0.1
self.confusion_immune = (self.confusion_immune or 0) - 0.1
end,
info = function(self, t)
local chance = t.getCriticalChance(self, t)
return ([[Your quick wit gives you a big advantage against stunned targets; all your hits will have a %d%% greater chance of being critical.]]):
format(chance)
return ([[Your attunement to violence has given you %d%% resistance to stuns and confusion arising in battle.]]):
format(self:getTalentLevelRaw(t) * 10)
end,
}
newTalent{
name = "Vicious Strikes",
type = {"technique/thuggery", 3},
points = 5,
random_ego = "defensive",
cooldown = 10,
stamina = 50,
require = cuns_req3,
requires_target = true,
tactical = { DISABLE = 2 },
getDuration = function(self, t) return 1 + self:getTalentLevel(t) end,
action = function(self, t)
local tg = {type="hit", range=self:getTalentRange(t)}
local x, y, target = self:getTarget(tg)
if not x or not y or not target then return nil end
if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end
local tx, ty, sx, sy = target.x, target.y, self.x, self.y
local hitted = self:attackTarget(target, nil, 0, true)
if hitted then
self:setEffect(self.EFF_EVASION, t.getDuration(self, t), {chance=50})
-- Displace
self.x = nil self.y = nil
self:move(tx, ty, true)
if not target.dead then
target.x = nil target.y = nil
target:move(sx, sy, true)
end
end
return true
require = techs_req3,
on_learn = function(self, t)
self.combat_critical_power = (self.combat_critical_power or 0) + 5
self.combat_apr = self.combat_apr + 4
end,
on_unlearn = function(self, t)
self.combat_critical_power = (self.combat_critical_power or 0) - 5
self.combat_apr = self.combat_apr - 4
end,
info = function(self, t)
local duration = t.getDuration(self, t)
return ([[Using a series of tricks and maneuvers, you switch places with your target.
Switching places will confuse your foes, granting you evasion(50%%) for %d turns.]]):
format(duration)
return ([[You know how to hit the right places, giving +%d%% critical damage mofidier and %d armour penetration.]]):
format(self:getTalentLevelRaw(t) * 5, self:getTalentLevelRaw(t) * 4)
end,
}
......@@ -115,47 +116,34 @@ newTalent{
name = "Total Thuggery",
type = {"technique/thuggery", 4},
points = 5,
random_ego = "attack",
cooldown = 25,
stamina = 30,
require = cuns_req4,
mode = "sustained",
cooldown = 30,
sustain_stamina = 40,
no_energy = true,
require = techs_req4,
requires_target = true,
range = 1,
tactical = { DISABLE = 2, ATTACK = 2 },
getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.9, 1.4) end,
getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end,
getAttackPenalty = function(self, t) return 10 + self:getTalentLevel(t) * 3 end,
getDamagePenalty = function(self, t) return 10 + self:getTalentLevel(t) * 4 end,
action = function(self, t)
local tg = {type="hit", range=self:getTalentRange(t)}
local x, y, target = self:getTarget(tg)
if not x or not y or not target then return nil end
if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end
local hitted = self:attackTarget(target, nil, t.getDamage(self, t), true)
if hitted then
if target:checkHit(self:combatAttackDex(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) then
local tw = target:getInven("MAINHAND")
if tw then
tw = tw[1] and tw[1].combat
end
tw = tw or target.combat
local atk = target:combatAttack(tw) * (t.getAttackPenalty(self, t)) / 100
local dam = target:combatDamage(tw) * (t.getDamagePenalty(self, t)) / 100
target:setEffect(target.EFF_CRIPPLE, t.getDuration(self, t), {atk=atk, dam=dam})
else
game.logSeen(target, "%s is not crippled!", target.name:capitalize())
end
end
getCrit = function(self, t) return self:combatTalentStatDamage(t, "dex", 10, 50) / 1.5 end,
getPen = function(self, t) return self:combatTalentStatDamage(t, "str", 10, 50) / 2 end,
getDrain = function(self, t) return 12 - self:getTalentLevelRaw(t) end,
activate = function(self, t)
local ret = {
crit = self:addTemporaryValue("combat_physcrit", t.getCrit(self, t)),
pen = self:addTemporaryValue("resists_pen", {[DamageType.PHYSICAL] = t.getPen(self, t)}),
drain = self:addTemporaryValue("stamina_use_on_hit", t.getDrain(self, t)),
}
return ret
end,
deactivate = function(self, t, p)
self:removeTemporaryValue("combat_physcrit", p.crit)
self:removeTemporaryValue("resists_pen", p.pen)
self:removeTemporaryValue("stamina_use_on_hit", p.drain)
return true
end,
info = function(self, t)
local damage = t.getDamage(self, t)
local duration = t.getDuration(self, t)
local attackpen = t.getAttackPenalty(self, t)
local damagepen = t.getDamagePenalty(self, t)
return ([[You hit your target doing %d%% damage. If your attack hits, the target is crippled for %d turns, losing %d%% accuracy and %d%% damage.
Hit chance improves with talent level and your Dexterity stat.]]):
format(100 * damage, duration, attackpen, damagepen)
return ([[You go all out, trying to burn down your foes as fast as possible.
Every hit in battle has +%d%% critical chance and +%d%% physical penetration, but each strike drains %d stamina.]]):
format(t.getCrit(self, t), t.getPen(self, t), t.getDrain(self, t))
end,
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment