diff --git a/config.lua b/config.lua index 3a320d3..e725f93 100644 --- a/config.lua +++ b/config.lua @@ -6,6 +6,9 @@ yl_speak_up.talk_after_spawn = true yl_speak_up.path = "yl_speak_up_dialogs" +-- What shall we call the folder all the inventories of the NPC will reside in? +yl_speak_up.inventory_path = "yl_speak_up_inventories" + -- Texts yl_speak_up.message_button_option_exit = "Farewell!" diff --git a/functions.lua b/functions.lua index d662eb1..197ca18 100644 --- a/functions.lua +++ b/functions.lua @@ -1457,6 +1457,14 @@ local function get_fs_talkdialog(player, n_id, d_id) "a conversation is started.]") end + -- access the inventory of the NPC + h = h + 1 + table.insert(formspec, "button[0.5," .. h .. ";53.8,0.9;show_inventory;]") + table.insert(formspec, "tooltip[show_inventory;Access and manage the inventory of the NPC. ".. + "This is used for adding trade items, getting collected payments and managing ".. + "quest items.]") + table.insert(formspec, "label[0.7,"..(h+0.45)..";I am your owner. Show me your inventory!]") + -- chat option: Mute/Unmute NPC h = h + 1 local obj = yl_speak_up.speak_to[pname].obj @@ -1717,10 +1725,26 @@ minetest.register_on_player_receive_fields( function(player, formname, fields) elseif formname == "yl_speak_up:fashion" then yl_speak_up.input_fashion(player, formname, fields) return true + elseif formname == "yl_speak_up:inventory" then + yl_speak_up.input_inventory(player, formname, fields) + return true end end) +-- the player has closed the inventory formspec of the NPC - save it +yl_speak_up.input_inventory = function(player, formname, fields) + local pname = player:get_player_name() + local d_id = yl_speak_up.speak_to[pname].d_id + local n_id = yl_speak_up.speak_to[pname].n_id + -- after closing the inventory formspec: + -- ..save the (very probably) modified inventory + yl_speak_up.save_npc_inventory(n_id) + -- ..and go back to the normal talk formspec + minetest.show_formspec(pname, "yl_speak_up:talk", get_fs_talkdialog(player, n_id, d_id)) +end + + yl_speak_up.input_optiondialog = function(player, formname, fields) if formname ~= "yl_speak_up:optiondialog" then return @@ -2742,6 +2766,14 @@ yl_speak_up.input_talk = function(player, formname, fields) return end + -- the player wants to access the inventory of the NPC + if(edit_mode and fields.show_inventory) then + local dialog = yl_speak_up.speak_to[pname].dialog + -- the inventory is just an inventory with a back button; come back to this dialog here + minetest.show_formspec(pname, "yl_speak_up:inventory", yl_speak_up.get_fs_inventory(player, n_id, dialog.n_npc)) + return + end + -- change skin, cape and wielded items if(edit_mode and fields.edit_skin) then local dialog = yl_speak_up.speak_to[pname].dialog @@ -3147,6 +3179,9 @@ function yl_speak_up.after_activate(self, staticdata, def, dtime) end yl_speak_up.update_nametag(self) + + -- create a detached inventory for the npc and load its inventory + yl_speak_up.load_npc_inventory("n_"..tostring(self.yl_speak_up.id)) end function yl_speak_up.talk(self, clicker) diff --git a/init.lua b/init.lua index 01de574..815eee0 100644 --- a/init.lua +++ b/init.lua @@ -17,12 +17,16 @@ yl_speak_up.speak_to = {} dofile(modpath .. "config.lua") dofile(modpath .. "privs.lua") +-- inventory management, trading and handling of quest items: +dofile(modpath .. "inventory.lua") dofile(modpath .. "functions.lua") dofile(modpath .. "tools.lua") dofile(modpath .. "mobs.lua") --dofile(modpath .. "debug.lua") minetest.mkdir(yl_speak_up.worldpath..yl_speak_up.path) +minetest.mkdir(yl_speak_up.worldpath..yl_speak_up.inventory_path) + yl_speak_up.mob_table = yl_speak_up.init_mob_table() or {} -minetest.log("action","[MOD] yl_speak_up loaded") \ No newline at end of file +minetest.log("action","[MOD] yl_speak_up loaded") diff --git a/inventory.lua b/inventory.lua new file mode 100644 index 0000000..0e0ad5d --- /dev/null +++ b/inventory.lua @@ -0,0 +1,126 @@ +-- inventory management, trading and handling of quest items for talking to NPCs + +-- cache the inventory of NPCs for easier access +yl_speak_up.npc_inventory = {} + +-- where are they stored on the disk? +yl_speak_up.get_inventory_save_path = function(n_id) + return yl_speak_up.worldpath .. yl_speak_up.inventory_path .. DIR_DELIM .. "inv_" .. n_id .. ".json" +end + + +-- access the inventory of the NPC (only possible for players with the right priv) +yl_speak_up.get_fs_inventory = function(player, n_id, npc_name) + return "size[12,11]" .. + "label[2,-0.2;Inventory of "..minetest.formspec_escape(npc_name).. + " (ID: "..tostring(n_id).."):]".. + "list[detached:yl_npc_"..tostring(n_id)..";npc_main;0,0.3;12,6;]" .. + "list[current_player;main;2,6.85;8,1;]" .. + "list[current_player;main;2,8.08;8,3;8]" .. + "listring[detached:yl_npc_"..tostring(n_id)..";npc_main]" .. + "listring[current_player;main]" .. + "button[10.0,10.2;2,0.9;back_from_inventory;Back]" +end + + +-- save the inventory of the NPC with the id n_id +yl_speak_up.save_npc_inventory = function( n_id ) + -- only save something if we actually can + if(not(n_id) or not(yl_speak_up.npc_inventory[ n_id ])) then + return + end + -- convert the inventory data to something we can actually store + local inv = yl_speak_up.npc_inventory[ n_id ] + local inv_as_table = {} + for i=1, inv:get_size("npc_main") do + local stack = inv:get_stack("npc_main", i) + -- only save those slots that are not empty + if(not(stack:is_empty())) then + inv_as_table[ i ] = stack:to_table() + end + end + -- convert the table into json + local json = minetest.write_json( inv_as_table ) + -- get a file name for storing the data + local file_name = yl_speak_up.get_inventory_save_path(n_id) + -- actually store it on disk + minetest.safe_file_write(file_name, json) +end + + +-- create and load the detached inventory in yl_speak_up.after_activate; +-- direct access to this inventory is only possible for players with the right privs +yl_speak_up.load_npc_inventory = function(n_id) + if(not(n_id)) then + return + end + -- the inventory is already loaded + if( yl_speak_up.npc_inventory[ n_id ]) then + return + end + -- create the detached inventory (it is empty for now) + local npc_inv = minetest.create_detached_inventory("yl_npc_"..tostring(n_id), { + allow_move = function(inv, from_list, from_index, to_list, to_index, count, player) + if(not(yl_speak_up.may_edit_npc(player, n_id))) then + return 0 + end + return count + end, + -- Called when a player wants to move items inside the inventory. + -- Return value: number of items allowed to move. + + allow_put = function(inv, listname, index, stack, player) + if(not(yl_speak_up.may_edit_npc(player, n_id))) then + return 0 + end + return stack:get_count() + end, + -- Called when a player wants to put something into the inventory. + -- Return value: number of items allowed to put. + -- Return value -1: Allow and don't modify item count in inventory. + + allow_take = function(inv, listname, index, stack, player) + if(not(yl_speak_up.may_edit_npc(player, n_id))) then + return 0 + end + return stack:get_count() + end + -- Called when a player wants to take something out of the inventory. + -- Return value: number of items allowed to take. + -- Return value -1: Allow and don't modify item count in inventory. + +-- on_move = function(inv, from_list, from_index, to_list, to_index, count, player) end, +-- on_put = function(inv, listname, index, stack, player) end, +-- on_take = function(inv, listname, index, stack, player) end, + -- Called after the actual action has happened, according to what was + -- allowed. + -- No return value. + }) + -- the NPC needs enough room for trade items, payment and questitems + npc_inv:set_size("npc_main", 6*12) + + -- cache a pointer to this inventory for easier access + yl_speak_up.npc_inventory[ n_id ] = npc_inv + + -- find out where the inventory of the NPC is stored + local file_name = yl_speak_up.get_inventory_save_path(n_id) + + -- load the data from the file + local file, err = io.open(file_name, "r") + if err then + return + end + io.input(file) + local text = io.read() + local inv_as_table = minetest.parse_json(text) + io.close(file) + + if(type(inv_as_table) ~= "table") then + return + end + + -- restore the inventory + for i=1, npc_inv:get_size("npc_main") do + npc_inv:set_stack("npc_main", i, ItemStack( inv_as_table[ i ])) + end +end