Server/TechWelt/RobotWorld

From Minetest
Revision as of 15:18, 10 February 2018 by >Hajo (→‎Brickmaker: chest-renewer)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

This is part of TechWelt, a server showing technical mods for educational purposes.

Robots & Machines

  • Basic_robots - a mod about programmable robots that can do almost everything.
  • Basic_machines - a mod for automation and production.

The main focus here is on basic_robots, using only a few of the machine-parts (mostly the keypad).

Robots can also generate power and craft items, so almost everything machines can do,
can be done with robots too.

Activating a robot is the main exception,
we need the keypad, clock-generator and detector for that.

Other players can look at the code inside a robot
(as opposed to machines, where the settings are only visible to the owner),
so it is easier to understand how a robot works.

It is also possible to hide the code, but that requires extra effort.

Robots-Intro

The basic-robots use the concept of a spawner + worker.

The spawner is a block that needs to be put on the ground before using,
much like a chest.
The spawner contains the robot's inventory and the source-code, as well as buttons (START, STOP, SAVE, STORAGE, etc.)
When started, a worker-robot is created ('spawned') on the spot above the spawner.

This worker executes the instructions of the code and can move around, dig, build etc.
It disappears when the program ends.

Programs that don't need to move, can run without the worker,
eg. programs that only listen+talk via chat.

Robot standalone

To get a robot, enter the chat-command:

  • /giveme basic_robot:spawner

To use, set this robot-spawner on the ground.

You cannot do this if the area is owned by someone else.

To activate the robot, rightclick the spawner, and press the START-button.
Now the robot-worker will appear on top of the spawner,
but it will do nothing because there is no program, yet.

Rightclick the spawner again, and press the STOP-button.
Enter a short program into the edit-area, such as

turn.left()

Then press the SAVE-button, and the START-button again.
The robot-worker should appear again, and turn around.

Other buttons inside the robot:

  • Storage - opens the robot's inventory (same size as a chest)
picking up the robot-spawner is not possible with items in the inventory.
  • Library - opens the robot's library (same size as a bookshelf)
The robot can read & write books here, eg. with text and/or code.
By specifying a library-position, the robot can use the library of another robot.
  • Help - shows a page with the available commands.

...

Robot with remote

Without programming, a robot can be used with a remotecontrol.
How to get, via chat-commands:

  • /giveme basic_robot:spawner
  • /giveme basic_robot:control

To use, set the robot-spawner on the ground,
and put the remote on the hotbar.

To activate the robot, rightclick the spawner, and press the START-button.

The remote has two modes, "buttons" and "edit",
that can be accessed by rightclick and leftclick onto empty space.

The buttons of the button-mode allows the robot to move around, and dig.

The edit-mode shows a small input-field for setting the id,
a bigger input-field for entering a (short) program, and a SAVE-button.

id: You can have several remotes on the hotbar, each controlling a different robot.

Without the robot-priv, you can only run two robots at the same time.

edit: enter a short program, such as

say("Hi")

Then press the SAVE-button.

When the robot is active, the program in the edit-field is executed by the robot with a leftclick.

While the edit-field has text in it, the button-mode cannot be used.


Machines-Intro

Basic_machines - a mod for automation and production.
It is possible to build an automated Factory that produces diamonds,
or any other item that can be crafted.

Constructor
This is like a special crafting-table, used to create all the other basic_machines.

How to use

  • Place it on the ground,
  • Open it with rightclick,
  • Select the type of machine you want --> it shows the needed materials
  • Put in the needed materials (eg. a wooden plank and a stick)
  • Press the CRAFT-button
  • Take out your new machine (eg. a keypad)

Machines:

  • Light - a block that gives light, can be turned on and off
  • Keypad - a big button, that sends signals to turn machines on & off
and can do much more (see next chapter)
  • Detector - can detect light, players, blocks, etc.
it can then send a signal to activate machines, open doors, etc.
  • Distributor - sends an input-signal to several other machines (up to 10 spaces away)
As opposed to mesecons, there are no wires - just a table of coordinates
  • clock-generator - periodically activates the device on top, every 5 seconds.
eg. to keep a furnace running.
  • Generator - generates powercells, that can be used as fuel
with upgrades, it can produce the more powerful powerblocks and powerrods
  • Battery - uses powercells to power other machines
eg. a mover, a grinder or a furnace on top of the battery
  • Mover - can move everything
eg. it can move powercells from the generator to a battery,
it can harvest trees and wheat, move stuff from chest into machines, etc.
The mover can also act as a teleporter or elevator.
  • Grinder - grind materials to dusts, which doubles the output when smelted.
see Grinder recipes
  • AutoCrafter - automated crafting. Set up a recipe, then fill in raw materials.
  • Recycler - recyle machines (yields 75% of the building materials).
  • Ball-spawner - spawn an energy ball that can activate stuff
  • Environment - change physics settings (e.g. gravity) and the skybox

...

Lights & Keypad

