1225ca7eca
redstone emulator fix
507 lines
20 KiB
Lua
507 lines
20 KiB
Lua
-- REDSTONE EMULATOR & EDITOR
|
|
--v 06/28/2018a
|
|
|
|
if not init then
|
|
local players = find_player(5);
|
|
if not players then
|
|
name = "";
|
|
else
|
|
name = players[1]
|
|
player_ = puzzle.get_player(name)
|
|
local inv = player_:get_inventory();
|
|
inv:set_stack("main", 8, puzzle.ItemStack("basic_robot:control 1 0 \"@\"")) -- add controller in players inventory
|
|
--add items for building
|
|
inv:set_stack("main", 1, puzzle.ItemStack("default:pick_diamond"))
|
|
inv:set_stack("main", 2, puzzle.ItemStack("basic_robot:button_273 999")) -- switch 9 = 273/274
|
|
inv:set_stack("main", 3, puzzle.ItemStack("basic_robot:button_275 999")) -- button 7 = 275/276
|
|
inv:set_stack("main", 4, puzzle.ItemStack("basic_robot:button_277 999")) -- equalizer 61 = 277
|
|
inv:set_stack("main", 5, puzzle.ItemStack("basic_robot:button_278 999")) -- setter 15 = 278
|
|
inv:set_stack("main", 6, puzzle.ItemStack("basic_robot:button_279 999")) -- piston 171 = 279
|
|
inv:set_stack("main", 7, puzzle.ItemStack("basic_robot:button_282 999")) -- delayer 232 = 282
|
|
inv:set_stack("main", 9, puzzle.ItemStack("basic_robot:button_281 999")) -- NOT 33 = 281
|
|
inv:set_stack("main", 10, puzzle.ItemStack("basic_robot:button_280 999")) -- diode 175 = 280
|
|
inv:set_stack("main", 11, puzzle.ItemStack("basic_robot:button_283 999")) -- platform 22 = 283
|
|
inv:set_stack("main", 12, puzzle.ItemStack("basic_robot:button_284 999")) -- giver 23 150/284
|
|
inv:set_stack("main", 13, puzzle.ItemStack("basic_robot:button_285 999")) -- checker 24 151/285
|
|
|
|
|
|
local round = math.floor; protector_position = function(pos) local r = 32;local ry = 2*r; return {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry,z=round(pos.z/r+0.5)*r}; end
|
|
local spawnblock = protector_position(self.spawnpos())
|
|
|
|
local meta = puzzle.get_meta(spawnblock);
|
|
meta:set_string("shares", name) -- add player to protection!
|
|
puzzle.chat_send_player(name,colorize("yellow","#EDITOR: if you need any blocks get them by using 'give me' in craft guide. you can now use controller to make links from pointed at blocks. In addition hold SHIFT to display infos. Reset block links by selecting block 2x"))
|
|
end
|
|
|
|
init = true
|
|
self.spam(1)
|
|
self.label(colorize("orange","REDSTONE EMULATOR/EDITOR"))
|
|
|
|
|
|
|
|
|
|
-- 1. EMULATOR CODE
|
|
|
|
|
|
TTL = 16 -- signal propagates so many steps before dissipate
|
|
--self.label(colorize("red","REDSTONE")..colorize("yellow","EMULATOR"))
|
|
opcount = 0;
|
|
|
|
-- DEFINITIONS OF BLOCKS THAT CAN BE ACTIVATED
|
|
toggle_button_action = function(mode,pos,ttl) -- SIMPLE TOGGLE BUTTONS - SWITCH
|
|
if not ttl or ttl <=0 then return end
|
|
if mode == 1 then -- turn on
|
|
puzzle.set_node(pos,{name = "basic_robot:button_274"})
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
for i = 1,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
else -- turn off
|
|
puzzle.set_node(pos,{name = "basic_robot:button_273"})
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
for i = 1,n do activate(0,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
end
|
|
end
|
|
|
|
|
|
button_action = function(mode,pos,ttl) -- SIMPLE ON BUTTON, TOGGLES BACK OFF after 1s
|
|
if not ttl or ttl <=0 then return end
|
|
if mode == 0 then return end
|
|
puzzle.set_node(pos,{name = "basic_robot:button_276"})
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
|
|
minetest.after(1, function()
|
|
puzzle.set_node(pos,{name = "basic_robot:button_275"})
|
|
for i = 1,n do activate(0,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
end)
|
|
for i = 1,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
end
|
|
|
|
giver_action = function(mode,pos,ttl) -- GIVER: give block below it to player and activate targets
|
|
local nodename = puzzle.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name;
|
|
if nodename == "air" then return end
|
|
local objects = minetest.get_objects_inside_radius(pos, 5);local player1;
|
|
for _,obj in pairs(objects) do if obj:is_player() then player1 = obj; break end end
|
|
if player1 then
|
|
player1:get_inventory():add_item("main", puzzle.ItemStack(nodename))
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
for i = 1,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
end
|
|
end
|
|
|
|
checker_action = function(mode,pos,ttl) -- CHECKER: check if player has block below it, then remove block from player and activate targets
|
|
local nodename = puzzle.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name;
|
|
if nodename == air then return end
|
|
local objects = minetest.get_objects_inside_radius(pos, 5);local player1;
|
|
for _,obj in pairs(objects) do if obj:is_player() then player1 = obj; break end end
|
|
if player1 then
|
|
local inv = player1:get_inventory();
|
|
if inv:contains_item("main", puzzle.ItemStack(nodename)) then
|
|
inv:remove_item("main",puzzle.ItemStack(nodename))
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
for i = 1,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
end
|
|
end
|
|
end
|
|
|
|
equalizer_action = function(mode,pos,ttl) -- CHECK NODES AT TARGET1,TARGET2. IF EQUAL ACTIVATE TARGET3,TARGET4,...
|
|
if not ttl or ttl <=0 then return end
|
|
if mode == 0 then return end
|
|
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
local node1 = puzzle.get_node({x=meta:get_int("x1")+pos.x,y=meta:get_int("y1")+pos.y,z=meta:get_int("z1")+pos.z}).name
|
|
local node2 = puzzle.get_node({x=meta:get_int("x2")+pos.x,y=meta:get_int("y2")+pos.y,z=meta:get_int("z2")+pos.z}).name
|
|
|
|
|
|
if node1==node2 then
|
|
for i = 3,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
else
|
|
for i = 3,n do activate(0,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
end
|
|
end
|
|
|
|
delayer_action = function(mode,pos,ttl) -- DELAY FORWARD SIGNAL, delay determined by distance of target1 from delayer ( in seconds)
|
|
if not ttl or ttl <=0 then return end
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
|
|
local n = meta:get_int("n");
|
|
local pos1 = {x=meta:get_int("x1"),y=meta:get_int("y1"),z=meta:get_int("z1")}
|
|
local delay = math.sqrt(pos1.x^2+pos1.y^2+pos1.z^2);
|
|
|
|
if delay > 0 then
|
|
minetest.after(delay, function()
|
|
if mode == 1 then
|
|
for i = 2,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
else
|
|
for i = 2,n do activate(0,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
|
|
diode_action = function(mode,pos,ttl) -- ONLY pass through ON signal
|
|
if not ttl or ttl <=0 then return end
|
|
if mode ~= 1 then return end
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
for i = 1,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
end
|
|
|
|
not_action = function(mode,pos,ttl) -- negate signal: 0 <-> 1
|
|
if not ttl or ttl <=0 then return end
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
for i = 1,n do activate(1-mode,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
|
|
end
|
|
|
|
setter_action = function(mode,pos,ttl) -- SETS NODES IN TARGET AREA TO PRESELECTED NODE
|
|
if not ttl or ttl <=0 then return end
|
|
if mode == 0 then return end
|
|
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
if n ~= 3 then say("#setter: error, needs to be set with 3 links"); return end
|
|
local node1 = puzzle.get_node({x=meta:get_int("x1")+pos.x,y=meta:get_int("y1")+pos.y,z=meta:get_int("z1")+pos.z})
|
|
local pos1 = {x=meta:get_int("x2")+pos.x,y=meta:get_int("y2")+pos.y,z=meta:get_int("z2")+pos.z}
|
|
local pos2 = {x=meta:get_int("x3")+pos.x,y=meta:get_int("y3")+pos.y,z=meta:get_int("z3")+pos.z}
|
|
|
|
if pos1.x>pos2.x then pos1.x,pos2.x = pos2.x,pos1.x end
|
|
if pos1.y>pos2.y then pos1.y,pos2.y = pos2.y,pos1.y end
|
|
if pos1.z>pos2.z then pos1.z,pos2.z = pos2.z,pos1.z end
|
|
|
|
local size = (pos2.x-pos1.x+1)*(pos2.y-pos1.y+1)*(pos2.z-pos1.z+1)
|
|
if size > 27 then say("#setter: target area too large, more than 27 blocks!"); return end
|
|
for x = pos1.x,pos2.x do
|
|
for y = pos1.y,pos2.y do
|
|
for z = pos1.z,pos2.z do
|
|
puzzle.set_node({x=x,y=y,z=z},node1)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local piston_displaceable_nodes = {["air"] = 1,["default:water_flowing"] = 1}
|
|
|
|
piston_action = function(mode,pos,ttl) -- PUSH NODE AT TARGET1 AWAY FROM PISTON
|
|
if not ttl or ttl <=0 then return end
|
|
--if mode == 0 then return end
|
|
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
if n < 1 or n>2 then say("#piston: error, needs to be set with at least link and most two"); return end
|
|
local pos1 = {x=meta:get_int("x1")+pos.x,y=meta:get_int("y1")+pos.y,z=meta:get_int("z1")+pos.z}
|
|
|
|
-- determine direction
|
|
local dir = {x=pos1.x-pos.x, y= pos1.y-pos.y, z= pos1.z-pos.z};
|
|
|
|
local dirabs = {x=math.abs(dir.x), y= math.abs(dir.y), z= math.abs(dir.z)};
|
|
local dirmax = math.max(dirabs.x,dirabs.y,dirabs.z);
|
|
|
|
if dirabs.x == dirmax then dir = { x = dir.x>0 and 1 or -1, y = 0,z = 0 }
|
|
elseif dirabs.y == dirmax then dir = { x = 0, y = dir.y>0 and 1 or -1, z=0}
|
|
else dir = {x = 0, y = 0, z = dir.z>0 and 1 or -1}
|
|
end
|
|
|
|
local pos2 = {x=pos1.x+dir.x,y=pos1.y+dir.y,z=pos1.z+dir.z};
|
|
|
|
if mode == 0 then pos1,pos2 = pos2,pos1 end
|
|
|
|
local node1 = puzzle.get_node(pos1)
|
|
if node1.name == "air" then return end
|
|
|
|
|
|
if piston_displaceable_nodes[puzzle.get_node(pos2).name] then
|
|
puzzle.set_node(pos2, node1)
|
|
puzzle.set_node(pos1, {name = "air"})
|
|
minetest.check_for_falling(pos2)
|
|
self.sound("doors_door_open",1,pos)
|
|
end
|
|
end
|
|
|
|
platform_action = function(mode,pos,ttl) -- SPAWN MOVING PLATFORM
|
|
|
|
if mode~=1 then return end
|
|
local meta = puzzle.get_meta(pos);
|
|
if not meta then return end
|
|
local n = meta:get_int("n");
|
|
if n ~= 2 then say("#platform: error, needs to be set with 2 targets"); return end
|
|
local pos1 = {x=meta:get_int("x1")+pos.x,y=meta:get_int("y1")+pos.y,z=meta:get_int("z1")+pos.z}
|
|
local pos2 = {x=meta:get_int("x2")+pos.x,y=meta:get_int("y2")+pos.y,z=meta:get_int("z2")+pos.z}
|
|
|
|
-- determine direction
|
|
local dir = {x=pos2.x-pos1.x, y= pos2.y-pos1.y, z= pos2.z-pos1.z};
|
|
|
|
local obj = minetest.add_entity(pos1, "basic_robot:projectile");
|
|
|
|
if not obj then return end
|
|
obj:setvelocity(dir);
|
|
--obj:setacceleration({x=0,y=-gravity,z=0});
|
|
local luaent = obj:get_luaentity();
|
|
luaent.name = name;
|
|
luaent.spawnpos = pos1;
|
|
|
|
local nodename = puzzle.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name;
|
|
local tiles = minetest.registered_nodes[nodename].tiles; tiles = tiles or {};
|
|
local texture = tiles[1] or "default_stone";
|
|
obj:set_properties({visual = "cube",textures = {texture,texture,texture,texture,texture,texture},visual_size = {x=1,y=1},
|
|
collisionbox={-0.5,-0.5,-0.5,0.5,0.5,0.5}})
|
|
end
|
|
|
|
|
|
-- HOW TO ACTIVATE TARGET ELEMENT - adds mesecons/basic machines compatibility
|
|
activate = function(mode, pos, ttl)
|
|
if not ttl or ttl <=0 then return end
|
|
local nodename = puzzle.get_node(pos).name;
|
|
local active_element = active_elements[nodename];
|
|
opcount = opcount + 1
|
|
if opcount > 64 then say("#puzzle error: opcount 64 exceeded. too many active connections."); error("#puzzle: abort") end
|
|
|
|
if active_element then
|
|
active_element(mode,pos,ttl-1)
|
|
else -- try mesecons activate
|
|
local nodename = puzzle.get_node(pos).name
|
|
local table = minetest.registered_nodes[nodename];
|
|
if table and table.mesecons then else return end
|
|
|
|
local effector=table.mesecons.effector;
|
|
|
|
if mode == 1 then
|
|
if effector.action_on then
|
|
effector.action_on(pos,node,ttl)
|
|
end
|
|
else
|
|
if effector.action_off then
|
|
effector.action_off(pos,node,ttl)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- THESE REACT WHEN PUNCHED
|
|
interactive_elements = {
|
|
[275] = {button_action,1}, -- BUTTON, 1 means it activates(ON) on punch
|
|
[273] = {toggle_button_action,1}, -- TOGGLE BUTTON_OFF
|
|
[274] = {toggle_button_action,0}, -- TOGGLE BUTTON_ON, 0 means it deactivates
|
|
[284] = {giver_action,0}, -- GIVER: give player item below it when activated and activate targets after that
|
|
[285] = {checker_action,0}, -- CHECKER: check if player has block below it in inventory, remove it and activate targets after that
|
|
}
|
|
|
|
-- THESE CAN BE ACTIVATED WITH SIGNAL
|
|
active_elements = {
|
|
["basic_robot:button_275"] = button_action, -- BUTTON, what action to do on activate
|
|
["basic_robot:button_273"] = toggle_button_action, -- TOGGLE BUTTON_OFF
|
|
["basic_robot:button_274"] = toggle_button_action, -- TOGGLE BUTTON_ON
|
|
["basic_robot:button_278"] = setter_action, -- SETTER
|
|
["basic_robot:button_277"] = equalizer_action, -- EQUALIZER
|
|
["basic_robot:button_279"] = piston_action, -- PISTON
|
|
["basic_robot:button_283"] = platform_action, -- PLATFORM
|
|
["basic_robot:button_282"] = delayer_action, -- DELAYER
|
|
["basic_robot:button_280"] = diode_action, -- DIODE
|
|
["basic_robot:button_281"] = not_action, -- NOT
|
|
}
|
|
|
|
|
|
-- EDITOR CODE --
|
|
|
|
edit = {};
|
|
edit.state = 1; -- tool state
|
|
edit.source = {}; edit.sourcenode = ""; -- selected source
|
|
|
|
-- blocks that can be activated
|
|
edit.active_elements = {
|
|
["basic_robot:button_275"] = "button: now select one or more targets", -- button
|
|
["basic_robot:button_273"] = "switch: now select one or more targets", -- switch OFF
|
|
["basic_robot:button_274"] = "switch: now select one or more targets", -- switch ON
|
|
["basic_robot:button_278"] = "setter: target1 defines what material wall will use, target2/3 defines where wall will be", -- setter
|
|
["basic_robot:button_277"] = "equalizer: target1 and target2 are for comparison, other targets are activated", -- equalizer
|
|
["basic_robot:button_279"] = "piston: push block at target1 in direction away from piston", -- equalizer
|
|
["basic_robot:button_283"] = "platform: select target1 to set origin, target2 for direction", -- PLATFORM
|
|
["basic_robot:button_282"] = "delayer: distance from delayer to target1 determines delay", -- delayer
|
|
["basic_robot:button_280"] = "diode: only pass through ON signal", -- DIODE
|
|
["basic_robot:button_281"] = "NOT gate: negates the signal", -- NOT
|
|
|
|
["basic_robot:button_284"] = "GIVER: give player item below it when activated and activate targets after that",
|
|
["basic_robot:button_285"] = "CHECKER: check if player has block below it in inventory, remove it and activate targets after that",
|
|
}
|
|
|
|
linker_use = function(pos)
|
|
if not pos then return end
|
|
|
|
--say(serialize(player_:get_player_control()))
|
|
if edit.state < 0 then -- link edit mode!
|
|
local meta = puzzle.get_meta(edit.source);
|
|
local i = -edit.state;
|
|
meta:set_int("x" ..i, pos.x-edit.source.x); meta:set_int("y" ..i, pos.y-edit.source.y); meta:set_int("z" ..i, pos.z-edit.source.z)
|
|
puzzle.chat_send_player(name, colorize("red", "EDIT ".. " target " .. i .. " changed"))
|
|
edit.state = 1
|
|
goto display_particle
|
|
end
|
|
|
|
if player_:get_player_control().sneak then -- SHOW LINKS
|
|
local meta = puzzle.get_meta(pos);
|
|
local n = meta:get_int("n");
|
|
local nodename = puzzle.get_node(pos).name;
|
|
local active_element = edit.active_elements[nodename]
|
|
if active_element and edit.source.x == pos.x and edit.source.y == pos.y and edit.source.z == pos.z then -- gui with more info
|
|
local form = "size[4,"..(0.75*n).."] label[0,-0.25; "..active_element .."]" ;
|
|
for i = 1,n do -- add targets as lines
|
|
form = form ..
|
|
"button[0,".. (0.75*i-0.5) .. ";1,1;".."S"..i..";" .. "show " .. i .. "]"..
|
|
"button_exit[1,".. (0.75*i-0.5) .. ";1,1;".."E"..i..";" .. "edit " .. "]" ..
|
|
"button_exit[2,".. (0.75*i-0.5) .. ";1,1;".."D"..i..";" .. "delete " .. "]"..
|
|
"label[3,".. (0.75*i-0.25) .. "; " .. meta:get_int("x"..i) .. " " .. meta:get_int("y"..i) .. " " .. meta:get_int("z"..i) .."]"
|
|
end
|
|
self.show_form(name,form);
|
|
edit.state = 3;
|
|
return
|
|
end
|
|
edit.source = {x=pos.x,y=pos.y, z=pos.z};
|
|
edit.state = 1
|
|
if not active_element then return end
|
|
local i = string.find(active_element,":");
|
|
if not i then return end
|
|
puzzle.chat_send_player(name,colorize("red","#INFO ".. string.sub(active_element,1,i-1) ..":") .." has " .. n .. " targets. Select again for more info.")
|
|
meta:set_string("infotext",string.sub(active_element,1,i-1)) -- write name of element on it!
|
|
|
|
for i = 1, n do
|
|
minetest.add_particle(
|
|
{
|
|
pos = {x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},
|
|
expirationtime = 5,
|
|
velocity = {x=0, y=0,z=0},
|
|
size = 18,
|
|
texture = "010.png",
|
|
acceleration = {x=0,y=0,z=0},
|
|
collisiondetection = true,
|
|
collision_removal = true,
|
|
}
|
|
)
|
|
end
|
|
return
|
|
end
|
|
|
|
if edit.state == 1 then -- SET SOURCE
|
|
local nodename = puzzle.get_node(pos).name;
|
|
local active_element = edit.active_elements[nodename]
|
|
if not active_element then puzzle.chat_send_player(name,colorize("red","#ERROR linker:").. " source must be valid element like switch"); return end
|
|
edit.source = {x=pos.x,y=pos.y, z=pos.z};
|
|
sourcenode = nodename;
|
|
puzzle.chat_send_player(name, colorize("yellow","SETUP " ..edit.state .. ": ").. active_element)
|
|
edit.state = 2
|
|
else -- SET TARGET
|
|
local meta = puzzle.get_meta(edit.source);
|
|
local n = meta:get_int("n");
|
|
|
|
if edit.state == 2 and pos.x == edit.source.x and pos.y == edit.source.y and pos.z == edit.source.z then -- RESET LINK FOR SOURCE
|
|
local meta = puzzle.get_meta(pos);meta:set_int("n",0) -- reset links
|
|
puzzle.chat_send_player(name, colorize("red", "SETUP " .. edit.state .. ":") .. " resetted links for selected source.")
|
|
edit.state = 1;return
|
|
else
|
|
n=n+1;
|
|
meta:set_int("x"..n, pos.x-edit.source.x);meta:set_int("y"..n, pos.y-edit.source.y);meta:set_int("z"..n, pos.z-edit.source.z) -- relative to source!
|
|
meta:set_int("n",n)
|
|
puzzle.chat_send_player(name, colorize("red", "SETUP "..edit.state .. ":") .. " added target #" .. n)
|
|
edit.state = 1
|
|
end
|
|
end
|
|
|
|
-- display
|
|
::display_particle::
|
|
|
|
minetest.add_particle(
|
|
{
|
|
pos = pos,
|
|
expirationtime = 5,
|
|
velocity = {x=0, y=0,z=0},
|
|
size = 18,
|
|
texture = "009.png",
|
|
acceleration = {x=0,y=0,z=0},
|
|
collisiondetection = true,
|
|
collision_removal = true,
|
|
}
|
|
)
|
|
end
|
|
|
|
tools = {
|
|
["basic_robot:control"] = linker_use
|
|
}
|
|
|
|
------ END OF EDIT PROGRAM
|
|
|
|
end
|
|
|
|
opcount = 0
|
|
event = keyboard.get() -- handle keyboard
|
|
if event then
|
|
if event.type == 0 then -- EDITING
|
|
if event.puncher == name then -- players in protection can edit -- not minetest.is_protected({x=event.x,y=event.y,z=event.z},event.puncher)
|
|
local wield_item = player_:get_wielded_item():get_name()
|
|
local tool = tools[wield_item]
|
|
if tool then tool({x=event.x,y=event.y,z=event.z}) end
|
|
end
|
|
else -- EMULATOR
|
|
local typ = event.type;
|
|
local interactive_element = interactive_elements[typ]
|
|
if interactive_element then
|
|
interactive_element[1](interactive_element[2],{x=event.x,y=event.y,z=event.z},TTL)
|
|
self.sound("doors_glass_door_open",1,{x=event.x,y=event.y,z=event.z})
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
sender,fields = self.read_form() -- handle gui for editing
|
|
if sender then
|
|
edit.state = 1
|
|
for k,_ in pairs(fields) do
|
|
local c = string.sub(k,1,1);
|
|
local i = tonumber(string.sub(k,2)) or 1;
|
|
if c == "S" then
|
|
|
|
local meta = puzzle.get_meta(edit.source);
|
|
minetest.add_particle(
|
|
{
|
|
pos = {x=meta:get_int("x"..i)+edit.source.x,y=meta:get_int("y"..i)+edit.source.y,z=meta:get_int("z"..i)+edit.source.z},
|
|
expirationtime = 5,
|
|
velocity = {x=0, y=0,z=0},
|
|
size = 18,
|
|
texture = "010.png",
|
|
acceleration = {x=0,y=0,z=0},
|
|
collisiondetection = true,
|
|
collision_removal = true,
|
|
}
|
|
)
|
|
elseif c == "E" then
|
|
edit.state = -i;
|
|
puzzle.chat_send_player(name, colorize("yellow", "#EDIT: select target " .. i));
|
|
elseif c == "D" then
|
|
local meta = puzzle.get_meta(edit.source);
|
|
local n = meta:get_int("n")
|
|
if n > 0 then
|
|
for j = i,n-1 do
|
|
meta:set_int("x"..j, meta:get_int("x"..(j+1)))
|
|
meta:set_int("y"..j, meta:get_int("y"..(j+1)))
|
|
meta:set_int("z"..j, meta:get_int("z"..(j+1)))
|
|
end
|
|
meta:set_int("n",n-1)
|
|
end
|
|
puzzle.chat_send_player(name, colorize("red", "#EDIT: target " .. i .. " deleted"));
|
|
end
|
|
--say(serialize(fields))
|
|
end
|
|
end |