259 lines
8.0 KiB
Lua
259 lines
8.0 KiB
Lua
local S = minetest.get_translator()
|
|
local F = minetest.formspec_escape
|
|
|
|
local has_doc = minetest.get_modpath("doc_items")
|
|
|
|
gtextitems = {}
|
|
|
|
-- gtextitem item group
|
|
-- This item is blank (stackable, no metadata yet).
|
|
gtextitems.GROUP_BLANK = 1
|
|
-- This item is written (not stackable, has metadata).
|
|
gtextitems.GROUP_WRITTEN = 2
|
|
|
|
if has_doc then
|
|
doc.sub.items.register_factoid(nil, "use", function(itemstring, def)
|
|
local ret = {}
|
|
local g = minetest.get_item_group(itemstring, "gtextitem")
|
|
if g > 0 then
|
|
table.insert(ret, S"This item can be written in when used (punched with).")
|
|
if g == gtextitems.GROUP_WRITTEN then
|
|
table.insert(ret, S("It can be copied by crafting with another empty @1.", minetest.registered_items[def._gtextitems_def.itemname].description))
|
|
end
|
|
end
|
|
return table.concat(ret, "\n")
|
|
end)
|
|
end
|
|
|
|
-- When punching, display the formspec.
|
|
function gtextitems.on_use(stack, player)
|
|
local playername = player:get_player_name()
|
|
|
|
local gtm = gtextitems.get_item(stack)
|
|
if not gtm then
|
|
return stack
|
|
end
|
|
|
|
local formspec = ""
|
|
.. "size[8,8]"
|
|
.. "real_coordinates[true]"
|
|
.. ("field[0.1,0.35;7.8,0.5;title;%s;%s]"):format(F(S"Title:"), F(gtm.title))
|
|
.. "field_close_on_enter[title;false]"
|
|
.. ("textarea[0.1,1.2;7.8,6;text;%s;%s]"):format(F(S"Text:"), F(gtm.text))
|
|
.. "field_close_on_enter[text;false]"
|
|
-- Only display the auther when it is set.
|
|
.. ((minetest.get_item_group(stack:get_name(), "gtextitem") == gtextitems.GROUP_BLANK or #gtm.author == 0) and "" or ("label[0.1,7.5;%s]"):format(F(S("Last written by @1", gtm.author))))
|
|
.. ("button_exit[6.75,7.4;1,0.5;save;%s]"):format(F(S"Write"))
|
|
|
|
minetest.show_formspec(playername, "gtextitems:formspec", formspec)
|
|
return stack
|
|
end
|
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname ~= "gtextitems:formspec" then
|
|
return
|
|
end
|
|
|
|
if not fields.save then
|
|
return
|
|
end
|
|
|
|
-- The wielded item will be the gtextitem.
|
|
local wielded = player:get_wielded_item()
|
|
-- Ensure it's a valid item.
|
|
if not gtextitems.get_item(wielded) then
|
|
return
|
|
end
|
|
|
|
-- Create a new stack of the written item.
|
|
local def = minetest.registered_items[wielded:get_name()]._gtextitems_def
|
|
local stack = ItemStack(def.writtenname)
|
|
|
|
stack = gtextitems.set_item(stack, {
|
|
author = player:get_player_name(),
|
|
author_type = "player",
|
|
title = fields.title,
|
|
text = fields.text,
|
|
})
|
|
|
|
-- Take one item from wielded (if blank, then one from the stack, otherwise the whole written stack).
|
|
wielded:take_item(1)
|
|
player:set_wielded_item(wielded)
|
|
|
|
-- Add the edited item. If it was originally a written item or single item stack, this will simply replace the item removed from wielded earlier.
|
|
minetest.add_item(player:get_pos(), player:get_inventory():add_item("main", stack))
|
|
return true
|
|
end)
|
|
|
|
-- gtextitem data structure.
|
|
local default = {
|
|
-- Who last modified this? If blank, then disregard.
|
|
author = "",
|
|
-- What kind of thing modified this?
|
|
--- Should be "player" if the author is a player name.
|
|
author_type = "",
|
|
title = "Untitled",
|
|
text = "",
|
|
|
|
-- Was this produced by copying?
|
|
copy = false,
|
|
-- Unique ID. Preserved over copies, reset on editing.
|
|
id = nil,
|
|
}
|
|
|
|
-- Add data to a gtextitem and sets description.
|
|
function gtextitems.set_item(stack, data)
|
|
stack:get_meta():set_string("gtextitem", minetest.serialize(data))
|
|
stack:get_meta():set_string("description", S("'@1' by @2@3", gtextitems.get_item(stack).title, gtextitems.get_item(stack).author, data.copy and S" (Copy)" or ""))
|
|
return stack
|
|
end
|
|
|
|
-- Get a gtextitem's data. Returns nil if the item is not a gtextitem.
|
|
function gtextitems.get_item(stack)
|
|
if minetest.get_item_group(stack:get_name(), "gtextitem") == 0 then
|
|
return nil
|
|
end
|
|
|
|
local d = stack:get_meta():get_string("gtextitem")
|
|
return b.t.combine(default, (#d > 0) and minetest.deserialize(d) or {})
|
|
end
|
|
|
|
-- Sets a gtextitem written node's data.
|
|
function gtextitems.set_node(pos, data)
|
|
local nn = minetest.get_node(pos).name
|
|
|
|
-- Only written nodes can be set.
|
|
if minetest.get_item_group(nn, "gtextitem") ~= gtextitems.GROUP_WRITTEN then
|
|
minetest.log("warning", ("Tried to gtextitems.set_node invalid node (%s) at (%s)."):format(nn, minetest.pos_to_string(pos)))
|
|
return
|
|
end
|
|
|
|
-- Construct "fake" stack.
|
|
local stack = gtextitems.set_item(ItemStack(nn), data)
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
meta:set_string("gtextitem", stack:get_meta():get_string("gtextitem"))
|
|
meta:set_string("infotext", stack:get_meta():get_string("description"))
|
|
|
|
local gtm = gtextitems.get_item(stack)
|
|
meta:set_string("formspec", "size[8,8]"
|
|
.. "real_coordinates[true]"
|
|
.. ("label[0.1,0.35;%s]"):format(F(gtm.title))
|
|
.. ("textarea[0.1,1.2;7.8,6.2;;;%s]"):format(F(gtm.text))
|
|
.. ((#gtm.author == 0) and "" or ("label[0.1,7.5;%s]"):format(F(S("Last written by @1", gtm.author))))
|
|
)
|
|
end
|
|
|
|
-- Get a gtextitem written node's data; returns nil if not a valid node or valid data
|
|
function gtextitems.get_node(pos)
|
|
if minetest.get_item_group(minetest.get_node(pos).name, "gtextitem") == gtextitems.GROUP_WRITTEN then
|
|
return minetest.deserialize(minetest.get_meta(pos):get_string("gtextitem"))
|
|
end
|
|
end
|
|
|
|
local function register_node(name, def)
|
|
-- Override def with functions to save and load metadata when converting between item and node.
|
|
local def = b.t.combine(def, {
|
|
preserve_metadata = function(pos, oldnode, oldmeta, drops)
|
|
for _,drop in ipairs(drops) do
|
|
if minetest.get_item_group(drop:get_name(), "gtextitem") == gtextitems.GROUP_WRITTEN then
|
|
drop:get_meta():set_string("gtextitem", oldmeta.gtextitem)
|
|
drop:get_meta():set_string("description", oldmeta.infotext)
|
|
end
|
|
end
|
|
end,
|
|
|
|
after_place_node = function(pos, _, stack)
|
|
-- Don't set any metadata if this is just a blank item.
|
|
if minetest.get_item_group(stack:get_name(), "gtextitem") == gtextitems.GROUP_BLANK then
|
|
return
|
|
end
|
|
gtextitems.set_node(pos, gtextitems.get_item(stack))
|
|
end,
|
|
})
|
|
minetest.register_node(":" .. name, def)
|
|
end
|
|
|
|
function gtextitems.register(name, def)
|
|
def = b.t.combine({
|
|
-- Item names.
|
|
itemname = name,
|
|
writtenname = name .. "_written",
|
|
|
|
-- Register as a node?
|
|
node = false,
|
|
}, def, {
|
|
-- Base item override.
|
|
item = b.t.combine({
|
|
description = S"Writable Item",
|
|
on_use = gtextitems.on_use,
|
|
}, def.item or {}),
|
|
|
|
-- Additional written item overrides.
|
|
written = b.t.combine({
|
|
description = S"Written Item",
|
|
on_use = gtextitems.on_use,
|
|
stack_max = 1,
|
|
}, def.written or {}),
|
|
})
|
|
|
|
def.item._gtextitems_def = def
|
|
|
|
def.item.groups = b.t.combine({
|
|
gtextitem = gtextitems.GROUP_BLANK,
|
|
}, def.item.groups or {})
|
|
|
|
def.written.groups = b.t.combine(def.item.groups, {
|
|
gtextitem = gtextitems.GROUP_WRITTEN,
|
|
}, def.written.groups or {})
|
|
|
|
if def.node then
|
|
register_node(def.itemname, def.item)
|
|
register_node(def.writtenname, b.t.combine(def.item, def.written))
|
|
else
|
|
minetest.register_craftitem(":" .. def.itemname, def.item)
|
|
minetest.register_craftitem(":" .. def.writtenname, b.t.combine(def.item, def.written))
|
|
end
|
|
|
|
-- Register shapeless copying recipe.
|
|
minetest.register_craft{
|
|
output = def.writtenname,
|
|
type = "shapeless",
|
|
recipe = {def.itemname, def.writtenname},
|
|
}
|
|
|
|
-- When copy-crafting, copy metadata and restore the old written item.
|
|
minetest.register_on_craft(function(stack, player, old_grid, craft_inv)
|
|
if stack:get_name() ~= def.writtenname then
|
|
return
|
|
end
|
|
|
|
-- Locate the item to copy.
|
|
for i=1,craft_inv:get_size("craft") do
|
|
if old_grid[i]:get_name() == def.writtenname then
|
|
stack = gtextitems.set_item(stack, b.t.combine(gtextitems.get_item(old_grid[i]), {copy = true}))
|
|
craft_inv:set_stack("craft", i, old_grid[i])
|
|
break
|
|
end
|
|
end
|
|
|
|
return stack
|
|
end)
|
|
|
|
-- Same as above, but for prediction. Don't restore the old written item.
|
|
minetest.register_craft_predict(function(stack, player, old_grid, craft_inv)
|
|
if stack:get_name() ~= def.writtenname then
|
|
return
|
|
end
|
|
|
|
for i=1,craft_inv:get_size("craft") do
|
|
if old_grid[i]:get_name() == def.writtenname then
|
|
stack = gtextitems.set_item(stack, b.t.combine(gtextitems.get_item(old_grid[i]), {copy = true}))
|
|
break
|
|
end
|
|
end
|
|
|
|
return stack
|
|
end)
|
|
end
|