yl_speak_up/trade_simple.lua
2021-05-22 19:49:09 +02:00

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)