The light is a simple block that gives light, and can be turned on and off (eg. with a keypad).

The keypad is a big button that can send a signal to another block.
It is very versatile, as it can be used to enter text, enter passwords,
write text on blocks (eg. on signs or chests), repeat a signal several times, play sounds, etc.

In combination with robots, the main use of keypads is to allow other players to activate a robot.

Normally, only the owner can start a robot.

...

Robot-Tutorial - Overview

## Title command introduced
01 Hallo say(), turn.DIR(), --
where DIR is one of left, right, angle
02 Hallo2 self.remove(), var
03 robots-version ..
04 more-output self.label(), self.display_text(), if, \n
05 TimeDate os.date(), write_text.DIR()
where DIR is one of forward, backward, up, down, left, right, forward_down ...
06 Greeter find_player()
07 look-around read_node.DIR()
08 chest-inventory for, check_inventory.DIR()
check_inventory can also use the DIRection 'self', to look are the robot's inventory
09 furnace-feeder1 take.DIR(), insert.DIR()
10 pickup() self.display_text()
11 Teleporter puzzle, find_player()
12 Keyboard-button-maker keyboard.set()
13 dig self.reset()
14 dig & place function()
15 mini-farmer function()
16 x y
  • #16 - chat-listener / self.listen()
  • #17 - Builder /
  • #18 - Demolisher / {} table of functions
  • #19 - move-demo / string.find()
  • #20 - Color-Tower
  • ...

Robot #01 - Hello

The robot outputs the text "Hallo" via chat, and turns on the spot.
This repeats until it is turned off, or another robot with the same id is started.

-- #1 Hallo --

-- Programm wird jede Sekunde neu ausgefuehrt
-- daher wiederholt sich die Ausgabe, und Robot dreht sich.

say("Hallo")

turn.left()
  • Text after -- is a comment, and is ignored.
  • The command say() is for text-output (like 'print()' in other languages)
  • turn.left() lets the robot-worker turn by 90 degree.

Robot #02 - Hello2

This program uses a string-variable for the output,
and adds a command to stop the execution.

-- #2 Hallo2 --

-- Programm wird jede Sekunde neu ausgefuehrt

msg="Hallo"
say(msg)

say("und Tschüss !")
self.remove()  -- stop
-- aber hier ist gleich nach dem ersten Durchlauf Schluss
  • The command self.remove() removes the worker, and stops the program.
see also 'self.spam()', below

Robot #03 - robot-version

This shows the installed version of the basic_robots - mod.

-- #3 robot-version --

v=robot_version()
say("robot version="..v)  -- .. verbindet strings
self.remove()
  • robot_version() is a built-in function, that returns a string with the version-number.
  • v is a variable, that gets assigned the result of the function robot_version().
in lua, each variable can contain everything (number, text, table ...)
  • '..' is an operation used to concatenate two strings.

Robot #04 - more output

This demonstrates some more ways a robot can show output.

-- #4 more-output --

if not i then i=0  -- nur einmal
  turn.left()     -- face to user
  say("Hallo")
end

-- ab hier werden die Befehle wiederholt:

i=i+1
self.label(i)  -- Anzeige in gruen, ueber dem Robot

if i==4 then 
  msg="ab jetzt  vorn mit  Text-\nAnzeige"  -- \n : newline
          --123456789+123456789+
  say(msg)
  self.display_text(msg,10,1)  -- Text-Anzeige anstelle des 'Gesicht'
end

--if i>6 and i<15 then  turn.right() end

if i>20 then 
  say("Stop")
  self.remove() 
end
  • if -- compare values, then depending on the outcome, execute some code
  • self.label(i) -- show that number i as a text floating above the robot
  • self.display_text(msg,10,1) -- show the text from variable msg on the 'face' of the robot
10 is the lenght of each line on that display
1 is the size for the display - 1 is normal, 2 means 'double size'.

Robot #05 - TimeDate

Shows the current time and date, and writes text on other blocks.

-- #5 TimeDate --

self.label("TimeDate")  -- program runs too short for this to be visible
 
td = os.date("%Y-%m-%d  %H:%M:%S")
msg = "Time and date"
say(msg..": "..td)
 
ok=write_text.up(msg)  -- label the button above the robot
ok=write_text.down("This robot was last run: "..td)  -- write text on cpu-box
 
self.remove()  -- stop program

To see the text written on the blocks, point at it with the crosshair (just like signs).

  • os.date() -- call the operating-system, to return a number that represents the time & date
the string inside the brackets specifies how you want to format that information,
e.g. "YEAR-MONTH-DAY HOUR:MINUTE:SECOND"
  • write_text.up() -- write text on the block above the robot
  • write_text.down() -- write text on the block below the robot

Robot #06 - Greeter

This gets the names of all nearby player, and greets them via chat.

-- #6 Greeter --

if not pn then pn="Greeter" 
  p=find_player(5)
  if p==nil then say("Hallo, niemand da?"); self.remove() end

  n=#p; --say(n)
  msg="Hi "
