<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.minetest.org/index.php?action=history&amp;feed=atom&amp;title=Mods%2Fbasic_robot%2FPrograms</id>
	<title>Mods/basic robot/Programs - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.minetest.org/index.php?action=history&amp;feed=atom&amp;title=Mods%2Fbasic_robot%2FPrograms"/>
	<link rel="alternate" type="text/html" href="https://wiki.minetest.org/index.php?title=Mods/basic_robot/Programs&amp;action=history"/>
	<updated>2026-05-24T17:59:10Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.4</generator>
	<entry>
		<id>https://wiki.minetest.org/index.php?title=Mods/basic_robot/Programs&amp;diff=12417&amp;oldid=prev</id>
		<title>&gt;Voxel at 05:27, 18 April 2021</title>
		<link rel="alternate" type="text/html" href="https://wiki.minetest.org/index.php?title=Mods/basic_robot/Programs&amp;diff=12417&amp;oldid=prev"/>
		<updated>2021-04-18T05:27:28Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 22:27, 17 April 2021&lt;/td&gt;
				&lt;/tr&gt;
&lt;!-- diff cache key mediawiki-mw_:diff::1.12:old-8652:rev-12417 --&gt;
&lt;/table&gt;</summary>
		<author><name>&gt;Voxel</name></author>
	</entry>
	<entry>
		<id>https://wiki.minetest.org/index.php?title=Mods/basic_robot/Programs&amp;diff=8652&amp;oldid=prev</id>
		<title>&gt;Voxel at 05:27, 18 April 2021</title>
		<link rel="alternate" type="text/html" href="https://wiki.minetest.org/index.php?title=Mods/basic_robot/Programs&amp;diff=8652&amp;oldid=prev"/>
		<updated>2021-04-18T05:27:28Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 22:27, 17 April 2021&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>&gt;Voxel</name></author>
	</entry>
	<entry>
		<id>https://wiki.minetest.org/index.php?title=Mods/basic_robot/Programs&amp;diff=4887&amp;oldid=prev</id>
		<title>&gt;Voxel at 05:27, 18 April 2021</title>
		<link rel="alternate" type="text/html" href="https://wiki.minetest.org/index.php?title=Mods/basic_robot/Programs&amp;diff=4887&amp;oldid=prev"/>
		<updated>2021-04-18T05:27:28Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 22:27, 17 April 2021&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>&gt;Voxel</name></author>
	</entry>
	<entry>
		<id>https://wiki.minetest.org/index.php?title=Mods/basic_robot/Programs&amp;diff=1122&amp;oldid=prev</id>
		<title>&gt;Voxel at 05:27, 18 April 2021</title>
		<link rel="alternate" type="text/html" href="https://wiki.minetest.org/index.php?title=Mods/basic_robot/Programs&amp;diff=1122&amp;oldid=prev"/>
		<updated>2021-04-18T05:27:28Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{DISPLAYTITLE:Mods/basic_robot Programs}}&lt;br /&gt;
