046bcc445a
-puzzle privs, puzzle mechanics
448 lines
18 KiB
Lua
448 lines
18 KiB
Lua
-- REDSTONE EMULATOR & EDITOR
|
|
--v 10/14a
|
|
|
|
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
|
|
|
|
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"))
|
|
|
|
|
|
-- 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); 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); 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); 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
|
|
|
|
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); 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); 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); 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); 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); 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); 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); 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];
|
|
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
|
|
--TODO
|
|
-- inventory checker(taker) : basic_robot:button_63 -> if player has stuff it will activate items after punch
|
|
-- inventory give: give item that is at position1 and activate selected machine at position2
|
|
}
|
|
|
|
-- 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: set block at target region {target2,target3} to block at target1", -- equalizer
|
|
["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
|
|
}
|
|
|
|
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
|
|
|
|
|
|
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 |