- initial beta version
This commit is contained in:
Leslie Krause 2020-02-21 17:42:00 -05:00
commit 66f64f90c9
25 changed files with 937 additions and 0 deletions

193
README.txt Normal file
View File

@ -0,0 +1,193 @@
Books Redux Mod v1.0
By Leslie Krause
Books Redux is full rewrite of default books from Minetest Game, offering players a rich
selection of books and papers for in-game communication.
* Choose from 4 different cover and page styles for books
* Choose from 12 different page styles for papers
* Choose from a wide variety of background color schemes
* Page sizes can range from small, large, wide, and tall
* Bookmarks can be added, removed, or recalled on-the-fly
* Edits to books and papers can be previewed before saving
* Simple page navigation for editing and viewing books
* All content is encrypted using a 128-bit block cipher
* Legacy books can still be viewed in compatibility mode
Even better still, books and papers are both easily craftable using the same traditional
recipes as before: 3 papyrus for one paper, and 3 paper for one book.
With so many possible combinations of sizes, colors, and styles, the design possibilities
are virtually endless! Moreover, custom layout and formatting of text is also possible
using the Bedrock Markup Language. In fact, the editor for books and papers should be
very familiar to those accustomed to the Signs Redux mod.
https://forum.minetest.net/viewtopic.php?f=9&t=23955
Of course, plain-text messages are acceptable as well, as they will render exactly as
they are input, without any fancy colors or styles. Then again, that would be boring ;)
Now for an important word about security....
Last year one of my more vigilant players made me aware that it is possible for anyone
to inspect locked chests on servers with only basic CSM knowledge. This means that
confidential information in written books is vulnerable to intrusion.
Fortunately, Books Redux addresses this very concern by encrypting the content of all
written books and written papers via the Simple Cipher mod. This means that if anyone
gains access to a copy of the map, without the server operator's private key, they
won't be able to examine the personal correspondence of other players.
Currently there is no way to automatically convert legacy books to the new format. It
must be done manually by copying and pasting text into a new book.
Repository
----------------------
Browse source code:
https://bitbucket.org/sorcerykid/books_rx
Download archive:
https://bitbucket.org/sorcerykid/books_rx/get/master.zip
https://bitbucket.org/sorcerykid/books_rx/get/master.tar.gz
Compatability
----------------------
Minetest 0.4.15+ required
Dependencies
----------------------
Default Mod (required)
https://github.com/minetest-game-mods/default
ActiveFormspecs Mod (required)
https://bitbucket.org/sorcerykid/formspecs
Bedrock Markup Language Mod (required)
https://bitbucket.org/sorcerykid/markup
Safety Deposit Mod (required)
https://bitbucket.org/sorcerykid/safety_deposit
Installation
----------------------
1) Unzip the archive into the mods directory of your game
2) Rename the books_rx-master directory to "books_rx"
Source Code License
----------------------------------------------------------
GNU Lesser General Public License v3 (LGPL-3.0)
Copyright (c) 2019-2020, Leslie E. Krause
This program is free software; you can redistribute it and/or modify it under the terms of
the GNU Lesser General Public License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
http://www.gnu.org/licenses/lgpl-2.1.html
Multimedia License (textures, sounds, and models)
----------------------------------------------------------
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
/textures/default_paper_written.png
obtained from https://github.com/Mossmanikin/memorandum
by Mossmanikin
modified by sorcerykid
/textures/book_classic_cover.png
obtained from https://www.onlygfx.com/7-old-book-open-textures-jpg/
by zolee
modified by sorcerykid
/textures/book_classic_front.png
obtained from https://colorlava.com/freebies/book-cover-texture-designs/
modified by sorcerykid
/textures/book_plain_cover.png
obtained from https://www.onlygfx.com/7-old-book-open-textures-jpg/
by zolee
modified by sorcerykid
/textures/book_plain_front.png
obtained from https://colorlava.com/freebies/book-cover-texture-designs/
modified by sorcerykid
/textures/book_vintage_cover.png
obtained from https://www.onlygfx.com/7-old-book-open-textures-jpg/
by zolee
modified by sorcerykid
/textures/book_vintage_front.png
obtained from https://colorlava.com/freebies/book-cover-texture-designs/
modified by sorcerykid
/textures/paper_classic1.png
obtained from http://designbeep.com/2012/09/24/40-free-high-resolution-old-book-textures-for-designers/
modified by sorcerykid
/textures/paper_classic2.png
obtained from http://designbeep.com/2012/09/24/40-free-high-resolution-old-book-textures-for-designers/
modified by sorcerykid
/textures/paper_plain1.png
obtained from http://designbeep.com/2012/09/24/40-free-high-resolution-old-book-textures-for-designers/
modified by sorcerykid
/textures/paper_plain2.png
obtained from http://designbeep.com/2012/09/24/40-free-high-resolution-old-book-textures-for-designers/
modified by sorcerykid
/textures/paper_vintage1.png
obtained from http://designbeep.com/2012/09/24/40-free-high-resolution-old-book-textures-for-designers/
modified by sorcerykid
/textures/paper_vintage2.png
obtained from http://designbeep.com/2012/09/24/40-free-high-resolution-old-book-textures-for-designers/
modified by sorcerykid
/textures/paper_vintage3.png
obtained from http://designbeep.com/2012/09/24/40-free-high-resolution-old-book-textures-for-designers/
modified by sorcerykid
/textures/paper_vintage4.png
obtained from http://designbeep.com/2012/09/24/40-free-high-resolution-old-book-textures-for-designers/
modified by sorcerykid
You are free to:
Share — copy and redistribute the material in any medium or format.
Adapt — remix, transform, and build upon the material for any purpose, even commercially.
The licensor cannot revoke these freedoms as long as you follow the license terms.
Under the following terms:
Attribution — You must give appropriate credit, provide a link to the license, and
indicate if changes were made. You may do so in any reasonable manner, but not in any way
that suggests the licensor endorses you or your use.
No additional restrictions — You may not apply legal terms or technological measures that
legally restrict others from doing anything the license permits.
Notices:
You do not have to comply with the license for elements of the material in the public
domain or where your use is permitted by an applicable exception or limitation.
No warranties are given. The license may not give you all of the permissions necessary
for your intended use. For example, other rights such as publicity, privacy, or moral
rights may limit how you use the material.
For more details:
http://creativecommons.org/licenses/by-sa/3.0/

