book editor/code loader
master
rnd1 2017-01-18 17:13:17 +01:00
parent d9a90160a7
commit 6c82554a65
261 changed files with 312 additions and 30 deletions

View File

@ -89,6 +89,7 @@ basic_robot.commands.dig = function(name,dir)
local obj = basic_robot.data[name].obj; local obj = basic_robot.data[name].obj;
local pos = pos_in_dir(obj, dir) local pos = pos_in_dir(obj, dir)
local luaent = obj:get_luaentity(); local luaent = obj:get_luaentity();
if minetest.is_protected(pos,luaent.owner) then return false end if minetest.is_protected(pos,luaent.owner) then return false end
@ -103,13 +104,12 @@ basic_robot.commands.dig = function(name,dir)
basic_robot.give_drops(nodename, inv); basic_robot.give_drops(nodename, inv);
minetest.set_node(pos,{name = "air"}) minetest.set_node(pos,{name = "air"})
--DS: sounds --DS: sounds
local sounds = minetest.registered_nodes[nodename].sounds local sounds = minetest.registered_nodes[nodename].sounds
if sounds then if sounds then
local sound = sounds.dug local sound = sounds.dug
if sound then if sound then
minetest.sound_play(sound,{object=obj, max_hear_distance = 10}) minetest.sound_play(sound,{pos=pos, max_hear_distance = 10})
end end
end end
@ -228,9 +228,6 @@ basic_robot.commands.pickup = function(r,name)
end end
basic_robot.commands.read_node = function(name,dir) basic_robot.commands.read_node = function(name,dir)
local obj = basic_robot.data[name].obj; local obj = basic_robot.data[name].obj;
local pos = pos_in_dir(obj, dir) local pos = pos_in_dir(obj, dir)
@ -276,7 +273,7 @@ basic_robot.commands.place = function(name,nodename, dir)
if sounds then if sounds then
local sound = sounds.place local sound = sounds.place
if sound then if sound then
minetest.sound_play(sound,{object=obj, max_hear_distance = 10}) minetest.sound_play(sound,{pos=pos, max_hear_distance = 10})
end end
end end
end end
@ -339,7 +336,7 @@ end
basic_robot.commands.read_book = function (itemstack) -- itemstack should contain book basic_robot.commands.read_book = function (itemstack) -- itemstack should contain book
local data = minetest.deserialize(itemstack:get_metadata()) local data = minetest.deserialize(itemstack:get_metadata())
if data then if data then
return data.text; return data.title,data.text;
else else
return nil return nil
end end
@ -400,3 +397,134 @@ basic_robot.give_drops = function(nodename, inv) -- gives apropriate drops when
end end
local render_text = function(text,linesize)
local count = math.floor(string.len(text)/linesize)+1;
local width = 18; local height = 24;
local tex = "";
local y = 0; local x=0;
for i=1,string.len(text) do
local cb = string.byte(text,i);
local c = "";
if cb == 10 or cb == 13 then
y=y+1; x=0
else
c = string.format("%03d",cb)..".png"
tex = tex .. ":" .. (x*width) .. "," .. (y*height) .. "=" .. c;
if x==linesize-1 then y=y+1 x=0 else x=x+1 end
end
end
local background = "(black_screen.png^[resize:"..(linesize*width).. "x".. (linesize*height) ..")";
tex = "([combine:"..(linesize*width).."x"..(linesize*height)..tex..")";
tex = background .. "^" .. tex;
return tex;
end
text = "";
basic_robot.commands.display_text = function(obj,text,linesize,size)
if not linesize then linesize = 20 end
if not size then size = 1 end
if string.len(text)>linesize*linesize then text = string.sub(text,1,linesize*linesize) end
local tex = render_text(text,linesize);
if string.len(tex)<60000 then
obj:set_properties({textures={"arrow.png","basic_machine_side.png",tex,"basic_machine_side.png","basic_machine_side.png","basic_machine_side.png"},visual_size = {x=size,y=size}})
else
self.label("error: string too long")
end
end
basic_robot.commands.activate = function(name,mode, dir)
local obj = basic_robot.data[name].obj;
local tpos = pos_in_dir(obj, dir); -- position of target block in front
local node = minetest.get_node(tpos);
local table = minetest.registered_nodes[node.name];
if table and table.mesecons and table.mesecons.effector then
else
return
end -- error
local effector=table.mesecons.effector;
if mode > 0 then
if not effector.action_on then return end
effector.action_on(tpos,node,16)
elseif mode<0 then
if not effector.action_off then return end
effector.action_off(tpos,node,16)
end
end
local register_robot_button = function(R,G,B,type)
minetest.register_node("basic_robot:button"..R..G..B,
{
description = "robot button",
tiles = {"robot_button.png^[colorize:#"..R..G..B..":180"},
is_ground_content = false,
groups = {cracky=3},
on_punch = function(pos, node, player)
local name = player:get_player_name(); if name==nil then return end
local round = math.floor;
local r = 20; local ry = 2*r;
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
local meta = minetest.get_meta(ppos);
local name = meta:get_string("name");
local data = basic_robot.data[name];
if data then data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = player:get_player_name(), type = type} end
end
})
end
register_robot_button("FF","FF","FF",1);
register_robot_button("80","80","80",2);
register_robot_button("FF","80","80",3);
register_robot_button("80","FF","80",4);
register_robot_button("80","80","FF",5);
register_robot_button("FF","FF","80",6);
-- interactive button for robot: place robot on top of protector to intercept events
basic_robot.commands.keyboard = {
get = function(name)
local data = basic_robot.data[name];
if data.keyboard then
local keyboard = data.keyboard;
local event = {x=keyboard.x,y=keyboard.y,z=keyboard.z, puncher = keyboard.puncher, type = keyboard.type};
data.keyboard = nil;
return event
else
return nil
end
end,
set = function(spos,pos,type)
if math.abs(pos.x-spos.x)>10 or math.abs(pos.y-spos.y)>10 or math.abs(pos.z-spos.z)>10 then return false end
local nodename;
if type == 0 then
nodename = "air"
elseif type == 1 then
nodename = "basic_robot:buttonFFFFFF";
elseif type == 2 then
nodename = "basic_robot:button808080";
elseif type == 3 then
nodename = "basic_robot:buttonFF8080";
elseif type == 4 then
nodename = "basic_robot:button80FF80";
elseif type == 5 then
nodename = "basic_robot:button8080FF";
elseif type == 6 then
nodename = "basic_robot:buttonFFFF80";
end
minetest.swap_node(pos, {name = nodename})
return true
end,
}

