minetest_doc/init.lua

1223 lines
44 KiB
Lua
Raw Permalink Normal View History

2019-03-07 10:24:52 -08:00
local S = minetest.get_translator("doc")
local F = function(f) return minetest.formspec_escape(S(f)) end
2016-10-12 21:10:24 -07:00
2016-12-27 10:07:41 -08:00
-- Compability for 0.4.14 or earlier
local colorize
2019-03-16 00:04:21 -07:00
if minetest.colorize then
colorize = minetest.colorize
2016-12-27 10:07:41 -08:00
else
colorize = function(color, text) return text end
end
2015-03-11 05:30:00 -07:00
doc = {}
-- Some informational variables
-- DO NOT CHANGE THEM AFTERWARDS AT RUNTIME!
-- Version number (follows the SemVer specification 2.0.0)
2015-03-11 05:30:00 -07:00
doc.VERSION = {}
2016-12-28 14:23:10 -08:00
doc.VERSION.MAJOR = 1
2019-03-18 22:49:22 -07:00
doc.VERSION.MINOR = 2
2017-02-02 17:26:30 -08:00
doc.VERSION.PATCH = 1
2016-07-20 10:39:54 -07:00
doc.VERSION.STRING = doc.VERSION.MAJOR.."."..doc.VERSION.MINOR.."."..doc.VERSION.PATCH
2015-03-11 05:30:00 -07:00
-- Formspec information
doc.FORMSPEC = {}
-- Width of formspec
2016-12-15 03:05:26 -08:00
doc.FORMSPEC.WIDTH = 15
doc.FORMSPEC.HEIGHT = 10.5
--[[ Recommended bounding box coordinates for widgets to be placed in entry pages. Make sure
all entry widgets are completely inside these coordinates to avoid overlapping. ]]
doc.FORMSPEC.ENTRY_START_X = 0
doc.FORMSPEC.ENTRY_START_Y = 0.5
doc.FORMSPEC.ENTRY_END_X = doc.FORMSPEC.WIDTH
doc.FORMSPEC.ENTRY_END_Y = doc.FORMSPEC.HEIGHT - 0.5
doc.FORMSPEC.ENTRY_WIDTH = doc.FORMSPEC.ENTRY_END_X - doc.FORMSPEC.ENTRY_START_X
doc.FORMSPEC.ENTRY_HEIGHT = doc.FORMSPEC.ENTRY_END_Y - doc.FORMSPEC.ENTRY_START_Y
--TODO: Use container formspec element later
-- Internal helper variables
2016-12-12 03:42:18 -08:00
local DOC_INTRO = S("This is the help.")
2016-11-03 11:20:03 -07:00
2016-12-23 08:55:20 -08:00
local COLOR_NOT_VIEWED = "#00FFFF" -- cyan
local COLOR_VIEWED = "#FFFFFF" -- white
local COLOR_HIDDEN = "#999999" -- gray
2016-12-23 09:01:13 -08:00
local COLOR_ERROR = "#FF0000" -- red
2016-12-23 08:55:20 -08:00
2016-11-07 05:12:49 -08:00
local CATEGORYFIELDSIZE = {
WIDTH = math.ceil(doc.FORMSPEC.WIDTH / 4),
HEIGHT = math.floor(doc.FORMSPEC.HEIGHT-1),
2016-11-07 05:12:49 -08:00
}
2015-03-11 05:30:00 -07:00
doc.data = {}
doc.data.categories = {}
doc.data.aliases = {}
2016-11-18 05:46:37 -08:00
-- Default order (includes categories of other mods from the Docuentation System modpack)
doc.data.category_order = {"basics", "nodes", "tools", "craftitems", "advanced"}
2016-12-12 03:47:40 -08:00
doc.data.category_count = 0
2015-03-11 09:51:41 -07:00
doc.data.players = {}
2015-03-11 05:30:00 -07:00
2016-07-24 08:30:23 -07:00
-- Space for additional APIs
doc.sub = {}
2016-11-18 05:46:37 -08:00
-- Status variables
local set_category_order_was_called = false
2016-12-28 10:19:03 -08:00
-- Returns the entry definition and true entry ID of an entry, taking aliases into account
local function get_entry(category_id, entry_id)
local category = doc.data.categories[category_id]
local entry
if category ~= nil then
entry = category.entries[entry_id]
end
if category == nil or entry == nil then
local c_alias = doc.data.aliases[category_id]
if c_alias then
local alias = c_alias[entry_id]
if alias then
category_id = alias.category_id
entry_id = alias.entry_id
category = doc.data.categories[category_id]
if category then
entry = category.entries[entry_id]
else
return nil
end
else
return nil
end
else
return nil
end
end
return entry, category_id, entry_id
end
--[[ Core API functions ]]
-- Add a new category
function doc.add_category(id, def)
2015-03-11 08:24:00 -07:00
if doc.data.categories[id] == nil and id ~= nil then
doc.data.categories[id] = {}
doc.data.categories[id].entries = {}
doc.data.categories[id].entry_count = 0
doc.data.categories[id].hidden_count = 0
2015-03-11 08:24:00 -07:00
doc.data.categories[id].def = def
2016-11-18 05:46:37 -08:00
-- Determine order position
local order_id = nil
for i=1,#doc.data.category_order do
if doc.data.category_order[i] == id then
order_id = i
break
end
end
if order_id == nil then
table.insert(doc.data.category_order, id)
doc.data.categories[id].order_position = #doc.data.category_order
else
doc.data.categories[id].order_position = order_id
end
2016-12-12 03:47:40 -08:00
doc.data.category_count = doc.data.category_count + 1
2015-03-11 08:24:00 -07:00
return true
else
return false
2015-03-11 05:30:00 -07:00
end
end
-- Add a new entry
function doc.add_entry(category_id, entry_id, def)
local cat = doc.data.categories[category_id]
if cat ~= nil then
local hidden = def.hidden or (def.hidden == nil and cat.def.hide_entries_by_default)
if hidden then
cat.hidden_count = cat.hidden_count + 1
def.hidden = hidden
end
cat.entry_count = doc.data.categories[category_id].entry_count + 1
if def.name == nil or def.name == "" then
minetest.log("warning", "[doc] Nameless entry added. Entry ID: "..entry_id)
end
cat.entries[entry_id] = def
2015-03-11 08:24:00 -07:00
return true
else
return false
2015-03-11 05:30:00 -07:00
end
end
2016-08-30 14:00:50 -07:00
-- Marks a particular entry as viewed by a certain player, which also
-- automatically reveals it
2016-07-31 11:54:47 -07:00
function doc.mark_entry_as_viewed(playername, category_id, entry_id)
2016-12-28 10:19:03 -08:00
local entry, category_id, entry_id = get_entry(category_id, entry_id)
if not entry then
return
end
2016-07-31 11:54:47 -07:00
if doc.data.players[playername].stored_data.viewed[category_id] == nil then
doc.data.players[playername].stored_data.viewed[category_id] = {}
doc.data.players[playername].stored_data.viewed_count[category_id] = 0
end
2016-08-03 16:32:06 -07:00
if doc.entry_exists(category_id, entry_id) and doc.data.players[playername].stored_data.viewed[category_id][entry_id] ~= true then
doc.data.players[playername].stored_data.viewed[category_id][entry_id] = true
doc.data.players[playername].stored_data.viewed_count[category_id] = doc.data.players[playername].stored_data.viewed_count[category_id] + 1
-- Needed because viewed entries get a different color
doc.data.players[playername].entry_textlist_needs_updating = true
2016-07-31 11:54:47 -07:00
end
2016-08-30 14:00:50 -07:00
doc.mark_entry_as_revealed(playername, category_id, entry_id)
end
-- Marks a particular entry as revealed/unhidden by a certain player
function doc.mark_entry_as_revealed(playername, category_id, entry_id)
2016-12-28 10:19:03 -08:00
local entry, category_id, entry_id = get_entry(category_id, entry_id)
if not entry then
return
end
2016-08-30 14:00:50 -07:00
if doc.data.players[playername].stored_data.revealed[category_id] == nil then
doc.data.players[playername].stored_data.revealed[category_id] = {}
doc.data.players[playername].stored_data.revealed_count[category_id] = doc.get_entry_count(category_id) - doc.data.categories[category_id].hidden_count
2016-08-30 14:00:50 -07:00
end
if doc.entry_exists(category_id, entry_id) and entry.hidden and doc.data.players[playername].stored_data.revealed[category_id][entry_id] ~= true then
2016-08-30 14:00:50 -07:00
doc.data.players[playername].stored_data.revealed[category_id][entry_id] = true
doc.data.players[playername].stored_data.revealed_count[category_id] = doc.data.players[playername].stored_data.revealed_count[category_id] + 1
-- Needed because a new entry is added to the list of visible entries
doc.data.players[playername].entry_textlist_needs_updating = true
-- Notify player of entry revelation
if doc.data.players[playername].stored_data.notify_on_reveal == true then
if minetest.get_modpath("central_message") ~= nil then
local cat = doc.data.categories[category_id]
cmsg.push_message_player(minetest.get_player_by_name(playername), S("New help entry unlocked: @1 > @2", cat.def.name, entry.name))
end
-- To avoid sound spamming, don't play sound more than once per second
local last_sound = doc.data.players[playername].last_reveal_sound
if last_sound == nil or os.difftime(os.time(), last_sound) >= 1 then
-- Play notification sound
2020-04-06 15:56:21 -07:00
minetest.sound_play({ name = "doc_reveal", gain = 0.2 }, { to_player = playername }, true)
doc.data.players[playername].last_reveal_sound = os.time()
end
end
2016-08-30 14:00:50 -07:00
end
2016-07-31 11:54:47 -07:00
end
-- Reveal
function doc.mark_all_entries_as_revealed(playername)
-- Has at least 1 new entry been revealed?
local reveal1 = false
for category_id, category in pairs(doc.data.categories) do
if doc.data.players[playername].stored_data.revealed[category_id] == nil then
doc.data.players[playername].stored_data.revealed[category_id] = {}
doc.data.players[playername].stored_data.revealed_count[category_id] = doc.get_entry_count(category_id) - doc.data.categories[category_id].hidden_count
end
for entry_id, _ in pairs(category.entries) do
if doc.data.players[playername].stored_data.revealed[category_id][entry_id] ~= true then
doc.data.players[playername].stored_data.revealed[category_id][entry_id] = true
doc.data.players[playername].stored_data.revealed_count[category_id] = doc.data.players[playername].stored_data.revealed_count[category_id] + 1
reveal1 = true
end
end
end
local msg
if reveal1 then
-- Needed because new entries are added to player's view on entry list
doc.data.players[playername].entry_textlist_needs_updating = true
msg = S("All help entries revealed!")
-- Play notification sound (ignore sound limit intentionally)
2020-04-06 15:56:21 -07:00
minetest.sound_play({ name = "doc_reveal", gain = 0.2 }, { to_player = playername }, true)
doc.data.players[playername].last_reveal_sound = os.time()
else
msg = S("All help entries are already revealed.")
end
-- Notify
if minetest.get_modpath("central_message") ~= nil then
cmsg.push_message_player(minetest.get_player_by_name(playername), msg)
else
minetest.chat_send_player(playername, msg)
end
end
2016-07-31 11:54:47 -07:00
-- Returns true if the specified entry has been viewed by the player
function doc.entry_viewed(playername, category_id, entry_id)
2016-12-28 10:19:03 -08:00
local entry, category_id, entry_id = get_entry(category_id, entry_id)
2016-07-31 11:54:47 -07:00
if doc.data.players[playername].stored_data.viewed[category_id] == nil then
return false
else
return doc.data.players[playername].stored_data.viewed[category_id][entry_id] == true
end
end
2016-08-30 14:00:50 -07:00
-- Returns true if the specified entry is hidden from the player
function doc.entry_revealed(playername, category_id, entry_id)
2016-12-28 10:19:03 -08:00
local entry, category_id, entry_id = get_entry(category_id, entry_id)
2016-08-30 14:00:50 -07:00
local hidden = doc.data.categories[category_id].entries[entry_id].hidden
if doc.data.players[playername].stored_data.revealed[category_id] == nil then
return not hidden
else
if hidden then
return doc.data.players[playername].stored_data.revealed[category_id][entry_id] == true
else
return true
end
end
end
-- Returns category definition
function doc.get_category_definition(category_id)
if doc.data.categories[category_id] == nil then
return nil
end
return doc.data.categories[category_id].def
end
-- Returns entry definition
function doc.get_entry_definition(category_id, entry_id)
if not doc.entry_exists(category_id, entry_id) then
return nil
end
2016-12-28 10:19:03 -08:00
local entry, _, _ = get_entry(category_id, entry_id)
2016-08-31 11:24:42 -07:00
return entry
end
-- Opens the main documentation formspec for the player
2015-03-11 05:30:00 -07:00
function doc.show_doc(playername)
if doc.get_category_count() <= 0 then
minetest.show_formspec(playername, "doc:error_no_categories", doc.formspec_error_no_categories())
return
end
local formspec = doc.formspec_core()..doc.formspec_main(playername)
2015-03-11 05:30:00 -07:00
minetest.show_formspec(playername, "doc:main", formspec)
end
-- Opens the documentation formspec for the player at the specified category
function doc.show_category(playername, category_id)
if doc.get_category_count() <= 0 then
minetest.show_formspec(playername, "doc:error_no_categories", doc.formspec_error_no_categories())
return
end
doc.data.players[playername].catsel = nil
doc.data.players[playername].category = category_id
doc.data.players[playername].entry = nil
local formspec = doc.formspec_core(2)..doc.formspec_category(category_id, playername)
minetest.show_formspec(playername, "doc:category", formspec)
end
-- Opens the documentation formspec for the player showing the specified entry in a category
2016-08-30 14:25:24 -07:00
function doc.show_entry(playername, category_id, entry_id, ignore_hidden)
if doc.get_category_count() <= 0 then
minetest.show_formspec(playername, "doc:error_no_categories", doc.formspec_error_no_categories())
return
end
2016-12-28 10:19:03 -08:00
local entry, category_id, entry_id = get_entry(category_id, entry_id)
2016-08-30 14:25:24 -07:00
if ignore_hidden or doc.entry_revealed(playername, category_id, entry_id) then
local playerdata = doc.data.players[playername]
playerdata.category = category_id
playerdata.entry = entry_id
2016-08-30 14:25:24 -07:00
doc.mark_entry_as_viewed(playername, category_id, entry_id)
playerdata.entry_textlist_needs_updating = true
doc.generate_entry_list(category_id, playername)
playerdata.catsel = playerdata.catsel_list[entry_id]
playerdata.galidx = 1
local formspec = doc.formspec_core(3)..doc.formspec_entry(category_id, entry_id, playername)
2016-08-30 14:25:24 -07:00
minetest.show_formspec(playername, "doc:entry", formspec)
else
minetest.show_formspec(playername, "doc:error_hidden", doc.formspec_error_hidden(category_id, entry_id))
end
end
2016-07-24 05:59:09 -07:00
-- Returns true if and only if:
-- * The specified category exists
-- * This category contains the specified entry
-- Aliases are taken into account
2016-07-24 05:59:09 -07:00
function doc.entry_exists(category_id, entry_id)
2016-12-28 10:19:03 -08:00
return get_entry(category_id, entry_id) ~= nil
2016-07-24 05:59:09 -07:00
end
2016-11-18 05:46:37 -08:00
-- Sets the order of categories in the category list
function doc.set_category_order(categories)
local reverse_categories = {}
for cid=1,#categories do
reverse_categories[categories[cid]] = cid
end
doc.data.category_order = categories
for cid, cat in pairs(doc.data.categories) do
if reverse_categories[cid] == nil then
table.insert(doc.data.category_order, cid)
end
end
reverse_categories = {}
for cid=1, #doc.data.category_order do
reverse_categories[categories[cid]] = cid
end
for cid, cat in pairs(doc.data.categories) do
cat.order_position = reverse_categories[cid]
end
if set_category_order_was_called then
minetest.log("warning", "[doc] doc.set_category_order was called again!")
end
set_category_order_was_called = true
end
-- Adds an alias for an entry. Attempting to open an entry by an alias name
2016-07-25 09:28:51 -07:00
-- results in opening the entry of the original name.
function doc.add_entry_alias(category_id_orig, entry_id_orig, category_id_alias, entry_id_alias)
if not doc.data.aliases[category_id_alias] then
doc.data.aliases[category_id_alias] = {}
2016-07-25 09:28:51 -07:00
end
doc.data.aliases[category_id_alias][entry_id_alias] = { category_id = category_id_orig, entry_id = entry_id_orig }
2016-07-25 09:38:18 -07:00
end
-- Returns number of categories
function doc.get_category_count()
2016-12-12 03:47:40 -08:00
return doc.data.category_count
end
-- Returns number of entries in category
function doc.get_entry_count(category_id)
return doc.data.categories[category_id].entry_count
end
-- Returns how many entries have been viewed by the player
function doc.get_viewed_count(playername, category_id)
local playerdata = doc.data.players[playername]
if playerdata == nil then
return nil
end
local count = playerdata.stored_data.viewed_count[category_id]
if count == nil then
playerdata.stored_data.viewed[category_id] = {}
count = 0
playerdata.stored_data.viewed_count[category_id] = count
return count
else
return count
end
end
2016-08-30 14:00:50 -07:00
-- Returns how many entries have been revealed by the player
function doc.get_revealed_count(playername, category_id)
local playerdata = doc.data.players[playername]
if playerdata == nil then
2016-08-30 14:00:50 -07:00
return nil
end
local count = playerdata.stored_data.revealed_count[category_id]
2016-08-30 14:00:50 -07:00
if count == nil then
playerdata.stored_data.revealed[category_id] = {}
count = doc.get_entry_count(category_id) - doc.data.categories[category_id].hidden_count
playerdata.stored_data.revealed_count[category_id] = count
return count
2016-08-30 14:00:50 -07:00
else
return count
end
end
2016-10-06 21:15:42 -07:00
-- Returns how many entries are hidden from the player
function doc.get_hidden_count(playername, category_id)
local playerdata = doc.data.players[playername]
if playerdata == nil then
return nil
end
local total = doc.get_entry_count(category_id)
local rcount = playerdata.stored_data.revealed_count[category_id]
if rcount == nil then
return total
else
return total - rcount
end
end
-- Returns the currently viewed entry and/or category of the player
function doc.get_selection(playername)
local playerdata = doc.data.players[playername]
if playerdata ~= nil then
local cat = playerdata.category
if cat then
local entry = playerdata.entry
if entry then
return cat, entry
else
return cat
end
else
return nil
end
else
return nil
end
end
-- Template function templates, to be used for build_formspec in doc.add_category
doc.entry_builders = {}
2016-10-08 18:03:09 -07:00
-- Scrollable freeform text
doc.entry_builders.text = function(data)
local formstring = doc.widgets.text(data, doc.FORMSPEC.ENTRY_START_X, doc.FORMSPEC.ENTRY_START_Y, doc.FORMSPEC.ENTRY_WIDTH - 0.4, doc.FORMSPEC.ENTRY_HEIGHT)
return formstring
2016-10-08 18:03:09 -07:00
end
2016-11-29 10:15:58 -08:00
-- Scrollable freeform text with an optional standard gallery (3 rows, 3:2 aspect ratio)
doc.entry_builders.text_and_gallery = function(data, playername)
-- How much height the image gallery “steals” from the text widget
local stolen_height = 0
local formstring = ""
-- Only add the gallery if images are in the data, otherwise, the text widget gets all of the space
if data.images ~= nil then
local gallery
gallery, stolen_height = doc.widgets.gallery(data.images, playername, nil, doc.FORMSPEC.ENTRY_END_Y + 0.2, nil, nil, nil, nil, false)
2016-11-29 10:15:58 -08:00
formstring = formstring .. gallery
end
formstring = formstring .. doc.widgets.text(data.text,
doc.FORMSPEC.ENTRY_START_X,
doc.FORMSPEC.ENTRY_START_Y,
doc.FORMSPEC.ENTRY_WIDTH - 0.4,
2016-11-29 10:15:58 -08:00
doc.FORMSPEC.ENTRY_HEIGHT - stolen_height)
return formstring
end
2016-10-08 18:03:09 -07:00
doc.widgets = {}
-- Scrollable freeform text
doc.widgets.text = function(data, x, y, width, height)
2016-11-07 12:30:03 -08:00
if x == nil then
x = doc.FORMSPEC.ENTRY_START_X
end
-- Offset to table[], which was used for this in a previous version
local xfix = x + 0.35
2016-11-07 12:30:03 -08:00
if y == nil then
y = doc.FORMSPEC.ENTRY_START_Y
end
if width == nil then
width = doc.FORMSPEC.ENTRY_WIDTH
end
if height == nil then
height = doc.FORMSPEC.ENTRY_HEIGHT
end
-- Weird offset for textarea[]
local heightfix = height + 1
-- Also add background box
local formstring = "box["..tostring(x-0.175)..","..tostring(y)..";"..tostring(width)..","..tostring(height)..";#000000]" ..
"textarea["..tostring(xfix)..","..tostring(y)..";"..tostring(width)..","..tostring(heightfix)..";;;"..minetest.formspec_escape(data).."]"
return formstring
end
2016-11-29 04:37:18 -08:00
-- Image gallery
2016-11-29 09:14:09 -08:00
-- Currently, only one gallery per entry is supported. TODO: Add support for multiple galleries in an entry (low priority)
doc.widgets.gallery = function(imagedata, playername, x, y, aspect_ratio, width, rows, align_left, align_top)
if playername == nil then return nil end -- emergency exit
2016-11-29 04:37:18 -08:00
local formstring = ""
-- Defaults
if x == nil then
if align_left == false then
x = doc.FORMSPEC.ENTRY_END_X
else
x = doc.FORMSPEC.ENTRY_START_X
end
end
if y == nil then
if align_top == false then
y = doc.FORMSPEC.ENTRY_END_Y
else
y = doc.FORMSPEC.ENTRY_START_Y
end
end
2016-11-29 04:37:18 -08:00
if width == nil then width = doc.FORMSPEC.ENTRY_WIDTH end
if rows == nil then rows = 3 end
if align_left == false then
x = x - width
end
local imageindex = doc.data.players[playername].galidx
2016-11-29 07:40:41 -08:00
doc.data.players[playername].maxgalidx = #imagedata
2016-11-29 07:51:12 -08:00
doc.data.players[playername].galrows = rows
2016-11-29 04:37:18 -08:00
if aspect_ratio == nil then aspect_ratio = (2/3) end
local pos = 0
local totalimagewidth, iw, ih
local bw = 0.5
local buttonoffset = 0
if #imagedata > rows then
totalimagewidth = width - bw*2
iw = totalimagewidth / rows
ih = iw * aspect_ratio
if align_top == false then
y = y - ih
end
local tt
if imageindex > 1 then
formstring = formstring .. "button["..x..","..y..";"..bw..","..ih..";doc_button_gallery_prev;"..F("<").."]"
if rows == 1 then
tt = F("Show previous image")
else
tt = F("Show previous gallery page")
end
formstring = formstring .. "tooltip[doc_button_gallery_prev;"..tt.."]"
2016-11-29 07:51:12 -08:00
end
if (imageindex + rows) <= #imagedata then
local rightx = buttonoffset + (x + rows * iw)
formstring = formstring .. "button["..rightx..","..y..";"..bw..","..ih..";doc_button_gallery_next;"..F(">").."]"
if rows == 1 then
tt = F("Show next image")
else
tt = F("Show next gallery page")
end
formstring = formstring .. "tooltip[doc_button_gallery_next;"..tt.."]"
2016-11-29 07:51:12 -08:00
end
2016-11-29 04:37:18 -08:00
buttonoffset = bw
else
totalimagewidth = width
iw = totalimagewidth / rows
ih = iw * aspect_ratio
if align_top == false then
y = y - ih
end
2016-11-29 04:37:18 -08:00
end
for i=imageindex, math.min(#imagedata, (imageindex-1)+rows) do
2016-12-05 04:36:47 -08:00
local xoffset = buttonoffset + (x + pos * iw)
2016-12-02 08:20:51 -08:00
local nx = xoffset - 0.2
local ny = y - 0.05
2016-12-07 02:21:01 -08:00
if imagedata[i].imagetype == "item" then
formstring = formstring .. "item_image["..xoffset..","..y..";"..iw..","..ih..";"..imagedata[i].image.."]"
else
formstring = formstring .. "image["..xoffset..","..y..";"..iw..","..ih..";"..imagedata[i].image.."]"
end
2016-12-02 08:20:51 -08:00
formstring = formstring .. "label["..nx..","..ny..";"..i.."]"
2016-11-29 04:37:18 -08:00
pos = pos + 1
end
local bw, bh
2016-11-29 09:14:09 -08:00
return formstring, ih
2016-11-29 04:37:18 -08:00
end
2016-08-02 15:54:58 -07:00
-- Direct formspec
doc.entry_builders.formspec = function(data)
2016-08-02 15:54:58 -07:00
return data
end
2016-08-29 03:29:55 -07:00
--[[ Internal stuff ]]
-- Loading and saving player data
do
local filepath = minetest.get_worldpath().."/doc.mt"
local file = io.open(filepath, "r")
if file then
minetest.log("action", "[doc] doc.mt opened.")
local string = file:read()
io.close(file)
if(string ~= nil) then
local savetable = minetest.deserialize(string)
for name, players_stored_data in pairs(savetable.players_stored_data) do
doc.data.players[name] = {}
doc.data.players[name].stored_data = players_stored_data
end
minetest.log("action", "[doc] doc.mt successfully read.")
2016-08-29 03:29:55 -07:00
end
end
end
function doc.save_to_file()
local savetable = {}
savetable.players_stored_data = {}
for name, playerdata in pairs(doc.data.players) do
savetable.players_stored_data[name] = playerdata.stored_data
end
local savestring = minetest.serialize(savetable)
local filepath = minetest.get_worldpath().."/doc.mt"
local file = io.open(filepath, "w")
if file then
file:write(savestring)
io.close(file)
minetest.log("action", "[doc] Wrote player data into "..filepath..".")
else
minetest.log("error", "[doc] Failed to write player data into "..filepath..".")
end
end
minetest.register_on_leaveplayer(function(player)
doc.save_to_file()
end)
minetest.register_on_shutdown(function()
2016-12-27 13:53:37 -08:00
minetest.log("action", "[doc] Server shuts down. Player data is about to be saved.")
2016-08-29 03:29:55 -07:00
doc.save_to_file()
end)
--[[ Functions for internal use ]]
2015-03-11 05:30:00 -07:00
function doc.formspec_core(tab)
if tab == nil then tab = 1 else tab = tostring(tab) end
return "size["..doc.FORMSPEC.WIDTH..","..doc.FORMSPEC.HEIGHT.."]"..
"tabheader[0,0;doc_header;"..
2016-10-12 21:10:24 -07:00
minetest.formspec_escape(S("Category list")) .. "," ..
minetest.formspec_escape(S("Entry list")) .. "," ..
minetest.formspec_escape(S("Entry")) .. ";"
2019-03-16 19:06:06 -07:00
..tab..";false;false]"
2019-03-16 22:26:30 -07:00
-- Let the Game decide on the style, such as background, etc.
2015-03-11 05:30:00 -07:00
end
function doc.formspec_main(playername)
local formstring = "textarea[0.35,0;"..doc.FORMSPEC.WIDTH..",1;;;"..minetest.formspec_escape(DOC_INTRO) .. "\n"
local notify_checkbox_x, notify_checkbox_y
if doc.get_category_count() >= 1 then
2016-10-12 21:10:24 -07:00
formstring = formstring .. F("Please select a category you wish to learn more about:").."]"
if doc.get_category_count() <= (CATEGORYFIELDSIZE.WIDTH * CATEGORYFIELDSIZE.HEIGHT) then
local y = 1
local x = 1
2016-11-18 05:46:37 -08:00
-- Show all categories in order
2016-11-07 05:12:49 -08:00
for c=1,#doc.data.category_order do
local id = doc.data.category_order[c]
local data = doc.data.categories[id]
2016-12-15 03:24:40 -08:00
local bw = doc.FORMSPEC.WIDTH / math.floor(((doc.data.category_count-1) / CATEGORYFIELDSIZE.HEIGHT)+1)
2016-11-18 05:46:37 -08:00
-- Skip categories which do not exist
if data ~= nil then
-- Category buton
2016-12-15 03:24:40 -08:00
local button = "button["..((x-1)*bw)..","..y..";"..bw..",1;doc_button_category_"..id..";"..minetest.formspec_escape(data.def.name).."]"
2016-11-18 05:46:37 -08:00
local tooltip = ""
-- Optional description
if data.def.description ~= nil then
tooltip = "tooltip[doc_button_category_"..id..";"..minetest.formspec_escape(data.def.description).."]"
end
formstring = formstring .. button .. tooltip
y = y + 1
if y > CATEGORYFIELDSIZE.HEIGHT then
x = x + 1
y = 1
end
2016-11-07 05:12:49 -08:00
end
end
notify_checkbox_x = 0
notify_checkbox_y = doc.FORMSPEC.HEIGHT-0.5
2016-11-07 05:12:49 -08:00
else
2016-11-07 13:00:41 -08:00
formstring = formstring .. "textlist[0,1;"..(doc.FORMSPEC.WIDTH-0.2)..","..(doc.FORMSPEC.HEIGHT-2)..";doc_mainlist;"
2016-11-07 05:12:49 -08:00
for c=1,#doc.data.category_order do
local id = doc.data.category_order[c]
local data = doc.data.categories[id]
formstring = formstring .. minetest.formspec_escape(data.def.name)
if c < #doc.data.category_order then
formstring = formstring .. ","
end
end
local sel = doc.data.categories[doc.data.players[playername].category]
if sel ~= nil then
formstring = formstring .. ";"
formstring = formstring .. doc.data.categories[doc.data.players[playername].category].order_position
end
formstring = formstring .. "]"
2016-11-07 13:00:41 -08:00
formstring = formstring .. "button[0,"..(doc.FORMSPEC.HEIGHT-1)..";3,1;doc_button_goto_category;"..F("Show category").."]"
notify_checkbox_x = 3.5
notify_checkbox_y = doc.FORMSPEC.HEIGHT-1
end
local text
if minetest.get_modpath("central_message") then
text = F("Notify me when new help is available")
else
text = F("Play notification sound when new help is available")
end
formstring = formstring .. "checkbox["..notify_checkbox_x..","..notify_checkbox_y..";doc_setting_notify_on_reveal;"..text..";"..
tostring(doc.data.players[playername].stored_data.notify_on_reveal == true) .. "]"
else
formstring = formstring .. "]"
2015-03-11 08:24:00 -07:00
end
return formstring
2015-03-11 05:30:00 -07:00
end
function doc.formspec_error_no_categories()
local formstring = "size[8,6]textarea[0.25,0;8,6;;"
2016-10-12 21:10:24 -07:00
formstring = formstring ..
2016-11-03 11:20:03 -07:00
minetest.formspec_escape(
2016-12-27 10:07:41 -08:00
colorize(COLOR_ERROR, S("Error: No help available.")) .. "\n\n" ..
2019-03-16 00:13:31 -07:00
S("No categories have been registered, but they are required to provide help.").."\n"..
S("The Documentation System [doc] does not come with help contents on its own, it needs additional mods to add help content. Please make sure such mods are enabled on for this world, and try again.")) .. "\n\n" ..
S("Recommended mods: doc_basics, doc_items, doc_identifier, doc_encyclopedia.")
2016-10-12 21:10:24 -07:00
formstring = formstring .. ";]button_exit[3,5;2,1;okay;"..F("OK").."]"
return formstring
end
2016-08-30 14:25:24 -07:00
function doc.formspec_error_hidden(category_id, entry_id)
local formstring = "size[8,6]textarea[0.25,0;8,6;;"
formstring = formstring .. minetest.formspec_escape(
2016-12-27 10:07:41 -08:00
colorize(COLOR_ERROR, S("Error: Access denied.")) .. "\n\n" ..
2016-12-15 04:45:01 -08:00
S("Access to the requested entry has been denied; this entry is secret. You may unlock access by progressing in the game. Figure out on your own how to unlock this entry."))
2016-10-12 21:10:24 -07:00
formstring = formstring .. ";]button_exit[3,5;2,1;okay;"..F("OK").."]"
2016-08-30 14:25:24 -07:00
return formstring
end
2015-03-11 11:01:51 -07:00
function doc.generate_entry_list(cid, playername)
local formstring
if doc.data.players[playername].entry_textlist == nil
or doc.data.players[playername].catsel_list == nil
or doc.data.players[playername].category ~= cid
or doc.data.players[playername].entry_textlist_needs_updating == true then
2016-11-07 13:00:41 -08:00
local entry_textlist = "textlist[0,1;"..(doc.FORMSPEC.WIDTH-0.2)..","..(doc.FORMSPEC.HEIGHT-2)..";doc_catlist;"
2015-03-11 09:28:09 -07:00
local counter = 0
2015-03-11 10:48:20 -07:00
doc.data.players[playername].entry_ids = {}
2015-05-16 12:02:34 -07:00
local entries = doc.get_sorted_entry_names(cid)
doc.data.players[playername].catsel_list = {}
2015-05-16 12:02:34 -07:00
for i=1, #entries do
local eid = entries[i]
local edata = doc.data.categories[cid].entries[eid]
2016-08-30 14:00:50 -07:00
if doc.entry_revealed(playername, cid, eid) then
2016-08-15 09:47:58 -07:00
table.insert(doc.data.players[playername].entry_ids, eid)
doc.data.players[playername].catsel_list[eid] = counter + 1
2016-08-15 09:47:58 -07:00
-- Colorize entries based on viewed status
2016-12-23 08:55:20 -08:00
local viewedprefix = COLOR_NOT_VIEWED
2016-10-30 12:27:13 -07:00
local name = edata.name
if name == nil or name == "" then
2016-12-15 04:27:36 -08:00
name = S("Nameless entry (@1)", eid)
2016-10-30 12:27:13 -07:00
if doc.entry_viewed(playername, cid, eid) then
viewedprefix = "#FF4444"
else
2016-12-23 09:01:13 -08:00
viewedprefix = COLOR_ERROR
2016-10-30 12:27:13 -07:00
end
elseif doc.entry_viewed(playername, cid, eid) then
2016-12-23 08:55:20 -08:00
viewedprefix = COLOR_VIEWED
2016-08-15 09:47:58 -07:00
end
2016-10-30 12:27:13 -07:00
entry_textlist = entry_textlist .. viewedprefix .. minetest.formspec_escape(name) .. ","
2016-08-15 09:47:58 -07:00
counter = counter + 1
2016-07-31 11:54:47 -07:00
end
2015-03-11 09:28:09 -07:00
end
if counter >= 1 then
2015-03-11 10:48:20 -07:00
entry_textlist = string.sub(entry_textlist, 1, #entry_textlist-1)
end
2015-03-11 09:51:41 -07:00
local catsel = doc.data.players[playername].catsel
if catsel then
2015-03-11 10:48:20 -07:00
entry_textlist = entry_textlist .. ";"..catsel
2015-03-11 09:51:41 -07:00
end
2015-03-11 10:48:20 -07:00
entry_textlist = entry_textlist .. "]"
doc.data.players[playername].entry_textlist = entry_textlist
formstring = entry_textlist
doc.data.players[playername].entry_textlist_needs_updating = false
2015-03-11 10:48:20 -07:00
else
formstring = doc.data.players[playername].entry_textlist
end
return formstring
end
2015-05-16 12:02:34 -07:00
function doc.get_sorted_entry_names(cid)
local sort_table = {}
local entry_table = {}
2016-08-12 11:09:46 -07:00
local cat = doc.data.categories[cid]
2016-08-13 01:19:34 -07:00
local used_eids = {}
-- Helper function to extract the entry ID out of the output table
local extract = function(entry_table)
local eids = {}
for k,v in pairs(entry_table) do
local eid = v.eid
table.insert(eids, eid)
end
return eids
end
2016-08-13 01:19:34 -07:00
-- Predefined sorting
if cat.def.sorting == "custom" then
for i=1,#cat.def.sorting_data do
local new_entry = table.copy(cat.entries[cat.def.sorting_data[i]])
new_entry.eid = cat.def.sorting_data[i]
table.insert(entry_table, new_entry)
used_eids[cat.def.sorting_data[i]] = true
end
end
2016-08-12 11:09:46 -07:00
for eid,entry in pairs(cat.entries) do
2015-05-16 12:02:34 -07:00
local new_entry = table.copy(entry)
new_entry.eid = eid
2016-08-13 01:19:34 -07:00
if not used_eids[eid] then
table.insert(entry_table, new_entry)
end
2015-05-16 12:02:34 -07:00
table.insert(sort_table, entry.name)
end
2016-08-13 01:19:34 -07:00
if cat.def.sorting == "custom" then
return extract(entry_table)
2016-08-13 01:19:34 -07:00
else
table.sort(sort_table)
end
2015-05-16 12:02:34 -07:00
local reverse_sort_table = table.copy(sort_table)
for i=1, #sort_table do
reverse_sort_table[sort_table[i]] = i
end
2016-08-12 11:09:46 -07:00
local comp
if cat.def.sorting ~= "nosort" then
2016-08-13 04:30:38 -07:00
-- Sorting by user function
if cat.def.sorting == "function" then
comp = cat.def.sorting_data
2016-08-13 01:19:34 -07:00
-- Alphabetic sorting
2016-08-13 04:30:38 -07:00
elseif cat.def.sorting == "abc" or cat.def.sorting == nil then
2016-08-12 11:09:46 -07:00
comp = function(e1, e2)
if reverse_sort_table[e1.name] < reverse_sort_table[e2.name] then return true else return false end
end
end
2016-08-13 04:30:38 -07:00
table.sort(entry_table, comp)
2015-05-16 12:02:34 -07:00
end
return extract(entry_table)
2015-05-16 12:02:34 -07:00
end
2015-03-11 10:48:20 -07:00
function doc.formspec_category(id, playername)
local formstring
if id == nil then
formstring = "label[0,0;"..F("Help > (No Category)") .. "]"
formstring = formstring .. "label[0,0.5;"..F("You haven't chosen a category yet. Please choose one in the category list first.").."]"
formstring = formstring .. "button[0,1;3,1;doc_button_goto_main;"..F("Go to category list").."]"
2015-03-11 10:48:20 -07:00
else
2016-12-15 04:27:36 -08:00
formstring = "label[0,0;"..minetest.formspec_escape(S("Help > @1", doc.data.categories[id].def.name)).."]"
local total = doc.get_entry_count(id)
if total >= 1 then
local revealed = doc.get_revealed_count(playername, id)
if revealed == 0 then
2019-03-16 00:13:31 -07:00
formstring = formstring .. "label[0,0.5;"..minetest.formspec_escape(S("Currently all entries in this category are hidden from you.").."\n"..S("Unlock new entries by progressing in the game.")).."]"
2016-10-12 21:10:24 -07:00
formstring = formstring .. "button[0,1.5;3,1;doc_button_goto_main;"..F("Go to category list").."]"
else
2016-10-12 21:10:24 -07:00
formstring = formstring .. "label[0,0.5;"..F("This category has the following entries:").."]"
formstring = formstring .. doc.generate_entry_list(id, playername)
2016-11-07 13:00:41 -08:00
formstring = formstring .. "button[0,"..(doc.FORMSPEC.HEIGHT-1)..";3,1;doc_button_goto_entry;"..F("Show entry").."]"
2016-12-15 04:27:36 -08:00
formstring = formstring .. "label["..(doc.FORMSPEC.WIDTH-4)..","..(doc.FORMSPEC.HEIGHT-1)..";"..minetest.formspec_escape(S("Number of entries: @1", total)).."\n"
local viewed = doc.get_viewed_count(playername, id)
local hidden = total - revealed
local new = total - viewed - hidden
-- TODO/FIXME: Check if number of hidden/viewed entries is always correct
if viewed < total then
2016-12-27 10:07:41 -08:00
formstring = formstring .. colorize(COLOR_NOT_VIEWED, minetest.formspec_escape(S("New entries: @1", new)))
if hidden > 0 then
formstring = formstring .. "\n"
2016-12-27 10:07:41 -08:00
formstring = formstring .. colorize(COLOR_HIDDEN, minetest.formspec_escape(S("Hidden entries: @1", hidden))).."]"
else
formstring = formstring .. "]"
end
2016-08-31 12:24:53 -07:00
else
2016-10-12 21:10:24 -07:00
formstring = formstring .. F("All entries read.").."]"
2016-08-31 12:24:53 -07:00
end
end
2016-08-03 17:21:15 -07:00
else
2016-10-12 21:10:24 -07:00
formstring = formstring .. "label[0,0.5;"..F("This category is empty.").."]"
formstring = formstring .. "button[0,1.5;3,1;doc_button_goto_main;"..F("Go to category list").."]"
2016-08-03 17:21:15 -07:00
end
end
return formstring
2015-03-11 05:30:00 -07:00
end
2016-08-12 08:14:26 -07:00
function doc.formspec_entry_navigation(category_id, entry_id)
if doc.get_entry_count(category_id) < 1 then
return ""
end
2016-08-12 08:14:26 -07:00
local formstring = ""
formstring = formstring .. "button["..(doc.FORMSPEC.WIDTH-2)..","..(doc.FORMSPEC.HEIGHT-0.5)..";1,1;doc_button_goto_prev;"..F("<").."]"
formstring = formstring .. "button["..(doc.FORMSPEC.WIDTH-1)..","..(doc.FORMSPEC.HEIGHT-0.5)..";1,1;doc_button_goto_next;"..F(">").."]"
2016-10-12 21:10:24 -07:00
formstring = formstring .. "tooltip[doc_button_goto_prev;"..F("Show previous entry").."]"
formstring = formstring .. "tooltip[doc_button_goto_next;"..F("Show next entry").."]"
2016-08-12 08:14:26 -07:00
return formstring
end
function doc.formspec_entry(category_id, entry_id, playername)
2015-03-11 09:10:22 -07:00
local formstring
if category_id == nil then
formstring = "label[0,0;"..F("Help > (No Category)") .. "]"
formstring = formstring .. "label[0,0.5;"..F("You haven't chosen a category yet. Please choose one in the category list first.").."]"
2016-10-12 21:10:24 -07:00
formstring = formstring .. "button[0,1;3,1;doc_button_goto_main;"..F("Go to category list").."]"
2015-03-11 09:10:22 -07:00
elseif entry_id == nil then
2016-12-15 04:27:36 -08:00
formstring = "label[0,0;"..minetest.formspec_escape(S("Help > @1 > (No Entry)", doc.data.categories[category_id].def.name)) .. "]"
2016-08-03 17:32:32 -07:00
if doc.get_entry_count(category_id) >= 1 then
2016-10-12 21:10:24 -07:00
formstring = formstring .. "label[0,0.5;"..F("You haven't chosen an entry yet. Please choose one in the entry list first.").."]"
formstring = formstring .. "button[0,1.5;3,1;doc_button_goto_category;"..F("Go to entry list").."]"
2016-08-03 17:32:32 -07:00
else
2016-10-12 21:10:24 -07:00
formstring = formstring .. "label[0,0.5;"..F("This category does not have any entries.").."]"
formstring = formstring .. "button[0,1.5;3,1;doc_button_goto_main;"..F("Go to category list").."]"
2016-08-03 17:32:32 -07:00
end
2015-03-11 09:10:22 -07:00
else
2016-07-25 09:28:51 -07:00
2015-03-11 09:10:22 -07:00
local category = doc.data.categories[category_id]
2016-12-28 10:19:03 -08:00
local entry = get_entry(category_id, entry_id)
local ename = entry.name
if ename == nil or ename == "" then
2016-12-15 04:27:36 -08:00
ename = S("Nameless entry (@1)", entry_id)
2016-10-30 12:27:13 -07:00
end
2020-03-10 10:28:46 -07:00
formstring = "style_type[textarea;textcolor=#FFFFFF]"
formstring = formstring .. "label[0,0;"..minetest.formspec_escape(S("Help > @1 > @2", category.def.name, ename)).."]"
formstring = formstring .. category.def.build_formspec(entry.data, playername)
2016-08-12 08:14:26 -07:00
formstring = formstring .. doc.formspec_entry_navigation(category_id, entry_id)
2015-03-11 09:10:22 -07:00
end
return formstring
2015-03-11 05:30:00 -07:00
end
function doc.process_form(player,formname,fields)
local playername = player:get_player_name()
--[[ process clicks on the tab header ]]
if(formname == "doc:main" or formname == "doc:category" or formname == "doc:entry") then
if fields.doc_header ~= nil then
local tab = tonumber(fields.doc_header)
local formspec, subformname, contents
local cid, eid
cid = doc.data.players[playername].category
eid = doc.data.players[playername].entry
2015-03-11 05:30:00 -07:00
if(tab==1) then
contents = doc.formspec_main(playername)
2015-03-11 05:30:00 -07:00
subformname = "main"
elseif(tab==2) then
contents = doc.formspec_category(cid, playername)
2015-03-11 05:30:00 -07:00
subformname = "category"
elseif(tab==3) then
doc.data.players[playername].galidx = 1
contents = doc.formspec_entry(cid, eid, playername)
if cid ~= nil and eid ~= nil then
doc.mark_entry_as_viewed(playername, cid, eid)
end
2015-03-11 05:30:00 -07:00
subformname = "entry"
end
formspec = doc.formspec_core(tab)..contents
minetest.show_formspec(playername, "doc:" .. subformname, formspec)
return
end
end
2015-03-11 09:26:19 -07:00
if(formname == "doc:main") then
for cid,_ in pairs(doc.data.categories) do
if fields["doc_button_category_"..cid] then
2015-03-11 09:51:41 -07:00
doc.data.players[playername].catsel = nil
doc.data.players[playername].category = cid
doc.data.players[playername].entry = nil
doc.data.players[playername].entry_textlist_needs_updating = true
local formspec = doc.formspec_core(2)..doc.formspec_category(cid, playername)
2015-03-11 09:26:19 -07:00
minetest.show_formspec(playername, "doc:category", formspec)
break
end
end
if fields["doc_mainlist"] then
local event = minetest.explode_textlist_event(fields["doc_mainlist"])
local cid = doc.data.category_order[event.index]
if cid ~= nil then
if event.type == "CHG" then
doc.data.players[playername].catsel = nil
doc.data.players[playername].category = cid
doc.data.players[playername].entry = nil
doc.data.players[playername].entry_textlist_needs_updating = true
elseif event.type == "DCL" then
doc.data.players[playername].catsel = nil
doc.data.players[playername].category = cid
doc.data.players[playername].entry = nil
doc.data.players[playername].entry_textlist_needs_updating = true
local formspec = doc.formspec_core(2)..doc.formspec_category(cid, playername)
minetest.show_formspec(playername, "doc:category", formspec)
end
end
end
if fields["doc_button_goto_category"] then
local cid = doc.data.players[playername].category
doc.data.players[playername].catsel = nil
doc.data.players[playername].entry = nil
doc.data.players[playername].entry_textlist_needs_updating = true
local formspec = doc.formspec_core(2)..doc.formspec_category(cid, playername)
minetest.show_formspec(playername, "doc:category", formspec)
end
if fields["doc_setting_notify_on_reveal"] then
doc.data.players[playername].stored_data.notify_on_reveal = fields["doc_setting_notify_on_reveal"] == "true"
end
2015-03-11 09:26:19 -07:00
elseif(formname == "doc:category") then
2015-03-11 09:36:44 -07:00
if fields["doc_button_goto_entry"] then
2015-03-11 10:48:20 -07:00
local cid = doc.data.players[playername].category
if cid ~= nil then
local eid = nil
local eids, catsel = doc.data.players[playername].entry_ids, doc.data.players[playername].catsel
if eids ~= nil and catsel ~= nil then
eid = eids[catsel]
end
doc.data.players[playername].galidx = 1
local formspec = doc.formspec_core(3)..doc.formspec_entry(cid, eid, playername)
2015-03-11 10:48:20 -07:00
minetest.show_formspec(playername, "doc:entry", formspec)
2016-07-31 11:54:47 -07:00
doc.mark_entry_as_viewed(playername, cid, eid)
2015-03-11 10:48:20 -07:00
end
2015-03-11 09:36:44 -07:00
end
2015-03-11 11:12:14 -07:00
if fields["doc_button_goto_main"] then
local formspec = doc.formspec_core(1)..doc.formspec_main(playername)
2015-03-11 11:12:14 -07:00
minetest.show_formspec(playername, "doc:main", formspec)
end
2015-03-11 09:51:41 -07:00
if fields["doc_catlist"] then
local event = minetest.explode_textlist_event(fields["doc_catlist"])
if event.type == "CHG" then
doc.data.players[playername].catsel = event.index
2015-03-11 10:53:40 -07:00
doc.data.players[playername].entry = doc.data.players[playername].entry_ids[event.index]
doc.data.players[playername].entry_textlist_needs_updating = true
2016-07-24 02:29:57 -07:00
elseif event.type == "DCL" then
local cid = doc.data.players[playername].category
local eid = nil
local eids, catsel = doc.data.players[playername].entry_ids, event.index
if eids ~= nil and catsel ~= nil then
eid = eids[catsel]
end
doc.mark_entry_as_viewed(playername, cid, eid)
doc.data.players[playername].entry_textlist_needs_updating = true
doc.data.players[playername].galidx = 1
local formspec = doc.formspec_core(3)..doc.formspec_entry(cid, eid, playername)
2016-07-24 02:29:57 -07:00
minetest.show_formspec(playername, "doc:entry", formspec)
2015-03-11 09:51:41 -07:00
end
end
2015-03-11 09:26:19 -07:00
elseif(formname == "doc:entry") then
2015-03-11 11:12:14 -07:00
if fields["doc_button_goto_main"] then
local formspec = doc.formspec_core(1)..doc.formspec_main(playername)
2015-03-11 11:12:14 -07:00
minetest.show_formspec(playername, "doc:main", formspec)
elseif fields["doc_button_goto_category"] then
local formspec = doc.formspec_core(2)..doc.formspec_category(doc.data.players[playername].category, playername)
minetest.show_formspec(playername, "doc:category", formspec)
elseif fields["doc_button_goto_next"] then
if doc.data.players[playername].catsel == nil then return end -- emergency exit
local eids = doc.data.players[playername].entry_ids
local cid = doc.data.players[playername].category
local new_catsel= doc.data.players[playername].catsel + 1
local new_eid = eids[new_catsel]
if #eids > 1 and new_catsel <= #eids then
doc.mark_entry_as_viewed(playername, cid, new_eid)
doc.data.players[playername].catsel = new_catsel
doc.data.players[playername].entry = new_eid
doc.data.players[playername].galidx = 1
local formspec = doc.formspec_core(3)..doc.formspec_entry(cid, new_eid, playername)
minetest.show_formspec(playername, "doc:entry", formspec)
end
elseif fields["doc_button_goto_prev"] then
if doc.data.players[playername].catsel == nil then return end -- emergency exit
local eids = doc.data.players[playername].entry_ids
local cid = doc.data.players[playername].category
local new_catsel= doc.data.players[playername].catsel - 1
local new_eid = eids[new_catsel]
if #eids > 1 and new_catsel >= 1 then
doc.mark_entry_as_viewed(playername, cid, new_eid)
doc.data.players[playername].catsel = new_catsel
doc.data.players[playername].entry = new_eid
doc.data.players[playername].galidx = 1
local formspec = doc.formspec_core(3)..doc.formspec_entry(cid, new_eid, playername)
minetest.show_formspec(playername, "doc:entry", formspec)
end
elseif fields["doc_button_gallery_prev"] then
local cid, eid = doc.get_selection(playername)
2016-11-29 07:51:12 -08:00
if doc.data.players[playername].galidx - doc.data.players[playername].galrows > 0 then
doc.data.players[playername].galidx = doc.data.players[playername].galidx - doc.data.players[playername].galrows
end
local formspec = doc.formspec_core(3)..doc.formspec_entry(cid, eid, playername)
minetest.show_formspec(playername, "doc:entry", formspec)
elseif fields["doc_button_gallery_next"] then
local cid, eid = doc.get_selection(playername)
2016-11-29 07:51:12 -08:00
if doc.data.players[playername].galidx + doc.data.players[playername].galrows <= doc.data.players[playername].maxgalidx then
doc.data.players[playername].galidx = doc.data.players[playername].galidx + doc.data.players[playername].galrows
2016-11-29 07:40:41 -08:00
end
local formspec = doc.formspec_core(3)..doc.formspec_entry(cid, eid, playername)
minetest.show_formspec(playername, "doc:entry", formspec)
2015-03-11 11:12:14 -07:00
end
2016-12-28 05:10:21 -08:00
else
if fields["doc_inventory_plus"] and minetest.get_modpath("inventory_plus") then
doc.show_doc(playername)
return
end
2015-03-11 09:26:19 -07:00
end
2015-03-11 05:30:00 -07:00
end
minetest.register_on_player_receive_fields(doc.process_form)
2016-12-12 04:09:17 -08:00
minetest.register_chatcommand("helpform", {
2015-03-11 05:30:00 -07:00
params = "",
2016-12-12 04:09:17 -08:00
description = S("Open a window providing help entries about Minetest and more"),
2015-03-11 05:30:00 -07:00
privs = {},
func = function(playername, param)
doc.show_doc(playername)
end,
}
)
2015-03-11 09:51:41 -07:00
minetest.register_on_joinplayer(function(player)
2016-07-31 11:54:47 -07:00
local playername = player:get_player_name()
local playerdata = doc.data.players[playername]
if playerdata == nil then
2016-08-29 03:29:55 -07:00
-- Initialize player data
doc.data.players[playername] = {}
playerdata = doc.data.players[playername]
-- Gallery index, stores current index of first displayed image in a gallery
playerdata.galidx = 1
2016-11-29 07:40:41 -08:00
-- Maximum gallery index (index of last image in gallery)
playerdata.maxgalidx = 1
2016-11-29 07:51:12 -08:00
-- Number of rows in an gallery of the current entry
playerdata.galrows = 1
2016-08-29 03:29:55 -07:00
-- Table for persistant data
playerdata.stored_data = {}
2016-08-29 03:29:55 -07:00
-- Contains viewed entries
playerdata.stored_data.viewed = {}
2016-08-29 03:29:55 -07:00
-- Count viewed entries
playerdata.stored_data.viewed_count = {}
2016-08-30 14:00:50 -07:00
-- Contains revealed/unhidden entries
playerdata.stored_data.revealed = {}
2016-08-30 14:00:50 -07:00
-- Count revealed entries
playerdata.stored_data.revealed_count = {}
else
-- Completely rebuild viewed and revealed counts from scratch
for cid, cat in pairs(doc.data.categories) do
if playerdata.stored_data.viewed[cid] == nil then
playerdata.stored_data.viewed[cid] = {}
end
if playerdata.stored_data.revealed[cid] == nil then
playerdata.stored_data.revealed[cid] = {}
end
local vc = 0
local rc = doc.get_entry_count(cid) - doc.data.categories[cid].hidden_count
for eid, entry in pairs(cat.entries) do
if playerdata.stored_data.viewed[cid][eid] then
vc = vc + 1
playerdata.stored_data.revealed[cid][eid] = true
end
if playerdata.stored_data.revealed[cid][eid] and entry.hidden then
rc = rc + 1
end
end
playerdata.stored_data.viewed_count[cid] = vc
playerdata.stored_data.revealed_count[cid] = rc
end
2016-08-29 03:29:55 -07:00
end
2016-12-28 05:10:21 -08:00
-- Add button for Inventory++
if minetest.get_modpath("inventory_plus") ~= nil then
inventory_plus.register_button(player, "doc_inventory_plus", S("Help"))
end
2015-03-11 09:51:41 -07:00
end)
2016-07-29 17:14:24 -07:00
---[[ Add buttons for inventory mods ]]
2016-12-07 10:14:38 -08:00
local button_action = function(player)
doc.show_doc(player:get_player_name())
end
2016-07-29 17:14:24 -07:00
-- Unified Inventory
if minetest.get_modpath("unified_inventory") ~= nil then
unified_inventory.register_button("doc", {
type = "image",
image = "doc_button_icon_hires.png",
2016-12-12 03:42:18 -08:00
tooltip = S("Help"),
2016-12-07 10:14:38 -08:00
action = button_action,
2016-07-29 17:14:24 -07:00
})
end
2016-12-07 10:14:38 -08:00
-- sfinv_buttons
if minetest.get_modpath("sfinv_buttons") ~= nil then
sfinv_buttons.register_button("doc", {
image = "doc_button_icon_lores.png",
tooltip = S("Collection of help texts"),
2016-12-12 03:42:18 -08:00
title = S("Help"),
2016-12-07 10:14:38 -08:00
action = button_action,
})
end
2016-12-12 04:09:17 -08:00
minetest.register_privilege("help_reveal", {
description = S("Allows you to reveal all hidden help entries with /help_reveal"),
give_to_singleplayer = false
})
2016-12-12 04:09:17 -08:00
minetest.register_chatcommand("help_reveal", {
params = "",
2016-12-12 04:09:17 -08:00
description = S("Reveal all hidden help entries to you"),
2016-12-12 04:59:20 -08:00
privs = { help_reveal = true },
func = function(name, param)
doc.mark_all_entries_as_revealed(name)
end,
})