From 21e5f68292c01b2419bdbe410e8ebc15a1627838 Mon Sep 17 00:00:00 2001 From: orbea Date: Sat, 4 Sep 2021 21:37:27 +0000 Subject: [PATCH] default: Improves reading and writing to books. (#2656) * Allow anyone to write to a book without any text and title. * Allows saving books without any text or title. * Adds a "Read" and "Write" tab to written owned books. Fixes #1743 --- mods/default/craftitems.lua | 119 +++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 34 deletions(-) diff --git a/mods/default/craftitems.lua b/mods/default/craftitems.lua index efb26ef3..cf2795c3 100644 --- a/mods/default/craftitems.lua +++ b/mods/default/craftitems.lua @@ -3,6 +3,46 @@ -- support for MT game translation. local S = default.get_translator +local esc = minetest.formspec_escape +local formspec_size = "size[8,8]" + +local function formspec_core(tab) + if tab == nil then tab = 1 else tab = tostring(tab) end + return "tabheader[0,0;book_header;" .. + esc(S("Write")) .. "," .. + esc(S("Read")) .. ";" .. + tab .. ";false;false]" +end + +local function formspec_write(title, text) + return "field[0.5,1;7.5,0;title;" .. esc(S("Title:")) .. ";" .. + esc(title) .. "]" .. + "textarea[0.5,1.5;7.5,7;text;" .. esc(S("Contents:")) .. ";" .. + esc(text) .. "]" .. + "button_exit[2.5,7.5;3,1;save;" .. esc(S("Save")) .. "]" +end + +local function formspec_read(owner, title, string, text, page, page_max) + return "label[0.5,0.5;" .. esc(S("by @1", owner)) .. "]" .. + "tablecolumns[color;text]" .. + "tableoptions[background=#00000000;highlight=#00000000;border=false]" .. + "table[0.4,0;7,0.5;title;#FFFF00," .. esc(title) .. "]" .. + "textarea[0.5,1.5;7.5,7;;" .. + esc(string ~= "" and string or text) .. ";]" .. + "button[2.4,7.6;0.8,0.8;book_prev;<]" .. + "label[3.2,7.7;" .. esc(S("Page @1 of @2", page, page_max)) .. "]" .. + "button[4.9,7.6;0.8,0.8;book_next;>]" +end + +local function formspec_string(lpp, page, lines, string) + for i = ((lpp * page) - lpp) + 1, lpp * page do + if not lines[i] then break end + string = string .. lines[i] .. "\n" + end + return string +end + +local tab_number local lpp = 14 -- Lines per book's page local function book_on_use(itemstack, user) local player_name = user:get_player_name() @@ -19,8 +59,8 @@ local function book_on_use(itemstack, user) local data = meta:to_table().fields if data.owner then - title = data.title - text = data.text + title = data.title or "" + text = data.text or "" owner = data.owner for str in (text .. "\n"):gmatch("([^\n]*)[\n]") do @@ -30,37 +70,26 @@ local function book_on_use(itemstack, user) if data.page then page = data.page page_max = data.page_max - - for i = ((lpp * page) - lpp) + 1, lpp * page do - if not lines[i] then break end - string = string .. lines[i] .. "\n" - end + string = formspec_string(lpp, page, lines, string) end end local formspec - local esc = minetest.formspec_escape - if owner == player_name then - formspec = "size[8,8]" .. - "field[0.5,1;7.5,0;title;" .. esc(S("Title:")) .. ";" .. - esc(title) .. "]" .. - "textarea[0.5,1.5;7.5,7;text;" .. esc(S("Contents:")) .. ";" .. - esc(text) .. "]" .. - "button_exit[2.5,7.5;3,1;save;" .. esc(S("Save")) .. "]" + if title == "" and text == "" then + formspec = formspec_write(title, text) + elseif owner == player_name then + local tab = tab_number or 1 + if tab == 2 then + formspec = formspec_core(tab) .. + formspec_read(owner, title, string, text, page, page_max) + else + formspec = formspec_core(tab) .. formspec_write(title, text) + end else - formspec = "size[8,8]" .. - "label[0.5,0.5;" .. esc(S("by @1", owner)) .. "]" .. - "tablecolumns[color;text]" .. - "tableoptions[background=#00000000;highlight=#00000000;border=false]" .. - "table[0.4,0;7,0.5;title;#FFFF00," .. esc(title) .. "]" .. - "textarea[0.5,1.5;7.5,7;;" .. - minetest.formspec_escape(string ~= "" and string or text) .. ";]" .. - "button[2.4,7.6;0.8,0.8;book_prev;<]" .. - "label[3.2,7.7;" .. esc(S("Page @1 of @2", page, page_max)) .. "]" .. - "button[4.9,7.6;0.8,0.8;book_next;>]" + formspec = formspec_read(owner, title, string, text, page, page_max) end - minetest.show_formspec(player_name, "default:book", formspec) + minetest.show_formspec(player_name, "default:book", formspec_size .. formspec) return itemstack end @@ -69,12 +98,37 @@ local max_title_size = 80 local short_title_size = 35 minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "default:book" then return end + local player_name = player:get_player_name() local inv = player:get_inventory() local stack = player:get_wielded_item() + local data = stack:get_meta():to_table().fields - if fields.save and fields.title and fields.text - and fields.title ~= "" and fields.text ~= "" then - local new_stack, data + local title = data.title or "" + local text = data.text or "" + + if fields.book_header ~= nil and data.owner == player_name then + local contents + local tab = tonumber(fields.book_header) + if tab == 1 then + contents = formspec_core(tab) .. + formspec_write(title, text) + elseif tab == 2 then + local lines, string = {}, "" + for str in (text .. "\n"):gmatch("([^\n]*)[\n]") do + lines[#lines+1] = str + end + string = formspec_string(lpp, data.page, lines, string) + contents = formspec_read(player_name, title, string, + text, data.page, data.page_max) + end + tab_number = tab + local formspec = formspec_size .. formspec_core(tab) .. contents + minetest.show_formspec(player_name, "default:book", formspec) + return + end + + if fields.save and fields.title and fields.text then + local new_stack if stack:get_name() ~= "default:book_written" then local count = stack:get_count() if count == 1 then @@ -83,11 +137,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) stack:set_count(count - 1) new_stack = ItemStack("default:book_written") end - else - data = stack:get_meta():to_table().fields end - if data and data.owner and data.owner ~= player:get_player_name() then + if data.owner ~= player_name and title ~= "" and text ~= "" then return end @@ -117,8 +169,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end elseif fields.book_next or fields.book_prev then - local data = stack:get_meta():to_table().fields - if not data or not data.page then + if not data.page then return end