diff --git a/game/engine/Actor.lua b/game/engine/Actor.lua index e2e5e23ec542ebde8a0f924509452bf4ba99457e..f929906f1319c94d1e81638aff0b5451715da103 100644 --- a/game/engine/Actor.lua +++ b/game/engine/Actor.lua @@ -21,6 +21,12 @@ function _M:init(t) self.compute_vals = {} end +--- Called when it is time to act +function _M:act() + if self.dead then return false end + return true +end + --- Moves an actor on the map -- *WARNING*: changing x and y properties manualy is *WRONG* and will blow up in your face. Use this method. Always. -- @param map the map to move onto @@ -29,6 +35,7 @@ end -- @param force if true do not check for the presence of an other entity. *Use wisely* -- @return true if a move was *ATTEMPTED*. This means the actor will proably want to use energy function _M:move(map, x, y, force) + if self.dead then return true end if not force and map:checkAllEntities(x, y, "block_move", self) then return true end if self.x and self.y then diff --git a/game/engine/DamageType.lua b/game/engine/DamageType.lua index 5eed8e8f277a089257d91ff2d62f8b14d5ad2f83..af074e0f0482fe498ded39f42b16eb002b0c9ddd 100644 --- a/game/engine/DamageType.lua +++ b/game/engine/DamageType.lua @@ -36,6 +36,6 @@ function _M:newDamageType(t) end function _M:get(id) - assert(_M.dam_def[id], "damage type "..id.." used but undefined") + assert(_M.dam_def[id], "damage type "..tostring(id).." used but undefined") return _M.dam_def[id] end diff --git a/game/engine/interface/ActorTalents.lua b/game/engine/interface/ActorTalents.lua index 94ce098d1c0622728b76a5a81561e09a1be095c6..97a8b3750e4bad2e790fdfad44dac288e2732e18 100644 --- a/game/engine/interface/ActorTalents.lua +++ b/game/engine/interface/ActorTalents.lua @@ -13,6 +13,7 @@ function _M:loadDefinition(file) if not f and err then error(err) end setfenv(f, setmetatable({ DamageType = require("engine.DamageType"), + Talents = self, newTalent = function(t) self:newTalent(t) end, newTalentType = function(t) self:newTalentType(t) end, load = function(f) self:loadDefinition(f) end @@ -181,6 +182,8 @@ function _M:learnTalent(t_id, force) end end + if t.on_learn then t.on_learn(self) end + self.talents[t_id] = true self.changed = true return true @@ -190,9 +193,14 @@ end -- @param t_id the id of the talent to learn -- @return true if the talent was unlearnt, nil and an error message otherwise function _M:unlearnTalent(t_id) + local t = _M.talents_def[t_id] + for i, known_t_id in pairs(self.hotkey) do if known_t_id == t_id then self.hotkey[i] = nil end end + + if t.on_unlearn then t.on_unlearn(self) end + self.talents[t_id] = nil self.changed = true return true @@ -210,6 +218,11 @@ function _M:canLearnTalent(t) if t.require.level and self.level < t.require.level then return nil, "not enough levels" end + if t.require.talent then + for _, tid in ipairs(t.require.talent) do + if not self:knowTalent(tid) then return nil, "missing dependency" end + end + end end -- Check talent type @@ -248,6 +261,12 @@ function _M:getTalentReqDesc(t_id) local c = (self.level >= req.level) and "#00ff00#" or "#ff0000#" str = str .. ("- %sLevel %d\n"):format(c, req.level) end + if req.talent then + for _, tid in ipairs(req.talent) do + local c = self:knowTalent(tid) and "#00ff00#" or "#ff0000#" + str = str .. ("- %sTalent %s\n"):format(c, self:getTalentFromId(tid).name) + end + end return str end diff --git a/game/engine/interface/ActorTemporaryEffects.lua b/game/engine/interface/ActorTemporaryEffects.lua index 2716c9f64ac49defb16057f396a68ff0c2777142..eb6c5b400b416fca1122f7adc1ec99083d12cceb 100644 --- a/game/engine/interface/ActorTemporaryEffects.lua +++ b/game/engine/interface/ActorTemporaryEffects.lua @@ -10,6 +10,7 @@ _M.tempeffect_def = {} function _M:loadDefinition(file) local f = loadfile(file) setfenv(f, setmetatable({ + DamageType = require "engine.DamageType", newEffect = function(t) self:newEffect(t) end, load = function(f) self:loadDefinition(f) end }, {__index=_G})) diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 1a9bc768413973a97c0c77b585837f8ce0cb7043..f47ee59f9723e9541f2e8afce9df1e177d406988 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -57,6 +57,8 @@ function _M:init(t) end function _M:act() + if not engine.Actor.act(self) then return end + -- Cooldown talents self:cooldownTalents() -- Regen resources @@ -64,6 +66,8 @@ function _M:act() self:regenResources() -- Compute timed effects self:timedEffects() + + return true end function _M:move(x, y, force) diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua index a95aa38b44e31cab0b7bd38a951138497a8a524e..d4d108e9e9467f112f4fb5cb8185cf742c0a00cd 100644 --- a/game/modules/tome/class/interface/Combat.lua +++ b/game/modules/tome/class/interface/Combat.lua @@ -93,6 +93,7 @@ function _M:attackTargetWith(target, weapon) -- If hit is over 0 it connects, if it is 0 we still have 50% chance if rng.percent(hit) then local dam = dam - math.max(0, armor - apr) + dam = self:physicalCrit(dam, weapon) DamageType:get(damtype).projector(self, target.x, target.y, damtype, dam) else game.logSeen(target, "%s misses %s.", self.name:capitalize(), target.name) @@ -162,3 +163,21 @@ end function _M:combatSpellSpeed() return self.combat_spellspeed + (self:getCun() - 10) * 0.3 + 1 end + +--- Computes physical crit for a damage +function _M:physicalCrit(dam, weapon) + local chance = self:combatCrit(weapon) + if rng.percent(chance) then + dam = dam * 2 + end + return dam +end + +--- Computes spell crit for a damage +function _M:spellCrit(dam) + local chance = self:combatSpellCrit() + if rng.percent(chance) then + dam = dam * 2 + end + return dam +end diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua index 17c6ccd5b10d27d86191abd3501df6d7f146aef9..990c441e0836192ff9437de014013438a4133cb1 100644 --- a/game/modules/tome/data/damage_types.lua +++ b/game/modules/tome/data/damage_types.lua @@ -41,3 +41,15 @@ newDamageType{ game.level.map.lites(x, y, true) end, } + +newDamageType{ + name = "fireburn", type = "FIREBURN", + projector = function(src, x, y, type, dam) + DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam / 2) + local target = game.level.map(x, y, Map.ACTOR) + if target then + -- Set on fire! + target:setEffect(target.EFF_BURNING, 3, {src=src, power=dam / 2 / 3}) + end + end, +} diff --git a/game/modules/tome/data/talents/physical/physical.lua b/game/modules/tome/data/talents/physical/physical.lua index 14d02864f2d0a5f912f7c5a8de921c6ba86ca8ea..46ac3edd39a226614c8810ef09b34a8a4780df30 100644 --- a/game/modules/tome/data/talents/physical/physical.lua +++ b/game/modules/tome/data/talents/physical/physical.lua @@ -1,5 +1,7 @@ -- Physical combat newTalentType{ type="physical/2hweapon", name = "two handed weapons", description = "Allows the user to be more proficient with two handed weapons." } -newTalentType{ type="physical/1hweapon", name = "one handed weapons", description = "Allows the user to be more proficient with one 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 = "shields", description = "Allows the user to be more proficient with shields." } +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/weapontraining", name = "weapon training", description = "Grants bonuses to the different weapon types." } +newTalentType{ type="physical/combat training", name = "wombat training", description = "Teaches to use various armors and improves health." } diff --git a/game/modules/tome/data/talents/spells/arcane.lua b/game/modules/tome/data/talents/spells/arcane.lua index bedf71fbb17348c48b819bfd3606771ac10436ad..6488b3ac8d9e710e02c3359df390962f8c18ffb4 100644 --- a/game/modules/tome/data/talents/spells/arcane.lua +++ b/game/modules/tome/data/talents/spells/arcane.lua @@ -2,14 +2,16 @@ newTalent{ name = "Manathrust", type = {"spell/arcane", 1}, mana = 10, + cooldown = 3, tactical = { ATTACK = 10, }, action = function(self) local t = {type="bolt", range=20} + if self:knowTalent(Talents.T_ARCANE_LANCE) then t.type = "beam" end local x, y = self:getTarget(t) if not x or not y then return nil end - self:project(t, x, y, DamageType.ARCANE, 10 + self:combatSpellpower()) + self:project(t, x, y, DamageType.ARCANE, self:spellCrit(10 + self:combatSpellpower())) return true end, require = { stat = { mag=10 }, }, @@ -19,25 +21,18 @@ newTalent{ end, } newTalent{ - name = "Disruption Shield", - type = {"spell/arcane",2}, - mode = "sustained", - sustain_mana = 60, - tactical = { - DEFEND = 10, - }, - action = function(self) - return true - end, - require = { stat = { mag=50 }, }, + name = "Arcane Lance", + type = {"spell/arcane", 2}, + mode = "passive", + require = { stat = { mag=24 }, talent = { Talents.T_MANATHRUST }, }, info = function(self) - return ([[Uses mana instead of life to take damage - The damage to mana ratio increases with the Magic stat]]):format(10 + self:combatSpellpower()) + return [[Manathrust is now a beam and hits all targets in line.]] end, } + newTalent{ name = "Manaflow", - type = {"spell/arcane", 3}, + type = {"spell/arcane", 2}, mana = 0, cooldown = 300, tactical = { @@ -49,9 +44,43 @@ newTalent{ end return true end, - require = { stat = { mag=60 }, }, + require = { stat = { mag=34 }, }, info = function(self) return ([[Engulf yourself into a surge of mana, quickly restoring %d mana every turns for 10 turns. The mana restored will increase with the Magic stat]]):format(5 + self:combatSpellpower(0.3)) end, } + +newTalent{ + name = "Arcane Power", + type = {"spell/arcane", 3}, + mode = "passive", + require = { stat = { mag=40 }, }, + on_learn = function(self) + self.combat_spellpower = self.combat_spellpower + 10 + end, + on_unlearn = function(self) + self.combat_spellpower = self.combat_spellpower - 10 + end, + info = function(self) + return [[Your mastery of magic allows your to permanently increase your spellpower by 10.]] + end, +} + +newTalent{ + name = "Disruption Shield", + type = {"spell/arcane",4}, + mode = "sustained", + sustain_mana = 150, + tactical = { + DEFEND = 10, + }, + action = function(self) + return true + end, + require = { stat = { mag=60 }, level=40 }, + info = function(self) + return ([[Uses mana instead of life to take damage + The damage to mana ratio increases with the Magic stat]]):format(10 + self:combatSpellpower()) + end, +} diff --git a/game/modules/tome/data/talents/spells/fire.lua b/game/modules/tome/data/talents/spells/fire.lua index 45221b39c77c5bdb06026334ff2a657d3cb27082..85ad00faa07c5efa81e04f8208f25fd7bcacfe63 100644 --- a/game/modules/tome/data/talents/spells/fire.lua +++ b/game/modules/tome/data/talents/spells/fire.lua @@ -2,26 +2,61 @@ newTalent{ name = "Globe of Light", type = {"spell/fire",1}, mana = 5, + cooldown = 14, tactical = { ATTACKAREA = 3, }, action = function(self) - local t = {type="ball", range=0, friendlyfire=false, radius=5 + self:combatSpellpower(0.1)} + local t = {type="ball", range=0, friendlyfire=false, radius=5 + self:combatSpellpower(0.2)} self:project(t, self.x, self.y, DamageType.LIGHT, 1) + if self:knowTalent(Talents.T_GLOBE_OF_LIGHT) then + self:project(t, self.x, self.y, DamageType.BLIND, 1) + end return true end, require = { stat = { mag=10 }, }, info = function(self) return ([[Creates a globe of pure light with a radius of %d that illuminates the area. - The radius will increase with the Magic stat]]):format(5 + self:combatSpellpower(0.1)) + The radius will increase with the Magic stat]]):format(5 + self:combatSpellpower(0.2)) + end, +} +newTalent{ + name = "Blinding Light", + type = {"spell/fire", 2}, + mode = "passive", + require = { stat = { mag=24 }, talent = { Talents.T_GLOBE_OF_LIGHT }, }, + info = function(self) + return [[Globe of Light will also blind foes.]] + end, +} + +newTalent{ + name = "Flame", + type = {"spell/fire",1}, + mana = 12, + cooldown = 4, + tactical = { + ATTACKAREA = 10, + }, + action = function(self) + local t = {type="bolt", range=20} + local x, y = self:getTarget(t) + if not x or not y then return nil end + self:project(t, x, y, DamageType.FIREBURN, self:spellCrit(28 + self:combatSpellpower(0.7))) + return true + end, + require = { stat = { mag=10 }, }, + info = function(self) + return ([[Conjures up a bolt of fire doing %0.2f fire damage in a radius of %d. + The damage will increase with the Magic stat]]):format(8 + self:combatSpellpower(0.7), math.min(6, 3 + self:combatSpellpower(0.06))) end, } newTalent{ name = "Fireflash", type = {"spell/fire",2}, - mana = 35, - cooldown = 6, + mana = 40, + cooldown = 8, tactical = { ATTACKAREA = 10, }, @@ -29,13 +64,46 @@ newTalent{ local t = {type="ball", range=15, radius=math.min(6, 3 + self:combatSpellpower(0.06))} local x, y = self:getTarget(t) if not x or not y then return nil end - self:project(t, x, y, DamageType.FIRE, 28 + self:combatSpellpower(0.7)) + self:project(t, x, y, DamageType.FIRE, self:spellCrit(28 + self:combatSpellpower(0.7))) return true end, - require = { stat = { mag=16 }, }, + require = { stat = { mag=24 }, level=5, }, info = function(self) return ([[Conjures up a flash of fire doing %0.2f fire damage in a radius of %d. - Cooldown: 6 turns The damage will increase with the Magic stat]]):format(8 + self:combatSpellpower(0.7), math.min(6, 3 + self:combatSpellpower(0.06))) end, } + +newTalent{ + name = "Inferno", + type = {"spell/fire",4}, + mana = 200, + cooldown = 30, + tactical = { + ATTACKAREA = 40, + }, + action = function(self) + local duration = 5 + self:combatSpellpower(0.25) + local radius = 5 + local dam = 15 + self:combatSpellpower(0.25) + local t = {type="ball", range=20, radius=radius} + local x, y = self:getTarget(t) + if not x or not y then return nil end + x, y = game.target:pointAtRange(self.x, self.y, x, y, 15) + -- Add a lasting map effect + game.level.map:addEffect(self, + x, y, duration, + DamageType.NETHERFLAME, dam, + radius, + 5, nil, + engine.Entity.new{alpha=100, display='', color_br=180, color_bg=30, color_bb=60} + ) + return true + end, + require = { stat = { mag=34 }, level=2}, + info = function(self) + return ([[Raging flames burn foes and allies alike doing %0.2f netherflame damage in a radius of 5 each turns for %d turns. + Cooldown: 8 turns + The damage and duration will increase with the Magic stat]]):format(15 + self:combatSpellpower(0.25), 5 + self:combatSpellpower(0.25)) + end, +} diff --git a/game/modules/tome/data/talents/spells/nature.lua b/game/modules/tome/data/talents/spells/nature.lua index 59067a0856984abc0c7712e0af0760c80c299982..7a86230d7d85f422976747980ce53d62c8fdc2fa 100644 --- a/game/modules/tome/data/talents/spells/nature.lua +++ b/game/modules/tome/data/talents/spells/nature.lua @@ -26,7 +26,7 @@ newTalent{ HEAL = 10, }, action = function(self) - self:heal(10 + self:combatSpellpower(2), self) + self:heal(self:spellCrit(10 + self:combatSpellpower(2)), self) return true end, require = { stat = { mag=20 }, }, diff --git a/game/modules/tome/data/timed_effects.lua b/game/modules/tome/data/timed_effects.lua index 41f1c39276dfe6ae07422a11cf52da344c7daadf..d2bcd39add0721946f285be3d4538465d4c67a48 100644 --- a/game/modules/tome/data/timed_effects.lua +++ b/game/modules/tome/data/timed_effects.lua @@ -42,3 +42,16 @@ newEffect{ self:removeTemporaryValue("life_regen", eff.tmpid) end, } + +newEffect{ + name = "BURNING", + desc = "Burning", + type = "magical", + status = "detrimental", + parameters = { power=10 }, + on_gain = function(self, err) return "#Target# is on fire!", "+Burn" end, + on_lose = function(self, err) return "#Target# stops burning.", "-Burn" end, + on_timeout = function(self, eff) + DamageType:get(DamageType.FIRE).projector(eff.src, self.x, self.y, DamageType.FIRE, eff.power) + end, +} diff --git a/ideas/spells.ods b/ideas/spells.ods index 1d4224aafca37a0225dc344c20e9ec68644d1ecc..a22b916ca97ee085129ef648f50cc729f1b905ec 100644 Binary files a/ideas/spells.ods and b/ideas/spells.ods differ diff --git a/ideas/technics.ods b/ideas/technics.ods index 31ca4eab0d5ac645478f727d7c803c5fd9b578c3..d6fa0c2aef929095e960d39c6d46ca464242e0dc 100644 Binary files a/ideas/technics.ods and b/ideas/technics.ods differ