194
init.lua
View File

@ -13,7 +13,7 @@ basic_robot.maxdig = 1; -- how many digs allowed per run, 0 = unlimited
basic_robot.version = "12/21a"; basic_robot.version = "01/18a";
basic_robot.data = {}; -- stores all robot data basic_robot.data = {}; -- stores all robot data
--[[ --[[
@ -100,6 +100,16 @@ function getSandboxEnv (name)
self = function(itemname, inventory) return commands.check_inventory(name,itemname, inventory,0) end, self = function(itemname, inventory) return commands.check_inventory(name,itemname, inventory,0) end,
}, },
activate = {
left = function(mode) return commands.activate(name,mode, 1) end,
right = function(mode) return commands.activate(name,mode, 2) end,
forward = function(mode) return commands.activate(name,mode, 3) end,
backward = function(mode) return commands.activate(name,mode, 4) end,
down = function(mode) return commands.activate(name,mode, 6) end,
up = function(mode) return commands.activate(name,mode, 5) end,
forward_down = function(mode) return commands.activate(name,mode, 7) end,
},
pickup = function(r) -- pick up items around robot pickup = function(r) -- pick up items around robot
commands.pickup(r, name); commands.pickup(r, name);
end, end,
@ -107,7 +117,7 @@ function getSandboxEnv (name)
self = { self = {
pos = function() return basic_robot.data[name].obj:getpos() end, pos = function() return basic_robot.data[name].obj:getpos() end,
spawnpos = function() return basic_robot.data[name].spawnpos end, spawnpos = function() local pos = basic_robot.data[name].spawnpos; return {x=pos.x,y=pos.y,z=pos.z} end,
name = function() return name end, name = function() return name end,
viewdir = function() local yaw = basic_robot.data[name].obj:getyaw(); return {x=math.cos(yaw), y = 0, z=math.sin(yaw)} end, viewdir = function() local yaw = basic_robot.data[name].obj:getyaw(); return {x=math.cos(yaw), y = 0, z=math.sin(yaw)} end,
@ -195,6 +205,17 @@ function getSandboxEnv (name)
obj:set_properties({nametag = "[" .. name .. "] " .. text}); obj:set_properties({nametag = "[" .. name .. "] " .. text});
end, end,
display_text = function(text,linesize,size)
local obj = basic_robot.data[name].obj;
commands.display_text(obj,text,linesize,size)
end,
},
keyboard = {
get = function() return commands.keyboard.get(name) end,
set = function(pos,type) return commands.keyboard.set(basic_robot.data[name].spawnpos,pos,type) end,
read = function(pos) return minetest.get_node(pos).name end,
}, },
find_nodes = find_nodes =
@ -249,8 +270,8 @@ function getSandboxEnv (name)
right = function(text) return commands.write_text(name,2,text) end, right = function(text) return commands.write_text(name,2,text) end,
forward = function(text) return commands.write_text(name,3,text) end, forward = function(text) return commands.write_text(name,3,text) end,
backward = function(text) return commands.write_text(name,4,text) end, backward = function(text) return commands.write_text(name,4,text) end,
down = function(text) return commands.write_text(name,5,text) end, down = function(text) return commands.write_text(name,6,text) end,
up = function(text) return commands.write_text(name,6,text) end, up = function(text) return commands.write_text(name,5,text) end,
}, },
say = function(text) say = function(text)
@ -498,7 +519,6 @@ local function preprocess_code(script)
end end
end end
i2=string.find (script, "goto ", i1) -- fix goto OK i2=string.find (script, "goto ", i1) -- fix goto OK
if i2 then if i2 then
if not is_inside_string(i2,script) then if not is_inside_string(i2,script) then
@ -517,7 +537,6 @@ end
local function CompileCode ( script ) local function CompileCode ( script )
--minetest.chat_send_all(script) --minetest.chat_send_all(script)
--if true then return nil, "" end --if true then return nil, "" end
@ -593,8 +612,8 @@ local robot_spawner_update_form = function (pos, mode)
if mode ~= 1 then -- when placed if mode ~= 1 then -- when placed
form = form =
"size[9.5,6]" .. -- width, height "size[9.5,8]" .. -- width, height
"textarea[1.25,-0.25;8.75,7.6;code;;".. code.."]".. "textarea[1.25,-0.25;8.75,9.8;code;;".. code.."]"..
"button_exit[-0.25,-0.25;1.25,1;OK;SAVE]".. "button_exit[-0.25,-0.25;1.25,1;OK;SAVE]"..
"button_exit[-0.25, 0.75;1.25,1;spawn;START]".. "button_exit[-0.25, 0.75;1.25,1;spawn;START]"..
"button[-0.25, 1.75;1.25,1;despawn;STOP]".. "button[-0.25, 1.75;1.25,1;despawn;STOP]"..
@ -605,8 +624,8 @@ local robot_spawner_update_form = function (pos, mode)
else -- when robot clicked else -- when robot clicked
form = form =
"size[9.5,6]" .. -- width, height "size[9.5,8]" .. -- width, height
"textarea[1.25,-0.25;8.75,7.6;code;;".. code.."]".. "textarea[1.25,-0.25;8.75,9.8;code;;".. code.."]"..
"button_exit[-0.25,-0.25;1.25,1;OK;SAVE]".. "button_exit[-0.25,-0.25;1.25,1;OK;SAVE]"..
"button[-0.25, 1.75;1.25,1;despawn;STOP]".. "button[-0.25, 1.75;1.25,1;despawn;STOP]"..
"button[-0.25, 3.6;1.25,1;inventory;storage]".. "button[-0.25, 3.6;1.25,1;inventory;storage]"..
@ -749,7 +768,7 @@ minetest.register_entity("basic_robot:robot",{
local text = minetest.formspec_escape(self.code); local text = minetest.formspec_escape(self.code);
local form = robot_spawner_update_form(self.spawnpos,1); local form = robot_spawner_update_form(self.spawnpos,1);
minetest.show_formspec(clicker:get_player_name(), "robot_worker_" .. self.name, form); -- yyy minetest.show_formspec(clicker:get_player_name(), "robot_worker_" .. self.name, form);
end, end,
}) })
@ -788,6 +807,77 @@ local spawn_robot = function(pos,node,ttl)
local id = meta:get_int("id"); local id = meta:get_int("id");
local name = owner..id; local name = owner..id;
if id == 0 then -- just compile code and run it, no robot spawn
local codechange = false;
if meta:get_int("codechange") == 1 then
meta:set_int("codechange",0);
codechange = true;
end
-- compile code & run it
local err;
local data = basic_robot.data[name];
if codechange or (not data) then
basic_robot.data[name] = {}; data = basic_robot.data[name];
meta:set_string("infotext",minetest.get_gametime().. " code changed ")
if meta:get_int("admin") == 1 then data.isadmin = 1 end
if not basic_robot.data[name].obj then
--create virtual robot that reports position and other properties
local obj = {};
function obj:getpos() return {x=pos.x,y=pos.y,z=pos.z} end
function obj:getyaw() return 0 end
function obj:get_luaentity()
local luaent = {};
luaent.owner = owner
luaent.spawnpos = {x=pos.x,y=pos.y-1,z=pos.z};
return luaent
end
function obj:remove() end
basic_robot.data[name].obj = obj;
end
end
if not data.bytecode then
local script = meta:get_string("code");
if data.isadmin~=1 then
err = check_code(script);
script = preprocess_code(script);
end
if err then
meta:set_string("infotext","#CODE CHECK ERROR : " .. err);
return
end
local bytecode, err = loadstring( script )
if err then
meta:set_string("infotext","#COMPILE ERROR : " .. err)
return
end
data.bytecode = bytecode;
end
--sandbox init
if not data.sandbox then data.sandbox = getSandboxEnv (name) end
-- actual code run process
data.ccounter = 0;data.digcount = 1;
setfenv(data.bytecode, data.sandbox )
local Result, err = pcall( data.bytecode )
if err then
meta:set_string("infotext","#RUN ERROR : " .. err)
return
end
return
end
-- if robot already exists do nothing -- if robot already exists do nothing
if basic_robot.data[name] and basic_robot.data[name].obj then if basic_robot.data[name] and basic_robot.data[name].obj then
minetest.chat_send_player(owner,"#ROBOT: ".. name .. " already active, removing ") minetest.chat_send_player(owner,"#ROBOT: ".. name .. " already active, removing ")
@ -826,7 +916,6 @@ local spawn_robot = function(pos,node,ttl)
if err then if err then
minetest.chat_send_player(self.owner,"#ROBOT CODE COMPILATION ERROR : " .. err) minetest.chat_send_player(self.owner,"#ROBOT CODE COMPILATION ERROR : " .. err)
self.running = 0; -- stop execution self.running = 0; -- stop execution
self.object:remove(); self.object:remove();
basic_robot.data[self.name].obj = nil; basic_robot.data[self.name].obj = nil;
return return
@ -865,6 +954,7 @@ local despawn_robot = function(pos)
pos.y=pos.y+1; pos.y=pos.y+1;
local owner = meta:get_string("owner") local owner = meta:get_string("owner")
local id = meta:get_int("id"); local id = meta:get_int("id");
if id == 0 then meta:set_int("codechange",1) return end
local name = owner..id; local name = owner..id;
-- if robot already exists remove it -- if robot already exists remove it
@ -898,18 +988,19 @@ local on_receive_robot_form = function(pos, formname, fields, sender)
return return
end end
end end
meta:set_string("code", code) meta:set_string("code", code); meta:set_int("codechange",1)
end end
if fields.id then if fields.id then
local id = math.floor(tonumber(fields.id) or 1); local id = math.floor(tonumber(fields.id) or 1);
local owner = meta:get_string("owner") local owner = meta:get_string("owner")
if not basic_robot.ids[owner] then setupid(owner) end if not basic_robot.ids[owner] then setupid(owner) end
if id<1 or id>basic_robot.ids[owner].maxid then if id<0 or id>basic_robot.ids[owner].maxid then
local privs = minetest.get_player_privs(name); local privs = minetest.get_player_privs(name);
if not privs.privs then return end if not privs.privs then return end
end end
meta:set_int("id",id) -- set active id for spawner meta:set_int("id",id) -- set active id for spawner
meta:set_string("name", owner..id)
end end
robot_spawner_update_form(pos); robot_spawner_update_form(pos);
@ -929,11 +1020,12 @@ local on_receive_robot_form = function(pos, formname, fields, sender)
"dig.direction()\nplace.direction(\"default:dirt\")\nread_node.direction() tells you names of nodes\n".. "dig.direction()\nplace.direction(\"default:dirt\")\nread_node.direction() tells you names of nodes\n"..
"insert.direction(item, inventory) inserts item from robot inventory to target inventory\n".. "insert.direction(item, inventory) inserts item from robot inventory to target inventory\n"..
"check_inventory.direction(itemname, inventory) looks at node and returns false/true, direction can be self\n".. "check_inventory.direction(itemname, inventory) looks at node and returns false/true, direction can be self\n"..
"activate.direction(mode) activates target block\n"..
"pickup(r) picks up all items around robot in radius r<8\n".. "pickup(r) picks up all items around robot in radius r<8\n"..
"take.direction(item, inventory) takes item from target inventory into robot inventory\n".. "take.direction(item, inventory) takes item from target inventory into robot inventory\n"..
"read_text.direction(stringname) reads text of signs, chests and other blocks, optional stringname for other meta\n".. "read_text.direction(stringname) reads text of signs, chests and other blocks, optional stringname for other meta\n"..
"write_text.direction(text) writes text to target block as infotext\n".. "write_text.direction(text) writes text to target block as infotext\n"..
" **BOOKS/CODE\nbook.read(i) returns contents of book at i-th position in library \nbook.write(i,title,text) writes book at i-th position at spawner library\n".. " **BOOKS/CODE\ntitle,text=book.read(i) returns title,contents of book at i-th position in library \nbook.write(i,title,text) writes book at i-th position at spawner library\n"..
"code.run(text) compiles and runs the code in sandbox\n".. "code.run(text) compiles and runs the code in sandbox\n"..
"code.set(text) replaces current bytecode of robot\n".. "code.set(text) replaces current bytecode of robot\n"..
"find_nodes(\"default:dirt\",3) is true if node can be found at radius 3 around robot, otherwise false\n".. "find_nodes(\"default:dirt\",3) is true if node can be found at radius 3 around robot, otherwise false\n"..
@ -957,7 +1049,12 @@ local on_receive_robot_form = function(pos, formname, fields, sender)
"self.fire(speed, pitch,gravity) fires a projectile from robot\n".. "self.fire(speed, pitch,gravity) fires a projectile from robot\n"..
"self.fire_pos() returns last hit position\n".. "self.fire_pos() returns last hit position\n"..
"self.label(text) changes robot label\n".. "self.label(text) changes robot label\n"..
"rom is aditional table that can store persistent data, like rom.x=1\n"; "self.display_text(text,linesize,size) displays text instead of robot face\n"..
"rom is aditional table that can store persistent data, like rom.x=1\n"..
" **KEYBOARD : place spawner at coordinates (20i,40j+1,20k) to monitor events\n"..
"keyboard.get() returns table {x=..,y=..,z=..,puncher = .. , type = .. } for keyboard event\n"..
"keyboard.set(pos,type) set key at pos of type 0=air, 1..6, limited to range 10 around\n"..
"keyboard.read(pos) return node name at pos\n";
text = minetest.formspec_escape(text); text = minetest.formspec_escape(text);
@ -966,7 +1063,7 @@ local on_receive_robot_form = function(pos, formname, fields, sender)
--textlist[X,Y;W,H;name;listelem 1,listelem 2,...,listelem n] --textlist[X,Y;W,H;name;listelem 1,listelem 2,...,listelem n]
local list = ""; local list = "";
for word in string.gmatch(text, "(.-)\r?\n+") do list = list .. word .. ", " end for word in string.gmatch(text, "(.-)\r?\n+") do list = list .. word .. ", " end
local form = "size [8,8] textlist[-0.25,-0.25;8.25,8.5;help;" .. list .. "]" local form = "size [10,8] textlist[-0.25,-0.25;10.25,8.5;help;" .. list .. "]"
minetest.show_formspec(sender:get_player_name(), "robot_help", form); minetest.show_formspec(sender:get_player_name(), "robot_help", form);
return return
@ -1146,9 +1243,14 @@ minetest.register_on_player_receive_fields(
local libpos = {x=tonumber(words[1] or spos.x),y=tonumber(words[2] or spos.y),z=tonumber(words[3] or spos.z)}; local libpos = {x=tonumber(words[1] or spos.x),y=tonumber(words[2] or spos.y),z=tonumber(words[3] or spos.z)};
local inv = minetest.get_meta(libpos):get_inventory();local itemstack = inv:get_stack("library", sel); local inv = minetest.get_meta(libpos):get_inventory();local itemstack = inv:get_stack("library", sel);
if itemstack then if itemstack then
local text = basic_robot.commands.read_book(itemstack) or ""; local title,text = basic_robot.commands.read_book(itemstack);
local form = "size [8,8] textarea[0.,0;8.75,9.75;book;BOOK CONTENTS;" .. minetest.formspec_escape(text) .. "]" title = title or ""; text = text or "";
minetest.show_formspec(player:get_player_name(), "robot_book", form); local dtitle = minetest.formspec_escape(title);
local form = "size [8,8] textarea[0.,0.;8.75,8.5;book; TITLE : " .. minetest.formspec_escape(title) .. ";" ..
minetest.formspec_escape(text) .. "] button_exit[-0.25,7.5;1.25,1;OK;SAVE] "..
"button_exit[1.,7.5;2.75,1;LOAD;USE AS PROGRAM] field[4,8;4.5,0.5;title;title;"..dtitle.."]";
minetest.show_formspec(player:get_player_name(), "robot_book_".. sel.. ":".. minetest.pos_to_string(libpos), form);
end end
end end
end end
@ -1162,8 +1264,54 @@ minetest.register_on_player_receive_fields(
return return
end end
local robot_formname = "robot_book_";
if string.find(formname,robot_formname) then
local p = string.find(formname,":");
local sel = tonumber(string.sub(formname, string.len(robot_formname)+1,p-1)) or 1;
local libpos = minetest.string_to_pos(string.sub(formname, p+1));
if minetest.is_protected(libpos, player:get_player_name()) then return end
if fields.OK and fields.book then
local meta = minetest.get_meta(libpos);
local inv = minetest.get_meta(libpos):get_inventory();local itemstack = inv:get_stack("library", sel);
if itemstack then
local data = minetest.deserialize(itemstack:get_metadata())
if not data then data = {} end
local text = fields.book or "";
data.text = text or ""
data.title = fields.title or ""
data.text_len = #data.text
data.page = 1
data.owner = data.owner or ""
local lpp = 14
data.page_max = math.ceil((#text:gsub("[^\n]", "") + 1) / lpp)
local data_str = minetest.serialize(data)
local new_stack = ItemStack("default:book_written")
new_stack:set_metadata(data_str);
inv:set_stack("library",sel, new_stack);
end
end
if fields.LOAD then
local meta = minetest.get_meta(libpos);
--minetest.chat_send_all(libpos.x .. " " .. libpos.y .. " " .. libpos.z)
--minetest.chat_send_all(fields.book or "")
local inv = minetest.get_meta(libpos):get_inventory();local itemstack = inv:get_stack("library", sel);
if itemstack then
local data = minetest.deserialize(itemstack:get_metadata())
meta:set_string("code", data.text or "")
robot_spawner_update_form(libpos);
minetest.chat_send_player(player:get_player_name(),"#robot: program loaded from book")
end
end
return
end
end end
) )
-- handle chats -- handle chats
@ -1195,6 +1343,7 @@ minetest.register_node("basic_robot:spawner", {
meta:set_string("code",""); meta:set_string("code","");
meta:set_int("id",1); -- initial robot id meta:set_int("id",1); -- initial robot id
meta:set_string("name", placer:get_player_name().."1")
meta:set_string("infotext", "robot spawner (owned by ".. placer:get_player_name() .. ")") meta:set_string("infotext", "robot spawner (owned by ".. placer:get_player_name() .. ")")
meta:set_string("libpos",pos.x .. " " .. pos.y .. " " .. pos.z) meta:set_string("libpos",pos.x .. " " .. pos.y .. " " .. pos.z)
@ -1321,6 +1470,9 @@ minetest.register_craftitem("basic_robot:control", {
return return
end end
if not data.isadmin then
if check_code(script)~=nil then return end
end
local ScriptFunc, CompileError = loadstring( script ) local ScriptFunc, CompileError = loadstring( script )
if CompileError then if CompileError then
@ -1391,6 +1543,8 @@ minetest.register_entity(
end, end,
}) })
minetest.register_craft({ minetest.register_craft({
output = "basic_robot:control", output = "basic_robot:control",
recipe = { recipe = {

BIN
textures/000.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 B

BIN
textures/001.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

BIN
textures/002.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

BIN
textures/003.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/004.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/005.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

BIN
textures/006.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

BIN
textures/007.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

BIN
textures/008.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

BIN
textures/009.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

BIN
textures/010.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

BIN
textures/011.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/012.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/013.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/014.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/015.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

BIN
textures/016.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

BIN
textures/017.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

BIN
textures/018.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

BIN
textures/019.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

BIN
textures/020.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

BIN
textures/021.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

BIN
textures/022.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

BIN
textures/023.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

BIN
textures/024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

BIN
textures/025.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/026.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/027.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

BIN
textures/028.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

BIN
textures/029.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

BIN
textures/030.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

BIN
textures/031.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

BIN
textures/032.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 B

BIN
textures/033.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

BIN
textures/034.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

BIN
textures/035.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

BIN
textures/036.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

BIN
textures/037.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

BIN
textures/038.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

BIN
textures/039.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 B

BIN
textures/040.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 B

BIN
textures/041.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

BIN
textures/042.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

BIN
textures/043.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

BIN
textures/044.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

BIN
textures/045.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

BIN
textures/046.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

BIN
textures/047.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

BIN
textures/048.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

BIN
textures/049.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

BIN
textures/050.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

BIN
textures/051.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

BIN
textures/052.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

BIN
textures/053.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

BIN
textures/054.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

BIN
textures/055.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

BIN
textures/056.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

BIN
textures/057.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

BIN
textures/058.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

BIN
textures/059.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

BIN
textures/060.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

BIN
textures/061.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

BIN
textures/062.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

BIN
textures/063.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

BIN
textures/064.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

BIN
textures/065.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/066.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

BIN
textures/067.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

BIN
textures/068.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

BIN
textures/069.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

BIN
textures/070.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

BIN
textures/071.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 B

BIN
textures/072.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

BIN
textures/073.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

BIN
textures/074.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

BIN
textures/075.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

BIN
textures/076.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

BIN
textures/077.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

BIN
textures/078.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
textures/079.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

BIN
textures/080.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

BIN
textures/081.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

BIN
textures/082.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

BIN
textures/083.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

BIN
textures/084.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

BIN
textures/085.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

BIN
textures/086.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

BIN
textures/087.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

BIN
textures/088.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

BIN
textures/089.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

BIN
textures/090.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

BIN
textures/091.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

BIN
textures/092.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

BIN
textures/093.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

BIN
textures/094.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

BIN
textures/095.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

BIN
textures/096.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

BIN
textures/097.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

Some files were not shown because too many files have changed in this diff Show More