--  if p==nil then s="Hello !" else s="Hello "..p[1].." !"  end
  for i=1, n do
    msg=msg..p[i].." "
  end
    msg=msg.."!"
  say(msg)

end
--
self.remove()
  • find_player(5) -- returns a table of playernames
  • nil -- a special value for 'nothing'
  • #p -- the length of the table p (= how many entries the table has)
  • for i=1, n do -- a loop that runs for all values from 1 to n
that is, once for every player that was detected

Robot #07 - look around

This robot turns around, looks at the surrounding blocks, and outputs their names.
It also counts the (quarter-)turns and stops after 4 have been done.

-- #7 look around --

if not i then i=0 end

n=read_node.forward()
say(i..": "..n)

i=i+1
if i>=4 then self.remove() end

turn.left()
  • say()
  • read_node.forward()

Robot #08 - list chest-inventory

Lists the items in the first 5 slots of the chest.

list only 5 items, so the chat-text doesn't scroll off
-- #8 list chest-inventory --

if not i then i=0 
  say("Inhalt der Kiste:")  -- "Contents of chest:"
end

for i=1,5 do
  m = check_inventory.forward("","main",i)
  say(i..": "..m)
end

self.remove()
  • check_inventory -- look at the "main"-inventory inside the block in front of the robot
and return the name from the item contained in slot number i
  • for i=1,5 do -- loop that repeats with i set to the values 1, 2, 3, 4, 5.

Robot #09 - furnace-feeder

The robot takes cobblestones and coal from the chest,
puts them into the furnace
and activates the furnace so it starts to burn.

A lump of coal burns long enough to turn 13 cobble into stone.

-- #9 furnace-feeder --

m="default:cobble 13"
ok = check_inventory.forward_down(m,"main")
if ok then
  take.forward_down(m)
  insert.backward(m,"src")
else
  say("no "..m);  self.remove()
end

m="default:coal_lump"
ok = check_inventory.forward_down(m,"main")
if ok then
  take.forward_down(m)
  insert.backward(m,"fuel")
else
  say("no "..m);  self.remove()
end

activate.backward(1)
say("Furnace activated")
self.remove()
  • take.DIR()
  • insert.DIR()
  • activate.DIR()
  • DIR

The furnace has 3 different inventories:

  • src - "source"  : for input-material (eg. cobble, ore, flour)
  • dst - "destination" : for the output (eg. stone, ingots, etc.)
  • fuel - for fuel (eg. wood, coal, etc.)

Robot #10 - Pickup

Collecting loose stuff, such as saplings that drop from trees,
or eggs dropped by chicken.

-- #10 pickup --

if not pn then pn="Pickup" 
  self.spam(1)  -- allow more than 1 output via say()
  p=0  -- counter
  turn.left();
  self.display_text(pn,10,1)
end

m=pickup(8) -- range 8, if successful returns a table of the items picked up
if m then 
  --say( serialize(m) )  -- easy way to output any datatype
  for i=1,#m do 
    say( "picked up: "..m[i] ) 
  end
  p=p+1
end

self.label(p)
  • self.spam() -- allow more than 1 output via say() to be seen by other players
  • pickup() -- picks up 'loose items', eg. saplings that drop when harvesting a tree
  • m -- the table returned by pickup()
  • #m -- length of table m
  • m[i] -- the element of the table m, at position i
  • serialize(m) -- returns a representation of m, as a printable string

Robot #11 - Teleporter

Teleport a player.
This robot needs the puzzle-priv.

-- #11 Teleporter--

--puzzle.get_player('hajo'):move_to({x=-23,y=26,z=-990})
--    1,2,33    Starter-Bay
--    0,3,75    House
--    4,26,-994 Robot&Machines
-- 1755,45,699  Mese-Welt

if not pn then pn="Teleporter" 
  p=find_player(4)
  if p==nil then say("Come closer!"); self.remove() 
  else
    n=p[1];   --say(n)
    puzzle.get_player(n):move_to( {x=-23,y=26,z=-990} )
  end
end

self.remove()

Short version:

puzzle.get_player('hajo'):move_to({x=-23,y=26,z=-990})
  • pn -- short for program_name
  • find_player(4) -- returns table of player-names within range 4
  • p[1] -- first element of table p --> name of first player found within range
  • puzzle.get_player(n):move_to() -- gets a handle to the player with name n, then moves /teleports him to the target-location
  • {x=-23,y=26,z=-990} -- a table with elements x,y,z, designating the target-location.

Robot #12 - Buttonmaker1

Create a single keyboard-button.
See also robot #13.

-- #12 simple Buttonmaker--

-- make 1 button at the position of the robot-worker
p = self.pos();
c = 3  -- 1=white 2=grey 3=red 4=green 5=blue 6=yellow 7-16="0"-"9" 17=black

keyboard.set(p,c)
--
self.remove()
  • self.pos() -- returns the position of the robot-worker
