From 91bc65842090883c16f47aa9b1ef37d0458d9625 Mon Sep 17 00:00:00 2001 From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54> Date: Tue, 22 Dec 2009 18:29:22 +0000 Subject: [PATCH] EGOS ! git-svn-id: http://svn.net-core.org/repos/t-engine4@139 51575b47-30f0-44d4-a5cc-537603b46e54 --- game/engine/Actor.lua | 4 +- game/engine/Entity.lua | 114 +++++++++--------- game/engine/Grid.lua | 4 +- game/engine/Level.lua | 13 ++ game/engine/Object.lua | 9 +- game/engine/Zone.lua | 43 ++++++- game/engine/generator/actor/Random.lua | 9 +- game/engine/generator/object/Random.lua | 11 +- game/modules/tome/class/Actor.lua | 4 +- game/modules/tome/class/Game.lua | 2 +- game/modules/tome/class/Grid.lua | 4 +- game/modules/tome/class/NPC.lua | 4 +- game/modules/tome/class/Object.lua | 4 +- game/modules/tome/class/Player.lua | 4 +- game/modules/tome/data/general/egos.lua | 2 +- game/modules/tome/data/general/staves.lua | 1 + game/modules/tome/data/general/swords.lua | 1 + .../tome/data/zones/ancient_ruins/zone.lua | 4 +- ideas/materials.ods | Bin 0 -> 9377 bytes 19 files changed, 146 insertions(+), 91 deletions(-) create mode 100644 ideas/materials.ods diff --git a/game/engine/Actor.lua b/game/engine/Actor.lua index 8223d00dcc..9d58fd9030 100644 --- a/game/engine/Actor.lua +++ b/game/engine/Actor.lua @@ -5,7 +5,7 @@ local Faction = require "engine.Faction" module(..., package.seeall, class.inherit(Entity)) -function _M:init(t) +function _M:init(t, no_default) t = t or {} self.name = t.name or "unknown actor" @@ -16,7 +16,7 @@ function _M:init(t) self.energy.mod = self.energy.mod or 0 self.faction = t.faction or "enemies" self.changed = true - Entity.init(self, t) + Entity.init(self, t, no_default) self.compute_vals = {} end diff --git a/game/engine/Entity.lua b/game/engine/Entity.lua index f7ac209c18..1d210d9167 100644 --- a/game/engine/Entity.lua +++ b/game/engine/Entity.lua @@ -11,14 +11,16 @@ setmetatable(__uids, {__mode="v"}) local function copy_recurs(dst, src, deep) for k, e in pairs(src) do - if not dst[k] then + if type(e) == "table" and e.__CLASSNAME then + dst[k] = e + elseif not dst[k] then if deep then dst[k] = {} copy_recurs(dst[k], e, deep) else dst[k] = e end - elseif type(dst[k]) == "table" and type(e) == "table" then + elseif type(dst[k]) == "table" and type(e) == "table" and not e.__CLASSNAME then copy_recurs(dst[k], e, deep) end end @@ -28,7 +30,7 @@ end -- Any subclass MUST call this constructor -- @param t a table defining the basic properties of the entity -- @usage Entity.new{display='#', color_r=255, color_g=255, color_b=255} -function _M:init(t) +function _M:init(t, no_default) t = t or {} self.uid = next_uid __uids[self.uid] = self @@ -39,23 +41,25 @@ function _M:init(t) self[k] = ee end - self.image = self.image or nil - self.display = self.display or '.' - if self.color then - self.color_r = self.color.r - self.color_g = self.color.g - self.color_b = self.color.b - self.color_br = self.color.br - self.color_bg = self.color.bg - self.color_bb = self.color.bb - self.color = nil + if not no_default then + self.image = self.image or nil + self.display = self.display or '.' + if self.color then + self.color_r = self.color.r + self.color_g = self.color.g + self.color_b = self.color.b + self.color_br = self.color.br + self.color_bg = self.color.bg + self.color_bb = self.color.bb + self.color = nil + end + self.color_r = self.color_r or 0 + self.color_g = self.color_g or 0 + self.color_b = self.color_b or 0 + self.color_br = self.color_br or -1 + self.color_bg = self.color_bg or -1 + self.color_bb = self.color_bb or -1 end - self.color_r = self.color_r or 0 - self.color_g = self.color_g or 0 - self.color_b = self.color_b or 0 - self.color_br = self.color_br or -1 - self.color_bg = self.color_bg or -1 - self.color_bb = self.color_bb or -1 next_uid = next_uid + 1 @@ -121,48 +125,46 @@ function _M:check(prop, ...) end --- Loads a list of entities from a definition file --- @param ... the files to load from +-- @param file the file to load from +-- @param no_default if true then no default values will be assigned -- @usage MyEntityClass:loadList("/data/my_entities_def.lua") -function _M:loadList(...) +function _M:loadList(file, no_default) local res = {} - for i, file in ipairs{...} do - local f, err = loadfile(file) - if err then error(err) end - - setfenv(f, setmetatable({ - resolvers = resolvers, - DamageType = require "engine.DamageType", - newEntity = function(t) - -- Do we inherit things ? - if t.base then - for k, e in pairs(res[t.base]) do - if not t[k] then - t[k] = e - elseif type(t[k]) == "table" and type(e) == "table" then - copy_recurs(t[k], e) - end + print("Loading entities file", file) + local f, err = loadfile(file) + if err then error(err) end + + setfenv(f, setmetatable({ + resolvers = resolvers, + DamageType = require "engine.DamageType", + newEntity = function(t) + -- Do we inherit things ? + if t.base then + for k, e in pairs(res[t.base]) do + if not t[k] then + t[k] = e + elseif type(t[k]) == "table" and type(e) == "table" then + copy_recurs(t[k], e) end - t.base = nil end + t.base = nil + end + + local e = self.new(t, no_default) + print("loaded", e.name, no_default) + res[#res+1] = e + if t.define_as then res[t.define_as] = e end + end, + load = function(f) + local ret = self:loadList(f) + for i, e in ipairs(ret) do res[#res+1] = e end + end, + loadList = function(f) + return self:loadList(f) + end, + }, {__index=_G})) + f() - local e = self.new(t) - res[#res+1] = e - if t.define_as then res[t.define_as] = e end --- print("new entity", t.name) - for k, ee in pairs(e) do --- print("prop:", k, ee) - end - end, - load = function(f) - local ret = self:loadList(f) - for i, e in ipairs(ret) do res[#res+1] = e end - end, - loadList = function(f) - return self:loadList(f) - end, - }, {__index=_G})) - f() - end return res end diff --git a/game/engine/Grid.lua b/game/engine/Grid.lua index d7647275b2..21bd36f2e1 100644 --- a/game/engine/Grid.lua +++ b/game/engine/Grid.lua @@ -3,8 +3,8 @@ local Entity = require "engine.Entity" module(..., package.seeall, class.inherit(Entity)) -function _M:init(t) +function _M:init(t, no_default) t = t or {} self.name = t.name - Entity.init(self, t) + Entity.init(self, t, no_default) end diff --git a/game/engine/Level.lua b/game/engine/Level.lua index b1a269f70b..d631223a8d 100644 --- a/game/engine/Level.lua +++ b/game/engine/Level.lua @@ -16,6 +16,8 @@ function _M:init(level, map) self.e_distances = {} self.distancer_co = self:createDistancer() + + self.entities_list = {} end --- Adds an entity to the level @@ -115,3 +117,14 @@ end function _M:idleProcessActor(act) table.insert(self.e_toprocess, 1, act) end + +--- Setup an entity list for the level, this allwos the Zone to pick objects/actors/... +function _M:setEntitiesList(type, list) + self.entities_list[type] = list + print("Stored entities list", type, list) +end + +--- Gets an entity list for the level, this allows the Zone to pick objects/actors/... +function _M:getEntitiesList(type) + return self.entities_list[type] +end diff --git a/game/engine/Object.lua b/game/engine/Object.lua index ac3170d4b4..9bfb78f8ad 100644 --- a/game/engine/Object.lua +++ b/game/engine/Object.lua @@ -3,14 +3,9 @@ local Entity = require "engine.Entity" module(..., package.seeall, class.inherit(Entity)) -function _M:init(t) +function _M:init(t, no_default) t = t or {} - Entity.init(self, t) -end - -function _M:resolve(t) - Entity.resolve(self, t) - self.egos = nil + Entity.init(self, t, no_default) end --- Gets the full name of the object diff --git a/game/engine/Zone.lua b/game/engine/Zone.lua index 4dbc53f713..d2d234992b 100644 --- a/game/engine/Zone.lua +++ b/game/engine/Zone.lua @@ -52,7 +52,7 @@ function _M:computeRarities(list, level, ood, filter) elseif lev > e.level_range[2] then max = 100 / (lev - e.level_range[2]) end local genprob = max / e.rarity - print("prob", e.name, math.floor(genprob), "max", math.floor(max), e.level_range[1], e.level_range[2], lev) + print("prob", e.name, math.floor(genprob), "max", math.floor(max), e.level_range[1], e.level_range[2], lev, "egoable", e.egos and #e.egos) r.total = r.total + genprob r[#r+1] = { e=e, genprob=r.total + genprob, level_diff = lev - level } @@ -76,6 +76,47 @@ function _M:pickEntity(list) return nil end +function _M:getEgosList(level, type, group, class) + -- Already loaded ? use it + local list = level:getEntitiesList(type.."/"..group) + if list then return list end + + -- otehrwise loads it and store it + list = require(class):loadList(group, true) + level:setEntitiesList(type.."/"..group, list) + + return list +end + +function _M:makeEntity(level, type) + local list = level:getEntitiesList(type) + local e = self:pickEntity(list) + e = e:clone() + e:resolve() + + -- Add "ego" properties + if e.egos then + local egos = self:getEgosList(level, type, e.egos, e.__CLASSNAME) + local ego = egos[rng.range(1, #egos)] + if ego then + print("ego", ego.__CLASSNAME, ego.name, getmetatable(ego)) + ego = ego:clone() + ego:resolve() + local newname + if ego.prefix then + newname = ego.name .. e.name + else + newname = e.name .. ego.name + end + print("applying ego", ego.name, "to ", e.name, "::", newname) + table.merge(e, ego, true) + e.name = newname + end + end + + return e +end + function _M:load() local f, err = loadfile("/data/zones/"..self.short_name.."/zone.lua") if err then error(err) end diff --git a/game/engine/generator/actor/Random.lua b/game/engine/generator/actor/Random.lua index a6950e2b51..11f48b780b 100644 --- a/game/engine/generator/actor/Random.lua +++ b/game/engine/generator/actor/Random.lua @@ -7,7 +7,10 @@ function _M:init(zone, map, level) engine.Generator.init(self, zone, map) self.level = level local data = level.data.generator.actor - self.npc_list = zone:computeRarities(zone.npc_list, level.level, data.ood, nil) + + -- Setup the entities list + level:setEntitiesList("actor", zone:computeRarities(zone.npc_list, level.level, data.ood, nil)) + if data.adjust_level_to_player and game:getPlayer() then self.adjust_level_to_player = {base=game:getPlayer().level, min=data.adjust_level_to_player[1], max=data.adjust_level_to_player[2]} end @@ -17,10 +20,8 @@ end function _M:generate() for i = 1, rng.range(self.nb_npc[1], self.nb_npc[2]) do - local m = self.zone:pickEntity(self.npc_list) + local m = self.zone:makeEntity(self.level, "actor") if m then - m = m:clone() - m:resolve() local x, y = rng.range(0, self.map.w), rng.range(0, self.map.h) local tries = 0 while not m:canMove(x, y) and tries < 100 do diff --git a/game/engine/generator/object/Random.lua b/game/engine/generator/object/Random.lua index 6ff3c45e73..4dc974907f 100644 --- a/game/engine/generator/object/Random.lua +++ b/game/engine/generator/object/Random.lua @@ -6,8 +6,11 @@ module(..., package.seeall, class.inherit(engine.Generator)) function _M:init(zone, map, level) engine.Generator.init(self, zone, map) self.level = level - local data = level.data - self.object_list = zone:computeRarities(zone.object_list, level.level, data.generator and data.generator.actor and data.generator.actor.ood, nil) + local data = level.data.generator.object + + -- Setup the entities list + level:setEntitiesList("object", zone:computeRarities(zone.object_list, level.level, data.ood, nil)) + if data.adjust_level_to_player and game:getPlayer() then self.adjust_level_to_player = {base=game:getPlayer().level, min=data.adjust_level_to_player[1], max=data.adjust_level_to_player[2]} end @@ -17,10 +20,8 @@ end function _M:generate() for i = 1, rng.range(self.nb_object[1], self.nb_object[2]) do - local o = self.zone:pickEntity(self.object_list) + local o = self.zone:makeEntity(self.level, "object") if o then - o = o:clone() - o:resolve() local x, y = rng.range(0, self.map.w), rng.range(0, self.map.h) local tries = 0 while (self.map:checkEntity(x, y, Map.TERRAIN, "block_move") or self.map(x, y, Map.OBJECT)) and tries < 100 do diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 27007f214f..27646543ce 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -25,7 +25,7 @@ module(..., package.seeall, class.inherit( mod.class.interface.Combat )) -function _M:init(t) +function _M:init(t, no_default) -- Define some basic combat stats self.combat_def = 0 self.combat_armor = 0 @@ -54,7 +54,7 @@ function _M:init(t) -- Default melee barehanded damage self.combat = { dam=1, atk=1, apr=0, dammod={str=1} } - engine.Actor.init(self, t) + engine.Actor.init(self, t, no_default) engine.interface.ActorInventory.init(self, t) engine.interface.ActorTemporaryEffects.init(self, t) engine.interface.ActorLife.init(self, t) diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index d7ae87c3bb..fd21bafb4c 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -75,7 +75,7 @@ function _M:newGame() self.player = Player.new{name=self.player_name} local birth = Birther.new(self.player, {"base", "race", "subrace", "sex", "class", "subclass" }, function() - self.player.wild_x, self.player.wild_y = 38, 15 + self.player.wild_x, self.player.wild_y = 39, 17 self:changeLevel(1) local ds = LevelupStatsDialog.new(self.player) diff --git a/game/modules/tome/class/Grid.lua b/game/modules/tome/class/Grid.lua index 8c9a2029e0..3d224a2ae3 100644 --- a/game/modules/tome/class/Grid.lua +++ b/game/modules/tome/class/Grid.lua @@ -3,8 +3,8 @@ require "engine.Grid" module(..., package.seeall, class.inherit(engine.Grid)) -function _M:init(t) - engine.Grid.init(self, t) +function _M:init(t, no_default) + engine.Grid.init(self, t, no_default) end function _M:block_move(x, y, e) diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua index 7a1372162c..47530eec3c 100644 --- a/game/modules/tome/class/NPC.lua +++ b/game/modules/tome/class/NPC.lua @@ -4,8 +4,8 @@ require "mod.class.Actor" module(..., package.seeall, class.inherit(mod.class.Actor, engine.interface.ActorAI)) -function _M:init(t) - mod.class.Actor.init(self, t) +function _M:init(t, no_default) + mod.class.Actor.init(self, t, no_default) ActorAI.init(self, t) end diff --git a/game/modules/tome/class/Object.lua b/game/modules/tome/class/Object.lua index 07909cbab9..85d2987786 100644 --- a/game/modules/tome/class/Object.lua +++ b/game/modules/tome/class/Object.lua @@ -3,8 +3,8 @@ require "engine.Object" module(..., package.seeall, class.inherit(engine.Object)) -function _M:init(t) - engine.Object.init(self, t) +function _M:init(t, no_default) + engine.Object.init(self, t, no_default) end function _M:tooltip() diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index 5fcd44fa63..c739697f3f 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -6,7 +6,7 @@ local ActorTalents = require "engine.interface.ActorTalents" module(..., package.seeall, class.inherit(mod.class.Actor)) -function _M:init(t) +function _M:init(t, no_default) t.body = { INVEN = 1000, MAINHAND = 1, @@ -20,7 +20,7 @@ function _M:init(t) FEET = 1, TOOL = 1, } - mod.class.Actor.init(self, t) + mod.class.Actor.init(self, t, no_default) self.player = true self.faction = "players" diff --git a/game/modules/tome/data/general/egos.lua b/game/modules/tome/data/general/egos.lua index 26bb20e48c..7d456d30dd 100644 --- a/game/modules/tome/data/general/egos.lua +++ b/game/modules/tome/data/general/egos.lua @@ -1,5 +1,5 @@ newEntity{ - name = "flaming ", + name = "flaming ", prefix=true, level_range = {1, 10}, rarity = 3, wielder = { diff --git a/game/modules/tome/data/general/staves.lua b/game/modules/tome/data/general/staves.lua index e0837b4612..c512986606 100644 --- a/game/modules/tome/data/general/staves.lua +++ b/game/modules/tome/data/general/staves.lua @@ -6,6 +6,7 @@ newEntity{ encumber = 5, rarity = 3, desc = [[Staves designed for wielders of magic, by the greats of the art.]], + egos = "/data/general/egos.lua", } newEntity{ base = "BASE_STAFF", diff --git a/game/modules/tome/data/general/swords.lua b/game/modules/tome/data/general/swords.lua index c33bc3c818..05fa636662 100644 --- a/game/modules/tome/data/general/swords.lua +++ b/game/modules/tome/data/general/swords.lua @@ -6,6 +6,7 @@ newEntity{ encumber = 3, rarity = 3, desc = [[Sharp, long, and deadly.]], + egos = "/data/general/egos.lua", } newEntity{ base = "BASE_LONGSWORD", diff --git a/game/modules/tome/data/zones/ancient_ruins/zone.lua b/game/modules/tome/data/zones/ancient_ruins/zone.lua index e4b45e529d..7d243d86d9 100644 --- a/game/modules/tome/data/zones/ancient_ruins/zone.lua +++ b/game/modules/tome/data/zones/ancient_ruins/zone.lua @@ -19,13 +19,13 @@ return { }, actor = { class = "engine.generator.actor.Random", - nb_npc = {20, 30}, + nb_npc = {2, 3}, ood = {chance=5, range={1, 10}}, adjust_level_to_player = {-1, 2}, }, object = { class = "engine.generator.object.Random", - nb_object = {3, 6}, + nb_object = {100, 100}, ood = {chance=5, range={1, 10}}, }, }, diff --git a/ideas/materials.ods b/ideas/materials.ods new file mode 100644 index 0000000000000000000000000000000000000000..9feec2ad97bd9d6641714ab878670287619deaae GIT binary patch literal 9377 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 a@JIh?s6&V`1P%^0=Cg{qLr7=GKK&nc;eW0G literal 0 HcmV?d00001 -- GitLab