diff --git a/game/engine/interface/ActorTalents.lua b/game/engine/interface/ActorTalents.lua index 3757eb5c35ec39dc5a99e7eae9783573c18b539d..10ecbf5ee5fd49a2fb3a945e9221e3cffa094691 100644 --- a/game/engine/interface/ActorTalents.lua +++ b/game/engine/interface/ActorTalents.lua @@ -44,6 +44,10 @@ function _M:newTalent(t) assert(t.mode == "activated" or t.mode == "sustained", "wrong talent mode, requires either 'activated' or 'sustained'") assert(t.info, "no talent info") + -- Remove line stat with tabs to be cleaner .. + local info = t.info + t.info = function(self) return info(self):gsub("\n\t+", "\n") end + table.insert(self.talents_def, t) t.id = #self.talents_def self["T_"..t.short_name] = #self.talents_def @@ -155,6 +159,32 @@ function _M:canLearnTalent(t) return true end +--- Formats the requirements as a (multiline) string +-- @param t_id the id of the talent to desc +function _M:getTalentReqDesc(t_id) + local t = _M.talents_def[t_id] + local req = t.require + if not req then return "" end + + local str = "" + + if t.type[2] and t.type[2] > 1 then + str = str .. ("- Talents of the same category: %d\n"):format(t.type[2] - 1) + end + + -- Obviously this requires the ActorStats interface + if req.stat then + for s, v in pairs(req.stat) do + str = str .. ("- %s %d\n"):format(self.stats_def[s].name, v) + end + end + if req.level then + str = str .. ("- Level %d\n"):format(req.level) + end + + return str +end + --- Do we know this talent type function _M:knowTalentType(name) return self.talents_types[name] @@ -174,3 +204,19 @@ end function _M:getTalentTypeFrom(id) return _M.talents_types_def[id] end + +--- Actor learns a talent type +-- @param t_id the id of the talent to learn +-- @return true if the talent was learnt, nil and an error message otherwise +function _M:learnTalentType(tt) + self.talents_types[tt] = true + return true +end + +--- Actor forgets a talent type +-- @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:unlearnTalentType(tt) + self.talents_types[tt] = nil + return true +end diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 7c8145dd879c0c52aa1e6b2268a8dbfd8e17ac3d..d62ede71db5b3275de2d522dec42fa1da133c973 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -73,6 +73,8 @@ end function _M:levelup() self.unused_stats = self.unused_stats + 3 self.unused_talents = self.unused_talents + 1 + -- TODO: change it later, we need much less + self.unused_talents_types = self.unused_talents_types + 1 end --- Notifies a change of stat value @@ -98,7 +100,17 @@ end -- @param ab the talent (not the id, the table) -- @return true to continue, false to stop function _M:preUseTalent(ab) - return self:enoughEnergy() + local ret = self:enoughEnergy() + if ret == true then + if ab.message then + game.logSeen(self, "%s", self:useTalentMessage(ab)) + elseif ab.type[1]:find("^spell/") then + game.logSeen(self, "%s casts %s.", self.name:capitalize(), ab.name) + else + game.logSeen(self, "%s uses %s.", self.name:capitalize(), ab.name) + end + end + return ret end --- Called before a talent is used @@ -108,13 +120,6 @@ end -- @return true to continue, false to stop function _M:postUseTalent(ab, ret) if ret == nil then return end - if ab.message then - game.logSeen(self, "%s", self:useTalentMessage(ab)) - elseif ab.type[1]:find("^spell/") then - game.logSeen(self, "%s casts %s.", self.name:capitalize(), ab.name) - else - game.logSeen(self, "%s uses %s.", self.name:capitalize(), ab.name) - end self:useEnergy() return true end diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 76875d8dc3778ce3fd84a5c73f75b9c97f18799f..64547a9dcf55cef9d8948526e77593b1d1001a73 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -257,9 +257,19 @@ function _M:setupCommands() end, [{"_g","shift"}] = function() --- local d = LevelupStatsDialog.new(self.player) - local d = LevelupTalentsDialog.new(self.player) - self:registerDialog(d) + local none = true + if self.player.unused_stats > 0 then + local ds = LevelupStatsDialog.new(self.player) + self:registerDialog(ds) + none = false + elseif self.player.unused_talents > 0 or self.player.unused_talents_types > 0 then + local dt = LevelupTalentsDialog.new(self.player) + self:registerDialog(dt) + none = false + end + if none then + engine.Dialog:simplePopup("Nothing to level", "You character has no stat or talent points to spend. Levelup and try again.") + end end, _LEFT = function() self.player:move(self.player.x - 1, self.player.y ) end, diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index 7ed1d99567437ce67a78167b5b2f994a0f81adf5..c4084ca0a2e2f39662f174e374b920045f058f54 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -37,7 +37,10 @@ function _M:levelup() local x, y = game.level.map:getTileToScreen(self.x, self.y) game.flyers:add(x, y, 80, 0.5, -2, "LEVEL UP!", {0,255,255}) - game.log("#00ffff#Welcome to level %d", self.level) + game.log("#00ffff#Welcome to level %d.", self.level) + if self.unused_stats > 0 then game.log("You have %d stat point(s) to spend. Press G to use them.", self.unused_stats) end + if self.unused_talents > 0 then game.log("You have %d talent point(s) to spend. Press G to use them.", self.unused_talents) end + if self.unused_talents_types > 0 then game.log("You have %d talent category point(s) to spend. Press G to use them.", self.unused_talents_types) end end --- Tries to get a target from the user diff --git a/game/modules/tome/dialogs/LevelupStatsDialog.lua b/game/modules/tome/dialogs/LevelupStatsDialog.lua index 643b31865ea7c0415af0a8913ab0922e5f7f6d2c..b74e082aa87805b9799f46682e29b0470497ceec 100644 --- a/game/modules/tome/dialogs/LevelupStatsDialog.lua +++ b/game/modules/tome/dialogs/LevelupStatsDialog.lua @@ -1,5 +1,6 @@ require "engine.class" require "engine.Dialog" +local LevelupTalentsDialog = require "mod.dialogs.LevelupTalentsDialog" module(..., package.seeall, class.inherit(engine.Dialog)) @@ -15,7 +16,15 @@ function _M:init(actor) _DOWN = function() self.statsel = util.boundWrap(self.statsel + 1, 1, 6) end, _LEFT = function() self:incStat(-1) end, _RIGHT = function() self:incStat(1) end, - _ESCAPE = function() game:unregisterDialog(self) end, + _ESCAPE = function() + game:unregisterDialog(self) + + -- if talents to spend, do it now + if self.actor.unused_talents > 0 or self.actor.unused_talents_types > 0 then + local dt = LevelupTalentsDialog.new(self.actor) + game:registerDialog(dt) + end + end, } self:mouseZones{ { x=2, y=25, w=130, h=self.font_h*6, fct=function(button, x, y, xrel, yrel, tx, ty) diff --git a/game/modules/tome/dialogs/LevelupTalentsDialog.lua b/game/modules/tome/dialogs/LevelupTalentsDialog.lua index f260004f136643b6feb2fbaaa130d9a3c59bb0f1..c18b95e017197c06678e0562649a61b319922ae0 100644 --- a/game/modules/tome/dialogs/LevelupTalentsDialog.lua +++ b/game/modules/tome/dialogs/LevelupTalentsDialog.lua @@ -34,14 +34,18 @@ function _M:generateList() for i, tt in ipairs(self.actor.talents_types_def) do local cat = tt.type:gsub("/.*", "") list[#list+1] = { name=cat:capitalize().." / "..tt.name:capitalize() .." (category)", type=tt.type } - if self.actor:knowTalentType(tt.type) then known[#known+1] = "#00FF00#known" else known[#known+1] = tt.points.." point(s)" end - - -- Find all talents of this school - for j, t in ipairs(tt.talents) do - local typename = "talent" - if t.type[1]:find("^spell/") then typename = "spell" end - list[#list+1] = { name=" "..t.name.." ("..typename..")", talent=t.id } - if self.actor:knowTalent(t.id) then known[#known+1] = "#00FF00#known" else known[#known+1] = t.points.." point(s)" end + if self.actor:knowTalentType(tt.type) then + known[#known+1] = "#00FF00#known" + + -- Find all talents of this school + for j, t in ipairs(tt.talents) do + local typename = "talent" + if t.type[1]:find("^spell/") then typename = "spell" end + list[#list+1] = { name=" "..t.name.." ("..typename..")", talent=t.id } + if self.actor:knowTalent(t.id) then known[#known+1] = "#00FF00#known" else known[#known+1] = t.points.." point(s)" end + end + else + known[#known+1] = tt.points.." point(s)" end end self.list = list @@ -93,12 +97,14 @@ function _M:learnType(tt, v) self:simplePopup("Not enough talent category points", "You have no talent category points left!") return end + self.actor:learnTalentType(tt) self.actor.unused_talents_types = self.actor.unused_talents_types - 1 else if self.actor_dup:getStat(self.talentsel) == self.actor:getStat(self.talentsel) then self:simplePopup("Impossible", "You cannot take out more points!") return end + self.actor:unlearnTalentType(tt) self.actor.unused_talents_types = self.actor.unused_talents_types + 1 end @@ -113,7 +119,7 @@ function _M:drawDialog(s) Mouse: #00FF00#Left click#FFFFFF# to learn; #00FF00#right click#FFFFFF# to unlearn. ]]):splitLines(self.iw / 2 - 10, self.font) - local lines, helplines = {} + local lines, helplines, reqlines = {}, {}, {} if self.list[self.talentsel].type then local str = "" str = str .. "#00FFFF#Talent Category\n" @@ -126,17 +132,39 @@ Mouse: #00FF00#Left click#FFFFFF# to learn; #00FF00#right click#FFFFFF# to unlea str = str .. "#00FFFF#A talent allows you to perform new combat moves, cast spells, improve your character. You gain a talent point every level. You may also find trainers or artifacts that allows you to learn more.\n\n" helplines = str:splitLines(self.iw / 2 - 10, self.font) lines = self.actor:getTalentFromId(self.list[self.talentsel].talent).info(self.actor):splitLines(self.iw / 2 - 10, self.font) + local req = self.actor:getTalentReqDesc(self.list[self.talentsel].talent) + if req ~= "" then + req = "Requirements:\n"..req + reqlines = req:splitLines(self.iw / 2 - 10, self.font) + end end + local h = 2 for i = 1, #talentshelp do - s:drawColorString(self.font, talentshelp[i], self.iw / 2 + 5, 2 + (i-1) * self.font:lineSkip()) + s:drawColorString(self.font, talentshelp[i], self.iw / 2 + 5, h) + h = h + self.font:lineSkip() end - self:drawWBorder(s, self.iw / 2 + self.iw / 6, 2 + (0.5 + #talentshelp) * self.font:lineSkip(), self.iw / 6) + + h = h + self.font:lineSkip() + self:drawWBorder(s, self.iw / 2 + self.iw / 6, h - 0.5 * self.font:lineSkip(), self.iw / 6) for i = 1, #helplines do - s:drawColorString(self.font, helplines[i], self.iw / 2 + 5, 2 + (i + #talentshelp) * self.font:lineSkip()) + s:drawColorString(self.font, helplines[i], self.iw / 2 + 5, h) + h = h + self.font:lineSkip() end - self:drawWBorder(s, self.iw / 2 + self.iw / 6, 2 + (1.5 + #talentshelp + #helplines) * self.font:lineSkip(), self.iw / 6) + + if #reqlines > 0 then + h = h + self.font:lineSkip() + self:drawWBorder(s, self.iw / 2 + self.iw / 6, h - 0.5 * self.font:lineSkip(), self.iw / 6) + for i = 1, #reqlines do + s:drawColorString(self.font, reqlines[i], self.iw / 2 + 5, h) + h = h + self.font:lineSkip() + end + end + + h = h + self.font:lineSkip() + self:drawWBorder(s, self.iw / 2 + self.iw / 6, h - 0.5 * self.font:lineSkip(), self.iw / 6) for i = 1, #lines do - s:drawColorString(self.font, lines[i], self.iw / 2 + 5, 2 + (i + #helplines + #talentshelp + 2) * self.font:lineSkip()) + s:drawColorString(self.font, lines[i], self.iw / 2 + 5, 2 + h) + h = h + self.font:lineSkip() end -- Talents