From 30f12a5d8a96696a1e79a644d7ab3c4a312f53f7 Mon Sep 17 00:00:00 2001 From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54> Date: Sat, 3 Apr 2010 19:53:27 +0000 Subject: [PATCH] achievements! git-svn-id: http://svn.net-core.org/repos/t-engine4@492 51575b47-30f0-44d4-a5cc-537603b46e54 --- game/engine/Dialog.lua | 3 +- game/engine/dialogs/GameMenu.lua | 5 ++ game/engine/dialogs/ShowAchievements.lua | 77 ++++++++++++++++++++ game/engine/interface/WorldAchievements.lua | 80 +++++++++++++++++++++ game/modules/tome/class/Actor.lua | 11 +++ game/modules/tome/class/Game.lua | 1 + game/modules/tome/class/Player.lua | 6 ++ game/modules/tome/class/World.lua | 10 ++- game/modules/tome/data/achievements/all.lua | 41 +++++++++++ game/modules/tome/load.lua | 4 ++ 10 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 game/engine/dialogs/ShowAchievements.lua create mode 100644 game/engine/interface/WorldAchievements.lua create mode 100644 game/modules/tome/data/achievements/all.lua diff --git a/game/engine/Dialog.lua b/game/engine/Dialog.lua index 49ef8d762d..b2b0b9af49 100644 --- a/game/engine/Dialog.lua +++ b/game/engine/Dialog.lua @@ -30,7 +30,8 @@ tiles = engine.Tiles.new(16, 16) function _M:simplePopup(title, text, fct, no_leave) local font = core.display.newFont("/data/font/Vera.ttf", 12) local w, h = font:size(text) - local d = new(title, w + 8, h + 25, nil, nil, nil, font) + local tw, th = font:size(title) + local d = new(title, math.max(w, tw) + 8, h + 25, nil, nil, nil, font) if no_leave then d:keyCommands{} else diff --git a/game/engine/dialogs/GameMenu.lua b/game/engine/dialogs/GameMenu.lua index 51146eae69..fb08e1d3aa 100644 --- a/game/engine/dialogs/GameMenu.lua +++ b/game/engine/dialogs/GameMenu.lua @@ -71,6 +71,11 @@ function _M:generateList(actions) local menu = require("engine.dialogs.DisplayResolution").new() game:registerDialog(menu) end }, + achievements = { "Show Achievements", function() + game:unregisterDialog(self) + local menu = require("engine.dialogs.ShowAchievements").new() + game:registerDialog(menu) + end }, save = { "Save Game", function() game:saveGame() end }, quit = { "Save and Exit", function() game:onQuit() end }, } diff --git a/game/engine/dialogs/ShowAchievements.lua b/game/engine/dialogs/ShowAchievements.lua new file mode 100644 index 0000000000..d7892d791e --- /dev/null +++ b/game/engine/dialogs/ShowAchievements.lua @@ -0,0 +1,77 @@ +-- TE4 - T-Engine 4 +-- Copyright (C) 2009, 2010 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +require "engine.class" +require "engine.Dialog" + +module(..., package.seeall, class.inherit(engine.Dialog)) + +function _M:init(title) + engine.Dialog.init(self, title or "Achievements", game.w * 0.8, game.h * 0.8, nil, nil, nil, core.display.newFont("/data/font/VeraMono.ttf", 12)) + + self:generateList() + + self.sel = 1 + self.scroll = 1 + self.max = math.floor((self.ih - 5) / self.font_h) - 1 + + self:keyCommands({},{ + MOVE_UP = function() self.sel = util.boundWrap(self.sel - 1, 1, #self.list) self.scroll = util.scroll(self.sel, self.scroll, self.max) end, + MOVE_DOWN = function() self.sel = util.boundWrap(self.sel + 1, 1, #self.list) self.scroll = util.scroll(self.sel, self.scroll, self.max) end, + EXIT = function() game:unregisterDialog(self) end, + }) + self:mouseZones{ + { x=2, y=5, w=350, h=self.font_h*self.max, fct=function(button, x, y, xrel, yrel, tx, ty) + self.sel = util.bound(self.scroll + math.floor(ty / self.font_h), 1, #self.list) + end }, + } +end + +function _M:generateList() + -- Makes up the list + local list = {} + local i = 0 + for id, data in pairs(world.achieved) do + local a = world:getAchievementFromId(id) + list[#list+1] = { name=a.name, desc=a.desc, when=data.when, who=data.who, order=a.order } + i = i + 1 + end + table.sort(list, function(a, b) return a.order < b.order end) + self.list = list +end + +function _M:drawDialog(s) + -- Description part + self:drawHBorder(s, self.iw / 2, 2, self.ih - 4) + + local h = 2 + if self.list[self.sel] then + local str = ("#GOLD#Achieved on:#LAST# %s\n#GOLD#Achieved by:#LAST# %s\n\n#GOLD#Description:#LAST# %s"):format(self.list[self.sel].when, self.list[self.sel].who, self.list[self.sel].desc) + lines = str:splitLines(self.iw / 2 - 10, self.font) + else + lines = {} + end + 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 + h) + h = h + self.font:lineSkip() + end + + self:drawSelectionList(s, 2, 5, self.font_h, self.list, self.sel, "name", self.scroll, self.max) +end diff --git a/game/engine/interface/WorldAchievements.lua b/game/engine/interface/WorldAchievements.lua new file mode 100644 index 0000000000..a43f052736 --- /dev/null +++ b/game/engine/interface/WorldAchievements.lua @@ -0,0 +1,80 @@ +-- TE4 - T-Engine 4 +-- Copyright (C) 2009, 2010 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +require "engine.class" +local Dialog = require "engine.Dialog" + +--- Handles archievements in a world +module(..., package.seeall, class.make) + +_M.achiev_defs = {} + +--- Loads achievements +function _M:loadDefinition(dir) + for i, file in ipairs(fs.list(dir)) do + if file:find("%.lua$") then + local f, err = loadfile(dir.."/"..file) + if not f and err then error(err) end + setfenv(f, setmetatable({ + newAchievement = function(t) self:newAchievement(t) end, + }, {__index=_G})) + f() + end + end +end + +--- Make a new achivement with a name and desc +function _M:newAchievement(t) + assert(t.name, "no achivement name") + assert(t.desc, "no achivement desc") + + t.id = t.id or t.name + t.id = t.id:upper():gsub("[ ]", "_") + t.order = #self.achiev_defs+1 + + self.achiev_defs[t.id] = t + self.achiev_defs[#self.achiev_defs+1] = t + print("[ACHIEVEMENT] defined", t.order, t.id) +end + +function _M:init() + self.achieved = {} +end + +function _M:getAchievementFromId(id) + return self.achiev_defs[id] +end + +--- Gain an achievement +-- @param id the achivement to gain +-- @param src who did it +function _M:gainAchievement(id, src) + if not self.achiev_defs[id] then error("Unknown achievement "..id) return end + if self.achieved[id] then return end + self.achieved[id] = {turn=game.turn, who=self:achievementWho(src), when=os.date("%Y-%m-%d %H:%M:%S")} + game.log("#LIGHT_GREEN#New Achievement: %s!", self.achiev_defs[id].name) + Dialog:simplePopup("New Achievement: #LIGHT_GREEN#"..self.achiev_defs[id].name, self.achiev_defs[id].desc) +end + +--- Format an achievement source +-- By default just uses the actor's name, you can overload it to do more +-- @param src the actor who did it +function _M:achievementWho(src) + return src.name +end diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 9586c3dfac..574fda17ed 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -320,6 +320,12 @@ function _M:onTakeHit(value, src) value = 0 end end + + -- Achievements + if src and src:resolveSource().player and value >= 600 then + world:gainAchievement("SIZE_MATTERS", src:resolveSource()) + end + return value end @@ -356,6 +362,11 @@ function _M:die(src) src:incStamina(src:getTalentLevel(src.T_UNENDING_FRENZY) * 2) end + -- Achievements + if src and src:resolveSource().player and src:resolveSource().life == 1 then + world:gainAchievement("THAT_WAS_CLOSE", src:resolveSource()) + end + return true end diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index d0b0157ec1..8cefd634bb 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -588,6 +588,7 @@ function _M:setupCommands() EXIT = function() local menu menu = require("engine.dialogs.GameMenu").new{ "resume", + "achievements", "keybinds", {"Graphic Mode", function() game:unregisterDialog(menu) game:registerDialog(require("mod.dialogs.GraphicMode").new()) end}, "resolution", diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index 9d66cbd9ba..06a39f0e27 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -169,6 +169,12 @@ function _M:levelup() 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 + + if self.level == 10 then world:gainAchievement("LEVEL_10", self) end + if self.level == 20 then world:gainAchievement("LEVEL_20", self) end + if self.level == 30 then world:gainAchievement("LEVEL_30", self) end + if self.level == 40 then world:gainAchievement("LEVEL_40", self) end + if self.level == 50 then world:gainAchievement("LEVEL_50", self) end end --- Tries to get a target from the user diff --git a/game/modules/tome/class/World.lua b/game/modules/tome/class/World.lua index b50e4c70e4..a2d4addabe 100644 --- a/game/modules/tome/class/World.lua +++ b/game/modules/tome/class/World.lua @@ -19,12 +19,14 @@ require "engine.class" require "engine.World" +require "engine.interface.WorldAchievements" local Savefile = require "engine.Savefile" -module(..., package.seeall, class.inherit(engine.World)) +module(..., package.seeall, class.inherit(engine.World, engine.interface.WorldAchievements)) function _M:init() engine.World.init(self) + engine.interface.WorldAchievements.init(self) end --- Requests the world to save @@ -34,3 +36,9 @@ function _M:saveWorld() save:close() game.log("Saved world.") end + +--- Format an achievement source +-- @param src the actor who did it +function _M:achievementWho(src) + return src.name.." the "..game.player.descriptor.subrace.." "..game.player.descriptor.subclass +end diff --git a/game/modules/tome/data/achievements/all.lua b/game/modules/tome/data/achievements/all.lua new file mode 100644 index 0000000000..a99ef2acca --- /dev/null +++ b/game/modules/tome/data/achievements/all.lua @@ -0,0 +1,41 @@ +-------------- Levels +newAchievement{ + name = "Level 10", + desc = [[Got a character to level 10.]], +} +newAchievement{ + name = "Level 20", + desc = [[Got a character to level 20.]], +} +newAchievement{ + name = "Level 30", + desc = [[Got a character to level 30.]], +} +newAchievement{ + name = "Level 40", + desc = [[Got a character to level 40.]], +} +newAchievement{ + name = "Level 50", + desc = [[Got a character to level 50.]], +} + +--------------- Main objectives +newAchievement{ + name = "Vampire crusher", + desc = [[Destroyed the Master in its lair of Tol Falas.]], +} +newAchievement{ + name = "A dangerous secret", + desc = [[Found the mysterious staff and told Minas Tirith about it.]], +} + +--------------- Misc +newAchievement{ + name = "That was close", + desc = [[Kill your target while having only 1 life left.]], +} +newAchievement{ + name = "Size matters", + desc = [[Do over 600 damage in one attack]], +} diff --git a/game/modules/tome/load.lua b/game/modules/tome/load.lua index a0b9bc197f..53bf1842f6 100644 --- a/game/modules/tome/load.lua +++ b/game/modules/tome/load.lua @@ -29,10 +29,14 @@ local ActorInventory = require "engine.interface.ActorInventory" local ActorLevel = require "engine.interface.ActorLevel" local Birther = require "engine.Birther" local Store = require "mod.class.Store" +local WorldAchievements = require "engine.interface.WorldAchievements" config.settings.tome = config.settings.tome or {} config.settings.tome.allow_build = config.settings.tome.allow_build or {} +-- Achievements +WorldAchievements:loadDefinition("/data/achievements/") + -- Usefull keybinds KeyBind:load("move,hotkeys,inventory,actions,debug") -- GitLab