mirror of
				https://github.com/minetest-mods/mesecons.git
				synced 2025-11-04 04:55:26 +01:00 
			
		
		
		
	Make pistons and movestones move objects (push only yet)
This commit is contained in:
		@@ -22,3 +22,17 @@ end
 | 
			
		||||
function mesecon:cmpPos(p1, p2)
 | 
			
		||||
	return (p1.x == p2.x and p1.y == p2.y and p1.z == p2.z)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon:tablecopy(table) -- deep table copy
 | 
			
		||||
	local newtable = {}
 | 
			
		||||
 | 
			
		||||
	for idx, item in pairs(table) do
 | 
			
		||||
		if type(item) == "table" then
 | 
			
		||||
			newtable[idx] = mesecon:tablecopy(item)
 | 
			
		||||
		else
 | 
			
		||||
			newtable[idx] = item
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	return newtable
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -77,8 +77,9 @@ minetest.register_entity("mesecons_movestones:movestone_entity", {
 | 
			
		||||
	physical = false,
 | 
			
		||||
	visual = "sprite",
 | 
			
		||||
	textures = {"jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_arrows.png", "jeija_movestone_arrows.png"},
 | 
			
		||||
	collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
 | 
			
		||||
	collisionbox = {-0.5,-0.5,-0.5, 0.5, 0.5, 0.5},
 | 
			
		||||
	visual = "cube",
 | 
			
		||||
	lastdir = {x=0, y=0, z=0},
 | 
			
		||||
 | 
			
		||||
	on_punch = function(self, hitter)
 | 
			
		||||
		self.object:remove()
 | 
			
		||||
@@ -90,21 +91,27 @@ minetest.register_entity("mesecons_movestones:movestone_entity", {
 | 
			
		||||
		pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)
 | 
			
		||||
		local direction = mesecon:get_movestone_direction(pos)
 | 
			
		||||
 | 
			
		||||
		if not direction then
 | 
			
		||||
		if not direction then -- no mesecon power
 | 
			
		||||
			local name = minetest.env:get_node(pos).name
 | 
			
		||||
			if name ~= "air" and name ~= "ignore" and minetest.registered_nodes[name].liquidtype == "none" then
 | 
			
		||||
				mesecon:mvps_push(pos, direction, MOVESTONE_MAXIMUM_PUSH)
 | 
			
		||||
			if  name ~= "air" and name ~= "ignore"
 | 
			
		||||
			and minetest.registered_nodes[name].liquidtype == "none" then
 | 
			
		||||
				mesecon:mvps_push(pos, self.lastdir, MOVESTONE_MAXIMUM_PUSH)
 | 
			
		||||
			end
 | 
			
		||||
			minetest.env:add_node(pos, {name="mesecons_movestones:movestone"})
 | 
			
		||||
			self.object:remove()
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		local np = mesecon:addPosRule(pos, direction)
 | 
			
		||||
		if not mesecon:mvps_push(np, direction, MOVESTONE_MAXIMUM_PUSH) then
 | 
			
		||||
		local success, stack, oldstack =
 | 
			
		||||
			mesecon:mvps_push(pos, direction, MOVESTONE_MAXIMUM_PUSH)
 | 
			
		||||
		if not success then -- Too large stack/stopper in the way
 | 
			
		||||
			minetest.env:add_node(pos, {name="mesecons_movestones:movestone"})
 | 
			
		||||
			self.object:remove()
 | 
			
		||||
			return
 | 
			
		||||
		else
 | 
			
		||||
			mesecon:mvps_process_stack (stack)
 | 
			
		||||
			mesecon:mvps_move_objects  (pos, direction, oldstack)
 | 
			
		||||
			self.lastdir = direction
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		self.object:setvelocity({x=direction.x*2, y=direction.y*2, z=direction.z*2})
 | 
			
		||||
@@ -154,8 +161,9 @@ minetest.register_entity("mesecons_movestones:sticky_movestone_entity", {
 | 
			
		||||
	physical = false,
 | 
			
		||||
	visual = "sprite",
 | 
			
		||||
	textures = {"jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_sticky_movestone.png", "jeija_sticky_movestone.png"},
 | 
			
		||||
	collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
 | 
			
		||||
	collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
 | 
			
		||||
	visual = "cube",
 | 
			
		||||
	lastdir = {x=0, y=0, z=0},
 | 
			
		||||
 | 
			
		||||
	on_punch = function(self, hitter)
 | 
			
		||||
		self.object:remove()
 | 
			
		||||
@@ -167,21 +175,27 @@ minetest.register_entity("mesecons_movestones:sticky_movestone_entity", {
 | 
			
		||||
		pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)
 | 
			
		||||
		local direction = mesecon:get_movestone_direction(pos)
 | 
			
		||||
 | 
			
		||||
		if not direction then
 | 
			
		||||
		if not direction then -- no mesecon power
 | 
			
		||||
			local name = minetest.env:get_node(pos).name
 | 
			
		||||
			if name ~= "air" and name ~= "ignore" and minetest.registered_nodes[name].liquidtype == "none" then
 | 
			
		||||
				mesecon:mvps_push(pos, direction, MOVESTONE_MAXIMUM_PUSH)
 | 
			
		||||
			if  name ~= "air" and name ~= "ignore"
 | 
			
		||||
			and minetest.registered_nodes[name].liquidtype == "none" then
 | 
			
		||||
				mesecon:mvps_push(pos, self.lastdir, MOVESTONE_MAXIMUM_PUSH)
 | 
			
		||||
			end
 | 
			
		||||
			minetest.env:add_node(pos, {name="mesecons_movestones:sticky_movestone"})
 | 
			
		||||
			self.object:remove()
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		local np = mesecon:addPosRule(pos, direction)
 | 
			
		||||
		if not mesecon:mvps_push(np, direction, MOVESTONE_MAXIMUM_PUSH) then
 | 
			
		||||
		local success, stack, oldstack =
 | 
			
		||||
			mesecon:mvps_push(pos, direction, MOVESTONE_MAXIMUM_PUSH)
 | 
			
		||||
		if not success then -- Too large stack/stopper in the way
 | 
			
		||||
			minetest.env:add_node(pos, {name="mesecons_movestones:sticky_movestone"})
 | 
			
		||||
			self.object:remove()
 | 
			
		||||
			return
 | 
			
		||||
		else
 | 
			
		||||
			mesecon:mvps_process_stack (stack)
 | 
			
		||||
			mesecon:mvps_move_objects  (pos, direction, oldstack)
 | 
			
		||||
			self.lastdir = direction
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		self.object:setvelocity({x=direction.x*2, y=direction.y*2, z=direction.z*2})
 | 
			
		||||
@@ -190,3 +204,7 @@ minetest.register_entity("mesecons_movestones:sticky_movestone_entity", {
 | 
			
		||||
		mesecon:mvps_pull_all(pos, direction)
 | 
			
		||||
	end,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
mesecon:register_mvps_unmov("mesecons_movestones:movestone_entity")
 | 
			
		||||
mesecon:register_mvps_unmov("mesecons_movestones:sticky_movestone_entity")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
--register stoppers for movestones/pistons
 | 
			
		||||
 | 
			
		||||
mesecon.mvps_stoppers={}
 | 
			
		||||
mesecon.mvps_stoppers = {}
 | 
			
		||||
mesecon.mvps_unmov = {}
 | 
			
		||||
 | 
			
		||||
function mesecon:is_mvps_stopper(node, pushdir, stack, stackid)
 | 
			
		||||
	local get_stopper = mesecon.mvps_stoppers[node.name]
 | 
			
		||||
@@ -17,6 +18,15 @@ function mesecon:register_mvps_stopper(nodename, get_stopper)
 | 
			
		||||
	mesecon.mvps_stoppers[nodename] = get_stopper
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Objects that cannot be moved (e.g. movestones)
 | 
			
		||||
function mesecon:register_mvps_unmov(objectname)
 | 
			
		||||
	mesecon.mvps_unmov[objectname] = true;
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon:is_mvps_unmov(objectname)
 | 
			
		||||
	return mesecon.mvps_unmov[objectname]
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon:mvps_process_stack(stack)
 | 
			
		||||
	-- update mesecons for placed nodes ( has to be done after all nodes have been added )
 | 
			
		||||
	for _, n in ipairs(stack) do
 | 
			
		||||
@@ -26,13 +36,12 @@ function mesecon:mvps_process_stack(stack)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon:mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: direction of push; maximum: maximum nodes to be pushed
 | 
			
		||||
	np = {x = pos.x, y = pos.y, z = pos.z}
 | 
			
		||||
 | 
			
		||||
function mesecon:mvps_get_stack(pos, dir, maximum)
 | 
			
		||||
	-- determine the number of nodes to be pushed
 | 
			
		||||
	local np = {x = pos.x, y = pos.y, z = pos.z}
 | 
			
		||||
	local nodes = {}
 | 
			
		||||
	while true do
 | 
			
		||||
		nn = minetest.env:get_node_or_nil(np)
 | 
			
		||||
		local nn = minetest.env:get_node_or_nil(np)
 | 
			
		||||
		if not nn or #nodes > maximum then
 | 
			
		||||
			-- don't push at all, something is in the way (unloaded map or too many nodes)
 | 
			
		||||
			return
 | 
			
		||||
@@ -47,6 +56,11 @@ function mesecon:mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: directio
 | 
			
		||||
 | 
			
		||||
		np = mesecon:addPosRule(np, dir)
 | 
			
		||||
	end
 | 
			
		||||
	return nodes
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon:mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: direction of push; maximum: maximum nodes to be pushed
 | 
			
		||||
	local nodes = mesecon:mvps_get_stack(pos, dir, maximum)
 | 
			
		||||
 | 
			
		||||
	-- determine if one of the nodes blocks the push
 | 
			
		||||
	for id, n in ipairs(nodes) do
 | 
			
		||||
@@ -74,11 +88,12 @@ function mesecon:mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: directio
 | 
			
		||||
		minetest.env:get_meta(np):from_table(n.meta)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	local oldstack = mesecon:tablecopy(nodes)
 | 
			
		||||
	for i in ipairs(nodes) do
 | 
			
		||||
		nodes[i].pos = mesecon:addPosRule(nodes[i].pos, dir)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	return true, nodes
 | 
			
		||||
	return true, nodes, oldstack
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon:mvps_pull_single(pos, dir) -- pos: pos of mvps; direction: direction of pull (matches push direction for sticky pistons)
 | 
			
		||||
@@ -101,26 +116,63 @@ function mesecon:mvps_pull_single(pos, dir) -- pos: pos of mvps; direction: dire
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon:mvps_pull_all(pos, direction) -- pos: pos of mvps; direction: direction of pull
 | 
			
		||||
		local lpos = {x=pos.x-direction.x, y=pos.y-direction.y, z=pos.z-direction.z} -- 1 away
 | 
			
		||||
		local lnode = minetest.env:get_node(lpos)
 | 
			
		||||
		local lpos2 = {x=pos.x-direction.x*2, y=pos.y-direction.y*2, z=pos.z-direction.z*2} -- 2 away
 | 
			
		||||
		local lnode2 = minetest.env:get_node(lpos2)
 | 
			
		||||
	local lpos = {x=pos.x-direction.x, y=pos.y-direction.y, z=pos.z-direction.z} -- 1 away
 | 
			
		||||
	local lnode = minetest.env:get_node(lpos)
 | 
			
		||||
	local lpos2 = {x=pos.x-direction.x*2, y=pos.y-direction.y*2, z=pos.z-direction.z*2} -- 2 away
 | 
			
		||||
	local lnode2 = minetest.env:get_node(lpos2)
 | 
			
		||||
 | 
			
		||||
		if lnode.name ~= "ignore" and lnode.name ~= "air" and minetest.registered_nodes[lnode.name].liquidtype == "none" then return end
 | 
			
		||||
		if lnode2.name == "ignore" or lnode2.name == "air" or not(minetest.registered_nodes[lnode2.name].liquidtype == "none") then return end
 | 
			
		||||
	if lnode.name ~= "ignore" and lnode.name ~= "air" and minetest.registered_nodes[lnode.name].liquidtype == "none" then return end
 | 
			
		||||
	if lnode2.name == "ignore" or lnode2.name == "air" or not(minetest.registered_nodes[lnode2.name].liquidtype == "none") then return end
 | 
			
		||||
 | 
			
		||||
		local oldpos = {x=lpos2.x+direction.x, y=lpos2.y+direction.y, z=lpos2.z+direction.z}
 | 
			
		||||
		repeat
 | 
			
		||||
			lnode2 = minetest.env:get_node(lpos2)
 | 
			
		||||
			minetest.env:add_node(oldpos, {name=lnode2.name})
 | 
			
		||||
			nodeupdate(oldpos)
 | 
			
		||||
			oldpos = {x=lpos2.x, y=lpos2.y, z=lpos2.z}
 | 
			
		||||
			lpos2.x = lpos2.x-direction.x
 | 
			
		||||
			lpos2.y = lpos2.y-direction.y
 | 
			
		||||
			lpos2.z = lpos2.z-direction.z
 | 
			
		||||
			lnode = minetest.env:get_node(lpos2)
 | 
			
		||||
		until lnode.name=="air" or lnode.name=="ignore" or not(minetest.registered_nodes[lnode2.name].liquidtype == "none")
 | 
			
		||||
		minetest.env:remove_node(oldpos)
 | 
			
		||||
	local oldpos = {x=lpos2.x+direction.x, y=lpos2.y+direction.y, z=lpos2.z+direction.z}
 | 
			
		||||
	repeat
 | 
			
		||||
		lnode2 = minetest.env:get_node(lpos2)
 | 
			
		||||
		minetest.env:add_node(oldpos, {name=lnode2.name})
 | 
			
		||||
		nodeupdate(oldpos)
 | 
			
		||||
		oldpos = {x=lpos2.x, y=lpos2.y, z=lpos2.z}
 | 
			
		||||
		lpos2.x = lpos2.x-direction.x
 | 
			
		||||
		lpos2.y = lpos2.y-direction.y
 | 
			
		||||
		lpos2.z = lpos2.z-direction.z
 | 
			
		||||
		lnode = minetest.env:get_node(lpos2)
 | 
			
		||||
	until lnode.name=="air" or lnode.name=="ignore" or not(minetest.registered_nodes[lnode2.name].liquidtype == "none")
 | 
			
		||||
	minetest.env:remove_node(oldpos)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon:mvps_move_objects(pos, dir, nodestack)
 | 
			
		||||
	-- Move object at tip of stack
 | 
			
		||||
	local pushpos = mesecon:addPosRule(pos, -- get pos at tip of stack
 | 
			
		||||
		{x = dir.x * (#nodestack),
 | 
			
		||||
		 y = dir.y * (#nodestack),
 | 
			
		||||
		 z = dir.z * (#nodestack)})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	local objects = minetest.env:get_objects_inside_radius(pushpos, 1)
 | 
			
		||||
	for _, obj in ipairs(objects) do
 | 
			
		||||
		local entity = obj:get_luaentity()
 | 
			
		||||
		if not entity or not mesecon:is_mvps_unmov(entity.name) then
 | 
			
		||||
			obj:setpos(mesecon:addPosRule(obj:getpos(), dir))
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	-- Move objects lying/standing on the stack (before it was pushed - oldstack)
 | 
			
		||||
	local objects_above = {}
 | 
			
		||||
	if tonumber(minetest.setting_get("movement_gravity")) > 0 and dir.y == 0 then
 | 
			
		||||
		-- If gravity positive and dir horizontal, push players standing on the stack
 | 
			
		||||
		for _, n in ipairs(nodestack) do
 | 
			
		||||
			local p_above = mesecon:addPosRule(n.pos, {x=0, y=1, z=0})
 | 
			
		||||
			local objects = minetest.env:get_objects_inside_radius(p_above, 1)
 | 
			
		||||
			for _, obj in ipairs(objects) do
 | 
			
		||||
				table.insert(objects_above, obj)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	for _, obj in ipairs(objects_above) do
 | 
			
		||||
		local entity = obj:get_luaentity()
 | 
			
		||||
		if not entity or not mesecon:is_mvps_unmov(entity.name) then
 | 
			
		||||
			obj:setpos(mesecon:addPosRule(obj:getpos(), dir))
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
mesecon:register_mvps_stopper("default:chest_locked")
 | 
			
		||||
 
 | 
			
		||||
@@ -70,13 +70,14 @@ end
 | 
			
		||||
local piston_on = function (pos, node)
 | 
			
		||||
	local pistonspec = minetest.registered_nodes[node.name].mesecons_piston
 | 
			
		||||
 | 
			
		||||
	dir = piston_get_direction(pistonspec.dir, node)
 | 
			
		||||
	local dir = piston_get_direction(pistonspec.dir, node)
 | 
			
		||||
	local np = mesecon:addPosRule(pos, dir)
 | 
			
		||||
	success, stack = mesecon:mvps_push(np, dir, PISTON_MAXIMUM_PUSH)
 | 
			
		||||
	local success, stack, oldstack = mesecon:mvps_push(np, dir, PISTON_MAXIMUM_PUSH)
 | 
			
		||||
	if success then
 | 
			
		||||
		minetest.env:add_node(pos, {param2 = node.param2, name = pistonspec.onname})
 | 
			
		||||
		minetest.env:add_node(np, {param2 = node.param2, name = pistonspec.pusher})
 | 
			
		||||
		mesecon:mvps_process_stack(stack)
 | 
			
		||||
		minetest.env:add_node(np,  {param2 = node.param2, name = pistonspec.pusher})
 | 
			
		||||
		mesecon:mvps_process_stack (stack)
 | 
			
		||||
		mesecon:mvps_move_objects  (np, dir, oldstack)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@@ -89,7 +90,7 @@ local piston_off = function (pos, node)
 | 
			
		||||
		dir = piston_get_direction(pistonspec.dir, node)
 | 
			
		||||
		pullpos = mesecon:addPosRule(pos, dir)
 | 
			
		||||
		stack = mesecon:mvps_pull_single(pullpos, dir)
 | 
			
		||||
		mesecon:mvps_process_stack(stack)
 | 
			
		||||
		mesecon:mvps_process_stack(pos, dir, stack)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user