From e154f5f4a2bcb13d9272572831eff4c8713b837d Mon Sep 17 00:00:00 2001 From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54> Date: Mon, 23 Nov 2009 18:21:31 +0000 Subject: [PATCH] class multiple inheritence soe new actor interfaces to handle levels, life, ... git-svn-id: http://svn.net-core.org/repos/t-engine4@21 51575b47-30f0-44d4-a5cc-537603b46e54 --- game/engine/Actor.lua | 3 +- game/engine/Game.lua | 2 + game/engine/class.lua | 18 +++++- game/engine/generator/map/Rooms.lua | 15 ++++- game/engine/interface/ActorLevel.lua | 60 +++++++++++++++++++ game/engine/interface/ActorLife.lua | 29 +++++++++ game/engine/utils.lua | 30 ++++++++++ game/modules/tome/class/Actor.lua | 37 +++--------- game/modules/tome/class/Game.lua | 1 + .../tome/data/zones/ancient_ruins/npcs.lua | 6 +- .../tome/data/zones/ancient_ruins/zone.lua | 2 +- 11 files changed, 165 insertions(+), 38 deletions(-) create mode 100644 game/engine/interface/ActorLevel.lua create mode 100644 game/engine/interface/ActorLife.lua diff --git a/game/engine/Actor.lua b/game/engine/Actor.lua index 12f4f436ad..1013524301 100644 --- a/game/engine/Actor.lua +++ b/game/engine/Actor.lua @@ -6,7 +6,8 @@ module(..., package.seeall, class.inherit(Entity)) function _M:init(t) t = t or {} - self.name = t.name + self.name = t.name or "unknown npc" + self.level = t.level or 1 self.energy = t.energy or { value=0, mod=1 } self.energy.value = self.energy.value or 0 self.energy.mod = self.energy.mod or 0 diff --git a/game/engine/Game.lua b/game/engine/Game.lua index 0641eeb37b..05cf45dfc0 100644 --- a/game/engine/Game.lua +++ b/game/engine/Game.lua @@ -10,6 +10,8 @@ module(..., package.seeall, class.make) function _M:init(keyhandler) self.key = keyhandler self.level = nil + self.log = function() end + self.logSeen = function() end self.w, self.h = core.display.size() end diff --git a/game/engine/class.lua b/game/engine/class.lua index b3d25cedcb..44bf1c4aa5 100644 --- a/game/engine/class.lua +++ b/game/engine/class.lua @@ -2,6 +2,14 @@ module("class", package.seeall) local base = _G +local function search(k, plist) + for i=1, #plist do + local v = plist[i][k] -- try `i'-th superclass + if v then return v end + end +end + + function make(c) setmetatable(c, {__index=_M}) c.new = function(...) @@ -14,9 +22,15 @@ function make(c) return c end -function inherit(base) +function inherit(base, ...) + local ifs = {...} return function(c) - setmetatable(c, {__index=base}) + if #ifs == 0 then + setmetatable(c, {__index=base}) + else + table.insert(ifs, 1, base) + setmetatable(c, {__index=function(t, k) return search(k, ifs) end}) + end c.new = function(...) local obj = {} obj.__CLASSNAME = c._NAME diff --git a/game/engine/generator/map/Rooms.lua b/game/engine/generator/map/Rooms.lua index ebc91f6940..8ea57dcf2a 100644 --- a/game/engine/generator/map/Rooms.lua +++ b/game/engine/generator/map/Rooms.lua @@ -12,6 +12,7 @@ function _M:init(map, grid_list, data) self.door = grid_list[data.door] self.up = grid_list[data.up] self.down = grid_list[data.down] + self.spots = {} end function _M:doRooms(room, no, tab) @@ -33,6 +34,10 @@ function _M:doRooms(room, no, tab) self:doRooms({ y=room.y, x=room.x + sx + 1, h=room.h, w=room.w - sx - 1}, no-1," "..tab) end self.map(room.x + sx, room.y + sy, Map.TERRAIN, self.door) + else + -- Final room, select an interresting "spot" + local spotx, spoty = rng.range(room.x, room.x + room.w - 1), rng.range(room.y, room.y + room.h - 1) + table.insert(self.spots, {x=spotx, y=spoty}) end end @@ -47,7 +52,11 @@ function _M:generate() self:doRooms({ x=1, y=1, h=self.map.h - 2, w=self.map.w - 2 }, 10, "#") - -- Always starts at 1, 1 - self.map(1, 1, Map.TERRAIN, self.up) - return 1, 1 + -- Select 2 spots, one for up and one for down, remove the up one, we dont want an actor generator to get smart + -- and place a monster where the player should be! + local up_spot = table.remove(self.spots, rng.range(1, #self.spots)) + local down_spot = self.spots[rng.range(1, #self.spots)] + self.map(up_spot.x, up_spot.y, Map.TERRAIN, self.up) + self.map(down_spot.x, down_spot.y, Map.TERRAIN, self.down) + return up_spot.x, up_spot.y, self.spots end diff --git a/game/engine/interface/ActorLevel.lua b/game/engine/interface/ActorLevel.lua new file mode 100644 index 0000000000..92ba9d5df9 --- /dev/null +++ b/game/engine/interface/ActorLevel.lua @@ -0,0 +1,60 @@ +require "engine.class" + +--- Interface to add leveling capabilities to actors +-- Defines the exp property, which is the current experience, level which is the current level and exp_worth which is a multiplicator +-- to the monster level default exp +module(..., package.seeall, class.make) + +_M.exp_chart = function(level) + local exp = 10 + local mult = 10 + for i = 2, level do + exp = exp + level * mult + mult = mult + 1 + end + return exp +end + +function _M:init(t) + self.level = t.level or 1 + self.exp = t.exp or 0 + self.exp_worth = t.exp_worth or 1 +end + +--- Defines the experience chart used +-- Static! +-- @param chart etiher a table of format "[level] = exp_needed" or a function that takes one parameter, a level, and returns the experience needed to reach it. +function _M:defineExperienceChart(chart) + assert(type(chart) == "table" or type(chart) == "function", "chart is neither table nor function") + self.exp_chart = chart +end + +function _M:getExpChart(level) + if type(self.exp_chart) == "table" then + return self.exp_chart[level] + else + return self.exp_chart(level) + end +end + +--- Gains some experience +-- If a levelup happens it calls self:levelup(), modules are encourraged to rewrite it to do whatever is needed. +function _M:gainExp(value) + print("gain exp",self.exp,"+",value) + self.exp = self.exp + value + while self:getExpChart(self.level + 1) and self.exp >= self:getExpChart(self.level + 1) do + self.level = self.level + 1 + self.exp = self.exp - self:getExpChart(self.level) + print("levelup", self.level, self.exp) + self:levelup() + end +end + +--- How much experience is this actor worth +-- @return the experience rewarded +function _M:worthExp() + return self.level * self.exp_worth +end + +function _M:levelup() +end diff --git a/game/engine/interface/ActorLife.lua b/game/engine/interface/ActorLife.lua new file mode 100644 index 0000000000..0fa7d2eb7a --- /dev/null +++ b/game/engine/interface/ActorLife.lua @@ -0,0 +1,29 @@ +require "engine.class" + +module(..., package.seeall, class.make) + +function _M:init(t) + self.life = t.life or 100 +end + +function _M:block_move(x, y, e) + -- Dont bump yourself! + if e and e ~= self then + e:attack(self) + end + return true +end + +function _M:takeHit(value, src) + self.life = self.life - value + if self.life <= 0 then + game.logSeen(self, "%s killed %s!", src.name:capitalize(), self.name) + game.level:removeEntity(self) + self:die(src) + end +end + +function _M:attack(target) + game.logSeen(target, "%s attacks %s.", self.name:capitalize(), target.name:capitalize()) + target:takeHit(10, self) +end diff --git a/game/engine/utils.lua b/game/engine/utils.lua index 2d13bab9e3..61bfae0d7b 100644 --- a/game/engine/utils.lua +++ b/game/engine/utils.lua @@ -1,3 +1,33 @@ +function string.capitalize(str) + if #str > 1 then + return string.upper(str:sub(1, 1))..str:sub(2) + elseif #str == 1 then + return str:upper() + else + return str + end +end + +function string.bookCapitalize(str) + local words = str:split(' ') + + for i = 1, #words do + local word = words[i] + + -- Don't capitalize certain words unless they are at the begining + -- of the string. + if i == 1 or (word ~= "of" and word ~= "the" and word ~= "and" and word ~= "a" and word ~= "an") + then + words[i] = word:gsub("^(.)", + function(x) + return x:upper() + end) + end + end + + return table.concat(words, " ") +end + function string.splitLine(str, max_width, font) local space_w = font:size(" ") local lines = {} diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 64a9c64d57..4c98adecea 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -1,20 +1,14 @@ require "engine.class" require "engine.Actor" +require "engine.interface.ActorLife" +require "engine.interface.ActorLevel" -module(..., package.seeall, class.inherit(engine.Actor)) +module(..., package.seeall, class.inherit(engine.Actor, engine.interface.ActorLife, engine.interface.ActorLevel)) function _M:init(t) - self.level = 1 - self.life = 100 - self.mana = 100 - self.skills = {} - self.attacks = {} engine.Actor.init(self, t) -end - --- When saving, ignore some fields -function _M:save() - return engine.Actor.save(self, {game=true}) + engine.interface.ActorLife.init(self, t) + engine.interface.ActorLevel.init(self, t) end function _M:move(x, y, force) @@ -26,27 +20,12 @@ function _M:move(x, y, force) return moved end -function _M:block_move(x, y, e) - -- Dont bump yourself! - if e and e ~= self then - game.log("%s attacks %s.", tostring(e.name), tostring(self.name)) - self:takeHit(10, e) - end - return true -end - function _M:tooltip() return self.name.."\n#ff0000#HP: "..self.life end -function _M:takeHit(value, src) - self.life = self.life - value - if self.life <= 0 then - game.log("%s killed %s!", src.name, self.name) - game.level:removeEntity(self) - self:die() +function _M:die(src) + if src then + src:gainExp(self:worthExp()) end end - -function _M:die() -end diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 259eacc8e7..7ce7882f38 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -29,6 +29,7 @@ function _M:run() self.log = engine.LogDisplay.new(self.w * 0.5, self.h * 0.20, nil, nil, nil, {255,255,255}, {30,30,30}) self.log("Welcome to #00FF00#Tales of Middle Earth!") + self.logSeen = function(e, ...) if e and self.level.map.seens(e.x, e.y) then self.log(...) end end self.zone:getLevel(self, 1) diff --git a/game/modules/tome/data/zones/ancient_ruins/npcs.lua b/game/modules/tome/data/zones/ancient_ruins/npcs.lua index 53bfb522fd..7fd8183206 100644 --- a/game/modules/tome/data/zones/ancient_ruins/npcs.lua +++ b/game/modules/tome/data/zones/ancient_ruins/npcs.lua @@ -3,14 +3,16 @@ return { { name = "dragon of death", display = "D", color_r=255, - life = 1000, + level = 1, exp_worth = 20, + life = 20, mana = 1000, energy = { mod=0.8 }, }, { name = "baby dragon", display = "d", color_r=128, - life = 1000, + level = 1, exp_worth = 10, + life = 30, mana = 1000, energy = { mod=0.3 }, }, diff --git a/game/modules/tome/data/zones/ancient_ruins/zone.lua b/game/modules/tome/data/zones/ancient_ruins/zone.lua index 7b0e31eefd..27bc2ee98d 100644 --- a/game/modules/tome/data/zones/ancient_ruins/zone.lua +++ b/game/modules/tome/data/zones/ancient_ruins/zone.lua @@ -6,7 +6,7 @@ return { all_lited = true, generator = { map = { - class= "engine.generator.map.Rooms", + class= "engine.generator.map.Empty", floor = "FLOOR", wall = "WALL", up = "UP", -- GitLab