Inventory and Equipment Dialogs
This section assumes that objects and inventory has already been enabled by following the instructions in the objects guide.
Picking up and dropping items
To start, lets add the ability to actually pickup and drop items.
First, in your Game.lua file, find the setupCommands() method. Inside this method add the following entry to the self.key:addBinds command:
PICKUP_FLOOR = function()
if self.player.no_inventory_access then return end
self.player:playerPickup()
end,
DROP_FLOOR = function()
if self.player.no_inventory_access then return end
self.player:playerDrop()
end,
This allows the pickup and drop commands to be mapped, which causes the player:playerPickup() or player:playerDrop() methods to execute. Now lets add these methods to the Player.lua file:
function _M:playerPickup()
-- If 2 or more objects, display a pickup dialog, otherwise just picks up
if game.level.map:getObject(self.x, self.y, 2) then
local d d = self:showPickupFloor("Pickup", nil, function(o, item)
self:pickupFloor(item, true)
self.changed = true
d:used()
end)
else
self:pickupFloor(1, true)
self:sortInven()
self:useEnergy()
self.changed = true
end
end
function _M:playerDrop()
local inven = self:getInven(self.INVEN_INVEN)
local d d = self:showInventory("Drop object", inven, nil, function(o, item)
self:dropFloor(inven, item, true, true)
self:sortInven(inven)
self:useEnergy()
self.changed = true
return true
end)end
Now you can play and pick up and drop your items!
Inventory and equipment Screen
Now that you can pick up and drop items, you need to be able to obtain an inventory list and equip items.
First, as above, add the following to the key mappings in Game.lua:
SHOW_INVENTORY = function()
if self.player.no_inventory_access then return end
local d
d = self.player:showEquipInven("Inventory", nil, function(o, inven, item, button, event)
if not o then return end
local ud = require("mod.dialogs.UseItemDialog").new(event == "button", self.player, o, item, inven, function(_, _, _, stop)
d:generate()
d:generateList()
if stop then self:unregisterDialog(d) end
end)
self:registerDialog(ud)
end)
end,
Once done, you can try run the game and enjoy your new inventory listing. You may however notice that the game will crash if you try to actually use or equip anything in your inventory. This is because we have not yet defined the UseItemDialog.
In your module's Dialogs directory, create a new file file UseItemDialog.lua and paste the following:
require "engine.class"
require "engine.ui.Dialog"
local List = require "engine.ui.List"
local Savefile = require "engine.Savefile"
local Map = require "engine.Map"
module(..., package.seeall, class.inherit(engine.ui.Dialog))
function _M:init(center_mouse, actor, object, item, inven, onuse)
self.actor = actor
self.object = object
self.inven = inven
self.item = item
self.onuse = onuse
self:generateList()
local name = object:getName()
local w = self.font_bold:size(name)
engine.ui.Dialog.init(self, name, 1, 1)
local list = List.new{width=math.max(w, self.max) + 10, nb_items=#self.list, list=self.list, fct=function(item) self:use(item) end}
self:loadUI{
{left=0, top=0, ui=list},
}
self:setupUI(true, true, function(w, h)
if center_mouse then
local mx, my = core.mouse.get()
self.force_x = mx - w / 2
self.force_y = my - (self.h - self.ih + list.fh / 3)
end
end)
self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }end
function _M:use(item)
if not item then return end
game:unregisterDialog(self)
local act = item.action
--if act == "use" then
--self.actor:playerUseItem(self.object, self.item, self.inven, self.onuse)
--self.onuse(self.inven, self.item, self.object, true)
--else
if act == "drop" then
self.actor:doDrop(self.inven, self.item, function() self.onuse(self.inven, self.item, self.object, false) end)
elseif act == "wear" then
self.actor:doWear(self.inven, self.item, self.object)
self.onuse(self.inven, self.item, self.object, false)
elseif act == "takeoff" then
self.actor:doTakeoff(self.inven, self.item, self.object)
self.onuse(self.inven, self.item, self.object, false)
endend
function _M:generateList()
local list = {}
--if self.object:canUseObject() then list[#list+1] = {name="Use", action="use"} end
if self.inven == self.actor.INVEN_INVEN and self.object:wornInven() and self.actor:getInven(self.object:wornInven()) then list[#list+1] = {name="Wield/Wear", action="wear"} end
if self.inven ~= self.actor.INVEN_INVEN and self.object:wornInven() then list[#list+1] = {name="Take off", action="takeoff"} end
if self.inven == self.actor.INVEN_INVEN then list[#list+1] = {name="Drop", action="drop"} end
self.max = 0
self.maxh = 0
for i, v in ipairs(list) do
local w, h = self.font:size(v.name)
self.max = math.max(self.max, w)
self.maxh = self.maxh + self.font_h
end
self.list = listend
In your Player.lua class file paste the following two functions:
function _M:doDrop(inven, item, on_done, nb)
if self.no_inventory_access then return end
if nb == nil or nb >= self:getInven(inven)[item]:getNumber() then
self:dropFloor(inven, item, true, true)
else
for i = 1, nb do self:dropFloor(inven, item, true) end
end
self:sortInven(inven)
self:useEnergy()
self.changed = true
if on_done then on_done() end
end
function _M:doWear(inven, item, o)
self:removeObject(inven, item, true)
local ro = self:wearObject(o, true, true)
if ro then
if type(ro) == "table" then self:addObject(inven, ro) end
elseif not ro then
self:addObject(inven, o)
end
self:sortInven()
self:useEnergy()
self.changed = trueend
function _M:doTakeoff(inven, item, o)
if self:takeoffObject(inven, item) then
self:addObject(self.INVEN_INVEN, o)
end
self:sortInven()
self:useEnergy()
self.changed = trueend
You should now be able to drop items from within the inventory screen as well as equip and takeoff items.
Consumable and activatable items
Right now you can only "wear", "takeoff", "pickup" and "drop" items. This section deals with allowing objects to be "used".
First, return to the UseItemDialog.lua file in the dialogs directory and uncomment the commented lines in the use and generateList methods.
Next you need to add a new method to the object class to allow the code to check whether an object can be used. If you have not already, this will involve actually creating an objects class. Paste the following into the Object.lua class file:
require "engine.class"
require "engine.Object"
require "engine.interface.ObjectActivable"
local Stats = require("engine.interface.ActorStats")
local Talents = require("engine.interface.ActorTalents")
local DamageType = require("engine.DamageType")
module(..., package.seeall, class.inherit(
engine.Object,
engine.interface.ObjectActivable,
engine.interface.ActorTalents))
function _M:init(t, no_default)
t.encumber = t.encumber or 0
engine.Object.init(self, t, no_default)
engine.interface.ObjectActivable.init(self, t)
engine.interface.ActorTalents.init(self, t)end
function _M:canAct()
if self.power_regen or self.use_talent then return true end
return falseend
function _M:act()
self:regenPower()
self:cooldownTalents()
self:useEnergy()end
function _M:use(who, typ, inven, item)
inven = who:getInven(inven)
if self:wornInven() and not self.wielded and not self.use_no_wear then
game.logPlayer(who, "You must wear this object to use it!")
return
end
local types = {}
if self:canUseObject() then types[#types+1] = "use" end
if not typ and #types == 1 then typ = types[1] end
if typ == "use" then
local ret = {self:useObject(who, inven, item)}
if ret[1] then
if self.use_sound then game:playSoundNear(who, self.use_sound) end
who:useEnergy(game.energy_to_act * (inven.use_speed or 1))
end
return unpack(ret)
endend
You will also need to modify you Game.lua class: In the loaded function modify the Zone:setup call to also include your new Object class:
Zone:setup{npc_class="mod.class.NPC", grid_class="mod.class.Grid", object_class="mod.class.Object"}
Also add the following function to the Player.lua class:
function _M:playerUseItem(object, item, inven)
local use_fct = function(o, inven, item)
if not o then return end
local co = coroutine.create(function()
self.changed = true
local ret = o:use(self, nil, inven, item) or {}
if not ret.used then return end
if ret.destroy then
if o.multicharge and o.multicharge > 1 then
o.multicharge = o.multicharge - 1
else
local _, del = self:removeObject(self:getInven(inven), item)
if del then
game.log("You have no more %s.", o:getName{no_count=true, do_color=true})
else
game.log("You have %s.", o:getName{do_color=true})
end
self:sortInven(self:getInven(inven))
end
end
end)
local ok, ret = coroutine.resume(co)
if not ok and ret then print(debug.traceback(co)) error(ret) end
return true
end
if object and item then return use_fct(object, inven, item) end
local titleupdator = self:getEncumberTitleUpdator("Use object")
self:showEquipInven(titleupdator(),
function(o)
return o:canUseObject()
end,
use_fct
)
end
Congratulations, you now have usable items.
Now all you need to do is define your items usable.
For consumable objects like potions:
use_simple = { name = "power name",
use = function(self,who)
<Code for power use here>
return {used = true, destroy = true}
end
},
For an object like a wand with limited charges:
multicharge = ,
use_simple = { name = "power name",
use = function(self,who)
<Code for power use here>
return {used = true, destroy = true}
end
},
For a magical object with regenerating power:
max_power = <max power>,
power_regen = <power regained per turn>,
use_power = {name = "power name", power = <power use per charge>,
use = function(self, who)
<Code for power use here>
return true
end
},
For a magical object that activates a talent on use:
max_power = <max power>,
power_regen = <power regained per turn>,
use_talent = {id = Talents.T_SOMETALENT, level = <level of talent>, power = <power use per charge> },
