From e1f0991e2a7efa0eebbf6ffb1ab0ca26b4c2b69e Mon Sep 17 00:00:00 2001 From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54> Date: Fri, 4 Dec 2009 01:11:44 +0000 Subject: [PATCH] Birther Better AI git-svn-id: http://svn.net-core.org/repos/t-engine4@90 51575b47-30f0-44d4-a5cc-537603b46e54 --- game/engine/Birther.lua | 163 +++++++++++++++ game/engine/ai/simple.lua | 9 +- game/engine/interface/ActorLevel.lua | 5 +- game/engine/interface/ActorStats.lua | 4 + game/engine/interface/ActorTalents.lua | 16 +- game/modules/tome/class/Actor.lua | 19 +- game/modules/tome/class/Game.lua | 49 ++--- game/modules/tome/class/Player.lua | 15 +- game/modules/tome/class/PlayerDisplay.lua | 2 +- game/modules/tome/data/birth/classes.lua | 68 +++++++ game/modules/tome/data/birth/descriptors.lua | 13 ++ game/modules/tome/data/birth/races.lua | 109 ++++++++++ game/modules/tome/data/birth/sexes.lua | 22 +++ game/modules/tome/data/birth/subraces.lua | 153 ++++++++++++++ game/modules/tome/data/talents.lua | 186 +----------------- game/modules/tome/data/talents/misc/misc.lua | 53 +++++ .../tome/data/talents/physical/physical.lua | 5 + .../tome/data/talents/spells/spells.lua | 161 +++++++++++++++ .../tome/data/zones/ancient_ruins/npcs.lua | 4 +- .../tome/data/zones/ancient_ruins/zone.lua | 2 +- .../tome/dialogs/LevelupTalentsDialog.lua | 30 +-- game/modules/tome/load.lua | 4 + 22 files changed, 832 insertions(+), 260 deletions(-) create mode 100644 game/engine/Birther.lua create mode 100644 game/modules/tome/data/birth/classes.lua create mode 100644 game/modules/tome/data/birth/descriptors.lua create mode 100644 game/modules/tome/data/birth/races.lua create mode 100644 game/modules/tome/data/birth/sexes.lua create mode 100644 game/modules/tome/data/birth/subraces.lua create mode 100644 game/modules/tome/data/talents/misc/misc.lua create mode 100644 game/modules/tome/data/talents/physical/physical.lua create mode 100644 game/modules/tome/data/talents/spells/spells.lua diff --git a/game/engine/Birther.lua b/game/engine/Birther.lua new file mode 100644 index 0000000000..5104130648 --- /dev/null +++ b/game/engine/Birther.lua @@ -0,0 +1,163 @@ +require "engine.class" +require "engine.Dialog" + +module(..., package.seeall, class.inherit(engine.Dialog)) + +_M.birth_descriptor_def = {} + +--- Defines birth descriptors +-- Static! +function _M:loadDefinition(file) + local f, err = loadfile(file) + if not f and err then error(err) os.exit() end + setfenv(f, setmetatable({ + ActorTalents = require("engine.interface.ActorTalents"), + newBirthDescriptor = function(t) self:newBirthDescriptor(t) end, + load = function(f) self:loadDefinition(f) end + }, {__index=_G})) + f() +end + +--- Defines one birth descriptor +-- Static! +function _M:newBirthDescriptor(t) + assert(t.name, "no birth name") + assert(t.type, "no birth type") + t.short_name = t.short_name or t.name + t.short_name = t.short_name:upper():gsub("[ ]", "_") + assert(t.desc, "no birth description") + t.descriptor_choices = t.descriptor_choices or {} + + table.insert(self.birth_descriptor_def, t) + t.id = #self.birth_descriptor_def + self.birth_descriptor_def[t.type] = self.birth_descriptor_def[t.type] or {} + self.birth_descriptor_def[t.type][t.name] = t + table.insert(self.birth_descriptor_def[t.type], t) +end + + +--- Instanciates a birther for the given actor +function _M:init(actor, order, at_end) + self.actor = actor + self.order = order + self.at_end = at_end + engine.Dialog.init(self, "Character Creation: "..actor.name, 600, 400) + + self.descriptors = {} + + self.cur_order = 1 + self:next() + + self:keyCommands{ + _UP = function() self.sel = util.boundWrap(self.sel - 1, 1, #self.list) end, + _DOWN = function() self.sel = util.boundWrap(self.sel + 1, 1, #self.list) end, + _RETURN = function() self:next() end, + _ESCAPE = function() game:unregisterDialog(self) end, + } + self:mouseZones{ + { x=2, y=25, w=350, h=self.h, fct=function(button, x, y, xrel, yrel, tx, ty) + if ty <= self.font_h*#self.list then + self.sel = 1 + math.floor(ty / self.font_h) + if button == "left" then self:next() + elseif button == "right" then self:learn(false) + end + end + end }, + } +end + +function _M:selectType(type) + self.list = {} + -- Make up the list + for i, d in ipairs(self.birth_descriptor_def[type]) do + local allowed = true + for j, od in ipairs(self.descriptors) do + if od.descriptor_choices[type] then + local what = od.descriptor_choices[type][d.name] or od.descriptor_choices[type].__ALL__ + if what and what == "allow" then + allowed = true + elseif what and what == "never" then + allowed = false + end + end + end + + -- Check it is allowed + if allowed then + table.insert(self.list, d) + end + end + self.sel = 1 + self.current_type = type +end + +function _M:next() + if self.list then + table.insert(self.descriptors, self.list[self.sel]) + + self.cur_order = self.cur_order + 1 + if not self.order[self.cur_order] then + game:unregisterDialog(self) + self:apply() + self.at_end() + return + end + end + self:selectType(self.order[self.cur_order]) + if #self.list == 1 then + self:next() + end +end + +--- Apply all birth options to the actor +function _M:apply() + self.actor.descriptor = {} + for i, d in ipairs(self.descriptors) do + print("[BIRTH] Applying descriptor "..d.name) + self.actor.descriptor[d.type] = d.name + + -- Change stats + if d.stats then + for stat, inc in pairs(d.stats) do + self.actor:incStat(stat, inc) + end + end + if d.talents_types then + for t, v in pairs(d.talents_types) do + self.actor:learnTalentType(t, v) + print(t) + end + end + if d.talents then + for i, tid in ipairs(d.talents) do + self.actor:learnTalent(tid, true) + print(tid) + end + end + if d.experience then self.actor.exp_mod = self.actor.exp_mod * d.experience end + end +end + +function _M:drawDialog(s) + if not self.list or not self.list[self.sel] then return end + + -- Description part + self:drawHBorder(s, self.iw / 2, 2, self.ih - 4) + local birthhelp = ([[Keyboard: #00FF00#up key/down key#FFFFFF# to select a stat; #00FF00#right key#FFFFFF# to increase stat; #00FF00#left key#FFFFFF# to decrease a stat. +Mouse: #00FF00#Left click#FFFFFF# to increase a stat; #00FF00#right click#FFFFFF# to decrease a stat. +]]):splitLines(self.iw / 2 - 10, self.font) + for i = 1, #birthhelp do + s:drawColorString(self.font, birthhelp[i], self.iw / 2 + 5, 2 + (i-1) * self.font:lineSkip()) + end + + local lines = table.concat(self.list[self.sel].desc,"\n"):splitLines(self.iw / 2 - 10, self.font) + for i = 1, #lines do + s:drawColorString(self.font, lines[i], self.iw / 2 + 5, 2 + (i + #birthhelp + 1) * self.font:lineSkip()) + end + + -- Stats + s:drawColorString(self.font, "Selecting: "..self.current_type:capitalize(), 2, 2) + self:drawWBorder(s, 2, 20, 200) + + self:drawSelectionList(s, 2, 25, self.font_h, self.list, self.sel, "name") +end diff --git a/game/engine/ai/simple.lua b/game/engine/ai/simple.lua index 7209459165..2024eaa61c 100644 --- a/game/engine/ai/simple.lua +++ b/game/engine/ai/simple.lua @@ -3,14 +3,9 @@ newAI("move_simple", function(self) if self.ai_target.actor then - local act = self.ai_target.actor - return self:moveDirection(act.x, act.y) + return self:moveDirection(self.ai_target.actor.x, self.ai_target.actor.y) elseif self.ai_target.x and self.ai_target.y then - local l = line.new(self.x, self.y, self.ai_target.x, self.ai_target.y) - local lx, ly = l() - if lx and ly then - self:move(lx, ly) - end + self:move(self.ai_target.x, self.ai_target.y) end end) diff --git a/game/engine/interface/ActorLevel.lua b/game/engine/interface/ActorLevel.lua index 9a7af3522d..f62e051e30 100644 --- a/game/engine/interface/ActorLevel.lua +++ b/game/engine/interface/ActorLevel.lua @@ -23,6 +23,7 @@ function _M:init(t) self.level = t.level or 1 end self.exp = t.exp or 0 + self.exp_mod = t.exp_mod or 1 self.exp_worth = t.exp_worth or 1 end @@ -39,9 +40,9 @@ end -- @return the exp needed, or nil if this level is not achievable function _M:getExpChart(level) if type(self.exp_chart) == "table" then - return self.exp_chart[level] + return self.exp_chart[level] * self.exp_mod else - return self.exp_chart(level) + return self.exp_chart(level) * self.exp_mod end end diff --git a/game/engine/interface/ActorStats.lua b/game/engine/interface/ActorStats.lua index 022642030b..6b0c7aa68e 100644 --- a/game/engine/interface/ActorStats.lua +++ b/game/engine/interface/ActorStats.lua @@ -44,6 +44,10 @@ end -- @param stat the stat id to change -- @param val the increment to add/substract function _M:incStat(stat, val) + if type(stat) == "string" then + stat = _M.stats_def[stat].id + end + local old = self.stats[stat] self.stats[stat] = math.max(math.min(self.stats[stat] + val, _M.stats_def[stat].max), _M.stats_def[stat].min) if self.stats[stat] - old ~= 0 then diff --git a/game/engine/interface/ActorTalents.lua b/game/engine/interface/ActorTalents.lua index ffb7d357eb..2c5071e22e 100644 --- a/game/engine/interface/ActorTalents.lua +++ b/game/engine/interface/ActorTalents.lua @@ -14,6 +14,7 @@ function _M:loadDefinition(file) DamageType = require("engine.DamageType"), newTalent = function(t) self:newTalent(t) end, newTalentType = function(t) self:newTalentType(t) end, + load = function(f) self:loadDefinition(f) end }, {__index=_G})) f() end @@ -128,11 +129,13 @@ end --- Actor learns a talent -- @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:learnTalent(t_id) +function _M:learnTalent(t_id, force) local t = _M.talents_def[t_id] - local ok, err = self:canLearnTalent(t) - if not ok and err then return nil, err end + if not force then + local ok, err = self:canLearnTalent(t) + if not ok and err then return nil, err end + end self.talents[t_id] = true self.changed = true @@ -225,8 +228,9 @@ 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 +function _M:learnTalentType(tt, v) + if v == nil then v = true end + self.talents_types[tt] = v self.changed = true return true end @@ -235,7 +239,7 @@ end -- @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 + self.talents_types[tt] = false self.changed = true return true end diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index d89721094a..8cbd3dde19 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -32,9 +32,9 @@ function _M:init(t) engine.interface.ActorTalents.init(self, t) engine.interface.ActorResource.init(self, t) - self.unused_stats = 0 - self.unused_talents = 0 - self.unused_talents_types = 0 + self.unused_stats = self.unused_stats or 0 + self.unused_talents = self.unused_talents or 0 + self.unused_talents_types = self.unused_talents_types or 0 end function _M:act() @@ -76,9 +76,16 @@ function _M:levelup() end -- Gain life and resources - self.max_life = self.max_life + 7 - self:incMaxMana(7) - self:incMaxStamina(7) + self.max_life = self.max_life + 10 + + (self:knowTalent(self.T_IMPROVED_HEALTH_I) and 1 or 0) + + (self:knowTalent(self.T_IMPROVED_HEALTH_II) and 1 or 0) + + (self:knowTalent(self.T_IMPROVED_HEALTH_III) and 1 or 0) + - (self:knowTalent(self.T_DECREASED_HEALTH_I) and 1 or 0) + - (self:knowTalent(self.T_DECREASED_HEALTH_II) and 1 or 0) + - (self:knowTalent(self.T_DECREASED_HEALTH_III) and 1 or 0) + + self:incMaxMana(10) + self:incMaxStamina(10) -- Healp up on new level self.life = self.max_life self.mana = self.max_mana diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 5c88989061..1a280726e2 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -7,6 +7,7 @@ local Zone = require "engine.Zone" local Map = require "engine.Map" local Target = require "engine.Target" local Level = require "engine.Level" +local Birther = require "engine.Birther" local Grid = require "engine.Grid" local Actor = require "mod.class.Actor" @@ -72,10 +73,18 @@ end function _M:newGame() self.zone = Zone.new("ancient_ruins") self.player = Player.new{ - name=self.player_name, max_life=10000, display='@', color_r=230, color_g=230, color_b=230, + name=self.player_name, max_life=25, max_mana=25, max_stamina=25, display='@', color_r=230, color_g=230, color_b=230, + unused_stats = 6, unused_talents = 3, move_others=true, } - self:changeLevel(1) + + local birth = Birther.new(self.player, {"base", "race", "subrace", "sex", "class", "subclass" }, function() + self:changeLevel(1) + + local ds = LevelupStatsDialog.new(self.player) + self:registerDialog(ds) + end) + self:registerDialog(birth) end function _M:loaded() @@ -109,12 +118,14 @@ function _M:getPlayer() end function _M:tick() - if self.target.target.entity and not self.level:hasEntity(self.target.target.entity) then self.target.target.entity = false end + if self.level then + if self.target.target.entity and not self.level:hasEntity(self.target.target.entity) then self.target.target.entity = false end - engine.GameTurnBased.tick(self) - -- Fun stuff: this can make the game realtime, although callit it in display() will make it work better - -- (since display is on a set FPS while tick() ticks as much as possible - -- engine.GameEnergyBased.tick(self) + engine.GameTurnBased.tick(self) + -- Fun stuff: this can make the game realtime, although callit it in display() will make it work better + -- (since display is on a set FPS while tick() ticks as much as possible + -- engine.GameEnergyBased.tick(self) + end end --- Called every game turns @@ -165,27 +176,6 @@ function _M:display() self.target.target.x, self.target.target.y = tmx, tmy end self.old_tmx, self.old_tmy = tmx, tmy - - local act = self.level.map(tmx, tmy, engine.Map.ACTOR) - if act then - - local s = core.display.newSurface(16,16) - s:alpha(125) - s:erase(0,255,255) - - core.fov.calc_circle(act.x, act.y, act.sight, function(self, lx, ly) - if self.level.map:checkEntity(lx, ly, engine.Map.TERRAIN, "block_sight") then return true end - - s:toScreen(self.level.map.display_x + (lx - game.level.map.mx) * self.level.map.tile_w, self.level.map.display_y + (ly - game.level.map.my) * self.level.map.tile_h) - - local dst = self.level.map(lx, ly, engine.Map.ACTOR) - if dst then --- table.insert(self.e_distances[e.uid], {uid=dst.uid, dist=core.fov.distance(e.x, e.y, dst.x, dst.y)}) --- print("found LOS", act.uid, dst.uid) - end - end, function()end, self) - - end end engine.GameTurnBased.display(self) @@ -288,6 +278,9 @@ function _M:setupCommands() _z = function() self.player:useTalent(ActorTalents.T_BLINK) end, + _m = function() + self.player:listTalents() + end, [{"_g","shift"}] = function() local none = true diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index fb03c72880..2730982fae 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -9,17 +9,10 @@ function _M:init(t) self.player = true self.faction = "players" self.combat = { dam=10, atk=40, apr=2, def=6, armor=4 } - self.talents_types = { - ["base/race"]=true, - ["base/class"]=true, - ["spell/arcane"]=true, - ["spell/fire"]=true, - ["physical/1hweapon"]=true - } - self.talents = {[ActorTalents.T_MANA_POOL]=true, [ActorTalents.T_STAMINA_POOL]=true} - self.mana_regen = 1 - self.stamina_regen = 1 - self.regen_life = 1 + self.mana_regen = self.mana_regen or 1 + self.stamina_regen = self.stamina_regen or 1 + self.regen_life = self.regen_life or 0.5 + self.descriptor = {} end function _M:move(x, y, force) diff --git a/game/modules/tome/class/PlayerDisplay.lua b/game/modules/tome/class/PlayerDisplay.lua index 559a1b8611..7f9b134837 100644 --- a/game/modules/tome/class/PlayerDisplay.lua +++ b/game/modules/tome/class/PlayerDisplay.lua @@ -20,7 +20,7 @@ function _M:display() local h = 0 self.surface:drawString(self.font, game.player.name, 0, h, 0, 200, 255) h = h + self.font_h - self.surface:drawString(self.font, "Human", 0, h, 0, 200, 255) h = h + self.font_h + self.surface:drawString(self.font, game.player.descriptor.race or "", 0, h, 0, 200, 255) h = h + self.font_h h = h + self.font_h self.surface:drawColorString(self.font, "Level: #00ff00#"..game.player.level, 0, h, 255, 255, 255) h = h + self.font_h self.surface:drawColorString(self.font, ("Exp: #00ff00#%2d%%"):format(100 * cur_exp / max_exp), 0, h, 255, 255, 255) h = h + self.font_h diff --git a/game/modules/tome/data/birth/classes.lua b/game/modules/tome/data/birth/classes.lua new file mode 100644 index 0000000000..8eebf82e97 --- /dev/null +++ b/game/modules/tome/data/birth/classes.lua @@ -0,0 +1,68 @@ +newBirthDescriptor{ + type = "class", + name = "Warrior", + desc = { + "Simple fighters, they hack away with their trusty weapon.", + }, + descriptor_choices = + { + subclass = + { + __ALL__ = "never", + Warrior = "allow", + }, + }, + talents = { ActorTalents.T_STAMINA_POOL, }, +} + +newBirthDescriptor{ + type = "subclass", + name = "Warrior", + desc = { + "Simple fighters, they hack away with their trusty weapon.", + }, + stats = { str=3, con=2, dex=1, }, + talents_types = { + ["physical/1hweapon"]=true, + ["physical/2hweapon"]=true, + ["physical/shield"]=true, + ["physical/1hweapon"]=true, + }, +} + +newBirthDescriptor{ + type = "class", + name = "Mage", + desc = { + "The basic spellcaster with lots of different skills", + }, + descriptor_choices = + { + subclass = + { + __ALL__ = "never", + Mage = "allow", + }, + }, + talents = { ActorTalents.T_MANA_POOL, }, +} + +newBirthDescriptor{ + type = "subclass", + name = "Mage", + desc = { + "Simple fighters, they hack away with their trusty weapon.", + }, + stats = { mag=3, wil=2, cun=1, }, + talents_types = { + ["spell/arcane"]=true, + ["spell/fire"]=true, + ["spell/earth"]=true, + ["spell/cold"]=true, + ["spell/air"]=true, + ["spell/conveyance"]=false, + }, + talents = { + ActorTalents.T_MANATHRUST, + }, +} diff --git a/game/modules/tome/data/birth/descriptors.lua b/game/modules/tome/data/birth/descriptors.lua new file mode 100644 index 0000000000..af7fc22cb8 --- /dev/null +++ b/game/modules/tome/data/birth/descriptors.lua @@ -0,0 +1,13 @@ +newBirthDescriptor{ + type = "base", + name = "base", + desc = { + }, + talents = {}, + experience = 1.0, +} + +load("/data/birth/races.lua") +load("/data/birth/subraces.lua") +load("/data/birth/sexes.lua") +load("/data/birth/classes.lua") diff --git a/game/modules/tome/data/birth/races.lua b/game/modules/tome/data/birth/races.lua new file mode 100644 index 0000000000..3fb671df04 --- /dev/null +++ b/game/modules/tome/data/birth/races.lua @@ -0,0 +1,109 @@ +newBirthDescriptor{ + type = "race", + name = "Human", + desc = { + "Humans are one of the youngest of the races of Arda.", + }, + descriptor_choices = + { + subrace = + { + Human = "allow", + Dunadan = "allow", + Rohirrim = "allow", + Beorning = "allow", + __ALL__ = "never", + }, + }, + stats = { cun=1 }, + talents = {}, + experience = 1.0, +} + +newBirthDescriptor{ + type = "race", + name = "Elf", + desc = { + "Elves are the first children of Eru.", + "The first Elves awoke by CuiviƩnen, the Water of Awakening in the far east of Middle-earth, long Ages before the Rising of the Sun or Moon. Unlike Men, the Elves were not subject to illness or death.", + }, + descriptor_choices = + { + subrace = + { + Noldor = "allow", + Avari = "allow", + __ALL__ = "never", + }, + }, + stats = { wil=1, mag=1, }, + talents = { + ActorTalents.T_IMPROVED_MANA_I, + }, + experience = 1.05, +} + +newBirthDescriptor{ + type = "race", + name = "Dwarf", + desc = { + "The children of Aule, a strong but small race.", + "Miners and fighters of legend.", + "Female dwarves remain a mystery and as such may not be played." + }, + descriptor_choices = + { + subrace = + { + __ALL__ = "never", + Dwarf = "allow", + }, + sex = + { + __ALL__ = "never", + Male = "allow", + }, + }, + stats = { str=1, con=1 }, + talents = { + ActorTalents.T_IMPROVED_HEALTH_I, + }, + experience = 1.05, +} + +newBirthDescriptor{ + type = "race", + name = "Hobbit", + desc = { + "Hobbits, or halflings, are very good at ranged combat ", + "(especially with slings), throwing, and have good saving ", + "throws. They also are very good at searching, disarming, ", + "perception and stealth; so they make excellent rogues, but ", + "prefer to be called burglars. They are much weaker than ", + "humans, thus not as good at melee fighting, and also not ", + "capable of carrying as many objects. Halflings have fair ", + "infra-vision, so they can detect warm creatures at a ", + "distance. Hobbits have their dexterity sustained and in time ", + "they learn to cook a delicious meal from available ", + "ingredients. Their sturdy constitutions also allow them to ", + "resist the insidious poison of the ring-wraiths. Their feet ", + "are cover from the ankle down in brown hairy fur, preventing ", + "them from wearing boots and shoes. ", + }, + descriptor_choices = + { + subrace = + { + __ALL__ = "never", + Harfoot = "allow", + Stoor = "allow", + Fallohide = "allow", + }, + }, + stats = { str=-2, cun=2, dex=3, con=2, }, + experience = 1.1, + talents = { + ActorTalents.T_IMPROVED_HEALTH_I, + ActorTalents.T_IMPROVED_HEALTH_II, + }, +} diff --git a/game/modules/tome/data/birth/sexes.lua b/game/modules/tome/data/birth/sexes.lua new file mode 100644 index 0000000000..1148181794 --- /dev/null +++ b/game/modules/tome/data/birth/sexes.lua @@ -0,0 +1,22 @@ +-- Player sexes +newBirthDescriptor{ + type = "sex", + name = "Female", + desc = + { + "You are a female of the species.", + "There is no in-game difference between the two sexes.", + }, + data = { female=true, }, +} + +newBirthDescriptor{ + type = "sex", + name = "Male", + desc = + { + "You are a male of the species.", + "There is no in-game difference between the two sexes.", + }, + flags = { male=true, }, +} diff --git a/game/modules/tome/data/birth/subraces.lua b/game/modules/tome/data/birth/subraces.lua new file mode 100644 index 0000000000..8164db76b3 --- /dev/null +++ b/game/modules/tome/data/birth/subraces.lua @@ -0,0 +1,153 @@ +--------------------------------------------------------- +-- Humans -- +--------------------------------------------------------- +newBirthDescriptor +{ + type = "subrace", + name = "Human", + desc = { + "Humans are one of the youngest of the races of Arda.", + }, +} +newBirthDescriptor +{ + type = "subrace", + name = "Dunadan", + desc = { + "The greatest of the Edain, humans in all respects but", + "stronger, smarter and wiser.", + }, + stats = { str=1, cun=1, dex=1, wil=1 }, + experience = 1.1, + talents = { ActorTalents.T_IMPROVED_HEALTH_I }, +} +--[[ +newBirthDescriptor +{ + type = "subrace" + name = "Rohirrim" + desc = { + "Humans from the land of Rohan, riding the great Mearas.", + } + stats = { [A_STR]=1, [A_INT]=1, [A_WIS]=0, [A_DEX]=3, [A_CON]=1, [A_CHR]=2, } + experience = 70 + levels = + { + [ 1] = { SPEED=3 } + } + skills = + { + ["Weaponmastery"] = { mods.add(0) , mods.add(200) } + ["Riding"] = { mods.add(5000), mods.add(600) } + } +} +]] +newBirthDescriptor +{ + type = "subrace", + name = "Beorning", + desc = { + "A race of men shapeshifters.", + "They have the unique power of being able to polymorph to bear form.", + }, + stats = { str=2, con=2, dex=-1, cun=-3, }, + experience = 1.8, + talents = {}, +} + +--------------------------------------------------------- +-- Elves -- +--------------------------------------------------------- +newBirthDescriptor +{ + type = "subrace", + name = "Noldor", + desc = { + "The Noldor are the second clan of Elves who came to Valinor, and ", + "are accounted as the greatest of all peoples in Middle-earth. ", + "They are masters of all skills, and are strong and intelligent. ", + "They can play all classes except rogues, and very well at that. ", + "High-elves begin their lives able to see the unseen, and resist ", + "light effects just like regular elves. However, there are few ", + "things that they have not seen already, and experience is very ", + "hard for them to gain." + }, + stats = { str=1, mag=2, wil=3, cun=1, dex=1, }, + experience = 1.3, + talents = {}, +} +newBirthDescriptor +{ + type = "subrace", + name = "Avari", + desc = { + "The Avari are those elves who refused the summons of Orome to come", + "to Valinor, and stayed behind in Middle-earth instead. While ", + "somewhat less hardy than the Noldor, they are better at magic, ", + "gain experience faster, and have an intrinsic magic missile ", + "attack. Unlike the Noldor, they are resistant to darkness attacks ", + "rather than light attacks, and gain the ability to see invisible ", + "things at a higher level, rather than starting out with it." + }, + stats = { str=-1, dex=2, cun=2, mag=1, }, + talents = { ActorTalents.DECREASED_HEALTH_I }, + experience = 1.1, +} + +--------------------------------------------------------- +-- Hobbits -- +--------------------------------------------------------- +newBirthDescriptor +{ + type = "subrace", + name = "Harfoot", + desc = { + "An old but quiet race related to humans.", + "They are small and quite weak but good at many things.", + }, +} +newBirthDescriptor +{ + type = "subrace", + name = "Fallohide", + desc = { + "An old but quiet race related to humans.", + "They are small and quite weak but good at many things.", + }, +} +newBirthDescriptor +{ + type = "subrace", + name = "Stoor", + desc = { + "An old but quiet race related to humans.", + "They are small and quite weak but good at many things.", + }, +} + +--------------------------------------------------------- +-- Dwarves -- +--------------------------------------------------------- +newBirthDescriptor +{ + type = "subrace", + name = "Dwarf", + desc = { + "The children of Aule, a strong but small race.", + "Miners and fighters of legend.", + }, +} + +--------------------------------------------------------- +-- Ents -- +--------------------------------------------------------- +newBirthDescriptor +{ + type = "subrace", + name = "Ent", + desc = { + "Guardian of the forests of Middle-earth, summoned by Yavanna before", + "even the elves awoke. It is said 'Trolls are strong, Ents are STRONGER'.", + "Ent-wives went away a long time ago and as such may not be played." + }, +} diff --git a/game/modules/tome/data/talents.lua b/game/modules/tome/data/talents.lua index e1bf6104d9..0a7400032e 100644 --- a/game/modules/tome/data/talents.lua +++ b/game/modules/tome/data/talents.lua @@ -1,183 +1,3 @@ --- "classes" -newTalentType{ type="base/class", name = "class", description = "The basic talents defining a class." } -newTalentType{ type="base/race", name = "race", description = "The various racial bonuses a character can have." } - -newTalent{ - name = "Mana Pool", - type = {"base/class", 1}, - info = "Allows you to have a mana pool. Mana is used to cast all spells.", -} -newTalent{ - name = "Stamina Pool", - type = {"base/class", 1}, - info = "Allows you to have a stamina pool. Stamina is used to activate special combat attacks.", -} - - --- Spells -newTalentType{ type="spell/arcane", name = "arcane", description = "Arcane manipulates the raw magic energies to shape them into both offensive and defensive spells." } -newTalentType{ type="spell/fire", name = "fire", description = "Harness the power of fire to burn your foes to ashes." } -newTalentType{ type="spell/earth", name = "earth", description = "Harness the power of the earth to protect and destroy." } -newTalentType{ type="spell/cold", name = "cold", description = "Harness the power of winter to shatter your foes." } -newTalentType{ type="spell/lightning", name = "lightning", description = "Harness the power of lightnings to fry your foes." } -newTalentType{ type="spell/conveyance", name = "conveyance", description = "Conveyance is the school of travel. It allows you to travel faster and to track others." } - --- Physical combat -newTalentType{ type="physical/2hweapon", name = "two handed weapons", description = "Allows the user to be more proficient with two handed weapons." } -newTalentType{ type="physical/1hweapon", name = "one handed weapons", description = "Allows the user to be more proficient with one handed weapons." } -newTalentType{ type="physical/dualweapon", name = "dual wielding", description = "Allows the user to be more proficient with dual wielding weapons." } -newTalentType{ type="physical/shield", name = "shields", description = "Allows the user to be more proficient with shields." } - -newTalent{ - name = "Manathrust", - type = {"spell/arcane", 1}, - mana = 10, - tactical = { - ATTACK = 10, - }, - action = function(self) - local t = {type="bolt", range=20} - local x, y = self:getTarget(t) - if not x or not y then return nil end - self:project(t, x, y, DamageType.ARCANE, 10 + self:getMag()) - return true - end, - require = { stat = { mag=10 }, }, - info = function(self) - return ([[Conjures up mana into a powerful bolt doing %0.2f arcane damage - The damage will increase with the Magic stat]]):format(10 + self:getMag()) - end, -} -newTalent{ - name = "Disruption Shield", - type = {"spell/arcane",2}, - mode = "sustained", - sustain_mana = 60, - tactical = { - DEFEND = 10, - }, - action = function(self) - return true - end, - require = { stat = { mag=12 }, }, - info = function(self) - return ([[Uses mana instead of life to take damage - The damage to mana ratio increases with the Magic stat]]):format(10 + self:getMag()) - end, -} - -newTalent{ - name = "Globe of Light", - type = {"spell/fire",1}, - mana = 5, - tactical = { - ATTACKAREA = 3, - }, - action = function(self) - local t = {type="ball", range=0, friendlyfire=false, radius=5 + self:getMag(10)} - self:project(t, self.x, self.y, DamageType.LIGHT, 1) - return true - end, - require = { stat = { mag=10 }, }, - info = function(self) - return ([[Creates a globe of pure light with a radius of %d that illuminates the area. - The radius will increase with the Magic stat]]):format(5 + self:getMag(10)) - end, -} - -newTalent{ - name = "Fireflash", - type = {"spell/fire",2}, - mana = 35, - cooldown = 6, - tactical = { - ATTACKAREA = 10, - }, - action = function(self) - local t = {type="ball", range=15, radius=math.min(6, 3 + self:getMag(6))} - local x, y = self:getTarget(t) - if not x or not y then return nil end - self:project(t, x, y, DamageType.FIRE, 28 + self:getMag(70)) - return true - end, - require = { stat = { mag=16 }, }, - info = function(self) - return ([[Conjures up a flash of fire doing %0.2f fire damage in a radius of %d. - Cooldown: 6 turns - The damage will increase with the Magic stat]]):format(8 + self:getMag(70), math.min(6, 3 + self:getMag(6))) - end, -} - -newTalent{ - name = "Blink", - type = {"spell/conveyance",1}, - message = "@Source@ blinks.", - mana = 15, - cooldown = 9, - tactical = { - ESCAPE = 4, - }, - action = function(self) - local x, y = self.x, self.y - if self:knowTalent(self.T_TELEPORT_CONTROL) then - x, y = self:getTarget{type="ball", range=10 + self:getMag(10), radius=5 - self:getMag(4)} - 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:getMag(10)) - self:teleportRandom(x, y, 5 - self:getMag(4)) - else - self:teleportRandom(x, y, 10 + self:getMag(10)) - end - return true - end, - require = { stat = { mag=16 }, }, - info = function(self) - return ([[Teleports you randomly on a small scale range (%d) - The range will increase with the Magic stat]]):format(10 + self:getMag(10)) - end, -} - -newTalent{ - name = "Teleport Control", - type = {"spell/conveyance",2}, - require = { stat = { mag=38 }, }, - 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:getMag(4)) - end, -} - - -newTalent{ - name = "Noxious Cloud", - type = {"spell/earth",1}, - mana = 45, - cooldown = 8, - tactical = { - ATTACKAREA = 10, - }, - action = function(self) - local duration = 5 + self:getMag(10) - local radius = 3 - local t = {type="ball", range=15, radius=math.min(6, 3 + self:getMag(6))} - local x, y = self:getTarget(t) - if not x or not y then return nil end - x, y = game.target:pointAtRange(self.x, self.y, x, y, 15) - -- Add a lasting map effect - game.level.map:addEffect(self, - x, y, duration, - DamageType.NATURE, 4 + self:getMag(30), - radius, - 5, nil, - engine.Entity.new{alpha=100, display='', color_br=30, color_bg=180, color_bb=60} - ) - return true - end, - require = { stat = { mag=16 }, }, - info = function(self) - return ([[Noxious fumes raises from the ground doing %0.2f nature damage in a radius of 3 each turns for %d turns. - Cooldown: 8 turns - The damage and duration will increase with the Magic stat]]):format(4 + self:getMag(30), 5 + self:getMag(10)) - end, -} +load("/data/talents/misc/misc.lua") +load("/data/talents/spells/spells.lua") +load("/data/talents/physical/physical.lua") diff --git a/game/modules/tome/data/talents/misc/misc.lua b/game/modules/tome/data/talents/misc/misc.lua new file mode 100644 index 0000000000..2e11e98dff --- /dev/null +++ b/game/modules/tome/data/talents/misc/misc.lua @@ -0,0 +1,53 @@ +-- race & classes +newTalentType{ type="base/class", name = "class", hide = true, description = "The basic talents defining a class." } +newTalentType{ type="base/race", name = "race", hide = true, description = "The various racial bonuses a character can have." } + +newTalent{ + name = "Mana Pool", + type = {"base/class", 1}, + info = "Allows you to have a mana pool. Mana is used to cast all spells.", + hide = true, +} +newTalent{ + name = "Stamina Pool", + type = {"base/class", 1}, + info = "Allows you to have a stamina pool. Stamina is used to activate special combat attacks.", + hide = true, +} + +newTalent{ + name = "Improved Health I", + type = {"base/race", 1}, + info = "Improves the number of health points per levels.", + hide = true, +} +newTalent{ + name = "Improved Health II", + type = {"base/race", 1}, + info = "Improves the number of health points per levels.", + hide = true, +} +newTalent{ + name = "Improved Health III", + type = {"base/race", 1}, + info = "Improves the number of health points per levels.", + hide = true, +} +newTalent{ + name = "Decreased Health I", + type = {"base/race", 1}, + info = "Improves the number of health points per levels.", + hide = true, +} +newTalent{ + name = "Decreased Health II", + type = {"base/race", 1}, + info = "Improves the number of health points per levels.", + hide = true, +} +newTalent{ + name = "Decreased Health III", + type = {"base/race", 1}, + info = "Improves the number of health points per levels.", + hide = true, +} diff --git a/game/modules/tome/data/talents/physical/physical.lua b/game/modules/tome/data/talents/physical/physical.lua new file mode 100644 index 0000000000..14d02864f2 --- /dev/null +++ b/game/modules/tome/data/talents/physical/physical.lua @@ -0,0 +1,5 @@ +-- Physical combat +newTalentType{ type="physical/2hweapon", name = "two handed weapons", description = "Allows the user to be more proficient with two handed weapons." } +newTalentType{ type="physical/1hweapon", name = "one handed weapons", description = "Allows the user to be more proficient with one handed weapons." } +newTalentType{ type="physical/dualweapon", name = "dual wielding", description = "Allows the user to be more proficient with dual wielding weapons." } +newTalentType{ type="physical/shield", name = "shields", description = "Allows the user to be more proficient with shields." } diff --git a/game/modules/tome/data/talents/spells/spells.lua b/game/modules/tome/data/talents/spells/spells.lua new file mode 100644 index 0000000000..673fde5369 --- /dev/null +++ b/game/modules/tome/data/talents/spells/spells.lua @@ -0,0 +1,161 @@ +-- Spells +newTalentType{ type="spell/arcane", name = "arcane", description = "Arcane manipulates the raw magic energies to shape them into both offensive and defensive spells." } +newTalentType{ type="spell/fire", name = "fire", description = "Harness the power of fire to burn your foes to ashes." } +newTalentType{ type="spell/earth", name = "earth", description = "Harness the power of the earth to protect and destroy." } +newTalentType{ type="spell/cold", name = "cold", description = "Harness the power of winter to shatter your foes." } +newTalentType{ type="spell/air", name = "air", description = "Harness the power of the air to fry your foes." } +newTalentType{ type="spell/conveyance", name = "conveyance", description = "Conveyance is the school of travel. It allows you to travel faster and to track others." } + +newTalent{ + name = "Manathrust", + type = {"spell/arcane", 1}, + mana = 10, + tactical = { + ATTACK = 10, + }, + action = function(self) + local t = {type="bolt", range=20} + local x, y = self:getTarget(t) + if not x or not y then return nil end + self:project(t, x, y, DamageType.ARCANE, 10 + self:getMag()) + return true + end, + require = { stat = { mag=10 }, }, + info = function(self) + return ([[Conjures up mana into a powerful bolt doing %0.2f arcane damage + The damage will increase with the Magic stat]]):format(10 + self:getMag()) + end, +} +newTalent{ + name = "Disruption Shield", + type = {"spell/arcane",2}, + mode = "sustained", + sustain_mana = 60, + tactical = { + DEFEND = 10, + }, + action = function(self) + return true + end, + require = { stat = { mag=12 }, }, + info = function(self) + return ([[Uses mana instead of life to take damage + The damage to mana ratio increases with the Magic stat]]):format(10 + self:getMag()) + end, +} + +newTalent{ + name = "Globe of Light", + type = {"spell/fire",1}, + mana = 5, + tactical = { + ATTACKAREA = 3, + }, + action = function(self) + local t = {type="ball", range=0, friendlyfire=false, radius=5 + self:getMag(10)} + self:project(t, self.x, self.y, DamageType.LIGHT, 1) + return true + end, + require = { stat = { mag=10 }, }, + info = function(self) + return ([[Creates a globe of pure light with a radius of %d that illuminates the area. + The radius will increase with the Magic stat]]):format(5 + self:getMag(10)) + end, +} + +newTalent{ + name = "Fireflash", + type = {"spell/fire",2}, + mana = 35, + cooldown = 6, + tactical = { + ATTACKAREA = 10, + }, + action = function(self) + local t = {type="ball", range=15, radius=math.min(6, 3 + self:getMag(6))} + local x, y = self:getTarget(t) + if not x or not y then return nil end + self:project(t, x, y, DamageType.FIRE, 28 + self:getMag(70)) + return true + end, + require = { stat = { mag=16 }, }, + info = function(self) + return ([[Conjures up a flash of fire doing %0.2f fire damage in a radius of %d. + Cooldown: 6 turns + The damage will increase with the Magic stat]]):format(8 + self:getMag(70), math.min(6, 3 + self:getMag(6))) + end, +} + +newTalent{ + name = "Blink", + type = {"spell/conveyance",1}, + message = "@Source@ blinks.", + mana = 15, + cooldown = 9, + tactical = { + ESCAPE = 4, + }, + action = function(self) + local x, y = self.x, self.y + if self:knowTalent(self.T_TELEPORT_CONTROL) then + x, y = self:getTarget{type="ball", range=10 + self:getMag(10), radius=5 - self:getMag(4)} + 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:getMag(10)) + self:teleportRandom(x, y, 5 - self:getMag(4)) + else + self:teleportRandom(x, y, 10 + self:getMag(10)) + end + return true + end, + require = { stat = { mag=16 }, }, + info = function(self) + return ([[Teleports you randomly on a small scale range (%d) + The range will increase with the Magic stat]]):format(10 + self:getMag(10)) + end, +} + +newTalent{ + name = "Teleport Control", + type = {"spell/conveyance",2}, + require = { stat = { mag=38 }, }, + 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:getMag(4)) + end, +} + + +newTalent{ + name = "Noxious Cloud", + type = {"spell/earth",1}, + mana = 45, + cooldown = 8, + tactical = { + ATTACKAREA = 10, + }, + action = function(self) + local duration = 5 + self:getMag(10) + local radius = 3 + local t = {type="ball", range=15, radius=math.min(6, 3 + self:getMag(6))} + local x, y = self:getTarget(t) + if not x or not y then return nil end + x, y = game.target:pointAtRange(self.x, self.y, x, y, 15) + -- Add a lasting map effect + game.level.map:addEffect(self, + x, y, duration, + DamageType.NATURE, 4 + self:getMag(30), + radius, + 5, nil, + engine.Entity.new{alpha=100, display='', color_br=30, color_bg=180, color_bb=60} + ) + return true + end, + require = { stat = { mag=16 }, }, + info = function(self) + return ([[Noxious fumes raises from the ground doing %0.2f nature damage in a radius of 3 each turns for %d turns. + Cooldown: 8 turns + The damage and duration will increase with the Magic stat]]):format(4 + self:getMag(30), 5 + self:getMag(10)) + end, +} diff --git a/game/modules/tome/data/zones/ancient_ruins/npcs.lua b/game/modules/tome/data/zones/ancient_ruins/npcs.lua index 167d612f02..4fe00c8144 100644 --- a/game/modules/tome/data/zones/ancient_ruins/npcs.lua +++ b/game/modules/tome/data/zones/ancient_ruins/npcs.lua @@ -3,7 +3,7 @@ return { { name = "dragon of death", display = "D", color_r=255, - level_range = {1, 10}, exp_worth = 1, + level_range = {1, 10}, exp_worth = 100, autolevel = "warrior", ai = "simple", max_life = 20, @@ -18,7 +18,7 @@ return { name = "baby dragon", display = "d", color_r=128, -- faction = "poorsods", - level_range = {1, 4}, exp_worth = 1, + level_range = {1, 4}, exp_worth = 100, autolevel = "caster", ai = "simple", max_life = 30, diff --git a/game/modules/tome/data/zones/ancient_ruins/zone.lua b/game/modules/tome/data/zones/ancient_ruins/zone.lua index e3f15b9451..c3e40aee15 100644 --- a/game/modules/tome/data/zones/ancient_ruins/zone.lua +++ b/game/modules/tome/data/zones/ancient_ruins/zone.lua @@ -7,7 +7,7 @@ return { -- persistant = true, generator = { map = { - class= "engine.generator.map.Rooms", + class= "engine.generator.map.Empty", floor = "FLOOR", wall = "WALL", up = "UP", diff --git a/game/modules/tome/dialogs/LevelupTalentsDialog.lua b/game/modules/tome/dialogs/LevelupTalentsDialog.lua index baa43c5134..3ce91026ac 100644 --- a/game/modules/tome/dialogs/LevelupTalentsDialog.lua +++ b/game/modules/tome/dialogs/LevelupTalentsDialog.lua @@ -32,20 +32,24 @@ function _M:generateList() -- Makes up the list local list, known = {}, {} 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" - - -- 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 not tt.hide and not (self.actor.talents_types[tt.type] == nil) then + 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" + + -- Find all talents of this school + for j, t in ipairs(tt.talents) do + if not t.hide then + 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 + end + else + known[#known+1] = tt.points.." point(s)" end - else - known[#known+1] = tt.points.." point(s)" end end self.list = list diff --git a/game/modules/tome/load.lua b/game/modules/tome/load.lua index 23fe0969da..e09e1be356 100644 --- a/game/modules/tome/load.lua +++ b/game/modules/tome/load.lua @@ -4,6 +4,7 @@ local ActorStats = require "engine.interface.ActorStats" local ActorResource = require "engine.interface.ActorResource" local ActorTalents = require "engine.interface.ActorTalents" local ActorAI = require "engine.interface.ActorAI" +local Birther = require "engine.Birther" -- Damage types DamageType:loadDefinition("/data/damage_types.lua") @@ -24,5 +25,8 @@ dofile("/data/autolevel_schemes.lua") -- Actor AIs ActorAI:loadDefinition("/engine/ai/") +-- Birther descriptor +Birther:loadDefinition("/data/birth/descriptors.lua") + return require "mod.class.Game" -- GitLab