From 13dbd5d1c09f9eaf45e99d7a9acd70c360a1678a Mon Sep 17 00:00:00 2001 From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54> Date: Thu, 24 Dec 2009 00:47:30 +0000 Subject: [PATCH] drops; multi-floor pickup dialog git-svn-id: http://svn.net-core.org/repos/t-engine4@145 51575b47-30f0-44d4-a5cc-537603b46e54 --- game/engine/Map.lua | 27 ++++++ game/engine/Zone.lua | 7 +- game/engine/dialogs/ShowPickupFloor.lua | 97 +++++++++++++++++++ game/engine/interface/ActorInventory.lua | 14 ++- game/modules/tome/class/Actor.lua | 11 +++ game/modules/tome/class/Game.lua | 9 +- .../tome/data/zones/ancient_ruins/npcs.lua | 3 +- game/modules/tome/resolvers.lua | 26 +++++ 8 files changed, 186 insertions(+), 8 deletions(-) create mode 100644 game/engine/dialogs/ShowPickupFloor.lua diff --git a/game/engine/Map.lua b/game/engine/Map.lua index ac2268107f..069acf48d9 100644 --- a/game/engine/Map.lua +++ b/game/engine/Map.lua @@ -460,4 +460,31 @@ function _M:addObject(x, y, o) while self(x, y, i) do i = i + 1 end -- Fill it self(x, y, i, o) + return true +end + +function _M:getObject(x, y, i) + -- Compute the map stack position + i = i - 1 + self.OBJECT + return self(x, y, i) +end + +function _M:removeObject(x, y, i) + -- Compute the map stack position + i = i - 1 + self.OBJECT + if not self(x, y, i) then return false end + -- Remove it + self:remove(x, y, i) + -- Move the last one to its position, to never get a "hole" + local j = i + 1 + while self(x, y, j) do j = j + 1 end + j = j - 1 + -- If the removed one was not the last + if j > i then + local o = self(x, y, j) + self:remove(x, y, j) + self(x, y, i, o) + end + + return true end diff --git a/game/engine/Zone.lua b/game/engine/Zone.lua index d1cf158c25..75fd6a4d1d 100644 --- a/game/engine/Zone.lua +++ b/game/engine/Zone.lua @@ -142,18 +142,18 @@ function _M:makeEntity(level, type, filter) end if tries == 0 then return nil end - e = self:finishEntity(level, type, e) + e = self:finishEntity(level, type, e, filter and filter.ego_chance) return e end --- Finishes generating an entity -function _M:finishEntity(level, type, e) +function _M:finishEntity(level, type, e, ego_chance) e = e:clone() e:resolve() -- Add "ego" properties, sometimes - if e.egos and e.egos_chance and rng.percent(e.egos_chance) then + if e.egos and e.egos_chance and rng.percent(e.egos_chance + (ego_chance or 0)) then local egos = self:getEgosList(level, type, e.egos, e.__CLASSNAME) local ego = self:pickEntity(egos) if ego then @@ -169,6 +169,7 @@ function _M:finishEntity(level, type, e) print("applying ego", ego.name, "to ", e.name, "::", newname) table.merge(e, ego, true) e.name = newname + e.egoed = true end end return e diff --git a/game/engine/dialogs/ShowPickupFloor.lua b/game/engine/dialogs/ShowPickupFloor.lua new file mode 100644 index 0000000000..260c67dec8 --- /dev/null +++ b/game/engine/dialogs/ShowPickupFloor.lua @@ -0,0 +1,97 @@ +require "engine.class" +require "engine.Dialog" + +module(..., package.seeall, class.inherit(engine.Dialog)) + +function _M:init(title, x, y, filter, action) + self.x, self.y = x, y + self.filter = filter + self.action = action + engine.Dialog.init(self, title or "Pickup", game.w * 0.8, game.h * 0.8) + + self:generateList() + + self.sel = 1 + 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:use() end, + _ESCAPE = function() game:unregisterDialog(self) end, + _ASTERISK = function() while self:use() do end end, + __TEXTINPUT = function(c) + if c:find("^[a-z]$") then + self.sel = util.bound(1 + string.byte(c) - string.byte('a'), 1, #self.list) + self:use() + end + end, + } + self:mouseZones{ + { x=2, y=5, w=350, h=self.font_h*#self.list, fct=function(button, x, y, xrel, yrel, tx, ty) + self.sel = util.bound(1 + math.floor(ty / self.font_h), 1, #self.list) + if button == "left" then self:use() + elseif button == "right" then + end + end }, + } +end + +function _M:use() + if self.list[self.sel] then + self.action(self.list[self.sel].object, self.list[self.sel].item) + end + self:generateList() + if #self.list == 0 then + game:unregisterDialog(self) + return false + end + return true +end + +function _M:generateList() + -- Makes up the list + local list = {} + local idx = 1 + local i = 1 + while true do + local o = game.level.map:getObject(self.x, self.y, idx) + if not o then break end + if not self.filter or self.filter(o) then + list[#list+1] = { name=string.char(string.byte('a') + i)..") "..o:getName(), object=o, item=idx } + i = i + 1 + end + idx = idx + 1 + end + self.list = list + self.sel = 1 +end + +function _M:drawDialog(s) + -- Description part + self:drawHBorder(s, self.iw / 2, 2, self.ih - 4) + + local talentshelp = ([[Keyboard: #00FF00#up key/down key#FFFFFF# to select an object; #00FF00#enter#FFFFFF# to use. +Mouse: #00FF00#Left click#FFFFFF# to pickup. +]]):splitLines(self.iw / 2 - 10, self.font) + + local lines = {} + local h = 2 + for i = 1, #talentshelp do + s:drawColorString(self.font, talentshelp[i], self.iw / 2 + 5, h) + h = h + self.font:lineSkip() + end + + h = h + self.font:lineSkip() + if self.list[self.sel] then + lines = self.list[self.sel].object:getDesc():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 + + -- Talents + self:drawSelectionList(s, 2, 5, self.font_h, self.list, self.sel, "name") +end diff --git a/game/engine/interface/ActorInventory.lua b/game/engine/interface/ActorInventory.lua index 278272593b..42205ae03d 100644 --- a/game/engine/interface/ActorInventory.lua +++ b/game/engine/interface/ActorInventory.lua @@ -2,6 +2,7 @@ require "engine.class" local Map = require "engine.Map" local ShowInventory = require "engine.dialogs.ShowInventory" local ShowEquipment = require "engine.dialogs.ShowEquipment" +local ShowPickupFloor = require "engine.dialogs.ShowPickupFloor" --- Handles actors stats module(..., package.seeall, class.make) @@ -69,11 +70,10 @@ end --- Picks an object from the floor function _M:pickupFloor(i, vocal) - i = i - 1 + Map.OBJECT - local o = game.level.map(self.x, self.y, i) + local o = game.level.map:getObject(self.x, self.y, i) if o then if self:addObject(self.INVEN_INVEN, o) then - game.level.map:remove(self.x, self.y, i) + game.level.map:removeObject(self.x, self.y, i) if vocal then game.logSeen(self, "%s picks up: %s.", self.name:capitalize(), o:getName()) end else @@ -130,6 +130,14 @@ function _M:showEquipment(title, filter, action) game:registerDialog(d) end +--- Show floor pickup dialog +-- @param filter nil or a function that filters the objects to list +-- @param action a function called when an object is selected +function _M:showPickupFloor(title, filter, action) + local d = ShowPickupFloor.new(title, self.x, self.y, filter, action) + game:registerDialog(d) +end + --- Wear/wield an item function _M:wearObject(o, replace, vocal) local inven = o:wornInven() diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index e43feffabb..6f748a3bef 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -125,6 +125,17 @@ function _M:die(src) end -- Do we get a blooooooody death ? if rng.percent(33) then self:bloodyDeath() end + + -- Drop stuff + for inven_id, inven in pairs(self.inven) do + for i, o in ipairs(inven) do + if not o.no_drop then + game.level.map:addObject(self.x, self.y, o) + end + end + end + self.inven = {} + return true end diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index fd21bafb4c..878887b39d 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -295,7 +295,14 @@ function _M:setupCommands() -- Pickup object _g = function() - self.player:pickupFloor(1, true) + -- If 2 or more objects, display a pickup dialog, otehrwise just picks up + if self.level.map:getObject(self.player.x, self.player.y, 2) then + self.player:showPickupFloor(nil, nil, function(o, item) + self.player:pickupFloor(item, true) + end) + else + self.player:pickupFloor(1, true) + end end, -- Show inventory diff --git a/game/modules/tome/data/zones/ancient_ruins/npcs.lua b/game/modules/tome/data/zones/ancient_ruins/npcs.lua index 1ed80a2a48..1815be1235 100644 --- a/game/modules/tome/data/zones/ancient_ruins/npcs.lua +++ b/game/modules/tome/data/zones/ancient_ruins/npcs.lua @@ -72,7 +72,8 @@ newEntity{ BODY = 1, HEAD = 1, HANDS = 1, FEET = 1, TOOL = 1, }, - equipment = resolvers.equip{ {type="weapon", subtype="longsword"}, {type="armor", subtype="massive"}, {type="armor", subtype="shield"}, }, + equipment = resolvers.equip{ {type="weapon", subtype="longsword"}, {type="armor", subtype="massive"}, {type="armor", subtype="shield"}, }, + drops = resolvers.drops{chance=100, nb=3, {ego_chance=100} }, stats = { str=14, dex=12, mag=8, con=13 }, talents = { }, diff --git a/game/modules/tome/resolvers.lua b/game/modules/tome/resolvers.lua index 1435156eab..dbeee886ab 100644 --- a/game/modules/tome/resolvers.lua +++ b/game/modules/tome/resolvers.lua @@ -11,6 +11,32 @@ function resolvers.calc.equip(t, e) if o then print("Zone made us an equipment according to filter!", o:getName()) e:wearObject(o, true, false) + + -- Do not drop it unless it is an ego or better + if not o.egoed and not o.unique then o.no_drop = true end + end + end + -- Delete the origin field + return nil +end + +--- Resolves drops creation for an actor +function resolvers.drops(t) + return {__resolver="drops", t} +end +--- Actually resolve the drops creation +function resolvers.calc.drops(t, e) + t = t[1] + if not rng.percent(t.chance) then return nil end + + -- Iterate of object requests, try to create them and drops them + for i = 1, (t.nb or 1) do + local filter = t[rng.range(1, #t)] + print("Drops resolver", filter.type, filter.subtype) + local o = game.zone:makeEntity(game.level, "object", filter) + if o then + print("Zone made us an drop according to filter!", o:getName()) + e:addObject(e.INVEN_INVEN, o) end end -- Delete the origin field -- GitLab