2012-04-01 11:37:41 +02:00
|
|
|
-- Minetest: builtin/item.lua
|
|
|
|
|
2016-11-16 10:17:46 +01:00
|
|
|
local builtin_shared = ...
|
|
|
|
|
2014-01-24 01:21:01 +01:00
|
|
|
local function copy_pointed_thing(pointed_thing)
|
|
|
|
return {
|
|
|
|
type = pointed_thing.type,
|
|
|
|
above = vector.new(pointed_thing.above),
|
|
|
|
under = vector.new(pointed_thing.under),
|
|
|
|
ref = pointed_thing.ref,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2012-04-01 11:37:41 +02:00
|
|
|
--
|
|
|
|
-- Item definition helpers
|
|
|
|
--
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.inventorycube(img1, img2, img3)
|
2012-04-01 11:37:41 +02:00
|
|
|
img2 = img2 or img1
|
|
|
|
img3 = img3 or img1
|
|
|
|
return "[inventorycube"
|
|
|
|
.. "{" .. img1:gsub("%^", "&")
|
|
|
|
.. "{" .. img2:gsub("%^", "&")
|
|
|
|
.. "{" .. img3:gsub("%^", "&")
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.get_pointed_thing_position(pointed_thing, above)
|
2012-04-01 11:37:41 +02:00
|
|
|
if pointed_thing.type == "node" then
|
|
|
|
if above then
|
|
|
|
-- The position where a node would be placed
|
|
|
|
return pointed_thing.above
|
|
|
|
end
|
2015-12-18 17:38:25 +01:00
|
|
|
-- The position where a node would be dug
|
|
|
|
return pointed_thing.under
|
2012-04-01 11:37:41 +02:00
|
|
|
elseif pointed_thing.type == "object" then
|
2015-12-18 17:38:25 +01:00
|
|
|
return pointed_thing.ref and pointed_thing.ref:getpos()
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.dir_to_facedir(dir, is6d)
|
2013-07-17 02:50:41 +02:00
|
|
|
--account for y if requested
|
|
|
|
if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then
|
|
|
|
|
|
|
|
--from above
|
|
|
|
if dir.y < 0 then
|
|
|
|
if math.abs(dir.x) > math.abs(dir.z) then
|
|
|
|
if dir.x < 0 then
|
|
|
|
return 19
|
|
|
|
else
|
|
|
|
return 13
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if dir.z < 0 then
|
|
|
|
return 10
|
|
|
|
else
|
|
|
|
return 4
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--from below
|
|
|
|
else
|
|
|
|
if math.abs(dir.x) > math.abs(dir.z) then
|
|
|
|
if dir.x < 0 then
|
|
|
|
return 15
|
|
|
|
else
|
|
|
|
return 17
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if dir.z < 0 then
|
|
|
|
return 6
|
|
|
|
else
|
|
|
|
return 8
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--otherwise, place horizontally
|
|
|
|
elseif math.abs(dir.x) > math.abs(dir.z) then
|
2012-04-01 11:37:41 +02:00
|
|
|
if dir.x < 0 then
|
|
|
|
return 3
|
|
|
|
else
|
|
|
|
return 1
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if dir.z < 0 then
|
|
|
|
return 2
|
|
|
|
else
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-02-10 01:46:22 +01:00
|
|
|
-- Table of possible dirs
|
|
|
|
local facedir_to_dir = {
|
|
|
|
{x= 0, y=0, z= 1},
|
|
|
|
{x= 1, y=0, z= 0},
|
|
|
|
{x= 0, y=0, z=-1},
|
|
|
|
{x=-1, y=0, z= 0},
|
|
|
|
{x= 0, y=-1, z= 0},
|
|
|
|
{x= 0, y=1, z= 0},
|
|
|
|
}
|
|
|
|
-- Mapping from facedir value to index in facedir_to_dir.
|
|
|
|
local facedir_to_dir_map = {
|
|
|
|
[0]=1, 2, 3, 4,
|
|
|
|
5, 2, 6, 4,
|
|
|
|
6, 2, 5, 4,
|
|
|
|
1, 5, 3, 6,
|
|
|
|
1, 6, 3, 5,
|
|
|
|
1, 4, 3, 2,
|
|
|
|
}
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.facedir_to_dir(facedir)
|
2017-02-01 00:02:30 +01:00
|
|
|
return facedir_to_dir[facedir_to_dir_map[facedir % 32]]
|
2013-07-17 02:50:41 +02:00
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.dir_to_wallmounted(dir)
|
2012-04-01 11:37:41 +02:00
|
|
|
if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
|
|
|
|
if dir.y < 0 then
|
|
|
|
return 1
|
|
|
|
else
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
elseif math.abs(dir.x) > math.abs(dir.z) then
|
|
|
|
if dir.x < 0 then
|
|
|
|
return 3
|
|
|
|
else
|
|
|
|
return 2
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if dir.z < 0 then
|
|
|
|
return 5
|
|
|
|
else
|
|
|
|
return 4
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-02-10 01:46:22 +01:00
|
|
|
-- table of dirs in wallmounted order
|
|
|
|
local wallmounted_to_dir = {
|
|
|
|
[0] = {x = 0, y = 1, z = 0},
|
|
|
|
{x = 0, y = -1, z = 0},
|
|
|
|
{x = 1, y = 0, z = 0},
|
|
|
|
{x = -1, y = 0, z = 0},
|
|
|
|
{x = 0, y = 0, z = 1},
|
|
|
|
{x = 0, y = 0, z = -1},
|
|
|
|
}
|
2015-10-02 21:18:40 +02:00
|
|
|
function core.wallmounted_to_dir(wallmounted)
|
2017-02-01 00:02:30 +01:00
|
|
|
return wallmounted_to_dir[wallmounted % 8]
|
2015-10-02 21:18:40 +02:00
|
|
|
end
|
|
|
|
|
2017-01-12 20:56:41 +01:00
|
|
|
function core.dir_to_yaw(dir)
|
|
|
|
return -math.atan2(dir.x, dir.z)
|
|
|
|
end
|
|
|
|
|
|
|
|
function core.yaw_to_dir(yaw)
|
|
|
|
return {x = -math.sin(yaw), y = 0, z = math.cos(yaw)}
|
|
|
|
end
|
|
|
|
|
2017-06-24 18:58:01 +02:00
|
|
|
function core.is_colored_paramtype(ptype)
|
|
|
|
return (ptype == "color") or (ptype == "colorfacedir") or
|
|
|
|
(ptype == "colorwallmounted")
|
|
|
|
end
|
|
|
|
|
|
|
|
function core.strip_param2_color(param2, paramtype2)
|
|
|
|
if not core.is_colored_paramtype(paramtype2) then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
if paramtype2 == "colorfacedir" then
|
|
|
|
param2 = math.floor(param2 / 32) * 32
|
|
|
|
elseif paramtype2 == "colorwallmounted" then
|
|
|
|
param2 = math.floor(param2 / 8) * 8
|
|
|
|
end
|
|
|
|
-- paramtype2 == "color" requires no modification.
|
|
|
|
return param2
|
|
|
|
end
|
|
|
|
|
2017-06-20 11:19:56 +02:00
|
|
|
function core.get_node_drops(node, toolname)
|
|
|
|
-- Compatibility, if node is string
|
|
|
|
local nodename = node
|
|
|
|
local param2 = 0
|
|
|
|
-- New format, if node is table
|
|
|
|
if (type(node) == "table") then
|
|
|
|
nodename = node.name
|
|
|
|
param2 = node.param2
|
|
|
|
end
|
2017-02-23 20:03:18 +01:00
|
|
|
local def = core.registered_nodes[nodename]
|
|
|
|
local drop = def and def.drop
|
2017-06-24 18:58:01 +02:00
|
|
|
local ptype = def and def.paramtype2
|
|
|
|
-- get color, if there is color (otherwise nil)
|
|
|
|
local palette_index = core.strip_param2_color(param2, ptype)
|
2012-04-01 11:37:41 +02:00
|
|
|
if drop == nil then
|
|
|
|
-- default drop
|
2017-06-24 18:58:01 +02:00
|
|
|
if palette_index then
|
|
|
|
local stack = ItemStack(nodename)
|
|
|
|
stack:get_meta():set_int("palette_index", palette_index)
|
|
|
|
return {stack:to_string()}
|
2017-06-20 11:19:56 +02:00
|
|
|
end
|
2017-06-24 18:58:01 +02:00
|
|
|
return {nodename}
|
2012-04-01 11:37:41 +02:00
|
|
|
elseif type(drop) == "string" then
|
|
|
|
-- itemstring drop
|
2012-12-02 17:19:06 +01:00
|
|
|
return {drop}
|
2012-04-01 11:37:41 +02:00
|
|
|
elseif drop.items == nil then
|
|
|
|
-- drop = {} to disable default drop
|
|
|
|
return {}
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Extended drop table
|
|
|
|
local got_items = {}
|
|
|
|
local got_count = 0
|
|
|
|
local _, item, tool
|
|
|
|
for _, item in ipairs(drop.items) do
|
|
|
|
local good_rarity = true
|
|
|
|
local good_tool = true
|
|
|
|
if item.rarity ~= nil then
|
|
|
|
good_rarity = item.rarity < 1 or math.random(item.rarity) == 1
|
|
|
|
end
|
|
|
|
if item.tools ~= nil then
|
|
|
|
good_tool = false
|
|
|
|
for _, tool in ipairs(item.tools) do
|
|
|
|
if tool:sub(1, 1) == '~' then
|
|
|
|
good_tool = toolname:find(tool:sub(2)) ~= nil
|
|
|
|
else
|
|
|
|
good_tool = toolname == tool
|
|
|
|
end
|
|
|
|
if good_tool then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if good_rarity and good_tool then
|
|
|
|
got_count = got_count + 1
|
|
|
|
for _, add_item in ipairs(item.items) do
|
2017-06-24 18:58:01 +02:00
|
|
|
-- add color, if necessary
|
|
|
|
if item.inherit_color and palette_index then
|
|
|
|
local stack = ItemStack(add_item)
|
|
|
|
stack:get_meta():set_int("palette_index", palette_index)
|
|
|
|
add_item = stack:to_string()
|
|
|
|
end
|
2012-04-01 11:37:41 +02:00
|
|
|
got_items[#got_items+1] = add_item
|
|
|
|
end
|
|
|
|
if drop.max_items ~= nil and got_count == drop.max_items then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return got_items
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.item_place_node(itemstack, placer, pointed_thing, param2)
|
2012-04-01 11:37:41 +02:00
|
|
|
local def = itemstack:get_definition()
|
2012-07-24 16:46:17 +02:00
|
|
|
if def.type ~= "node" or pointed_thing.type ~= "node" then
|
2013-09-11 16:32:05 +02:00
|
|
|
return itemstack, false
|
2012-07-24 16:46:17 +02:00
|
|
|
end
|
2012-04-01 11:37:41 +02:00
|
|
|
|
2012-07-24 16:46:17 +02:00
|
|
|
local under = pointed_thing.under
|
2014-04-28 03:02:48 +02:00
|
|
|
local oldnode_under = core.get_node_or_nil(under)
|
2013-03-28 09:24:48 +01:00
|
|
|
local above = pointed_thing.above
|
2014-04-28 03:02:48 +02:00
|
|
|
local oldnode_above = core.get_node_or_nil(above)
|
2017-02-23 20:03:18 +01:00
|
|
|
local playername = placer:get_player_name()
|
2013-03-28 09:24:48 +01:00
|
|
|
|
|
|
|
if not oldnode_under or not oldnode_above then
|
2017-02-23 20:03:18 +01:00
|
|
|
core.log("info", playername .. " tried to place"
|
2014-04-28 03:02:48 +02:00
|
|
|
.. " node in unloaded position " .. core.pos_to_string(above))
|
2013-09-11 16:32:05 +02:00
|
|
|
return itemstack, false
|
2013-03-28 09:24:48 +01:00
|
|
|
end
|
|
|
|
|
2017-02-23 20:03:18 +01:00
|
|
|
local olddef_under = core.registered_nodes[oldnode_under.name]
|
2014-04-28 03:02:48 +02:00
|
|
|
olddef_under = olddef_under or core.nodedef_default
|
2017-02-23 20:03:18 +01:00
|
|
|
local olddef_above = core.registered_nodes[oldnode_above.name]
|
2014-04-28 03:02:48 +02:00
|
|
|
olddef_above = olddef_above or core.nodedef_default
|
2012-07-24 16:46:17 +02:00
|
|
|
|
|
|
|
if not olddef_above.buildable_to and not olddef_under.buildable_to then
|
2017-02-23 20:03:18 +01:00
|
|
|
core.log("info", playername .. " tried to place"
|
2014-04-28 03:02:48 +02:00
|
|
|
.. " node in invalid position " .. core.pos_to_string(above)
|
2012-07-24 16:46:17 +02:00
|
|
|
.. ", replacing " .. oldnode_above.name)
|
2013-09-11 16:32:05 +02:00
|
|
|
return itemstack, false
|
2012-07-24 16:46:17 +02:00
|
|
|
end
|
2012-07-23 19:41:40 +02:00
|
|
|
|
2012-07-24 16:46:17 +02:00
|
|
|
-- Place above pointed node
|
|
|
|
local place_to = {x = above.x, y = above.y, z = above.z}
|
2012-07-23 19:41:40 +02:00
|
|
|
|
2012-07-24 16:46:17 +02:00
|
|
|
-- If node under is buildable_to, place into it instead (eg. snow)
|
|
|
|
if olddef_under.buildable_to then
|
2014-04-28 03:02:48 +02:00
|
|
|
core.log("info", "node under is buildable to")
|
2012-07-24 16:46:17 +02:00
|
|
|
place_to = {x = under.x, y = under.y, z = under.z}
|
|
|
|
end
|
2012-04-01 11:37:41 +02:00
|
|
|
|
2017-02-23 20:03:18 +01:00
|
|
|
if core.is_protected(place_to, playername) and
|
Introduce "protection_bypass" privilege.
This privilege allows map protection bypassing for server operators
and world moderators.
Initially I had thought that bypassing protection mods would have been
something that could entirely be done inside mods and minetest_game,
but the concept of protection is defined in core, in the code of
core.is_protected().
I don't feel that it would be logical to introduce a protection
concept in core, but not some way around that for server operators
to maintain map parts that need fixing, de-griefing or cleanup.
Others had noticed the same problems, and proposed a patch to
minetest_game. That patch is fine by itself, but it fails to add
protection bypass functionality for digging normal nodes and placing
nodes.
So, instead, we indroduce the new priv "protection_bypass" in core,
and modify 'on_place_node' and 'node_dig' to allow bypassing node
protections if the player holds this priv.
This priv was tested with protector redo by tenplus1.
A followup patch to Minetest Game will include allowing special checks
for doors, trapdoors, chests in Minetest Game.
Protection mods will likely want to mimic the changes in their relevant
code sections.
2016-02-29 06:53:26 +01:00
|
|
|
not minetest.check_player_privs(placer, "protection_bypass") then
|
2017-02-23 20:03:18 +01:00
|
|
|
core.log("action", playername
|
2013-08-02 22:41:36 +02:00
|
|
|
.. " tried to place " .. def.name
|
|
|
|
.. " at protected position "
|
2014-04-28 03:02:48 +02:00
|
|
|
.. core.pos_to_string(place_to))
|
2017-02-23 20:03:18 +01:00
|
|
|
core.record_protection_violation(place_to, playername)
|
2013-08-02 22:41:36 +02:00
|
|
|
return itemstack
|
|
|
|
end
|
|
|
|
|
2017-02-23 20:03:18 +01:00
|
|
|
core.log("action", playername .. " places node "
|
2014-04-28 03:02:48 +02:00
|
|
|
.. def.name .. " at " .. core.pos_to_string(place_to))
|
2015-02-12 17:57:22 +01:00
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
local oldnode = core.get_node(place_to)
|
2017-06-20 11:19:56 +02:00
|
|
|
local newnode = {name = def.name, param1 = 0, param2 = param2 or 0}
|
2012-07-24 16:46:17 +02:00
|
|
|
|
|
|
|
-- Calculate direction for wall mounted stuff like torches and signs
|
2016-05-31 00:07:09 +02:00
|
|
|
if def.place_param2 ~= nil then
|
|
|
|
newnode.param2 = def.place_param2
|
2017-02-23 20:03:18 +01:00
|
|
|
elseif (def.paramtype2 == "wallmounted" or
|
|
|
|
def.paramtype2 == "colorwallmounted") and not param2 then
|
2012-07-24 16:46:17 +02:00
|
|
|
local dir = {
|
|
|
|
x = under.x - above.x,
|
|
|
|
y = under.y - above.y,
|
|
|
|
z = under.z - above.z
|
|
|
|
}
|
2014-04-28 03:02:48 +02:00
|
|
|
newnode.param2 = core.dir_to_wallmounted(dir)
|
2012-07-24 16:46:17 +02:00
|
|
|
-- Calculate the direction for furnaces and chests and stuff
|
2017-02-23 20:03:18 +01:00
|
|
|
elseif (def.paramtype2 == "facedir" or
|
|
|
|
def.paramtype2 == "colorfacedir") and not param2 then
|
2012-07-24 16:46:17 +02:00
|
|
|
local placer_pos = placer:getpos()
|
|
|
|
if placer_pos then
|
2012-07-23 19:41:40 +02:00
|
|
|
local dir = {
|
2012-07-24 16:46:17 +02:00
|
|
|
x = above.x - placer_pos.x,
|
|
|
|
y = above.y - placer_pos.y,
|
|
|
|
z = above.z - placer_pos.z
|
2012-07-23 19:41:40 +02:00
|
|
|
}
|
2014-04-28 03:02:48 +02:00
|
|
|
newnode.param2 = core.dir_to_facedir(dir)
|
|
|
|
core.log("action", "facedir: " .. newnode.param2)
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
2012-07-24 16:46:17 +02:00
|
|
|
end
|
2012-04-01 11:37:41 +02:00
|
|
|
|
2017-06-20 11:19:56 +02:00
|
|
|
local metatable = itemstack:get_meta():to_table().fields
|
|
|
|
|
|
|
|
-- Transfer color information
|
|
|
|
if metatable.palette_index and not def.place_param2 then
|
|
|
|
local color_divisor = nil
|
|
|
|
if def.paramtype2 == "color" then
|
|
|
|
color_divisor = 1
|
|
|
|
elseif def.paramtype2 == "colorwallmounted" then
|
|
|
|
color_divisor = 8
|
|
|
|
elseif def.paramtype2 == "colorfacedir" then
|
|
|
|
color_divisor = 32
|
|
|
|
end
|
|
|
|
if color_divisor then
|
|
|
|
local color = math.floor(metatable.palette_index / color_divisor)
|
|
|
|
local other = newnode.param2 % color_divisor
|
|
|
|
newnode.param2 = color * color_divisor + other
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-01 13:32:32 +01:00
|
|
|
-- Check if the node is attached and if it can be placed there
|
2014-04-28 03:02:48 +02:00
|
|
|
if core.get_item_group(def.name, "attached_node") ~= 0 and
|
2016-11-16 10:17:46 +01:00
|
|
|
not builtin_shared.check_attached_node(place_to, newnode) then
|
2014-04-28 03:02:48 +02:00
|
|
|
core.log("action", "attached node " .. def.name ..
|
|
|
|
" can not be placed at " .. core.pos_to_string(place_to))
|
2013-09-11 16:32:05 +02:00
|
|
|
return itemstack, false
|
2012-12-01 13:32:32 +01:00
|
|
|
end
|
|
|
|
|
2012-07-24 16:46:17 +02:00
|
|
|
-- Add node and update
|
2014-04-28 03:02:48 +02:00
|
|
|
core.add_node(place_to, newnode)
|
2012-06-02 12:20:30 +02:00
|
|
|
|
2012-12-17 19:49:18 +01:00
|
|
|
local take_item = true
|
|
|
|
|
2012-07-24 16:46:17 +02:00
|
|
|
-- Run callback
|
|
|
|
if def.after_place_node then
|
2014-01-11 17:23:28 +01:00
|
|
|
-- Deepcopy place_to and pointed_thing because callback can modify it
|
2012-07-24 16:46:17 +02:00
|
|
|
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
2014-01-24 01:21:01 +01:00
|
|
|
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
2014-01-07 03:15:44 +01:00
|
|
|
if def.after_place_node(place_to_copy, placer, itemstack,
|
|
|
|
pointed_thing_copy) then
|
2012-12-17 19:49:18 +01:00
|
|
|
take_item = false
|
|
|
|
end
|
2012-07-24 16:46:17 +02:00
|
|
|
end
|
2012-04-01 11:37:41 +02:00
|
|
|
|
2012-07-24 16:46:17 +02:00
|
|
|
-- Run script hook
|
2014-04-28 03:02:48 +02:00
|
|
|
for _, callback in ipairs(core.registered_on_placenodes) do
|
2014-01-24 01:21:01 +01:00
|
|
|
-- Deepcopy pos, node and pointed_thing because callback can modify them
|
2012-07-24 16:46:17 +02:00
|
|
|
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
|
|
|
local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
|
|
|
|
local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
|
2014-01-24 01:21:01 +01:00
|
|
|
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
|
|
|
if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack, pointed_thing_copy) then
|
2012-12-17 19:49:18 +01:00
|
|
|
take_item = false
|
|
|
|
end
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
2012-07-24 16:46:17 +02:00
|
|
|
|
2012-12-17 19:49:18 +01:00
|
|
|
if take_item then
|
|
|
|
itemstack:take_item()
|
|
|
|
end
|
2013-09-11 16:32:05 +02:00
|
|
|
return itemstack, true
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.item_place_object(itemstack, placer, pointed_thing)
|
|
|
|
local pos = core.get_pointed_thing_position(pointed_thing, true)
|
2012-04-01 11:37:41 +02:00
|
|
|
if pos ~= nil then
|
|
|
|
local item = itemstack:take_item()
|
2014-04-28 03:02:48 +02:00
|
|
|
core.add_item(pos, item)
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
|
|
|
return itemstack
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.item_place(itemstack, placer, pointed_thing, param2)
|
2013-01-04 00:05:56 +01:00
|
|
|
-- Call on_rightclick if the pointed node defines it
|
2013-01-27 21:58:46 +01:00
|
|
|
if pointed_thing.type == "node" and placer and
|
|
|
|
not placer:get_player_control().sneak then
|
2014-04-28 03:02:48 +02:00
|
|
|
local n = core.get_node(pointed_thing.under)
|
2013-01-04 00:05:56 +01:00
|
|
|
local nn = n.name
|
2014-04-28 03:02:48 +02:00
|
|
|
if core.registered_nodes[nn] and core.registered_nodes[nn].on_rightclick then
|
|
|
|
return core.registered_nodes[nn].on_rightclick(pointed_thing.under, n,
|
2014-01-11 17:23:28 +01:00
|
|
|
placer, itemstack, pointed_thing) or itemstack, false
|
2013-01-04 00:05:56 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-04-01 11:37:41 +02:00
|
|
|
if itemstack:get_definition().type == "node" then
|
2014-04-28 03:02:48 +02:00
|
|
|
return core.item_place_node(itemstack, placer, pointed_thing, param2)
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
2013-02-19 20:16:55 +01:00
|
|
|
return itemstack
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
|
|
|
|
2015-11-18 20:26:09 +01:00
|
|
|
function core.item_secondary_use(itemstack, placer)
|
|
|
|
return itemstack
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.item_drop(itemstack, dropper, pos)
|
2015-11-05 19:56:19 +01:00
|
|
|
if dropper and dropper:is_player() then
|
2012-04-01 15:06:01 +02:00
|
|
|
local v = dropper:get_look_dir()
|
2013-03-12 01:29:02 +01:00
|
|
|
local p = {x=pos.x, y=pos.y+1.2, z=pos.z}
|
|
|
|
local cs = itemstack:get_count()
|
|
|
|
if dropper:get_player_control().sneak then
|
|
|
|
cs = 1
|
|
|
|
end
|
|
|
|
local item = itemstack:take_item(cs)
|
|
|
|
local obj = core.add_item(p, item)
|
2012-08-19 09:55:04 +02:00
|
|
|
if obj then
|
|
|
|
v.x = v.x*2
|
2013-03-12 01:29:02 +01:00
|
|
|
v.y = v.y*2 + 2
|
2012-08-19 09:55:04 +02:00
|
|
|
v.z = v.z*2
|
|
|
|
obj:setvelocity(v)
|
2015-11-05 19:56:19 +01:00
|
|
|
obj:get_luaentity().dropped_by = dropper:get_player_name()
|
2015-09-29 17:26:07 +02:00
|
|
|
return itemstack
|
2012-08-19 09:55:04 +02:00
|
|
|
end
|
2013-03-12 01:29:02 +01:00
|
|
|
|
2012-04-01 15:06:01 +02:00
|
|
|
else
|
2015-09-29 17:26:07 +02:00
|
|
|
if core.add_item(pos, itemstack) then
|
|
|
|
return itemstack
|
|
|
|
end
|
2012-04-01 15:06:01 +02:00
|
|
|
end
|
2015-09-29 17:26:07 +02:00
|
|
|
-- If we reach this, adding the object to the
|
|
|
|
-- environment failed
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
|
|
|
|
2015-02-12 17:57:22 +01:00
|
|
|
function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
|
|
|
for _, callback in pairs(core.registered_on_item_eats) do
|
|
|
|
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
|
|
|
if result then
|
|
|
|
return result
|
2014-05-20 16:21:09 +02:00
|
|
|
end
|
2015-02-12 17:57:22 +01:00
|
|
|
end
|
|
|
|
if itemstack:take_item() ~= nil then
|
|
|
|
user:set_hp(user:get_hp() + hp_change)
|
|
|
|
|
|
|
|
if replace_with_item then
|
|
|
|
if itemstack:is_empty() then
|
|
|
|
itemstack:add_item(replace_with_item)
|
|
|
|
else
|
|
|
|
local inv = user:get_inventory()
|
|
|
|
if inv:room_for_item("main", {name=replace_with_item}) then
|
|
|
|
inv:add_item("main", replace_with_item)
|
|
|
|
else
|
|
|
|
local pos = user:getpos()
|
|
|
|
pos.y = math.floor(pos.y + 0.5)
|
|
|
|
core.add_item(pos, replace_with_item)
|
|
|
|
end
|
|
|
|
end
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
2015-02-12 17:57:22 +01:00
|
|
|
end
|
|
|
|
return itemstack
|
|
|
|
end
|
|
|
|
|
|
|
|
function core.item_eat(hp_change, replace_with_item)
|
|
|
|
return function(itemstack, user, pointed_thing) -- closure
|
|
|
|
return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.node_punch(pos, node, puncher, pointed_thing)
|
2012-04-01 11:37:41 +02:00
|
|
|
-- Run script hook
|
2014-04-28 03:02:48 +02:00
|
|
|
for _, callback in ipairs(core.registered_on_punchnodes) do
|
2012-07-24 16:46:17 +02:00
|
|
|
-- Copy pos and node because callback can modify them
|
2014-01-24 01:21:01 +01:00
|
|
|
local pos_copy = vector.new(pos)
|
2012-07-24 16:46:17 +02:00
|
|
|
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
|
2014-03-11 17:59:02 +01:00
|
|
|
local pointed_thing_copy = pointed_thing and copy_pointed_thing(pointed_thing) or nil
|
2014-01-24 01:21:01 +01:00
|
|
|
callback(pos_copy, node_copy, puncher, pointed_thing_copy)
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.handle_node_drops(pos, drops, digger)
|
2012-09-02 18:38:44 +02:00
|
|
|
-- Add dropped items to object's inventory
|
|
|
|
if digger:get_inventory() then
|
|
|
|
local _, dropped_item
|
|
|
|
for _, dropped_item in ipairs(drops) do
|
2013-01-12 20:18:43 +01:00
|
|
|
local left = digger:get_inventory():add_item("main", dropped_item)
|
|
|
|
if not left:is_empty() then
|
|
|
|
local p = {
|
|
|
|
x = pos.x + math.random()/2-0.25,
|
|
|
|
y = pos.y + math.random()/2-0.25,
|
|
|
|
z = pos.z + math.random()/2-0.25,
|
|
|
|
}
|
2014-04-28 03:02:48 +02:00
|
|
|
core.add_item(p, left)
|
2013-01-12 20:18:43 +01:00
|
|
|
end
|
2012-09-02 18:38:44 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
function core.node_dig(pos, node, digger)
|
2017-02-23 20:03:18 +01:00
|
|
|
local def = core.registered_nodes[node.name]
|
|
|
|
if def and (not def.diggable or
|
|
|
|
(def.can_dig and not def.can_dig(pos, digger))) then
|
2014-04-28 03:02:48 +02:00
|
|
|
core.log("info", digger:get_player_name() .. " tried to dig "
|
2012-04-01 11:37:41 +02:00
|
|
|
.. node.name .. " which is not diggable "
|
2014-04-28 03:02:48 +02:00
|
|
|
.. core.pos_to_string(pos))
|
2012-04-01 11:37:41 +02:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
Introduce "protection_bypass" privilege.
This privilege allows map protection bypassing for server operators
and world moderators.
Initially I had thought that bypassing protection mods would have been
something that could entirely be done inside mods and minetest_game,
but the concept of protection is defined in core, in the code of
core.is_protected().
I don't feel that it would be logical to introduce a protection
concept in core, but not some way around that for server operators
to maintain map parts that need fixing, de-griefing or cleanup.
Others had noticed the same problems, and proposed a patch to
minetest_game. That patch is fine by itself, but it fails to add
protection bypass functionality for digging normal nodes and placing
nodes.
So, instead, we indroduce the new priv "protection_bypass" in core,
and modify 'on_place_node' and 'node_dig' to allow bypassing node
protections if the player holds this priv.
This priv was tested with protector redo by tenplus1.
A followup patch to Minetest Game will include allowing special checks
for doors, trapdoors, chests in Minetest Game.
Protection mods will likely want to mimic the changes in their relevant
code sections.
2016-02-29 06:53:26 +01:00
|
|
|
if core.is_protected(pos, digger:get_player_name()) and
|
|
|
|
not minetest.check_player_privs(digger, "protection_bypass") then
|
2014-04-28 03:02:48 +02:00
|
|
|
core.log("action", digger:get_player_name()
|
2013-08-02 22:41:36 +02:00
|
|
|
.. " tried to dig " .. node.name
|
|
|
|
.. " at protected position "
|
2014-04-28 03:02:48 +02:00
|
|
|
.. core.pos_to_string(pos))
|
|
|
|
core.record_protection_violation(pos, digger:get_player_name())
|
2013-08-02 22:41:36 +02:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
core.log('action', digger:get_player_name() .. " digs "
|
|
|
|
.. node.name .. " at " .. core.pos_to_string(pos))
|
2012-04-01 11:37:41 +02:00
|
|
|
|
2012-07-25 13:07:45 +02:00
|
|
|
local wielded = digger:get_wielded_item()
|
2017-06-20 11:19:56 +02:00
|
|
|
local drops = core.get_node_drops(node, wielded:get_name())
|
2015-02-12 17:57:22 +01:00
|
|
|
|
2013-05-06 18:53:15 +02:00
|
|
|
local wdef = wielded:get_definition()
|
|
|
|
local tp = wielded:get_tool_capabilities()
|
2017-02-23 20:03:18 +01:00
|
|
|
local dp = core.get_dig_params(def and def.groups, tp)
|
2013-05-06 18:53:15 +02:00
|
|
|
if wdef and wdef.after_use then
|
|
|
|
wielded = wdef.after_use(wielded, digger, node, dp) or wielded
|
|
|
|
else
|
|
|
|
-- Wear out tool
|
2014-12-12 20:49:19 +01:00
|
|
|
if not core.settings:get_bool("creative_mode") then
|
2013-05-06 18:53:15 +02:00
|
|
|
wielded:add_wear(dp.wear)
|
2016-01-23 06:52:50 +01:00
|
|
|
if wielded:get_count() == 0 and wdef.sound and wdef.sound.breaks then
|
2016-11-19 23:58:11 +01:00
|
|
|
core.sound_play(wdef.sound.breaks, {pos = pos, gain = 0.5})
|
2016-01-23 06:52:50 +01:00
|
|
|
end
|
2013-05-06 18:53:15 +02:00
|
|
|
end
|
2013-03-11 13:36:04 +01:00
|
|
|
end
|
2013-05-06 18:53:15 +02:00
|
|
|
digger:set_wielded_item(wielded)
|
2015-02-12 17:57:22 +01:00
|
|
|
|
2012-09-02 18:38:44 +02:00
|
|
|
-- Handle drops
|
2014-04-28 03:02:48 +02:00
|
|
|
core.handle_node_drops(pos, drops, digger)
|
2012-07-25 13:07:45 +02:00
|
|
|
|
2012-06-02 12:20:30 +02:00
|
|
|
local oldmetadata = nil
|
2017-03-15 08:04:53 +01:00
|
|
|
if def and def.after_dig_node then
|
2014-04-28 03:02:48 +02:00
|
|
|
oldmetadata = core.get_meta(pos):to_table()
|
2012-06-02 12:20:30 +02:00
|
|
|
end
|
2012-04-01 11:37:41 +02:00
|
|
|
|
|
|
|
-- Remove node and update
|
2014-04-28 03:02:48 +02:00
|
|
|
core.remove_node(pos)
|
2015-02-12 17:57:22 +01:00
|
|
|
|
2012-06-02 12:20:30 +02:00
|
|
|
-- Run callback
|
2017-03-15 08:04:53 +01:00
|
|
|
if def and def.after_dig_node then
|
2012-07-24 16:46:17 +02:00
|
|
|
-- Copy pos and node because callback can modify them
|
|
|
|
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
|
|
|
|
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
|
|
|
|
def.after_dig_node(pos_copy, node_copy, oldmetadata, digger)
|
2012-06-02 12:20:30 +02:00
|
|
|
end
|
2012-04-01 11:37:41 +02:00
|
|
|
|
2012-07-24 16:46:17 +02:00
|
|
|
-- Run script hook
|
2012-04-01 11:37:41 +02:00
|
|
|
local _, callback
|
2014-04-28 03:02:48 +02:00
|
|
|
for _, callback in ipairs(core.registered_on_dignodes) do
|
2015-08-12 04:27:54 +02:00
|
|
|
local origin = core.callback_origins[callback]
|
|
|
|
if origin then
|
|
|
|
core.set_last_run_mod(origin.mod)
|
|
|
|
--print("Running " .. tostring(callback) ..
|
|
|
|
-- " (a " .. origin.name .. " callback in " .. origin.mod .. ")")
|
|
|
|
else
|
|
|
|
--print("No data associated with callback")
|
|
|
|
end
|
|
|
|
|
2012-07-24 16:46:17 +02:00
|
|
|
-- Copy pos and node because callback can modify them
|
|
|
|
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
|
|
|
|
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
|
|
|
|
callback(pos_copy, node_copy, digger)
|
2012-04-01 11:37:41 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
-- This is used to allow mods to redefine core.item_place and so on
|
2012-06-02 12:20:30 +02:00
|
|
|
-- NOTE: This is not the preferred way. Preferred way is to provide enough
|
|
|
|
-- callbacks to not require redefining global functions. -celeron55
|
2012-04-09 20:14:16 +02:00
|
|
|
local function redef_wrapper(table, name)
|
|
|
|
return function(...)
|
|
|
|
return table[name](...)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-04-01 11:37:41 +02:00
|
|
|
--
|
|
|
|
-- Item definition defaults
|
|
|
|
--
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
core.nodedef_default = {
|
2012-04-01 11:37:41 +02:00
|
|
|
-- Item properties
|
|
|
|
type="node",
|
|
|
|
-- name intentionally not defined here
|
|
|
|
description = "",
|
|
|
|
groups = {},
|
|
|
|
inventory_image = "",
|
|
|
|
wield_image = "",
|
|
|
|
wield_scale = {x=1,y=1,z=1},
|
|
|
|
stack_max = 99,
|
|
|
|
usable = false,
|
|
|
|
liquids_pointable = false,
|
|
|
|
tool_capabilities = nil,
|
2012-06-10 11:46:48 +02:00
|
|
|
node_placement_prediction = nil,
|
2012-04-01 11:37:41 +02:00
|
|
|
|
|
|
|
-- Interaction callbacks
|
2014-04-28 03:02:48 +02:00
|
|
|
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
|
|
|
|
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
|
2012-04-01 11:37:41 +02:00
|
|
|
on_use = nil,
|
2012-06-03 12:02:10 +02:00
|
|
|
can_dig = nil,
|
2012-04-01 11:37:41 +02:00
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
on_punch = redef_wrapper(core, 'node_punch'), -- core.node_punch
|
2013-01-04 00:05:56 +01:00
|
|
|
on_rightclick = nil,
|
2014-04-28 03:02:48 +02:00
|
|
|
on_dig = redef_wrapper(core, 'node_dig'), -- core.node_dig
|
2012-04-01 11:37:41 +02:00
|
|
|
|
2012-06-01 23:33:51 +02:00
|
|
|
on_receive_fields = nil,
|
2015-02-12 17:57:22 +01:00
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
on_metadata_inventory_move = core.node_metadata_inventory_move_allow_all,
|
|
|
|
on_metadata_inventory_offer = core.node_metadata_inventory_offer_allow_all,
|
|
|
|
on_metadata_inventory_take = core.node_metadata_inventory_take_allow_all,
|
2012-06-01 23:33:51 +02:00
|
|
|
|
2012-04-01 11:37:41 +02:00
|
|
|
-- Node properties
|
|
|
|
drawtype = "normal",
|
|
|
|
visual_scale = 1.0,
|
2012-06-16 17:02:26 +02:00
|
|
|
-- Don't define these because otherwise the old tile_images and
|
|
|
|
-- special_materials wouldn't be read
|
|
|
|
--tiles ={""},
|
|
|
|
--special_tiles = {
|
|
|
|
-- {name="", backface_culling=true},
|
|
|
|
-- {name="", backface_culling=true},
|
|
|
|
--},
|
2012-04-01 11:37:41 +02:00
|
|
|
alpha = 255,
|
|
|
|
post_effect_color = {a=0, r=0, g=0, b=0},
|
|
|
|
paramtype = "none",
|
|
|
|
paramtype2 = "none",
|
2013-11-30 08:37:10 +01:00
|
|
|
is_ground_content = true,
|
2012-04-01 11:37:41 +02:00
|
|
|
sunlight_propagates = false,
|
|
|
|
walkable = true,
|
|
|
|
pointable = true,
|
|
|
|
diggable = true,
|
|
|
|
climbable = false,
|
|
|
|
buildable_to = false,
|
2015-12-30 05:22:58 +01:00
|
|
|
floodable = false,
|
2012-04-01 11:37:41 +02:00
|
|
|
liquidtype = "none",
|
|
|
|
liquid_alternative_flowing = "",
|
|
|
|
liquid_alternative_source = "",
|
|
|
|
liquid_viscosity = 0,
|
2013-08-01 18:36:11 +02:00
|
|
|
drowning = 0,
|
2012-04-01 11:37:41 +02:00
|
|
|
light_source = 0,
|
|
|
|
damage_per_second = 0,
|
|
|
|
selection_box = {type="regular"},
|
|
|
|
legacy_facedir_simple = false,
|
|
|
|
legacy_wallmounted = false,
|
|
|
|
}
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
core.craftitemdef_default = {
|
2012-04-01 11:37:41 +02:00
|
|
|
type="craft",
|
|
|
|
-- name intentionally not defined here
|
|
|
|
description = "",
|
|
|
|
groups = {},
|
|
|
|
inventory_image = "",
|
|
|
|
wield_image = "",
|
|
|
|
wield_scale = {x=1,y=1,z=1},
|
|
|
|
stack_max = 99,
|
|
|
|
liquids_pointable = false,
|
|
|
|
tool_capabilities = nil,
|
|
|
|
|
|
|
|
-- Interaction callbacks
|
2014-04-28 03:02:48 +02:00
|
|
|
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
|
|
|
|
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
|
2015-11-18 20:26:09 +01:00
|
|
|
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
|
2012-04-01 11:37:41 +02:00
|
|
|
on_use = nil,
|
|
|
|
}
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
core.tooldef_default = {
|
2012-04-01 11:37:41 +02:00
|
|
|
type="tool",
|
|
|
|
-- name intentionally not defined here
|
|
|
|
description = "",
|
|
|
|
groups = {},
|
|
|
|
inventory_image = "",
|
|
|
|
wield_image = "",
|
|
|
|
wield_scale = {x=1,y=1,z=1},
|
|
|
|
stack_max = 1,
|
|
|
|
liquids_pointable = false,
|
|
|
|
tool_capabilities = nil,
|
|
|
|
|
|
|
|
-- Interaction callbacks
|
2014-04-28 03:02:48 +02:00
|
|
|
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
|
2015-11-18 20:26:09 +01:00
|
|
|
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
|
2014-04-28 03:02:48 +02:00
|
|
|
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
|
2012-04-01 11:37:41 +02:00
|
|
|
on_use = nil,
|
|
|
|
}
|
|
|
|
|
2014-04-28 03:02:48 +02:00
|
|
|
core.noneitemdef_default = { -- This is used for the hand and unknown items
|
2012-04-01 11:37:41 +02:00
|
|
|
type="none",
|
|
|
|
-- name intentionally not defined here
|
|
|
|
description = "",
|
|
|
|
groups = {},
|
|
|
|
inventory_image = "",
|
|
|
|
wield_image = "",
|
|
|
|
wield_scale = {x=1,y=1,z=1},
|
|
|
|
stack_max = 99,
|
|
|
|
liquids_pointable = false,
|
|
|
|
tool_capabilities = nil,
|
|
|
|
|
|
|
|
-- Interaction callbacks
|
2014-04-28 03:02:48 +02:00
|
|
|
on_place = redef_wrapper(core, 'item_place'),
|
2015-11-18 20:26:09 +01:00
|
|
|
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
|
2012-04-01 11:37:41 +02:00
|
|
|
on_drop = nil,
|
|
|
|
on_use = nil,
|
|
|
|
}
|