13
config.lua Normal file
View File

@ -0,0 +1,13 @@
max_book_title_length = 50
max_book_message_length = 800
max_book_content_length = 5000
max_paper_subject_length = 50
max_paper_message_length = 800
default_book_title = "Untitled"
default_book_scale = "small"
default_book_style = "plain"
default_book_color = "white"
default_paper_subject = "Untitled"
default_paper_scale = "small"
default_paper_style = "plain"
default_paper_color = "white"

4
depends.txt Normal file
View File

@ -0,0 +1,4 @@
default
markup
safety_deposit
config

727
init.lua Normal file
View File

@ -0,0 +1,727 @@
--------------------------------------------------------
-- Minetest :: Books Redux Mod (books_rx)
--
-- See README.txt for licensing and other information.
-- Copyright (c) 2019-2020, Leslie E. Krause
--
-- ./games/minetest_game/mods/books_rx/init.lua
--------------------------------------------------------
local config = minetest.load_config( )
local fs = minetest.formspec_escape
local open_book_viewer, open_book_editor, open_paper_viewer, open_paper_editor
-----------------------
function open_defbook_viewer( player_name, owner, title, text )
local function get_formspec( )
local formspec = "size[8.0,8.5]" ..
default.gui_bg ..
default.gui_bg_img ..
"label[0.3,0.2;Title:]" ..
"label[1.5,0.2;" .. title .. "]" ..
"label[0.3,0.8;By:]" ..
"label[1.5,0.8;" .. owner .. "]" ..
"textarea[0.5,1.5;7.6,7.0;content;;" .. minetest.formspec_escape( text ) .. "]" ..
"button_exit[3.0,7.8;2.0,0.8;close;Close]"
return formspec
end
minetest.create_form( nil, player_name, get_formspec( ) )
end
function open_book_viewer( player_name, oldtime, owner, title, scale, style, color, pages, marks, page_idx, vars, is_preview )
local book_scales = {
small = { width = 12.0, height = 8.5 },
tall = { width = 12.0, height = 11.0 },
large = { width = 15.5, height = 11.0 },
wide = { width = 15.5, height = 8.5 },
}
local book_colors = {
gray = "#333333",
brown = "#663300",
teal = "#006633",
purple = "#330066",
olive = "#336600",
indigo = "#003366",
maroon = "#660033",
red = "#660000",
green = "#006600",
blue = "#000066",
}
local mark_ver = 1
local function add_bookmark( )
if not table.get_index( marks, page_idx ) then
table.insert( marks, page_idx )
table.sort( marks )
end
end
local function del_bookmark( )
local idx = table.get_index( marks, page_idx )
if idx then
table.remove( marks, idx )
end
end
local function get_formspec( )
local page_width = book_scales[ scale ].width / 2
local page_height = book_scales[ scale ].height
local foot_x1 = ( page_width - 4.5 ) / 2 + 0.3 -- horz pos of left-hand footer
local foot_x2 = page_width + ( page_width - 4.5 ) / 2 - 0.3 -- horz pos of right-hand footer
local foot_y = page_height - 1.3 -- vert pos of both footers
if page_idx == 1 then
-- render background and controls of front cover
local formspec =
string.format( "size[%0.2f,%0.2f]", page_width, page_height ) ..
default.gui_bg ..
string.format( "background[0.0,0.0;%0.2f,%0.2f;%s;false]", page_width, page_height,
fs( "book_" .. style .. "_front.png^[colorize:" .. book_colors[ color ] .. "66^[noalpha" ) ) ..
string.format( "%s[%0.2f,%0.2f;2.0,1.0;close;Close]",
is_preview and "button" or "button_exit", foot_x1 + 0.8, foot_y ) ..
string.format( "button[%0.2f,%0.2f;1.0,1.0;next_page;>>]",
foot_x1 + 2.7, foot_y )
-- render front cover content
local page_x1 = 0.8
local page_y1 = 0.5
local page_x2 = page_x1 + page_width - 1.4
local page_y2 = page_y1 + page_height - 1.5
formspec = formspec ..
markup.get_formspec_string( markup.parse_message( pages[ page_idx ], vars ),
page_x1, page_y1, page_x2, page_y2, "#666666", "#CCCCCC" )
return formspec
else
-- render background and controls of page
local mark_idx = table.get_index( marks, page_idx )
local formspec =
string.format( "size[%0.2f,%0.2f]", page_width * 2, page_height ) ..
default.gui_bg ..
string.format( "background[0.0,0.0;%0.2f,%0.2f;%s;false]", page_width, page_height,
fs( "book_" .. style .. "_cover.png^[colorize:" .. book_colors[ color ] .. "66^[noalpha" ) ) ..
string.format( "background[%0.2f,0.0;%0.2f,%0.2f;%s;false]", page_width, page_width, page_height,
fs( "book_" .. style .. "_cover.png^[transformFX^[colorize:" .. book_colors[ color ] .. "66^[noalpha" ) ) ..
string.format( "button[%0.2f,%0.2f;1.0,1.0;prev_page;<<]", foot_x2, foot_y ) ..
string.format( "button[%0.2f,%0.2f;1.0,1.0;next_page;>>]", foot_x2 + 1.0, foot_y ) ..
string.format( "%s[%0.2f,%0.2f;2.0,1.0;close;Close]",
is_preview and "button" or "button_exit", foot_x2 + 2.5, foot_y ) ..
string.format( "label[%0.2f,%0.2f;Bookmarks:]", foot_x1, foot_y + 0.2 )
if #marks > 0 then
formspec = formspec ..
string.format( "dropdown[%0.2f,%0.2f;1.8,1.0;marks_%d;,%s;%d;true]", foot_x1 + 1.5, foot_y + 0.1, mark_ver,
table.join( marks, ",", function ( a, b ) return "Page " .. b - 1 end ),
mark_idx and mark_idx + 1 or 1 )
else
formspec = formspec ..
string.format( "dropdown[%0.2f,%0.2f;1.8,1.0;marks;;1;true]", foot_x1 + 1.5, foot_y + 0.1 )
end
if mark_idx then
formspec = formspec ..
string.format( "button[%0.2f,%0.2f;1.2,1.0;del_mark;Del]", foot_x1 + 3.3, foot_y )
else
formspec = formspec ..
string.format( "button[%0.2f,%0.2f;1.2,1.0;add_mark;Add]", foot_x1 + 3.3, foot_y )
end
-- render left-hand page content
local page_x1 = 1.0
local page_y1 = 0.5
local page_x2 = page_x1 + page_width - 1.4
local page_y2 = page_y1 + page_height - 1.8
local text_colors = {
gray = "#999999",
cyan = "#00EEEE",
magenta = "#EE00EE",
yellow = "#EEEE00",
red = "#CC0000",
green = "#00CC00",
blue = "#0000CC",
brown = "#CC9900",
teal = "#00CC99",
purple = "#9900CC",
olive = "#99CC00",
indigo = "#0099CC",
maroon = "#CC0099",
}
formspec = formspec ..
markup.get_formspec_string( markup.parse_message( pages[ page_idx ], vars, { colors = text_colors } ),
page_x1, page_y1, page_x2, page_y2, "#666666", "#CCCCCC" )
if pages[ page_idx + 1 ] then
-- render right-hand page content, if it exists
page_x1 = page_x1 + page_width - 0.6
page_x2 = page_x2 + page_width - 0.6
formspec = formspec .. markup.get_formspec_string( markup.parse_message( pages[ page_idx + 1 ], vars ),
page_x1, page_y1, page_x2, page_y2, "#666666", "#CCCCCC" )
end
return formspec
end
end
local function on_close( meta, player, fields )
local fields_marks = fields[ "marks_" .. mark_ver ]
if fields.close then
if is_preview then
open_book_editor( player_name, oldtime, owner, title, scale, style, color, pages, page_idx, vars )
elseif mark_ver > 1 then
local itemstack = player:get_wielded_item( )
local player_inv = player:get_inventory( )
local data = {
oldtime = oldtime,
owner = owner,
title = title,
scale = scale,
style = style,
color = color,
pages = pages,
marks = marks,
}
safety_deposit.encrypt_metadata( itemstack, data )
player:set_wielded_item( itemstack )
minetest.chat_send_player( player_name, "Your bookmarks were updated!" )
end
elseif fields.next_page then
if page_idx < #pages then
page_idx = page_idx + 1
minetest.update_form( player_name, get_formspec( ) )
end
elseif fields.prev_page then
if page_idx > 1 then
page_idx = page_idx - 1
minetest.update_form( player_name, get_formspec( ) )
end
elseif fields.add_mark then
mark_ver = mark_ver + 1
add_bookmark( page_idx )
minetest.update_form( player_name, get_formspec( ) )
elseif fields.del_mark then
mark_ver = mark_ver + 1
del_bookmark( page_idx )
minetest.update_form( player_name, get_formspec( ) )
elseif fields_marks then -- overcome bug with dropdowns not updating values in older clients
page_idx = marks[ fields_marks - 1 ] or 1
minetest.update_form( player_name, get_formspec( ) )
end
end
-- basic sanity check for proper inputs
if not book_scales[ scale ] then scale = config.default_book_scale end
if not book_colors[ color ] then color = config.default_book_color end
if page_idx < 1 or page_idx > #pages then page_idx = 1 end
minetest.create_form( nil, player_name, get_formspec( ), on_close, is_preview and minetest.FORMSPEC_SIGSTOP or nil )
end
function open_book_editor( player_name, oldtime, owner, title, scale, style, color, pages, page_idx, vars )
local function sanitize( buf )
return string.trim( string.gsub( buf, ".", { ["\r"] = "\n", ["\t"] = " ", ["\f"] = "?", ["\b"] = "?" } ) ) .. "\n"
end
local function get_formspec( )
local book_scales = { "small", "large", "tall", "wide" }
local book_colors = { "gray", "brown", "teal", "purple", "olive", "indigo", "maroon", "red", "green", "blue" }
local book_styles = { "plain", "fancy", "classic", "vintage" }
-- book texture filenames:
-- books_cover_<style>_<scale>.png
-- books_pages_<style>_<scale>.png
local message = pages[ page_idx ]
local formspec =
"size[10.5,10.0]" ..
default.gui_bg ..
default.gui_bg_img ..
"label[0.0,0.1;Book Title:]" ..
"field[1.7,0.2;9.1,1.0;title;;" .. fs( title ) .. "]" ..
"textarea[0.3,1.2;10.5,6.7;message;Enter the message to display on the page (" .. config.max_book_content_length .. " character limit per book);" .. fs( message ) .. "]" ..
"label[0.0,7.3;Book Color:]" ..
"dropdown[1.6,7.2;1.8,1.0;color;" .. table.concat( book_colors, "," ) .. ";" .. table.get_index( book_colors, color, 1 ) .. ";false]" ..
"label[3.5,7.3;Book Style:]" ..
"dropdown[5.1,7.2;1.8,1.0;style;" .. table.concat( book_styles, "," ) .. ";" .. table.get_index( book_styles, style, 1 ) .. ";false]" ..
"label[7.0,7.3;Book Scale:]" ..
"dropdown[8.6,7.2;1.8,1.0;scale;" .. table.concat( book_scales, "," ) .. ";" .. table.get_index( book_scales, scale, 1 ) .. ";false]" ..
"button[0.0,8.3;1.0,0.3;cover_page;|<<]" ..
"button[1.0,8.3;1.0,0.3;prev_page;<<]" ..
"button[2.0,8.3;1.0,0.3;next_page;>>]" ..
"button[3.0,8.3;1.0,0.3;final_page;>>|]" ..
"button[8.5,8.3;2.0,0.3;add_page;Add Page]"
if page_idx == 1 then
formspec = formspec ..
string.format( "label[4.5,8.2;Front Cover]", page_idx == 1 and "Cover" or ( "Page " .. page_idx - 1 ) )
else
formspec = formspec ..
"button[6.5,8.3;2.0,0.3;del_page;Del Page]" ..
string.format( "label[4.5,8.2;Page %d of %d]", page_idx - 1, #pages - 1 )
end
formspec = formspec ..
"box[0.0,9.0;10.3,0.1;#111111]" ..
"button_exit[0.0,9.3;2.0,1.0;cancel;Cancel]" ..
"button[6.5,9.3;2.0,1.0;preview;Preview]" ..
"button_exit[8.5,9.3;2.0,1.0;publish;Publish]"
return formspec
end
local function on_close( meta, player, fields )
if fields.cancel or fields.quit then return end -- no-op when quitting form
if fields.preview or fields.publish then
if not fields.message or not fields.title or not fields.color or not fields.scale or not fields.style then
return
elseif string.len( fields.message ) > config.max_book_message_length then
minetest.chat_send_player( player_name, "The specified message is too long." )
return
elseif string.len( fields.title ) > config.max_book_title_length then
minetest.chat_send_player( player_name, "The specified title too long." )
return
end
pages[ page_idx ] = sanitize( fields.message ) -- update the respective page content before previewing
end
if fields.preview then
open_book_viewer( player_name, oldtime, owner, fields.title, fields.scale, fields.style, fields.color, pages, { }, page_idx, vars, true )
elseif fields.publish then
-- check that book content is within range
local length = 0
for i, v in ipairs( pages ) do
length = length + string.len( v )
end
if length > config.max_book_content_length then
minetest.chat_send_player( player_name, "The content is too long." )
end
-- save all changes to the itemstack meta
local itemstack = player:get_wielded_item( )
local player_inv = player:get_inventory( )
local data = {
oldtime = oldtime,
owner = owner,
scale = scale,
style = style,
color = color,
title = title,
pages = pages,
marks = { }, -- editing clears bookmarks
}
if itemstack:get_name( ) == "default:book" then
itemstack:take_item( 1 ) -- take from unwritten books
player:set_wielded_item( itemstack )
itemstack = ItemStack( "default:book_written" ) -- get reference to new stack
safety_deposit.encrypt_metadata( itemstack, data )
if player_inv:room_for_item( "main", itemstack ) then
player_inv:add_item( "main", itemstack )
else
minetest.add_item( player:getpos( ), itemstack )
end
else
safety_deposit.encrypt_metadata( itemstack, data )
player:set_wielded_item( itemstack )
end
minetest.log( "action", player_name .. " wrote " .. length .. " bytes to a book titled \"" .. string.gsub( fields.title, "[\n\t]", "" ) .. "\"" )
minetest.chat_send_player( player_name, "Your book was successfully published!" )
elseif fields.cover_page then
if page_idx > 1 then
page_idx = 1
minetest.update_form( player_name, get_formspec( ) )
end
elseif fields.final_page then
if page_idx < #pages then
page_idx = #pages
minetest.update_form( player_name, get_formspec( ) )
end
elseif fields.next_page then
if page_idx < #pages then
page_idx = page_idx + 1
minetest.update_form( player_name, get_formspec( ) )
end
elseif fields.prev_page then
if page_idx > 1 then
page_idx = page_idx - 1
minetest.update_form( player_name, get_formspec( ) )
end
elseif fields.add_page then
pages[ page_idx ] = fields.message
table.insert( pages, page_idx + 1, "New Page" )
page_idx = page_idx + 1
minetest.update_form( player_name, get_formspec( ) )
elseif fields.del_page then
if page_idx > 1 then
table.remove( pages, page_idx )
page_idx = page_idx - 1
minetest.update_form( player_name, get_formspec( ) )
end
elseif fields.color then
color = fields.color
elseif fields.style then
style = fields.style
elseif fields.scale then
scale = fields.scale
end
end
minetest.create_form( nil, player_name, get_formspec( ), on_close, minetest.FORMSPEC_SIGSTOP )
end
function open_paper_viewer( player_name, oldtime, owner, scale, style, color, subject, message, vars, is_preview )
local paper_scales = {
small = { width = 6.5, height = 9.0 },
tall = { width = 6.5, height = 11.0 },
large = { width = 8.0, height = 11.0 },
wide = { width = 8.0, height = 9.0 },
}
local paper_colors = {
gray = "#333333",
brown = "#663300",
teal = "#006633",
purple = "#330066",
olive = "#336600",
indigo = "#003366",
maroon = "#660033",
red = "#660000",
green = "#006600",
blue = "#000066",
}
local function get_formspec( )
local page_width = paper_scales[ scale ].width
local page_height = paper_scales[ scale ].height
local foot_x = ( page_width - 2.0 ) / 2 -- horz pos of footer
local foot_y = page_height - 1.2 -- vert pos of footer
local formspec =
string.format( "size[%0.2f,%0.2f]", page_width, page_height ) ..
default.gui_bg ..
string.format( "background[0.0,0.0;%0.2f,%0.2f;%s;false]", page_width, page_height,
fs( "paper_" .. style .. ".png^[colorize:" .. paper_colors[ color ] .. "66^[noalpha" ) ) ..
string.format( "%s[%0.2f,%0.2f;2.0,1.0;close;Close]",
is_preview and "button" or "button_exit", foot_x, foot_y )
if subject ~= "" then
formspec = formspec ..
"label[0.5,0.5;From:]" ..
"label[1.6,0.5;" .. owner .. "]" ..
"label[0.5,1.0;Date:]" ..
"label[1.6,1.0;" .. os.date( "%X", oldtime ) .. "]" ..
"label[0.5,1.5;Subject:]" ..
"label[1.6,1.5;" .. subject .. "]" ..
string.format( "box[0.3,2.1;%0.2f,0.05;#FFFFFF]", page_width - 1.0 )
end
local page_x1 = 0.5
local page_y1 = subject == "" and 0.5 or 2.4
local page_x2 = page_x1 + page_width - 1.0
local page_y2 = subject == "" and page_y1 + page_height - 1.3 or page_y1 + page_height - 3.7
formspec = formspec ..
markup.get_formspec_string( markup.parse_message( message, vars ),
page_x1, page_y1, page_x2, page_y2, "#666666", "#CCCCCC" )
return formspec
end
local function on_close( meta, player, fields )
if fields.close then
if is_preview then
open_paper_editor( player_name, oldtime, owner, scale, style, color, subject, message, vars )
end
end
end
-- basic sanity check for proper inputs
if not paper_scales[ scale ] then scale = config.default_paper_scale end
if not paper_colors[ color ] then color = config.default_paper_color end
minetest.create_form( nil, player_name, get_formspec( ), on_close, is_preview and minetest.FORMSPEC_SIGSTOP or nil )
end
function open_paper_editor( player_name, oldtime, owner, scale, style, color, subject, message, vars )
local function sanitize( buf )
return string.trim( string.gsub( buf, ".", { ["\r"] = "\n", ["\t"] = " ", ["\f"] = "?", ["\b"] = "?" } ) ) .. "\n"
end
local function get_formspec( )
local paper_scales = { "small", "large", "tall", "wide" }
local paper_colors = { "gray", "brown", "teal", "purple", "olive", "indigo", "maroon", "red", "green", "blue" }
local paper_styles = { "plain1", "plain2", "fancy1", "fancy2", "fancy3", "fancy4", "classic1", "classic2", "vintage1", "vintage2", "vintage3", "vintage4" }
local formspec =
"size[10.5,9.5]" ..
default.gui_bg ..
default.gui_bg_img ..
"label[0.0,0.1;Subject:]" ..
"field[1.5,0.2;9.3,1.0;subject;;" .. fs( subject ) .. "]" ..
"textarea[0.3,1.2;10.5,7.0;message;Enter the message to display on the page (" .. config.max_paper_message_length .. " character limit per paper);" .. fs( message ) .. "]" ..
"label[0.0,7.6;Paper Color:]" ..
"dropdown[1.6,7.5;1.8,1.0;color;" .. table.concat( paper_colors, "," ) .. ";" .. table.get_index( paper_colors, color, 1 ) .. ";false]" ..
"label[3.5,7.6;Paper Style:]" ..
"dropdown[5.1,7.5;1.8,1.0;style;" .. table.concat( paper_styles, "," ) .. ";" .. table.get_index( paper_styles, style, 1 ) .. ";false]" ..
"label[7.0,7.6;Paper Scale:]" ..
"dropdown[8.6,7.5;1.8,1.0;scale;" .. table.concat( paper_scales, "," ) .. ";" .. table.get_index( paper_scales, scale, 1 ) .. ";false]" ..
"box[0.0,8.5;10.3,0.1;#111111]" ..
"button_exit[0.0,8.8;2.0,1.0;cancel;Cancel]" ..
"button[6.5,8.8;2.0,1.0;preview;Preview]" ..
"button_exit[8.5,8.8;2.0,1.0;publish;Publish]"
return formspec
end
local function on_close( meta, player, fields )
if fields.cancel then
return
elseif fields.preview or fields.publish then
if not fields.message or not fields.subject or not fields.color or not fields.scale or not fields.style then
return
elseif string.len( fields.message ) > config.max_paper_message_length then
minetest.chat_send_player( player_name, "The specified message is too long." )
return
elseif string.len( fields.subject ) > config.max_paper_subject_length then
minetest.chat_send_player( player_name, "The specified subject is too long." )
return
end
message = sanitize( fields.message )
end
if fields.preview then
open_paper_viewer( player_name, oldtime, owner, fields.scale, fields.style, fields.color, fields.subject, message, vars, true )
elseif fields.publish then
-- save all changes to the itemstack meta
local itemstack = player:get_wielded_item( )
local player_inv = player:get_inventory( )
local data = {
oldtime = oldtime,
owner = owner,
scale = scale,
style = style,
color = color,
subject = subject,
message = message,
marks = { }, -- editing clears bookmarks
}
if itemstack:get_name( ) == "default:paper" then
itemstack:take_item( 1 ) -- take from unwritten books
player:set_wielded_item( itemstack )
itemstack = ItemStack( "default:paper_written" ) -- get reference to new stack
safety_deposit.encrypt_metadata( itemstack, data )
if player_inv:room_for_item( "main", itemstack ) then
player_inv:add_item( "main", itemstack )
else
minetest.add_item( player:getpos( ), itemstack )
end
else
safety_deposit.encrypt_metadata( itemstack, data )
player:set_wielded_item( itemstack )
end
minetest.log( "action", player_name .. " wrote " .. #message .. " bytes to a paper titled \"" .. string.gsub( fields.subject, "[\n\t]", "" ) .. "\"" )
minetest.chat_send_player( player_name, "Your paper was successfully published!" )
elseif fields.color then
color = fields.color
elseif fields.style then
style = fields.style
elseif fields.scale then
scale = fields.scale
end
end
minetest.create_form( nil, player_name, get_formspec( ), on_close, minetest.FORMSPEC_SIGSTOP )
end
local function open_default_book_editor( player_name, vars )
local title = config.default_book_title
local scale = config.default_book_scale
local style = config.default_book_style
local color = config.default_book_color
open_book_editor( player_name, os.time( ), player_name, title, style, scale, color, { "" }, 1, vars )
end
local function open_default_paper_editor( player_name, vars )
local subject = config.default_paper_subject
local color = config.default_paper_color
local style = config.default_paper_style
local scale = config.default_paper_scale
open_paper_editor( player_name, os.time( ), player_name, scale, style, color, subject, "", vars )
end
-----------------------
minetest.register_craftitem( ":default:book", {
description = "Book",
inventory_image = "default_book.png",
groups = { book = 1, flammable = 3 },
on_use = function ( itemstack, player )
local player_name = player:get_player_name( )
local vars = markup.get_builtin_vars( player_name )
open_default_book_editor( player_name, vars )
return itemstack
end,
} )
minetest.register_craftitem( ":default:book_written", {
description = "Book With Text (Sneak and Use to Edit)",
inventory_image = "default_book_written.png",
groups = { book = 1, not_in_creative_inventory = 1, flammable = 3 },
stack_max = 1,
on_use = function ( itemstack, player )
local player_name = player:get_player_name( )
local data = safety_deposit.decrypt_metadata( itemstack )
local vars = markup.get_builtin_vars( player_name )
if not data then
-- apparently book is empty, so let's start fresh
open_default_book_editor( player_name, vars )
return itemstack
end
local oldtime = data.oldtime
local owner = data.owner
local title = data.title
local scale = data.scale
local style = data.style
local color = data.color
local pages = data.pages
local marks = data.marks
-- if book format is obsolete, then open the compatibility viewer
if not pages and data.owner and data.title and data.text then
open_defbook_viewer( player_name, data.owner, data.title, data.text, data.page, data.page_max )
return itemstack
elseif not oldtime or not owner or not title or not scale or not style or not color or not pages or not marks then
minetest.chat_send_player( player_name, "This book is corrupted and cannot be opened." )
return itemstack
end
if player:get_player_control( ).sneak and owner == player_name then
open_book_editor( player_name, oldtime, owner, title, scale, style, color, pages, 1, vars )
else
open_book_viewer( player_name, oldtime, owner, title, scale, style, color, pages, marks, 1, vars )
end
return itemstack
end,
} )
minetest.register_craftitem( ":default:paper", {
description = "Paper",
inventory_image = "default_paper.png",
groups = { flammable = 3 },
on_use = function ( itemstack, player )
local player_name = player:get_player_name( )
local vars = markup.get_builtin_vars( player_name )
open_default_paper_editor( player_name, vars )
return itemstack
end,
} )
minetest.register_craftitem( ":default:paper_written", {
description = "Paper With Text (Sneak and Use to Edit)",
inventory_image = "default_paper.png^default_paper_written.png",
groups = { book = 1, not_in_creative_inventory = 1, flammable = 3 },
stack_max = 1,
on_use = function ( itemstack, player )
local player_name = player:get_player_name( )
local data = safety_deposit.decrypt_metadata( itemstack )
local vars = markup.get_builtin_vars( player_name )
if not data then
-- apparently paper is empty, so let's start fresh
open_default_paper_editor( player_name, vars )
return itemstack
end
local oldtime = data.oldtime
local owner = data.owner
local scale = data.scale
local style = data.style
local color = data.color
local subject = data.subject
local message = data.message
if not oldtime or not owner or not scale or not style or not color or not subject or not message then
minetest.chat_send_player( player_name, "This paper is corrupted and cannot be opened." )
return itemstack
end
if player:get_player_control( ).sneak and owner == player_name then
open_paper_editor( player_name, oldtime, owner, scale, style, color, subject, message, vars )
else
open_paper_viewer( player_name, oldtime, owner, scale, style, color, subject, message, vars )
end
return itemstack
end,
} )

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

BIN
textures/paper_classic1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
textures/paper_classic2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
textures/paper_fancy1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
textures/paper_fancy2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
textures/paper_fancy3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
textures/paper_fancy4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
textures/paper_plain1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
textures/paper_plain2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
textures/paper_vintage1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
textures/paper_vintage2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
textures/paper_vintage3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
textures/paper_vintage4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB