diff -r 88f08638aa28 -r d2255241678c game/modules/tome/class/Actor.lua
--- a/game/modules/tome/class/Actor.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/class/Actor.lua Fri Mar 25 19:27:01 2011 -0500
@@ -174,7 +174,7 @@
mod.class.interface.ActorInscriptions.init(self, t)
-- Default melee barehanded damage
- self.combat = self.combat or { dam=1, atk=1, apr=0, dammod={str=1} }
+ self.combat = self.combat or { dam=1, atk=1, apr=0, physcrit=0, physspeed =1, dammod={str=1} }
self.talents[self.T_ATTACK] = self.talents[self.T_ATTACK] or 1
self:resetCanSeeCache()
@@ -401,7 +401,7 @@
if moved and self:isTalentActive(self.T_BODY_OF_STONE) then
self:forceUseTalent(self.T_BODY_OF_STONE, {ignore_energy=true})
end
-
+
if moved and not force and ox and oy and (ox ~= self.x or oy ~= self.y) and config.settings.tome.smooth_move > 0 then
local blur = 0
if self:attr("lightning_speed") or self:attr("step_up") or self:attr("wild_speed") then blur = 3 end
@@ -1037,6 +1037,13 @@
self:forceUseTalent(self.T_SECOND_LIFE, {ignore_energy=true})
end
+ -- Unflinching Resolve
+ if self:knowTalent(self.T_UNFLINCHING_RESOLVE) and value >= (self.max_life / 10) then
+ local t = self:getTalentFromId(self.T_UNFLINCHING_RESOLVE)
+ local dam = value
+ t.on_hit(self, t, dam)
+ end
+
if value >= self.life and self.ai_state and self.ai_state.can_reform then
local t = self:getTalentFromId(self.T_SHADOW_REFORM)
if rng.percent(t.getChance(self, t)) then
@@ -1400,6 +1407,9 @@
self.resists.all = self.resists.all - self.temp_con_perc
end
local inc = self:getCon() / 7
+ if self:knowTalent(self.T_IRON_SKIN) then
+ inc = inc * (1 + (self:getTalentLevel(self.T_IRON_SKIN) * 0.2))
+ end
self.temp_con_perc = inc
self.resists.all = self.resists.all + inc
end
@@ -1640,6 +1650,20 @@
if not silent then game.logSeen(self, "The spell fizzles.") end
return false
end
+
+ -- when using unarmed techniques check for weapons and heavy armor
+ if ab.is_unarmed then
+ -- first check for heavy and massive armor
+ if self:hasMassiveArmor() then
+ if not silent then game.logSeen(self, "You are to heavily armored to use this talent.") end
+ return false
+ -- next make sure we're unarmed
+ elseif not self:isUnarmed() then
+ if not silent then game.logSeen(self, "You can't use this talent while holding a weapon or shield.") end
+ return false
+ end
+ end
+
if not self:enoughEnergy() and not fake then return false end
@@ -1953,6 +1977,9 @@
if self:hasEffect(self.EFF_WILD_SPEED) then
self:removeEffect(self.EFF_WILD_SPEED)
end
+ if self:hasEffect(self.EFF_REFLEXIVE_DODGING) then
+ self:removeEffect(self.EFF_REFLEXIVE_DODGING)
+ end
end
--- Breaks lightning speed if active
@@ -2277,6 +2304,10 @@
p.energy.mod = p.energy.mod * (100 - self.slow_projectiles) / 100
print("Projectile slowing down to", p.energy.mod)
end
+ if self:knowTalent(self.T_HEIGHTENED_REFLEXES) then
+ local t = self:getTalentFromId(self.T_HEIGHTENED_REFLEXES)
+ t.do_reflexes(self, t)
+ end
end
--- Call when added to a level
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/class/Object.lua
--- a/game/modules/tome/class/Object.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/class/Object.lua Fri Mar 25 19:27:01 2011 -0500
@@ -410,6 +410,7 @@
if w.fear_immune then desc:add(("Increases fear immunity: %d%%."):format(w.fear_immune * 100), true) end
if w.knockback_immune then desc:add(("Increases knockback immunity: %d%%."):format(w.knockback_immune * 100), true) end
if w.instakill_immune then desc:add(("Increases instant-death immunity: %d%%."):format(w.instakill_immune * 100), true) end
+ if w.teleport_immune then desc:add(("Increases teleport immunity: %d%%."):format(w.teleport_immune * 100), true) end
if w.life_regen then desc:add(("Regenerates %0.2f hitpoints each turn."):format(w.life_regen), true) end
if w.stamina_regen then desc:add(("Regenerates %0.2f stamina each turn."):format(w.stamina_regen), true) end
@@ -447,7 +448,7 @@
desc:add({"color","YELLOW"}, "When used to attack (with talents):", {"color", "LAST"}, true)
desc_combat(self.special_combat)
end
-
+
if self.no_teleport then
desc:add("It is immune to teleportation, if you teleport it will fall on the ground.", true)
end
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/class/interface/Combat.lua
--- a/game/modules/tome/class/interface/Combat.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/class/interface/Combat.lua Fri Mar 25 19:27:01 2011 -0500
@@ -107,7 +107,7 @@
end
local break_stealth = false
- if not self:attr("disarmed") then
+ if 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
@@ -373,6 +373,12 @@
local t = self:getTalentFromId(self.T_CONDUIT)
t.do_combat(self, t, target)
end
+
+ -- Exploit Weakness
+ if hitted and not target.dead and self:knowTalent(self.T_EXPLOIT_WEAKNESS) and self:isTalentActive(self.T_EXPLOIT_WEAKNESS) then
+ local t = self:getTalentFromId(self.T_EXPLOIT_WEAKNESS)
+ t.do_weakness(self, t, target)
+ end
-- Special effect
if hitted and not target.dead and weapon.special_on_hit and weapon.special_on_hit.fct then
@@ -399,6 +405,27 @@
game.logSeen(self, "%s ripostes!", target.name:capitalize())
target:attackTarget(self, nil, nil, true)
end
+
+ -- Set Up
+ if not hitted and not target.dead and not evaded and not target:attr("stunned") and not target:attr("dazed") and not target:attr("stoned") and target:hasEffect(target.EFF_DEFENSIVE_MANEUVER) then
+ local t = target:getTalentFromId(target.T_SET_UP)
+ local power = t.getPower(target, t)
+ self:setEffect(self.EFF_SET_UP, 2, {src = target, power=power})
+ end
+
+ -- Defensive Throw!
+ if not hitted and not target.dead and not evaded and not target:attr("stunned") and not target:attr("dazed") and not target:attr("stoned") and target:knowTalent(target.T_DEFENSIVE_THROW) and rng.percent(target:getTalentLevel(target.T_DEFENSIVE_THROW) * (5 + target:getCun(5))) then
+ local t = target:getTalentFromId(target.T_DEFENSIVE_THROW)
+ t.do_throw(target, self, t)
+ end
+
+ -- Counter Attack!
+ if not hitted and not target.dead and not evaded and not target:attr("stunned") and not target:attr("dazed") and not target:attr("stoned") and target:knowTalent(target.T_COUNTER_ATTACK) and rng.percent(target:getTalentLevel(target.T_COUNTER_ATTACK) * (5 + target:getCun(5))) then
+ game.logSeen(self, "%s counters the attack!", target.name:capitalize())
+ local t = target:getTalentFromId(target.T_COUNTER_ATTACK)
+ local damage = t.getDamage(target, t)
+ local hit = target:attackTarget(self, nil, damage, true)
+ end
-- Greater Weapon Focus
local gwf = self:hasEffect(self.EFF_GREATER_WEAPON_FOCUS)
@@ -439,6 +466,14 @@
if self:hasDualWeapon() and self:knowTalent(self.T_DUAL_WEAPON_DEFENSE) then
add = add + 4 + (self:getTalentLevel(self.T_DUAL_WEAPON_DEFENSE) * self:getDex()) / 12
end
+ if self:knowTalent(self.T_TACTICAL_EXPERT) then
+ local t = self:getTalentFromId(self.T_TACTICAL_EXPERT)
+ add = add + t.do_tact_update(self, t)
+ end
+ if self:knowTalent(self.T_STEADY_MIND) then
+ 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
end
@@ -456,6 +491,10 @@
if self:hasMassiveArmor() and self:knowTalent(self.T_MASSIVE_ARMOUR_TRAINING) then
add = add + self:getTalentLevel(self.T_MASSIVE_ARMOUR_TRAINING) * 1.6
end
+ if self:knowTalent(self.T_PHYSICAL_CONDITIONING) then
+ local t = self:getTalentFromId(self.T_PHYSICAL_CONDITIONING)
+ add = add + t.getArmor(self, t)
+ end
if self:knowTalent(self.T_CARBON_SPIKES) and self:isTalentActive(self.T_CARBON_SPIKES) then
add = add + self.carbon_armor
end
@@ -547,8 +586,18 @@
if self:isTalentActive(Talents.T_BLOOD_FRENZY) then
add = add + self.blood_frenzy
end
-
- local talented_mod = math.sqrt(self:combatCheckTraining(weapon) / 10) + 1
+ if self:knowTalent(self.T_EMPTY_HAND) and weapon == self.combat then
+ local t = self:getTalentFromId(self.T_EMPTY_HAND)
+ add = add + t.getDamage(self, t)
+ end
+
+ if weapon == self.combat then
+ -- Handles unarmed mastery
+ talented_mod = math.sqrt(self:getTalentLevel(Talents.T_UNARMED_MASTERY) / 10) + 1 or 0
+ else
+ talented_mod = math.sqrt(self:combatCheckTraining(weapon) / 10) + 1
+ end
+
local power = math.max(self.combat_dam + (weapon.dam or 1) + add, 1)
power = (math.sqrt(power / 10) - 1) * 0.8 + 1
print(("[COMBAT DAMAGE] power(%f) totstat(%f) talent_mod(%f)"):format(power, totstat, talented_mod))
@@ -636,7 +685,14 @@
if target:attr("combat_critical") then
chance = chance + target:attr("combat_critical")
end
- if target:knowTalent(target.T_PROBABILITY_WEAVING) and target:isTalentActive(T_PROBABILIT_WEAVING) then
+ if target:hasEffect(target.EFF_SET_UP) then
+ local p = target:hasEffect(target.EFF_SET_UP)
+ if p and p.src == self then
+ chance = chance + p.power
+ end
+ end
+
+ if target:knowTalent(target.T_PROBABILITY_WEAVING) and target:isTalentActive(T_PROBABILITY_WEAVING) then
chance = chance - target:getTalentLevel(target.T_PROBABILITY_WEAVING)
end
if target:hasHeavyArmor() and target:knowTalent(target.T_HEAVY_ARMOUR_TRAINING) then
@@ -652,6 +708,7 @@
if rng.percent(chance) then
dam = dam * (1.5 + (self.combat_critical_power or 0) / 100)
crit = true
+
end
return dam, crit
end
@@ -723,17 +780,28 @@
--- Computes physical resistance
function _M:combatPhysicalResist()
- return self.combat_physresist + (self:getCon() + self:getStr() + (self:getLck() - 50) * 0.5) * 0.35
+ local add = 0
+ if self:knowTalent(self.T_PHYSICAL_CONDITIONING) then
+ local t = self:getTalentFromId(self.T_PHYSICAL_CONDITIONING)
+ add = add + t.getPhysical(self, t)
+ end
+ return self.combat_physresist + add + (self:getCon() + self:getStr() + (self:getLck() - 50) * 0.5) * 0.35
end
--- Computes spell resistance
function _M:combatSpellResist()
- return self.combat_spellresist + (self:getMag() + self:getWil() + (self:getLck() - 50) * 0.5) * 0.35
+ local add = 0
+ return self.combat_spellresist + add + (self:getMag() + self:getWil() + (self:getLck() - 50) * 0.5) * 0.35
end
--- Computes mental resistance
function _M:combatMentalResist()
- return self.combat_mentalresist + (self:getCun() + self:getWil() + (self:getLck() - 50) * 0.5) * 0.35
+ local add = 0
+ if self:knowTalent(self.T_STEADY_MIND) then
+ local t = self:getTalentFromId(self.T_STEADY_MIND)
+ add = add + t.getMental(self, t)
+ end
+ return self.combat_mentalresist + add + (self:getCun() + self:getWil() + (self:getLck() - 50) * 0.5) * 0.35
end
--- Computes movement speed
@@ -807,6 +875,18 @@
return shield
end
+-- Check if actor is unarmed
+function _M:isUnarmed()
+ local unarmed = true
+ if not self:getInven("MAINHAND") or not self:getInven("OFFHAND") then return end
+ local weapon = self:getInven("MAINHAND")[1]
+ local offweapon = self:getInven("OFFHAND")[1]
+ if weapon or offweapon then
+ unarmed = false
+ end
+ return unarmed
+end
+
--- Check if the actor dual wields
function _M:hasDualWeapon()
if self:attr("disarmed") then
@@ -851,3 +931,106 @@
end
return mount
end
+
+-- Unarmed Combat; this handles grapple checks and building combo points
+
+-- Builds Comob; reduces the cooldown on all unarmed abilities on cooldown by one
+function _M:buildCombo()
+
+ local duration = 3
+ local power = 1
+ -- Combo String bonuses
+ if self:knowTalent(self.T_COMBO_STRING) then
+ local t= self:getTalentFromId(self.T_COMBO_STRING)
+ if rng.percent(t.getChance(self, t)) then
+ power = 2
+ end
+ duration = 3 + math.ceil(t.getDuration(self, t))
+ end
+ -- Relentless Strike bonus
+ if self:hasEffect(self.EFF_RELENTLESS_STRIKES) then
+ for tid, cd in pairs(self.talents_cd) do
+ local tt = self:getTalentFromId(tid)
+ if tt.type[1]:find("^technique/") then
+ self.talents_cd[tid] = cd - 1
+ end
+ end
+ end
+
+ self:setEffect(self.EFF_COMBO, duration, {power=power})
+
+end
+
+function _M:getCombo(combo)
+ local combo = 0
+ local p = self:hasEffect(self.EFF_COMBO)
+ if p then
+ combo = p.cur_power
+ end
+ return combo
+end
+
+function _M:clearCombo()
+ if self:hasEffect(self.EFF_COMBO) then
+ self:removeEffect(self.EFF_COMBO)
+ end
+end
+
+-- Check to see if the target is already being grappled; many talents have extra effects on grappled targets
+function _M:isGrappled(source)
+ local p = self:hasEffect(self.EFF_GRAPPLED)
+ if p and p.src == source then
+ return true
+ else
+ return false
+ end
+end
+
+-- Breaks active grapples; called by a few talents that involve a lot of movement
+function _M:breakGrapples()
+ if self:hasEffect(self.EFF_GRAPPLING) then
+ -- deactivating GRAPPLING will clear the target's Grappled effect as well
+ self:removeEffect(self.EFF_GRAPPLING)
+ end
+end
+
+-- grapple size check; compares attackers size and targets size
+function _M:grappleSizeCheck(target)
+ size = target.size_category - self.size_category
+ if size > 1 then
+ game.logSeen(target, "%s fails because %s is too big!", self.name:capitalize(), target.name:capitalize())
+ return true
+ else
+ return false
+ end
+end
+
+-- Starts the grapple
+function _M:startGrapple(target)
+ -- pulls boosted grapple effect from the clinch talent if known
+ if self:knowTalent(self.T_CLINCH) then
+ local t = self:getTalentFromId(self.T_CLINCH)
+ power = t.getPower(self, t)
+ duration = t.getDuration(self, t)
+ hitbonus = self:getTalentLevel(t)/2
+ else
+ power = 5
+ duration = 4
+ hitbonus = 0
+ end
+ -- Breaks the grapple before reapplying
+ if self:hasEffect(self.EFF_GRAPPLING) then
+ -- deactivating GRAPPLING will clear the targets Grappled effect and various holds
+ self:removeEffect(self.EFF_GRAPPLING, true)
+ target:setEffect(target.EFF_GRAPPLED, duration, {src=self, power=power}, true)
+ self:setEffect(self.EFF_GRAPPLING, duration, {src=target}, true)
+ return true
+ elseif target:checkHit(self:combatAttackStr(), target:combatPhysicalResist(), 0, 95, 5 - hitbonus) and target:canBe("pin") then
+ target:setEffect(target.EFF_GRAPPLED, duration, {src=self, power=power})
+ self:setEffect(self.EFF_GRAPPLING, duration, {src=target}, true)
+ return true
+ else
+ game.logSeen(target, "%s resists the grapple!", target.name:capitalize())
+ return false
+ end
+end
\ No newline at end of file
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/birth/classes/warrior.lua
--- a/game/modules/tome/data/birth/classes/warrior.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/birth/classes/warrior.lua Fri Mar 25 19:27:01 2011 -0500
@@ -30,6 +30,7 @@
__ALL__ = "disallow",
Fighter = "allow",
Berserker = "allow",
+ Brawler = "allow",
["Arcane Blade"] = "allow",
},
},
@@ -174,3 +175,51 @@
life_rating = 2,
},
}
+
+newBirthDescriptor{
+ type = "subclass",
+ name = "Brawler",
+ desc = {
+ "Rather a pit-fighter, a boxer, or just a practitioner the brawler has learned to use his armored fists as weapons just as deadly as any blade.",
+ "Many of the brawler's abilities will earn combo points which they can use on finishing moves that will have added effect.",
+ "The unarmed fighting styles the brawler uses rely on maneuverability and having both hands available, as such they may not be practiced in massive armor or while a weapon or shield is equipped.",
+ "Their most important stats are: Strength, Dexterity, and Cunning",
+ "#GOLD#Stat modifiers:",
+ "#LIGHT_BLUE# * +3 Strength, +3 Dexterity, +0 Constitution",
+ "#LIGHT_BLUE# * +0 Magic, +0 Willpower, +3 Cunning",
+ },
+ stats = { str=3, dex=3, cun=3},
+ talents_types = {
+ ["cunning/survival"]={false, 0},
+ ["technique/combat-training"]={true, 0.1},
+ ["technique/field-control"]={false, 0.3},
+ ["technique/combat-techniques-active"]={false, 0},
+ ["technique/pugilism"]={true, 0.3},
+ -- ["technique/kick-boxing"]={false, 0.3},
+ ["technique/finishing-moves"]={true, 0.3},
+ ["technique/grappling"]={true, 0.3},
+ ["technique/martial-arts"]={false, 0.3},
+ ["cunning/tactical"]={true, 0.3},
+ ["technique/unarmed-training"]={true, 0.3},
+ ["technique/conditioning"]={true, 0.3},
+
+ },
+ talents = {
+ [ActorTalents.T_UPPERCUT] = 1,
+ [ActorTalents.T_DOUBLE_STRIKE] = 1,
+ [ActorTalents.T_WEAPON_COMBAT] = 1,
+ [ActorTalents.T_HEAVY_ARMOUR_TRAINING] = 1,
+
+ -- base monk attack
+ [ActorTalents.T_EMPTY_HAND] = 1,
+ },
+ copy = {
+ resolvers.equip{ id=true,
+ {type="armor", subtype="hands", name="iron gauntlets", autoreq=true},
+ {type="armor", subtype="heavy", name="iron mail armour", autoreq=true},
+ },
+ },
+ copy_add = {
+ life_rating = 2,
+ },
+}
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/damage_types.lua
--- a/game/modules/tome/data/damage_types.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/damage_types.lua Fri Mar 25 19:27:01 2011 -0500
@@ -635,7 +635,7 @@
target:knockback(src.x, src.y, dam.dist)
game.logSeen(target, "%s is knocked back!", target.name:capitalize())
else
- game.logSeen(target, "%s resists the punch!", target.name:capitalize())
+ game.logSeen(target, "%s resists the knockback!", target.name:capitalize())
end
end
end,
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/general/objects/boss-artifacts.lua
--- a/game/modules/tome/data/general/objects/boss-artifacts.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/general/objects/boss-artifacts.lua Fri Mar 25 19:27:01 2011 -0500
@@ -753,6 +753,15 @@
inc_stats = { [Stats.STAT_WIL] = 3, },
resists = { [DamageType.FIRE]= 10, },
inc_damage = { [DamageType.FIRE]= 5, },
+ combat = {
+ dam = 10,
+ apr = 1,
+ physcrit = 7,
+ physspeed = -0.4,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ damtype = DamageType.FIRE,
+ damrange = 1.2,
+ },
},
max_power = 24, power_regen = 1,
use_talent = { id = Talents.T_RITCH_FLAMESPITTER_BOLT, level = 2, power = 6 },
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/general/objects/egos/gloves.lua
--- a/game/modules/tome/data/general/objects/egos/gloves.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/general/objects/egos/gloves.lua Fri Mar 25 19:27:01 2011 -0500
@@ -18,6 +18,7 @@
-- darkgod@te4.org
local Stats = require "engine.interface.ActorStats"
local DamageType = require "engine.DamageType"
+local Talents = require("engine.interface.ActorTalents")
newEntity{
power_source = {technique=true},
@@ -39,6 +40,9 @@
wielder = {
combat_spellcrit = resolvers.mbonus_material(15, 5, function(e, v) return v * 1.4 end),
combat_physcrit = resolvers.mbonus_material(15, 5, function(e, v) return v * 1.4 end),
+ combat = {
+ physcrit = resolvers.mbonus_material(10, 4, function(e, v) return v * 0.4 end),
+ },
},
}
@@ -51,6 +55,9 @@
cost = 25,
wielder = {
combat_critical_power = resolvers.mbonus_material(35, 5, function(e, v) return v * 2, v end),
+ combat = {
+ physcrit = resolvers.mbonus_material(10, 4, function(e, v) return v * 0.4 end),
+ },
},
}
@@ -62,6 +69,9 @@
cost = 5,
wielder = {
combat_atk = resolvers.mbonus_material(15, 10, function(e, v) return v * 1 end),
+ combat = {
+ atk = resolvers.mbonus_material(10, 4, function(e, v) return v * 0.4 end),
+ },
},
}
@@ -73,6 +83,9 @@
cost = 10,
wielder = {
combat_dam = resolvers.mbonus_material(15, 5, function(e, v) return v * 3 end),
+ combat = {
+ dam = resolvers.mbonus_material(7, 3, function(e, v) return v * 3 end),
+ },
},
}
@@ -85,6 +98,9 @@
wielder = {
inc_damage={ [DamageType.FIRE] = resolvers.mbonus_material(8, 3, function(e, v) return v * 0.8 end), },
resists = { [DamageType.FIRE] = resolvers.mbonus_material(5, 5, function(e, v) return v * 0.15 end), },
+ combat = {
+ melee_project={[DamageType.FIRE] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.64 end)},
+ },
},
}
@@ -97,6 +113,9 @@
wielder = {
inc_damage={ [DamageType.COLD] = resolvers.mbonus_material(8, 3, function(e, v) return v * 0.8 end), },
resists = { [DamageType.COLD] = resolvers.mbonus_material(5, 5, function(e, v) return v * 0.15 end), },
+ combat = {
+ melee_project={[DamageType.ICE] = resolvers.mbonus_material(15, 4, function(e, v) return v * 0.64 end)},
+ },
},
}
@@ -109,6 +128,9 @@
wielder = {
inc_damage={ [DamageType.ACID] = resolvers.mbonus_material(8, 3, function(e, v) return v * 0.8 end), },
resists = { [DamageType.ACID] = resolvers.mbonus_material(5, 5, function(e, v) return v * 0.15 end), },
+ combat = {
+ melee_project={[DamageType.ACID] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.64 end)},
+ },
},
}
@@ -121,6 +143,9 @@
wielder = {
inc_damage={ [DamageType.LIGHTNING] = resolvers.mbonus_material(8, 3, function(e, v) return v * 0.8 end), },
resists = { [DamageType.LIGHTNING] = resolvers.mbonus_material(5, 5, function(e, v) return v * 0.15 end), },
+ combat = {
+ melee_project={[DamageType.LIGHTNING] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.64 end)},
+ },
},
}
newEntity{
@@ -132,6 +157,9 @@
wielder = {
inc_damage={ [DamageType.TEMPORAL] = resolvers.mbonus_material(8, 3, function(e, v) return v * 0.8 end), },
resists = { [DamageType.TEMPORAL] = resolvers.mbonus_material(5, 5, function(e, v) return v * 0.15 end), },
+ combat = {
+ melee_project={[DamageType.TEMPORAL] = resolvers.mbonus_material(15, 4, function(e, v) return v * 0.64 end)},
+ },
},
}
@@ -144,6 +172,9 @@
wielder = {
inc_damage={ [DamageType.NATURE] = resolvers.mbonus_material(8, 3, function(e, v) return v * 0.8 end), },
resists = { [DamageType.NATURE] = resolvers.mbonus_material(5, 5, function(e, v) return v * 0.15 end), },
+ combat = {
+ melee_project={[DamageType.SLIME] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.64 end)},
+ },
},
}
@@ -156,6 +187,9 @@
wielder = {
inc_damage={ [DamageType.BLIGHT] = resolvers.mbonus_material(8, 3, function(e, v) return v * 0.8 end), },
resists = { [DamageType.BLIGHT] = resolvers.mbonus_material(5, 5, function(e, v) return v * 0.15 end), },
+ combat = {
+ melee_project={[DamageType.BLIGHT] = resolvers.mbonus_material(25, 4, function(e, v) return v * 0.64 end)},
+ },
},
}
@@ -167,6 +201,9 @@
cost = 5,
wielder = {
inc_damage={ [DamageType.PHYSICAL] = resolvers.mbonus_material(8, 3, function(e, v) return v * 0.8 end), },
+ combat = {
+ dam = resolvers.mbonus_material(7, 3, function(e, v) return v * 3 end),
+ },
},
}
@@ -178,6 +215,9 @@
cost = 4,
wielder = {
inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material(4, 2, function(e, v) return v * 3 end) },
+ combat = {
+ dam = resolvers.mbonus_material(7, 3, function(e, v) return v * 3 end),
+ },
},
}
@@ -187,8 +227,14 @@
level_range = {1, 50},
rarity = 6,
cost = 4,
+ unarmed_combat = {
+ physcrit = resolvers.mbonus_material(10, 4, function(e, v) return v * 0.4 end),
+ },
wielder = {
inc_stats = { [Stats.STAT_DEX] = resolvers.mbonus_material(4, 2, function(e, v) return v * 3 end) },
+ combat = {
+ physcrit = resolvers.mbonus_material(10, 4, function(e, v) return v * 0.4 end),
+ },
},
}
@@ -210,6 +256,7 @@
rarity = 9,
cost = 15,
wielder = {
+ talent_cd_reduction={[Talents.T_CLINCH]=2},
inc_stats = { [Stats.STAT_STR] = resolvers.mbonus_material(2, 2, function(e, v) return v * 3 end) },
disarm_immune = resolvers.mbonus_material(4, 4, function(e, v) v=v/10 return v * 8, v end),
},
@@ -244,6 +291,10 @@
[Stats.STAT_DEX] = resolvers.mbonus_material(3, 2, function(e, v) return v * 3 end),
},
combat_apr = resolvers.mbonus_material(4, 4, function(e, v) return v * 0.3 end),
+ combat = {
+ physcrit = resolvers.mbonus_material(10, 4, function(e, v) return v * 0.4 end),
+ atk = resolvers.mbonus_material(10, 2, function(e, v) return v * 0.3 end),
+ },
},
}
@@ -276,6 +327,10 @@
},
max_life=resolvers.mbonus_material(40, 40, function(e, v) return v * 0.1 end),
combat_armor = resolvers.mbonus_material(3, 3, function(e, v) return v * 1 end),
+ combat = {
+ dam = resolvers.mbonus_material(7, 3, function(e, v) return v * 0.3 end),
+ atk = resolvers.mbonus_material(10, 2, function(e, v) return v * 0.3 end),
+ },
},
}
@@ -309,7 +364,31 @@
[Stats.STAT_CUN] = resolvers.mbonus_material(3, 2, function(e, v) return v * 3 end),
},
combat_atk = resolvers.mbonus_material(5, 5, function(e, v) return v * 1 end),
+ combat = {
+ apr = resolvers.mbonus_material(8, 1, function(e, v) return v * 0.3 end),
+ atk = resolvers.mbonus_material(10, 2, function(e, v) return v * 0.3 end),
+ },
},
-
}
+newEntity{
+ power_source = {technique=true},
+ name = "brawler's ", prefix=true, instant_resolve=true,
+ level_range = {40, 50},
+ greater_ego = 1,
+ rarity = 20,
+ cost = 75,
+ wielder = {
+ talent_cd_reduction={ [Talents.T_DOUBLE_STRIKE]=1, },
+ inc_stats = {
+ [Stats.STAT_STR] = resolvers.mbonus_material(3, 2, function(e, v) return v * 3 end),
+ [Stats.STAT_DEX] = resolvers.mbonus_material(3, 2, function(e, v) return v * 3 end),
+ [Stats.STAT_CUN] = resolvers.mbonus_material(3, 2, function(e, v) return v * 3 end),
+ },
+ combat = {
+ physcrit = resolvers.mbonus_material(10, 4, function(e, v) return v * 0.4 end),
+ atk = resolvers.mbonus_material(10, 2, function(e, v) return v * 0.3 end),
+ physspeed = -0.1,
+ },
+ },
+}
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/general/objects/gauntlets.lua
--- a/game/modules/tome/data/general/objects/gauntlets.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/general/objects/gauntlets.lua Fri Mar 25 19:27:01 2011 -0500
@@ -30,6 +30,7 @@
encumber = 1.5,
rarity = 9,
metallic = true,
+ combat = { talented = "unarmed" ,},
desc = [[Metal gloves protecting the hands up to the middle of the lower arm.]],
randart_able = { attack=10, physical=10, spell=10, def=40, misc=30 },
egos = "/data/general/objects/egos/gloves.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -42,6 +43,14 @@
material_level = 1,
wielder = {
combat_armor = 1,
+ combat = {
+ dam = resolvers.rngavg(7, 12),
+ apr = 4,
+ physcrit = 1,
+ physspeed = -0.2,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ damrange = 1.4,
+ },
},
}
@@ -52,6 +61,14 @@
material_level = 3,
wielder = {
combat_armor = 2,
+ combat = {
+ dam = resolvers.rngavg(16, 22),
+ apr = 7,
+ physcrit = 1,
+ physspeed = -0.2,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ damrange = 1.4,
+ },
},
}
@@ -62,5 +79,13 @@
material_level = 5,
wielder = {
combat_armor = 3,
+ unarmed_combat = {
+ dam = resolvers.rngavg(25, 32),
+ apr = 10,
+ physcrit = 3,
+ physspeed = -0.2,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ damrange = 1.4,
+ },
},
}
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/general/objects/gloves.lua
--- a/game/modules/tome/data/general/objects/gloves.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/general/objects/gloves.lua Fri Mar 25 19:27:01 2011 -0500
@@ -28,6 +28,7 @@
image = resolvers.image_material("gloves", "leather"),
encumber = 1,
rarity = 9,
+ unarmed_combat = { talented = "unarmed", damrange = 1.4, sound = "actions/melee", sound_miss = "actions/melee_miss", },
desc = [[Light gloves which do not seriously hinder finger movements, while still protecting the hands somewhat.]],
randart_able = { attack=10, physical=10, spell=10, def=30, misc=10 },
egos = "/data/general/objects/egos/gloves.lua", egos_chance = { prefix=resolvers.mbonus(40, 5), suffix=resolvers.mbonus(40, 5) },
@@ -40,6 +41,14 @@
material_level = 1,
wielder = {
combat_armor = 1,
+ combat = {
+ dam = resolvers.rngavg(5, 8),
+ apr = 1,
+ physcrit = 4,
+ physspeed = -0.4,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ damrange = 1.2,
+ },
},
}
@@ -50,6 +59,14 @@
material_level = 3,
wielder = {
combat_armor = 2,
+ combat = {
+ dam = resolvers.rngavg(14, 18),
+ apr = 1,
+ physcrit = 7,
+ physspeed = -0.4,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ damrange = 1.2,
+ },
},
}
@@ -60,5 +77,13 @@
material_level = 5,
wielder = {
combat_armor = 3,
+ combat = {
+ dam = resolvers.rngavg(23, 28),
+ apr = 3,
+ physcrit = 10,
+ physspeed = -0.4,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ damrange = 1.2,
+ },
},
}
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/general/objects/world-artifacts.lua
--- a/game/modules/tome/data/general/objects/world-artifacts.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/general/objects/world-artifacts.lua Fri Mar 25 19:27:01 2011 -0500
@@ -1091,10 +1091,19 @@
cost = 150,
material_level = 3,
wielder = {
+ talent_cd_reduction={[Talents.T_CLINCH]=2},
inc_stats = { [Stats.STAT_CON] = 4 },
disarm_immune=0.3,
knockback_immune=0.3,
stun_immune=0.3,
+ combat = {
+ dam = 18,
+ apr = 1,
+ physcrit = 7,
+ physspeed = -0.4,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ damrange = 1.2
+ },
},
}
@@ -1114,6 +1123,15 @@
combat_physcrit = 10,
combat_spellcrit = 10,
combat_critical_power = 50,
+ combat = {
+ dam = 35,
+ apr = 10,
+ physcrit = 10,
+ physspeed = -0.2,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ melee_project={[DamageType.ARCANE] = 20},
+ damrange = 1.4
+ },
},
}
@@ -1132,6 +1150,15 @@
resists = { [DamageType.COLD]= 10, [DamageType.LIGHTNING] = 10, },
knockback_immune = 0.5,
max_life = 60,
+ combat = {
+ dam = 16,
+ apr = 1,
+ physcrit = 4,
+ physspeed = -0.4,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ melee_project={ [DamageType.COLD] = 10, [DamageType.LIGHTNING] = 10, },
+ damrange = 1.2
+ },
},
max_power = 6, power_regen = 1,
use_talent = { id = Talents.T_THROW_BOULDER, level = 2, power = 6 },
@@ -1155,6 +1182,16 @@
resists_cap = { [DamageType.LIGHTNING] = 5 },
combat_spellcrit = 5,
combat_critical_power = 20,
+ combat = {
+ dam = 22,
+ apr = 10,
+ physcrit = 4,
+ physspeed = -0.2,
+ dammod = {dex=0.4, str=-0.6, cun=0.4 },
+ melee_project={ [DamageType.LIGHTNING] = 20, },
+ talent_on_hit = { [Talents.T_LIGHTNING] = {level=3, chance=10} },
+ damrange = 1.4
+ },
},
max_power = 16, power_regen = 1,
use_talent = { id = Talents.T_CHAIN_LIGHTNING, level = 3, power = 16 },
@@ -1838,16 +1875,28 @@
desc = [[Fashioned in ancient times by cultists of Harkor'Zun, these heavy granite gauntlets were designed to protect the wearer from the wrath of their dark master.]],
level_range = {26, 31},
rarity = 210,
- encumber = 14,
+ encumber = 7,
metallic = false,
cost = 150,
- material_level = 4,
+ material_level = 3,
wielder = {
- fatigue = 20,
- resists = {[DamageType.ACID] = 20},
- resists = {[DamageType.PHYSICAL] = 10},
- resists_cap = {[DamageType.ACID] = 5},
- resists_cap = {[DamageType.PHYSICAL] = 5},
+ talent_cd_reduction={
+ [Talents.T_CLINCH]=2,
+ [Talents.T_CRUSHING_HOLD]=2,
+ },
+ fatigue = 10,
+ inc_damage = { [DamageType.PHYSICAL]=5, [DamageType.ACID]=10, },
+ resists = {[DamageType.ACID] = 20, [DamageType.PHYSICAL] = 10, },
+ resists_cap = {[DamageType.ACID] = 10, [DamageType.PHYSICAL] = 5, },
+ combat = {
+ dam = 26,
+ apr = 15,
+ physcrit = 5,
+ physspeed = 1,
+ dammod = {dex=0.3, str=-0.4, cun=0.3 },
+ melee_project={[DamageType.ACID] = 10},
+ damrange = 1.4,
+ },
},
}
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents.lua
--- a/game/modules/tome/data/talents.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/talents.lua Fri Mar 25 19:27:01 2011 -0500
@@ -25,6 +25,7 @@
if engine.interface.ActorTalents.talents_types_def[t.type[1]].generic then t.generic = true end
if engine.interface.ActorTalents.talents_types_def[t.type[1]].no_silence then t.no_silence = true end
if engine.interface.ActorTalents.talents_types_def[t.type[1]].is_spell then t.is_spell = true end
+ if engine.interface.ActorTalents.talents_types_def[t.type[1]].is_unarmed then t.is_unarmed = true end
if t.tactical then
local tacts = {}
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/chronomancy/energy.lua
--- a/game/modules/tome/data/talents/chronomancy/energy.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/talents/chronomancy/energy.lua Fri Mar 25 19:27:01 2011 -0500
@@ -137,7 +137,7 @@
-- Go through all sustained spells
for tid, act in pairs(target.sustain_talents) do
local talent = target:getTalentFromId(tid)
- if talent.is_spell then
+ if talent.is_spell then
effs[#effs+1] = {"talent", tid}
end
end
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/chronomancy/timetravel.lua
--- a/game/modules/tome/data/talents/chronomancy/timetravel.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/talents/chronomancy/timetravel.lua Fri Mar 25 19:27:01 2011 -0500
@@ -34,8 +34,8 @@
target = function(self, t)
return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
end,
- getDamage = function(self, t) return (self:combatTalentSpellDamage(t, 10, 120)*getParadoxModifier(self, pm)) end,
- getPercent = function(self, t) return (30 + (self:combatTalentSpellDamage(t, 10, 30)*getParadoxModifier(self, pm))) / 100 end,
+ getDamage = function(self, t) return (self:combatTalentSpellDamage(t, 18, 160)*getParadoxModifier(self, pm)) end,
+ getPercent = function(self, t) return (10 + (self:combatTalentSpellDamage(t, 1, 10))) / 100 end,
action = function(self, t)
local tg = self:getTalentTarget(t)
self:project(tg, self.x, self.y, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t)))
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/cunning/cunning.lua
--- a/game/modules/tome/data/talents/cunning/cunning.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/talents/cunning/cunning.lua Fri Mar 25 19:27:01 2011 -0500
@@ -26,6 +26,7 @@
newTalentType{ allow_random=true, type="cunning/lethality", name = "lethality", description = "How to make your foes feel the pain." }
newTalentType{ allow_random=true, type="cunning/shadow-magic", name = "shadow magic", description = "Blending magic and shadows." }
newTalentType{ allow_random=true, type="cunning/survival", name = "survival", generic = true, description = "The knowledge of the dangers of the world, and how to best avoid them." }
+newTalentType{ allow_random=true, type="cunning/tactical", name = "tactical", description = "Tactical combat abilities." }
-- Generic requires for cunning based on talent level
cuns_req1 = {
@@ -53,5 +54,6 @@
load("/data/talents/cunning/traps.lua")
load("/data/talents/cunning/dirty.lua")
load("/data/talents/cunning/lethality.lua")
+load("/data/talents/cunning/tactical.lua")
load("/data/talents/cunning/survival.lua")
load("/data/talents/cunning/shadow-magic.lua")
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/cunning/tactical.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/game/modules/tome/data/talents/cunning/tactical.lua Fri Mar 25 19:27:01 2011 -0500
@@ -0,0 +1,159 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 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 .
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+local function getStrikingStyle(self, dam)
+ local dam = 0
+ if self:isTalentActive(self.T_STRIKING_STANCE) then
+ local t = self:getTalentFromId(self.T_STRIKING_STANCE)
+ dam = t.getDamage(self, t)
+ end
+ return dam / 100
+end
+
+newTalent{
+ name = "Tactical Expert",
+ type = {"cunning/tactical", 1},
+ require = cuns_req1,
+ mode = "passive",
+ points = 5,
+ getDefense = function(self, t) return self:getTalentLevel(t) * 2 end,
+ getMaximum = function(self, t) return (4 + (self:getTalentLevel(t) * self:getCun()) / 6) end,
+ do_tact_update = function (self, t)
+ local nb_foes = 0
+ local act
+ for i = 1, #self.fov.actors_dist do
+ act = self.fov.actors_dist[i]
+ if self:reactionToward(act) < 0 and self:canSee(act) and act["__sqdist"] <= 2 then nb_foes = nb_foes + 1 end
+ end
+
+ local defense = nb_foes * t.getDefense(self, t)
+
+ if defense <= t.getMaximum(self, t) then
+ defense = defense
+ else
+ defense = t.getMaximum(self, t)
+ end
+
+ return defense
+ end,
+ info = function(self, t)
+ local defense = t.getDefense(self, t)
+ local maximum = t.getMaximum(self, t)
+ return ([[Your defense is increased by %d for every visible foe that is adjacent too you up to a maximum of +%d defense.
+ The maximum defense increase will scale with the cunning stat.]]):format(defense, maximum)
+ end,
+}
+
+newTalent{
+ name = "Counter Attack",
+ type = {"cunning/tactical", 2},
+ require = cuns_req2,
+ mode = "passive",
+ points = 5,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.8, 1.3) + getStrikingStyle(self, dam) end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t) * 100
+ return ([[When you avoid a melee blow you have a %d%% chance to get a free, automatic melee attack against your foe for %d%% damage.
+ The is considered a strike for the purpose of stance damage bonuses (if you have any).
+ The chance of countering increases with the cunning stat.]]):format(self:getTalentLevel(t) * (5 + self:getCun(5)), damage)
+ end,
+}
+
+newTalent{
+ name = "Set Up",
+ type = {"cunning/tactical", 3},
+ require = cuns_req3,
+ points = 5,
+ random_ego = "utility",
+ cooldown = 12,
+ stamina = 12,
+ tactical = { DISABLE = 1, DEFEND = 2 },
+ getPower = function(self, t) return 5 + self:combatTalentStatDamage(t, "cun", 1, 25) end,
+ getDuration = function(self, t) return 2 + math.ceil(self:getTalentLevel(t)) end,
+ getDefense = function(self, t) return 5 + self:combatTalentStatDamage(t, "cun", 1, 50) end,
+ action = function(self, t)
+
+ self:setEffect(self.EFF_DEFENSIVE_MANEUVER, t.getDuration(self, t), {power=t.getDefense(self, t)})
+
+ return true
+ end,
+ info = function(self, t)
+ local duration = t.getDuration(self, t)
+ local power = t.getPower(self, t)
+ local defense = t.getDefense(self, t)
+ return ([[Increases defense by %d for %d turns. When you avoid a melee blow you set the target up, increasing the chance of you landing a critical strike on them by %d%% and reducing their saving throws by %d.
+ The defense increase will scale with the cunning stat.]])
+ :format(defense, duration, power, power)
+ end,
+}
+
+--[=[newTalent{
+ name = "Sprint",
+ type = {"cunning/tactical", 2},
+ require = cuns_req2,
+ points = 5,
+ cooldown = 24,
+ stamina = 12,
+ tactical = { CLOSEIN = 2, ESCAPE = 2 },
+ no_energy = true,
+ getMovement = function(self, t) return 1 - 1 / (1 + (100)/ 100) end,
+ getDuration = function(self, t) return 4 + math.ceil(self:getTalentLevel(t)) end,
+ action = function(self, t)
+
+ self:setEffect(self.EFF_SPRINT, t.getDuration(self, t), {power=t.getMovement(self, t)})
+
+ return true
+ end,
+ info = function(self, t)
+ local movement = t.getMovement(self, t)
+ local duration = t.getDuration(self, t)
+ return ([[Increases movement speed by %d%% for %d turns.
+ Activating this talent takes no time]]):
+ format(movement * 100, duration)
+ end,
+}]=]
+
+newTalent{
+ name = "Exploit Weakness",
+ type = {"cunning/tactical", 4},
+ require = cuns_req4,
+ mode = "sustained",
+ points = 5,
+ cooldown = 30,
+ sustain_stamina = 30,
+ tactical = { BUFF = 2 },
+ getReductionMax = function(self, t) return 7 * self:getTalentLevel(t) end,
+ do_weakness = function(self, t, target)
+ target:setEffect(target.EFF_WEAKENED_DEFENSES, 3, {inc = - 5, max = - t.getReductionMax(self, t)})
+ end,
+ activate = function(self, t)
+ return {
+ dam = self:addTemporaryValue("inc_damage", {[DamageType.PHYSICAL]=-10}),
+ }
+ end,
+ deactivate = function(self, t, p)
+ self:removeTemporaryValue("inc_damage", p.dam)
+ return true
+ end,
+ info = function(self, t)
+ local reduction = t.getReductionMax(self, t)
+ return ([[Systematically find the weaknesses in your opponents physical resists at the cost of 10%% of your physical damage. Each time you hit an opponenet with a melee attack you reduce their physical resistance by 5%% up to a maximum of %d%%.
+ ]]):format(reduction)
+ end,
+}
\ No newline at end of file
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/techniques/conditioning.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/game/modules/tome/data/talents/techniques/conditioning.lua Fri Mar 25 19:27:01 2011 -0500
@@ -0,0 +1,103 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 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 .
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+newTalent{
+ name = "Physical Conditioning",
+ type = {"technique/conditioning", 1},
+ require = techs_con_req1,
+ mode = "passive",
+ points = 5,
+ getArmor = function(self, t) return 4 + self:combatTalentStatDamage(t, "con", 1, 20) end,
+ getPhysical = function(self, t) return 4 + self:combatTalentStatDamage(t, "con", 1, 20) end,
+ info = function(self, t)
+ local armor = t.getArmor(self, t)
+ local saves = t.getPhysical(self, t)
+ return ([[Physical conditioning that increases armor by %d and physical saves by %d.
+ The bonuses will scale with your Constitution stat.]]):
+ format(armor, saves)
+ end,
+}
+
+newTalent{
+ name = "Firm Footing",
+ type = {"technique/conditioning", 2},
+ require = techs_con_req2,
+ mode = "passive",
+ points = 5,
+ getResists = function(self, t) return self:getTalentLevelRaw(t) * 15 end,
+ on_learn = function(self, t)
+ self:attr("knockback_immune", 0.15)
+ self:attr("pin_immune", 0.15)
+ end,
+ on_unlearn = function(self, t)
+ self:attr("knockback_immune", -0.15)
+ self:attr("pin_immune", -0.15)
+ end,
+ info = function(self, t)
+ local resists = t.getResists(self, t)
+ return ([[Increases Knockback and Pin resistance by %d%%.]]):
+ format(resists)
+ end,
+}
+
+newTalent{
+ name = "Iron Skin",
+ type = {"technique/conditioning", 3},
+ require = techs_con_req3,
+ mode = "passive",
+ points = 5,
+ getPercent = function (self, t) return self:getTalentLevel(t) * 20 end,
+ on_learn = function(self, t)
+ self:updateConDamageReduction()
+ end,
+ on_unlearn = function(self, t)
+ self:updateConDamageReduction()
+ end,
+ info = function(self, t)
+ local percent = t.getPercent(self, t)
+ return ([[You've learned to shrug off more damage then is normal. Increases your effective constitution for resist all bonuses by %d%%.]]):
+ format(percent)
+ end,
+}
+
+newTalent{
+ name = "Unflinching Resolve",
+ type = {"technique/conditioning", 4},
+ require = techs_con_req4,
+ mode = "passive",
+ points = 5,
+ getRegen = function(self, t) return self:getTalentLevel(t) * 0.05 end,
+ getResist = function(self, t) return self:getTalentLevelRaw(t) * 15 end,
+ on_hit = function(self, t, dam)
+ local power = (dam * self:getRegen(t)) / 3
+ self:setEffect(self.EFF_RECOVERY, 3, {power = power})
+ end,
+ on_learn = function(self, t)
+ self:attr("stun_immune", 0.15)
+ end,
+ on_unlearn = function(self, t)
+ self:attr("stun_immune", -0.15)
+ end,
+ info = function(self, t)
+ local resist = t.getResist(self, t)
+ local regen = t.getRegen(self, t)
+ return ([[After being hit for 10%% or more of your maximum life in a single blow you recover %d%% of the damage over three turns. Additionally your stun immunity is increased by %d%%.]]):
+ format(regen * 100, resist)
+ end,
+}
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/techniques/finishing-moves.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/game/modules/tome/data/talents/techniques/finishing-moves.lua Fri Mar 25 19:27:01 2011 -0500
@@ -0,0 +1,216 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 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 .
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+newTalent{
+ name = "Uppercut",
+ type = {"technique/finishing-moves", 1},
+ require = techs_dex_req1,
+ points = 5,
+ random_ego = "attack",
+ cooldown = function(self, t) return math.floor(16 - self:getTalentLevelRaw(t) * 2) end,
+ stamina = 10,
+ message = "@Source@ throws a finishing uppercut.",
+ tactical = { ATTACK = 2, DISABLE = 2 },
+ requires_target = true,
+ on_pre_use = function(self, t, silent) if not self:hasEffect(self.EFF_COMBO) then if not silent then game.logPlayer(self, "You must have a combo going to use this ability.") end return false end return true end,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.1, 1.5) end,
+ getDuration = function(self, t) return 2 + (self:getCombo(combo)) 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
+
+ -- breaks active grapples if the target is not grappled
+ if target:isGrappled(self) then
+ grappled = true
+ else
+ self:breakGrapples()
+ end
+
+ local hit = self:attackTarget(target, nil, t.getDamage(self, t), true)
+
+ if hit then
+ if target:checkHit(self:combatAttackStr(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("stun") then
+ target:setEffect(target.EFF_STUNNED, t.getDuration(self, t), {})
+ else
+ game.logSeen(target, "%s resists the stun!", target.name:capitalize())
+ end
+ end
+
+ self:clearCombo()
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t) * 100
+ return ([[A finishing uppercut that deals %d%% damage and attempts to stun your target for 2 turns + 1 turn per combo point you have.
+ The stun chance will improve with the strength stat.
+ Using this talent removes your combo points.]])
+ :format(damage)
+ end,
+}
+
+newTalent{
+ name = "Spinning Backhand",
+ type = {"technique/finishing-moves", 2},
+ require = techs_dex_req2,
+ points = 5,
+ random_ego = "attack",
+ cooldown = function(self, t) return math.floor(16 - self:getTalentLevelRaw(t) * 2) end,
+ stamina = 12,
+ range = function(self, t) return 1 + (self:getCombo(combo) or 0) end,
+ message = "@Source@ lashes out with a spinning backhand.",
+ tactical = { ATTACKAREA = 2, CLOSEIN = 1 },
+ requires_target = true,
+ on_pre_use = function(self, t, silent) if not self:hasEffect(self.EFF_COMBO) then if not silent then game.logPlayer(self, "You must have a combo going to use this ability.") end return false end return true end,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.2, 1.7) 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)) > self:getTalentRange(t) then return nil end
+
+ -- bonus damage for charging
+ local charge = math.floor((core.fov.distance(self.x, self.y, x, y)) -1) / 10
+ local damage = t.getDamage(self, t) + charge
+
+ -- do the rush
+ local l = line.new(self.x, self.y, x, y)
+ local tx, ty = self.x, self.y
+ lx, ly = l()
+ while lx and ly do
+ if game.level.map:checkAllEntities(lx, ly, "block_move", self) then break end
+ tx, ty = lx, ly
+ lx, ly = l()
+ end
+
+ local ox, oy = self.x, self.y
+ self:move(tx, ty, true)
+ if config.settings.tome.smooth_move > 0 then
+ self:resetMoveAnim()
+ self:setMoveAnim(ox, oy, 8, 5)
+ end
+
+ -- do the backhand
+ if math.floor(core.fov.distance(self.x, self.y, x, y)) == 1 then
+ -- get left and right side
+ local dir = util.getDir(x, y, self.x, self.y)
+ local lx, ly = util.coordAddDir(self.x, self.y, dir_sides[dir].left)
+ local rx, ry = util.coordAddDir(self.x, self.y, dir_sides[dir].right)
+ local lt, rt = game.level.map(lx, ly, Map.ACTOR), game.level.map(rx, ry, Map.ACTOR)
+
+ local hit = self:attackTarget(target, nil, damage, true)
+
+ --left hit
+ if lt then
+ hit2 = self:attackTarget(lt, nil, damage, true)
+ end
+ --right hit
+ if rt then
+ hit3 = self:attackTarget(rt, nil, damage, true)
+ end
+ end
+
+ -- remove grappls
+ self:breakGrapples()
+
+ self:clearCombo()
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t) * 100
+ return ([[Attack your foes in a frontal arc with a spinning backhand doing %d%% damage. If your not adjacent to the target you'll step forward as you spin, gaining 10%% bonus damage for each tile you move.
+ The range of this attack will increase by one per combo point you have.
+ This attack will remove any grapples you're maintaining and remove your combo points.]])
+ :format(damage)
+ end,
+}
+
+newTalent{
+ name = "Relentless Strikes",
+ type = {"technique/finishing-moves", 3},
+ require = techs_dex_req3,
+ points = 5,
+ random_ego = "utility",
+ cooldown = function(self, t) return math.floor(26 - self:getTalentLevelRaw(t) * 2) end,
+ stamina = 20,
+ tactical = { BUFF = 2 },
+ on_pre_use = function(self, t, silent) if not self:hasEffect(self.EFF_COMBO) then if not silent then game.logPlayer(self, "You must have a combo going to use this ability.") end return false end return true end,
+ getStamina = function(self, t) return self:getTalentLevel(t) * 2 end,
+ getDuration = function(self, t) return self:getCombo(combo) * 2 end,
+ action = function(self, t)
+
+ self:setEffect(self.EFF_RELENTLESS_STRIKES, t.getDuration(self, t), {power=t.getStamina(self, t)})
+
+ self:clearCombo()
+
+ return true
+ end,
+ info = function(self, t)
+ local stamina = t.getStamina(self, t)
+ return ([[Increases your stamina regen by %d per turn for a number of turns equal to double your combo points. Additionally every combo point you earn during this time will reduce the cooldown on all your techniques on cooldown by 1.
+ Using this talent removes your combo points.]])
+ :format(stamina)
+ end,
+}
+
+newTalent{
+ name = "Haymaker",
+ type = {"technique/finishing-moves", 4},
+ require = techs_dex_req4,
+ points = 5,
+ random_ego = "attack",
+ cooldown = function(self, t) return math.floor(16 - self:getTalentLevelRaw(t) * 2) end,
+ stamina = 12,
+ message = "@Source@ throws a wild haymaker!",
+ tactical = { ATTACK = 2 },
+ requires_target = true,
+ on_pre_use = function(self, t, silent) if not self:hasEffect(self.EFF_COMBO) then if not silent then game.logPlayer(self, "You must have a combo going to use this ability.") end return false end return true end,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.3, 1.7) end,
+ getBonusDamage = function(self, t) return (self:getCombo(combo))/10 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
+
+ -- breaks active grapples if the target is not grappled
+ if target:isGrappled(self) then
+ grappled = true
+ else
+ self:breakGrapples()
+ end
+
+ local damage = t.getDamage(self, t) * (1 + (t.getBonusDamage(self, t) or 0))
+
+ self:attackTarget(target, nil, damage, true)
+
+ self:clearCombo()
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t) * 100
+ return ([[A vicious finishing strike that deals %d%% damage + 10%% damage per combo point you have.
+ Using this talent removes your combo points.]])
+ :format(damage)
+ end,
+}
\ No newline at end of file
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/techniques/grappling.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/game/modules/tome/data/talents/techniques/grappling.lua Fri Mar 25 19:27:01 2011 -0500
@@ -0,0 +1,297 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 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 .
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+newTalent{
+ name = "Grappling Stance",
+ type = {"technique/unarmed-other", 1},
+ mode = "sustained",
+ hide = true,
+ points = 1,
+ cooldown = 12,
+ tactical = { BUFF = 2 },
+ type_no_req = true,
+ getSave = function(self, t) return 5 + self:getStr(20) end,
+ getDamage = function(self, t) return 20 + self:getStr(20) end,
+ activate = function(self, t)
+ cancelStances(self)
+ local ret = {
+ phys = self:addTemporaryValue("combat_physresist", t.getSave(self, t)),
+ }
+ return ret
+ end,
+ deactivate = function(self, t, p)
+ self:removeTemporaryValue("combat_physresist", p.phys)
+ return true
+ end,
+ info = function(self, t)
+ local save = t.getSave(self, t)
+ local damage = t.getDamage(self, t)
+ return ([[Increases your physical saves by %d and the damage of your grappling talents by %d%%.
+ The bonuses will scale with the strength stat.]])
+ :format(save, damage)
+ end,
+}
+
+newTalent{
+ name = "Clinch",
+ type = {"technique/grappling", 1},
+ require = techs_req1,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 6,
+ stamina = 5,
+ tactical = { ATTACK = 2, DISABLE = 2 },
+ requires_target = true,
+ getDuration = function(self, t) return 4 + math.floor(self:getTalentLevel(t)) end,
+ getPower = function(self, t) return 5 + self:combatTalentStatDamage(t, "str", 1, 50) end,
+ getDrain = function(self, t) return 6 - (self:getTalentLevelRaw(t) or 0) end,
+ -- Learn the appropriate stance
+ on_learn = function(self, t)
+ if not self:knowTalent(self.T_GRAPPLING_STANCE) then
+ self:learnTalent(self.T_GRAPPLING_STANCE, true)
+ end
+ end,
+ on_unlearn = function(self, t)
+ if not self:knowTalent(t) then
+ self:unlearnTalent(self.T_GRAPPLING_STANCE)
+ end
+ 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 grappled = false
+
+ -- force stance change
+ if target and not self:isTalentActive(self.T_GRAPPLING_STANCE) then
+ self:forceUseTalent(self.T_GRAPPLING_STANCE, {ignore_energy=true, ignore_cd = true})
+ end
+
+ -- breaks active grapples if the target is not grappled
+ if target:isGrappled(self) then
+ grappled = true
+ else
+ self:breakGrapples()
+ end
+
+ -- end the talent without effect if the target is to big
+ if self:grappleSizeCheck(target) then
+ return true
+ end
+
+ -- start the grapple
+ local hit = self:startGrapple(target)
+
+ local duration = t.getDuration(self, t)
+
+ -- do crushing hold if we know it
+ if hit and self:knowTalent(self.T_CRUSHING_HOLD) then
+ local t = self:getTalentFromId(self.T_CRUSHING_HOLD)
+ if grappled and not target.no_breath and not target.undead and target:canBe("silence") then
+ target:setEffect(target.EFF_STRANGLE_HOLD, duration, {src=self, power=t.getDamage(self, t) * 1.5})
+ else
+ target:setEffect(target.EFF_CRUSHING_HOLD, duration, {src=self, power=t.getDamage(self, t)})
+ end
+
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local duration = t.getDuration(self, t)
+ local power = t.getPower(self, t)
+ local drain = t.getDrain(self, t)
+ return ([[Grapples the target for %d turns. A grappled opponent will be unable to move and it's attack and defense will be reduced by %d. Any movement from the target or you will break the grapple. Maintaining a grapple drains %d stamina per turn.
+ You may only grapple a single target at a time and using any targeted unarmed talent on a target that you're not grappling will break the grapple.
+ The grapple attack and defense reduction as well as success chance will scale with the strength stat.
+ Performing this action will switch your stance to Grappling Stance.]])
+ :format(duration, power, drain)
+ end,
+}
+
+newTalent{
+ name = "Maim",
+ type = {"technique/grappling", 2},
+ require = techs_req2,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 12,
+ stamina = 10,
+ tactical = { ATTACK = 2, DISABLE = 2 },
+ requires_target = true,
+ getDuration = function(self, t) return 2 + math.floor(self:getTalentLevel(t)) end,
+ getDamage = function(self, t) return 10 + self:combatTalentStatDamage(t, "str", 20, 400) * (1 + getGrapplingStyle(self, dam)) end,
+ getMaim = function(self, t) return 10 + self:combatTalentStatDamage(t, "str", 5, 20) * (1 + getGrapplingStyle(self, dam)) end,
+ -- Learn the appropriate stance
+ 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 grappled = false
+
+ -- breaks active grapples if the target is not grappled
+ if target:isGrappled(self) then
+ grappled = true
+ else
+ self:breakGrapples()
+ end
+
+ -- end the talent without effect if the target is to big
+ if self:grappleSizeCheck(target) then
+ return true
+ end
+
+ local hit = self:startGrapple (target)
+
+ -- deal damage and maim if appropriate
+ if hit then
+
+ if grappled then
+ self:project(target, x, y, DamageType.PHYSICAL, self:physicalCrit(t.getDamage(self, t), nil, target))
+ target:setEffect(target.EFF_MAIMED, t.getDuration(self, t), {power=t.getMaim(self, t)})
+ else
+ self:project(target, x, y, DamageType.PHYSICAL, self:physicalCrit(t.getDamage(self, t), nil, target))
+ end
+
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local duration = t.getDuration(self, t)
+ local damage = t.getDamage(self, t)
+ local maim = t.getMaim(self, t)
+ return ([[Grapples the target and inflicts %0.2f physical damage. If the target is already grappled the target will be maimed as well, reducing attack and damage by %d and global speed by 30%% for %d turns.
+ The grapple effects will be based off your grapple talent effect if you have it and the damage will scale with the strength stat.]])
+ :format(damDesc(self, DamageType.PHYSICAL, (damage)), maim, duration)
+ end,
+}
+
+newTalent{
+ name = "Crushing Hold",
+ type = {"technique/grappling", 3},
+ require = techs_req3,
+ mode = "passive",
+ points = 5,
+ tactical = { ATTACK = 2, DISABLE = 2 },
+ requires_target = true,
+ getDamage = function(self, t) return self:combatTalentStatDamage(t, "str", 1, 200) * (1 + getGrapplingStyle(self, dam)) end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t)
+ return ([[Your clinch talent now starts a crushing hold that deals %0.2f physical damage each turn. If the target is already grappled the hold will instead become a strangle hold, silencing the target and inflicting %0.2f physical damage each turn.
+ The damage will scale with the strength stat.]])
+ :format(damDesc(self, DamageType.PHYSICAL, (damage)), damDesc(self, DamageType.PHYSICAL, (damage * 1.5)))
+ end,
+}
+
+newTalent{
+ name = "Take Down",
+ type = {"technique/grappling", 4},
+ require = techs_req4,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 24,
+ stamina = 12,
+ tactical = { ATTACK = 2, DISABLE = 2, CLOSEIN = 2 },
+ requires_target = true,
+ range = function(self, t) return 2 + math.floor(self:getTalentLevel(t)/3) end,
+ getDuration = function(self, t) return 2 + math.floor(self:getTalentLevel(t)) end,
+ getTakeDown = function(self, t) return 10 + self:combatTalentStatDamage(t, "str", 15, 250) * (1 + getGrapplingStyle(self, dam)) end,
+ getSlam = function(self, t) return 20 + self:combatTalentStatDamage(t, "str", 30, 500) * (1 + getGrapplingStyle(self, dam)) end,
+ -- Learn the appropriate stance
+ 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)) > self:getTalentRange(t) then return nil end
+
+ local grappled = false
+
+ -- do the rush
+ local l = line.new(self.x, self.y, x, y)
+ local tx, ty = self.x, self.y
+ lx, ly = l()
+ while lx and ly do
+ if game.level.map:checkAllEntities(lx, ly, "block_move", self) then break end
+ tx, ty = lx, ly
+ lx, ly = l()
+ end
+
+ local ox, oy = self.x, self.y
+ self:move(tx, ty, true)
+ if config.settings.tome.smooth_move > 0 then
+ self:resetMoveAnim()
+ self:setMoveAnim(ox, oy, 8, 5)
+ end
+
+ -- breaks active grapples if the target is not grappled
+ if target:isGrappled(self) then
+ grappled = true
+ else
+ self:breakGrapples()
+ end
+
+ if math.floor(core.fov.distance(self.x, self.y, x, y)) == 1 then
+ -- end the talent without effect if the target is to big
+ if self:grappleSizeCheck(target) then
+ return true
+ end
+
+ local hit = self:startGrapple (target)
+
+ -- takedown or slam as appropriate
+ if hit then
+
+ if grappled then
+ self:project(target, x, y, DamageType.PHYSICAL, self:physicalCrit(t.getSlam(self, t), nil, target))
+ if target:checkHit(self:combatAttackStr(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("stun") then
+ target:setEffect(target.EFF_STUNNED, t.getDuration(self, t), {})
+ else
+ game.logSeen(target, "%s resists the stun!", target.name:capitalize())
+ end
+ else
+ self:project(target, x, y, DamageType.PHYSICAL, self:physicalCrit(t.getTakeDown(self, t), nil, target))
+ if target:checkHit(self:combatAttackStr(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("stun") then
+ target:setEffect(target.EFF_DAZED, t.getDuration(self, t), {})
+ else
+ game.logSeen(target, "%s resists the daze!", target.name:capitalize())
+ end
+ end
+
+ end
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local duration = t.getDuration(self, t)
+ local takedown = t.getTakeDown(self, t)
+ local slam = t.getSlam(self, t)
+ return ([[Rushes forward and attempts to take the target to the ground, starting a grapple, inflicting %0.2f physical damage, and dazing the target for %d turns. If you're already grappling the target you'll instead slam them into the ground for %0.2f physical damage and potentially stun them for %d turns.
+ The grapple effects and duration will be based off your grapple talent effect if you have it and the damage will scale with the strength stat.]])
+ :format(damDesc(self, DamageType.PHYSICAL, (takedown)), duration, damDesc(self, DamageType.PHYSICAL, (slam)), duration)
+ end,
+}
\ No newline at end of file
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/techniques/kick-boxing.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/game/modules/tome/data/talents/techniques/kick-boxing.lua Fri Mar 25 19:27:01 2011 -0500
@@ -0,0 +1,237 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 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 .
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+newTalent{
+ name = "Push Kick",
+ type = {"unarmed/kick-boxing", 1},
+ require = mart_dex_req1,
+ points = 5,
+ cooldown = 6,
+ stamina = 6,
+ tactical = { ATTACK = 2, ESCAPE = 2 },
+ requires_target = true,
+ getDamage = function(self, t) return self:combatTalentStatDamage(t, "str", 20, 200) * (1 + getStrikingStyle(self, dam)) end,
+ getPush = function(self, t) return 1 + math.ceil(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 hit = target:checkHit(self:combatAttack(), target:combatDefense(), 0, 95, 5 - self:getTalentLevel(t) / 2)
+ -- local hit = self:attackTarget(target, nil, nil, true)
+
+ -- Try to knockback !
+ if hit then
+ local can = function(target)
+ if target:checkHit(self:combatAttack(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("knockback") then
+ self:project(target, target.x, target.y, DamageType.PHYSICAL, t.getDamage(self, t), nil, target)
+ return true
+ else
+ self:project(target, target.x, target.y, DamageType.PHYSICAL, t.getDamage(self, t), nil, target)
+ game.logSeen(target, "%s resists the knockback!", target.name:capitalize())
+ end
+
+ end
+
+ if can(target) then target:knockback(self.x, self.y, t.getPush(self, t), can) end
+
+ -- move the attacker back and build combo point
+ self:knockback(target.x, target.y, 1)
+ self:buildCombo()
+ else
+ game.logSeen(target, "%s misses %s.", self.name:capitalize(), target.name:capitalize())
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t)
+ local push =t.getPush(self, t)
+ return ([[A push kick that knocks the target back %d tiles, moves you back 1 tile, and inflicts %0.2f physical damage. If another creature is in the way that creature will be affected too. Targets knocked into other targets may take extra damage.
+ The damage will scale with the Strength stat.
+ Builds one combo point.]])
+ :format(push, damDesc(self, DamageType.PHYSICAL, (damage)))
+ end,
+}
+
+newTalent{
+ name = "Uppercut3",
+ type = {"unarmed/kick-boxing", 2},
+ require = mart_dex_req2,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 12,
+ stamina = 10,
+ tactical = { ATTACK = 2 },
+ requires_target = true,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.1, 1.5) + getStrikingStyle(self, dam) end,
+ getDamageTwo = function(self, t) return self:combatTalentWeaponDamage(t, 1.5, 2.1) + getStrikingStyle(self, dam) 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
+
+ -- extra damage vs. grappled targets
+ if target:isGrappled(self) then
+ hit = self:attackTarget(target, nil, t.getDamageTwo(self, t), true)
+ else
+ hit = self:attackTarget(target, nil, t.getDamage(self, t), true)
+ end
+
+ -- combo point
+ if hit then
+ self:buildCombo()
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t) * 100
+ local damagetwo = t.getDamageTwo(self, t) * 100
+ return ([[Attack the target with a rising knee strike that deals %d%% damage or %d%% damage against grappled targets.
+ If the attack lands it will build one combo point.]])
+ :format(damage, damagetwo)
+ end,
+}
+
+newTalent{
+ name = "Spinning Backhand3",
+ type = {"unarmed/kick-boxing", 3},
+ require = mart_dex_req3,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 18,
+ stamina = 20,
+ range = function(self, t) return 2 + math.floor(self:getTalentLevel(t)/3) end,
+ tactical = { ATTACKAREA = 2, CLOSEIN = 1 },
+ requires_target = true,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 1.7) + getStrikingStyle(self, dam) 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)) > self:getTalentRange(t) then return nil end
+
+ -- bonus damage for charging
+ local charge = math.floor((core.fov.distance(self.x, self.y, x, y)) -1) / 10
+
+ -- do the rush
+ local l = line.new(self.x, self.y, x, y)
+ local tx, ty = self.x, self.y
+ lx, ly = l()
+ while lx and ly do
+ if game.level.map:checkAllEntities(lx, ly, "block_move", self) then break end
+ tx, ty = lx, ly
+ lx, ly = l()
+ end
+
+ local ox, oy = self.x, self.y
+ self:move(tx, ty, true)
+ if config.settings.tome.smooth_move > 0 then
+ self:resetMoveAnim()
+ self:setMoveAnim(ox, oy, 8, 5)
+ end
+
+ -- do the backhand
+ if math.floor(core.fov.distance(self.x, self.y, x, y)) == 1 then
+ -- get left and right side
+ local dir = util.getDir(x, y, self.x, self.y)
+ local lx, ly = util.coordAddDir(self.x, self.y, dir_sides[dir].left)
+ local rx, ry = util.coordAddDir(self.x, self.y, dir_sides[dir].right)
+ local lt, rt = game.level.map(lx, ly, Map.ACTOR), game.level.map(rx, ry, Map.ACTOR)
+
+ local hit = self:attackTarget(target, nil, t.getDamage(self, t) + charge, true)
+ --combo point?
+ if hit then
+ self:buildCombo()
+ end
+
+ --left hit
+ if lt then
+ hit2 = self:attackTarget(lt, nil, t.getDamage(self, t) + charge, true)
+ --combo point?
+ if hit2 then
+ self:buildCombo()
+ end
+ end
+ --right hit
+ if rt then
+ hit3 = self:attackTarget(rt, nil, t.getDamage(self, t) + charge, true)
+ --combo point?
+ if hit3 then
+ self:buildCombo()
+ end
+ end
+ end
+
+ -- remove grappls
+ self:breakGrapples()
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t) * 100
+ return ([[Attack your foes in a frontal arc with a spinning backhand doing %d%% damage. If your not adjacent to the target you'll step forward as you spin, gaining 10%% bonus damage for each tile you move.
+ This attack will remove any grapples you're maintaining.
+ Earns one combo point for each target hit.]])
+ :format(damage)
+ end,
+}
+
+newTalent{
+ name = "Expert Strikes3",
+ type = {"unarmed/kick-boxing", 4},
+ require = mart_dex_req4,
+ mode = "sustained",
+ points = 5,
+ cooldown = 24,
+ sustain_stamina = 50,
+ tactical = { BUFF = 2 },
+ no_energy = true,
+ getResistPenetration = function(self, t) return 10 + self:combatTalentStatDamage(t, "dex", 10, 50) end,
+ getStaminaDrain = function(self, t) return 1 + self:getTalentLevelRaw(t) end,
+ getComboChance = function(self, t) return 20 * self:getTalentLevelRaw(t) end,
+ on_crit = function(self, t)
+ if rng.percent(t.getComboChance(self,t)) then
+ self:buildCombo()
+ end
+ end,
+ activate = function(self, t)
+ local ret = {
+ resist = self:addTemporaryValue("resists_pen", {[DamageType.PHYSICAL] = t.getResistPenetration(self, t)}),
+ stamina_regen = self:addTemporaryValue("stamina_regen", - t.getStaminaDrain(self, t)),
+ }
+ return ret
+ end,
+ deactivate = function(self, t, p)
+ self:removeTemporaryValue("resists_pen", p.resist)
+ self:removeTemporaryValue("stamina_regen", p.stamina_regen)
+ return true
+ end,
+ info = function(self, t)
+ local resistpen = t.getResistPenetration(self, t)
+ local drain = t.getStaminaDrain(self, t)
+ local combo = t.getComboChance(self, t)
+ return ([[Increases your physical resist penetration by %d%% and has a %d%% chance to grant you a combo point whenever one of your attacks is a critical hit but drains stamina quickly (-%d stamina/turn).
+ The resist penetration will scale with the Dexterity stat.]]):
+ format(resistpen, combo, drain)
+ end,
+}
\ No newline at end of file
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/techniques/martial-arts.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/game/modules/tome/data/talents/techniques/martial-arts.lua Fri Mar 25 19:27:01 2011 -0500
@@ -0,0 +1,189 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 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 .
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+-- strength, cunning, and dexterity damage combined
+local function getTriStat(self, t, low, high)
+ low = low / 3
+ high = high / 3
+ return self:combatTalentStatDamage(t, "str", low, high) + self:combatTalentStatDamage(t, "cun", low, high) + self:combatTalentStatDamage(t, "dex", low, high)
+end
+
+newTalent{
+ name = "Push Kick",
+ type = {"technique/martial-arts", 1},
+ require = techs_dex_req1,
+ points = 5,
+ cooldown = 6,
+ stamina = 12,
+ tactical = { ATTACK = 2, ESCAPE = 2 },
+ requires_target = true,
+ getDamage = function(self, t) return getTriStat(self, t, 30, 300) * (1 + getStrikingStyle(self, dam)) end,
+ getPush = function(self, t) return 1 + math.ceil(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 hit = target:checkHit(self:combatAttack(), target:combatDefense(), 0, 95, 5 - self:getTalentLevel(t) / 2)
+ -- local hit = self:attackTarget(target, nil, nil, true)
+
+ -- Try to knockback !
+ if hit then
+ local can = function(target)
+ if target:checkHit(self:combatAttack(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("knockback") then
+ self:project(target, target.x, target.y, DamageType.PHYSICAL, t.getDamage(self, t))
+ return true
+ else
+ self:project(target, target.x, target.y, DamageType.PHYSICAL, t.getDamage(self, t))
+ game.logSeen(target, "%s resists the knockback!", target.name:capitalize())
+ end
+
+ end
+
+ if can(target) then target:knockback(self.x, self.y, t.getPush(self, t), can) end
+
+ -- move the attacker back
+ self:knockback(target.x, target.y, 1)
+ self:breakGrapples()
+ self:buildCombo()
+
+ else
+ game.logSeen(target, "%s misses %s.", self.name:capitalize(), target.name:capitalize())
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t)
+ local push =t.getPush(self, t)
+ return ([[A push kick that knocks the target back %d tiles, moves you back 1 tile, and inflicts %0.2f physical damage. If another creature is in the way that creature will be affected too. Targets knocked into other targets may take extra damage.
+ This is considered a strike for the purposes of stance damage bonuses, will earn one combo point, and will break any grapples you're maintaining.
+ The damage will scale with the strength, dexterity, and cunning stats.]])
+ :format(push, damDesc(self, DamageType.PHYSICAL, (damage)))
+ end,
+}
+
+newTalent{
+ name = "Defensive Throw",
+ type = {"technique/martial-arts", 2},
+ require = techs_dex_req2,
+ mode = "passive",
+ points = 5,
+ getDamage = function(self, t) return getTriStat(self, t, 10, 100) * (1 + getGrapplingStyle(self, dam)) end,
+ getDamageTwo = function(self, t) return getTriStat(self, t, 10, 100) * (1.5 + getGrapplingStyle(self, dam)) end,
+ do_throw = function(self, target, t)
+
+ local hit = self:checkHit(self:combatAttack(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2)
+
+ -- if grappled stun
+ if hit and target:canBe("knockback") and target:isGrappled(self) then
+ self:project(target, target.x, target.y, DamageType.PHYSICAL, self:physicalCrit(t.getDamageTwo(self, t), nil, target))
+ game.logSeen(target, "%s has been slammed into the ground!", target.name:capitalize())
+ -- see if the throw stuns the enemy
+ if hit and target:canBe("stun")then
+ target:setEffect(target.EFF_STUNNED, 2, {})
+ end
+ -- if not grappled daze
+ elseif hit and target:canBe("knockback") then
+ self:project(target, target.x, target.y, DamageType.PHYSICAL, self:physicalCrit(t.getDamage(self, t), nil, target))
+ game.logSeen(target, "%s has been thrown to the ground!", target.name:capitalize())
+ -- see if the throw dazes the enemy
+ if hit and target:canBe("stun")then
+ target:setEffect(target.EFF_DAZED, 2, {})
+ end
+ end
+
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t)
+ local damagetwo = t.getDamageTwo(self, t)
+ return ([[When you avoid a melee blow you have a %d%% chance to throw the target to the ground. If the throw lands the target will take %0.2f damage and be dazed for 2 turns or %0.2f damage and be stunned for 2 turns if grappled.
+ The chance of throwing increases with the cunning stat and the damage will scale with the strength stat, dexterity, and cunning stats.
+ This is considered a grapple for the purposes of stance damage bonuses.]]):format(self:getTalentLevel(t) * (5 + self:getCun(5)), damDesc(self, DamageType.PHYSICAL, (damage)), damDesc(self, DamageType.PHYSICAL, (damagetwo)))
+ end,
+}
+
+newTalent{
+ name = "Breath Control",
+ type = {"technique/martial-arts", 3},
+ require = techs_dex_req2,
+ mode = "sustained",
+ points = 5,
+ cooldown = 30,
+ sustain_stamina = 30,
+ tactical = { BUFF = 1, STAMINA = 2 },
+ getSpeed = function(self, t) return 0.1 end,
+ getStamina = function(self, t) return self:getTalentLevel(t) * 1.5 end,
+ activate = function(self, t)
+ return {
+ speed = self:addTemporaryValue("energy", {mod = -t.getSpeed(self, t)}),
+ stamina = self:addTemporaryValue("stamina_regen", t.getStamina(self, t)),
+ }
+ end,
+ deactivate = function(self, t, p)
+ self:removeTemporaryValue("energy", p.speed)
+ self:removeTemporaryValue("stamina_regen", p.stamina)
+ return true
+ end,
+ info = function(self, t)
+ local speed = t.getSpeed(self, t)
+ local stamina = t.getStamina(self, t)
+ return ([[You focus your breathing, increasing stamina regeneration by %0.2f per turn at the cost of %d%% global speed.]]):
+ format(stamina, speed * 100)
+ end,
+}
+
+newTalent{
+ name = "Roundhouse Kick",
+ type = {"technique/martial-arts", 4},
+ require = techs_dex_req3,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 12,
+ stamina = 18,
+ range = 0,
+ radius = function(self, t) return 1 end,
+ tactical = { ATTACKAREA = 2, DISABLE = 2 },
+ requires_target = true,
+ getDamage = function(self, t) return getTriStat(self, t, 20, 600) * (1 + getStrikingStyle(self, dam)) end,
+ target = function(self, t)
+ return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
+ end,
+ action = function(self, t)
+ local tg = self:getTalentTarget(t)
+ local x, y, target = self:getTarget(tg)
+ if not x or not y then return nil end
+
+ self:breakGrapples()
+
+ self:project(tg, x, y, DamageType.PHYSKNOCKBACK, {dam=self:physicalCrit(t.getDamage(self, t), nil, target), dist=4})
+
+ self:buildCombo()
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t)
+ return ([[Attack your foes in a frontal arc with a roundhouse kick that deals %0.2f physical damage and knocks your foes back.
+ This is considered a strike for the purposes of stance damage bonuses, will earn one combo point, and break any grapples you're maintaining.
+ The knockback chance will increase with the strength stat and the damage will scale with the strength, dexterity, and cunning stats.]])
+ :format(damDesc(self, DamageType.PHYSICAL, (damage)))
+ end,
+}
\ No newline at end of file
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/techniques/pugilism.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/game/modules/tome/data/talents/techniques/pugilism.lua Fri Mar 25 19:27:01 2011 -0500
@@ -0,0 +1,297 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 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 .
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+newTalent{
+ name = "Striking Stance",
+ type = {"technique/unarmed-other", 1},
+ mode = "sustained",
+ hide = true,
+ points = 1,
+ cooldown = 12,
+ tactical = { BUFF = 2 },
+ type_no_req = true,
+ getCriticalPower = function(self, t) return 10 + self:getDex(20) end,
+ getDamage = function(self, t) return 20 + self:getDex(20) end,
+ activate = function(self, t)
+ cancelStances(self)
+ local ret = {
+ critpower = self:addTemporaryValue("combat_critical_power", t.getCriticalPower(self, t)),
+ }
+ return ret
+ end,
+ deactivate = function(self, t, p)
+ self:removeTemporaryValue("combat_critical_power", p.critpower)
+ return true
+ end,
+ info = function(self, t)
+ local critpower = t.getCriticalPower(self, t)
+ local damage = t.getDamage(self, t)
+ return ([[Increases your critical damage multiplier by %d%% and the damage multiplier of your pugilism talents by %d%%.
+ The bonuses will scale with the Dexterity stat.]]):
+ format(critpower, damage)
+ end,
+}
+
+newTalent{
+ name = "Double Strike",
+ type = {"technique/pugilism", 1},
+ require = techs_dex_req1,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 3,
+ stamina = 5,
+ message = "@Source@ throws two quick punches.",
+ tactical = { ATTACK = 2 },
+ requires_target = true,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.3, 0.7) + getStrikingStyle(self, dam) end,
+ -- Learn the appropriate stance
+ on_learn = function(self, t)
+ if not self:knowTalent(self.T_STRIKING_STANCE) then
+ self:learnTalent(self.T_STRIKING_STANCE, true)
+ end
+ end,
+ on_unlearn = function(self, t)
+ if not self:knowTalent(t) then
+ self:unlearnTalent(self.T_STRIKING_STANCE)
+ end
+ 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
+
+ -- force stance change
+ if target and not self:isTalentActive(self.T_STRIKING_STANCE) then
+ self:forceUseTalent(self.T_STRIKING_STANCE, {ignore_energy=true, ignore_cd = true})
+ end
+
+ -- breaks active grapples if the target is not grappled
+ if target:isGrappled(self) then
+ grappled = true
+ else
+ self:breakGrapples()
+ end
+
+ local hit1 = self:attackTarget(target, nil, t.getDamage(self, t), true)
+ local hit2 = self:attackTarget(target, nil, t.getDamage(self, t), true)
+
+ if hit1 then
+ self:buildCombo()
+ end
+
+ if hit2 then
+ self:buildCombo()
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t) * 100
+ return ([[Two quick punches that deal %d%% damage each.
+ Each jab that connects will earn one combo point.]])
+ :format(damage)
+ end,
+}
+
+newTalent{
+ name = "Body Shot",
+ type = {"technique/pugilism", 2},
+ require = techs_dex_req2,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 8,
+ stamina = 10,
+ message = "@Source@ throws a body shot.",
+ tactical = { ATTACK = 2, DISABLE = 2 },
+ requires_target = true,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.1, 1.5) + getStrikingStyle(self, dam) end,
+ getDuration = function(self, t) return 1 + math.floor(self:getTalentLevel(t)) end,
+ getDrain = function(self, t) return self:getTalentLevel(t) * 10 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
+
+ -- breaks active grapples if the target is not grappled
+ if target:isGrappled(self) then
+ grappled = true
+ else
+ self:breakGrapples()
+ end
+
+ local hit = self:attackTarget(target, nil, t.getDamage(self, t), true)
+
+ if hit then
+ -- try to daze
+ if target:checkHit(self:combatAttackStr(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("stun") then
+ target:setEffect(target.EFF_DAZED, t.getDuration(self, t), {})
+ else
+ game.logSeen(target, "%s resists the body shot!", target.name:capitalize())
+ end
+
+ target:incStamina(- t.getDrain(self, t))
+ self:buildCombo()
+
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t) * 100
+ local drain = t.getDrain(self, t)
+ local daze = t.getDuration(self, t)
+ return ([[A punch to the body that deals %d%% damage, drains %d of the target's stamina, and potentially dazes the target for %d turns.
+ The daze chance will increase with the strength stat.
+ If the blow connects it will earn one combo point.]])
+ :format(damage, drain, daze)
+ end,
+}
+
+newTalent{
+ name = "Rushing Strike",
+ type = {"technique/pugilism", 3},
+ require = techs_dex_req3,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 6,
+ message = "@Source@ throws a rushing punch!",
+ range = function(self, t) return 2 + math.ceil(self:getTalentLevel(t)/2) end,
+ stamina = 8,
+ tactical = { ATTACK = 2, DISABLE = 2, CLOSEIN = 2 },
+ requires_target = true,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.8, 1.4) + getStrikingStyle(self, dam) end,
+ getDuration = function(self, t) return 1 + math.ceil(self:getTalentLevel(t)) end,
+ action = function(self, t)
+ if self:attr("never_move") then game.logPlayer(self, "You can not do that currently.") return end
+
+ 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)) > self:getTalentRange(t) then return nil end
+
+ -- bonus damage for charging
+ local charge = math.floor((core.fov.distance(self.x, self.y, x, y)) -1) / 5
+
+ -- do the rush
+ local l = line.new(self.x, self.y, x, y)
+ local tx, ty = self.x, self.y
+ lx, ly = l()
+ while lx and ly do
+ if game.level.map:checkAllEntities(lx, ly, "block_move", self) then break end
+ tx, ty = lx, ly
+ lx, ly = l()
+ end
+
+ local ox, oy = self.x, self.y
+ self:move(tx, ty, true)
+ if config.settings.tome.smooth_move > 0 then
+ self:resetMoveAnim()
+ self:setMoveAnim(ox, oy, 8, 5)
+ end
+
+ -- force stance change
+ if target and not self:isTalentActive(self.T_STRIKING_STANCE) then
+ self:forceUseTalent(self.T_STRIKING_STANCE, {ignore_energy=true, ignore_cd = true})
+ end
+
+ -- break grabs
+ self:breakGrapples()
+
+ if math.floor(core.fov.distance(self.x, self.y, x, y)) == 1 then
+ local hit = self:attackTarget(target, nil, t.getDamage(self, t), true)
+
+ -- Try to stun !
+ if hit then
+
+ if target:checkHit(self:combatAttackStr(), target:combatPhysicalResist(), 0, 95, 5 - self:getTalentLevel(t) / 2) and target:canBe("stun") then
+ target:setEffect(target.EFF_STUNNED, t.getDuration(self, t), {})
+ else
+ game.logSeen(target, "%s resists the stun!", target.name:capitalize())
+ end
+
+ self:buildCombo()
+ end
+
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local duration = t.getDuration(self, t)
+ local damage = t.getDamage(self, t) * 100
+ return ([[Attacks the target with a vicious rushing strike that deals %d%% and may stun the target for %d turns. If the target is at range you'll rush towards them and deal 20%% bonus damage per tile traveled.
+ This attack will remove any grapples you're maintaining, switch your stance to Striking Stance, and earn one combo point if the blow connects.
+ The stun chance will increase with the strength stat.]])
+ :format(damage, duration)
+ end,
+}
+
+newTalent{
+ name = "Flurry of Fists",
+ type = {"technique/pugilism", 4},
+ require = techs_dex_req4,
+ points = 5,
+ random_ego = "attack",
+ cooldown = 24,
+ stamina = 15,
+ message = "@Source@ lashes out with a flurry of fists.",
+ tactical = { ATTACK = 2 },
+ requires_target = true,
+ getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.4, 1) + getStrikingStyle(self, dam) 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
+
+ -- breaks active grapples if the target is not grappled
+ if target:isGrappled(self) then
+ grappled = true
+ else
+ self:breakGrapples()
+ end
+
+
+ local hit1 = self:attackTarget(target, nil, t.getDamage(self, t), true)
+ local hit2 = self:attackTarget(target, nil, t.getDamage(self, t), true)
+ local hit3 = self:attackTarget(target, nil, t.getDamage(self, t), true)
+
+ if hit1 then
+ self:buildCombo()
+ end
+
+ if hit2 then
+ self:buildCombo()
+ end
+
+ if hit3 then
+ self:buildCombo()
+ end
+
+ return true
+ end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t) * 100
+ return ([[Lashes out at the target with three quick punches that each deal %d%% damage.
+ Each punch that connects will earn one combo point.]])
+ :format(damage)
+ end,
+}
\ No newline at end of file
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/techniques/techniques.lua
--- a/game/modules/tome/data/talents/techniques/techniques.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/talents/techniques/techniques.lua Fri Mar 25 19:27:01 2011 -0500
@@ -39,6 +39,19 @@
newTalentType{ allow_random=true, type="technique/combat-training", name = "combat training", generic = true, description = "Teaches to use various armors and improves health." }
newTalentType{ allow_random=true, type="technique/magical-combat", name = "magical combat", description = "The blending together of magic and melee prowess." }
+-- Unarmed Combat
+newTalentType{ is_unarmed=true, allow_random=true, type="technique/pugilism", name = "pugilism", description = "Boxing techniques." }
+--newTalentType{ is_unarmed=true, allow_random=true, type="technique/kick-boxing", name = "kick boxing", description = "Kick Boxing techniques." }
+newTalentType{ is_unarmed=true, allow_random=true, type="technique/finishing-moves", name = "finishing moves", description = "Finishing moves that use combo points." }
+newTalentType{ is_unarmed=true, allow_random=true, type="technique/grappling", name = "grappling", description = "Grappling techniques." }
+newTalentType{ is_unarmed=true, allow_random=true, type="technique/martial-arts", name = "martial arts", description = "Advanced unarmed techniques including kicks and throws." }
+newTalentType{ is_unarmed=true, allow_random=true, type="technique/unarmed-training", name = "unarmed training", generic = true, description = "Teaches various martial arts techniques." }
+newTalentType{ allow_random=true, type="technique/conditioning", name = "conditioning", generic = true, description = "Physical conditioning." }
+
+newTalentType{ is_unarmed=true, type="technique/unarmed-other", name = "unarmed other", generic = true, description = "Base martial arts attack and stances." }
+
+
+
-- Generic requires for techs based on talent level
-- Uses STR
techs_req1 = function(self, t) local stat = "str"; return {
@@ -126,6 +139,27 @@
level = function(level) return 16 + (level-1) end,
} end
+-- Generic requires for techs_con based on talent level
+techs_con_req1 = {
+ stat = { con=function(level) return 12 + (level-1) * 2 end },
+ level = function(level) return 0 + (level-1) end,
+}
+techs_con_req2 = {
+ stat = { con=function(level) return 20 + (level-1) * 2 end },
+ level = function(level) return 4 + (level-1) end,
+}
+techs_con_req3 = {
+ stat = { con=function(level) return 28 + (level-1) * 2 end },
+ level = function(level) return 8 + (level-1) end,
+}
+techs_con_req4 = {
+ stat = { con=function(level) return 36 + (level-1) * 2 end },
+ level = function(level) return 12 + (level-1) end,
+}
+techs_con_req5 = {
+ stat = { con=function(level) return 44 + (level-1) * 2 end },
+ level = function(level) return 16 + (level-1) end,
+}
-- Archery range talents
archery_range = function(self, t)
@@ -134,6 +168,35 @@
return weapon.combat.range or 6
end
+-- Unarmed stance changes and stance damage bonuses
+
+getGrapplingStyle = function(self, dam)
+ local dam = 0
+ if self:isTalentActive(self.T_GRAPPLING_STANCE) then
+ local t = self:getTalentFromId(self.T_GRAPPLING_STANCE)
+ dam = t.getDamage(self, t)
+ end
+ return dam / 100
+end
+
+getStrikingStyle = function(self, dam)
+ local dam = 0
+ if self:isTalentActive(self.T_STRIKING_STANCE) then
+ local t = self:getTalentFromId(self.T_STRIKING_STANCE)
+ dam = t.getDamage(self, t)
+ end
+ return dam / 100
+end
+
+cancelStances = function(self)
+ local stances = {self.T_STRIKING_STANCE, self.T_GRAPPLING_STANCE}
+ for i, t in ipairs(stances) do
+ if self:isTalentActive(t) then
+ self:forceUseTalent(t, {ignore_energy=true, ignore_cd=true})
+ end
+ end
+end
+
load("/data/talents/techniques/2hweapon.lua")
load("/data/talents/techniques/dualweapon.lua")
load("/data/talents/techniques/weaponshield.lua")
@@ -148,3 +211,11 @@
load("/data/talents/techniques/sling.lua")
load("/data/talents/techniques/archery.lua")
load("/data/talents/techniques/magical-combat.lua")
+
+load("/data/talents/techniques/pugilism.lua")
+load("/data/talents/techniques/martial-arts.lua")
+load("/data/talents/techniques/finishing-moves.lua")
+load("/data/talents/techniques/grappling.lua")
+--load("/data/talents/techniques/throws.lua")
+load("/data/talents/techniques/unarmed-training.lua")
+load("/data/talents/techniques/conditioning.lua")
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/talents/techniques/unarmed-training.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/game/modules/tome/data/talents/techniques/unarmed-training.lua Fri Mar 25 19:27:01 2011 -0500
@@ -0,0 +1,103 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 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 .
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+-- Empty Hand adds extra scaling to gauntlet and glove attacks based on character level.
+
+newTalent{
+ name = "Empty Hand",
+ type = {"technique/unarmed-other", 1},
+ innate = true,
+ hide = true,
+ mode = "passive",
+ points = 1,
+ getDamage = function(self, t) return self.level * 0.5 end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t)
+ return ([[Adds %d damage to all glove and gauntlet strikes.
+ This talent's effects will scale with your level.]]):
+ format(damage)
+ end,
+}
+
+-- generic unarmed training
+
+newTalent{
+ name = "Unarmed Mastery",
+ type = {"technique/unarmed-training", 1},
+ points = 10,
+ require = { stat = { dex=function(level) return 12 + level * 3 end }, },
+ mode = "passive",
+ getDamage = function(self, t) return math.sqrt(self:getTalentLevel(t) / 10) end,
+ info = function(self, t)
+ local damage = t.getDamage(self, t)
+ return ([[Increases damage done with unarmed attacks by %d%%.]]):
+ format(100 * damage)
+ end,
+}
+
+newTalent{
+ name = "Steady Mind",
+ type = {"technique/unarmed-training", 2},
+ mode = "passive",
+ points = 5,
+ require = techs_dex_req2,
+ getDefense = function(self, t) return 4 + self:combatTalentStatDamage(t, "dex", 1, 20) end,
+ getMental = function(self, t) return 4 + self:combatTalentStatDamage(t, "cun", 1, 20) end,
+ info = function(self, t)
+ local defense = t.getDefense(self, t)
+ local saves = t.getMental(self, t)
+ return ([[Superior cunning and training allows you to out think and out wit your opponents physical and mental assualts. Increases defense by %d and mental saves by %d.
+ The defense bonus will scale with the Dexterity stat and the save bonus with the Cunning stat.]]):
+ format(defense, saves)
+ end,
+}
+
+newTalent{
+ name = "Heightened Reflexes",
+ type = {"technique/unarmed-training", 3},
+ require = techs_dex_req3,
+ mode = "passive",
+ points = 5,
+ getDuration = function(self, t) return 1 + math.floor(self:getTalentLevel(t)) end,
+ do_reflexes = function(self, t)
+ self:setEffect(self.EFF_REFLEXIVE_DODGING, t.getDuration(self, t), {power=1})
+ end,
+ info = function(self, t)
+ local duration = t.getDuration(self, t)
+ return ([[When you're targeted by a projectile your global speed is increased by 100%% for %d turns. Taking any action other then movement will break the effect.]]):
+ format(duration)
+ end,
+}
+
+newTalent{
+ name = "Combo String",
+ type = {"technique/unarmed-training", 4},
+ require = techs_dex_req4,
+ mode = "passive",
+ points = 5,
+ getDuration = function(self, t) return math.floor(self:getTalentLevel(t)/2) end,
+ getChance = function(self, t) return self:getTalentLevel(t) * (5 + self:getCun(5)) end,
+ info = function(self, t)
+ local duration = t.getDuration(self, t)
+ local chance = t.getChance(self, t)
+ return ([[When building a combo point you have a %d%% chance to gain an extra combo point. Additionally your combo points will last %d turns longer before expiring.
+ The chance of building a second combo point will improve with the cunning stat.]]):
+ format(chance, duration)
+ end,
+}
\ No newline at end of file
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/data/timed_effects.lua
--- a/game/modules/tome/data/timed_effects.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/data/timed_effects.lua Fri Mar 25 19:27:01 2011 -0500
@@ -3452,4 +3452,292 @@
end,
deactivate = function(self, eff)
end,
-}
\ No newline at end of file
+}
+
+-- Grappling stuff
+newEffect{
+ name = "GRAPPLING",
+ desc = "Grappling",
+ long_desc = function(self, eff) return ("The target is engaged in a grapple. Any movement will break the effect as will some unarmed talents."):format() end,
+ type = "physical",
+ status = "beneficial",
+ parameters = {},
+ on_gain = function(self, err) return "#Target# is engaged in a grapple!", "+Grappling" end,
+ on_lose = function(self, err) return "#Target# has released the hold.", "-Grappling" end,
+ on_timeout = function(self, eff)
+ if math.floor(core.fov.distance(self.x, self.y, eff.src.x, eff.src.y)) > 1 or eff.src.dead or not eff.src:hasEffect(self.EFF_GRAPPLED) then
+ if eff.src:hasEffect(self.EFF_GRAPPLED) then
+ eff.src:removeEffect(self.EFF_GRAPPLED)
+ end
+ return true
+ end
+ end,
+ activate = function(self, eff)
+ local drain = 6 - (self:getTalentLevelRaw(self.T_CLINCH) or 0)
+ eff.tmpid = self:addTemporaryValue("stamina_regen", - drain)
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("stamina_regen", eff.tmpid)
+ -- clears debuffs from the grappled opponent; grapple break is set to silent so it won't spam everytime a grapple is reapplied
+ if eff.src:hasEffect(self.EFF_GRAPPLED) then
+ eff.src:removeEffect(self.EFF_GRAPPLED, true)
+ end
+ if eff.src:hasEffect(self.EFF_CRUSHING_HOLD) then
+ eff.src:removeEffect(self.EFF_CRUSHING_HOLD)
+ end
+ if eff.src:hasEffect(self.EFF_STRANGLE_HOLD) then
+ eff.src:removeEffect(self.EFF_STRANGLE_HOLD)
+ end
+ end,
+}
+
+newEffect{
+ name = "GRAPPLED",
+ desc = "Grappled",
+ long_desc = function(self, eff) return ("The target is grappled, unable to move, and has it's defense and attack reduced by %d."):format(eff.power) end,
+ type = "physical",
+ status = "detrimental",
+ parameters = {},
+ on_gain = function(self, err) return "#Target# is grappled!", "+Grappled" end,
+ on_lose = function(self, err) return "#Target# is free from the grapple.", "-Grappled" end,
+ activate = function(self, eff)
+ eff.tmpid = self:addTemporaryValue("never_move", 1)
+ eff.def = self:addTemporaryValue("combat_def", -eff.power)
+ eff.atk = self:addTemporaryValue("combat_atk", -eff.power)
+ end,
+ on_timeout = function(self, eff)
+ if math.floor(core.fov.distance(self.x, self.y, eff.src.x, eff.src.y)) > 1 or eff.src.dead or not eff.src:hasEffect(self.EFF_GRAPPLING) then
+ if eff.src:hasEffect(self.EFF_GRAPPLING) then
+ eff.src:removeEffect(self.EFF_GRAPPLING)
+ end
+ return true
+ end
+ end,
+ deactivate = function(self, eff)
+ -- clears the grappling effect from the attacker; this will in turn remove all other holds.
+ if eff.src:hasEffect(self.EFF_GRAPPLING) then
+ eff.src:removeEffect(self.EFF_GRAPPLING)
+ end
+ self:removeTemporaryValue("combat_atk", eff.atk)
+ self:removeTemporaryValue("combat_def", eff.def)
+ self:removeTemporaryValue("never_move", eff.tmpid)
+ end,
+}
+
+newEffect{
+ name = "CRUSHING_HOLD",
+ desc = "Crushing Hold",
+ long_desc = function(self, eff) return ("The target is being crushed and suffers %d damage each turn"):format(eff.power) end,
+ type = "physical",
+ status = "detrimental",
+ parameters = { power=1 },
+ on_gain = function(self, err) return "#Target# is being crushed.", "+Crushing Hold" end,
+ on_lose = function(self, err) return "#Target# has escaped the crushing hold.", "-Crushing Hold" end,
+ on_timeout = function(self, eff)
+ DamageType:get(DamageType.PHYSICAL).projector(eff.src or self, self.x, self.y, DamageType.PHYSICAL, eff.power)
+ end,
+}
+
+newEffect{
+ name = "STRANGLE_HOLD",
+ desc = "Strangle Hold",
+ long_desc = function(self, eff) return ("The target is being strangled and may not cast spells and suffers %d damage each turn."):format(eff.power) end,
+ type = "physical",
+ status = "detrimental",
+ parameters = { power=1 },
+ on_gain = function(self, err) return "#Target# is being strangled.", "+Strangle Hold" end,
+ on_lose = function(self, err) return "#Target# has escaped the strangle hold.", "-Strangle Hold" end,
+ on_timeout = function(self, eff)
+ DamageType:get(DamageType.PHYSICAL).projector(eff.src or self, self.x, self.y, DamageType.PHYSICAL, eff.power)
+ end,
+ activate = function(self, eff)
+ if self:canBe("silence") then
+ eff.tmpid = self:addTemporaryValue("silence", 1)
+ eff.dur = self:updateEffectDuration(eff.dur, "silence")
+ end
+ silenced = true
+ end,
+ deactivate = function(self, eff)
+ if silenced then
+ self:removeTemporaryValue("silence", eff.tmpid)
+ end
+ end,
+}
+
+newEffect{
+ name = "MAIMED",
+ desc = "Maimed",
+ long_desc = function(self, eff) return ("The target is maimed, reducing attack and damage by %d and global speed by 30%%."):format(eff.power) end,
+ type = "physical",
+ status = "detrimental",
+ parameters = { atk=10, dam=10 },
+ on_gain = function(self, err) return "#Target# is maimed.", "+Maimed" end,
+ on_lose = function(self, err) return "#Target# has recovered from the maiming.", "-Maimed" end,
+ activate = function(self, eff)
+ eff.atkid = self:addTemporaryValue("combat_atk", -eff.atk)
+ eff.damid = self:addTemporaryValue("combat_dam", -eff.dam)
+ eff.tmpid = self:addTemporaryValue("energy", {mod=-0.3})
+ eff.dur = self:updateEffectDuration(eff.dur, "slow")
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("combat_atk", eff.atkid)
+ self:removeTemporaryValue("combat_dam", eff.damid)
+ self:removeTemporaryValue("energy", eff.tmpid)
+ end,
+}
+
+newEffect{
+ name = "COMBO",
+ desc = "Combo",
+ long_desc = function(self, eff) return ("The target is in the middle of a combo chain and has earned %d combo points."):format(eff.cur_power) end,
+ type = "physical",
+ status = "beneficial",
+ parameters = { power=1, max=5 },
+ on_merge = function(self, old_eff, new_eff)
+ self:removeTemporaryValue("combo", old_eff.tmpid)
+ old_eff.cur_power = math.min(old_eff.cur_power + new_eff.power, new_eff.max)
+ old_eff.tmpid = self:addTemporaryValue("combo", {power = old_eff.cur_power})
+
+ old_eff.dur = new_eff.dur
+ return old_eff
+ end,
+ activate = function(self, eff)
+ eff.cur_power = eff.power
+ eff.tmpid = self:addTemporaryValue("combo", {eff.power})
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("combo", eff.tmpid)
+ end,
+}
+
+newEffect{
+ name = "RELENTLESS_STRIKES",
+ desc = "Relentless Strikes",
+ long_desc = function(self, eff) return ("The target is attacking relentlessly, increasing it's stamina regen by %d and gaining increased effect from combo point gains."):format(eff.power) end,
+ type = "physical",
+ status = "beneficial",
+ parameters = { power=10 },
+ on_gain = function(self, err) return "#Target# is striking relentlessly!", "+Relentless Strikes" end,
+ on_lose = function(self, err) return "#Target#'s striking ability has returned to normal.", "-Relentless Strikes" end,
+ activate = function(self, eff)
+ eff.tmpid = self:addTemporaryValue("stamina_regen", eff.power)
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("stamina_regen", eff.tmpid)
+ end,
+}
+
+newEffect{
+ name = "DEFENSIVE_MANEUVER",
+ desc = "Defensive Maneuver",
+ long_desc = function(self, eff) return ("The target's defense is increased by %d."):format(eff.power) end,
+ type = "physical",
+ status = "beneficial",
+ parameters = {power = 1},
+ on_gain = function(self, err) return "#Target# is moving defensively!", "+Defensive Maneuver" end,
+ on_lose = function(self, err) return "#Target# isn't moving as defensively anymore.", "-Defensive Maneuver" end,
+ activate = function(self, eff)
+ eff.defense = self:addTemporaryValue("combat_def", eff.power)
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("combat_def", eff.defense)
+ end,
+}
+
+newEffect{
+ name = "SET_UP",
+ desc = "Set Up",
+ long_desc = function(self, eff) return ("The target is off balance and is %d%% more likely to be crit by the target that set it up. In addition all it's saves are reduced by %d."):format(eff.power, eff.power) end,
+ type = "physical",
+ status = "detrimental",
+ parameters = {power = 1},
+ on_gain = function(self, err) return "#Target# has been set up!", "+Set Up" end,
+ on_lose = function(self, err) return "#Target# has survived the set up.", "-Set Up" end,
+ activate = function(self, eff)
+ eff.mental = self:addTemporaryValue("combat_mentalresist", -eff.power)
+ eff.spell = self:addTemporaryValue("combat_spellresist", -eff.power)
+ eff.physical = self:addTemporaryValue("combat_physresist", -eff.power)
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("combat_mentalresist", eff.mental)
+ self:removeTemporaryValue("combat_spellresist", eff.spell)
+ self:removeTemporaryValue("combat_physresist", eff.physical)
+ end,
+}
+
+newEffect{
+ name = "RECOVERY",
+ desc = "Recovery",
+ long_desc = function(self, eff) return ("The target is recovering from a critical hit and regaining %d life each turn."):format(eff.power) end,
+ type = "physical",
+ status = "beneficial",
+ parameters = { power=10 },
+ on_gain = function(self, err) return "#Target# is recovering from the attack!", "+Recovery" end,
+ on_lose = function(self, err) return "#Target# has finished recovering from the attack.", "-Recovery" end,
+ activate = function(self, eff)
+ eff.tmpid = self:addTemporaryValue("life_regen", eff.power)
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("life_regen", eff.tmpid)
+ end,
+}
+
+newEffect{
+ name = "REFLEXIVE_DODGING",
+ desc = "Reflexive Dodging",
+ long_desc = function(self, eff) return ("Increases global action speed by %d%%."):format(eff.power * 100) end,
+ type = "physical",
+ status = "beneficial",
+ parameters = { power=0.1 },
+ on_gain = function(self, err) return "#Target# speeds up.", "+Reflexive Dodging" end,
+ on_lose = function(self, err) return "#Target# slows down.", "-Reflexive Dodging" end,
+ activate = function(self, eff)
+ eff.tmpid = self:addTemporaryValue("energy", {mod=eff.power})
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("energy", eff.tmpid)
+ end,
+}
+
+newEffect{
+ name = "WEAKENED_DEFENSES",
+ desc = "Weakened Defenses",
+ long_desc = function(self, eff) return ("The target's physical resistance has been reduced by %d%%."):format(eff.inc) end,
+ type = "physical",
+ status = "detrimental",
+ parameters = { inc=1, max=5 },
+ on_merge = function(self, old_eff, new_eff)
+ self:removeTemporaryValue("resists", old_eff.tmpid)
+ old_eff.cur_inc = math.max(old_eff.cur_inc + new_eff.inc, new_eff.max)
+ old_eff.tmpid = self:addTemporaryValue("resists", {[DamageType.PHYSICAL] = old_eff.cur_inc})
+
+ old_eff.dur = new_eff.dur
+ return old_eff
+ end,
+ activate = function(self, eff)
+ eff.cur_inc = eff.inc
+ eff.tmpid= self:addTemporaryValue("resists", {
+ [DamageType.PHYSICAL]= eff.inc,
+ })
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("resists", eff.tmpid)
+ end,
+}
+
+newEffect{
+ name = "SPRINT",
+ desc = "Sprint",
+ long_desc = function(self, eff) return ("Increases movement speed by %d%%."):format(eff.power*100) end,
+ type = "physical",
+ status = "beneficial",
+ parameters = { power=0.1 },
+ on_gain = function(self, err) return "#Target# speeds up.", "+Sprint" end,
+ on_lose = function(self, err) return "#Target# slows down.", "-Sprint" end,
+ activate = function(self, eff)
+ eff.tmpid = self:addTemporaryValue("movement_speed", -eff.power)
+ end,
+ deactivate = function(self, eff)
+ self:removeTemporaryValue("movement_speed", eff.tmpid)
+ end,
+}
diff -r 88f08638aa28 -r d2255241678c game/modules/tome/dialogs/CharacterSheet.lua
--- a/game/modules/tome/dialogs/CharacterSheet.lua Thu Mar 03 01:35:51 2011 +0000
+++ b/game/modules/tome/dialogs/CharacterSheet.lua Fri Mar 25 19:27:01 2011 -0500
@@ -136,22 +136,35 @@
h = basey
w = 200
-- All weapons in main hands
- if player:getInven(player.INVEN_MAINHAND) then
+ local mainhand = player:getInven(player.INVEN_MAINHAND)
+ if mainhand and (#mainhand > 0) then
for i, o in ipairs(player:getInven(player.INVEN_MAINHAND)) do
local mean, dam = o.combat, o.combat
if o.archery and mean then
dam = (player:getInven("QUIVER")[1] and player:getInven("QUIVER")[1].combat) or o.basic_ammo
end
if mean and dam then
- self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Attack(Main Hand): #00ff00#%3d"):format(player:combatAttack(mean)), w, h, 255, 255, 255)) h = h + self.font_h
- self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage(Main Hand): #00ff00#%3d"):format(player:combatDamage(dam)), w, h, 255, 255, 255)) h = h + self.font_h
- self:mouseTooltip(self.TOOLTIP_COMBAT_APR, s:drawColorStringBlended(self.font, ("APR (Main Hand): #00ff00#%3d"):format(player:combatAPR(dam)), w, h, 255, 255, 255)) h = h + self.font_h
- self:mouseTooltip(self.TOOLTIP_COMBAT_CRIT, s:drawColorStringBlended(self.font, ("Crit (Main Hand): #00ff00#%3d%%"):format(player:combatCrit(dam)), w, h, 255, 255, 255)) h = h + self.font_h
- self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED, s:drawColorStringBlended(self.font, ("Speed (Main Hand): #00ff00#%0.2f"):format(player:combatSpeed(mean)), w, h, 255, 255, 255)) h = h + self.font_h
+ self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Accuracy(Main Hand): #00ff00#%3d"):format(player:combatAttack(mean)), w, h, 255, 255, 255)) h = h + self.font_h
+ self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage (Main Hand): #00ff00#%3d"):format(player:combatDamage(dam)), w, h, 255, 255, 255)) h = h + self.font_h
+ self:mouseTooltip(self.TOOLTIP_COMBAT_APR, s:drawColorStringBlended(self.font, ("APR (Main Hand): #00ff00#%3d"):format(player:combatAPR(dam)), w, h, 255, 255, 255)) h = h + self.font_h
+ self:mouseTooltip(self.TOOLTIP_COMBAT_CRIT, s:drawColorStringBlended(self.font, ("Crit (Main Hand): #00ff00#%3d%%"):format(player:combatCrit(dam)), w, h, 255, 255, 255)) h = h + self.font_h
+ self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED, s:drawColorStringBlended(self.font, ("Speed (Main Hand): #00ff00#%0.2f"):format(player:combatSpeed(mean)), w, h, 255, 255, 255)) h = h + self.font_h
end
if mean and mean.range then self:mouseTooltip(self.TOOLTIP_COMBAT_RANGE, s:drawColorStringBlended(self.font, ("Range (Main Hand): #00ff00#%3d"):format(mean.range), w, h, 255, 255, 255)) h = h + self.font_h end
end
+ -- Handle bare-handed combat
+ else
+ local mean, dam = player.combat, player.combat
+ if mean and dam then
+ self:mouseTooltip(self.TOOLTIP_COMBAT_ATTACK, s:drawColorStringBlended(self.font, ("Accuracy(Unarmed): #00ff00#%3d"):format(player:combatAttack(mean)), w, h, 255, 255, 255)) h = h + self.font_h
+ self:mouseTooltip(self.TOOLTIP_COMBAT_DAMAGE, s:drawColorStringBlended(self.font, ("Damage (Unarmed): #00ff00#%3d"):format(player:combatDamage(dam)), w, h, 255, 255, 255)) h = h + self.font_h
+ self:mouseTooltip(self.TOOLTIP_COMBAT_APR, s:drawColorStringBlended(self.font, ("APR (Unarmed): #00ff00#%3d"):format(player:combatAPR(dam)), w, h, 255, 255, 255)) h = h + self.font_h
+ self:mouseTooltip(self.TOOLTIP_COMBAT_CRIT, s:drawColorStringBlended(self.font, ("Crit (Unarmed): #00ff00#%3d%%"):format(player:combatCrit(dam)), w, h, 255, 255, 255)) h = h + self.font_h
+ self:mouseTooltip(self.TOOLTIP_COMBAT_SPEED, s:drawColorStringBlended(self.font, ("Speed (Unarmed): #00ff00#%0.2f"):format(player:combatSpeed(mean)), w, h, 255, 255, 255)) h = h + self.font_h
+ end
+ if mean and mean.range then self:mouseTooltip(self.TOOLTIP_COMBAT_RANGE, s:drawColorStringBlended(self.font, ("Range (Main Hand): #00ff00#%3d"):format(mean.range), w, h, 255, 255, 255)) h = h + self.font_h end
end
+
h = h + self.font_h
-- All weapons in off hands
-- Offhand attacks are with a damage penalty, that can be reduced by talents
@@ -172,6 +185,7 @@
if mean and mean.range then self:mouseTooltip(self.TOOLTIP_COMBAT_RANGE, s:drawColorStringBlended(self.font, ("Range (Off Hand): #00ff00#%3d"):format(mean.range), w, h, 255, 255, 255)) h = h + self.font_h end
end
end
+
h = h + self.font_h
self:mouseTooltip(self.TOOLTIP_SPELL_POWER, s:drawColorStringBlended(self.font, ("Spellpower: #00ff00#%3d"):format(player:combatSpellpower()), w, h, 255, 255, 255)) h = h + self.font_h
self:mouseTooltip(self.TOOLTIP_SPELL_CRIT, s:drawColorStringBlended(self.font, ("Spell Crit: #00ff00#%3d%%"):format(player:combatSpellCrit()), w, h, 255, 255, 255)) h = h + self.font_h