1 local S
=minetest
.get_translator("mcl_books")
3 local max_text_length
= 4500 -- TODO: Increase to 12800 when scroll bar was added to written book
4 local max_title_length
= 64
7 if minetest
.get_modpath("mcl_init") then
8 header
= "no_prepend[]" .. mcl_vars
.gui_nonbg
.. mcl_vars
.gui_bg_color
..
9 "style_type[button;border=false;bgimg=mcl_books_button9.png;bgimg_pressed=mcl_books_button9_pressed.png;bgimg_middle=2,2]"
13 minetest
.register_craftitem("mcl_books:book", {
14 description
= S("Book"),
15 _doc_items_longdesc
= S("Books are used to make bookshelves and book and quills."),
16 inventory_image
= "default_book.png",
18 groups
= { book
=1, craftitem
= 1 },
21 if minetest
.get_modpath("mcl_core") and minetest
.get_modpath("mcl_mobitems") then
22 minetest
.register_craft({
24 output
= 'mcl_books:book',
25 recipe
= { 'mcl_core:paper', 'mcl_core:paper', 'mcl_core:paper', 'mcl_mobitems:leather', }
29 -- Get the included text out of the book item
30 -- itemstack: Book item
31 -- meta: Meta of book (optional)
32 local get_text
= function(itemstack
)
34 local meta
= itemstack
:get_meta()
35 local text
= meta
:get_string("text")
37 -- Backwards-compability with MCL2 0.21.0
38 -- Remember that get_metadata is deprecated since MT 0.4.16!
39 if text
== nil or text
== "" then
40 local meta_legacy
= itemstack
:get_metadata()
41 if itemstack
:get_name() == "mcl_books:written_book" then
42 local des
= minetest
.deserialize(meta_legacy
)
58 local make_description
= function(title
, author
, generation
)
60 if generation
== 0 then
61 desc
= S("“@1”", title
)
62 elseif generation
== 1 then
63 desc
= S("Copy of “@1”", title
)
64 elseif generation
== 2 then
65 desc
= S("Copy of Copy of “@1”", title
)
67 desc
= S("Tattered Book")
69 desc
= desc
.. "\n" .. minetest
.colorize("#AAAAAA", S("by @1", author
))
73 local cap_text_length
= function(text
, max_length
)
74 return string.sub(text
, 1, max_length
)
77 local write = function(itemstack
, user
, pointed_thing
)
78 -- Call on_rightclick if the pointed node defines it
79 if pointed_thing
.type == "node" then
80 local node
= minetest
.get_node(pointed_thing
.under
)
81 if user
and not user
:get_player_control().sneak
then
82 if minetest
.registered_nodes
[node
.name
] and minetest
.registered_nodes
[node
.name
].on_rightclick
then
83 return minetest
.registered_nodes
[node
.name
].on_rightclick(pointed_thing
.under
, node
, user
, itemstack
) or itemstack
88 local text
= get_text(itemstack
)
89 local formspec
= "size[8,9]"..
91 "background[-0.5,-0.5;9,10;mcl_books_book_bg.png]"..
92 "textarea[0.75,0.1;7.25,9;text;;"..minetest
.formspec_escape(text
).."]"..
93 "button[0.75,7.95;3,1;sign;"..minetest
.formspec_escape(S("Sign")).."]"..
94 "button_exit[4.25,7.95;3,1;ok;"..minetest
.formspec_escape(S("Done")).."]"
95 minetest
.show_formspec(user
:get_player_name(), "mcl_books:writable_book", formspec
)
98 local read = function(itemstack
, user
, pointed_thing
)
99 -- Call on_rightclick if the pointed node defines it
100 if pointed_thing
.type == "node" then
101 local node
= minetest
.get_node(pointed_thing
.under
)
102 if user
and not user
:get_player_control().sneak
then
103 if minetest
.registered_nodes
[node
.name
] and minetest
.registered_nodes
[node
.name
].on_rightclick
then
104 return minetest
.registered_nodes
[node
.name
].on_rightclick(pointed_thing
.under
, node
, user
, itemstack
) or itemstack
109 local text
= get_text(itemstack
)
110 local formspec
= "size[8,9]"..
112 "background[-0.5,-0.5;9,10;mcl_books_book_bg.png]"..
113 "textarea[0.75,0.1;7.25,9;;"..minetest
.formspec_escape(text
)..";]"..
114 "button_exit[2.25,7.95;3,1;ok;"..minetest
.formspec_escape(S("Done")).."]"
115 minetest
.show_formspec(user
:get_player_name(), "mcl_books:written_book", formspec
)
119 minetest
.register_craftitem("mcl_books:writable_book", {
120 description
= S("Book and Quill"),
121 _tt_help
= S("Write down some notes"),
122 _doc_items_longdesc
= S("This item can be used to write down some notes."),
123 _doc_items_usagehelp
= S("Hold it in the hand, then rightclick to read the current notes and edit then. You can edit the text as often as you like. You can also sign the book which turns it into a written book which you can stack, but it can't be edited anymore.").."\n"..
124 S("A book can hold up to 4500 characters. The title length is limited to 64 characters."),
125 inventory_image
= "mcl_books_book_writable.png",
129 on_secondary_use
= write,
132 minetest
.register_on_player_receive_fields(function ( player
, formname
, fields
)
133 if ((formname
== "mcl_books:writable_book") and fields
and fields
.text
) then
134 local stack
= player
:get_wielded_item()
135 if (stack
:get_name() and (stack
:get_name() == "mcl_books:writable_book")) then
136 local meta
= stack
:get_meta()
137 local text
= cap_text_length(fields
.text
, max_text_length
)
139 meta
:set_string("text", text
)
140 player
:set_wielded_item(stack
)
141 elseif fields
.sign
then
142 meta
:set_string("text", text
)
143 player
:set_wielded_item(stack
)
145 local name
= player
:get_player_name()
146 local formspec
= "size[8,9]"..
148 "background[-0.5,-0.5;9,10;mcl_books_book_bg.png]"..
149 "field[0.75,1;7.25,1;title;"..minetest
.formspec_escape(minetest
.colorize("#000000", S("Enter book title:")))..";]"..
150 "label[0.75,1.5;"..minetest
.formspec_escape(minetest
.colorize("#404040", S("by @1", name
))).."]"..
151 "button_exit[0.75,7.95;3,1;sign;"..minetest
.formspec_escape(S("Sign and Close")).."]"..
152 "tooltip[sign;"..minetest
.formspec_escape(S("Note: The book will no longer be editable after signing")).."]"..
153 "button[4.25,7.95;3,1;cancel;"..minetest
.formspec_escape(S("Cancel")).."]"
154 minetest
.show_formspec(player
:get_player_name(), "mcl_books:signing", formspec
)
157 elseif ((formname
== "mcl_books:signing") and fields
and fields
.sign
and fields
.title
) then
158 local newbook
= ItemStack("mcl_books:written_book")
159 local book
= player
:get_wielded_item()
160 local name
= player
:get_player_name()
161 if book
:get_name() == "mcl_books:writable_book" then
162 local title
= fields
.title
163 if string.len(title
) == 0 then
164 title
= S("Nameless Book")
166 title
= cap_text_length(title
, max_title_length
)
167 local meta
= newbook
:get_meta()
168 local text
= cap_text_length(get_text(book
), max_text_length
)
169 meta
:set_string("title", title
)
170 meta
:set_string("author", name
)
171 meta
:set_string("text", text
)
172 meta
:set_string("description", make_description(title
, name
, 0))
174 -- The book copy counter. 0 = original, 1 = copy of original, 2 = copy of copy of original, …
175 meta
:set_int("generation", 0)
177 player
:set_wielded_item(newbook
)
179 minetest
.log("error", "[mcl_books] "..name
.." failed to sign a book!")
181 elseif ((formname
== "mcl_books:signing") and fields
and fields
.cancel
) then
182 local book
= player
:get_wielded_item()
183 if book
:get_name() == "mcl_books:writable_book" then
184 write(book
, player
, { type = "nothing" })
189 if minetest
.get_modpath("mcl_dye") and minetest
.get_modpath("mcl_mobitems") then
190 minetest
.register_craft({
192 output
= "mcl_books:writable_book",
193 recipe
= { "mcl_books:book", "mcl_dye:black", "mcl_mobitems:feather" },
198 minetest
.register_craftitem("mcl_books:written_book", {
199 description
= S("Written Book"),
200 _doc_items_longdesc
= S("Written books contain some text written by someone. They can be read and copied, but not edited."),
201 _doc_items_usagehelp
= S("Hold it in your hand, then rightclick to read the book.").."\n\n"..
203 S("To copy the text of the written book, place it into the crafting grid together with a book and quill (or multiple of those) and craft. The written book will not be consumed. Copies of copies can not be copied."),
204 inventory_image
= "mcl_books_book_written.png",
205 groups
= { not_in_creative_inventory
=1, book
=1, no_rename
=1 },
208 on_secondary_use
= read
213 -- This adds 8 recipes
214 local baq
= "mcl_books:writable_book"
215 local wb
= "mcl_books:written_book"
220 {baq
, baq
, baq
, baq
, wb
},
221 {baq
, baq
, baq
, baq
, wb
, baq
},
222 {baq
, baq
, baq
, baq
, wb
, baq
, baq
},
223 {baq
, baq
, baq
, baq
, wb
, baq
, baq
, baq
},
224 {baq
, baq
, baq
, baq
, wb
, baq
, baq
, baq
, baq
},
226 for r
=#recipes
, 1, -1 do
227 minetest
.register_craft({
229 output
= "mcl_books:written_book "..r
,
234 minetest
.register_craft_predict(function(itemstack
, player
, old_craft_grid
, craft_inv
)
235 if itemstack
:get_name() ~= "mcl_books:written_book" then
241 for i
= 1, player
:get_inventory():get_size("craft") do
242 if old_craft_grid
[i
]:get_name() == "mcl_books:written_book" then
243 original
= old_craft_grid
[i
]
251 local ometa
= original
:get_meta()
252 local generation
= ometa
:get_int("generation")
254 -- Check generation, don't allow crafting with copy of copy of book
255 if generation
>= 2 then
258 -- Valid copy. Let's update the description field of the result item
259 -- so it is properly displayed in the crafting grid.
260 local imeta
= itemstack
:get_meta()
261 local title
= cap_text_length(ometa
:get_string("title"), max_title_length
)
262 local author
= ometa
:get_string("author")
264 -- Increase book generation and update description
265 generation
= generation
+ 1
266 if generation
< 1 then
270 local desc
= make_description(title
, author
, generation
)
271 imeta
:set_string("description", desc
)
276 minetest
.register_on_craft(function(itemstack
, player
, old_craft_grid
, craft_inv
)
277 if itemstack
:get_name() ~= "mcl_books:written_book" then
283 for i
= 1, player
:get_inventory():get_size("craft") do
284 if old_craft_grid
[i
]:get_name() == "mcl_books:written_book" then
285 original
= old_craft_grid
[i
]
294 local text
= get_text(original
)
295 if not text
or text
== "" then
296 local copymeta
= original
:get_metadata()
297 itemstack
:set_metadata(copymeta
)
299 local ometa
= original
:get_meta()
300 local generation
= ometa
:get_int("generation")
302 -- No copy of copy of copy of book allowed
303 if generation
>= 2 then
308 local imeta
= itemstack
:get_meta()
309 local title
= cap_text_length(ometa
:get_string("title"), max_title_length
)
310 local author
= ometa
:get_string("author")
311 imeta
:set_string("title", title
)
312 imeta
:set_string("author", author
)
313 imeta
:set_string("text", cap_text_length(text
, max_text_length
))
315 -- Increase book generation and update description
316 generation
= generation
+ 1
317 if generation
< 1 then
321 local desc
= make_description(title
, author
, generation
)
323 imeta
:set_string("description", desc
)
324 imeta
:set_int("generation", generation
)
326 -- put the book with metadata back in the craft grid
327 craft_inv
:set_stack("craft", index
, original
)
331 if minetest
.get_modpath("mcl_sounds") then
332 wood_sound
= mcl_sounds
.node_sound_wood_defaults()
336 minetest
.register_node("mcl_books:bookshelf", {
337 description
= S("Bookshelf"),
338 _doc_items_longdesc
= S("Bookshelves are used for decoration."),
339 tiles
= {"mcl_books_bookshelf_top.png", "mcl_books_bookshelf_top.png", "default_bookshelf.png"},
341 is_ground_content
= false,
342 groups
= {handy
=1,axey
=1, flammable
=3,building_block
=1, material_wood
=1, fire_encouragement
=30, fire_flammability
=20},
343 drop
= "mcl_books:book 3",
345 _mcl_blast_resistance
= 1.5,
349 minetest
.register_craft({
350 output
= 'mcl_books:bookshelf',
352 {'group:wood', 'group:wood', 'group:wood'},
353 {'mcl_books:book', 'mcl_books:book', 'mcl_books:book'},
354 {'group:wood', 'group:wood', 'group:wood'},
358 minetest
.register_craft({
360 recipe
= "mcl_books:bookshelf",