From ff70a962ae0459a8f3c609137bfe0962af00b558 Mon Sep 17 00:00:00 2001 From: alek13 Date: Tue, 3 Oct 2023 22:24:04 +0300 Subject: [PATCH] Mobs: Traders: Return forgotten money to player or drop int world. Closes #1156 --- .../lord_traders/src/traders/trader.lua | 11 ++- .../lord_traders/src/traders/trader/Form.lua | 77 ++++++++++++++++++- .../src/traders/trader/Inventory.lua | 30 +++++++- util/mt-ide-helper/minetest_types.lua | 6 ++ 4 files changed, 117 insertions(+), 7 deletions(-) diff --git a/mods/lord/Entities/lord_traders/src/traders/trader.lua b/mods/lord/Entities/lord_traders/src/traders/trader.lua index e55a821a4..0dfec09f5 100644 --- a/mods/lord/Entities/lord_traders/src/traders/trader.lua +++ b/mods/lord/Entities/lord_traders/src/traders/trader.lua @@ -60,9 +60,6 @@ local common_trader_definition = { attack = "default_punch2", -- except elves (mobs_slash_attack) } } - ------------------------------------------------------------------------------------------------------------------------- - --- @param entity LuaEntity --- @param clicker Player --- @param race string @@ -93,6 +90,14 @@ local function on_rightclick(entity, clicker, race) end +------------------------------------------------------------------------------------------------------------------------ + +Form.on_close(function(form) + Inventory.get_by_id(form.inventory_id):return_forgotten() +end) + +------------------------------------------------------------------------------------------------------------------------ + --- @param name string --- @param definition table local function register_trader(name, definition) diff --git a/mods/lord/Entities/lord_traders/src/traders/trader/Form.lua b/mods/lord/Entities/lord_traders/src/traders/trader/Form.lua index 34ca8251a..f6662fd59 100644 --- a/mods/lord/Entities/lord_traders/src/traders/trader/Form.lua +++ b/mods/lord/Entities/lord_traders/src/traders/trader/Form.lua @@ -1,19 +1,33 @@ local S = minetest.get_translator("lord_traders") +--- @class traders.trader.Form.Event +local Event = { + CLOSE = "close", +} + --- --- @class traders.trader.Form --- local Form = { --- @const --- @type string - NAME = "trade", + NAME = "lord_traders:trade", + --- @static + --- @private + --- @type table + opened_for = {}, + --- @static + --- @type table + event_callback = { + ["on_"..Event.CLOSE] = {} + }, --- @type string - player_name = nil, + player_name = nil, --- @type string inventory_id = nil, --- @type string - trader_name = nil, + trader_name = nil, } --- Constructor @@ -32,11 +46,40 @@ function Form:new(player, inventory_id, trader_name) return setmetatable(self, { __index = class }) end +--- @public +--- @static +--- @param player Player +function Form.get_opened_for(player) + return Form.opened_for[player:get_player_name()] +end + +--- @private +--- @param event string +function Form:trigger(event) + for _, callback in pairs(self.event_callback["on_"..event]) do + callback(self) + end +end + +--- @public +--- @static +--- @param callback fun(form:traders.trader.Form) +function Form.on_close(callback) + table.insert(Form.event_callback["on_" .. Event.CLOSE], callback) +end + --- @public function Form:open() + self.opened_for[self.player_name] = self; minetest.show_formspec(self.player_name, self.NAME, self:get_spec()) end +--- @public +function Form:close() + self.opened_for[self.player_name] = nil + self:trigger(Event.CLOSE) +end + --- @private --- @return string function Form:get_spec() @@ -62,5 +105,33 @@ function Form:get_spec() "listring[detached:" .. self.inventory_id .. ";goods]" end +--- @public +--- @static +--- @param player Player +--- @param form_name string +--- @param fields table +function Form.handler(player, form_name, fields) + if form_name ~= Form.NAME then + return + end + + local form = Form.get_opened_for(player) + if not form then return end + + if fields.quit then + form:close() + end +end + +minetest.register_on_player_receive_fields(Form.handler) + +--- @param player Player +minetest.register_on_leaveplayer(function(player, timed_out) + local form = Form.get_opened_for(player); + if form then + form:close() + end +end) + return Form diff --git a/mods/lord/Entities/lord_traders/src/traders/trader/Inventory.lua b/mods/lord/Entities/lord_traders/src/traders/trader/Inventory.lua index 88e2d1b0d..62cf4fbf2 100644 --- a/mods/lord/Entities/lord_traders/src/traders/trader/Inventory.lua +++ b/mods/lord/Entities/lord_traders/src/traders/trader/Inventory.lua @@ -254,12 +254,21 @@ function Inventory:new(player, entity, goods_config, same_race) end --- @static +--- @private --- @param inv InvRef --- @return traders.trader.Inventory|nil function Inventory.get_by_invRef(inv) return inventories_by_id[inv:get_location().name] end +--- @static +--- @public +--- @param id string +--- @return traders.trader.Inventory|nil +function Inventory.get_by_id(id) + return inventories_by_id[id] +end + --- @private --- @param inventory_id string --- @return InvRef @@ -281,7 +290,7 @@ function Inventory:get_or_create_detached_inventory() self.detached_inv_id = self.player_name.."_trader_".. self.entity_id:gsub(":", "_") inventories_by_id[self.detached_inv_id] = self - local trader_inventory = minetest.get_inventory({ type ="detached", name = self.detached_inv_id }) + local trader_inventory = minetest.get_inventory({ type = "detached", name = self.detached_inv_id }) if trader_inventory ~= nil then return trader_inventory end @@ -299,4 +308,23 @@ function Inventory:get_id() return self.detached_inv_id end +--- Returns forgotten money into player's inventory or drops into world. +--- @public +function Inventory:return_forgotten() + local player_inventory = minetest.get_inventory({ type = "player", name = self.player_name }) + local trader_inventory = minetest.get_inventory({ type = "detached", name = self.detached_inv_id }) + + if trader_inventory:is_empty("payment") then return end + + local stack = trader_inventory:get_stack("payment", 1) + trader_inventory:set_stack("payment", 1, nil) + trader_inventory:set_stack("takeaway", 1, nil) + if player_inventory:room_for_item("main", stack) then + player_inventory:add_item("main", stack) + else + local player = minetest.get_player_by_name(self.player_name) + minetest.item_drop(stack, player, player:get_pos()) + end +end + return Inventory diff --git a/util/mt-ide-helper/minetest_types.lua b/util/mt-ide-helper/minetest_types.lua index c8b8edfd8..09b3733f1 100644 --- a/util/mt-ide-helper/minetest_types.lua +++ b/util/mt-ide-helper/minetest_types.lua @@ -992,6 +992,8 @@ function minetest.add_item(pos, item) end --- Get an `ObjectRef` to a player --- --- [View in lua_api.txt](https://github.com/minetest/minetest/blob/5.4.1/doc/lua_api.txt#L4913-L4913) +--- @param name string +--- @return Player function minetest.get_player_by_name(name) end --- Returns a list of --- ObjectRefs. @@ -1634,6 +1636,10 @@ function minetest.item_place(itemstack, placer, pointed_thing, param2) end --- * returns the leftover itemstack --- --- [View in lua_api.txt](https://github.com/minetest/minetest/blob/5.4.1/doc/lua_api.txt#L5376-L5378) +--- @param itemstack ItemStack +--- @param dropper Player|ObjectRef +--- @param pos Position +--- @return ItemStack function minetest.item_drop(itemstack, dropper, pos) end --- * Returns `function(itemstack, user, pointed_thing)` as a --- function wrapper for `minetest.do_item_eat`.