-- when closing the yl_speak_up.get_fs_add_trade_simple formspec: -- give the items back to the player (he took them from his inventory and -- had no real chance to put them elsewhere - so there really ought to be -- room enough) yl_speak_up.add_trade_simple_return_items = function(player, trade_inv, pay, buy) local player_inv = player:get_inventory() if( pay and player_inv:room_for_item("main", pay)) then player_inv:add_item("main", pay) trade_inv:set_stack("setup", 1, "") end if( buy and player_inv:room_for_item("main", buy)) then player_inv:add_item("main", buy) trade_inv:set_stack("setup", 2, "") end end -- simple trade: add a new trade or edit existing one (by storing a new one); -- set trade_id to "new" if it shall be a new trade added to the trade list; -- set trade_id to " " if it shall be a result/effect of a dialog option; yl_speak_up.get_fs_add_trade_simple = function(player, trade_id) if(not(player)) then return yl_speak_up.trade_fail_fs end local pname = player:get_player_name() local n_id = yl_speak_up.speak_to[pname].n_id local dialog = yl_speak_up.speak_to[pname].dialog -- is this player allowed to edit the NPC and his trades? If not abort. if(not(yl_speak_up.may_edit_npc(player, n_id)) or not(dialog) or not(dialog.n_npc)) then return "size[9,2]".. "label[2.0,1.8;Ups! Something went wrong.]".. "button[6.2,1.6;2.0,0.9;abort_trade_simple;Back]" end -- store the trade_id (so that it doesn't have to be transfered in a hidden field) yl_speak_up.speak_to[pname].trade_id = trade_id local delete_button = "button[0.2,2.6;1.0,0.9;delete_trade_simple;Delete]".. "tooltip[delete_trade_simple;Delete this trade.]" -- no point in deleting a new trade - it doesn't exist yet if(trade_id and trade_id == "new") then delete_button = "" end return "size[8.5,9]".. "label[4.35,0.8;"..minetest.formspec_escape(dialog.n_npc).." sells:]".. "list[current_player;main;0.2,4.85;8,1;]".. "list[current_player;main;0.2,6.08;8,3;8]".. -- 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[0.5,0.0;Configure trade with "..minetest.formspec_escape(dialog.n_npc)..":]".. "label[1.5,0.8;The customer pays:]".. "label[1.5,3.8;Put items in the two slots and click on \"Store trade\".]".. "label[1.5,4.2;You will get your items back when storing the trade.]".. -- annoyingly, the height value no longer works :-( "label[0.2,2.5;Item\nname:]".. "field[1.5,3.2;3,0.2;item_name_price;;]".. "label[4.35,2.5;If you don't have the item you\n".. "want to buy, then enter its item\n".. "name (i.e. default:diamond) here.]".. "button[0.2,1.6;1.0,0.9;abort_trade_simple;Abort]".. delete_button.. "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\n".. "items will be returned to you and the trade will\n".. "will be shown the way the customer can see it.]".. "tooltip[abort_trade_simple;Abort setting up this new trade.]" end -- the player wants to add a simple trade; handle formspec input -- possible inputs: -- fields.back_from_error_msg show this formspec here again -- fields.store_trade_simple store this trade as a result and -- go on to showing the do_trade_simple formspec -- fields.delete_trade_simple delete this trade -- go back to edit options dialog -- abort_trade_simple, ESC go back to edit options dialog -- The rest is inventory item movement. yl_speak_up.input_add_trade_simple = function(player, formname, fields) if(not(player)) then return 0 end local pname = player:get_player_name() local input_to = "add_trade_simple" -- 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 = "edit_actions" end -- we return from showing an error message (the player may not have noticed -- a chat message while viewing a formspec; thus, we showed a formspec message) if(fields.back_from_error_msg) then yl_speak_up.show_fs(player, input_to) return end -- which trade are we talking about? local trade_id = yl_speak_up.speak_to[pname].trade_id -- this also contains the inventory list "setup" where the player placed the items local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname}) -- fields.abort_trade_simple can be ignored as it is similar to ESC local pay = trade_inv:get_stack("setup", 1) local buy = trade_inv:get_stack("setup", 2) -- clicking on abort here when adding a new trade via the trade list -- goes back to the trade list (does not require special privs) if(fields.abort_trade_simple and trade_id == "new") then -- we are no longer doing a particular trade yl_speak_up.speak_to[pname].trade_id = nil -- return the items (setting up the trade was aborted) yl_speak_up.add_trade_simple_return_items(player, trade_inv, pay, buy) -- ..else go back to the edit options formspec yl_speak_up.show_fs(player, "trade_list") return end -- adding a new trade via the trade list? if(not(trade_id) and fields.store_trade_simple) then trade_id = "new" end local n_id = yl_speak_up.speak_to[pname].n_id local d_id = yl_speak_up.speak_to[pname].d_id local o_id = yl_speak_up.speak_to[pname].o_id -- the trade can only be changed in edit mode if((not(n_id) or yl_speak_up.edit_mode[pname] ~= n_id) -- exception: when adding a new trade via the trade list -- (that is allowed without having to be in edit mode) and not(trade_id == "new" and yl_speak_up.may_edit_npc(player, n_id))) then -- return the items (setting up the trade was aborted) yl_speak_up.add_trade_simple_return_items(player, trade_inv, pay, buy) return end -- store the new trade if(fields.store_trade_simple) then local error_msg = "" local simulated_pay = false if(pay:is_empty() and fields.item_name_price and fields.item_name_price ~= "") then pay = ItemStack(fields.item_name_price) simulated_pay = true end -- check for error conditions if(pay:is_empty()) then error_msg = "What shall the customer pay?\nWe don't give away stuff for free here!" elseif(buy:is_empty()) then error_msg = "What shall your NPC sell?\nCustomers won't pay for nothing!" elseif(pay:get_wear() > 0 or buy:get_wear() > 0) then error_msg = "Selling used items is not possible." elseif(not(minetest.registered_items[ pay:get_name() ]) or not(minetest.registered_items[ buy:get_name() ])) then error_msg = "Unkown items cannot be traded." elseif(pay:get_name() == buy:get_name()) then error_msg = "Selling *and* buying the same item\nat the same time makes no sense." else -- get the necessary dialog data local dialog = yl_speak_up.speak_to[pname].dialog -- player_gives (pay stack): local ps = pay:get_name().." "..tostring(pay:get_count()) -- npc_gives (buy stack): local bs = buy:get_name().." "..tostring(buy:get_count()) local r_id = "?" if(not(dialog.trades)) then dialog.trades = {} end -- is this a trade attached to the trade list? -- or do we have to create a new trade ID? if(trade_id == "new") then -- if the player adds the same trade again, the ID is reused; other -- than that, the ID is uniq -- (the ID is formed so that we can later easily sort the offers by -- the name of the buy stack - which is more helpful for the player -- than sorting by the pay stack) trade_id = "sell "..bs.." for "..ps -- log the change yl_speak_up.log_change(pname, n_id, "Trade: Added offer "..tostring(trade_id)..".") -- add this new trade dialog.trades[ trade_id ] = {pay={ps},buy={bs}} -- actually save the dialog to disk yl_speak_up.save_dialog(n_id, dialog) -- store the newly created trade_id yl_speak_up.speak_to[pname].trade_id = trade_id -- all ok so far error_msg = nil -- storing trades that are associated with particular dialogs and options -- requires d_id and o_id to be set elseif(trade_id ~= "new" and (not(d_id) or not(o_id))) then error_msg = "Internal error. o_id was not set." else -- record this as a change, but do not save do disk yet table.insert(yl_speak_up.npc_was_changed[ n_id ], "Dialog "..d_id..": Trade "..tostring(trade_id).." added to option ".. tostring(o_id)..".") -- add this new trade - complete with information to which dialog and -- to which option the trade belongs dialog.trades[ trade_id ] = {pay={ps},buy={bs}, d_id = d_id, o_id = o_id} -- all ok so far error_msg = nil end -- do not return yet - the items still need to be given back! end -- make sure we don't create items here out of thin air if(simulated_pay) then pay = ItemStack("") end -- show error message (that leads back to this formspec) if(error_msg) then yl_speak_up.show_fs(player, "msg", { input_to = "yl_speak_up:"..input_to, formspec = "size[6,2]".. "label[0.2,0.5;"..error_msg.."]".. "button[2,1.5;1,0.9;back_from_error_msg;Back]"}) return end -- we need a way of deleting trades as well; -- this affects only trades that are associated with dialogs and options; -- trades from the trade list are deleted more directly elseif(fields.delete_trade_simple) then -- delete this result (if it exists) -- get the necessary dialog data local dialog = yl_speak_up.speak_to[pname].dialog -- record this as a change table.insert(yl_speak_up.npc_was_changed[ n_id ], "Dialog "..d_id..": Trade "..tostring(trade_id).." deleted from option ".. tostring(o_id)..".") if(not(dialog.trades)) then dialog.trades = {} end -- delete the trade type result if(trade_id) then dialog.trades[ trade_id ] = nil end -- do not return yet - the items still need to be given back! end -- return the items after successful setup yl_speak_up.add_trade_simple_return_items(player, trade_inv, pay, buy) local dialog = yl_speak_up.speak_to[pname].dialog if(not(dialog.trades)) then dialog.trades = {} end if(dialog.trades[ trade_id ] and dialog.trades[ trade_id ].d_id and input_to ~= "edit_actions") then yl_speak_up.speak_to[pname].trade_id = trade_id -- tell the player that the new trade has been added yl_speak_up.show_fs(player, "msg", { input_to = "yl_speak_up:do_trade_simple", formspec = "size[6,2]".. "label[0.2,0.5;The new trade has been configured successfully.]".. "button[1.5,1.5;2,0.9;trade_simple_stored;Show trade]"}) -- return back to trade list elseif(not(o_id)) then -- we are no longer trading yl_speak_up.speak_to[pname].trade_id = nil -- ..else go back to the edit options formspec yl_speak_up.show_fs(player, "trade_list") else -- we are no longer trading yl_speak_up.speak_to[pname].trade_id = nil -- the trade has been stored or deleted successfully return true -- -- ..else go back to the edit options formspec (obsolete) -- yl_speak_up.show_fs(player, "edit_option_dialog", -- {n_id = n_id, d_id = d_id, o_id = o_id}) end end