forked from your-land-mirror/yl_speak_up
276 lines
11 KiB
Lua
276 lines
11 KiB
Lua
-- spimple trading: one item(stack) for another item(stack)
|
|
|
|
-- fallback message if something went wrong
|
|
yl_speak_up.trade_fail_fs = "size[6,2]"..
|
|
"label[0.2,0.5;Ups! The trade is not possible.\nPlease notify an admin.]"..
|
|
"button_exit[2,1.5;1,0.9;exit;Exit]"
|
|
|
|
-- TODO: when closing the formspec: give the items in the pay slot back
|
|
|
|
-- can this trade be made? called in allow_take
|
|
yl_speak_up.can_trade_simple = function(player, count)
|
|
if(not(player)) then
|
|
return 0
|
|
end
|
|
local pname = player:get_player_name()
|
|
-- which trade are we talking about?
|
|
local trade = yl_speak_up.trade[pname]
|
|
-- do we have all the necessary data?
|
|
if(not(trade) or trade.trade_type ~= "trade_simple") then
|
|
return 0
|
|
end
|
|
|
|
-- the player tries to take *less* items than what his payment is;
|
|
-- avoid this confusion!
|
|
if(ItemStack(trade.npc_gives):get_count() ~= count) then
|
|
return 0
|
|
end
|
|
-- buy, sell and config items need to be placed somewhere
|
|
local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname})
|
|
-- the players' inventory
|
|
local player_inv = player:get_inventory()
|
|
-- the NPCs' inventory
|
|
local npc_inv = minetest.get_inventory({type="detached", name="yl_speak_up_npc_"..tostring(trade.n_id)})
|
|
|
|
-- is the payment in the payment slot?
|
|
if( not(trade_inv:contains_item("pay", trade.player_gives))
|
|
-- is the item to be sold in the buy slot?
|
|
or not(trade_inv:contains_item("buy", trade.npc_gives))
|
|
-- has the NPC room for the payment?
|
|
or not(npc_inv:room_for_item("npc_main", trade.player_gives))
|
|
-- has the player room for the sold item?
|
|
or not(player_inv:room_for_item("main", trade.npc_gives))) then
|
|
-- trade not possible
|
|
return 0
|
|
end
|
|
-- all ok; all items that are to be sold can be taken
|
|
return ItemStack(trade.npc_gives):get_count()
|
|
end
|
|
|
|
|
|
-- actually execute the trade
|
|
yl_speak_up.do_trade_simple = function(player, count)
|
|
-- can the trade be made?
|
|
if(not(yl_speak_up.can_trade_simple(player, count))) then
|
|
return
|
|
end
|
|
|
|
local pname = player:get_player_name()
|
|
-- which trade are we talking about?
|
|
local trade = yl_speak_up.trade[pname]
|
|
|
|
-- buy, sell and config items need to be placed somewhere
|
|
local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname})
|
|
-- the NPCs' inventory
|
|
local npc_inv = minetest.get_inventory({type="detached", name="yl_speak_up_npc_"..tostring(trade.n_id)})
|
|
|
|
-- the NPC sells these items right now, and the player is moving it to his inventory
|
|
npc_inv:remove_item("npc_main", trade.npc_gives)
|
|
|
|
-- move price items to the NPC
|
|
local stack = trade_inv:remove_item("pay", trade.player_gives)
|
|
npc_inv:add_item("npc_main", stack)
|
|
-- save the inventory of the npc so that the payment does not get lost
|
|
yl_speak_up.save_npc_inventory( trade.n_id )
|
|
|
|
-- store for statistics how many times the player has executed this trade
|
|
trade.trade_done = trade.trade_done + 1
|
|
end
|
|
|
|
|
|
-- simple trade: one item(stack) for another
|
|
-- handles configuration of new trades and showing the formspec for trades;
|
|
-- checks if payment and buying is possible
|
|
yl_speak_up.get_fs_trade_simple = function(player, player_gives, npc_gives)
|
|
if(not(player)) then
|
|
return yl_speak_up.trade_fail_fs
|
|
end
|
|
local pname = player:get_player_name()
|
|
-- which trade are we talking about?
|
|
local trade = yl_speak_up.trade[pname]
|
|
-- do we have all the necessary data?
|
|
if(not(trade) or trade.trade_type ~= "trade_simple") then
|
|
return yl_speak_up.trade_fail_fs
|
|
end
|
|
-- the common formspec, shared by actual trade and configuration
|
|
-- no listring here as that would make things more complicated
|
|
local formspec = "size[8.5,8]"..
|
|
"label[4.35,0.8;"..minetest.formspec_escape(trade.npc_name).." sells:]"..
|
|
"list[current_player;main;0.2,3.85;8,1;]"..
|
|
"list[current_player;main;0.2,5.08;8,3;8]"
|
|
|
|
-- configuration of a new trade happens here
|
|
if(not(trade.player_gives) or not(trade.npc_gives)) then
|
|
-- is this player allowed to edit the NPC and his trades? If not abort.
|
|
if(not(yl_speak_up.may_edit_npc(player, trade.n_id))) then
|
|
return formspec..
|
|
"label[2.0,1.8;Ups! Something went wrong.]"..
|
|
"button[6.2,1.6;2.0,0.9;abort_trade_simple;Back]"
|
|
end
|
|
return formspec..
|
|
-- show the second slot of the setup inventory in the detached player's inv
|
|
"list[detached:yl_speak_up_player_"..pname..";setup;2,1.5;1,1;]"..
|
|
-- show the second slot of said inventory
|
|
"list[detached:yl_speak_up_player_"..pname..";setup;5,1.5;1,1;1]"..
|
|
"label[2.5,0.0;Configure trade with "..minetest.formspec_escape(trade.npc_name)..":]"..
|
|
"label[1.5,0.8;The customer pays:]"..
|
|
"label[1.5,2.8;Put items in the two slots and click on \"Store trade\".]"..
|
|
"label[1.5,3.2;You will get your items back when storing the trade.]"..
|
|
"button[0.2,1.6;1.0,0.9;abort_trade_simple;Abort]"..
|
|
"button[6.2,1.6;2.0,0.9;store_trade_simple;Store trade]"..
|
|
"tooltip[store_trade_simple;Click here to store this as a new trade. Your "..
|
|
"items will be returned to you and the trade will be shown the way "..
|
|
"the customer can see it.]"..
|
|
"tooltip[abort_trade_simple;Abort setting up this new trade.]"
|
|
end
|
|
|
|
-- view for the customer when actually trading
|
|
|
|
-- buy, sell and config items need to be placed somewhere
|
|
local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname})
|
|
-- the players' inventory
|
|
local player_inv = player:get_inventory()
|
|
-- the NPCs' inventory
|
|
local npc_inv = minetest.get_inventory({type="detached", name="yl_speak_up_npc_"..tostring(trade.n_id)})
|
|
|
|
-- show edit button for the owner
|
|
if(yl_speak_up.may_edit_npc(player, trade.n_id)) then
|
|
formspec = formspec..
|
|
"button[0.2,1.6;0.8,0.9;edit_trade_simple;Edit]"..
|
|
"tooltip[edit_trade_simple;Edit this trade. You can do so only "..
|
|
"if you can edit the NPC as such (i.e. own it).]"
|
|
end
|
|
|
|
local trade_possible_msg = "Status of trade: Unknown."
|
|
-- has the NPC room for the payment?
|
|
if(not(npc_inv:room_for_item("npc_main", trade.player_gives))) then
|
|
trade_possible_msg = "Sorry. "..minetest.formspec_escape(trade.npc_name)..
|
|
" ran out of inventory space.\nThere is no room to store your payment!]"
|
|
-- can the player pay?
|
|
elseif(not(player_inv:contains_item("main", trade.player_gives))) then
|
|
-- both slots will remain empty
|
|
trade_possible_msg = "You cannot pay the price."
|
|
-- is the slot for the payment empty?
|
|
elseif not(trade_inv:is_empty("pay")) then
|
|
-- both slots will remain empty
|
|
-- (the slot may already contain the right things; we'll find that out later on)
|
|
trade_possible_msg = "Please insert the right payment manually."
|
|
-- all good so far; move the price stack to the pay slot
|
|
else
|
|
-- move price item to the price slot
|
|
local stack = player_inv:remove_item("main", trade.player_gives)
|
|
trade_inv:add_item("pay", stack)
|
|
end
|
|
|
|
-- make sure the sale slot is empty (we will fill it if the trade is possible)
|
|
trade_inv:set_stack("buy", 1, "")
|
|
-- after all this: does the payment slot contain the right things?
|
|
if(trade_inv:contains_item("pay", trade.player_gives)) then
|
|
trade_possible_msg = "Take the offered item(s) in order to buy them."
|
|
|
|
-- can the NPC provide his part?
|
|
if(not(npc_inv:contains_item("npc_main", trade.npc_gives))) then
|
|
trade_possible_msg = "Sorry. "..minetest.formspec_escape(trade.npc_name)..
|
|
" ran out of stock.\nPlease come back later."
|
|
else
|
|
-- put a *copy* of the item(stack) that is to be sold in the sale slot
|
|
trade_inv:add_item("buy", trade.npc_gives)
|
|
end
|
|
end
|
|
|
|
if(not(player_inv:room_for_item("main", trade.npc_gives))) then
|
|
-- the player has no room for the sold item; give a warning
|
|
trade_possible_msg = "Careful! You do not seem to have enough\n"..
|
|
"free inventory space to store your purchase.]"
|
|
end
|
|
|
|
return formspec..
|
|
"label[2.5,0.0;Trading with "..minetest.formspec_escape(trade.npc_name).."]"..
|
|
"label[1.5,0.8;You pay:]"..
|
|
-- show images of price and what is sold so that the player knows what
|
|
-- it costs and what he will get even if the trade is not possible at
|
|
-- that moment
|
|
"item_image[1,1.5;1,1;"..tostring(trade.player_gives).."]"..
|
|
"item_image[4,1.5;1,1;"..tostring(trade.npc_gives).."]"..
|
|
-- show the pay slot from the detached player's trade inventory
|
|
"list[detached:yl_speak_up_player_"..pname..";pay;2,1.5;1,1;]" ..
|
|
-- show the buy slot from the same inventory
|
|
"list[detached:yl_speak_up_player_"..pname..";buy;5,1.5;1,1;]" ..
|
|
"label[1.5,2.8;"..trade_possible_msg.."]"..
|
|
"button[6.2,1.6;2.0,0.9;finished_trading;Finish trading]"..
|
|
"tooltip[finished_trading;Click here once you've traded enough with this "..
|
|
"NPC and want to get back to talking.]"
|
|
end
|
|
|
|
|
|
-- create a detached inventory for the *player* for trading with the npcs
|
|
minetest.register_on_joinplayer(function(player, last_login)
|
|
local pname = player:get_player_name()
|
|
|
|
-- create the detached inventory;
|
|
-- the functions for monitoring changes will be important later on
|
|
-- only the the player owning this detached inventory may access it
|
|
local trade_inv = minetest.create_detached_inventory("yl_speak_up_player_"..tostring(pname), {
|
|
-- moving of items between diffrent lists is not allowed
|
|
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
|
|
if(not(player) or player:get_player_name() ~= pname) then
|
|
return 0
|
|
end
|
|
if(from_list ~= to_list) then
|
|
return 0
|
|
end
|
|
return count
|
|
end,
|
|
|
|
-- these all require calling special functions, depending on context
|
|
allow_put = function(inv, listname, index, stack, player)
|
|
if(not(player) or player:get_player_name() ~= pname) then
|
|
return 0
|
|
end
|
|
-- the "buy" slot is managed by the NPC; the player only takes from it
|
|
if(listname == "buy") then
|
|
return 0
|
|
end
|
|
return stack:get_count()
|
|
end,
|
|
allow_take = function(inv, listname, index, stack, player)
|
|
if(not(player) or player:get_player_name() ~= pname) then
|
|
return 0
|
|
end
|
|
-- can the trade be made?
|
|
if(listname == "buy") then
|
|
return yl_speak_up.can_trade_simple(player, stack:get_count())
|
|
end
|
|
return stack:get_count()
|
|
end,
|
|
on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
|
|
end,
|
|
on_put = function(inv, listname, index, stack, player)
|
|
if(listname == "pay") then
|
|
local pname = player:get_player_name()
|
|
-- show formspec with updated information (perhaps sale is now possible)
|
|
minetest.show_formspec(pname, "yl_speak_up:talk", yl_speak_up.get_fs_trade_simple(player))
|
|
end
|
|
end,
|
|
on_take = function(inv, listname, index, stack, player)
|
|
-- the player may have put something wrong in the payment slot
|
|
-- -> show updated formspec
|
|
if(listname == "pay") then
|
|
local pname = player:get_player_name()
|
|
-- show formspec with updated information (perhaps sale is now possible)
|
|
minetest.show_formspec(pname, "yl_speak_up:talk", yl_speak_up.get_fs_trade_simple(player))
|
|
elseif(listname == "buy") then
|
|
yl_speak_up.do_trade_simple(player, stack:get_count())
|
|
-- information may require an update (NPC might now be out of stock), or
|
|
-- the player can do the trade a second time
|
|
minetest.show_formspec(pname, "yl_speak_up:talk", yl_speak_up.get_fs_trade_simple(player))
|
|
end
|
|
end,
|
|
})
|
|
-- prepare the actual inventories
|
|
trade_inv:set_size("pay", 1)
|
|
trade_inv:set_size("buy", 1)
|
|
-- for setting up new simple trades
|
|
trade_inv:set_size("setup", 2*1)
|
|
end)
|