reward_inv/show_reward_fs.lua

432 lines
17 KiB
Lua

-- 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])
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
local anz_taken = 0
for k, v in pairs(access_data[3] or {}) do
anz_taken = anz_taken + v
end
table.insert(formspec, "label[2,6.5;")
table.insert(formspec, tostring(anz_taken))
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