SaferLua Robot added

This commit is contained in:
Joachim Stolberg 2018-07-12 22:55:57 +02:00
parent 1433f79b5d
commit 38dafae5a4
24 changed files with 893 additions and 0 deletions

452
sl_robot/base.lua Normal file

@ -0,0 +1,452 @@
--[[
sl_robot
========
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
base.lua:
]]--
local FUEL_AMOUNT = 1000000
local sHELP = [[SaferLua Robot
The SaferLua Robot can be programmed in Lua by
means of this Robot Base.
The Robot needs Bio Fluel to operate.
]]
local Cache = {}
local tCommands = {}
local tFunctions = {" Overview", " Data structures"}
local tHelpTexts = {[" Overview"] = sHELP, [" Data structures"] = safer_lua.DataStructHelp}
local sFunctionList = ""
local tFunctionIndex = {}
minetest.after(2, function()
sFunctionList = table.concat(tFunctions, ",")
for idx,key in ipairs(tFunctions) do
tFunctionIndex[key] = idx
end
end)
local function output(pos, text)
local meta = minetest.get_meta(pos)
text = meta:get_string("output") .. "\n" .. (text or "")
text = text:sub(-500,-1)
meta:set_string("output", text)
end
--
-- API functions for function/action registrations
--
function sl_robot.register_action(key, attr)
tCommands[key] = attr.cmnd
table.insert(tFunctions, " $"..key)
tHelpTexts[" $"..key] = attr.help
end
local function merge(dest, keys, values)
for idx,key in ipairs(keys) do
dest.env[key] = values[idx]
end
return dest
end
sl_robot.register_action("print", {
cmnd = function(self, text1, text2, text3)
local pos = self.meta.pos
text1 = tostring(text1 or "")
text2 = tostring(text2 or "")
text3 = tostring(text3 or "")
output(pos, text1..text2..text3)
end,
help = " $print(text,...)\n"..
" Send a text line to the output window.\n"..
" The function accepts up to 3 text strings\n"..
' e.g. $print("Hello ", name, " !")'
})
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local meta = minetest.get_meta(pos)
if meta:get_int("state") == tubelib.RUNNING then
return 0
end
local inv = meta:get_inventory()
if listname == "main" then
return stack:get_count()
elseif listname == "fuel" and stack:get_name() == "tubelib_addons1:biofuel" then
return stack:get_count()
end
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local meta = minetest.get_meta(pos)
if meta:get_int("state") == tubelib.RUNNING then
return 0
end
return stack:get_count()
end
local function formspec1(meta)
local running = meta:get_int("state") == tubelib.RUNNING
local cmnd = running and "stop;Stop" or "start;Start"
local init = meta:get_string("init")
local fuel = math.floor((meta:get_int("fuel") * 100.0) / FUEL_AMOUNT)
init = minetest.formspec_escape(init)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"tabheader[0,0;tab;Inv,init,loop,outp,notes,help;1;;true]"..
"label[5.3,0.5;1]label[6.3,0.5;2]label[7.3,0.5;3]label[8.3,0.5;4]"..
"list[context;main;5,1;4,2;]"..
"label[5.3,3;5]label[6.3,3;6]label[7.3,3;7]label[8.3,3;8]"..
"list[context;fuel;1,1.7;1,1;]"..
"item_image[1,1.7;1,1;tubelib_addons1:biofuel]"..
"image[2,1.7;1,1;default_furnace_fire_bg.png^[lowpart:"..
(fuel)..":default_furnace_fire_fg.png]"..
"list[current_player;main;1,4;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
local function formspec2(meta)
local running = meta:get_int("state") == tubelib.RUNNING
local cmnd = running and "stop;Stop" or "start;Start"
local init = meta:get_string("init")
init = minetest.formspec_escape(init)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"tabheader[0,0;tab;Inv,init,loop,outp,notes,help;2;;true]"..
"textarea[0.3,0.2;10,8.3;init;function init();"..init.."]"..
"label[0,7.3;end]"..
"button_exit[4.4,7.5;1.8,1;cancel;Cancel]"..
"button[6.3,7.5;1.8,1;save;Save]"..
"button[8.2,7.5;1.8,1;"..cmnd.."]"
end
local function formspec3(meta)
local running = meta:get_int("state") == tubelib.RUNNING
local cmnd = running and "stop;Stop" or "start;Start"
local loop = meta:get_string("loop")
loop = minetest.formspec_escape(loop)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"tabheader[0,0;tab;Inv,init,loop,outp,notes,help;3;;true]"..
"textarea[0.3,0.2;10,8.3;loop;function loop(ticks, elapsed);"..loop.."]"..
"label[0,7.3;end]"..
"button_exit[4.4,7.5;1.8,1;cancel;Cancel]"..
"button[6.3,7.5;1.8,1;save;Save]"..
"button[8.2,7.5;1.8,1;"..cmnd.."]"
end
local function formspec4(meta)
local running = meta:get_int("state") == tubelib.RUNNING
local cmnd = running and "stop;Stop" or "start;Start"
local output = meta:get_string("output")
output = minetest.formspec_escape(output)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"tabheader[0,0;tab;Inv,init,loop,outp,notes,help;4;;true]"..
"textarea[0.3,0.2;10,8.3;help;Output:;"..output.."]"..
"button[4.4,7.5;1.8,1;clear;Clear]"..
"button[6.3,7.5;1.8,1;update;Update]"..
"button[8.2,7.5;1.8,1;"..cmnd.."]"
end
local function formspec5(meta)
local notes = meta:get_string("notes")
notes = minetest.formspec_escape(notes)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"tabheader[0,0;tab;Inv,init,loop,outp,notes,help;5;;true]"..
"textarea[0.3,0.2;10,8.3;notes;Notepad:;"..notes.."]"..
"button_exit[6.3,7.5;1.8,1;cancel;Cancel]"..
"button[8.2,7.5;1.8,1;save;Save]"
end
local function formspec6(items, pos, text)
text = minetest.formspec_escape(text)
return "size[10,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"tabheader[0,0;tab;Inv,init,loop,outp,notes,help;6;;true]"..
"label[0,-0.2;Functions:]"..
"dropdown[0.3,0.2;10,8.3;functions;"..items..";"..pos.."]"..
"textarea[0.3,1.3;10,8;help;Help:;"..text.."]"
end
local function error(pos, err)
output(pos, err)
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
meta:set_string("formspec", formspec4(meta))
meta:set_string("infotext", "Robot Base "..number..": error")
meta:set_int("state", tubelib.STOPPED)
minetest.get_node_timer(pos):stop()
local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos"))
minetest.sound_play('sl_robot_error', {pos = robot_pos})
return false
end
-- check the fuel level and return false if empty
local function check_fuel(pos, meta)
local fuel = meta:get_int("fuel")
if fuel <= 0 then
if tubelib.get_this_item(meta, "fuel", 1) == nil then
return false
end
fuel = FUEL_AMOUNT
end
meta:set_int("fuel", fuel)
return true
end
local function reset_robot(pos, meta)
print("robot_pos", meta:get_string("robot_pos"))
local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos"))
if robot_pos then
sl_robot.remove_robot(robot_pos)
end
local param2 = (minetest.get_node(pos).param2 + 1) % 4
robot_pos = sl_robot.new_pos(pos, param2, 1)
local pos_below = {x=robot_pos.x, y=robot_pos.y-1, z=robot_pos.z}
meta:set_string("robot_pos", minetest.pos_to_string(robot_pos))
meta:set_int("robot_param2", param2)
sl_robot.place_robot(robot_pos, pos_below, param2, nil)
end
local function compile(pos, meta, number)
local init = meta:get_string("init")
local loop = meta:get_string("loop")
local owner = meta:get_string("owner")
local env = table.copy(tCommands)
reset_robot(pos, meta)
env.meta = {pos=pos, owner=owner, number=number, error=error}
local co, code = safer_lua.co_create(pos, init, loop, env, error)
if co then
Cache[number] = {code=code, co=co}
return true
end
return false
end
local function start_robot(pos)
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
meta:set_string("output", "<press update>")
if not check_fuel(pos, meta) then
local number = meta:get_string("number")
meta:set_string("infotext", "Robot Base "..number..": no fuel")
return false
end
if compile(pos, meta, number) then
meta:set_int("state", tubelib.RUNNING)
meta:set_string("formspec", formspec4(meta))
minetest.get_node_timer(pos):start(1)
meta:set_string("infotext", "Robot Base "..number..": running")
return true
end
return false
end
local function stop_robot(pos)
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos"))
meta:set_int("state", tubelib.STOPPED)
minetest.get_node_timer(pos):stop()
meta:set_string("infotext", "Robot Base "..number..": stopped")
meta:set_string("formspec", formspec3(meta))
if Cache[number] then
local code = Cache[number].code
local env = getfenv(code)
sl_robot.remove_robot(robot_pos)
end
end
local function call_loop(pos, meta, elapsed)
local t = minetest.get_us_time()
local number = meta:get_string("number")
if Cache[number] or compile(pos, meta, number) then
local cpu = meta:get_int("cpu") or 0
local code = Cache[number].code
local co = Cache[number].co
local res = safer_lua.co_resume(pos, co, code, error)
if res then
t = minetest.get_us_time() - t
cpu = math.floor(((cpu * 20) + t) / 21)
meta:set_int("cpu", cpu)
local robot_pos = meta:get_string("robot_pos")
meta:set_string("infotext", "Robot Base "..number..": running ("..cpu.."us) "..robot_pos)
meta:set_int("fuel", meta:get_int("fuel") - t)
end
return res
end
return false
end
local function on_timer(pos, elapsed)
local meta = minetest.get_meta(pos)
--so some maintenance every 10 cycles
local ticks = (meta:get_int("ticks") or 0) + 1
meta:set_int("ticks", ticks)
if (ticks % 100) == 0 then
if not check_fuel(pos, meta) then
local number = meta:get_string("number")
meta:set_string("infotext", "Robot Base "..number..": no fuel")
return false
end
end
return call_loop(pos, meta, elapsed)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = minetest.get_meta(pos)
--print(dump(fields))
if fields.cancel == nil then
if fields.init then
meta:set_string("init", fields.init)
meta:set_string("formspec", formspec2(meta))
elseif fields.loop then
meta:set_string("loop", fields.loop)
meta:set_string("formspec", formspec3(meta))
elseif fields.notes then
meta:set_string("notes", fields.notes)
meta:set_string("formspec", formspec5(meta))
end
end
if fields.update then
meta:set_string("formspec", formspec4(meta))
elseif fields.clear then
meta:set_string("output", "<press update>")
meta:set_string("formspec", formspec4(meta))
elseif fields.tab == "1" then
meta:set_string("formspec", formspec1(meta))
elseif fields.tab == "2" then
meta:set_string("formspec", formspec2(meta))
elseif fields.tab == "3" then
meta:set_string("formspec", formspec3(meta))
elseif fields.tab == "4" then
meta:set_string("formspec", formspec4(meta))
elseif fields.tab == "5" then
meta:set_string("formspec", formspec5(meta))
elseif fields.tab == "6" then
meta:set_string("formspec", formspec6(sFunctionList, 1, sHELP))
elseif fields.start == "Start" then
start_robot(pos)
minetest.log("action", player:get_player_name() ..
" starts the sl_robot at ".. minetest.pos_to_string(pos))
elseif fields.stop == "Stop" then
stop_robot(pos)
elseif fields.functions then
local key = fields.functions
local text = tHelpTexts[key] or ""
local pos = tFunctionIndex[key] or 1
meta:set_string("formspec", formspec6(sFunctionList, pos, text))
end
end
minetest.register_node("sl_robot:base", {
description = "SaferLua Robot Base",
stack_max = 1,
tiles = {
-- up, down, right, left, back, front
'sl_robot_base_top.png',
'sl_robot_base_top.png',
'sl_robot_base_right.png',
'sl_robot_base_left.png',
'sl_robot_base_front.png',
'sl_robot_base_front.png',
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('main', 8)
inv:set_size('fuel', 1)
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local number = tubelib.add_node(pos, "sl_robot:base")
meta:set_string("owner", placer:get_player_name())
meta:set_string("number", number)
meta:set_int("state", tubelib.STOPPED)
meta:set_string("init", "-- called only once")
meta:set_string("loop", "-- called cyclically")
meta:set_string("notes", "For your notes / snippets")
meta:set_string("formspec", formspec1(meta))
meta:set_string("infotext", "Robot Base "..number..": stopped")
end,
on_receive_fields = on_receive_fields,
on_dig = function(pos, node, puncher, pointed_thing)
if minetest.is_protected(pos, puncher:get_player_name()) then
return
end
local meta = minetest.get_meta(pos)
if meta:get_int("state") == tubelib.RUNNING then
return
end
minetest.node_dig(pos, node, puncher, pointed_thing)
tubelib.remove_node(pos)
end,
on_timer = on_timer,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
is_ground_content = false,
groups = {cracky = 1},
sounds = default.node_sound_metal_defaults(),
})
--minetest.register_craft({
-- type = "shapeless",
-- output = "sl_robot:robot",
-- recipe = {"smartline:controller"}
--})

115
sl_robot/commands.lua Normal file

@ -0,0 +1,115 @@
--[[
sl_robot
========
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
commands.lua:
Register all robot commands
]]--
sl_robot.register_action("get_ms_time", {
cmnd = function(self)
return math.floor(minetest.get_us_time() / 1000)
end,
help = "$get_ms_time()\n"..
" returns time with millisecond precision."
})
sl_robot.register_action("forward", {
cmnd = function(self, steps)
steps = tonumber(steps or 1)
local idx = 1
while idx <= steps do
local meta = minetest.get_meta(self.meta.pos)
local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos"))
local robot_param2 = meta:get_int("robot_param2")
local new_pos = sl_robot.move_robot(robot_pos, robot_param2, 1)
if new_pos then -- not blocked?
if new_pos.y == robot_pos.y then -- forward move?
idx = idx + 1
end
meta:set_string("robot_pos", minetest.pos_to_string(new_pos))
else -- blocked
-- because of unloaded areas and the LBM replace blocked robots
--minetest.set_node(robot_pos, {name = "sl_robot:robot_dummy", param2 = robot_param2})
end
coroutine.yield()
end
end,
help = "tbd"
})
sl_robot.register_action("left", {
cmnd = function(self)
local meta = minetest.get_meta(self.meta.pos)
local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos"))
local robot_param2 = meta:get_int("robot_param2")
robot_param2 = sl_robot.turn_robot(robot_pos, robot_param2, "L")
meta:set_int("robot_param2", robot_param2)
coroutine.yield()
end,
help = "tbd"
})
sl_robot.register_action("right", {
cmnd = function(self)
local meta = minetest.get_meta(self.meta.pos)
local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos"))
local robot_param2 = meta:get_int("robot_param2")
robot_param2 = sl_robot.turn_robot(robot_pos, robot_param2, "R")
meta:set_int("robot_param2", robot_param2)
coroutine.yield()
end,
help = "tbd"
})
sl_robot.register_action("up", {
cmnd = function(self)
local meta = minetest.get_meta(self.meta.pos)
local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos"))
local robot_param2 = meta:get_int("robot_param2")
local new_pos
while true do
new_pos = sl_robot.robot_up(robot_pos, robot_param2)
if new_pos then break end
coroutine.yield()
end
meta:set_string("robot_pos", minetest.pos_to_string(new_pos))
coroutine.yield()
end,
help = "tbd"
})
sl_robot.register_action("down", {
cmnd = function(self)
local meta = minetest.get_meta(self.meta.pos)
local robot_pos = minetest.string_to_pos(meta:get_string("robot_pos"))
local robot_param2 = meta:get_int("robot_param2")
while true do
new_pos = sl_robot.robot_down(robot_pos, robot_param2)
if new_pos then break end
coroutine.yield()
end
meta:set_string("robot_pos", minetest.pos_to_string(new_pos))
coroutine.yield()
end,
help = "tbd"
})
sl_robot.register_action("stop", {
cmnd = function(self)
while true do
coroutine.yield()
end
end,
help = "tbd"
})

4
sl_robot/depends.txt Normal file

@ -0,0 +1,4 @@
default
tubelib
safer_lua

2
sl_robot/description.txt Normal file

@ -0,0 +1,2 @@
SaferLua Robot - a simple robot to be programmed in LUA

18
sl_robot/init.lua Normal file

@ -0,0 +1,18 @@
--[[
sl_robot
========
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
]]--
sl_robot = {}
--dofile(minetest.get_modpath("sl_robot") .. "/config.lua")
dofile(minetest.get_modpath("sl_robot") .. "/robot.lua")
dofile(minetest.get_modpath("sl_robot") .. "/base.lua")
dofile(minetest.get_modpath("sl_robot") .. "/commands.lua")

1
sl_robot/mod.conf Normal file

@ -0,0 +1 @@
name=sl_robot

19
sl_robot/readme.md Normal file

@ -0,0 +1,19 @@
SaferLua Robot [sl_robot]
=========================
A tubelib compatible robot to be programmed in LUA
The mod uses SaferLua [safer_lua] as Lua sandbox for safe and secure code execution.
### License
Copyright (C) 2018 Joachim Stolberg
Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt
### Dependencies
tubelib, safer_lua
### History
- 2018-07-06 v0.01 * first draft

282
sl_robot/robot.lua Normal file

@ -0,0 +1,282 @@
--[[
sl_robot
========
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
robot.lua:
]]--
local Face2Dir = {[0]=
{x=0, y=0, z=1},
{x=1, y=0, z=0},
{x=0, y=0, z=-1},
{x=-1, y=0, z=0},
{x=0, y=-1, z=0},
{x=0, y=1, z=0}
}
function sl_robot.new_pos(pos, param2, step)
return vector.add(pos, vector.multiply(Face2Dir[param2], step))
end
-- use Voxel Manipulator to read the node
local function read_node_with_vm(pos)
local vm = VoxelManip()
local MinEdge, MaxEdge = vm:read_from_map(pos, pos)
local data = vm:get_data()
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
return {
name = minetest.get_name_from_content_id(data[area:index(pos.x, pos.y, pos.z)])
}
end
-- check is posA == air-like and posB == solid and no player around
local function check_pos(posA, posB)
local nodeA = minetest.get_node_or_nil(posA) or read_node_with_vm(posA)
local nodeB = minetest.get_node_or_nil(posB) or read_node_with_vm(posB)
if not minetest.registered_nodes[nodeA.name].walkable and
minetest.registered_nodes[nodeB.name].walkable then
local objects = minetest.get_objects_inside_radius(posA, 1)
if #objects ~= 0 then
minetest.sound_play('sl_robot_go_away', {pos = posA})
return false
else
return true
end
end
return false
end
function sl_robot.place_robot(pos1, pos2, param2, player_name)
if check_pos(pos1, pos2) then
minetest.set_node(pos1, {name = "sl_robot:robot", param2 = param2})
end
end
function sl_robot.remove_robot(pos)
local node = minetest.get_node(pos)
if node.name == "sl_robot:robot" or node.name == "sl_robot:robot_dummy" then
minetest.remove_node(pos)
local pos1 = {x=pos.x, y=pos.y-1, z=pos.z}
node = minetest.get_node(pos1)
if node.name == "sl_robot:robot_foot" or node.name == "sl_robot:robot_leg" then
minetest.remove_node(pos1)
pos1 = {x=pos.x, y=pos.y-2, z=pos.z}
node = minetest.get_node(pos1)
if node.name == "sl_robot:robot_foot" then
minetest.remove_node(pos1)
end
end
end
end
-- Positions to check:
-- 3
-- [R]1
-- 4 2
-- 5
function sl_robot.move_robot(pos, param2, step)
local pos1 = sl_robot.new_pos(pos, param2, step)
local pos2 = {x=pos1.x, y=pos1.y-1, z=pos1.z}
local pos3 = {x=pos1.x, y=pos1.y+1, z=pos1.z}
local pos4 = {x=pos.x, y=pos.y-1, z=pos.z}
local pos5 = {x=pos.x, y=pos.y-2, z=pos.z}
local new_pos = nil
if check_pos(pos1, pos2) then -- one step forward
new_pos = pos1
elseif check_pos(pos3, pos1) then -- one step up
new_pos = {x=pos.x, y=pos.y+1, z=pos.z}
minetest.swap_node(pos, {name="sl_robot:robot_foot"})
minetest.set_node(new_pos, {name="sl_robot:robot", param2=param2})
minetest.sound_play('sl_robot_step', {pos = new_pos})
return new_pos
elseif check_pos(pos1, pos4) then -- one step forward
new_pos = pos1
elseif check_pos(pos4, pos5) then -- one step down
new_pos = pos4
else
return nil -- blocked
end
local node4 = minetest.get_node(pos4)
if node4.name == "sl_robot:robot_foot" or node4.name == "sl_robot:robot_leg" then
minetest.remove_node(pos4)
local node5 = minetest.get_node(pos5)
if node5.name == "sl_robot:robot_foot" then
minetest.remove_node(pos5)
end
end
minetest.remove_node(pos)
minetest.set_node(new_pos, {name="sl_robot:robot", param2=param2})
minetest.sound_play('sl_robot_step', {pos = new_pos})
return new_pos
end
function sl_robot.turn_robot(pos, param2, dir)
if dir == "R" then
param2 = (param2 + 1) % 4
else
param2 = (param2 + 3) % 4
end
minetest.swap_node(pos, {name="sl_robot:robot", param2=param2})
minetest.sound_play('sl_robot_step', {pos = pos, gain = 0.6})
return param2
end
-- Positions to check:
-- 1
-- [R]
-- 2
function sl_robot.robot_up(pos, param2)
local pos1 = {x=pos.x, y=pos.y+1, z=pos.z}
local pos2 = {x=pos.x, y=pos.y-1, z=pos.z}
if check_pos(pos1, pos2) then
local node = minetest.get_node(pos2)
if node.name == "sl_robot:robot_foot" then
minetest.swap_node(pos, {name="sl_robot:robot_leg"})
else
minetest.swap_node(pos, {name="sl_robot:robot_foot"})
end
minetest.set_node(pos1, {name="sl_robot:robot", param2=param2})
minetest.sound_play('sl_robot_step', {pos = new_pos})
return pos1
end
return nil
end
-- Positions to check:
-- [R]
-- 1
-- 2
function sl_robot.robot_down(pos, param2)
if dir == "U" then dir = 1 else dir = -1 end
local new_pos = {x=pos.x, y=pos.y-1, z=pos.z}
local new_pos_node = minetest.get_node(new_pos)
local objects = minetest.get_objects_inside_radius(new_pos, 1)
if #objects == 0 and new_pos_node.name == "sl_robot:robot_foot" or
new_pos_node.name == "sl_robot:robot_leg" then
minetest.remove_node(pos)
minetest.set_node(new_pos, {name="sl_robot:robot", param2=param2})
minetest.sound_play('sl_robot_step', {pos = new_pos})
return new_pos
end
pos.y = pos.y+1
minetest.sound_play('sl_robot_go_away', {pos = pos, gain = 0.6})
pos.y = pos.y-1
return nil
end
minetest.register_node("sl_robot:robot", {
description = "SaferLua Robot",
-- up, down, right, left, back, front
tiles = {
"sl_robot_robot_top.png",
"sl_robot_robot_bottom.png",
"sl_robot_robot_right.png",
"sl_robot_robot_left.png",
"sl_robot_robot_front.png",
"sl_robot_robot_back.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -5/16, 3/16, -5/16, 5/16, 8/16, 5/16},
{ -3/16, 2/16, -3/16, 3/16, 3/16, 3/16},
{ -6/16, -7/16, -6/16, 6/16, 2/16, 6/16},
{ -6/16, -8/16, -3/16, 6/16, -7/16, 3/16},
},
},
paramtype2 = "facedir",
is_ground_content = false,
groups = {crumbly=0, not_in_creative_inventory = 1},
sounds = default.node_sound_metal_defaults(),
})
-- dummy robots are used as marker for stucked robots in unloaded areas
minetest.register_node("sl_robot:robot_dummy", {
description = "SaferLua Robot",
-- up, down, right, left, back, front
tiles = {
"sl_robot_robot_top.png^[opacity:127",
"sl_robot_robot_bottom.png^[opacity:127",
"sl_robot_robot_right.png^[opacity:127",
"sl_robot_robot_left.png^[opacity:127",
"sl_robot_robot_front.png^[opacity:127",
"sl_robot_robot_back.png^[opacity:127",
},
drawtype = "nodebox",
use_texture_alpha = true,
node_box = {
type = "fixed",
fixed = {
{ -5/16, 3/16, -5/16, 5/16, 8/16, 5/16},
{ -3/16, 2/16, -3/16, 3/16, 3/16, 3/16},
{ -6/16, -7/16, -6/16, 6/16, 2/16, 6/16},
{ -6/16, -8/16, -3/16, 6/16, -7/16, 3/16},
},
},
paramtype2 = "facedir",
is_ground_content = false,
walkable = false,
drop = "",
groups = {cracky = 3},
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("sl_robot:robot_leg", {
description = "SaferLua Robot",
tiles = {"sl_robot_robot.png^[transformR90]"},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -1/8, -4/8, -1/8, 1/8, 4/8, 1/8},
},
},
paramtype2 = "facedir",
is_ground_content = false,
groups = {crumbly=0, not_in_creative_inventory = 1},
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("sl_robot:robot_foot", {
description = "SaferLua Robot",
tiles = {"sl_robot_robot.png^[transformR90]"},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -1/8, -4/8, -1/8, 1/8, 4/8, 1/8},
{ -2/8, -4/8, -2/8, 2/8, -3/8, 2/8},
},
},
paramtype2 = "facedir",
is_ground_content = false,
groups = {crumbly=0, not_in_creative_inventory = 1},
sounds = default.node_sound_metal_defaults(),
})
minetest.register_lbm({
label = "[sl_robot] Remove Robots",
name = "sl_robot:update",
nodenames = {"sl_robot:robot", "sl_robot:robot_leg", "sl_robot:robot_foot"},
run_at_every_load = true,
action = function(pos, node)
if node.name == "sl_robot:robot" then
minetest.swap_node(pos, {name="sl_robot:robot_dummy", param2 = node.param2})
else
minetest.remove_node(pos)
end
end
})

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B