diff --git a/game/engine/Actor.lua b/game/engine/Actor.lua index f929906f1319c94d1e81638aff0b5451715da103..722248b006033bc14dec659eb9c965bc7a5aab7b 100644 --- a/game/engine/Actor.lua +++ b/game/engine/Actor.lua @@ -160,3 +160,24 @@ function _M:removeTemporaryValue(prop, id, noupdate) end end end + +--- Increases/decreases an attribute +-- The attributes are just actor properties, but this ensures they are numbers and not booleans +-- thus making them compatible with temporary values system +-- @param prop the property to use +-- @param v the value to add, if nil this the function return +-- @param fix forces the value to v, do not add +-- @return nil if v was specified. If not then it returns the current value if it exists and is not 0 otherwise returns nil +function _M:attr(prop, v, fix) + if v then + if fix then self.prop = v + else self.prop = (self.prop or 0) + v + end + else + if self.prop and self.prop ~= 0 then + return self.prop + else + return nil + end + end +end diff --git a/game/engine/interface/ActorTalents.lua b/game/engine/interface/ActorTalents.lua index 97a8b3750e4bad2e790fdfad44dac288e2732e18..dd4b6c5042fd7de265ed09e1975565a0aed14da9 100644 --- a/game/engine/interface/ActorTalents.lua +++ b/game/engine/interface/ActorTalents.lua @@ -14,6 +14,7 @@ function _M:loadDefinition(file) setfenv(f, setmetatable({ DamageType = require("engine.DamageType"), Talents = self, + Map = require("engine.Map"), newTalent = function(t) self:newTalent(t) end, newTalentType = function(t) self:newTalentType(t) end, load = function(f) self:loadDefinition(f) end diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index f47ee59f9723e9541f2e8afce9df1e177d406988..389188e70325ffeb7209dac5f9eb6d6163869c98 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -73,13 +73,31 @@ end function _M:move(x, y, force) local moved = false if force or self:enoughEnergy() then - moved = engine.Actor.move(self, game.level.map, x, y, force) + -- Should we prob travel through walls ? + if not force and self:attr("prob_travel") and game.level.map:checkEntity(x, y, Map.TERRAIN, "block_move", self) then + moved = self:probabilityTravel(x, y) + else + moved = engine.Actor.move(self, game.level.map, x, y, force) + end if not force and moved and not self.did_energy then self:useEnergy() end end self.did_energy = nil return moved end +function _M:probabilityTravel(x, y) + local dirx, diry = x - self.x, y - self.y + local tx, ty = x, y + while game.level.map:checkEntity(x, y, Map.TERRAIN, "block_move", self) do + tx = tx + dirx + ty = ty + diry + end + if game.level.map:isBound(x, y) then + return engine.Actor.move(self, game.level.map, tx, ty, false) + end + return true +end + function _M:tooltip() return ("%s\n#00ffff#Level: %d\nExp: %d/%d\n#ff0000#HP: %d"):format(self.name, self.level, self.exp, self:getExpChart(self.level+1) or "---", self.life) end diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index 49d917776a488c46b07a5ec14c3297a15b67f939..72cd7bdfc6c4b4461fbd22af63b8a52039728776 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -89,7 +89,10 @@ function _M:getTarget(typ) if coroutine.running() then local msg if type(typ) == "string" then msg, typ = typ, nil - elseif type(typ) == "table" then msg = typ.msg end + elseif type(typ) == "table" then + if typ.default_target then self.target.target.entity = typ.default_target end + msg = typ.msg + end game:targetMode("exclusive", msg, coroutine.running(), typ) return coroutine.yield() end diff --git a/game/modules/tome/data/talents/spells/arcane.lua b/game/modules/tome/data/talents/spells/arcane.lua index 6488b3ac8d9e710e02c3359df390962f8c18ffb4..f03b6cde583833fe027a36862fe2737c2d677fb6 100644 --- a/game/modules/tome/data/talents/spells/arcane.lua +++ b/game/modules/tome/data/talents/spells/arcane.lua @@ -75,7 +75,8 @@ newTalent{ tactical = { DEFEND = 10, }, - action = function(self) + activate = function(self) + game.log("IMPLEMENT ME!") return true end, require = { stat = { mag=60 }, level=40 }, diff --git a/game/modules/tome/data/talents/spells/conveyance.lua b/game/modules/tome/data/talents/spells/conveyance.lua index 67bf132628bcfebeb1294271fb3167f5789b6d35..0521bf433ef6259e0b996efc5a0fa4e7d04c6b4f 100644 --- a/game/modules/tome/data/talents/spells/conveyance.lua +++ b/game/modules/tome/data/talents/spells/conveyance.lua @@ -2,26 +2,35 @@ newTalent{ name = "Phase Door", type = {"spell/conveyance",1}, message = "@Source@ blinks.", - mana = 15, - cooldown = 9, + mana = 10, + cooldown = 8, tactical = { ESCAPE = 4, }, action = function(self) + local target = self + + if self:knowTalent(Talents.T_TARGETED_TELEPORT) then + local tx, ty = self:getTarget{default_target=self, type="hit", range=10} + if tx and ty then + target = game.level.map(tx, ty, Map.ACTOR) or self + end + end + local x, y = self.x, self.y - if self:knowTalent(self.T_TELEPORT_CONTROL) then - x, y = self:getTarget{type="ball", range=10 + self:combatSpellpower(0.1), radius=5 - self:combatSpellpower(0.04)} + if self:knowTalent(Talents.T_CONTROLLED_TELEPORT) then + x, y = self:getTarget{type="ball", range=10 + self:combatSpellpower(0.1), radius=5 - self:combatSpellpower(0.03)} if not x then return nil end -- Target code doesnot restrict the target coordinates to the range, it lets the poject function do it -- but we cant ... x, y = game.target:pointAtRange(self.x, self.y, x, y, 10 + self:combatSpellpower(0.1)) - self:teleportRandom(x, y, 5 - self:combatSpellpower(0.4)) + target:teleportRandom(x, y, 5 - self:combatSpellpower(0.03)) else - self:teleportRandom(x, y, 10 + self:combatSpellpower(0.1)) + target:teleportRandom(x, y, 10 + self:combatSpellpower(0.1)) end return true end, - require = { stat = { mag=12 }, }, + require = { stat = { mag=15 }, }, info = function(self) return ([[Teleports you randomly on a small scale range (%d) The range will increase with the Magic stat]]):format(10 + self:combatSpellpower(0.1)) @@ -29,12 +38,133 @@ newTalent{ } newTalent{ - name = "Teleport Control", + name = "Teleport", type = {"spell/conveyance",2}, + message = "@Source@ teleports away.", + mana = 20, + cooldown = 30, + tactical = { + ESCAPE = 8, + }, + action = function(self) + local target = self + + if self:knowTalent(Talents.T_TARGETED_TELEPORT) then + local tx, ty = self:getTarget{default_target=self, type="hit", range=10} + if tx and ty then + target = game.level.map(tx, ty, Map.ACTOR) or self + end + end + + local x, y = self.x, self.y + if self:knowTalent(Talents.T_CONTROLLED_TELEPORT) then + x, y = self:getTarget{type="ball", range=100 + self:combatSpellpower(1), radius=5 - self:combatSpellpower(0.03)} + if not x then return nil end + -- Target code doesnot restrict the target coordinates to the range, it lets the poject function do it + -- but we cant ... + x, y = game.target:pointAtRange(self.x, self.y, x, y, 10 + self:combatSpellpower(0.1)) + target:teleportRandom(x, y, 5 - self:combatSpellpower(0.03)) + else + target:teleportRandom(x, y, 100 + self:combatSpellpower(1)) + end + return true + end, + require = { stat = { mag=24 }, }, + info = function(self) + return ([[Teleports you randomly on a small scale range (%d) + The range will increase with the Magic stat]]):format(10 + self:combatSpellpower(0.1)) + end, +} + +newTalent{ + name = "Controlled Teleport", + type = {"spell/conveyance",4}, mode = "passive", - require = { stat = { mag=38 }, }, + points = 2, + require = { stat = { mag=50 }, talent = {Talents.T_TELEPORT}, }, info = function(self) return ([[Allows teleport spells to specify a target area. You will blink in this radius randomly. - The radius (%d) of the target area decreases with Magic stat]]):format(5 - self:combatSpellpower(0.04)) + The radius (%d) of the target area decreases with Magic stat]]):format(5 - self:combatSpellpower(0.03)) + end, +} + +newTalent{ + name = "Targeted Teleport", + type = {"spell/conveyance",4}, + mode = "passive", + require = { stat = { mag=50 }, talent = {Talents.T_TELEPORT}, }, + info = function(self) + return ([[Allows teleport spells to specify the affected target, either you, allies or foes.]]) + end, +} + +newTalent{ + name = "Probability Travel", + type = {"spell/conveyance",4}, + mode = "sustained", + points = 2, + cooldown = 40, + sustain_mana = 100, + tactical = { + MOVEMENT = 20, + }, + activate = function(self) + self:attr("prob_travel", 1) + return true + end, + deactivate = function(self) + self:attr("prob_travel", -1) + return true + end, + require = { stat = { mag=34 }, level=25 }, + info = function(self) + return ([[When you hit a solid surface this spell tears down the laws of probability to make you instantly appear on the other side.]]) + end, +} + +newTalent{ + name = "Recall", + type = {"spell/conveyance",3}, + mana = 30, + cooldown = 10, + action = function(self) +--[[ + local target = self + local tx, ty = self.x, self.y + if self:knowTalent(Talents.T_TELEKINESIS) or self:knowTalent(Talents.T_IMPERIOUS_SUMMON) then + local tx, ty = self:getTarget{default_target=self, type="hit", range=20} + if tx and ty then + target = game.level.map(tx, ty, Map.ACTOR) or self + end + end + + if +]] + game.log("IMPLEMENT ME!") + return true + end, + require = { stat = { mag=34 }, }, + info = function(self) + return ([[Recalls you to your home town after a few turns.]]) + end, +} + +newTalent{ + name = "Telekinesis", + type = {"spell/conveyance",4}, + mode = "passive", + require = { stat = { mag=50 }, }, + info = function(self) + return ([[Recall can now target an object on the floor to teleport it to your inventory.]]) + end, +} + +newTalent{ + name = "Imperious Summon", + type = {"spell/conveyance",4}, + mode = "passive", + require = { stat = { mag=50 }, }, + info = function(self) + return ([[Recall can now target your foes to teleport one to you.]]) end, } diff --git a/game/modules/tome/dialogs/LevelupTalentsDialog.lua b/game/modules/tome/dialogs/LevelupTalentsDialog.lua index 1b9e4365eed52cde4096a751fcb30a703e52ae45..703c84a81abb2061d2860fd1f3738de92ff28942 100644 --- a/game/modules/tome/dialogs/LevelupTalentsDialog.lua +++ b/game/modules/tome/dialogs/LevelupTalentsDialog.lua @@ -72,33 +72,34 @@ function _M:learn(v) end end -function _M:learnTalent(t, v) +function _M:learnTalent(t_id, v) + local t = self.actor:getTalentFromId(t_id) if v then - if self.actor.unused_talents == 0 then + if self.actor.unused_talents < t.points then self:simplePopup("Not enough talent points", "You have no talent points left!") return end - if not self.actor:canLearnTalent(self.actor:getTalentFromId(t)) then + if not self.actor:canLearnTalent(t_id) then self:simplePopup("Cannot learn talent", "Prerequisites not met!") return end - if self.actor:knowTalent(t) then + if self.actor:knowTalent(t_id) then self:simplePopup("Already known", "You already know this talent!") return end - self.actor:learnTalent(t) - self.actor.unused_talents = self.actor.unused_talents - 1 + self.actor:learnTalent(t_id) + self.actor.unused_talents = self.actor.unused_talents - t.points else - if not self.actor:knowTalent(t) then + if not self.actor:knowTalent(t_id) then self:simplePopup("Impossible", "You do not know this talent!") return end - if self.actor_dup:knowTalent(t) == true and self.actor:knowTalent(t) == true then + if self.actor_dup:knowTalent(t_id) == true and self.actor:knowTalent(t_id) == true then self:simplePopup("Impossible", "You cannot unlearn talents!") return end - self.actor:unlearnTalent(t) - self.actor.unused_talents = self.actor.unused_talents + 1 + self.actor:unlearnTalent(t_id) + self.actor.unused_talents = self.actor.unused_talents + t.points end self:generateList() end diff --git a/ideas/spells.ods b/ideas/spells.ods index a22b916ca97ee085129ef648f50cc729f1b905ec..50cbe18f0563d209e2a0278ea440b3985bc8152e 100644 Binary files a/ideas/spells.ods and b/ideas/spells.ods differ diff --git a/ideas/technics.ods b/ideas/technics.ods index d6fa0c2aef929095e960d39c6d46ca464242e0dc..f3a7128754c0681497303e156ad55b5ed837fff5 100644 Binary files a/ideas/technics.ods and b/ideas/technics.ods differ