&lt;br /&gt;
Programs for support/maintainance/admins. &amp;lt;br /&amp;gt;&lt;br /&gt;
They might need admin- or puzzle-privileges.&lt;br /&gt;
&lt;br /&gt;
==Administration==&lt;br /&gt;
&lt;br /&gt;
===Mailbox===&lt;br /&gt;
Shows a form with a field for textinput and a &amp;quot;SEND&amp;quot;-button to the player,&amp;lt;br /&amp;gt;&lt;br /&gt;
stores the text in a book.&amp;lt;br /&amp;gt;&lt;br /&gt;
For mailing feedback to the admin.&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
-- feedback-form, based on rnd's mailrobot&lt;br /&gt;
if not pn then pn=&amp;quot;Mailbox&amp;quot;  -- hajo 2017-03-07&lt;br /&gt;
  s=0&lt;br /&gt;
  daynr=os.date(&amp;quot;%w&amp;quot;)  -- %w : weekday [0-6 = Sunday-Saturday]&lt;br /&gt;
  booknr=tonumber(daynr);  -- say(daynr..&amp;quot;/&amp;quot;..booknr)&lt;br /&gt;
  msgsize = 2500;&lt;br /&gt;
  _,text = book.read(booknr); text = text or &amp;quot;&amp;quot;;&lt;br /&gt;
  &lt;br /&gt;
	write_msg = function(sender,msg)&lt;br /&gt;
		local newsize = string.len(text)+string.len(msg);&lt;br /&gt;
		if newsize&amp;gt;msgsize then return &amp;quot;messages space exceeded&amp;quot; end&lt;br /&gt;
		text = text .. &amp;quot;\n&amp;quot;..os.date(&amp;quot;%Y-%m-%d %H:%M&amp;quot;) .. &amp;quot; &amp;quot; .. sender .. &amp;quot;: &amp;quot; .. msg; &lt;br /&gt;
		book.write(booknr,&amp;quot;messages #&amp;quot;..booknr, text)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--textarea[X,Y;W,H;name;label;default]&lt;br /&gt;
--button[X,Y;W,H;name;label]&lt;br /&gt;
if s == 0 then&lt;br /&gt;
	players = find_player(4);&lt;br /&gt;
	if players and players[1] then&lt;br /&gt;
		s=1&lt;br /&gt;
		local form = &amp;quot;size[8,4.5]&amp;quot; ..&lt;br /&gt;
		&amp;quot;textarea[0,0;9,4.5;msg;YOUR FEEDBACK-MESSAGE;]&amp;quot;..&lt;br /&gt;
		&amp;quot;button_exit[-0.5,4.15;2,1;send;send]&amp;quot;&lt;br /&gt;
		self.show_form(players[1],form)&lt;br /&gt;
	end&lt;br /&gt;
elseif s==1 then&lt;br /&gt;
	sender,fields = self.read_form();&lt;br /&gt;
	if sender then&lt;br /&gt;
		if fields.send then&lt;br /&gt;
			msg = fields.msg;&lt;br /&gt;
			if msg and msg~=&amp;quot;&amp;quot; then&lt;br /&gt;
				write_msg(sender,msg); -- activate.up(1)&lt;br /&gt;
				--_G.minetest.chat_send_player(sender,&amp;quot;#mailbot: your message has been stored&amp;quot;)&lt;br /&gt;
				say(&amp;quot;#mailbot: your message has been stored&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		self.remove()&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
--&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
This variant uses separate books for each day of the week.&amp;lt;br /&amp;gt;&lt;br /&gt;
Without access to _G, the program can also be used by regular users &lt;br /&gt;
as their mailbox.&lt;br /&gt;
&lt;br /&gt;
To read the messages, open the books in the robot's library.&lt;br /&gt;
&lt;br /&gt;
===Poll/Vote===&lt;br /&gt;
Shows a form with text and several buttons to choose from to the player,&amp;lt;br /&amp;gt;&lt;br /&gt;
stores which button was choosen in a book.&amp;lt;br /&amp;gt;&lt;br /&gt;
This is much like the mailbox above, with buttons instead of a field for text-input.&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
--todo&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Spawn-Quiz===&lt;br /&gt;
This is the spawn-quiz from the old robots-server.&lt;br /&gt;
&lt;br /&gt;
On the old robot-server, the spawn-building was like a cage,&amp;lt;br /&amp;gt;&lt;br /&gt;
and to get out, players had to solve this quiz.&lt;br /&gt;
&lt;br /&gt;
The program shows a dialog with a math-quiz, like &amp;quot;2 * 3 + 4 = ?&amp;quot;,&amp;lt;br /&amp;gt;&lt;br /&gt;
with 5 multiple-choice-buttons in a formspec.&lt;br /&gt;
&lt;br /&gt;
When solved, the player is teleported out of the spawn-building.&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
    -- rnd - Spawn-Quiz @ -7 -3 5, with dialog/formspec.&lt;br /&gt;
    -- When solved, gives apple, and teleports the player out of the spawn-building.&lt;br /&gt;
 &lt;br /&gt;
    if not s then&lt;br /&gt;
       s=0&lt;br /&gt;
       t=0&lt;br /&gt;
       option = {&amp;quot;A&amp;quot;,&amp;quot;B&amp;quot;,&amp;quot;C&amp;quot;,&amp;quot;D&amp;quot;,&amp;quot;E&amp;quot;}&lt;br /&gt;
       generate_question = function()&lt;br /&gt;
          local a = math.random(10)+0;&lt;br /&gt;
          local b = math.random(10)+0;&lt;br /&gt;
          local c = math.random(20)-10;&lt;br /&gt;
          local d = a*b+c;&lt;br /&gt;
          msg = &amp;quot;To get out solve the math problem\n\n&amp;quot;;&lt;br /&gt;
          msg = msg .. a..&amp;quot;*&amp;quot;..b..&amp;quot;+&amp;quot;..c .. &amp;quot; = ?\n\n&amp;quot;&lt;br /&gt;
          problem = a..&amp;quot;*&amp;quot;..b..&amp;quot;+&amp;quot;..c .. &amp;quot; = ?&amp;quot;;&lt;br /&gt;
          correct = math.random(5);&lt;br /&gt;
          local frm = &amp;quot;&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
          for i =1,5 do&lt;br /&gt;
             local offset = 0;&lt;br /&gt;
             if i~=correct then offset = math.random(10)-5; if offset == 0 then offset = -1 end end&lt;br /&gt;
             frm = frm .. &amp;quot;button_exit[&amp;quot;.. -0.25+(i-1)*1.25 ..&amp;quot;,1.75;1.25,1;&amp;quot; .. i .. &amp;quot;;&amp;quot;.. d + offset .. &amp;quot;]&amp;quot;&lt;br /&gt;
          end&lt;br /&gt;
       &lt;br /&gt;
          local form = &amp;quot;size[6,2.25]&amp;quot; .. &amp;quot;textarea[0.05,-0.3;6.5,2.25;message;;&amp;quot;.. msg..&amp;quot;]&amp;quot;..frm;&lt;br /&gt;
          return form, correct&lt;br /&gt;
       end&lt;br /&gt;
 &lt;br /&gt;
       selection = 1;&lt;br /&gt;
       question  = &amp;quot;&amp;quot;;&lt;br /&gt;
       problem   = &amp;quot;&amp;quot;;&lt;br /&gt;
    end&lt;br /&gt;
 &lt;br /&gt;
    if t%10 == 0 then  -- new quiz every 10s&lt;br /&gt;
       t = 0; form,selection = generate_question();&lt;br /&gt;
       local players = find_player(4);&lt;br /&gt;
       if players then&lt;br /&gt;
          for _,pname in ipairs(players) do&lt;br /&gt;
             self.show_form(pname,form)&lt;br /&gt;
          end&lt;br /&gt;
       end&lt;br /&gt;
    end&lt;br /&gt;
    t=t+1;&lt;br /&gt;
 &lt;br /&gt;
    sender,fields = self.read_form()&lt;br /&gt;
    if sender then&lt;br /&gt;
       player = _G.minetest.get_player_by_name(sender);&lt;br /&gt;
       if player then&lt;br /&gt;
          &lt;br /&gt;
          answer = 0;&lt;br /&gt;
          for i = 1,5 do if fields[_G.tostring(i)] then answer = i end end&lt;br /&gt;
          &lt;br /&gt;
          if answer == correct then&lt;br /&gt;
             player:setpos({x=-4,y=2,z=0})&lt;br /&gt;
             inv = player:get_inventory(); inv:add_item(&amp;quot;main&amp;quot;, &amp;quot;default:apple&amp;quot;)&lt;br /&gt;
             _G.minetest.chat_send_player(sender,&amp;quot;&amp;lt;MATH ROBOT&amp;gt; congratulations, here is an apple.&amp;quot;)&lt;br /&gt;
          elseif answer ~= 0 then&lt;br /&gt;
             player:setpos({x=0,y=-6,z=-1})&lt;br /&gt;
             say(sender .. &amp;quot; failed to solve the problem &amp;quot; .. problem)&lt;br /&gt;
          end&lt;br /&gt;
       end&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Commands like player:setpos(), player:get_inventory() and access to _G&lt;br /&gt;
require admin-privileges.&lt;br /&gt;
&lt;br /&gt;
==Education==&lt;br /&gt;
&lt;br /&gt;
===Math-Quiz===&lt;br /&gt;
See [[Basic_robot/Tutorial#Math_quiz1|Math_quiz1]]&lt;br /&gt;
and [[Basic_robot/Tutorial#Math_quiz2|Math_quiz2]].&lt;br /&gt;
&lt;br /&gt;
They give rewards for solving questions like &amp;quot;WHAT IS 12*13 ?&amp;quot;, via chat.&lt;br /&gt;
&lt;br /&gt;
===General-Quiz===&lt;br /&gt;
From the [https://forum.minetest.net/viewtopic.php?f=9&amp;amp;t=15850&amp;amp;p=304075#p303543 forum], by rnd.&amp;lt;br /&amp;gt;&lt;br /&gt;
Show a quiz with text-questions, and buttons with multiple-choice answers.&amp;lt;br /&amp;gt;&lt;br /&gt;
The order of the answer-buttons is randomized on each run.&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
if not quiz then&lt;br /&gt;
-- QUIZ QUESTIONS:&lt;br /&gt;
-- FORMAT:  question,   answer1, answer2,...,   index of correct answer&lt;br /&gt;
 quiz = {&lt;br /&gt;
   {&lt;br /&gt;
      &amp;quot;QUESTION 1: what is the correct answer ?&amp;quot;,&lt;br /&gt;
      &amp;quot;correct is a.&amp;quot;,&lt;br /&gt;
      &amp;quot;correct is b.&amp;quot;,&lt;br /&gt;
      &amp;quot;correct is c.&amp;quot;,&lt;br /&gt;
      3 -- correct is 3rd answer - c.&lt;br /&gt;
   },&lt;br /&gt;
&lt;br /&gt;
   {&lt;br /&gt;
      &amp;quot;QUESTION 2: what is the correct answer ?&amp;quot;,&lt;br /&gt;
      &amp;quot;correct is a.&amp;quot;,&lt;br /&gt;
      &amp;quot;correct is b.&amp;quot;,&lt;br /&gt;
      &amp;quot;correct is c.&amp;quot;,&lt;br /&gt;
      1 -- correct is a.&lt;br /&gt;
   },&lt;br /&gt;
&lt;br /&gt;
   {&lt;br /&gt;
      &amp;quot;QUESTION 3: what is the correct answer ?&amp;quot;,&lt;br /&gt;
      &amp;quot;correct is a.&amp;quot;,&lt;br /&gt;
      &amp;quot;correct is b.&amp;quot;,&lt;br /&gt;
      &amp;quot;correct is c.&amp;quot;,&lt;br /&gt;
      2&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 local permute = function(n,seed) -- return permuted array {1,..,n}&lt;br /&gt;
   _G.math.randomseed(seed);&lt;br /&gt;
   local permute = {}&lt;br /&gt;
   for i = 1, n do permute[i] = i end --input:sub(i, i)&lt;br /&gt;
   for i = n,2,-1 do&lt;br /&gt;
      local j = math.random(i-1);&lt;br /&gt;
      local tmp = permute[j];&lt;br /&gt;
      permute[j] = permute[i]; permute[i] = tmp;&lt;br /&gt;
   end&lt;br /&gt;
   return permute&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
 get_form = function(k)&lt;br /&gt;
   &lt;br /&gt;
   local n = #quiz[k]-2;&lt;br /&gt;
   if n &amp;lt; 1 then error(&amp;quot;quiz: error in question &amp;quot; .. k) end&lt;br /&gt;
   &lt;br /&gt;
   local frm = &amp;quot;label[0,0;&amp;quot; .. quiz[k][1] .. &amp;quot;] &amp;quot;&lt;br /&gt;
   order = permute(n,os.time())&lt;br /&gt;
   &lt;br /&gt;
   for i = 1,n do&lt;br /&gt;
      frm = frm .. &amp;quot;button_exit[0,&amp;quot;.. (i)*1 ..&amp;quot;;8,1;&amp;quot; .. order[i] .. &amp;quot;;&amp;quot;.. quiz[k][1+order[i]].. &amp;quot;] &amp;quot;&lt;br /&gt;
   end&lt;br /&gt;
   &lt;br /&gt;
   local form = &amp;quot;size[8,&amp;quot; .. (n+1) .. &amp;quot;]&amp;quot; .. frm;&lt;br /&gt;
   return form, quiz[k][#quiz[k]]&lt;br /&gt;
 end&lt;br /&gt;
 &lt;br /&gt;
 points   = 0; -- how many correct answers so far&lt;br /&gt;
 question = 1; -- current question&lt;br /&gt;
 correct  = 1; -- current correct answer&lt;br /&gt;
 state    = 1; -- 1: display question, 2: wait for answer&lt;br /&gt;
&lt;br /&gt;
 local players = find_player(4);&lt;br /&gt;
 if not players then say(&amp;quot;quiz: no players&amp;quot;) self.remove() end&lt;br /&gt;
 pname = players[1];&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
if state == 1 then&lt;br /&gt;
   if question&amp;gt;#quiz then&lt;br /&gt;
      say(&amp;quot;Congratulations! You answered all question. Your result: &amp;quot; .. points .. &amp;quot;/&amp;quot; .. #quiz)&lt;br /&gt;
      self.remove();&lt;br /&gt;
   else&lt;br /&gt;
      local form;&lt;br /&gt;
      form, correct = get_form(question)&lt;br /&gt;
      self.show_form(pname,form)&lt;br /&gt;
      state = 2 -- wait for answer&lt;br /&gt;
   end&lt;br /&gt;
elseif state == 2 then&lt;br /&gt;
   &lt;br /&gt;
   sender,fields = self.read_form()&lt;br /&gt;
   if sender then -- form event&lt;br /&gt;
      local pl = _G.minetest.get_player_by_name(pname);&lt;br /&gt;
      if pl then&lt;br /&gt;
         if fields.quit then -- button was pressed&lt;br /&gt;
            local selected = 0;&lt;br /&gt;
            -- what is the answer?&lt;br /&gt;
            for k,_ in pairs(fields) do  if k~=&amp;quot;quit&amp;quot; then selected = tonumber(k) break end  end&lt;br /&gt;
            if selected&amp;gt;0 then&lt;br /&gt;
               if selected == correct then&lt;br /&gt;
                  say(&amp;quot;correct!&amp;quot;)&lt;br /&gt;
                  points=points+1&lt;br /&gt;
                  --correct: do something with player&lt;br /&gt;
               else&lt;br /&gt;
                  say(&amp;quot;incorrect!&amp;quot;)&lt;br /&gt;
                  -- incorrect: do something else with player&lt;br /&gt;
               end&lt;br /&gt;
               state = 1&lt;br /&gt;
               question = question + 1&lt;br /&gt;
            else&lt;br /&gt;
               say(&amp;quot;quiz aborted&amp;quot;)&lt;br /&gt;
               self.remove()&lt;br /&gt;
               -- no question was selected in form?&lt;br /&gt;
            end&lt;br /&gt;
         end&lt;br /&gt;
      end&lt;br /&gt;
   end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Service==&lt;br /&gt;
&lt;br /&gt;
===Char-table===&lt;br /&gt;
Make a table of all the keyboard-blocks, above the robot.&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
-- Char-table, by Kurik&lt;br /&gt;
local pos = self.pos()&lt;br /&gt;
pos.y = pos.y + 5&lt;br /&gt;
local p = {x=0,y=pos.y,z=0}&lt;br /&gt;
local i = 1&lt;br /&gt;
&lt;br /&gt;
for z = -8,8 --[[ do ]] do&lt;br /&gt;
  for x = -8,7 --[[ do ]] do&lt;br /&gt;
    p.x = pos.x + x&lt;br /&gt;
    p.z = pos.z + z&lt;br /&gt;
    --local n = puzzle.get_node(p)&lt;br /&gt;
    --if n.name == 'air' then puzzle.set_node(p,node) end&lt;br /&gt;
  --i=0  -- air, for removing the table&lt;br /&gt;
    keyboard.set(p,i)&lt;br /&gt;
    i = i + 1&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
self.remove()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Char-table2====&lt;br /&gt;
A variant of the above, can limit the output to selected ranges, &lt;br /&gt;
and set markers.&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
-- Char-table - 2017-10-14+&lt;br /&gt;
&lt;br /&gt;
local pos = self.pos()&lt;br /&gt;
pos.y = pos.y + 5&lt;br /&gt;
local p = {x=0,y=pos.y,z=0}&lt;br /&gt;
local i = 1&lt;br /&gt;
&lt;br /&gt;
for z = -8,8 --[[ do ]] do&lt;br /&gt;
  for x = -8,7 --[[ do ]] do&lt;br /&gt;
    p.x = pos.x + x&lt;br /&gt;
    p.z = pos.z + z&lt;br /&gt;
    keyboard.set(p,0) -- air&lt;br /&gt;
&lt;br /&gt;
    r=0&lt;br /&gt;
    if i&amp;lt;=  6            then r=1 end -- colors &lt;br /&gt;
    if i&amp;gt;=  7 and i&amp;lt;= 16 then r=2 end -- white numbers&lt;br /&gt;
    if i&amp;gt;= 65 and i&amp;lt;= 74 then r=3 end -- black numbers&lt;br /&gt;
    if i&amp;gt;= 82 and i&amp;lt;=107 then r=4 end -- uppercase chars&lt;br /&gt;
    if i&amp;gt;=114 and i&amp;lt;=139 then r=5 end -- lowercase chars&lt;br /&gt;
&lt;br /&gt;
    if i==  17 then r=-1 end  -- set marker&lt;br /&gt;
    if i== 272 then r=-2 end &lt;br /&gt;
&lt;br /&gt;
    if r&amp;gt;0 then keyboard.set(p,i) end  -- !! adjust condition here !!&lt;br /&gt;
    if r==-1 then keyboard.set(p,4) end  -- green&lt;br /&gt;
    if r==-2 then keyboard.set(p,3) end  -- red marker&lt;br /&gt;
&lt;br /&gt;
    i = i + 1&lt;br /&gt;
  end&lt;br /&gt;
  --say(i)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
self.remove()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For example, change &amp;quot;if r&amp;gt;0&amp;quot; to &amp;quot;if r==1&amp;quot; to only show the colored keyboard-blocks.&lt;br /&gt;
&lt;br /&gt;
===Door-Opener===&lt;br /&gt;
Place robot (with a keypad above it) next to a door,&lt;br /&gt;
&lt;br /&gt;
Opens the locked doors inside a building owned by another player for guests,&amp;lt;br /&amp;gt;&lt;br /&gt;
eg. 'Hotels'.&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
-- simple door-opener - 2017-11&lt;br /&gt;
-- activated by keypad with password&lt;br /&gt;
 &lt;br /&gt;
if not i then i=0 end&lt;br /&gt;
 &lt;br /&gt;
i=i+1&lt;br /&gt;
n=read_node.forward();  --say(i..n)&lt;br /&gt;
n=string.sub(n,1,4)&lt;br /&gt;
if n==&amp;quot;door&amp;quot; then activate.forward(1); i=9 end&lt;br /&gt;
 &lt;br /&gt;
if i&amp;gt;=4 then self.remove() end &lt;br /&gt;
turn.left()&lt;br /&gt;
--turn.right()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The robot turns around until it finds a door,&lt;br /&gt;
then activates it = opens/closes it.&lt;br /&gt;
&lt;br /&gt;
===Teleporter===&lt;br /&gt;
Move player to new location.&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
-- teleporter, by Kurik&lt;br /&gt;
puzzle.get_player('hajo'):move_to({x=100,y=9,z=100})&lt;br /&gt;
self.remove()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See also the mover from the mod basic_machines.&lt;br /&gt;
&lt;br /&gt;
===Shop===&lt;br /&gt;
For selling stuff - see [[Mods/basic_robot#Simple_Shop|Simple_Shop]].&amp;lt;br /&amp;gt;&lt;br /&gt;
It checks a chest above the robot for payment,&amp;lt;br /&amp;gt;&lt;br /&gt;
then exchanges the item(s) from the chest &amp;lt;br /&amp;gt;&lt;br /&gt;
for one (or more) item(s) from the robot's inventory. &lt;br /&gt;
&lt;br /&gt;
As this uses item-names, it cannot sell unique stuff,&lt;br /&gt;
eg. keys or books-with-text.&lt;br /&gt;
&lt;br /&gt;
====Shop2====&lt;br /&gt;
A variant of the above shop.&amp;lt;br /&amp;gt;&lt;br /&gt;
This shop offers to sell several different items, with their own prices,&amp;lt;br /&amp;gt;&lt;br /&gt;
selected by pressing the different keypads/buttons that are placed near the robot.&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
if not pn then pn=&amp;quot;Mike's Snack-Shop v0.6c&amp;quot;;  -- 2017-03-29&lt;br /&gt;
self.spam(1)&lt;br /&gt;
pickup(3) --collect empty cups&lt;br /&gt;
t=&amp;quot;&amp;quot;&lt;br /&gt;
steel1=&amp;quot;default:steel_ingot&amp;quot;&lt;br /&gt;
gold1 =&amp;quot;default:gold_ingot&amp;quot;; gold2 =&amp;quot;default:gold_ingot 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
n=read_node.down(); -- say(n)&lt;br /&gt;
if n==&amp;quot;basic_robot:spawner&amp;quot; then&lt;br /&gt;
  t=read_text.down()   -- text can be set with keypad &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
slot=0&lt;br /&gt;
-- row 1,2,3,4 --&amp;gt; slot 1,9,17,25&lt;br /&gt;
if t==&amp;quot;snack1&amp;quot;  then slot= 1;  price=gold1 end -- donut&lt;br /&gt;
if t==&amp;quot;snack2&amp;quot;  then slot= 9;  price=gold2 end -- apple-donut&lt;br /&gt;
if t==&amp;quot;drink1&amp;quot;  then slot=17;  price=gold1 end -- cold coffee&lt;br /&gt;
if t==&amp;quot;drink2&amp;quot;  then slot=25;  price=gold2 end -- hot coffee&lt;br /&gt;
if slot&amp;lt;1 then say(&amp;quot;config error:&amp;quot;..t) self.remove(); end&lt;br /&gt;
&lt;br /&gt;
item = check_inventory.self(&amp;quot;&amp;quot;,&amp;quot;main&amp;quot;,slot)&lt;br /&gt;
if item==&amp;quot;&amp;quot; then &lt;br /&gt;
  say(pn..&amp;quot;\n&amp;quot;..&amp;quot;out of stock: slot&amp;quot;..slot); self.remove(); &lt;br /&gt;
end&lt;br /&gt;
--say(slot..&amp;quot;-&amp;gt;&amp;quot;..item..&amp;quot;!&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if not item then say(&amp;quot;?&amp;quot;) &lt;br /&gt;
else &lt;br /&gt;
  --say(&amp;quot;&amp;lt;&amp;quot;..item..&amp;quot;&amp;gt;&amp;quot;) &lt;br /&gt;
  cItem=1&lt;br /&gt;
  p=string.find(item,&amp;quot; &amp;quot;)  &lt;br /&gt;
  if p then -- say(&amp;quot;pos=&amp;quot;..p)&lt;br /&gt;
    cItem = string.sub(item,p+1)  --!! tools also have a wear-count&lt;br /&gt;
  --say(p..&amp;quot;:&amp;quot;..cItem)&lt;br /&gt;
    item1 = string.sub(item,1,p-1) &lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
 say(item..&amp;quot;--&amp;gt; &amp;quot;..item1..&amp;quot; itemCount:&amp;quot;..cItem) --&lt;br /&gt;
  msg=pn..&amp;quot;\n&amp;quot;..&amp;quot;selling &amp;quot;..item1..&amp;quot; for &amp;quot;..price&lt;br /&gt;
-- remove &amp;quot;default&amp;quot; and &amp;quot;farming&amp;quot;&lt;br /&gt;
  msg = string.gsub(msg, &amp;quot;default:&amp;quot;, &amp;quot;&amp;quot;) &lt;br /&gt;
  msg = string.gsub(msg, &amp;quot;farming:&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
  say(msg)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
m=check_inventory.up(price,inv)&lt;br /&gt;
if m==&amp;quot;&amp;quot; then msg=msg..&amp;quot;\n no payment in chest !&amp;quot;&lt;br /&gt;
  say(msg); self.remove(); &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
  ok2 = check_inventory.up( price,&amp;quot;main&amp;quot;) -- look at chest above robot&lt;br /&gt;
  if not ok2 then&lt;br /&gt;
    price = string.gsub(price, &amp;quot;default:&amp;quot;, &amp;quot;&amp;quot;) &lt;br /&gt;
    say(&amp;quot;No payment in chest (&amp;quot;..price..&amp;quot;)&amp;quot;); self.remove(); &lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
--say(&amp;quot;Selling &amp;quot;..m1..&amp;quot; for &amp;quot;..m2) &lt;br /&gt;
  take.up(price)&lt;br /&gt;
  insert.up(item1)&lt;br /&gt;
  say(&amp;quot;Thanks for your purchase !&amp;quot;);&lt;br /&gt;
  take.up(&amp;quot;farming:coffee_cup&amp;quot;)  -- take back empty cups&lt;br /&gt;
  self.remove()&lt;br /&gt;
end&lt;br /&gt;
--&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
This shop sells snacks: cold and hot coffee, and two kinds of food.&amp;lt;br /&amp;gt;&lt;br /&gt;
Each row of the robot's inventory is used to store one of the different kinds of goods.&amp;lt;br /&amp;gt;&lt;br /&gt;
( but 1-2 spots somewhere need to be empty for the payments :)&lt;br /&gt;
&lt;br /&gt;
By specifying the goods to sell by slotnumber, this robot can also sell unique items,&amp;lt;br /&amp;gt;&lt;br /&gt;
such as keys set to open specific doors, or books with different texts.&lt;br /&gt;
&lt;br /&gt;
'''Setup:'''&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Keypad1 ||   _     || Keypad3&lt;br /&gt;
|-&lt;br /&gt;
| Keypad2 || Chest   || Keypad4&lt;br /&gt;
|-&lt;br /&gt;
| Sign    ||   _     || Sign with prices&lt;br /&gt;
|-&lt;br /&gt;
| (Floor) || Spawner || (Floor)&lt;br /&gt;
|}&lt;br /&gt;
Each keypad has to be set to point at the spawner, and write a unique text onto it, eg. &amp;quot;snack1&amp;quot;.&amp;lt;br /&amp;gt;&lt;br /&gt;
The robot reads that text to determine which good to sell.&lt;br /&gt;
&lt;br /&gt;
====Admin-Shop====&lt;br /&gt;
Remote-shop by rnd, from the server ROBOTS-SKYBLOCK.&lt;br /&gt;
&lt;br /&gt;
It supplements the regular admin-shop of about 50 shops at spawn. &amp;lt;br /&amp;gt;&lt;br /&gt;
If the shop-bot is running, it can be contacted via chat-command &amp;quot;#shop&amp;quot;.&amp;lt;br /&amp;gt;&lt;br /&gt;
It shows a list of items and prices, and directly accesses the players inventory&amp;lt;br /&amp;gt;&lt;br /&gt;
for payment and delivery.&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
if not s then&lt;br /&gt;
	s=0;item = 1; price =&amp;quot;&amp;quot;; buyer = &amp;quot;&amp;quot;&lt;br /&gt;
	_G.minetest.forceload_block(self.pos(),true)&lt;br /&gt;
	_G.basic_robot.data[self.name()].obj:set_properties({nametag = &amp;quot;&amp;quot;})&lt;br /&gt;
	self.listen(1);self.spam(1)&lt;br /&gt;
	shoplist = {};&lt;br /&gt;
	--scan shops:&lt;br /&gt;
	pos = self.pos(); pos.y=pos.y-5; pos.x=pos.x-6&lt;br /&gt;
	pos1 = {x=pos.x-8,y=pos.y-2,z=pos.z-8};pos2 = {x=pos.x+8,y=pos.y+2,z=pos.z+8};&lt;br /&gt;
	local shoppos = _G.minetest.find_nodes_in_area(pos1, pos2, &amp;quot;shop:shop&amp;quot;);&lt;br /&gt;
	--say(&amp;quot;scanning... i found &amp;quot; .. #shoppos .. &amp;quot; shops &amp;quot;);&lt;br /&gt;
	count = 0&lt;br /&gt;
	for _,p in pairs(shoppos) do&lt;br /&gt;
		local inv = _G.minetest.get_meta(p):get_inventory()&lt;br /&gt;
		local s = inv:get_list(&amp;quot;sell&amp;quot;);local b = inv:get_list(&amp;quot;buy&amp;quot;)&lt;br /&gt;
		local k = s[1]:to_string();&lt;br /&gt;
		local v = b[1]:to_string();&lt;br /&gt;
		if (k and k~=&amp;quot;&amp;quot;) and (v and v~=&amp;quot;&amp;quot;) then count = count +1 shoplist[count] = {k,v}  end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local f_sort = function(a,b) return a[1]&amp;lt;b[1] end; &lt;br /&gt;
	table.sort(shoplist,f_sort)&lt;br /&gt;
 &lt;br /&gt;
	itemlist = &amp;quot;&amp;quot;; count = 0;&lt;br /&gt;
	shopinventory = {};&lt;br /&gt;
	for k,v in pairs(shoplist) do&lt;br /&gt;
		if v[1] then&lt;br /&gt;
			count = count +1&lt;br /&gt;
			itemlist = itemlist .. string.format(&amp;quot;%-5s%-40s%-32s&amp;quot;,k,v[1],v[2]) .. &amp;quot;,&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	t = 0; ct = 0;	ci = 0&lt;br /&gt;
	say(&amp;quot;scanning shops ... completed. Added &amp;quot; .. count .. &amp;quot; items for sale &amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	player1=&amp;quot;&amp;quot;;player2 =&amp;quot;&amp;quot;;&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
ct=ct+1&lt;br /&gt;
if ct%5 == 0 then&lt;br /&gt;
	ct=0&lt;br /&gt;
	ctext = &amp;quot;say #shop to buy&amp;quot;;&lt;br /&gt;
	if ci&amp;gt;0 and ci&amp;lt;=count then&lt;br /&gt;
		if shoplist[ci] then&lt;br /&gt;
			iname = shoplist[ci][1];local p=string.find(iname,&amp;quot;:&amp;quot;);	if p then iname = string.sub(iname,p+1) end&lt;br /&gt;
			sname = shoplist[ci][2];p=string.find(sname,&amp;quot;:&amp;quot;);	if p then sname = string.sub(sname,p+1) end&lt;br /&gt;
			ctext = &amp;quot;#SHOP &amp;quot;.. ci ..&amp;quot;\n&amp;quot; ..iname .. &amp;quot;\nPRICE\n&amp;quot; .. sname&lt;br /&gt;
		end&lt;br /&gt;
		ci=ci+1&lt;br /&gt;
	elseif ci == count+1 then ci=0&lt;br /&gt;
	elseif ci == 0 then ci=1&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	text = &amp;quot;SHOP ROBOT&amp;quot;..os.date(&amp;quot;%x&amp;quot;) ..&amp;quot;  &amp;quot; .. os.date(&amp;quot;%H:%M:%S&amp;quot;).. &amp;quot;\n\n&amp;quot;..ctext&lt;br /&gt;
	self.display_text(text,10,3);&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
speaker,msg = self.listen_msg()&lt;br /&gt;
if msg then&lt;br /&gt;
	if s == 0 then&lt;br /&gt;
		if string.sub(msg,1,5)==&amp;quot;#shop&amp;quot; then&lt;br /&gt;
			if msg == &amp;quot;#shop&amp;quot; then&lt;br /&gt;
				--say(&amp;quot;say #shop command, where command is list OR armor OR item number. Example: #shop list or #shop 1&amp;quot;)&lt;br /&gt;
				&lt;br /&gt;
				local list = &amp;quot;1,2,3&amp;quot;;&lt;br /&gt;
				local form = &amp;quot;size[8,8.5]&amp;quot; ..&lt;br /&gt;
				&amp;quot;label[0.,0.5;ID]&amp;quot;..&lt;br /&gt;
				&amp;quot;label[0.4,0.5;BUY]&amp;quot;..&lt;br /&gt;
				&amp;quot;label[3.,0.5;SELL]&amp;quot; ..&lt;br /&gt;
				&amp;quot;field[7.2,0.25;1.,1;count;count;&amp;quot;.. 1 ..&amp;quot;]&amp;quot;..&lt;br /&gt;
				&amp;quot;button[5.,-0.05;2.,1;ARMOR;ARMOR]&amp;quot;..&lt;br /&gt;
				&amp;quot;textlist[0,1;7.75,7.5;list;&amp;quot; .. itemlist .. &amp;quot;]&amp;quot;;&lt;br /&gt;
				self.show_form(speaker,form)&lt;br /&gt;
			end&lt;br /&gt;
		elseif string.sub(msg,1,3) == &amp;quot;#tp&amp;quot; then&lt;br /&gt;
			local tname = string.sub(msg,5);&lt;br /&gt;
			player1 = speaker; player2 = tname; s = 1&lt;br /&gt;
			_G.minetest.chat_send_player(player2,&amp;quot;#SHOP: say tp to allow teleport of &amp;quot; .. player1)&lt;br /&gt;
		end&lt;br /&gt;
	elseif s == 1 then -- tp&lt;br /&gt;
		s=0; &lt;br /&gt;
		if string.sub(msg,1,2)==&amp;quot;tp&amp;quot; and speaker == player2 then &lt;br /&gt;
			local player = _G.minetest.get_player_by_name(player1);&lt;br /&gt;
			local tplayer = _G.minetest.get_player_by_name(player2);&lt;br /&gt;
			if player and tplayer then&lt;br /&gt;
				local p1 = player:getpos(); local p2 = tplayer:getpos();&lt;br /&gt;
				local price = math.floor(math.sqrt((p1.x-p2.x)^2+(p1.y-p2.y)^2+(p1.z-p2.z)^2)/100)+1;&lt;br /&gt;
				local inv = player:get_inventory(); &lt;br /&gt;
				local stack = _G.ItemStack(&amp;quot;default:gold_ingot &amp;quot; .. price);&lt;br /&gt;
				if price&amp;gt;0 and inv:contains_item(&amp;quot;main&amp;quot;,stack) then&lt;br /&gt;
					player:setpos(tplayer:getpos()); inv:remove_item(&amp;quot;main&amp;quot;,stack)&lt;br /&gt;
				elseif price&amp;gt;0 then&lt;br /&gt;
					_G.minetest.chat_send_player(player1,&amp;quot;You need &amp;quot; .. price .. &amp;quot; gold to teleport &amp;quot;)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		else &lt;br /&gt;
			say(&amp;quot;tp aborted.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
sender,fields = self.read_form()&lt;br /&gt;
if sender then&lt;br /&gt;
	local sel = fields.list; --&amp;quot;CHG:3&amp;quot;&lt;br /&gt;
	--say( string.gsub(_G.dump(fields),&amp;quot;\n&amp;quot;,&amp;quot;&amp;quot;))&lt;br /&gt;
	if sel and string.sub(sel,1,3) == &amp;quot;DCL&amp;quot; then&lt;br /&gt;
		local quantity = tonumber(fields.count) or 1;&lt;br /&gt;
		local select = tonumber(string.sub(sel,5) or &amp;quot;&amp;quot;) or 1;&lt;br /&gt;
		local item, price&lt;br /&gt;
		&lt;br /&gt;
		if shoplist[select] then&lt;br /&gt;
			item,price = shoplist[select][1],shoplist[select][2];&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		local player = _G.minetest.get_player_by_name(sender);&lt;br /&gt;
		if player and item and price then&lt;br /&gt;
			&lt;br /&gt;
			local inv = player:get_inventory();&lt;br /&gt;
			if quantity &amp;gt; 99 then quantity = 99 end&lt;br /&gt;
			if quantity &amp;gt; 1 then&lt;br /&gt;
				local k = 1;&lt;br /&gt;
				local i = string.find(price,&amp;quot; &amp;quot;);&lt;br /&gt;
				if i then &lt;br /&gt;
					k = tonumber(string.sub(price,i+1)) or 1 &lt;br /&gt;
					price = string.sub(price,1,i-1).. &amp;quot; &amp;quot; .. k*quantity&lt;br /&gt;
				else &lt;br /&gt;
					price = price.. &amp;quot; &amp;quot; .. quantity&lt;br /&gt;
				end&lt;br /&gt;
				&lt;br /&gt;
				k=1;i = string.find(item,&amp;quot; &amp;quot;);&lt;br /&gt;
				if i then &lt;br /&gt;
					k = tonumber(string.sub(item,i+1)) or 1 &lt;br /&gt;
					item = string.sub(item,1,i-1).. &amp;quot; &amp;quot; .. k*quantity&lt;br /&gt;
				else&lt;br /&gt;
					item = item .. &amp;quot; &amp;quot; .. quantity&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			if inv:contains_item(&amp;quot;main&amp;quot;, price ) then &lt;br /&gt;
				inv:remove_item(&amp;quot;main&amp;quot;,price)&lt;br /&gt;
				inv:add_item(&amp;quot;main&amp;quot;,item)&lt;br /&gt;
				_G.minetest.chat_send_player(sender,&amp;quot;#SHOP ROBOT: &amp;quot; .. item .. &amp;quot; sold to &amp;quot; .. sender .. &amp;quot; for &amp;quot; .. price)&lt;br /&gt;
			else &lt;br /&gt;
				_G.minetest.chat_send_player(sender,&amp;quot;#SHOP ROBOT: you dont have &amp;quot; .. price .. &amp;quot; in inventory &amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	elseif fields.ARMOR then&lt;br /&gt;
		local player = _G.minetest.get_player_by_name(sender);&lt;br /&gt;
		if player then&lt;br /&gt;
			local inv = player:get_inventory();&lt;br /&gt;
			if inv:contains_item(&amp;quot;main&amp;quot;,_G.ItemStack(&amp;quot;default:diamond 30&amp;quot;)) then&lt;br /&gt;
				player:set_armor_groups({fleshy = 50})&lt;br /&gt;
				_G.minetest.chat_send_player(sender,&amp;quot;#SHOP ROBOT: you bought 50% damage reduction.&amp;quot;)&lt;br /&gt;
			else&lt;br /&gt;
				_G.minetest.chat_send_player(sender,&amp;quot;#SHOP ROBOT: you need 30 diamonds to get armor effect&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The robot sits under the roof above the admin-shop, &amp;lt;br /&amp;gt;&lt;br /&gt;
and scans the shops below to get the list of goods and prices.&lt;br /&gt;
&lt;br /&gt;
The armor-item is special, the server has no mod for armor / 3d-armor.&amp;lt;br /&amp;gt;&lt;br /&gt;
But if a player has 30 diamonds, the shop can give him a 50% damage-reduction.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Replicator===&lt;br /&gt;
Make copies of a block from the chest above the robot.&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
-- Replicator -  single, solid, placeable blocks only !     &lt;br /&gt;
-- No stone, desert-stone, basalt, slate, gneis, ORS. or cobble !&lt;br /&gt;
&lt;br /&gt;
-- Also, no doors, or protectors ...&lt;br /&gt;
-- but trapdoors work&lt;br /&gt;
&lt;br /&gt;
if not pn then pn=&amp;quot;Replicator v1b&amp;quot;;  --say(pn)  --hajo, 2017-11-11&lt;br /&gt;
  m=&amp;quot;default:glass&amp;quot;&lt;br /&gt;
  i=0&lt;br /&gt;
  max=4&lt;br /&gt;
  it=check_inventory.up(&amp;quot;&amp;quot;,&amp;quot;main&amp;quot;,1); --  say(it)&lt;br /&gt;
  if it==&amp;quot;&amp;quot; then&lt;br /&gt;
    say(pn..&amp;quot; running on robot version=&amp;quot;..robot_version() )&lt;br /&gt;
    self.remove()&lt;br /&gt;
  end&lt;br /&gt;
  if it==&amp;quot;default:stone&amp;quot; then&lt;br /&gt;
    say(&amp;quot;Cannot process stone !&amp;quot; )&lt;br /&gt;
    take.up(it)&lt;br /&gt;
    self.remove()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  m=it&lt;br /&gt;
--&lt;br /&gt;
  p=string.find(m,&amp;quot; &amp;quot;)&lt;br /&gt;
  if p then &lt;br /&gt;
    say(&amp;quot;Need single item as master !&amp;quot; )&lt;br /&gt;
    self.remove()&lt;br /&gt;
--  m=string.sub(m,1,p-1)&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  say(pn..&amp;quot; working on &amp;quot;..m..&amp;quot;...&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  turn.right()&lt;br /&gt;
  move.forward()&lt;br /&gt;
  p0=self.pos()&lt;br /&gt;
  self.reset()&lt;br /&gt;
  turn.right()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
  ok=puzzle.set_node(p0,{name = m})  -- needs puzzle-priv !&lt;br /&gt;
--todo (there is no returncode yet):&lt;br /&gt;
--if ok==nil then  say(&amp;quot;+&amp;quot;)  else  say(&amp;quot;Error !&amp;quot;); self.remove()  end&lt;br /&gt;
&lt;br /&gt;
  dig.forward()&lt;br /&gt;
  craft(&amp;quot;default:clay&amp;quot;)  -- when dug, they crumble to lumps&lt;br /&gt;
  craft(&amp;quot;darkage:silt&amp;quot;) &lt;br /&gt;
  i=i+1&lt;br /&gt;
  self.label(i)&lt;br /&gt;
  insert.up(m)&lt;br /&gt;
&lt;br /&gt;
  if i&amp;gt;=max then&lt;br /&gt;
    say(pn .. &amp;quot; done.&amp;quot;)&lt;br /&gt;
    self.remove()&lt;br /&gt;
  end&lt;br /&gt;
--&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To keep the game balanced, it only makes 4 copies on each activation.&amp;lt;br /&amp;gt;&lt;br /&gt;
It uses digging, so only placeable blocks can be copied (eg. gold-blocks, but no ingots). &lt;br /&gt;
&lt;br /&gt;
That means, players still have to do some work &lt;br /&gt;
before they can benefit from this machine.&lt;br /&gt;
&lt;br /&gt;
===Outfitter===&lt;br /&gt;
Give several items, much like give-initial-stuff.&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;source lang=lua&amp;gt;&lt;br /&gt;
-- 2017-11-11+&lt;br /&gt;
if not pn then pn=&amp;quot;Outfittery&amp;quot;; --  say(pn)&lt;br /&gt;
  i=0&lt;br /&gt;
  n=&amp;quot;hajo&amp;quot;; --  i=31&lt;br /&gt;
  p = find_player(2); --say(serialize(p))&lt;br /&gt;
  if p then n=p[1] end&lt;br /&gt;
&lt;br /&gt;
  inv = puzzle.get_player_inv(n)  --  say(serialize(inv))&lt;br /&gt;
  if inv then say(&amp;quot;Hello &amp;quot;..n)&lt;br /&gt;
  else         say(&amp;quot;Error&amp;quot;); self.remove() end &lt;br /&gt;
  if n==&amp;quot;hajo&amp;quot; then i=31 end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
i=i+1&lt;br /&gt;
--&lt;br /&gt;
  m=check_inventory.self(&amp;quot;&amp;quot;,&amp;quot;main&amp;quot;,i);&lt;br /&gt;
  say(i..&amp;quot; =&amp;quot;..m)&lt;br /&gt;
  local itm = puzzle.ItemStack(m)&lt;br /&gt;
  ok = inv:add_item('main', itm)&lt;br /&gt;
--say(i..&amp;quot; =&amp;quot;..m..&amp;quot; &amp;gt; &amp;quot;..serialize(ok))  -- userdata&lt;br /&gt;
--&lt;br /&gt;
if i&amp;gt;=9 then say(&amp;quot;YW!&amp;quot;); self.remove() end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
This outfits a player:&amp;lt;br /&amp;gt;&lt;br /&gt;
the first 9 items from the robot's inventory are copied to the player's inventory.&lt;br /&gt;
&lt;br /&gt;
Special handling for player 'hajo'; he gets the item from slot 32 instead.&lt;/div&gt;</summary>
		<author><name>&gt;Voxel</name></author>
	</entry>
</feed>