At the start of the program, this is the space above the spawner
  • keyboard.set(position,color) -- create a keyboard-button
The position must be within range 10 of the spawner

Originally, these keyboard-buttons were designed as an input-device,
that the robot can monitor for keypresses.

But keyboard-buttons can also be used as a cheap building material.

Robot #13 - dig

Dig the keyboard-button created by robot #12, and puts it into the chest above the worker.

-- #13 dig--

move.forward()

ok=dig.forward()
if ok then say("ok") else say("fail") end
--say( serialize(ok) )

self.reset()
m = check_inventory.self("","main",1);  -- say(m)
insert.up(m)

self.remove()
--
  • dig.DIR() --
  • self.reset() -- moves the worker back to its position when the program started
  • check_inventory.self() -- check the robot's own inventory
  • insert.DIR() -- put stuff into a container

Note: the robot can dig only one item per turn, and digging stone might also need energy.

Note: the robot can dig its own spawner, thereby destroying it. AVOID THIS !

Robot #14 - dig & place

This robot digs the block of cobblestone at one side,
and places the same block on the other side of the spawner.

This will not work with some types of blocks:

  • stone - digging stone can be configured to require energy, and the robot has none, yet.
  • clay - digging a block of clay turns it into 4 clay-lumps.
  • liquids - the robot cannot dig water or lava.
  • mobs - mobs are no blocks, but entities - so digging is not possible.
-- #14 --
-- !! Don't use stone, or clay for this demo !!

function t2()  -- a simple function
  turn.left(); turn.left();
end

if not i then i=0 
  say("dig & place")
end

n=read_node.forward();  say(n)
if n~="air" then
  dig.forward()
  t2()
  place.forward(n)
end

i=i+1
t2()

if i>1 then
  self.remove()
end
--
  • ~= -- compare for 'not-equeal'
comparison-operators are ==, ~=, <, >, <=, >=
  • place.DIR(m) -- build a block of material m in direction DIR
  • function t2() -- defines a function, here without parameters, and without return-value.
This is just to show how a simple function is used.

Robot #15 - mini-farmer

Wheat grows from wheat-seeds planted on soil, and needs water nearby.

Here, we have one space with a watersource, and
4 spaces around that for planting and harvesting wheat,

-- #15 --
if not pn then pn="mini-farmer"; 

  function fwd(c9)
    for i=1,c9 do
      ok=move.forward()
    end
    return ok
  end

  function init() -- needs to be defined before first call
    say(pn)
    t=0
    air ="air"
    soil="farming:soil_wet"
    seed="farming:seed_wheat"
    ripe="farming:wheat_8"
    crop="farming:wheat"

    turn.left()
    _=fwd(3)   -- here, we don't need the result. 
  end

  init()
end
 
function work()
  pickup(8)

  nd=read_node.forward_down()
  nf=read_node.forward(); 
  say(t.." work: " .. nf.." - "..nd)

  if nf==ripe then  say("harvesting")
    dig.forward()
    return  -- done for now
  end
  if nf==air and nd==soil then  say("planting")
    place.forward(seed)
    return
  end

  turn.right(); t=t+1
--return 
end

work()
if t>=4 then say("stop"); self.remove() end

The robot moves to the space over the watersource,
then turns around to reach the 4 spaces growing wheat.

Soil is made from dirt with a hoe near water,
this must be done by the player.

In this example, we don't need the return-values of the functions.
So we use a dummy-variable _.

Robot #16 - chat-listener

This robot listens to the chat, and report who said what.
If someone says 'stop', the program ends.

if not pn then pn="chat-listener"; say(pn)
   self.listen(1)
   self.spam(1)
end

speaker, msg = self.listen_msg()
if msg then 
  say( "["..speaker.."] said >>"..msg.."<<")
end

if msg=="stop" then
  say("Bye !")
  self.remove()
end
--
  • the function self.listen_msg() returns a result that consists of 2 values
the name of the player that speaks, and his text

Robot #17 - Builder

