Make pistons and movestones move objects (push only yet)

This commit is contained in:
Jeija 2013-04-02 11:56:37 +02:00
parent e789794c75
commit 3b38bbcaf2
4 changed files with 126 additions and 41 deletions

View File

@ -22,3 +22,17 @@ end
function mesecon:cmpPos(p1, p2) function mesecon:cmpPos(p1, p2)
return (p1.x == p2.x and p1.y == p2.y and p1.z == p2.z) return (p1.x == p2.x and p1.y == p2.y and p1.z == p2.z)
end 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

View File

@ -77,8 +77,9 @@ minetest.register_entity("mesecons_movestones:movestone_entity", {
physical = false, physical = false,
visual = "sprite", 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"}, 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", visual = "cube",
lastdir = {x=0, y=0, z=0},
on_punch = function(self, hitter) on_punch = function(self, hitter)
self.object:remove() 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) 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) 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 local name = minetest.env:get_node(pos).name
if name ~= "air" and name ~= "ignore" and minetest.registered_nodes[name].liquidtype == "none" then if name ~= "air" and name ~= "ignore"
mesecon:mvps_push(pos, direction, MOVESTONE_MAXIMUM_PUSH) and minetest.registered_nodes[name].liquidtype == "none" then
mesecon:mvps_push(pos, self.lastdir, MOVESTONE_MAXIMUM_PUSH)
end end
minetest.env:add_node(pos, {name="mesecons_movestones:movestone"}) minetest.env:add_node(pos, {name="mesecons_movestones:movestone"})
self.object:remove() self.object:remove()
return return
end end
local np = mesecon:addPosRule(pos, direction) local success, stack, oldstack =
if not mesecon:mvps_push(np, direction, MOVESTONE_MAXIMUM_PUSH) then 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"}) minetest.env:add_node(pos, {name="mesecons_movestones:movestone"})
self.object:remove() self.object:remove()
return return
else
mesecon:mvps_process_stack (stack)
mesecon:mvps_move_objects (pos, direction, oldstack)
self.lastdir = direction
end end
self.object:setvelocity({x=direction.x*2, y=direction.y*2, z=direction.z*2}) 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, physical = false,
visual = "sprite", 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"}, 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", visual = "cube",
lastdir = {x=0, y=0, z=0},
on_punch = function(self, hitter) on_punch = function(self, hitter)
self.object:remove() 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) 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) 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 local name = minetest.env:get_node(pos).name
if name ~= "air" and name ~= "ignore" and minetest.registered_nodes[name].liquidtype == "none" then if name ~= "air" and name ~= "ignore"
mesecon:mvps_push(pos, direction, MOVESTONE_MAXIMUM_PUSH) and minetest.registered_nodes[name].liquidtype == "none" then
mesecon:mvps_push(pos, self.lastdir, MOVESTONE_MAXIMUM_PUSH)
end end
minetest.env:add_node(pos, {name="mesecons_movestones:sticky_movestone"}) minetest.env:add_node(pos, {name="mesecons_movestones:sticky_movestone"})
self.object:remove() self.object:remove()
return return
end end
local np = mesecon:addPosRule(pos, direction) local success, stack, oldstack =
if not mesecon:mvps_push(np, direction, MOVESTONE_MAXIMUM_PUSH) then 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"}) minetest.env:add_node(pos, {name="mesecons_movestones:sticky_movestone"})
self.object:remove() self.object:remove()
return return
else
mesecon:mvps_process_stack (stack)
mesecon:mvps_move_objects (pos, direction, oldstack)
self.lastdir = direction
end end
self.object:setvelocity({x=direction.x*2, y=direction.y*2, z=direction.z*2}) 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) mesecon:mvps_pull_all(pos, direction)
end, end,
}) })
mesecon:register_mvps_unmov("mesecons_movestones:movestone_entity")
mesecon:register_mvps_unmov("mesecons_movestones:sticky_movestone_entity")

View File

