mirror of
				https://gitea.your-land.de/Sokomine/yl_speak_up.git
				synced 2025-11-03 22:03:08 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			240 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
-- 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
 | 
						|
 | 
						|
 | 
						|
-- check if stack contains any metadata; return true if it does
 | 
						|
-- (trade_simple does not allow used items or those with metadata)
 | 
						|
yl_speak_up.check_stack_has_meta = function(player, stack)
 | 
						|
	local meta = stack:get_meta()
 | 
						|
	for k, v in pairs(meta:to_table()) do
 | 
						|
		-- the name "fields" is allowed - as long as it is empty
 | 
						|
		if(k ~= "fields") then
 | 
						|
			return true
 | 
						|
		end
 | 
						|
		for k2, v2 in pairs(v) do
 | 
						|
			if(k2) then
 | 
						|
				return true
 | 
						|
			end
 | 
						|
		end
 | 
						|
	end
 | 
						|
	return false
 | 
						|
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)
 | 
						|
	-- show inventory again?
 | 
						|
	if(fields.back_from_error_msg) then
 | 
						|
		yl_speak_up.show_fs(player, "inventory")
 | 
						|
		return
 | 
						|
	end
 | 
						|
	-- show the trade list?
 | 
						|
	if(fields.inventory_show_tradelist) then
 | 
						|
		yl_speak_up.show_fs(player, "trade_list")
 | 
						|
		return
 | 
						|
	end
 | 
						|
	-- ..and go back to the normal talk formspec
 | 
						|
	yl_speak_up.show_fs(player, "talk", {n_id = n_id, d_id = d_id})
 | 
						|
end
 | 
						|
 | 
						|
 | 
						|
-- access the inventory of the NPC (only possible for players with the right priv)
 | 
						|
yl_speak_up.get_fs_inventory = function(player)
 | 
						|
	if(not(player)) then
 | 
						|
		return ""
 | 
						|
	end
 | 
						|
	local pname = player:get_player_name()
 | 
						|
	-- which NPC is the player talking to?
 | 
						|
	local n_id = yl_speak_up.speak_to[pname].n_id
 | 
						|
	local dialog = yl_speak_up.speak_to[pname].dialog
 | 
						|
	-- do we have all the necessary data?
 | 
						|
	if(not(n_id) or not(dialog.n_npc)) then
 | 
						|
		return "size[6,2]"..
 | 
						|
			"label[0.2,0.5;Ups! This NPC lacks ID or name.]"..
 | 
						|
		                "button_exit[2,1.5;1,0.9;exit;Exit]"
 | 
						|
	end
 | 
						|
 | 
						|
	-- only players which can edit this npc can see its inventory
 | 
						|
	if(not(yl_speak_up.may_edit_npc(player, n_id))) then
 | 
						|
		return "size[6,2]"..
 | 
						|
			"label[0.2,0.5;Sorry. You lack the privileges.]"..
 | 
						|
		                "button_exit[2,1.5;1,0.9;exit;Exit]"
 | 
						|
	end
 | 
						|
 | 
						|
	return "size[12,11]" ..
 | 
						|
		"label[2,-0.2;Inventory of "..minetest.formspec_escape(dialog.n_npc)..
 | 
						|
			" (ID: "..tostring(n_id).."):]"..
 | 
						|
		"list[detached:yl_speak_up_npc_"..tostring(n_id)..";npc_main;0,0.3;12,6;]" ..
 | 
						|
		"list[current_player;main;2,7.05;8,1;]" ..
 | 
						|
		"list[current_player;main;2,8.28;8,3;8]" ..
 | 
						|
		"listring[detached:yl_speak_up_npc_"..tostring(n_id)..";npc_main]" ..
 | 
						|
		"listring[current_player;main]" ..
 | 
						|
		"button[3.5,6.35;5,0.6;inventory_show_tradelist;Show trade list trades (player view)]"..
 | 
						|
		"button[10.0,10.4;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
 | 
						|
 | 
						|
 | 
						|
-- helper function for yl_speak_up.load_npc_inventory and
 | 
						|
-- minetest.register_on_joinplayer
 | 
						|
yl_speak_up.inventory_allow_item = function(player, stack, input_to)
 | 
						|
	if(not(player) or not(stack) or not(input_to)) then
 | 
						|
		return 0
 | 
						|
	end
 | 
						|
	local pname = player:get_player_name()
 | 
						|
	local n_id = yl_speak_up.speak_to[pname].n_id
 | 
						|
	if(not(n_id) or not(yl_speak_up.may_edit_npc(player, n_id))) then
 | 
						|
		return 0
 | 
						|
	end
 | 
						|
	-- are we editing an action of the type trade?
 | 
						|
	if(   yl_speak_up.speak_to[pname][ "tmp_action" ]
 | 
						|
	  and yl_speak_up.speak_to[pname][ "tmp_action" ].what == 3) then
 | 
						|
		input_to = "yl_speak_up:edit_actions"
 | 
						|
	end
 | 
						|
 | 
						|
	local error_msg = nil
 | 
						|
	if(stack:get_wear() > 0) then
 | 
						|
		error_msg = "Your NPC accepts only undammaged items.\n"..
 | 
						|
			    "Trading dammaged items would be unfair."
 | 
						|
	-- items with metadata cannot be traded
 | 
						|
	elseif(yl_speak_up.check_stack_has_meta(player, stack)) then
 | 
						|
		error_msg = "Your NPC cannot sell items that contain\n"..
 | 
						|
			    "additional (meta-) data."
 | 
						|
	end
 | 
						|
	if(error_msg) then
 | 
						|
		yl_speak_up.show_fs(player, "msg", {
 | 
						|
			input_to = input_to,
 | 
						|
			formspec = "size[6,2]"..
 | 
						|
				"label[0.2,-0.2;"..tostring(error_msg).."]"..
 | 
						|
				"button[2,1.5;1,0.9;back_from_error_msg;"..
 | 
						|
					"OK]"})
 | 
						|
		return 0
 | 
						|
	end
 | 
						|
	return stack:get_count()
 | 
						|
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
 | 
						|
-- (this is an inventory for the *NPC*, which is stored to disk sometimes)
 | 
						|
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_speak_up_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)
 | 
						|
			-- check if player can edit NPC, item is undammaged and contains no metadata
 | 
						|
			return yl_speak_up.inventory_allow_item(player, stack, "yl_speak_up:inventory")
 | 
						|
		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.
 | 
						|
 | 
						|
		-- log inventory changes (same way as modifications to chest inventories)
 | 
						|
	        on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
 | 
						|
			minetest.log("action", "(yl_speak_up) "..player:get_player_name() ..
 | 
						|
				" moves stuff in inventory of NPC " .. tostring(n_id))
 | 
						|
 | 
						|
		end,
 | 
						|
	        on_put = function(inv, listname, index, stack, player)
 | 
						|
			minetest.log("action", "(yl_speak_up) "..player:get_player_name() ..
 | 
						|
				" moves " .. stack:get_name() ..
 | 
						|
				" to inventory of NPC " .. tostring(n_id))
 | 
						|
 | 
						|
		end,
 | 
						|
	        on_take = function(inv, listname, index, stack, player)
 | 
						|
			minetest.log("action", "(yl_speak_up) "..player:get_player_name() ..
 | 
						|
				" takes " .. stack:get_name() ..
 | 
						|
				" from inventory of NPC " .. tostring(n_id))
 | 
						|
		end,
 | 
						|
	})
 | 
						|
	-- 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
 |