minetest_doc/init.lua
2016-08-02 00:01:51 +02:00

394 lines
13 KiB
Lua

doc = {}
doc.VERSION = {}
doc.VERSION.MAJOR = 0
doc.VERSION.MINOR = 2
doc.VERSION.PATCH = 0
doc.VERSION.STRING = doc.VERSION.MAJOR.."."..doc.VERSION.MINOR.."."..doc.VERSION.PATCH
doc.data = {}
doc.data.categories = {}
doc.data.category_order = {}
doc.data.players = {}
-- Space for additional APIs
doc.sub = {}
--[[ Core API functions ]]
-- Add a new category
function doc.new_category(id, def)
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].def = def
doc.data.categories[id].entry_aliases = {}
table.insert(doc.data.category_order, id)
return true
else
return false
end
end
-- Add a new entry
function doc.new_entry(category_id, entry_id, def)
if doc.data.categories[category_id] ~= nil then
doc.data.categories[category_id].entries[entry_id] = def
doc.data.categories[category_id].entry_count = doc.data.categories[category_id].entry_count + 1
return true
else
return false
end
end
-- Marks a particular entry as viewed by a certain player
function doc.mark_entry_as_viewed(playername, category_id, entry_id)
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
if 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
end
end
-- Returns true if the specified entry has been viewed by the player
function doc.entry_viewed(playername, category_id, entry_id)
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
-- Opens the main documentation formspec for the player
function doc.show_doc(playername)
local formspec = doc.formspec_core()..doc.formspec_main()
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)
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
function doc.show_entry(playername, category_id, entry_id)
doc.data.players[playername].catsel = nil
doc.data.players[playername].category = category_id
doc.data.players[playername].entry = entry_id
doc.mark_entry_as_viewed(playername, category_id, entry_id)
local eids, catsel = doc.data.players[playername].entry_ids, doc.data.players[playername].catsel
local formspec = doc.formspec_core(3)..doc.formspec_entry(category_id, entry_id)
minetest.show_formspec(playername, "doc:entry", formspec)
end
-- Returns true if and only if:
-- * The specified category exists
-- * This category contains the specified entry
function doc.entry_exists(category_id, entry_id)
if doc.data.categories[category_id] ~= nil then
if doc.data.categories[category_id].entries[entry_id] ~= nil then
-- Entry exists
return true
else
-- Entry of this ID does not exist, so we check if there's an alis for it
return doc.data.categories[category_id].entry_aliases[entry_id] ~= nil
end
else
return false
end
end
-- Adds aliases for an entry. Attempting to open an entry by an alias name
-- results in opening the entry of the original name.
-- Aliases are true within one category only.
function doc.add_entry_aliases(category_id, entry_id, aliases)
for a=1,#aliases do
doc.data.categories[category_id].entry_aliases[aliases[a]] = entry_id
end
end
-- Same as above, but only adds one alias
function doc.add_entry_alias(category_id, entry_id, alias)
doc.data.categories[category_id].entry_aliases[alias] = entry_id
end
-- Returns number of categories
function doc.get_category_count()
return #doc.data.category_order
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)
if doc.data.players[playername] == nil then
return nil
end
local count = doc.data.players[playername].stored_data.viewed_count[category_id]
if count == nil then
return 0
else
return count
end
end
--[[ Functions for internal use ]]
function doc.formspec_core(tab)
if tab == nil then tab = 1 else tab = tostring(tab) end
return "size[12,9]tabheader[0,0;doc_header;Main,Category,Entry;"..tab..";true;false]"
end
function doc.formspec_main()
local y = 1
local formstring = "label[0,0;Available help topics:]"
for c=1,#doc.data.category_order do
local id = doc.data.category_order[c]
local data = doc.data.categories[id]
local button = "button[0,"..y..";3,1;doc_button_category_"..id..";"..minetest.formspec_escape(data.def.name).."]"
formstring = formstring .. button
y = y + 1
end
return formstring
end
function doc.generate_entry_list(cid, playername)
local formstring
if doc.data.players[playername].entry_textlist == nil
or doc.data.players[playername].category ~= cid
or doc.data.players[playername].entry_textlist_needs_updating == true then
local entry_textlist = "textlist[0,1;11,7;doc_catlist;"
local counter = 0
doc.data.players[playername].entry_ids = {}
local entries = doc.get_sorted_entry_names(cid)
for i=1, #entries do
local eid = entries[i].eid
table.insert(doc.data.players[playername].entry_ids, eid)
-- Colorize entries based on viewed status
-- Not viewed: Cyan
local viewedprefix = "#00FFFF"
if doc.entry_viewed(playername, cid, eid) then
-- Viewed: White
viewedprefix = "#FFFFFF"
end
entry_textlist = entry_textlist .. viewedprefix .. minetest.formspec_escape(entries[i].name) .. ","
counter = counter + 1
end
if counter >= 1 then
entry_textlist = string.sub(entry_textlist, 1, #entry_textlist-1)
end
local catsel = doc.data.players[playername].catsel
if catsel then
entry_textlist = entry_textlist .. ";"..catsel
end
entry_textlist = entry_textlist .. "]"
doc.data.players[playername].entry_textlist = entry_textlist
formstring = entry_textlist
doc.data.players[playername].entry_testlist_needs_updating = false
else
formstring = doc.data.players[playername].entry_textlist
end
return formstring
end
function doc.get_sorted_entry_names(cid)
local sort_table = {}
local entry_table = {}
for eid,entry in pairs(doc.data.categories[cid].entries) do
local new_entry = table.copy(entry)
new_entry.eid = eid
table.insert(entry_table, new_entry)
table.insert(sort_table, entry.name)
end
table.sort(sort_table)
local reverse_sort_table = table.copy(sort_table)
for i=1, #sort_table do
reverse_sort_table[sort_table[i]] = i
end
local comp = function(e1, e2)
if reverse_sort_table[e1.name] < reverse_sort_table[e2.name] then return true else return false end
end
table.sort(entry_table, comp)
return entry_table
end
function doc.formspec_category(id, playername)
local formstring
if id == nil then
formstring = "label[0,0;You haven't selected a help topic yet. Please select one in the category list first.]"
formstring = formstring .. "button[0,1;3,1;doc_button_goto_main;Go to category list]"
else
formstring = "label[0,0;Current help topic: "..doc.data.categories[id].def.name.."]"
formstring = formstring .. "label[0,0.5;Available entries:]"
formstring = formstring .. doc.generate_entry_list(id, playername)
formstring = formstring .. "button[0,8;3,1;doc_button_goto_entry;Show entry]"
end
return formstring
end
function doc.formspec_entry(category_id, entry_id)
local formstring
if category_id == nil then
formstring = "label[0,0;You haven't selected a help topic yet. Please select one in the category list first.]"
formstring = formstring .. "button[0,1;3,1;doc_button_goto_main;Go to category list]"
elseif entry_id == nil then
formstring = "label[0,0;You haven't selected an help entry yet. Please select one in the list of entries first.]"
formstring = formstring .. "button[0,1;3,1;doc_button_goto_category;Go to entry list]"
else
local category = doc.data.categories[category_id]
local entry = category.entries[entry_id]
-- Check if entry has an alias
if entry == nil then
local resolved_alias = doc.data.categories[category_id].entry_aliases[entry_id]
if resolved_alias ~= nil then
entry = category.entries[resolved_alias]
end
end
formstring = "label[0,0;Help > "..category.def.name.." > "..entry.name.."]"
formstring = formstring .. category.def.build_formspec(entry.data)
end
return formstring
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
if(tab==1) then
contents = doc.formspec_main()
subformname = "main"
elseif(tab==2) then
contents = doc.formspec_category(cid, playername)
subformname = "category"
elseif(tab==3) then
contents = doc.formspec_entry(cid, eid)
if cid ~= nil and eid ~= nil then
doc.mark_entry_as_viewed(playername, cid, eid)
end
subformname = "entry"
end
formspec = doc.formspec_core(tab)..contents
minetest.show_formspec(playername, "doc:" .. subformname, formspec)
return
end
end
if(formname == "doc:main") then
for id,category in pairs(doc.data.categories) do
if fields["doc_button_category_"..id] then
local formspec = doc.formspec_core(2)..doc.formspec_category(id, playername)
doc.data.players[playername].catsel = nil
doc.data.players[playername].category = id
doc.data.players[playername].entry = nil
minetest.show_formspec(playername, "doc:category", formspec)
break
end
end
elseif(formname == "doc:category") then
if fields["doc_button_goto_entry"] then
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
local formspec = doc.formspec_core(3)..doc.formspec_entry(cid, eid)
minetest.show_formspec(playername, "doc:entry", formspec)
doc.mark_entry_as_viewed(playername, cid, eid)
end
end
if fields["doc_button_goto_main"] then
local formspec = doc.formspec_core(1)..doc.formspec_main()
minetest.show_formspec(playername, "doc:main", formspec)
end
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
doc.data.players[playername].entry = doc.data.players[playername].entry_ids[event.index]
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
local formspec = doc.formspec_core(3)..doc.formspec_entry(cid, eid)
minetest.show_formspec(playername, "doc:entry", formspec)
doc.mark_entry_as_viewed(playername, cid, eid)
end
end
elseif(formname == "doc:entry") then
if fields["doc_button_goto_main"] then
local formspec = doc.formspec_core(1)..doc.formspec_main()
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)
end
end
end
minetest.register_on_player_receive_fields(doc.process_form)
minetest.register_chatcommand("doc", {
params = "",
description = "Open documentation system.",
privs = {},
func = function(playername, param)
doc.show_doc(playername)
end,
}
)
minetest.register_on_joinplayer(function(player)
local playername = player:get_player_name()
doc.data.players[playername] = {}
-- Table for persistant data
doc.data.players[playername].stored_data = {}
-- Contains viewed entries
doc.data.players[playername].stored_data.viewed = {}
-- Count viewed entries
doc.data.players[playername].stored_data.viewed_count = {}
end)
minetest.register_on_leaveplayer(function(player)
doc.data.players[player:get_player_name()] = nil
end)
---[[ Add buttons for inventory mods ]]
-- Unified Inventory
if minetest.get_modpath("unified_inventory") ~= nil then
unified_inventory.register_button("doc", {
type = "image",
image = "doc_button_icon_hires.png",
tooltip = "Documentation System",
action = function(player)
doc.show_doc(player:get_player_name())
end,
})
end