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

stealth & such

git-svn-id: http://svn.net-core.org/repos/t-engine4@186 51575b47-30f0-44d4-a5cc-537603b46e54
parent 58afa088
No related branches found
No related tags found
No related merge requests found
Showing
with 116 additions and 10 deletions
...@@ -278,6 +278,12 @@ function _M:postUseTalent(ab, ret) ...@@ -278,6 +278,12 @@ function _M:postUseTalent(ab, ret)
end end
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 return true
end end
...@@ -300,6 +306,16 @@ function _M:canSee(actor) ...@@ -300,6 +306,16 @@ function _M:canSee(actor)
-- Blindness means can't see anything -- Blindness means can't see anything
if self:attr("blind") then return false, 0 end 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 -- Check for invisibility. This is a "simple" checkHit between invisible and see_invisible attrs
if actor:attr("invisible") then if actor:attr("invisible") then
-- Special case, 0 see invisible, can NEVER see invisible things -- Special case, 0 see invisible, can NEVER see invisible things
......
...@@ -163,7 +163,7 @@ function _M:display() ...@@ -163,7 +163,7 @@ function _M:display()
-- Display the map and compute FOV for the player if needed -- Display the map and compute FOV for the player if needed
if self.level.map.changed then if self.level.map.changed then
self.level.map:fov(self.player.x, self.player.y, 20) 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 end
self.level.map:display() self.level.map:display()
......
...@@ -42,6 +42,13 @@ The ToME combat system has the following attributes: ...@@ -42,6 +42,13 @@ The ToME combat system has the following attributes:
function _M:attackTarget(target, damtype, mult, noenergy) function _M:attackTarget(target, damtype, mult, noenergy)
local speed = nil 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 -- All weaponsin main hands
if self:getInven(self.INVEN_MAINHAND) then if self:getInven(self.INVEN_MAINHAND) then
for i, o in ipairs(self:getInven(self.INVEN_MAINHAND)) do for i, o in ipairs(self:getInven(self.INVEN_MAINHAND)) do
...@@ -76,6 +83,12 @@ function _M:attackTarget(target, damtype, mult, noenergy) ...@@ -76,6 +83,12 @@ function _M:attackTarget(target, damtype, mult, noenergy)
self:useEnergy(game.energy_to_act * speed) self:useEnergy(game.energy_to_act * speed)
self.did_energy = true self.did_energy = true
end end
-- Cancel stealth!
if self:isTalentActive(self.T_STEALTH) then
self:useTalent(self.T_STEALTH)
self.changed = true
end
end end
--- Computes a logarithmic chance to hit, opposing chance to hit to chance to miss --- 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) ...@@ -111,8 +124,10 @@ function _M:attackTargetWith(target, weapon, damtype, mult)
local hitted = false local hitted = false
if self:checkHit(atk, def) then if self:checkHit(atk, def) then
local dam = dam - math.max(0, armor - apr) local dam = dam - math.max(0, armor - apr)
local crit
dam = dam * mult 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)) DamageType:get(damtype).projector(self, target.x, target.y, damtype, math.max(0, dam))
hitted = true hitted = true
else else
...@@ -213,20 +228,32 @@ end ...@@ -213,20 +228,32 @@ end
--- Computes physical crit for a damage --- Computes physical crit for a damage
function _M:physicalCrit(dam, weapon) 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 chance = self:combatCrit(weapon)
local crit = false
if rng.percent(chance) then if rng.percent(chance) then
dam = dam * 2 dam = dam * 2
crit = true
end end
return dam return dam, crit
end end
--- Computes spell crit for a damage --- Computes spell crit for a damage
function _M:spellCrit(dam) 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 chance = self:combatSpellCrit()
local crit = false
if rng.percent(chance) then if rng.percent(chance) then
dam = dam * 2 dam = dam * 2
crit = true
end end
return dam return dam, crit
end end
--- Computes physical resistance --- Computes physical resistance
......
...@@ -73,11 +73,16 @@ newBirthDescriptor{ ...@@ -73,11 +73,16 @@ newBirthDescriptor{
"Rogues are masters of tricks, they can steal from shops and monsters", "Rogues are masters of tricks, they can steal from shops and monsters",
"and lure monsters into deadly traps.", "and lure monsters into deadly traps.",
}, },
stats = { dex=3, con=1, cun=2, }, stats = { dex=3, wil=1, cun=3, },
talents_types = { talents_types = {
["physical/dualweapon"]=true, ["physical/dualweapon"]=true,
["physical/combat-training"]=true, ["physical/combat-training"]=true,
["physical/weapon-training"]=true, ["physical/weapon-training"]=true,
["cunning/stealth"]=true,
},
talents_types_mastery = {
["physical/dualweapon"]=0.2,
["cunning/stealth"]=0.3,
}, },
} }
......
load("/data/talents/misc/misc.lua") load("/data/talents/misc/misc.lua")
load("/data/talents/spells/spells.lua") load("/data/talents/spells/spells.lua")
load("/data/talents/physical/physical.lua") load("/data/talents/physical/physical.lua")
load("/data/talents/misc/misc.lua") load("/data/talents/cunning/cunning.lua")
-- 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")
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,
}
...@@ -2,13 +2,11 @@ ...@@ -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/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/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/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/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." } 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/2hweapon.lua")
load("/data/talents/physical/dualweapon.lua") load("/data/talents/physical/dualweapon.lua")
load("/data/talents/physical/weaponshield.lua") load("/data/talents/physical/weaponshield.lua")
load("/data/talents/physical/dirty.lua")
load("/data/talents/physical/weapon-training.lua") load("/data/talents/physical/weapon-training.lua")
load("/data/talents/physical/combat-training.lua") load("/data/talents/physical/combat-training.lua")
...@@ -4,7 +4,7 @@ return { ...@@ -4,7 +4,7 @@ return {
level_scheme = "player", level_scheme = "player",
max_level = 5, max_level = 5,
width = 50, height = 50, width = 50, height = 50,
all_remembered = true, -- all_remembered = true,
-- all_lited = true, -- all_lited = true,
-- persistant = true, -- persistant = true,
generator = { generator = {
...@@ -27,7 +27,7 @@ return { ...@@ -27,7 +27,7 @@ return {
}, },
object = { object = {
class = "engine.generator.object.Random", class = "engine.generator.object.Random",
nb_object = {200, 500}, nb_object = {2, 5},
ood = {chance=5, range={1, 10}}, ood = {chance=5, range={1, 10}},
}, },
}, },
......
File added
No preview for this file type
No preview for this file type
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment