summaryrefslogtreecommitdiff
path: root/util_item_place_node.lua
blob: 759ef8eafba606760df93f3124f06aee92d488a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
-- The default minetest.item_place_node from item.lua was hard to work with given some of the details
-- of how it handled pointed_thing. It also didn't work right with default:torch. It was simpler to
-- just copy it here and chop out the special cases that were causing problems.

-- This specific file is therefore licensed under the LGPL 2.1

--GNU Lesser General Public License, version 2.1
--Copyright (C) 2011-2016 celeron55, Perttu Ahola <celeron55@gmail.com>
--Copyright (C) 2011-2016 Various Minetest developers and contributors

--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 2.1 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:
--https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html

-- Mapping from facedir value to index in facedir_to_dir.
digtron.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,
}

local function copy_pointed_thing(pointed_thing)
	return {
		type  = pointed_thing.type,
		above = vector.new(pointed_thing.above),
		under = vector.new(pointed_thing.under),
	}
end

local function check_attached_node(p, n)
	local def = minetest.registered_nodes[n.name]
	local d = {x = 0, y = 0, z = 0}
	if def.paramtype2 == "wallmounted" then
		-- The fallback vector here is in case 'wallmounted to dir' is nil due
		-- to voxelmanip placing a wallmounted node without resetting a
		-- pre-existing param2 value that is out-of-range for wallmounted.
		-- The fallback vector corresponds to param2 = 0.
		d = minetest.wallmounted_to_dir(n.param2) or {x = 0, y = 1, z = 0}
	else
		d.y = -1
	end
	local p2 = vector.add(p, d)
	local nn = minetest.get_node(p2).name
	local def2 = minetest.registered_nodes[nn]
	if def2 and not def2.walkable then
		return false
	end
	return true
end

digtron.item_place_node = function(itemstack, placer, place_to, param2)
	local item = itemstack:peek_item()
	local def = itemstack:get_definition()
	if def.type ~= "node" then
		return itemstack, false
	end

	local pointed_thing = {}
	pointed_thing.type = "node"
	pointed_thing.above = {x=place_to.x, y=place_to.y, z=place_to.z}
	pointed_thing.under = {x=place_to.x, y=place_to.y - 1, z=place_to.z}

	local oldnode = minetest.get_node_or_nil(place_to)

	--this should never happen, digtron is testing for adjacent unloaded nodes before getting here.
	if not oldnode then
		minetest.log("info", placer:get_player_name() .. " tried to place"
			.. " node in unloaded position " .. minetest.pos_to_string(place_to)
			.. " using a digtron.")
		return itemstack, false
	end

	local newnode = {name = def.name, param1 = 0, param2 = param2}
	if def.place_param2 ~= nil then
		newnode.param2 = def.place_param2
	end

	-- Check if the node is attached and if it can be placed there
	if minetest.get_item_group(def.name, "attached_node") ~= 0 and
		not check_attached_node(place_to, newnode) then
		minetest.log("action", "attached node " .. def.name ..
			" can not be placed at " .. minetest.pos_to_string(place_to))
		return itemstack, false
	end
	
	-- digtron HACK! the default torch mod uses "on_place" to change its model to the correct one,
	-- not "after_place_node". It probably should be using after_place_node, but until then I must
	-- adapt as best I can to the quirks of default.
	if newnode.name == "default:torch" then
		if newnode.param2 == 0 then
			newnode.name = "default:torch_ceiling"
		elseif newnode.param2 > 1 then
			newnode.name = "default:torch_wall"
		end
	end

	-- Add node and update
	minetest.add_node(place_to, newnode)

	local take_item = true

	-- Run callback
	if def.after_place_node then
		-- Deepcopy place_to and pointed_thing because callback can modify it
		local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
		local pointed_thing_copy = copy_pointed_thing(pointed_thing)
		if def.after_place_node(place_to_copy, placer, itemstack,
				pointed_thing_copy) then
			take_item = false
		end
	end

	-- Run script hook
	local _, callback
	for _, callback in ipairs(minetest.registered_on_placenodes) do
		-- Deepcopy pos, node and pointed_thing because callback can modify them
		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}
		local pointed_thing_copy = copy_pointed_thing(pointed_thing)
		if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack, pointed_thing_copy) then
			take_item = false
		end
	end

	if take_item then
		itemstack:take_item()
	end
	return itemstack, true
end