@ -1,6 +1,7 @@
--register stoppers for movestones/pistons --register stoppers for movestones/pistons
mesecon.mvps_stoppers={} mesecon.mvps_stoppers = {}
mesecon.mvps_unmov = {}
function mesecon:is_mvps_stopper(node, pushdir, stack, stackid) function mesecon:is_mvps_stopper(node, pushdir, stack, stackid)
local get_stopper = mesecon.mvps_stoppers[node.name] 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 mesecon.mvps_stoppers[nodename] = get_stopper
end 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) function mesecon:mvps_process_stack(stack)
-- update mesecons for placed nodes ( has to be done after all nodes have been added ) -- update mesecons for placed nodes ( has to be done after all nodes have been added )
for _, n in ipairs(stack) do for _, n in ipairs(stack) do
@ -26,13 +36,12 @@ function mesecon:mvps_process_stack(stack)
end end
end end
function mesecon:mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: direction of push; maximum: maximum nodes to be pushed function mesecon:mvps_get_stack(pos, dir, maximum)
np = {x = pos.x, y = pos.y, z = pos.z}
-- determine the number of nodes to be pushed -- determine the number of nodes to be pushed
local np = {x = pos.x, y = pos.y, z = pos.z}
local nodes = {} local nodes = {}
while true do 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 if not nn or #nodes > maximum then
-- don't push at all, something is in the way (unloaded map or too many nodes) -- don't push at all, something is in the way (unloaded map or too many nodes)
return return
@ -47,6 +56,11 @@ function mesecon:mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: directio
np = mesecon:addPosRule(np, dir) np = mesecon:addPosRule(np, dir)
end 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 -- determine if one of the nodes blocks the push
for id, n in ipairs(nodes) do 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) minetest.env:get_meta(np):from_table(n.meta)
end end
local oldstack = mesecon:tablecopy(nodes)
for i in ipairs(nodes) do for i in ipairs(nodes) do
nodes[i].pos = mesecon:addPosRule(nodes[i].pos, dir) nodes[i].pos = mesecon:addPosRule(nodes[i].pos, dir)
end end
return true, nodes return true, nodes, oldstack
end end
function mesecon:mvps_pull_single(pos, dir) -- pos: pos of mvps; direction: direction of pull (matches push direction for sticky pistons) 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 end
function mesecon:mvps_pull_all(pos, direction) -- pos: pos of mvps; direction: direction of pull 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 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 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 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 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 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 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} local oldpos = {x=lpos2.x+direction.x, y=lpos2.y+direction.y, z=lpos2.z+direction.z}
repeat repeat
lnode2 = minetest.env:get_node(lpos2) lnode2 = minetest.env:get_node(lpos2)
minetest.env:add_node(oldpos, {name=lnode2.name}) minetest.env:add_node(oldpos, {name=lnode2.name})
nodeupdate(oldpos) nodeupdate(oldpos)
oldpos = {x=lpos2.x, y=lpos2.y, z=lpos2.z} oldpos = {x=lpos2.x, y=lpos2.y, z=lpos2.z}
lpos2.x = lpos2.x-direction.x lpos2.x = lpos2.x-direction.x
lpos2.y = lpos2.y-direction.y lpos2.y = lpos2.y-direction.y
lpos2.z = lpos2.z-direction.z lpos2.z = lpos2.z-direction.z
lnode = minetest.env:get_node(lpos2) lnode = minetest.env:get_node(lpos2)
until lnode.name=="air" or lnode.name=="ignore" or not(minetest.registered_nodes[lnode2.name].liquidtype == "none") until lnode.name=="air" or lnode.name=="ignore" or not(minetest.registered_nodes[lnode2.name].liquidtype == "none")
minetest.env:remove_node(oldpos) 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 end
mesecon:register_mvps_stopper("default:chest_locked") mesecon:register_mvps_stopper("default:chest_locked")

View File

@ -70,13 +70,14 @@ end
local piston_on = function (pos, node) local piston_on = function (pos, node)
local pistonspec = minetest.registered_nodes[node.name].mesecons_piston 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) 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 if success then
minetest.env:add_node(pos, {param2 = node.param2, name = pistonspec.onname}) minetest.env:add_node(pos, {param2 = node.param2, name = pistonspec.onname})
minetest.env:add_node(np, {param2 = node.param2, name = pistonspec.pusher}) minetest.env:add_node(np, {param2 = node.param2, name = pistonspec.pusher})
mesecon:mvps_process_stack(stack) mesecon:mvps_process_stack (stack)
mesecon:mvps_move_objects (np, dir, oldstack)
end end
end end
@ -89,7 +90,7 @@ local piston_off = function (pos, node)
dir = piston_get_direction(pistonspec.dir, node) dir = piston_get_direction(pistonspec.dir, node)
pullpos = mesecon:addPosRule(pos, dir) pullpos = mesecon:addPosRule(pos, dir)
stack = mesecon:mvps_pull_single(pullpos, dir) stack = mesecon:mvps_pull_single(pullpos, dir)
mesecon:mvps_process_stack(stack) mesecon:mvps_process_stack(pos, dir, stack)
end end
end end