diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index d9b20c37273a6005e1aee1a3e4639ed8ec0f3066..1a0cb61bd5d0476e7fb356beca8dee35069797f8 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -278,6 +278,12 @@ function _M:postUseTalent(ab, ret) end end + -- Cancel stealth! + if ab.id ~= self.T_STEALTH and self:isTalentActive(self.T_STEALTH) then + self:useTalent(self.T_STEALTH) + self.changed = true + end + return true end @@ -300,6 +306,16 @@ function _M:canSee(actor) -- Blindness means can't see anything if self:attr("blind") then return false, 0 end + -- Check for stealth. Checks against the target cunning and level + if actor:attr("stealth") and actor ~= self then + local def = self.level / 2 + self:getCun(25) + local hit, chance = self:checkHit(def, actor:attr("stealth") + (actor:attr("inc_stealth") or 0), 0, 100) + print("Stealth", actor:attr("stealth") + (actor:attr("inc_stealth") or 0), "<:>", def, " ===> ", hit, chance) + if not hit then + return false, chance + end + end + -- Check for invisibility. This is a "simple" checkHit between invisible and see_invisible attrs if actor:attr("invisible") then -- Special case, 0 see invisible, can NEVER see invisible things diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 0f9930882ad957786451989eb8069b8b59fd42fd..c77f1b062bd238edaf81cc9d12f9beeabdb10a2b 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -163,7 +163,7 @@ function _M:display() -- Display the map and compute FOV for the player if needed if self.level.map.changed then self.level.map:fov(self.player.x, self.player.y, 20) - self.level.map:fovLite(self.player.x, self.player.y, self.player.lite) + if self.player.lite > 0 then self.level.map:fovLite(self.player.x, self.player.y, self.player.lite) end end self.level.map:display() diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua index fde51c7a7075a731441e803766747ac396fcdd72..64050f83c662e65f6ada3750ded5a89a92dd8b1b 100644 --- a/game/modules/tome/class/interface/Combat.lua +++ b/game/modules/tome/class/interface/Combat.lua @@ -42,6 +42,13 @@ The ToME combat system has the following attributes: function _M:attackTarget(target, damtype, mult, noenergy) local speed = nil + -- Cancel stealth early if we are noticed + if self:isTalentActive(self.T_STEALTH) and target:canSee(self) then + self:useTalent(self.T_STEALTH) + self.changed = true + game.logPlayer(self, "%s notices you at the last moment!", target.name:capitalize()) + end + -- All weaponsin main hands if self:getInven(self.INVEN_MAINHAND) then for i, o in ipairs(self:getInven(self.INVEN_MAINHAND)) do @@ -76,6 +83,12 @@ function _M:attackTarget(target, damtype, mult, noenergy) self:useEnergy(game.energy_to_act * speed) self.did_energy = true end + + -- Cancel stealth! + if self:isTalentActive(self.T_STEALTH) then + self:useTalent(self.T_STEALTH) + self.changed = true + end end --- Computes a logarithmic chance to hit, opposing chance to hit to chance to miss @@ -111,8 +124,10 @@ function _M:attackTargetWith(target, weapon, damtype, mult) local hitted = false if self:checkHit(atk, def) then local dam = dam - math.max(0, armor - apr) + local crit dam = dam * mult - dam = self:physicalCrit(dam, weapon) + dam, crit = self:physicalCrit(dam, weapon) + game.logSeen(self, "%s performs a critical stike!", self.name:capitalize()) DamageType:get(damtype).projector(self, target.x, target.y, damtype, math.max(0, dam)) hitted = true else @@ -213,20 +228,32 @@ end --- Computes physical crit for a damage function _M:physicalCrit(dam, weapon) + if self:isTalentActive(self.T_STEALTH) and self:knowTalent(self.T_SHADOWSTRIKE) then + return dam * (2 + self:getTalentLevel(self.T_SHADOWSTRIKE) / 5), true + end + local chance = self:combatCrit(weapon) + local crit = false if rng.percent(chance) then dam = dam * 2 + crit = true end - return dam + return dam, crit end --- Computes spell crit for a damage function _M:spellCrit(dam) + if self:isTalentActive(self.T_STEALTH) and self:knowTalent(self.T_SHADOWSTRIKE) then + return dam * (2 + self:getTalentLevel(self.T_SHADOWSTRIKE) / 5), true + end + local chance = self:combatSpellCrit() + local crit = false if rng.percent(chance) then dam = dam * 2 + crit = true end - return dam + return dam, crit end --- Computes physical resistance diff --git a/game/modules/tome/data/birth/classes.lua b/game/modules/tome/data/birth/classes.lua index 1cb13b7420bb5a9f80bbe2edecdba7fabd213a55..a85ca2281f4d965888ee8ff44756cd51d6fcd704 100644 --- a/game/modules/tome/data/birth/classes.lua +++ b/game/modules/tome/data/birth/classes.lua @@ -73,11 +73,16 @@ newBirthDescriptor{ "Rogues are masters of tricks, they can steal from shops and monsters", "and lure monsters into deadly traps.", }, - stats = { dex=3, con=1, cun=2, }, + stats = { dex=3, wil=1, cun=3, }, talents_types = { ["physical/dualweapon"]=true, ["physical/combat-training"]=true, ["physical/weapon-training"]=true, + ["cunning/stealth"]=true, + }, + talents_types_mastery = { + ["physical/dualweapon"]=0.2, + ["cunning/stealth"]=0.3, }, } diff --git a/game/modules/tome/data/talents.lua b/game/modules/tome/data/talents.lua index 14ac1a16f16306988d3e2746b99d97de07bc5de0..143a20c9ea7abab82ad0231499868c7e48297825 100644 --- a/game/modules/tome/data/talents.lua +++ b/game/modules/tome/data/talents.lua @@ -1,4 +1,4 @@ load("/data/talents/misc/misc.lua") load("/data/talents/spells/spells.lua") load("/data/talents/physical/physical.lua") -load("/data/talents/misc/misc.lua") +load("/data/talents/cunning/cunning.lua") diff --git a/game/modules/tome/data/talents/cunning/cunning.lua b/game/modules/tome/data/talents/cunning/cunning.lua new file mode 100644 index 0000000000000000000000000000000000000000..6e30c90b635df56eaee9494b5d354a10a494a40e --- /dev/null +++ b/game/modules/tome/data/talents/cunning/cunning.lua @@ -0,0 +1,8 @@ +-- Cunning talents +newTalentType{ type="cunning/stealth", name = "stealth", description = "Allows the user to enter stealth." } +newTalentType{ type="cunning/traps", name = "traps", description = "The knowledge of traps." } +newTalentType{ type="cunning/dirty", name = "dirty fighting", description = "Teaches various talents to criple your foes." } + +load("/data/talents/cunning/stealth.lua") +load("/data/talents/cunning/traps.lua") +load("/data/talents/cunning/dirty.lua") diff --git a/game/modules/tome/data/talents/physical/dirty.lua b/game/modules/tome/data/talents/cunning/dirty.lua similarity index 100% rename from game/modules/tome/data/talents/physical/dirty.lua rename to game/modules/tome/data/talents/cunning/dirty.lua diff --git a/game/modules/tome/data/talents/cunning/stealth.lua b/game/modules/tome/data/talents/cunning/stealth.lua new file mode 100644 index 0000000000000000000000000000000000000000..f224812b7656eb045107dded524765728b775081 --- /dev/null +++ b/game/modules/tome/data/talents/cunning/stealth.lua @@ -0,0 +1,52 @@ +newTalent{ + name = "Stealth", + type = {"cunning/stealth", 1}, + mode = "sustained", + points = 5, + cooldown = 10, + require = { stat = { cun=12 }, }, + activate = function(self, t) + local armor = self:getInven("BODY")[1] + if armor and (armor.subtype == "heavy" or armor.subtype == "massive") then + game.logPlayer(self, "You cannot Stealth with such heavy armour!") + return nil + end + + -- Check nearby actors + local grids = core.fov.circle_grids(self.x, self.y, math.floor(10 - self:getTalentLevel(t) * 1.3), true) + for x, yy in pairs(grids) do for y in pairs(yy) do + local actor = game.level.map(x, y, game.level.map.ACTOR) + if actor and actor ~= self and actor:reactionToward(self) < 0 then + game.logPlayer(self, "You cannot Stealth with nearby foes watching!") + return nil + end + end end + + return { + stealth = self:addTemporaryValue("stealth", self:getCun(10) * self:getTalentLevel(t)), + lite = self:addTemporaryValue("lite", -100), + } + end, + deactivate = function(self, t, p) + self:removeTemporaryValue("stealth", p.stealth) + self:removeTemporaryValue("lite", p.lite) + return true + end, + info = function(self, t) + return ([[Enters stealth mode, making you harder to detect. + While in stealth mode, light radius is reduced to 0. + There needs to be no foes in sight in a radius of %d around you to enter stealth.]]):format(math.floor(10 - self:getTalentLevel(t) * 1.3)) + end, +} + +newTalent{ + name = "Shadowstrike", + type = {"cunning/stealth", 1}, + mode = "passive", + points = 5, + require = { stat = { cun=18 }, }, + info = function(self, t) + return ([[When striking from stealth, hits are automatically criticals if the target does not notice you. + Shadowstrikes do %.02f%% more damage than a normal hit.]]):format(math.floor(2 + self:getTalentLevel(t) / 5)) + end, +} diff --git a/game/modules/tome/data/talents/cunning/traps.lua b/game/modules/tome/data/talents/cunning/traps.lua new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/game/modules/tome/data/talents/physical/physical.lua b/game/modules/tome/data/talents/physical/physical.lua index 778173bb6954c8ce7b63c9b979e6da49dae2ec79..ca5980d0092b6521a9826eeff1b1cf3e16543ff4 100644 --- a/game/modules/tome/data/talents/physical/physical.lua +++ b/game/modules/tome/data/talents/physical/physical.lua @@ -2,13 +2,11 @@ newTalentType{ type="physical/2hweapon", name = "two handed weapons", description = "Allows the user to be more proficient with two handed weapons." } newTalentType{ type="physical/dualweapon", name = "dual wielding", description = "Allows the user to be more proficient with dual wielding weapons." } newTalentType{ type="physical/shield", name = "weapon and shields", description = "Allows the user to be more proficient with shields and one handed weapons." } -newTalentType{ type="physical/dirty", name = "dirty fighting", description = "Teaches various physical talents to criple your foes." } newTalentType{ type="physical/weapon-training", name = "weapon-training", description = "Grants bonuses to the different weapon types." } newTalentType{ type="physical/combat-training", name = "combat-training", description = "Teaches to use various armors and improves health." } load("/data/talents/physical/2hweapon.lua") load("/data/talents/physical/dualweapon.lua") load("/data/talents/physical/weaponshield.lua") -load("/data/talents/physical/dirty.lua") load("/data/talents/physical/weapon-training.lua") load("/data/talents/physical/combat-training.lua") diff --git a/game/modules/tome/data/zones/tower-amon-sul/zone.lua b/game/modules/tome/data/zones/tower-amon-sul/zone.lua index c24cb29259a21744cef030c60bbec6c3a265f2c8..a73f3476d6d76d32dac05aa08ea883b0b164cbfc 100644 --- a/game/modules/tome/data/zones/tower-amon-sul/zone.lua +++ b/game/modules/tome/data/zones/tower-amon-sul/zone.lua @@ -4,7 +4,7 @@ return { level_scheme = "player", max_level = 5, width = 50, height = 50, - all_remembered = true, +-- all_remembered = true, -- all_lited = true, -- persistant = true, generator = { @@ -27,7 +27,7 @@ return { }, object = { class = "engine.generator.object.Random", - nb_object = {200, 500}, + nb_object = {2, 5}, ood = {chance=5, range={1, 10}}, }, }, diff --git a/ideas/cunning.ods b/ideas/cunning.ods new file mode 100644 index 0000000000000000000000000000000000000000..17e62e4d39e9247231f30fbe7eae99750d3cbf6b Binary files /dev/null and b/ideas/cunning.ods differ diff --git a/ideas/spells.ods b/ideas/spells.ods index eadd0142aa687141bc5f134ec9fdd0388d32e7d2..ad35ee00bac2a532847ba5034f8948e3a57f0f25 100644 Binary files a/ideas/spells.ods and b/ideas/spells.ods differ diff --git a/ideas/technics.ods b/ideas/technics.ods index 55859dcb12b0de24a271df84d3bc81c9b7408ed4..6ff3174ec760c72d3bc54466e83fa4916f7b8b40 100644 Binary files a/ideas/technics.ods and b/ideas/technics.ods differ