diff --git a/game/engine/interface/ActorAbilities.lua b/game/engine/interface/ActorAbilities.lua new file mode 100644 index 0000000000000000000000000000000000000000..d989031a70ea46167b463863d44f592711d63c03 --- /dev/null +++ b/game/engine/interface/ActorAbilities.lua @@ -0,0 +1,44 @@ +require "engine.class" + +--- Handles actors stats +module(..., package.seeall, class.make) + +_M.abilities_def = {} +_M.abilities_types_def = {} + +--- Defines actor abilities +-- Static! +function _M:loadDefinition(file) + local f = loadfile(file) + setfenv(f, { + newAbility = function(t) self:newAbility(t) end, + newAbilityType = function(t) self:newAbilityType(t) end, + }) + f() +end + +--- Defines one ability type(group) +-- Static! +function _M:newAbilityType(t) + assert(t.name, "no ability type name") + assert(t.type, "no ability type type") +end + +--- Defines one ability +-- Static! +function _M:newAbility(t) + assert(t.name, "no ability name") + assert(t.type, "no or unknown ability type") + t.short_name = t.short_name or t.name + t.short_name = t.short_name:upper():gsub("[ ]", "_") + t.mana = t.mana or 0 + t.stamina = t.stamina or 0 + t.mode = t.mode or "activated" + assert(t.mode == "activated" or t.mode == "sustained", "wrong ability mode, requires either 'activated' or 'sustained'") + assert(t.info, "no ability info") +end + +--- Initialises stats with default values if needed +function _M:init(t) + self.abilities = t.abilities or {} +end diff --git a/game/engine/interface/ActorStats.lua b/game/engine/interface/ActorStats.lua new file mode 100644 index 0000000000000000000000000000000000000000..e9243bafa604a5c3f716a4671adcb7a6f1fba2c2 --- /dev/null +++ b/game/engine/interface/ActorStats.lua @@ -0,0 +1,51 @@ +require "engine.class" + +--- Handles actors stats +module(..., package.seeall, class.make) + +_M.stats_def = {} + +--- Defines stats +-- Static! +function _M:defineStat(name, short_name, default_value, min, max) + assert(name, "no stat name") + assert(short_name, "no stat short_name") + table.insert(self.stats_def, { + name = name, + short_name = short_name, + def = default_value or 10, + min = min or 1, + max = max or 100, + }) + self.stats_def[short_name] = self.stats_def[#self.stats_def] + self["STAT_"..short_name:upper()] = #self.stats_def + self["get"..short_name:lower():capitalize()] = function(self, scale) + local val = self.stats[_M["STAT_"..short_name:upper()]] + if scale then + val = math.floor(val * scale / max) + end + return val + end +end + +--- Initialises stats with default values if needed +function _M:init(t) + self.stats = t.stats or {} + for i, s in ipairs(_M.stats_def) do + if self.stats[i] then + elseif self.stats[s.short_name] then + self.stats[i] = self.stats[s.short_name] + self.stats[s.short_name] = nil + else + self.stats[i] = s.def + end + end +end + +--- +-- Module authors should rewrite it to handle combat, dialog, ... +-- @param target the actor attacking us +function _M:incStat(stat, val) + self.stats[stat] = max(min(val, _M.stats_def[stat].max), _M.stats_def[stat].min) + return self.stats[stat] +end diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 4fb99141a0afaa4a51e34e08a799ed1a340dc4c8..254e56e8961af877b7469adf012357a81f7ba2e3 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -2,6 +2,8 @@ require "engine.class" require "engine.Actor" require "engine.interface.ActorLife" require "engine.interface.ActorLevel" +require "engine.interface.ActorStats" +require "engine.interface.ActorAbilities" require "engine.interface.BloodyDeath" require "mod.class.interface.Combat" @@ -10,6 +12,8 @@ module(..., package.seeall, class.inherit( engine.Actor, engine.interface.ActorLife, engine.interface.ActorLevel, + engine.interface.ActorStats, + engine.interface.ActorAbilities, engine.interface.BloodyDeath, mod.class.interface.Combat )) @@ -18,6 +22,8 @@ function _M:init(t) engine.Actor.init(self, t) engine.interface.ActorLife.init(self, t) engine.interface.ActorLevel.init(self, t) + engine.interface.ActorStats.init(self, t) + engine.interface.ActorAbilities.init(self, t) end function _M:move(x, y, force) diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 2963575109d6f00da2ff230aa80b858962892d3b..13ec489dbbce4a13f902190bc966ab4f39a66793 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -13,6 +13,8 @@ local Target = require "engine.Target" local Level = require "engine.Level" local Grid = require "engine.Grid" local Actor = require "mod.class.Actor" +local ActorStats = require "engine.interface.ActorStats" +local ActorAbilities = require "engine.interface.ActorAbilities" local Player = require "mod.class.Player" local NPC = require "mod.class.NPC" @@ -26,6 +28,15 @@ function _M:init() end function _M:run() + -- Actor stats + ActorStats:defineStat("Strength", "str", 10, 1, 100) + ActorStats:defineStat("Dexterity", "dex", 10, 1, 100) + ActorStats:defineStat("Magic", "mag", 10, 1, 100) + ActorStats:defineStat("Willpower", "wil", 10, 1, 100) + ActorStats:defineStat("Cunning", "cun", 10, 1, 100) + ActorStats:defineStat("Constitution", "con", 10, 1, 100) + ActorAbilities:loadDefinition("/data/abilities.lua") + self.log = engine.LogDisplay.new(0, self.h * 0.80, self.w * 0.5, self.h * 0.20, nil, nil, nil, {255,255,255}, {30,30,30}) self.calendar = Calendar.new("/data/calendar_rivendell.lua", "Today is the %s %s of the %s year of the Fourth Age of Middle-earth.\nThe time is %02d:%02d.", 122) self.tooltip = engine.Tooltip.new(nil, nil, {255,255,255}, {30,30,30}) @@ -59,7 +70,7 @@ end function _M:loaded() Zone:setup{npc_class="mod.class.NPC", grid_class="mod.class.Grid", object_class="engine.Entity"} -- Map:setViewPort(0, 0, self.w, math.floor(self.h * 0.80), 20, 20, "/data/font/10X20.FON", 20) - Map:setViewPort(0, 0, self.w, math.floor(self.h * 0.80), 16, 16) + Map:setViewPort(self.w * 0.2, 0, self.w * .8, math.floor(self.h * 0.80), 16, 16) engine.GameTurnBased.loaded(self) self.key = engine.KeyCommand.new() end @@ -109,7 +120,7 @@ function _M:display() -- Display a tooltip if available local mx, my = core.mouse.get() - local tmx, tmy = math.floor(mx / self.level.map.tile_w) + self.level.map.mx, math.floor(my / self.level.map.tile_h) + self.level.map.my + local tmx, tmy = math.floor((mx - Map.display_x) / self.level.map.tile_w) + self.level.map.mx, math.floor((my - Map.display_y) / self.level.map.tile_h) + self.level.map.my local tt = self.level.map:checkAllEntities(tmx, tmy, "tooltip") if tt and self.level.map.seens(tmx, tmy) then self.tooltip:set(tt) @@ -291,7 +302,7 @@ function _M:setupMouse() self.mouse:registerZone(Map.display_x, Map.display_y, Map.viewport.width, Map.viewport.height, function(button, mx, my, xrel, yrel) -- Compute map coordonates if button == "right" then - local tmx, tmy = math.floor(mx / self.level.map.tile_w) + self.level.map.mx, math.floor(my / self.level.map.tile_h) + self.level.map.my + local tmx, tmy = math.floor((mx - Map.display_x) / self.level.map.tile_w) + self.level.map.mx, math.floor((my - Map.display_x) / self.level.map.tile_h) + self.level.map.my local actor = self.level.map(tmx, tmy, Map.ACTOR) diff --git a/game/modules/tome/data/abilities.lua b/game/modules/tome/data/abilities.lua new file mode 100644 index 0000000000000000000000000000000000000000..520f02118e8505692fcd1acd3efb8606bb1a7730 --- /dev/null +++ b/game/modules/tome/data/abilities.lua @@ -0,0 +1,20 @@ +-- Mana spells +newAbilityType{ type="spell/mana", name = "mana" } + +newAbility{ + name = "Manathrust", + type = "spell/mana", + mana = 15, + tactical = { + ATTACK = 10, + }, + action = function(user) + user:project(game.target.x, game.target.y, Damages.MANA, 10 + user:getMag()) + return true + end, + require = { stat = { mag=12 }, }, + info = function(user) + return ([[Conjures up mana into a powerful bolt doing %d", + The damage is irresistible and will increase with magic stat]]):format(10 + user:getMag()) + end +}