This robot builds a small, phonebooth-sized house around the spawner.
It needs the building-materials in its inventory (but doesn't check).

 if not pn then pn="Instant shelter v1.7"  say(pn)
   pickup(8)
   i=0
   m0="default:dirt"  m1="default:glass" m2="default:cobble"
   m8="default:sand"  m9="default:torch"  
   mS=m0  mC=m2   -- material for sides and corners
 end
 
  i=i+1; say(i)
  if i<100 then
    dig.forward(); move.forward()
    place.right(mC)
    move.backward()
    place.forward(mS)  
    turn.left()
  end
 
  if i== 4 then move.up()  place.down(m8)  mS=m1 end
  if i== 8 then move.up()  place.down(m8)  mS=m0 end
  if i==12 then 
    place.up(m1); 
    i=100
  end
  if i==101 then 
    dig.down(); move.down()
    place.up(m9); 
  end
  if i>=102 then
    dig.down(); 
    say(pn .." done.");  self.remove()  
  end
--

As shown above, the robot uses cobble for the corners and dirt for the sides of the house.
The center of the sides are built with a block of glass.
Also, a single block of glass is placed as a roof, with a torch beneath.
The robot uses sand as filler, so it can move up more than one space above the ground.

The player can stand on the spawner before starting the program.
To get out, simply dig the glass and dirt from one of the sides.

Robot #18 - Demolition

This is a turtle-bot, with a script for digging the building made by robot #17.

--
if not pn then pn="DemoliTurtle v1b"
 s = "-f<->>-<"
 s3=s..s..s
 script = "i@"..">ff"..s3 .."@>uff-"..s3  -- demolish levels 0 & 1

 cmds = {
  ["f"] = function() move.forward()  end,
  ["b"] = function() move.backward() end,
  ["l"] = function() move.left()  end,
  ["r"] = function() move.right() end,
  ["u"] = function() move.up()   end,
  ["d"] = function() move.down() end,
  ["<"] = function() turn.left()  end,
  [">"] = function() turn.right() end,
 
  ["-"] = function() dig.forward() end,
  ["_"] = function() dig.forward_down() end,
  ["^"] = function() dig.up() end,
  ["v"] = function() dig.down() end,
 
  ["@"] = function() self.reset(); pickup(8) end,
  ["i"] = function() say(pn) end,
  ["!"] = function() say("Hello") end,
 }
 n=string.len(script)
 i=0; 
end
 
if i>=n then say("done."); self.remove()
else i=i+1 end
 
c=string.sub(script,i,i);   say(i.." --> "..c)
cmds[c]();
--

A turtle-bot get its instructions from a script.
Each character represents one operation, such as ">" for 'turn.right()'.

Robot #19 - move-demo

Location -6 26 -1000

This robot looks at the floor below to decide what to do.
It moves along the trench behind the spawner,
and finally activates the switch for the light.

-- #19 move-demo --

n=read_node.down()
if string.find(n,"dirt") then n="DIRT" end
say(n)

if n=="basic_robot:spawner" then   
   turn.right();   turn.right();
   move.forward() 
end

if n=="air"  then   move.down()    end
if n=="DIRT" then   move.forward() end

if n=="default:cobble" then 
  turn.right() 
  move.forward() 
end

if n=="default:stone" then 
  move.up()
  turn.right()
  move.forward() 
end

if n=="default:gravel" then 
  move.up()
  turn.right()
  activate.forward()
  self.remove() 
end
--
  • string.find(n,"dirt") -- string-operation: return the position of "dirt" within string n
see also paver-robot

Robot #20 - Color-Tower

This robot builds a tower made of keyboard-blocks, of max. height 10.
The color for each level can be specified by textinput via keypad.
Eg. entering "RGBg" means red, green, blue, gray.

--#22--
function keytype(k) 
  -- 0=air 1=white 2=grey 3=red 4=green 5=blue 6=yellow 7="0" 17=black
  return string.find("wgRGBY0123456789k",k) or 0
end

function lv(h,c)  -- build one level of the tower, at height h, in color c
  if c=="" then return end
  kt=keytype(c); --say(h..":"..c.."->"..kt)
    --sides:
    keyboard.set({x=pos.x+1,y=pos.y+h,z=pos.z  },kt)
    keyboard.set({x=pos.x-1,y=pos.y+h,z=pos.z  },kt)
    keyboard.set({x=pos.x,  y=pos.y+h,z=pos.z+1},kt)
    keyboard.set({x=pos.x,  y=pos.y+h,z=pos.z-1},kt)
    --corners:
    keyboard.set({x=pos.x+1,y=pos.y+h,z=pos.z+1},kt)
    keyboard.set({x=pos.x+1,y=pos.y+h,z=pos.z-1},kt)
    keyboard.set({x=pos.x-1,y=pos.y+h,z=pos.z+1},kt)
    keyboard.set({x=pos.x-1,y=pos.y+h,z=pos.z-1},kt)
    --center
   if h>0 then keyboard.set({x=pos.x+0,y=pos.y+h,z=pos.z  }, 0) end
end

if not pn then pn="ColorTowerBuilder"; v="0.5b";  say(pn.." "..v) -- 2018-01-13
  i=0
  pos = self.spawnpos();

  --read text from robot-spawner / written by keypad:
  b=read_text.down(); s=string.sub(b,1,8)
  if s=="overheat" then b="kgwRYGBk20" end
  if s=="overheat" then b="kgwR22B" end

  say("Buildplan:"..b)
end

i=i+1
t=string.sub(b,i,i)
lv(i, t)

--dig passages into the sides of the two bottom tower-levels:
dig.forward(); turn.right()
if i==4 then move.up() end

if i>9 then 
  say(pn.." done: "..b);
  self.remove()
end
  • string.sub(b,1,8) -- returns the substring from b, from position 1 to 8.

Robot #21 - Countdown

This program mainly just counts down, then stops.

Greeting the player, and picking up loose stuff are extras.

But the robot-spawner sits in a pit deep enough so that a player without help cannot get out.
While the program is running, the player can jump onto the robot-worker, and get out of the pit.

if not pn then pn="Countdown";  --say(pn)
  p=pickup(8)
  if p then say(pn.." pickup:"..p[1]) end

  p=find_player(2)
  if p then say("Hello "..p[1])
  else       say(pn..": no player nearby"); self.remove() end
 
  i=11
end

i=i-1
self.label(i)

if i<0 then self.remove() end
  • ...

Robot #22 - X

--todo
  • ...

Useful Robots

Some robots that might be useful in a normal game, or useful for the admin.

This would include some of the tutorial-robots too, such as the teleporter.

BigDisplay

This shows a welcome-message on a big display, plays a sound, and ends the program after a countdown.

if not pn then pn="BigDisplay"
 
  spin=function()  -- turn robot until something other than air is at its back
   for i=1,4 do
      n=read_node.backward(); --say(n)
      if n~="air" then return end
      turn.right()
    end
  end
 
  spin()
--msg="\n* Hello *"
--self.display_text(msg,9,1)

  msg="\n Willkommen\n".."    auf\n".." TechWelt !\n"
  msg=msg.."\n- -- ** -- -\n"
  msg=msg.." Welcome\n".."    on\n".." TechWelt !\n"
  self.display_text(msg,12,1)  -- 1: normal-size

  i=10
end
 
self.label(i)
i=i-1;

if i==8 then
  self.sound("dingdong",1)
  self.display_text(msg,12,2)  -- 2: double-size
end

if i==3 then
  self.sound("dingdong",1)
  self.display_text(msg,12,3)  -- 3: triple-size
end
if i<0 then self.remove() end
--
  • spin=function() -- this is another variant how to define a function
There is a torch behind the robot.
This is used to turn the robot with its display towards the player.

Mailbox

Location: 6 26 -983

This shows a dialog/formspec to the player,
for writing a message to the owner of the robot.

The messages are written into books in the robot's library.

-- from https://wiki.minetest.net/Mods/basic_robot/Programs#Mailbox
-- mail & feedback using formspec, based on rnd's mailrobot

if not pn then pn="Mailbox"  -- hajo 2017-03-07
  s=0
  daynr=os.date("%w")  -- %w : weekday [0-6 = Sunday-Saturday]
  booknr=tonumber(daynr);  -- say(daynr.."/"..booknr)
  msgsize = 2500;
  _,text = book.read(booknr); text = text or "";
 
	write_msg = function(sender,msg)
		local newsize = string.len(text)+string.len(msg);
		if newsize>msgsize then return "messages space exceeded" end
		text = text .. "\n"..os.date("%Y-%m-%d %H:%M") .. " " .. sender .. ": " .. msg; 
		book.write(booknr,"messages #"..booknr, text)
	end
 
end
 
--textarea[X,Y;W,H;name;label;default]
--button[X,Y;W,H;name;label]
if s == 0 then
	players = find_player(4);
	if players and players[1] then
		s=1
		local form = "size[8,4.5]" ..
		"textarea[0,0;9,4.5;msg;YOUR FEEDBACK-MESSAGE;]"..
		"button_exit[-0.5,4.15;2,1;send;send]"
		self.show_form(players[1],form)
	end
elseif s==1 then
	sender,fields = self.read_form();
	if sender then
		if fields.send then
			msg = fields.msg;
			if msg and msg~="" then
				write_msg(sender,msg); -- activate.up(1)
				--_G.minetest.chat_send_player(sender,"#mailbot: your message has been stored")
				say("#mailbot: your message has been stored")
			end
		end
		self.remove()
	end
end
--

Paver

Location: 5 25 -995, sunk into the road

Pave a road with gravel.
The robot needs enough gravel in its inventory.

Moves straight ahead, and replaces all kinds of dirt with gravel on the ground below the robot.
Stops when movement is blocked, when it finds something other then dirt or gravel, or when it runs out of gravel for paving.

-- hajo, 2017-12-31
if not progname then progname=" paver" 
  self.spam(1)
  say("# "..progname.." started #")
  m="default:gravel"
end

ok=move.forward()
if not ok then
  say("blocked")
  self.remove()
end

n=read_node.down();  --say(n)
if n=="default:dirt"                        then n="DIRT" end
if n=="default:dirt_with_snow"              then n="DIRT" end
if n=="default:dirt_with_grass"             then n="DIRT" end
if n=="default:dirt_with_dry_grass"         then n="DIRT" end
if n=="default:dirt_with_rainforest_litter" then n="DIRT" end
say(n)

if n=="DIRT" then
  dig.down()
  ok=place.down(m)
  say("ok=".. serialize(ok) )
  if not ok then  say("empty"); self.remove()  end
elseif n==m then
  -- already done
else
  say("stop");  self.remove()
end
--
  • self.spam(1) -- allow more then one output from say() to other players
  • if .. elseif
  • ok=place.down(m) -- returns true if successful
  • serialize(ok)

Brickmaker

This is an extended version of robot #12 'simple brickmaker':
It makes a set of keyboard-buttons (all colors, all numbers), and puts them into the chest.

-- Brickmaker--

if not pn then pn="Keyboard-button-maker" 
  c=1  -- 1=white 2=grey 3=red 4=green 5=blue 6=yellow 7-16="0"-"9" 17=black
  p0 = self.spawnpos();
--turn.left();   turn.left();
end

  keyboard.set( {x=p0.x, y=p0.y+2, z=p0.z}, c)

  dig.up()
  m = check_inventory.self("","main",1);  -- say(m)
  self.label(c.."-->"..m) 
--say(c.."-->"..m) 
  insert.forward(m)

--c=99  -- uncomment this to stop after making the first button
  c=c+1;
  if c>17 then
    c=1    -- repeat, make another set of buttons
    say(pn.." done.");  self.remove()  -- uncomment this to stop after first set
  end
--
  • self.spawnpos() -- returns the position of the robot-spawner, as a table
  • {x=p0.x, y=p0.y+2, z=p0.z} -- specifies a new table, with elements from table p0
y+2 means '2 spaces above the spawner'
  • check_inventory.self("","main",1) -- returns the name of the item in slot 1 of the robot's inventory

After the button is created, the robot digs it.
The button goes into slot 1 of the robot's inventory,
and is put into the chest in front of the robot.

New chest

This program 'cleans' the chest with all the generated buttons.

if not pn then pn="chest-renewer"; say(pn)
  turn.left();   turn.left();  -- turn worker towards chest
  m="default:chest"
end

dig.forward()      -- !! this destroys the chest-contents !!
place.forward(m)

say(pn.." done.")
self.remove()

It simply digs the chest (thereby destroying the contents),
and places a new chest at the same location.

Buttonmaker2

This is an extended version of robot #12 'simple brickmaker':
It makes a set of keyboard-buttons for use as turtle-commands, and puts them into the chest.

--todo
if not pn then pn="Buttonmaker2"; say(pn)
  c=1  -- 1=white 2=grey 3=red 4=green 5=blue 6=yellow 7-16="0"-"9" 17=black
  p0 = self.spawnpos();
--turn.left();   turn.left();
end

  keyboard.set( {x=p0.x, y=p0.y+2, z=p0.z}, c)

  dig.up()
  m = check_inventory.self("","main",1);  -- say(m)
  self.label(c.."-->"..m) 
--say(c.."-->"..m) 
  insert.forward(m)

--c=99  -- uncomment this to stop after making the first button
  c=c+1;
  if c>17 then
    c=1    -- repeat, make another set of buttons
    say(pn.." done.");  self.remove()  -- uncomment this to stop after first set
  end
--
say(pn.." done.")
self.remove()

Math-Quiz

Math-Quiz, using chat.

It asks questions like WHAT is 12*13 ?,
and listens to the chat for players to answer.
Puts reward for correct answer into chest.

It doesn't check who gives an answer, and who takes the rewards from the chest.
-- from https://wiki.minetest.net/Basic_robot/Tutorial#Math_quiz2

-- QUIZ: asks math question, like ""WHAT IS 12*13 ?"
if not state then 
state = 1;
a=0; b=0; question = "";
function generate_question()
  a = math.random(12)+10;
  b = math.random(12)+10;
  t=0
  question = "WHAT IS " .. a .."*".. b .. " ? ";
  say(question)
end

generate_question()
self.listen(1)
end
 
speaker, msg = self.listen_msg()
msg = tonumber(msg)
if msg then 
 if msg == a*b then
   say(speaker .. " ANSWERED CORRECTLY!  You get reward in chest")
   insert.up("default:apple")
   insert.up("default:pine_tree")
   generate_question()
 else
   say("WRONG! " .. question)
 end
end

turn.left(); 
t=t+1; self.label(t)
if t>30 then self.remove() end
--
  • speaker,msg=self.listen_msg() -- the function returns 2 results: the speaker, and his text
  • tonumber(msg) -- tries to convert a text to a number
only numbers are considered as answers to the quiz, other text is ignored

The robot stops if there is no answer within 30 seconds.

Simple Shop

Shop - Robot sells 1 Keypad for 2 Steel-ingots.

To use, the player must put the payment into the chest, then press the keypad-button.

-- from https://wiki.minetest.net/Mods/basic_robot#Simple_Shop

 --say("Shop out of order ... check back soon !"); self.remove()
 --
 if not pn then pn="SimpleShop v0.2" -- Hajo, 2017-03-03+
  say(pn)
  p=find_player(4)
  if p==nil then s="Hello !" else s="Hello "..p[1].." !" end
  say(s)
  --
  -- m1="default:torch";  m2="default:dirt" --Test
 
  --m1="default:sword_steel"  -- Example 1: sell 1 sword for 1 gold
  --m2="default:gold_ingot"
 
  m1="basic_machines:keypad"  -- Example 2: sell 1 keypad for 2 steel
  m2="default:steel_ingot 2"
 
  ok1 = check_inventory.self(m1,"main") -- look at robot's inventory
  if not ok1 then say("Out of stock: "..m1); self.remove() end
 
  ok2 = check_inventory.up(m2,"main")   -- look at chest above robot
  if not ok2 then say("No payment in chest ("..m2..")"); self.remove() end
 
  say("Selling "..m1.." for "..m2) 
  take.up(m2)
  insert.up(m1)
  say("Thanks for your purchase !");
 end

The robot first checks his inventory if there still are items to sell.
Then it checks the chest for payment.
If both are ok, it takes the payment from the chest, and puts the goods into the chest.

Note: another player could try to steal the payment or the sold item from the chest.

Multi-language sign

Location: -33,26,-973

Shows some text like the program 'BigDisplay' above,
but also listens to chat to switch the text.

-- 2018-02-02, hajo

function sign(msg)
  self.display_text(msg,24,2)
  self.label("")
end

if not pn then pn="Multilanguage-sign v1.1"; --say(pn)
--self.spam(1)
  msg="Select via chat:\n\n"
  msg=msg.."EN: to show english text"
--msg=msg.."DE: für deutschen Text\n"  -- Umlaute !!
  msg=msg.."DE: deutschen Text anzeigen\n"
  sign(msg)

  self.listen(1)
--say("I',m listening...")
end

speaker, inp = self.listen_msg()
--if inp then  say( "player ["..speaker.."] said >>"..inp.."<<") end

if inp=="DE" then  sign("Deutscher Text.\n") end

if inp=="EN" then msg="english text\n....+....1....+....2...\n"
  msg=msg.."3\n4\n5\n6\n7\n8\n9\n10\n"
  msg=msg.."11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22"
  sign(msg)
end

if inp=="#" or inp=="stop" then  -- cannot use . or /
  say("Bye !")
  pickup(8)
  self.remove()
end

This program could be extended, eg. to listen only to nearby players,
and to get the texts to display from books stored in the robots library.

Outfitter

--todo

Robo-Farm

This is a much extended version of the mini-farmer, robot #15.

Wheat grows on soil, and needs water within 2 spaces.
Here, we have set up a 5x5 wheat-field around a 3x3 pont with a fountain in the center.

The robot drives around this field, harvests ripe wheat, and plants new seeds.
The robot normally drives forward, and turns right when it hits an obstacle.
There are some trapdoors at the corners of the field that act as an obstacle/free space depending on their open/closed state.
They can be switched by the robot with activate().
This is used to 'switch lanes' while moving around the field.

There is a chest at the border of the field, where the robot unloads some wheat whenever it reaches that location.

Also on the border are some bee-hives that produce honey,
and the robot takes some of that honey out when it drives by.

Finally, the robot picks up 'loose items' and announces what was found.

Eg. eggs from chickens, or raw meat that drops when animal-mobs drown in the central pont.
-- robot-farmer --
-- !! the field must be prepared first, by hand / hoe !!

if not pn then pn="robo-farmer v1"; say(pn)
  seed="farming:seed_wheat"
  ripe="farming:wheat_8"
  crop="farming:wheat"
  self.spam(1)
end

m=pickup(8)  -- collect meat, eggs, saplings etc.
if m then say(pn..": pickup "..m[1]) end

n=read_node.forward(); 
if n=="default:chest" then   n=""
--say(pn..": unload")
  insert.forward(crop.." 16")
end

if n=="xdecor:hive" then   n=""
--say(pn..": get honey")
  take.forward("xdecor:honey".." 2","honey")
end

if n==ripe then  n=""
  dig.forward()
  place.forward(seed)
end

--if n~="" then say(n) end -- debug

activate.forward(1)  -- trapdoor
ok=move.forward()
if not ok then turn.right() end
--

Ideas & Homework:

  • Detect spaces without planted seed, and spaces without soil (eg. holes, or plain dirt).
  • Check if the robot has seeds in its inventory.
  • Extend this program to unload different types of collected stuff into different chests.
  • replace the wheat-chest with another robot, and activate it after unloading
  • let this 2nd robot process the wheat into flour, and bake that into bread (see robot #8)
  • move the finished bread to a shop-robot
  • Same for eggs and meat that was picked up from animals.
  • Extend this program to also plant & harvest cotton, and make wool.
  • Install farming-redo, and also farm the other plants (pumpkin, blueberry, etc),
    and make other products from that mod (donuts, blueberry-pie, pumpkin-bread, etc.)

Demos: Robots&Machines

Machines&Robots working together.

Street-lanterns

Keypad, Distributor, Lights

There are several street-lanterns that can be switched on and off with a keypad.
A distributor is used to transmit the signal from the keypad to the lights.

Production-Demo

Generator, Battery, Furnace, Robots

A generator produces powercells, a battery powers a furnace, robots move powercells around, and craft items.

...