-- who is allowed to edit and create new reward inventories? -- works with player object and player name reward_inv.may_edit = function(pname) return minetest.check_player_privs(pname, {give=true}) end reward_inv.show_error_msg_fs = function(pname, error_msg) local formspec = {"size[10,3]".. "label[0.2,0.5;Error:]".. "label[0.5,1.0;"} table.insert(formspec, minetest.colorize("#FFFF00", minetest.formspec_escape( minetest.wrap_text(tostring(error_msg), 80)))) table.insert(formspec, "]") table.insert(formspec, "button[3.5,2.0;2,0.9;back_from_error_msg;Back]") minetest.show_formspec(pname, "reward_inv:main", table.concat(formspec, "")) return true end reward_inv.input_handler = function(player, formname, fields) if(not(formname) or formname ~= "reward_inv:main") then return false end local pname = player:get_player_name() local reward_data = {} if(reward_inv.player_using[pname]) then reward_data = reward_inv.get_reward_data(reward_inv.player_using[pname]) or {} end -- if in edit mode: give items that were added back local liste = {} if(reward_inv.player_is_editing[pname]) then -- make sure we do have a content we can compare with if(not(reward_data.content)) then reward_data.content = {} for i=1, 32 do reward_data.content[i] = "" end end local inv_name = reward_inv.reward_inv_get_name(pname) -- has the inventory already been created? Then don't create it anew local inv = minetest.get_inventory({type="detached", name=inv_name}) if(inv) then -- returns a list of stacks liste = inv:get_list("main") end -- the reason why we return items here is because something complex like -- written books or other itemstacks with complex metadata shall not be lost local player_inv = player:get_inventory() for i, work_stack in pairs(liste) do local prev_stack = ItemStack(reward_data.content[i] or "") -- there is something or something diffrent in the detached inv now if(not(work_stack:equals(prev_stack))) then -- is there more in the stack than there used to be? if( work_stack:get_name() == prev_stack:get_name() and work_stack:get_count() > prev_stack:get_count()) then local c = work_stack:get_count() - prev_stack:get_count() work_stack:set_count(c) -- return the leftover parts player_inv:add_item("main", work_stack) else -- diffrent stack (even if only in metadata) - so return all player_inv:add_item("main", work_stack) end end liste[i] = liste[i]:to_table() end end if(fields.show_reward_list) then reward_inv.show_reward_list_fs(player, reward_inv.player_using[pname]) return true end -- any input here is only accepted if the player is allwed to edit this if(not(player) or not(fields) or not(reward_inv.may_edit(player))) then return false end if(fields.exit or fields.quit) then return true end if(fields.back_from_error_msg) then reward_inv.show_reward_fs(player, reward_inv.player_using[pname]) return true end local reward_id = "" if(fields.select_reward_id and fields.set_reward_id) then reward_id = fields.select_reward_id if(not(reward_id) or reward_id == "") then return reward_inv.show_error_msg_fs(pname, "Please select a name for the new ".. "reward ID or enter a new name!") end elseif(fields.new_reward_id and fields.create_reward_id) then reward_id = fields.new_reward_id if(string.len(reward_id) < 2 or string.len(reward_id) > 120) then return reward_inv.show_error_msg_fs(pname, "The reward ID needs to be between ".. "2 and 120 characters long.") end else reward_id = reward_inv.player_using[pname] end if(not(reward_id) or reward_id == "") then return reward_inv.show_error_msg_fs(pname, "No reward_id selected.") end -- if it's a chest make sure reward_id is stored in its metadata if(reward_inv.clicked_at_chest[pname]) then local meta = minetest.get_meta(reward_inv.clicked_at_chest[pname]) meta:set_string("reward_id", reward_id) -- update infotext as well meta:set_string("infotext", "Treasure chest") end -- the player is working on this reward and editing it (until the Store button is clicked) reward_inv.player_using[pname] = reward_id reward_inv.player_is_editing[pname] = true if(fields.save) then -- save the new reward inventory reward_data.content = liste -- set values for which we got input if(fields.input_text_hint) then reward_data.hint = fields.input_text_hint end if(fields.input_text_when_found) then reward_data.text_when_found = fields.input_text_when_found end if(fields.input_refill_after_t_seconds and fields.input_refill_after_t_seconds ~= "") then reward_data.refill_after_t_seconds = tonumber(fields.input_refill_after_t_seconds) end if(reward_inv.clicked_at_chest[pname]) then reward_data.pos = reward_inv.clicked_at_chest[pname] elseif(minetest.global_exists("yl_speak_up")) then reward_data.npc = yl_speak_up.speak_to[pname].n_id end -- actually save it reward_inv.set_inv_data(reward_id, reward_data) -- leave edit mode reward_inv.player_is_editing[pname] = nil end reward_inv.show_reward_fs(player, reward_inv.player_using[pname]) return true end -- show the initial formspec for assinging a reward_id reward_inv.get_fs_set_reward_id = function(player) local pname = player:get_player_name() local suggested_id = "" -- is this for a chest? if(reward_inv.clicked_at_chest[pname]) then suggested_id = minetest.pos_to_string(reward_inv.clicked_at_chest[pname]) -- or for an NPC? elseif(minetest.global_exists("yl_speak_up") and yl_speak_up.speak_to[pname]) then suggested_id = yl_speak_up.speak_to[pname] end local liste = reward_inv.get_sorted_reward_id_list() local formspec = {} table.insert(formspec, "size[8,4.5]") table.insert(formspec, "label[0,0;Not yet configured. No reward_id set. ".. "You have the priv to set one.]") table.insert(formspec, "label[0,1;Select existing:]") table.insert(formspec, "dropdown[2.2,0.9;4.8,1;select_reward_id;") table.insert(formspec, table.concat(liste, ",")) table.insert(formspec, ";1;false]") table.insert(formspec, "button[6.8,0.8;1.2,1;set_reward_id;Set]") table.insert(formspec, "label[0,2;..or create new:]") table.insert(formspec, "field[2.5,2.1;4.7,1;new_reward_id;;") table.insert(formspec, minetest.formspec_escape(suggested_id)) table.insert(formspec, "]") table.insert(formspec, "button[6.8,1.8;1.2,1;create_reward_id;Create]") table.insert(formspec, "tooltip[new_reward_id;".. "The reward_id you store here is needed in order to reference the reward.\n".. "If you are adding a treasure chest, just go with the suggested name/pos.\n".. "When adding a treasure for an NPC, add some description that will help\n".. "you remember what this reward is for.]") table.insert(formspec, "tooltip[create_reward_id;Click here to proceed.]") table.insert(formspec, "tooltip[select_reward_id;".. "You can select an existing reward_id.\n".. "Note that this is seldom necessary. It is usually only needed when you\n".. "moved a treasure chest a few blocks away and want to keep the data.\n".. "Or when you changed the dialog structure of the NPC that hands out the\n".. "reward.]") table.insert(formspec, "tooltip[set_reward_id;".. "Click here to store the selected reward_id. This is seldom needed.\n".. "Usually, creating a new one is the better choice.]") table.insert(formspec, "label[0,2.6;Note: Select a name which will help you remember ".. "what this]") table.insert(formspec, "label[0,3.0;reward is for and/or where it will be handed out.]") table.insert(formspec, "label[0,3.4;In general, just click on \"Create\" to proceed.]") table.insert(formspec, "button_exit[3,3.9;2,1;exit;Exit]") return table.concat(formspec, "") end -- create a formspec with the updated reward inventory for the player reward_inv.get_reward_fs = function(player, reward_id) if(not(player)) then return "" end local pname = player:get_player_name() reward_inv.player_using[pname] = reward_id -- make the detached inventory contain those items that according to -- our stored data are still available to the player local inv = reward_inv.update_reward_inv(player, reward_id) if(not(inv)) then -- nothing to show return "size[10,2]".. "label[0,0;Internal error: Failed to create detached inventory.]".. "button[4,1;2,1;close;Close]" end -- is the player editing this? local edit_mode = reward_inv.player_is_editing[pname] -- we use the "give" priv as that seems most fitting local has_edit_priv = reward_inv.may_edit(pname, {give=true}) -- do we need to assign a reward_id here first? if(not(reward_id) or reward_id == "") then if(not(has_edit_priv)) then return "size[6,1]".. "label[0,0;No reward assigned. Please come back later!]".. "button_exit[2,0.5;2,1;exit;Exit]" end return reward_inv.get_fs_set_reward_id(player) end -- get general information about the reward as such local reward_data = reward_inv.get_reward_data(reward_id) if(not(reward_data)) then if(not(has_edit_priv)) then return "size[6,1]".. "label[0,0;Not yet filled. Please come back later!]".. "button_exit[2,0.5;2,1;exit;Exit]" end -- no data yet - force entering edit mode so that we get data reward_inv.player_is_editing[pname] = true edit_mode = true reward_data = {} end -- for showing the player when and how much he/she took local access_data = reward_inv.get_access_data(pname, reward_id) or {0, 0, {}, 0} -- create the formspec local formspec = {"size[12,11]"} local text = "Congratulations! You've " local error_msg = "" if(edit_mode) then text = "You are in edit mode and editing this reward with ID \"".. minetest.formspec_escape(reward_id).."\"" elseif(not(reward_data)) then text = text.."found something not yet ready to use" -- TODO: add assign reward_id button? elseif(reward_data.pos) then text = text.."found this treasure chest at ".. minetest.formspec_escape(minetest.pos_to_string(reward_data.pos)) elseif(reward_data.npc_name) then text = text.."been awarded this reward by ".. table.insert(formspec, minetest.formspec_escape(reward_data.npc_name)) else text = text.."found this treasure" end table.insert(formspec, "label[1,-0.3;") table.insert(formspec, text) table.insert(formspec, ":]") -- provide information about how to identify this reward local text_hint = reward_data.hint local text_when_found = reward_data.text_when_found if(text_hint and (not(text_when_found) or text_when_found=="")) then text_when_found = text_hint end table.insert(formspec, "container[0.2,0.2]") table.insert(formspec, "label[0,0;The hint that was supposed to lead you here was:]") table.insert(formspec, "label[0,1;Now this will be listed like this when you type \"/rewards\":]") text_hint = minetest.formspec_escape(text_hint or "") text_when_found = minetest.formspec_escape(text_when_found or "") if(edit_mode) then table.insert(formspec, "field[0.5,0.6;7.6,1.0;input_text_hint;;") table.insert(formspec, text_hint) table.insert(formspec, "]") table.insert(formspec, "field[0.5,1.6;7.6,1.0;input_text_when_found;;") table.insert(formspec, text_when_found) table.insert(formspec, "]") table.insert(formspec, "label[8.0,0;Refill reward after t seconds:]") table.insert(formspec, "field[8.5,0.6;3.7,1.0;input_refill_after_t_seconds;;") table.insert(formspec, minetest.formspec_escape(reward_data.refill_after_t_seconds or 0)) table.insert(formspec, "]") table.insert(formspec, "tooltip[input_text_hint;".. "This hint will be shown to players who have not found or not\n".. "been awarded this reward yet. The hint ought to help players\n".. "locate the general area where to search, i.e.\n".. "\tTavern \"The Lion's Inn\" in Capital City ".. minetest.formspec_escape("[Area ID 1234]").. "\nor something like:\n".. "\tTalk to shopkeeper in the village Lone Valley\n".. "If no text is set, then this reward will not show up in /rewards.]") table.insert(formspec, "tooltip[input_text_when_found;".. "This text will be shown to players who have found or been\n".. "awarded this reward.\n".. "If nothing is set here, the hint text will be shown.]") table.insert(formspec, "tooltip[input_refill_after_t_secons;".. "If this value is higher than 0, players can claim this reward\n".. "again if more than this many seconds have passed since they\n".. "last took something from this reward.\n".. "Hour: 3600 s, day: 86400 s, week: 604800 s, month: 18144000 s\n".. "Leave it at 0 in order to hand each reward out only once.]") else if(text_hint == "") then text_hint = "- none -" end if(text_when_found == "") then text_when_found = "- not listed -" end table.insert(formspec, "label[0.5,0.5;") table.insert(formspec, minetest.colorize("#CCCCFF", text_hint)) table.insert(formspec, "]") table.insert(formspec, "label[0.5,1.5;") table.insert(formspec, minetest.colorize("#00FF00", text_when_found)) table.insert(formspec, "]") end if(reward_data and reward_data.refill_after_t_seconds and reward_data.refill_after_t_seconds > 0) then table.insert(formspec, "label[8.0,6;This treasure refills sometimes.]") table.insert(formspec, "label[8.0,6.3;") table.insert(formspec, minetest.colorize("#FFFF00", "Might be worth comming back!")) table.insert(formspec, "]") else table.insert(formspec, "label[8.0,6;But beware: There is no refill.]") table.insert(formspec, "label[8.0,6.3;You will get this only once.]") end table.insert(formspec, "container_end[]") -- show some simple access data to all table.insert(formspec, "container[8.2,2]") table.insert(formspec, "box[-0.2,0.3;3.9,2.9;#000000]") table.insert(formspec, "label[1,0.5;Statistic:]") table.insert(formspec, "label[0,2.5;Found by:]") table.insert(formspec, "label[2,2.5;") table.insert(formspec, tostring(reward_data.anz_found or 0)) table.insert(formspec, " people]") table.insert(formspec, "label[0,1.0;First found:]") table.insert(formspec, "label[0,1.5;Last found:]") table.insert(formspec, "label[0,2.0;Last taken:]") -- player-specific information table.insert(formspec, "box[-0.2,4.9;3.9,2.1;#000000]") table.insert(formspec, "label[1,5.0;Your data:]") table.insert(formspec, "label[0,5.5;First found:]") table.insert(formspec, "label[0,6.0;Last taken:]") table.insert(formspec, "label[0,6.5;Items taken:]") local offset = 0.5 local dates = {reward_data.first_found or 0, reward_data.last_found or 0, reward_data.last_taken or 0, access_data[1] or 0, access_data[4] or 0} for i, date in ipairs(dates) do local txt = "- never -" if(date and date > 0) then txt = os.date("%m/%d/%y %H:%M", date) end table.insert(formspec, "label[1.6,") table.insert(formspec, tostring(offset + (0.5 * i))) table.insert(formspec, ";") table.insert(formspec, minetest.formspec_escape(txt)) table.insert(formspec, "]") -- for the "Your data:" part if(i==3) then offset = 3.5 end end table.insert(formspec, "label[2,6.5;") table.insert(formspec, tostring(access_data[5])) table.insert(formspec, "]") table.insert(formspec, "button_exit[-0.2,-0.5;4.1,1;show_reward_list;Show reward list]") table.insert(formspec, "button_exit[-0.2,8.2;4.1,1;exit;Close]") if(edit_mode) then table.insert(formspec, "button[-0.2,3.4;4.1,1;save;Save changes]") else table.insert(formspec, "button[-0.2,3.4;4.1,1;start_edit;Edit]") end table.insert(formspec, "container_end[]") -- add a short text in the space between the two inventories if(edit_mode) then table.insert(formspec, "label[0.5,6.15;Fill this inventory with what you want the ".. "reward to be.]") table.insert(formspec, "label[0.5,6.45;Each player may then take out one copy of it.]") else table.insert(formspec, "label[0.5,6.15;Don't worry if you can't carry it all.]") table.insert(formspec, "label[0.5,6.45;You can come back any time later and claim the rest.]") end local reward_inv_name = reward_inv.reward_inv_get_name(pname) table.insert(formspec, "container[0,2]") -- table.insert(formspec, "background[0,0;8,9;default_gold_block.png;true]") -- table.insert(formspec, "background[0,0;8,9;default_chest_top.png;true]") table.insert(formspec, "list[current_player;main;0,4.95;8,1;]") table.insert(formspec, "list[current_player;main;0,6.08;8,3;8]") table.insert(formspec, "list[detached:") table.insert(formspec, reward_inv_name) table.insert(formspec, ";main;0,0.3;8,4;]") table.insert(formspec, "listring[detached:") table.insert(formspec, reward_inv_name) table.insert(formspec, ";main]") table.insert(formspec, "listring[current_player;main]") table.insert(formspec, "container_end[]") return table.concat(formspec, "") end -- show a formspec with the updated reward inventory to the player reward_inv.show_reward_fs = function(player, reward_id) if(not(player)) then return end local pname = player:get_player_name() -- create the formspec local formspec = reward_inv.get_reward_fs(player, reward_id) -- actually show the reward formspec to the player minetest.show_formspec(pname, "reward_inv:main", formspec) end