DEMI-PROJECT-PACKAGE {"files":[{"hash":"sha256:c99ea5ffd66f034b3c6e28a3dcc2b5c6382b93421dab52e26d453134c575dd42","path":"README.md","size":156},{"hash":"sha256:0a0c94933d468e9c7220157c785d3c61daa00d291337cf23eca22fe8f8a7ed17","path":"scripts/demi/gameplay/inventory.lua","size":1701},{"hash":"sha256:7aad69aee3dd94704cb57c45a8e361a659941b52602af40d8487a005aa5336bc","path":"tests/inventory_test.lua","size":663}],"format_version":1,"manifest":{"dependencies":{"demi.gameplay.core":"^1.0.0"},"engine":"^0.1.0","exported_events":["inventory_changed","equipment_changed"],"files":["README.md","scripts/demi/gameplay/inventory.lua","tests/inventory_test.lua"],"format_version":1,"name":"demi.gameplay.inventory","public_modules":["demi.gameplay.inventory"],"version":"1.0.0"},"package_type":"DemiProjectPackage"}# demi.gameplay.inventory Serializable stack and equipment state. Item definitions and gameplay effects are supplied by the game as validated data assets. local Inventory = {} Inventory.__index = Inventory function Inventory.new(events, capacity) return setmetatable({ events = assert(events), capacity = capacity or 20, stacks = {}, equipment = {} }, Inventory) end function Inventory:add(item, count, maximum) count, maximum = count or 1, maximum or math.huge if count <= 0 then return 0 end local current = self.stacks[item] or 0 local added = math.min(count, maximum - current) if current == 0 and added > 0 then local unique = 0; for _ in pairs(self.stacks) do unique = unique + 1 end if unique >= self.capacity then return 0 end end if added > 0 then self.stacks[item] = current + added; self.events:emit("inventory_changed", { item = item, count = self.stacks[item] }) end return added end function Inventory:remove(item, count) local current = self.stacks[item] or 0; local removed = math.min(current, math.max(0, count or 1)) local left = current - removed; self.stacks[item] = left > 0 and left or nil if removed > 0 then self.events:emit("inventory_changed", { item = item, count = left }) end return removed end function Inventory:equip(slot, item) if item and not self.stacks[item] then return false end self.equipment[slot] = item; self.events:emit("equipment_changed", { slot = slot, item = item }); return true end function Inventory:save() return { stacks = self.stacks, equipment = self.equipment, capacity = self.capacity } end function Inventory:load(value) if type(value) ~= "table" or type(value.stacks) ~= "table" then return false end self.stacks, self.equipment, self.capacity = value.stacks, value.equipment or {}, value.capacity or self.capacity return true end return Inventory local Events = require("demi.gameplay.events") local Inventory = require("demi.gameplay.inventory") Test.case("capacity and stacks clamp", function() local inventory = Inventory.new(Events.new(), 1) Test.equal(inventory:add("coin", 8, 5), 5); Test.equal(inventory:add("key", 1), 0) Test.equal(inventory:remove("coin", 99), 5); Test.equal(inventory.stacks.coin, nil) end) Test.case("save load keeps equipment", function() local first = Inventory.new(Events.new()); first:add("sword"); first:equip("hand", "sword") local second = Inventory.new(Events.new()); Test.equal(second:load(first:save()), true) Test.equal(second.equipment.hand, "sword") end)