diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index d428df0fd5746f96747ff43d8f44d1d4c4b24c04..7d1aa656536ad2f0ce868fdabe08bffbc6838559 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -41,6 +41,7 @@ function _M:init(t, no_default) self.combat_physresist = 0 self.combat_spellresist = 0 + self.combat_mentalresist = 0 self.fatigue = 0 @@ -107,7 +108,7 @@ function _M:move(x, y, force) if force or self:enoughEnergy() then -- Confused ? if not force and self:attr("confused") then - if rng.chance(self:attr("confused")) then + if rng.percent(self:attr("confused")) then x, y = self.x + rng.range(-1, 1), self.y + rng.range(-1, 1) end end diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua index b740d215b3bbbf8d329c73ed693f91c4988332e3..80d2110b12d57c4495a788679045e3c432968449 100644 --- a/game/modules/tome/class/interface/Combat.lua +++ b/game/modules/tome/class/interface/Combat.lua @@ -291,3 +291,18 @@ end function _M:combatSpellResist() return self.combat_spellresist + (self:getMag() + self:getWil()) * 0.25 end + +--- Computes mental resistance +function _M:combatMentalResist() + return self.combat_mentalresist + (self:getCun() + self:getWil()) * 0.25 +end + + +--- Check if the user has a two handed weapon +function _M:hasTwoHandedWeapon() + local weapon = self:getInven("MAINHAND")[1] + if not weapon or not weapon.twohanded then + return nil + end + return weapon +end diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua index fc04e0c6d44dde526eac51251e3c91d54e27480a..4f84fa4736fa3732f789391e01d43b15b55e5b8e 100644 --- a/game/modules/tome/data/damage_types.lua +++ b/game/modules/tome/data/damage_types.lua @@ -299,7 +299,7 @@ newDamageType{ projector = function(src, x, y, type, dam) local target = game.level.map(x, y, Map.ACTOR) if target then - if target:checkHit(src:combatSpellpower(), target:combatSpellResist(), 0, 95, 15) and target:canBe("stun") then + if target:checkHit((dam.power_check or src.combatSpellpower)(src), (dam.resist_check or target.combatSpellResist)(target), 0, 95, 15) and target:canBe("stun") then target:setEffect(target.EFF_CONFUSED, dam.dur, {power=dam.dam}) else game.logSeen(target, "%s resists!", target.name:capitalize()) diff --git a/game/modules/tome/data/talents/misc/npcs.lua b/game/modules/tome/data/talents/misc/npcs.lua index 08f77fe55c39bc3fc162905d36538a68a0c946af..d56f88b8d8dc5dde06e4cfa4e8afc7dfd36e6fdb 100644 --- a/game/modules/tome/data/talents/misc/npcs.lua +++ b/game/modules/tome/data/talents/misc/npcs.lua @@ -46,7 +46,8 @@ newTalent{ cooldown = 5, range = 1, action = function(self, t) - local x, y, target = self:getTarget() + local tg = {type="hit", range=self:getTalentRange(t)} + local x, y, target = self:getTarget(tg) if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end self.combat_apr = self.combat_apr + 1000 self:attackTarget(target, DamageType.POISON, 2 + self:getTalentLevel(t), true) @@ -67,7 +68,8 @@ newTalent{ cooldown = 2, range = 1, action = function(self, t) - local x, y, target = self:getTarget() + local tg = {type="hit", range=self:getTalentRange(t)} + local x, y, target = self:getTarget(tg) if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end self.combat_apr = self.combat_apr + 1000 self:attackTarget(target, DamageType.ACID, 1 + self:getTalentLevel(t) / 3, true) @@ -88,8 +90,8 @@ newTalent{ cooldown = 2, range = 1, action = function(self, t) - local t = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(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 self.combat_apr = self.combat_apr + 1000 @@ -111,7 +113,8 @@ newTalent{ cooldown = 2, range = 1, action = function(self, t) - local x, y, target = self:getTarget() + local tg = {type="hit", range=self:getTalentRange(t)} + local x, y, target = self:getTarget(tg) if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end self.combat_apr = self.combat_apr + 1000 self:attackTarget(target, DamageType.POISON, 2 + self:getTalentLevel(t), true) @@ -131,8 +134,8 @@ newTalent{ stamina = 8, require = { stat = { str=12 }, }, action = function(self, t) - local t = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(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 = self:attackTarget(target, 0.5 + self:getTalentLevel(t) / 10, true) @@ -161,8 +164,8 @@ newTalent{ stamina = 8, require = { stat = { str=12 }, }, action = function(self, t) - local t = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(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 = self:attackTarget(target, nil, 1.5 + self:getTalentLevel(t) / 10, true) @@ -192,7 +195,8 @@ newTalent{ cooldown = 5, range = 1, action = function(self, t) - local x, y, target = self:getTarget() + local tg = {type="hit", range=self:getTalentRange(t)} + local x, y, target = self:getTarget(tg) if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end self:attackTarget(target, DamageType.POISON, 2 + self:getTalentLevel(t), true) return true diff --git a/game/modules/tome/data/talents/misc/random.lua b/game/modules/tome/data/talents/misc/random.lua index ef3c7b5fb00704e935a55f941b33e19e46d3ace9..bb8a58f7b6ce2d5e2d4d9ee6aae871e2a7acf4b3 100644 --- a/game/modules/tome/data/talents/misc/random.lua +++ b/game/modules/tome/data/talents/misc/random.lua @@ -17,8 +17,8 @@ newTalent{ ATTACK = 10, }, action = function(self, t) - local t = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(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 self.combat_apr = self.combat_apr + 1000 diff --git a/game/modules/tome/data/talents/techniques/2hweapon.lua b/game/modules/tome/data/talents/techniques/2hweapon.lua index 3cf392289ea5255380b251df12cadd3a0e2fe415..88eb73a0eb1ad1a7545aa91d869be21c89a794d0 100644 --- a/game/modules/tome/data/talents/techniques/2hweapon.lua +++ b/game/modules/tome/data/talents/techniques/2hweapon.lua @@ -7,17 +7,17 @@ newTalent{ cooldown = 30, sustain_stamina = 40, activate = function(self, t) - local weapon = self:getInven("MAINHAND")[1] - if not weapon or not weapon.twohanded then + local weapon = self:hasTwoHandedWeapon() + if not weapon then game.logPlayer(self, "You cannot use Berserker without a two handed weapon!") return nil end return { - atk = self:addTemporaryValue("combat_dam", 5 + self:getStr(6) * self:getTalentLevel(t)), - dam = self:addTemporaryValue("combat_atk", 5 + self:getDex(6) * self:getTalentLevel(t)), - def = self:addTemporaryValue("combat_def", -5 - 2 * self:getTalentLevel(t)), - armor = self:addTemporaryValue("combat_armor", -5 - 2 * self:getTalentLevel(t)), + atk = self:addTemporaryValue("combat_dam", 5 + self:getStr(7) * self:getTalentLevel(t)), + dam = self:addTemporaryValue("combat_atk", 5 + self:getDex(7) * self:getTalentLevel(t)), + def = self:addTemporaryValue("combat_def", -5 - 2 * (self:getTalentLevelRaw(t)-1)), + armor = self:addTemporaryValue("combat_armor", -5 - 2 * (self:getTalentLevelRaw(t)-1)), } end, @@ -30,11 +30,10 @@ newTalent{ end, info = function(self, t) return ([[Enters an aggressive battle stance, increasing attack by %d and damage by %d at the cost of %d defense and %d armor.]]): - format(5 + self:getDex(6) * self:getTalentLevel(t), 5 + self:getStr(6) * self:getTalentLevel(t), -5 - 2 * self:getTalentLevel(t), -5 - 2 * self:getTalentLevel(t)) + format(5 + self:getDex(7) * self:getTalentLevel(t), 5 + self:getStr(7) * self:getTalentLevel(t), -5 - 2 * (self:getTalentLevelRaw(t)-1), -5 - 2 * (self:getTalentLevelRaw(t)-1)) end, } - newTalent{ name = "Death Dance", type = {"technique/2hweapon-offense", 2}, @@ -43,8 +42,8 @@ newTalent{ cooldown = 10, stamina = 30, action = function(self, t) - local weapon = self:getInven("MAINHAND")[1] - if not weapon or not weapon.twohanded then + local weapon = self:hasTwoHandedWeapon() + if not weapon then game.logPlayer(self, "You cannot use Death Dance without a two handed weapon!") return nil end @@ -76,15 +75,26 @@ newTalent{ }, range = 1, action = function(self, t) + local weapon = self:hasTwoHandedWeapon() + if not weapon then + game.logPlayer(self, "You cannot use Warshout without a two handed weapon!") + return nil + end + local tg = {type="cone", range=0, radius=3 + self:getTalentLevelRaw(t), friendlyfire=false} local x, y = self:getTarget(tg) if not x or not y then return nil end - self:project(tg, x, y, DamageType.CONFUSION, {dur=self:getTalentLevelRaw(t), dam=50+self:getTalentLevelRaw(t)*10}, {type="flame"}) + self:project(tg, x, y, DamageType.CONFUSION, { + dur=3+self:getTalentLevelRaw(t), + dam=50+self:getTalentLevelRaw(t)*10, + power_check=function() return self:combatAttackStr(weapon) end, + resist_check=self.combatPhysicalResist, + }, {type="flame"}) return true end, info = function(self, t) return ([[Shout your warcry in a frontal cone, any targets caught inside will be confused for %d turns.]]): - format(self:getTalentLevelRaw(t)) + format(3 + self:getTalentLevelRaw(t)) end, } @@ -95,16 +105,15 @@ newTalent{ points = 5, cooldown = 30, stamina = 30, - require = { stat = { str=22 }, }, action = function(self, t) - local weapon = self:getInven("MAINHAND")[1] - if not weapon or not weapon.twohanded then + local weapon = self:hasTwoHandedWeapon() + if not weapon then game.logPlayer(self, "You cannot use Death Blow without a two handed weapon!") return nil end - local t = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(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 @@ -150,16 +159,15 @@ newTalent{ points = 5, cooldown = 6, stamina = 8, - require = { stat = { str=12 }, }, action = function(self, t) - local weapon = self:getInven("MAINHAND")[1] - if not weapon or not weapon.twohanded then + local weapon = self:hasTwoHandedWeapon() + if not weapon then game.logPlayer(self, "You cannot use Stunning Blow without a two handed weapon!") return nil end - local t = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(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 speed, hit = self:attackTargetWith(target, weapon.combat, nil, 1.5 + self:getTalentLevel(t) / 10) @@ -179,3 +187,111 @@ newTalent{ return ([[Hits the target with your weapon doing %d%% damage, if the atatck hits, the target is stunned.]]):format(100 * (1.5 + self:getTalentLevel(t) / 10)) end, } + +newTalent{ + name = "Sunder Armour", + type = {"technique/2hweapon-cripple", 2}, + require = techs_req2, + points = 5, + cooldown = 6, + stamina = 12, + action = function(self, t) + local weapon = self:hasTwoHandedWeapon() + if not weapon then + game.logPlayer(self, "You cannot use Sunder Armour without a two handed weapon!") + return nil + 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)) > 1 then return nil end + local speed, hit = self:attackTargetWith(target, weapon.combat, nil, 1.5 + self:getTalentLevel(t) / 10) + + -- Try to stun ! + if hit then + if target:checkHit(self:combatAttackStr(weapon.combat), target:combatPhysicalResist(), 0, 95, 10 - self:getTalentLevel(t) / 2) and target:canBe("stun") then + target:setEffect(target.EFF_SUNDER_ARMOUR, 4 + self:getTalentLevel(t), {power=5*self:getTalentLevel(t)}) + else + game.logSeen(target, "%s resists the sundering!", target.name:capitalize()) + end + end + + return true + end, + info = function(self, t) + return ([[Hits the target with your weapon doing %d%% damage, if the attack hits, the target is armor is reduced by %d.]]):format(100 * (1.5 + self:getTalentLevel(t) / 10), 5*self:getTalentLevel(t)) + end, +} + +newTalent{ + name = "Sunder Arms", + type = {"technique/2hweapon-cripple", 3}, + require = techs_req3, + points = 5, + cooldown = 6, + stamina = 12, + action = function(self, t) + local weapon = self:hasTwoHandedWeapon() + if not weapon then + game.logPlayer(self, "You cannot use Sunder Arms without a two handed weapon!") + return nil + 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)) > 1 then return nil end + local speed, hit = self:attackTargetWith(target, weapon.combat, nil, 1.5 + self:getTalentLevel(t) / 10) + + -- Try to stun ! + if hit then + if target:checkHit(self:combatAttackStr(weapon.combat), target:combatPhysicalResist(), 0, 95, 10 - self:getTalentLevel(t) / 2) and target:canBe("stun") then + target:setEffect(target.EFF_SUNDER_ARMS, 4 + self:getTalentLevel(t), {power=3*self:getTalentLevel(t)}) + else + game.logSeen(target, "%s resists the sundering!", target.name:capitalize()) + end + end + + return true + end, + info = function(self, t) + return ([[Hits the target with your weapon doing %d%% damage, if the attack hits, the target is attack power is reduced by %d.]]):format(100 * (1.5 + self:getTalentLevel(t) / 10), 3*self:getTalentLevel(t)) + end, +} + +newTalent{ + name = "Crush", + type = {"technique/2hweapon-cripple", 4}, + require = techs_req4, + points = 5, + cooldown = 6, + stamina = 12, + action = function(self, t) + local weapon = self:hasTwoHandedWeapon() + if not weapon then + game.logPlayer(self, "You cannot use Crush without a two handed weapon!") + return nil + 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)) > 1 then return nil end + local speed, hit = self:attackTargetWith(target, weapon.combat, nil, 2 + self:getTalentLevel(t) / 10) + + -- Try to stun ! + if hit then + if target:checkHit(self:combatAttackStr(weapon.combat), target:combatPhysicalResist(), 0, 95, 10 - self:getTalentLevel(t) / 2) and target:canBe("stun") then + target:setEffect(target.EFF_PINNED, 2 + self:getTalentLevel(t), {}) + else + game.logSeen(target, "%s resists the crushing!", target.name:capitalize()) + end + end + + return true + end, + info = function(self, t) + return ([[Hits the target with a mighty blow to the legs doing %d%% weapon damage, if the attack hits, the target is unable to move for %d turns.]]):format(100 * (2 + self:getTalentLevel(t) / 10), 2+self:getTalentLevel(t)) + end, +} diff --git a/game/modules/tome/data/talents/techniques/dualweapon.lua b/game/modules/tome/data/talents/techniques/dualweapon.lua index 17f8de3f174ee9254f0b4c63b25bcba8e161b78d..a5a7a43c026cfa21ba67e4686b3dfa442e4d8b1e 100644 --- a/game/modules/tome/data/talents/techniques/dualweapon.lua +++ b/game/modules/tome/data/talents/techniques/dualweapon.lua @@ -24,8 +24,8 @@ newTalent{ return nil end - local t = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(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 self:attackTarget(target, nil, 1.8 + self:getTalentLevel(t) / 10, true) diff --git a/game/modules/tome/data/talents/techniques/weaponshield.lua b/game/modules/tome/data/talents/techniques/weaponshield.lua index df203ecee814d29808d7329b7cb60303b858f56b..93cdc8f329cf7ea1e70f07a115f5ecb6e36868ee 100644 --- a/game/modules/tome/data/talents/techniques/weaponshield.lua +++ b/game/modules/tome/data/talents/techniques/weaponshield.lua @@ -12,8 +12,8 @@ newTalent{ return nil end - local t = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(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 speed, hit = self:attackTargetWith(target, shield.special_combat, nil, 2 + self:getTalentLevel(t) / 5) @@ -49,8 +49,8 @@ newTalent{ return nil end - local t = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(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 diff --git a/game/modules/tome/data/timed_effects.lua b/game/modules/tome/data/timed_effects.lua index 0a35435c7caf447cd07c71addac427ffe500cbc8..dc319ce1f2fa0ebeebd4c686d47b92d81fa74585 100644 --- a/game/modules/tome/data/timed_effects.lua +++ b/game/modules/tome/data/timed_effects.lua @@ -374,3 +374,47 @@ newEffect{ DamageType:get(DamageType.ARCANE).projector(self, self.x, self.y, DamageType.ARCANE, eff.power) end, } + +newEffect{ + name = "SUNDER_ARMOUR", + desc = "Sunder Armour", + type = "physical", + status = "detrimental", + parameters = { power=10 }, + activate = function(self, eff) + eff.tmpid = self:addTemporaryValue("combat_armor", -eff.power) + end, + deactivate = function(self, eff) + self:removeTemporaryValue("combat_armor", eff.tmpid) + end, +} + +newEffect{ + name = "SUNDER_ARMS", + desc = "Sunder Arms", + type = "physical", + status = "detrimental", + parameters = { power=10 }, + activate = function(self, eff) + eff.tmpid = self:addTemporaryValue("combat_atk", -eff.power) + end, + deactivate = function(self, eff) + self:removeTemporaryValue("combat_atk", eff.tmpid) + end, +} + +newEffect{ + name = "PINNED", + desc = "Pinned to the ground", + type = "physical", + status = "detrimental", + parameters = {}, + on_gain = function(self, err) return "#Target# is pinned to the ground.", "+Pinned" end, + on_lose = function(self, err) return "#Target# is no longer pinned.", "-Pinned" end, + activate = function(self, eff) + eff.tmpid = self:addTemporaryValue("never_move", 1) + end, + deactivate = function(self, eff) + self:removeTemporaryValue("never_move", eff.tmpid) + end, +} diff --git a/ideas/technics.ods b/ideas/technics.ods index adfe86bf63aac3a16491ad7554545aea84600f11..c0ea9f9d5dcd8a864aba355ec580e2cf80abd489 100644 Binary files a/ideas/technics.ods and b/ideas/technics.ods differ diff --git a/src/core_lua.c b/src/core_lua.c index 1e2adab23aa1a319c458d389e4719bcd4afe0d8a..3b9457f4229e8e6a003459195762de453c8f75e6 100644 --- a/src/core_lua.c +++ b/src/core_lua.c @@ -824,7 +824,8 @@ static int rng_range(lua_State *L) { int x = luaL_checknumber(L, 1); int y = luaL_checknumber(L, 2); - lua_pushnumber(L, x + rand_div(1 + y - x)); + int res = x + rand_div(1 + y - x); + lua_pushnumber(L, res); return 1; } @@ -851,7 +852,8 @@ static int rng_call(lua_State *L) if (lua_isnumber(L, 2)) { int y = luaL_checknumber(L, 2); - lua_pushnumber(L, x + rand_div(1 + y - x)); + int res = x + rand_div(1 + y - x); + lua_pushnumber(L, res); } else {