master
rnd 2018-04-03 23:21:12 +01:00
parent ca09e73c6b
commit 43514e6733
47 changed files with 5039 additions and 2 deletions

View File

@ -7,7 +7,7 @@ basic_robot.call_limit = 48; -- how many execution calls per script run allowed
basic_robot.entry_count = 2 -- how many robots ordinary player can have
basic_robot.advanced_count = 16 -- how many robots player with robot privs can have
basic_robot.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches
basic_robot.password = "password"; -- IMPORTANT: change it before running mod, password used for authentifications
basic_robot.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running mod, password used for authentifications
basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
["craft_guide:sign_wall"] = true,
@ -1724,13 +1724,15 @@ end
-- handle chats
minetest.register_on_chat_message(
function(name, message)
local hidden = false;
if string.sub(message,1,1) == "\\" then hidden = true; message = string.sub(message,2) end
local listeners = basic_robot.data.listening;
for pname,_ in pairs(listeners) do
local data = basic_robot.data[pname];
data.listen_msg = message;
data.listen_speaker = name;
end
return false
return hidden
end
)

242
scripts/command_robot.lua Normal file
View File

@ -0,0 +1,242 @@
--COMMAND ROBOT by rnd, v2, adapted for skyblock
if not s then
self.listen(1)
s=1;_G.minetest.forceload_block(self.pos(),true)
self.spam(1)
users = {["rnd"]=3,["rnd1"]=3,["Giorge"]=1,["quater"]=1,["UltimateNoob"]=1,["reandh3"]=1,["karo"]=1,["Fedon"]=1,["DS"]=2,
["Arcelmi"]=1,["Gregorro"]=1,Mokk = 1, Evandro010 = 1}
cmdlvl = {["kill"]=2,["tp"]=3,["heal"]=1, ["rename"]=1,["jump"]=1,["givediamond"]=3, ["msg"]=1,["calc"]=0, ["acalc"]=3,["run"]=3, ["shutdown"] = 3,["sayhi"]=0, ["day"] = 1};
tpr = {};
cmds = {
help =
{
level = 0,
run = function(param)
local arg = param[2];
if not arg then
say(colorize("red","OPEN INVENTORY AND READ 'Quests'. YOU GET REWARD AND BETTER STUFF FOR COMPLETING QUESTS. Say /spawn to get to spawn area."))
return
end
if arg and cmds[arg] then
local text = cmds[arg]["docs"];
if text then say(text) end
else
--say(colorize("red","commands") .. colorize("LawnGreen",": 0 status, 2 kill $name, 3 tp $name1 $name2, 1 heal $name, 1 day, 1 rename $name $newname, 3 givediamond $name, 1 msg $name $message, 0 sayhi, 0 calc $formula, 3 acalc $formula, 3 run $expr"))
local msg = ""
for k,v in pairs(cmds) do
msg = msg .. v.level .. " " .. k .. ", "
end
say(colorize("red","commands") .. " " .. colorize("LawnGreen", msg))
end
end,
docs = "Displays available commands. 'help command' shows help about particular command"
},
status =
{
level = 0,
run = function(param)
local usr = param[2] or speaker;
local id = _G.skyblock.players[usr].id;
local pos = _G.skyblock.get_island_pos(id)
minetest.chat_send_all(minetest.colorize("yellow",
usr .. " data : permission level " .. (users[usr] or 0).. ", island " .. id .." (at " .. pos.x .. " " .. pos.z .. "), skyblock level " .. _G.skyblock.players[usr].level
))
end,
docs = "status name, Show target(speaker if none) level, which determines access privilege."
},
kill =
{
level = 2,
run = function(param)
local name = param[2]; if not name then return end
local player = _G.minetest.get_player_by_name(name);
if player then
if (users[name] or 0)<=(users[speaker] or 0) then player:set_hp(0) end
end
end,
docs = "kill name; kills target player",
},
tp =
{
level = 2,
run = function(param)
local player1 = _G.minetest.get_player_by_name(param[2] or "");
local player2 = _G.minetest.get_player_by_name(param[3] or "");
if player1 and player2 then if (users[param[2]] or 0)<=(users[speaker] or 0) then player1:setpos(player2:getpos()) end end
end,
docs = "tp name1 name2; teleports player name2 to name2",
},
tpr =
{
level = 0,
run = function(param)
local name = param[2] or "";
local player1 = _G.minetest.get_player_by_name(name);
if player1 then tpr = {speaker, name} else return end
_G.minetest.chat_send_player(name,minetest.colorize("yellow","#TELEPORT REQUEST: say tpy to teleport " .. speaker .. " to you."))
end,
docs = "tpr name; request teleport to target player",
},
tpy =
{
level = 0,
run = function(param)
if speaker == tpr[2] then
local player1 = _G.minetest.get_player_by_name(tpr[1] or "");
local player2 = _G.minetest.get_player_by_name(tpr[2] or "");
if player1 and player2 then else return end
player1:setpos(player2:getpos())
_G.minetest.chat_send_player(tpr[2],minetest.colorize("yellow","#teleporting " .. tpr[1] .. " to you."))
tpr = {}
end
end,
docs = "tpy; allow player who sent teleport request to teleport to you.",
},
calc =
{
level = 0,
run = function(param)
local formula = param[2] or "";
if not string.find(formula,"%a") then
result = 0;
code.run("result = "..formula);
result = tonumber(result)
if result then say(result) else say("error in formula") end
else
say("dont use any letters in formula")
end
end,
docs = "calculate expression",
},
day =
{
level = 1,
run = function() minetest.set_timeofday(0.25) end,
docs = "set time to day"
},
sayhi =
{
level = 0,
run = function()
local players = _G.minetest.get_connected_players();local msg = "";
for _,player in pairs(players) do
local name = player:get_player_name();
local color = string.format("#%x",math.random(2^24)-1)
if name~=speaker then msg = msg..colorize(color , " hi " .. name) .."," end
end
_G.minetest.chat_send_all("<"..speaker..">" .. string.sub(msg,1,-2))
end,
docs = "say hi to all the other players"
},
msg = {
level = 2,
run = function(param)
local text = string.sub(msg, string.len(param[1] or "")+string.len(param[2] or "") + 3)
local form = "size [8,2] textarea[0.,0;8.75,3.75;book;MESSAGE from " .. speaker .. ";" .. _G.minetest.formspec_escape(text or "") .. "]"
_G.minetest.show_formspec(param[2], "robot_msg", form);
end,
docs = "msg name message, displays message to target player",
},
plist = {
level = 0,
run = function()
local p = {};
for k,v in pairs(minetest.get_connected_players()) do
local name = v:get_player_name()
local pdata = _G.skyblock.players[name]
p[#p+1] = name..", level " .. pdata.level .. "+" .. pdata.completed .. "/" .. pdata.total
end
local text = table.concat(p,"\n")
local form = "size [8,5] textarea[0.,0;8.75,6.75;book;PLAYERS;" .. _G.minetest.formspec_escape(text or "") .. "]"
_G.minetest.show_formspec(speaker, "robot_msg", form);
end,
docs = "plist, displays player list and their levels",
},
run = {
level = 3,
run = function(param)
local expr = string.sub(msg,5);
--say("running " .. expr)
code.run(expr);
end,
docs = "run lua code",
},
}
self.label(colorize("red","\nCMD ROBOT"))
end
speaker, msg = self.listen_msg();
if msg then
local words = {};
for word in string.gmatch(msg,"%S+") do words[#words+1]=word end -- extract words
local level = users[speaker] or 0;
local cmd = words[1];
cmdlevel = cmdlvl[cmd] or 0;
if level < cmdlevel then
say("You need to be level " .. cmdlevel .. " to use " .. words[1])
else
if cmds[cmd] then
cmds[cmd].run(words)
elseif words[1]=="heal" and words[2] then
local player = _G.minetest.get_player_by_name(words[2]);
if player then player:set_hp(20) end
elseif words[1]=="rename" then
local player = _G.minetest.get_player_by_name(words[2]);
if player then if ((users[words[2]] or 0)<=level) and (level>=3 or words[2]~=speaker) then player:set_nametag_attributes({text = words[3] or words[2]}) end end
elseif words[1]=="robot"then
local player = _G.minetest.get_player_by_name(words[2])
if player then
player:set_properties({visual = "cube"});
player:set_properties({textures={"arrow.png^[transformR90","basic_machine_side.png","basic_machine_side.png","basic_machine_side.png","face.png","basic_machine_side.png"}})
player:set_properties({collisionbox={-0.5,-0.5,-0.5,0.5,0.5,0.5}})
end
elseif words[1] == "mese" then
local player = _G.minetest.get_player_by_name(words[2])
if player then
player:set_properties({visual = "mesh",textures = {"zmobs_mese_monster.png"},mesh = "zmobs_mese_monster.x",visual_size = {x=1,y=1}})
end
elseif words[1] == "givediamond" then
local player = _G.minetest.get_player_by_name(words[2])
local pos = player:getpos();
_G.minetest.add_item(pos,_G.ItemStack("default:diamond"))
elseif words[1] == "acalc" then
local formula = words[2] or "";
if not string.find(formula,"_G") then
result = 0;
code.run("result = "..formula);
result = tonumber(result)
if result then say(result) else say("error in formula") end
end
elseif words[1] == "shutdown" then
_G.minetest.request_shutdown("maintenance, come back",true)
elseif words[1] == "web" then
local text = string.sub(msg,5);
local f = _G.io.open("H:\\sfk\\files\\index.html", "w")
f:write(text);f:close()
end
end
end

70
scripts/copy_paste.lua Normal file
View File

@ -0,0 +1,70 @@
-- COPY PASTE ROBOT by rnd: c1 c2 r = markers, c = copy p = paste
if not paste then
_G.minetest.forceload_block(self.pos(),true)
paste = {};
round = function(x)
if x>0 then
return math.floor(x+0.5)
else
return -math.floor(-x+0.5)
end
end
data = {};
self.listen(1)
self.label("COPY-PASTE MASTER v1.2 gold edition. commands: c1 c2 r c p")
end
speaker, msg = self.listen_msg()
if speaker == "rnd" then
local player = _G.minetest.get_player_by_name(speaker);
local p = player:getpos(); p.x = round(p.x); p.y=round(p.y); p.z = round(p.z);
if msg == "c1" then
paste.src1 = {x=p.x,y=p.y,z=p.z};say("marker 1 set at " .. p.x .. " " .. p.y .. " " .. p.z)
elseif msg == "c2" then
paste.src2 = {x=p.x,y=p.y,z=p.z};say("marker 2 set at " .. p.x .. " " .. p.y .. " " .. p.z)
elseif msg == "r" then
paste.ref = {x=p.x,y=p.y,z=p.z};say("reference set at " .. p.x .. " " .. p.y .. " " .. p.z)
elseif msg == "c" then -- copy
local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z);
local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z);
local count = 0; data = {};
for i = x1,x2 do
for j = y1,y2 do
for k = z1,z2 do
local node = _G.minetest.get_node({x=i,y=j,z=k});
if node.name ~= "air" then
if not data[i] then data[i]= {} end
if not data[i][j] then data[i][j]= {} end
data[i][j][k] = {node, _G.minetest.get_meta({x=i,y=j,z=k}):to_table()}
count = count +1;
end
end
end
end
say(count .. " nodes copied ");
elseif msg == "p" then -- paste
local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z);
local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z);
local count = 0; p.x = p.x-paste.ref.x; p.y = p.y-paste.ref.y; p.z = p.z-paste.ref.z;
for i = x1,x2 do
for j = y1,y2 do
for k = z1,z2 do
local pdata;
if data[i] and data[i][j] and data[i][j][k] then
pdata = data[i][j][k]
end
if pdata then
count = count + 1
_G.minetest.set_node({x=i+p.x,y=j+p.y,z=k+p.z}, pdata[1]);
_G.minetest.get_meta({x=i+p.x,y=j+p.y,z=k+p.z}):from_table(pdata[2])
end
end
end
end
say(count .. " nodes pasted ");
end
end

108
scripts/craft_guide.lua Normal file
View File

@ -0,0 +1,108 @@
-- ROBOT craft guide by rnd, 2017
if not list then
tname = "rnd";
list = {};
tmplist = _G.minetest.registered_items;
for k,v in pairs(tmplist) do
local texture = v.inventory_image or "";
if texture=="" and v.tiles then texture = v.tiles[1] or "" end
if (not v.groups.not_in_craft_guide or v.groups.not_in_craft_guide == 0) and type(texture)=="string" and texture~="" then
list[#list+1] = {_G.minetest.formspec_escape(k),_G.minetest.formspec_escape(v.description),_G.minetest.formspec_escape(texture)}; -- v.inventory_image, k, v.description
end
end
idx = 1; n = 35; row = 6; size = 1.25;
filter = "" item = "" recipeid = 1
filterlist = {}; for i = 1,#list do filterlist[i] = i end
get_texture = function(ritem)
local v = _G.minetest.registered_items[ritem]; if not v then return "" end
local texture = v.inventory_image or "";
if texture=="" and v.tiles then texture = v.tiles[1] or "" end
if type(texture)~="string" then return "" end
return texture
end
get_form = function()
local form = "size[7.5,8.5]";
local x,y,i; local idxt = idx+n; if idxt > #filterlist then idxt = #filterlist end
for i = idx, idxt do
local id = filterlist[i];
if list[id] and list[id][3] then
x = ((i-idx) % row)
y = (i-idx-x)/row;
form = form .. "image_button[".. x*size ..",".. y*size+0.75 .. ";"..size.."," .. size .. ";" .. list[id][3] ..";".."item"..";".. list[id][1] .."]"
end
end
form = form .. "textarea[0.25,0;2,0.75;filter;filter;"..filter .. "]" .. "button[2.,0;1,0.5;search;search]"..
"button[5.5,0;1,0.5;prev;PREV]" .. "button[6.5,0;1,0.5;next;NEXT]" .. "label[4,0;".. idx .. "-"..idxt .. "/" .. #filterlist.."]";
return form
end
get_recipe = function()
local form = "size[7.5,8.5]";
local recipes = _G.minetest.get_all_craft_recipes(item); if not recipes then return end;
local recipe = recipes[recipeid]; if not recipe then return end
local items = recipe.items
local x,y,i;
for i = 0, 8 do
local ritem = items[i+1] or ""; local sritem = "";
local j = string.find(ritem,":"); if j then sritem = string.sub(ritem,j+1) end; --ritem = _G.minetest.formspec_escape(ritem);
x = (i % 3)
y = (i-x)/3;
form = form .. "image_button[".. x*size ..",".. y*size+0.75 .. ";"..size.."," .. size .. ";" .. get_texture(ritem) ..";".."item"..";".. sritem .."]"
end
form = form .. "textarea[0.25,0;2,0.75;recipeid;recipeid ".. #recipes .. ";"..recipeid .. "]" .. "button[2.,0;1,0.5;go;go]"..
"label[3,0;" .. item .. "]" .. "button[6.5,0;1,0.5;back;BACK]" ;
return form
end
s=0
end
if s==0 then
local p = find_player(4); s = 1
if p then
self.show_form(p[1],get_form())
else
self.remove()
end
end
sender,fields = self.read_form()
if sender then
if fields.search then
filter = fields.filter or ""
filterlist = {};
for i = 1,#list do
if string.find(list[i][1],filter) then filterlist[#filterlist+1] = i end
end
idx=1;self.show_form(sender,get_form())
elseif fields.prev then
idx = idx - n; if idx<1 then idx =#filterlist-n end
self.show_form(sender,get_form())
elseif fields.next then
idx = idx+n; if idx > #filterlist then idx = 1 end
self.show_form(sender,get_form())
elseif fields.back then
self.show_form(sender,get_form())
elseif fields.recipeid then
recipeid = tonumber(fields.recipeid) or 1;
self.show_form(sender,get_recipe())
elseif fields.item then
item = fields.item;
local recipes = _G.minetest.get_all_craft_recipes(item);
local count = 0; if recipes then count = #recipes end
if count>0 then
recipeid = 1
self.show_form(sender,get_recipe() or "")
end
elseif fields.quit then
self.remove()
end
end

137
scripts/games/CTF_bot.lua Normal file
View File

@ -0,0 +1,137 @@
-- simple ctf robot, rnd
--instructions: build game arena and place blue/red buttons as flags. edit flag positions below
--you must register 'keyboard' events by placing robot with same 'id' as robot running this code at 'event register' positions - default (32*i,64*j+1, 32*k)
if not ctf then
_G.minetest.forceload_block(self.pos(),true)
ctf = {
[1] = {state = 1, flagnode = "basic_robot:button8080FF", pos = {x=-18,y=501,z=17}, name = "blue", owner = "", score = 0}, -- team[1]
[2] = {state = 1, flagnode = "basic_robot:buttonFF8080", pos = {x=-79,y=501,z=46}, name = "red", owner = "", score = 0}, -- team[2]
}
teams = {} -- example : {["rnd"] = {1,0, player, health points at start}}; -- team, ownership of flag
maxscore = 3;
t = 0
teamid = 1; -- team selector when joining
gamestate = 0;
self.listen(1)
self.spam(1)
get_id = function(pos)
local range = 1000;
return pos.x + range*pos.y+range^2*pos.z
end
flag_id = {}; for i = 1,#ctf do flag_id[get_id(ctf[i].pos)] = i end
render_flags = function()
for i = 1,#ctf do minetest.set_node(ctf[i].pos, {name = ctf[i].flagnode}) end
end
end
if gamestate == 0 then -- welcome
say(colorize("red","#CAPTURE THE FLAG GAME. say '\\join' to join game. to start game one of joined players says '\\start'"))
gamestate = 1
elseif gamestate == 1 then
speaker,msg = self.listen_msg()
if msg == "join" then
local pl = minetest.get_player_by_name(speaker);
teams[speaker] = {teamid, 0, pl,20};pl:set_hp(20)
local msg1 = ""; local msg2 = ""
for k,v in pairs(teams) do
if v[1] == 1 then msg1 = msg1 .. k .. " " elseif v[1] == 2 then msg2 = msg2 .. k .. " " end
end
say(colorize("yellow","#CTF : " .. speaker .. " joined team " .. ctf[teamid].name .. ". TEAM " .. ctf[1].name .. ": " .. msg1 .. ", TEAM " .. ctf[2].name .. ": " .. msg2))
teamid = 3-teamid; -- 1,2
elseif msg == "start" then -- game start
if teams[speaker] then
gamestate = 2
keyboard.get() -- clear keyboard buffer
say(colorize("red","#CTF GAME STARTED. GET ENEMY FLAG AND BRING IT BACK TO YOUR FLAG. DONT LET YOUR HEALTH GO BELOW 5 HEARTS OR YOU ARE OUT."))
for k,_ in pairs(teams) do -- teleport players
local data = teams[k];data[3]:setpos( ctf[data[1]].pos )
end
render_flags()
end
end
elseif gamestate == 2 then
-- check player health
for k,v in pairs(teams) do
local hp = teams[k][3]:get_hp();
if not hp or hp<10 then -- teams[k][4]
local cflag = teams[k][2];
if cflag>0 then -- drop flag
ctf[cflag].state = 1
ctf[cflag].owner = ""
minetest.set_node(ctf[cflag].pos, {name = ctf[cflag].flagnode})
say(colorize("red", "#CTF " .. k .. " dropped " .. ctf[cflag].name .. " flag!"))
end
if not hp then -- player left
say(colorize("yellow", "#CTF " .. k .. " left the game!"))
teams[k] = nil
else -- reset player
say(colorize("yellow", "#CTF " .. k .. " resetted!"))
v[2] = 0 -- player has no flag
v[3]:set_hp(20)
v[3]:setpos( ctf[v[1]].pos )
end
end
end
event = keyboard.get()
if event and teams[event.puncher] then
--say(serialize(event))
local punch_id = get_id({x=event.x,y=event.y,z=event.z});
local flag = flag_id[punch_id];
if flag then
local state = ctf[flag].state
local puncher = event.puncher;
if state == 1 then -- flag is here, ready to be taken or capture of enemy flag
if teams[puncher][1] ~= flag then -- take
say(colorize("red","#CTF " .. puncher .. " has taken " .. ctf[flag].name .. " flag !"))
ctf[flag].state = 2;
ctf[flag].owner = puncher;
teams[puncher][2] = flag;
minetest.set_node(ctf[flag].pos, {name = "basic_robot:buttonFFFF80"})
else -- capture?
if teams[puncher][2] > 0 then
local cflag = teams[puncher][2] -- puncher has this flag
local data = ctf[cflag];
local team = teams[puncher][1];
ctf[team].score = ctf[team].score + 1
ctf[team].owner = ""
ctf[cflag].state = 1; -- reset captured flag state
minetest.set_node(ctf[cflag].pos, {name = ctf[cflag].flagnode})
teams[puncher][2] = 0
say(colorize("orange","#CTF " .. puncher .. " has captured " .. data.name .. " flag! Team " .. ctf[team].name .. " has score " .. ctf[team].score ))
if ctf[team].score == maxscore then
say(colorize("yellow","#CTF: TEAM " .. ctf[team].name .. " WINS! "))
gamestate = 3;t=5; -- intermission, duration 5
--reset
teams = {}
for i=1,#ctf do ctf[i].state = 1 ctf[i].score = 0 ctf[i].owner = "" end
end
end
end
end
end
--say(serialize(event))
end
elseif gamestate == 3 then -- intermission
if t>0 then t=t-1 else gamestate = 0 end
end

View File

@ -0,0 +1,91 @@
if not s then
-- init
bots = {[4] = {}, [5] = {}}; -- [type] = {{1,1,10}, {3,2,10}}; -- {x,y,hp}
arena = {}; --[x][z] = {type, idx}
for i = -10,10 do arena[i] = {} for j=-10,10 do arena[i][j] = {0,0} end end
centerpos = self.spawnpos(); centerpos.y = centerpos.y+2
TYPE = 4; -- 4,5 defines which bots are on the move/attack
DIR = 1
s=0
t=0
-- load user progs
_,script1 = book.read(1);_,script2 = book.read(2);
prog1, _ = _G.loadstring( script1 ); prog2, _ = _G.loadstring( script2 );
spawn_bot = function (x,z,type)
if arena[x] and arena[x][z] and arena[x][z][1] == 0 then
keyboard.set({x=centerpos.x+x,y=centerpos.y,z=centerpos.z+z},type)
table.insert(bots[type],{x,z,10})
arena[x][z] = {type,#bots[type]}
else
return false
end
end
move_bot = function (i,dx,dz)
local bot = bots[TYPE][i];if not bot then return false end
if math.abs(dx)>1 or math.abs(dz)>1 then return false end
local x1=bot[1]+dx; local z1=bot[2]+dz;
if math.abs(x1)>10 or math.abs(z1)>10 then return false end
if arena[x1] and arena[x1][z1] and arena[x1][z1][1] == 0 then else return false end
keyboard.set({x=centerpos.x+bot[1],y=centerpos.y,z=centerpos.z+bot[2]},0);
keyboard.set({x=centerpos.x+x1,y=centerpos.y,z=centerpos.z+z1},TYPE);
arena[bot[1]][bot[2]] = {0,0}
arena[x1][z1] = {TYPE,i}
bot[1]=x1;bot[2]=z1;
end
attack_bot = function(i,dx,dz)
local bot = bots[TYPE][i];if not bot then return false end
if math.abs(dx)>1 or math.abs(dz)>1 then return false end
local x1=bot[1]+dx; local z1=bot[2]+dz;
if math.abs(x1)>10 or math.abs(z1)>10 then return false end
if arena[x1] and arena[x1][z1] and arena[x1][z1][1] == 0 then return false end
local type = arena[x1][z1][1]; local idx = arena[x1][z1][2];
local tbot = bots[type][idx];
if not tbot then return false end
tbot[3]=tbot[3]-5;
if tbot[3]<=0 then
keyboard.set({x=centerpos.x+tbot[1],y=centerpos.y,z=centerpos.z+tbot[2]},0);
table.remove(bots[type],idx);
arena[x1][z1] = {0,0}
end
end
read_arena = function(x,z)
local data = arena[x][z];
if not data then return end
return {data[1],data[2]};
end
read_bots = function (type, idx)
local data = bots[type][idx];
if not data then return end
return {data[1],data[2],data[3]}
end
end
if t%10 == 0 then
spawn_bot(0,-10,4)
spawn_bot(0,10,5)
end
t=t+1
self.label(#bots[4] .. " " .. #bots[5])
-- PROGRAM RULES:
-- not allowed to modify api code: TYPE, bots,t,s, spawn_bot, move_bot, attack_bot, read_arena, read_bots
-- only allowed to move bot or attack, but not to dig/place
TYPE = 4+(t%2);
DIR = - DIR
if TYPE == 5 then
_G.setfenv(prog1, _G.basic_robot.data[self.name()].sandbox )
_,err = pcall(prog1)
else
_G.setfenv(prog2, _G.basic_robot.data[self.name()].sandbox )
_,err = pcall(prog2)
end
if err then say(err) self.remove() end

View File

@ -0,0 +1,150 @@
if not data then
m=10;n=10;
players = {};
paused = true
turn = 2;
t = 0;
SIGNUP = 0; GAME = 1; INTERMISSION = 2
state = SIGNUP
t0 = _G.minetest.get_gametime();spawnpos = self.spawnpos() -- place mines
data = {};
init_game = function()
data = {}; minescount = 32
for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end
if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area
data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0;
minescount = 0;
for i = 1,m do for j = 1,n do -- render game
if data[i] and data[i][j] == 1 then minescount = minescount + 1 end
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2)
end
end end
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z+1},4) -- safe start spot
end
get_mine_count = function(i,j)
if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0
for k = -1,1 do for l = -1,1 do
if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end
end end
return count
end
chk_mines = function()
local count = minescount;
for i=1,m do for j=1,n do
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonFF8080" and data[i] and data[i][j]==1 then
count=count-1
end
end end
return count
end
greeting = function()
_G.minetest.chat_send_all(colorize("red","#BATTLE MINESWEEPER : two player battle in minesweeper. say join to play.\nRules: 1. each player has 5 second turn to make a move 2. if you dont make move you lose\n3. if you make move in other player turn you lose. 4. if you hit bomb or mark bomb falsely you lose"))
end
player_lost = function ()
for i=1,#players do
local player = _G.minetest.get_player_by_name(players[i]);
if player then player:setpos({x=spawnpos.x,y=spawnpos.y+10,z=spawnpos.z}) end
end
state = INTERMISSION; t = 0
end
function change_turn()
if turn == 1 then
_G.minetest.sound_play("default_break_glass",{pos=spawnpos, max_hear_distance = 100})
else
_G.minetest.sound_play("note_a",{pos=spawnpos, max_hear_distance = 100})
end
if paused == false then
say(players[turn] .. " lost : didn't make a move");
player_lost()
else
if turn == 1 then turn = 2 else turn = 1 end
self.label("turn " .. turn .. " " .. players[turn])
t=0
paused = false
end
end
init_game()
greeting()
self.listen(1)
end
if state == SIGNUP then
speaker,msg = self.listen_msg()
if speaker then
if msg == "join" then
players[#players+1] = speaker;
local plist = ""; for i=1,#players do plist = plist .. players[i] .. ", " end
_G.minetest.chat_send_all("BATTLE MINESWEEPER, current players : " .. plist)
if #players >= 2 then
state = GAME
change_turn();
keyboard.get(); t=0;
for i = 1, #players do
local player = _G.minetest.get_player_by_name(players[i]);
if player then player:setpos({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z}) end
end
_G.minetest.chat_send_all(colorize("red","BATTLE MINESWEEPER " .. m .. "x" ..n .. " with " .. minescount .. " mines.\n" .. players[turn] .. " its your move!"))
end
end
end
elseif state == GAME then
t = t + 1;
if t>5 then -- change of turn
change_turn()
end
event = keyboard.get();
if event and event.type == 2 and not paused then
if event.puncher == players[turn] then
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
if x<1 or x>m or z<1 or z>n then
else
local ppos = player.getpos(event.puncher)
if ppos and math.abs(ppos.x-event.x)<0.5 and math.abs(ppos.z-event.z)<0.5 then -- just mark mine
if data[x] and data[x][z] == 1 then
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then
keyboard.set({x=event.x,y=event.y,z=event.z},2)
else
keyboard.set({x=event.x,y=event.y,z=event.z},3)
end
else
say(event.puncher .. " lost : marked a bomb where it was none! ");
player_lost()
end
else
if data[x] and data[x][z]==1 then
_G.minetest.sound_play("tnt_boom",{pos=spawnpos, max_hear_distance = 100})
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3)
say(event.puncher .. " lost : punched a bomb! ");
player_lost()
else
local count = get_mine_count(x,z);
if count == 0 then keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4)
else keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},7+count) end
end
end
end
paused = true
else
say(event.puncher .. " lost : played out of his/her turn"); player_lost()
end
end
elseif state == INTERMISSION then
t=t+1; if t> 15 then state = SIGNUP;players = {}; paused = true; init_game(); greeting() end
end

View File

@ -0,0 +1,195 @@
--black box by rnd, 03/18/2017
--https://en.wikipedia.org/wiki/Black_Box_(game)
if not data then
m=8;n=8;turn = 0;
attempts = 1;
self.spam(1);t0 = _G.minetest.get_gametime();
spawnpos = self.spawnpos()
data = {};
for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end
for i=1,4 do -- put in 4 atoms randomly
data[math.random(m)][math.random(n)] = 1
end
render_board = function(mode) -- mode 0 : render without solution, 1: render solution
for i = 1,m do for j = 1,n do -- render game
if mode == 0 or data[i][j] == 0 then
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2)
end
else
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},3)
end
end end
end
get_dirl = function(dir)
local dirl; -- direction left
if dir[1] > 0.5 then dirl = {0,-1}
elseif dir[1] < -0.5 then dirl = {0,1}
elseif dir[2] > 0.5 then dirl = {-1,0}
elseif dir[2] < -0.5 then dirl = {1,0}
end
return dirl
end
read_pos = function(x,z)
if x<1 or x>m or z<1 or z>n then return nil end
return data[x][z]
end
newdir = function(x,z,dir) -- where will ray go next
local retdir = {dir[1],dir[2]};
local xf = x+dir[1]; local zf = z+dir[2] -- forward
local dirl = get_dirl(dir)
local nodef = read_pos(xf,zf)
local nodel = read_pos(xf + dirl[1],zf + dirl[2])
local noder = read_pos(xf - dirl[1],zf - dirl[2])
if nodef == 1 then
retdir = {0,0} -- ray hit something
elseif nodel == 1 and noder ~= 1 then
retdir = {-dirl[1],-dirl[2]}
elseif nodel ~= 1 and noder == 1 then
retdir = {dirl[1],dirl[2]}
elseif nodel == 1 and noder == 1 then
retdir = {-dir[1],-dir[2]}
end
return retdir
end
shootray = function(x,z,dir)
--say("ray starts " .. x .. " " .. z .. " dir " .. dir[1] .. " " .. dir[2])
local xp = x; local zp = z;
local dirp = {dir[1],dir[2]};
local maxstep = m*n;
for i = 1,maxstep do
dirp = newdir(xp,zp,dirp);
if dirp[1]==0 and dirp[2]==0 then return -i end -- hit
xp=xp+dirp[1];zp=zp+dirp[2];
if xp<1 or xp>m or zp<1 or zp>n then return i,{xp,zp} end -- out
end
return 0 -- hit
end
count = 0; -- how many letters were used up
border_start_ray = function(x,z)
local rdir
if x==0 then rdir = {1,0}
elseif x == m+1 then rdir = {-1,0}
elseif z == 0 then rdir = {0,1}
elseif z == n+1 then rdir = {0,-1}
end
if rdir then
local result,out = shootray(x,z,rdir);
if result >= 0 then
if out then
if out[1]==x and out[2]==z then -- got back where it originated, reflection
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},1);
else
if result<=1 then
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},6); -- immediate bounce off
else
local nodename = "default:obsidian_letter_"..string.char(97+count) .. "u";
_G.minetest.set_node(
{x=spawnpos.x+out[1],y=spawnpos.y+1,z=spawnpos.z+out[2]},
{name = nodename, param2 = 1})
_G.minetest.set_node(
{x=spawnpos.x+x,y=spawnpos.y+1,z=spawnpos.z+z},
{name = nodename, param2 = 1})
count = count + 1;
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4);
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},4);
end
end
end
elseif result<0 then
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3); -- hit
end
end
end
-- initial border loop and marking
--render blue border
for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+0},5) keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+n+1},5) end
for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y,z=spawnpos.z+j},5) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y,z=spawnpos.z+j},5) end
for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+0},0) keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+n+1},0) end
for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y+1,z=spawnpos.z+j},0) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y+1,z=spawnpos.z+j},0) end
z=0 -- bottom
for x = 1,m do
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
border_start_ray(x,z)
end
end
x=m+1 -- right
for z = 1,n do
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
border_start_ray(x,z)
end
end
z=n+1 -- top
for x = m,1,-1 do
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
border_start_ray(x,z)
end
end
x=0 -- left
for z = n,1,-1 do
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
border_start_ray(x,z)
end
end
check_solution = function()
for i = 1,m do
for j = 1,n do
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}) == "basic_robot:buttonFF8080" then -- red
if data[i][j]~=1 then return false end
else
if data[i][j]~=0 then return false end
end
end
end
return true
end
--render board
render_board(0)
keyboard.set({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z-1},5)
end
event = keyboard.get();
if event then
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
if x<1 or x>m or z<1 or z>n then
if event.type == 5 then
if check_solution() then
say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove()
else
say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.")
attempts = attempts+1
end
end
else -- interior punch
nodetype = 2;
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button808080" then
nodetype = 3
end
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype);
end
end
::END::

View File

@ -0,0 +1,38 @@
-- rnd 2017
if not s then
s=0
player0 ="";
reward = "default:gold_ingot 6"
price = "default:gold_ingot";
self.spam(1)
end
if s==0 then
local player = find_player(5);
if player then
player=player[1]
if player~=player0 then
self.label("Hello " .. player .. ". Please insert one gold ingot in chest to play.\nYou need to roll 6 on dice to win 6 gold.")
player0 = player
end
else
self.label(colorize("red","Come and win 6 gold!"))
end
if check_inventory.forward(price) then
take.forward("default:gold_ingot");
self.label("Thank you for your gold. rolling the dice!")
s=1
end
elseif s==1 then
roll = math.random(6);
if roll == 6 then
self.label("#YOU WIN!")
say("#WE HAVE A WINNER! get 6 gold in chest!")
insert.forward(reward)
s=2
else
self.label(":( you rolled " .. roll.. ". Put gold in to try again.")
s=0
end
elseif s==2 then
if not check_inventory.forward(reward) then s=0 self.label("Please insert one gold to continue playing") end
end

View File

@ -0,0 +1,60 @@
-- CONNECT, coded in 20 minutes by rnd
if not data then
m=8;n=8;turn = 0; num = 4;
self.spam(1);t0 = _G.minetest.get_gametime();
spawnpos = self.spawnpos() -- place mines
state = 0; -- 0 signup 1 game
players = {};
data = {};
for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end
for i = 1,m do for j = 1,n do -- render game
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2)
end
end end
get_count_in_dir = function(dir,x,y)
local r = num; -- num=4? in a row
local snode = data[x][y];local count = 1;
for j = 1,2 do
for i = 1,r-1 do
local x1 = x + dir[1]*i;local y1 = y + dir[2]*i;
if not data[x1] or not data[x1][y1] then break end; if data[x1][y1]~= snode then break end
count = count +1
end
dir[1]=-dir[1];dir[2]=-dir[2];
end
return count
end
get_count = function(x,y)
local c1 = get_count_in_dir({0,1},x,y); local c2 = get_count_in_dir({1,0},x,y)
local c3 = get_count_in_dir({1,1},x,y); local c4 = get_count_in_dir({1,-1},x,y)
if c2>c1 then c1 = c2 end; if c3>c1 then c1 = c3 end; if c4>c1 then c1 = c4 end
return c1
end
self.label("CONNECT 4 : GREEN starts play. 2 players punch to join game.")
end
event = keyboard.get();
if event then
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
if x<1 or x>m or z<1 or z>n then
elseif event.type == 2 then --if event.type == 2 then
if state == 0 then
if #players<2 then players[#players+1] = event.puncher
else state = 1 end
if #players==2 then state = 1 end
end
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4+turn);
data[x][z] = 4+turn;
if get_count(x,z) == num then say("CONGRATULATIONS! " .. event.puncher .. " has "..num .. " in a row"); self.remove(); goto END end
turn = 1-turn
if state == 1 then
local msg = ""; if turn == 0 then msg = "GREEN " else msg = "BLUE" end
self.label(msg .. " : " .. players[turn+1])
end
end
end
::END::

View File

@ -0,0 +1,95 @@
if not init then
init = true
generate_random_string = function(n,m)
local ret = {};
for i = 1,n do ret[i]=string.char(math.random(m)+96) end --24
return table.concat(ret)
end
get_similiarity = function(text1,text2)
local n = string.len(text1);
if string.len(text2)~=n then return 0 end
local ret = 0;
for i = 1,n do
if string.sub(text1,i,i) == string.sub(text2,i,i) then ret = ret + 1 end
end
return ret
end
get_form = function()
local n = #passlist;
local frm = "label[0,0;" .. intro_msg .. "] " .. "label[0,8.5;" .. msg .. "] "
for i = 1,10 do
frm = frm .. "button[0,".. (i)*0.75 ..";2,1;" .. i .. ";".. passlist[i] .. "] "
end
for i = 11,n do
frm = frm .. "button[2,".. (i-11+1)*0.75 ..";2,1;" .. i .. ";".. passlist[i] .. "] "
end
local form = "size[6," .. 9 .. "]" .. frm;
return form
end
_G.math.randomseed(os.time())
intro_msg = minetest.colorize("lawngreen","FALLOUT PASSWORD HACKING GAME\nmatch is both position and character.")
msg = "" --TEST\nTEST\nTEST";
passlist = {}; passdict = {}
n = 20; -- how many options
count = 0;
while count< n do
local pass = generate_random_string(5,5); -- password length, charset size
if not passdict[pass] then passlist[#passlist+1] = pass; passdict[pass] = true; count = count + 1 end
end
correct = math.random(n)
guesses = 0
max_guesses = 4
rom.data = {};
if not rom.data then rom.data = {} end
self.spam(1)
local players = find_player(4);
if not players then say("#fallout hacking game: no players") self.remove() end
pname = players[1];
say("#fallout hacking game, player " .. pname)
--if rom.data[pname] then say("password is locked out!") self.remove() end
self.show_form(pname,get_form())
self.read_form()
end
sender,fields = self.read_form()
if sender and sender == pname then -- form event
local pl = _G.minetest.get_player_by_name(pname);
if pl then
local selected = 0
for k,_ in pairs(fields) do if k~="quit" then selected = tonumber(k) break end end
if selected>0 then
guesses = guesses + 1
if selected == correct then
say("password " .. passlist[correct] .. " is correct! " .. guesses .. " guesses.")
self.show_form(pname, "size[1,1] label[0,0.5;" .. minetest.colorize("lawngreen", "ACCESS GRANTED") .. "]")
self.remove()
--correct: do something with player
else
msg = msg .. " " .. minetest.colorize("yellow",guesses .. ". " .. passlist[selected]) .. " (" .. get_similiarity(passlist[correct], passlist[selected]) .. " match)"
self.show_form(pname, get_form())
end
if guesses>=max_guesses then
msg = minetest.colorize("red","A C C E S S D E N I E D!")
self.show_form(pname, get_form())
say("too many false guesses. password locked out!") rom.data[pname] = 1; self.remove()
end
end
if fields.quit then self.remove() end
end
end

View File

@ -0,0 +1,97 @@
-- 'hacking' game from Fallout, by rnd
if not init then
init = true
generate_random_string = function(n,m)
local ret = {};
for i = 1,n do ret[i]=string.char(math.random(m)+96) end --24
return table.concat(ret)
end
get_similiarity = function(text1,text2)
local n = string.len(text1);
if string.len(text2)~=n then return 0 end
local ret = 0;
for i = 1,n do
if string.sub(text1,i,i) == string.sub(text2,i,i) then ret = ret + 1 end
end
return ret
end
get_form = function()
local n = #passlist;
local frm = "label[0,0;" .. intro_msg .. "] " .. "label[0,8.5;" .. msg .. "] "
for i = 1,10 do
frm = frm .. "button[0,".. (i)*0.75 ..";2,1;" .. i .. ";".. passlist[i] .. "] "
end
for i = 11,n do
frm = frm .. "button[2,".. (i-11+1)*0.75 ..";2,1;" .. i .. ";".. passlist[i] .. "] "
end
local form = "size[4," .. 9 .. "]" .. frm;
return form
end
_G.math.randomseed(os.time())
intro_msg = minetest.colorize("lawngreen","FALLOUT PASSWORD HACKING GAME\nmatch is both position and character.")
msg = "" --TEST\nTEST\nTEST";
passlist = {}; passdict = {}
n = 20; -- how many options
count = 0;
while count< n do
local pass = generate_random_string(4,5); -- password length, charset size
if not passdict[pass] then passlist[#passlist+1] = pass; passdict[pass] = true; count = count + 1 end
end
correct = math.random(n)
guesses = 0
max_guesses = 4
rom.data = {};
if not rom.data then rom.data = {} end
self.spam(1)
local players = find_player(4);
if not players then say("#fallout hacking game: no players") self.remove() end
pname = players[1];
say("#fallout hacking game, player " .. pname)
--if rom.data[pname] then say("password is locked out!") self.remove() end
self.show_form(pname,get_form())
self.read_form()
end
sender,fields = self.read_form()
if sender and sender == pname then -- form event
local pl = _G.minetest.get_player_by_name(pname);
if pl then
local selected = 0
for k,_ in pairs(fields) do if k~="quit" then selected = tonumber(k) break end end
if selected>0 then
guesses = guesses + 1
if selected == correct then
say("password " .. passlist[correct] .. " is correct! " .. guesses .. " guesses.")
self.show_form(pname, "size[1,1] label[0,0.5;" .. minetest.colorize("lawngreen", "ACCESS GRANTED") .. "]")
self.remove()
--correct: do something with player
else
if guesses == 3 then msg = msg .. "\n" end
msg = msg .. " " .. minetest.colorize("yellow",guesses .. ". " .. passlist[selected]) .. " (" .. get_similiarity(passlist[correct], passlist[selected]) .. " match)"
self.show_form(pname, get_form())
end
if guesses>=max_guesses then
msg = minetest.colorize("red","A C C E S S D E N I E D!")
self.show_form(pname, get_form())
say("too many false guesses. password locked out!") rom.data[pname] = 1; self.remove()
end
end
if fields.quit then self.remove() end
end
end

View File

@ -0,0 +1,106 @@
--HIDE AND SEEK game robot, by rnd
if not gamemaster then
timeout = 10;
gamemaster = "rnd"
player_list = {};
_G.minetest.chat_send_all("# HIDE AND SEEK .. say #hide to join play")
s=0;t=0; count = 0;
_G.minetest.forceload_block(self.pos(),true)
self.listen(1); self.label(colorize("yellow","HIDE&SEEK"))
end
speaker,msg = self.listen_msg();
if s==0 then
if msg =="#hide" then
player_list[speaker]={};
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. speaker .. " joined the game")
local player = _G.minetest.get_player_by_name(speaker);
if player then
player:setpos({x=0,y=5,z=0});player:set_properties({nametag_color = "0x0"})
end
end
if msg == "#start" and speaker == gamemaster then s = 0.5 _G.minetest.chat_send_all("# HIDE AND SEEK STARTS in " .. timeout .. " SECONDS!") end
elseif s==0.5 then
t=t+1
if t==timeout then
t=0;s = 1; count = 0;
for pname,_ in pairs(player_list) do
local player = _G.minetest.get_player_by_name(pname);
if player then
player_list[pname].hp = player:get_hp();
player_list[pname].pos = player:getpos()
player_list[pname].t = 0;
count = count+1
end
end
if count == 1 then
gamemaster = false; _G.minetest.chat_send_all("# HIDE AND SEEK only 1 player, aborting.")
else
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK STARTS NOW WITH " .. count .. " PLAYERS. You are out if: 1.your health changes, 2. leave spawn. If stay in same area for too long or you will be exposed."))
end
end
elseif s==1 then
players = _G.minetest.get_connected_players();
count = 0;
for _,player in pairs(players) do
local name = player:get_player_name();
local data = player_list[name];
if data then
count=count+1
local pos = player:getpos();
local dist = math.max(math.abs(pos.x),math.abs(pos.y),math.abs(pos.z));
if dist>50 or (not _G.minetest.get_player_by_name(name)) then
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! went too far away " )
player:set_properties({nametag_color = "white"})
player_list[name] = nil;
end
if data.hp ~= player:get_hp() then
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! his health changed!" )
player:set_properties({nametag_color = "white"})
player_list[name] = nil;
end
--expose campers
local p = data.pos;
dist = math.max(math.abs(pos.x-p.x),math.abs(pos.y-p.y),math.abs(pos.z-p.z));
--say( name .. " dist " .. dist .. " t " .. data.t)
if dist<8 then
data.t = data.t+1;
if not data.camp then
if data.t>15 and not data.camp then
_G.minetest.chat_send_player(name, "# HIDE AND SEEK: move in 5s or be exposed")
data.camp = true
end
elseif data.t>=20 then
pos.x=math.ceil(pos.x);pos.y=math.ceil(pos.y);pos.z=math.ceil(pos.z);
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. name .. " is camping at " .. pos.x .. " " .. pos.z)
data.camp = false; data.t = 0
end
else
data.t = 0; data.pos = player:getpos(); data.camp = false
end
end
end
self.label(count)
if count<=1 then
if count==1 then
for name,_ in pairs(player_list) do
player0=_G.minetest.get_player_by_name(name)
_G.minetest.chat_send_all(colorize("red","****** HIDE AND SEEK: ".. name .. " wins ******"))
player0:set_properties({nametag_color = "white"})
gamemaster = false;
end
else
_G.minetest.chat_send_all("# HIDE AND SEEK: no players left")
gamemaster = false;
end
end
end

View File

@ -0,0 +1,151 @@
--HIDE AND SEEK game robot
if not gamemaster then
timeout = 30;
gamemaster = "rnd"
gamepos = {x=0,y=5,z=0}
player_list = {};
s=0;t=0; count = 0;
prize = ""
get_players = function()
local msg = "";
for name,_ in pairs(player_list) do
msg = msg .. " " .. name
end
return msg
end
init_game = function()
local msg = get_players();
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK : hide from everyone else who is playing. Winner gets DIAMONDS\nsay join to join play. say #start to start game."..
" players: " .. msg))
s=0;t=0;
end
init_game()
_G.minetest.forceload_block(self.pos(),true)
self.listen(1); self.label(colorize("yellow","HIDE&SEEK"))
end
speaker,msg = self.listen_msg();
if s==0 then
t = t +1
if t%30 == 0 then
init_game();
end
if msg =="join" then
player_list[speaker]={};
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK: " .. speaker .. " joined the game"));
_G.minetest.chat_send_all("players: " .. get_players())
local player = _G.minetest.get_player_by_name(speaker);
count = count + 1
if player then
player:setpos(gamepos);player:set_properties({nametag_color = "0x0"})
player:set_hp(20)
local inv = player:get_inventory();inv:set_list("main",{})
end
end
if msg == "#start" and count>1 then s = 0.5 _G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK STARTS in " .. timeout .. " SECONDS!")) end
elseif s==0.5 then
t=t+1
if t==timeout then
t=0;s = 1; count = 0;
for pname,_ in pairs(player_list) do
local player = _G.minetest.get_player_by_name(pname);
if player then
player_list[pname].hp = player:get_hp();
player_list[pname].pos = player:getpos()
player_list[pname].t = 0;
count = count+1
end
end
if count == 1 then
gamemaster = false; _G.minetest.chat_send_all("# HIDE AND SEEK only 1 player, aborting.")
else
prize = "default:diamond " .. (count-1);
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK STARTS NOW WITH " .. count .. " PLAYERS."..
"You are out if: 1.your health changes, 2. leave game area. If stay in same area for too long or you will be exposed."))
_G.minetest.chat_send_all(colorize("red","# WINNER WILL GET " .. prize))
end
end
elseif s==1 then
players = _G.minetest.get_connected_players();
count = 0;
for _,player in pairs(players) do
local name = player:get_player_name();
local data = player_list[name];
if data then
count=count+1
local pos = player:getpos();
local dist = math.max(math.abs(pos.x-gamepos.x),math.abs(pos.y-gamepos.y),math.abs(pos.z-gamepos.z));
if dist>100 or (not _G.minetest.get_player_by_name(name)) then
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! went too far away " )
player:set_properties({nametag_color = "white"})
player_list[name] = nil;
_G.minetest.chat_send_all("remaining players: " .. get_players())
end
if data.hp ~= player:get_hp() then
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! his health changed!" )
player:set_properties({nametag_color = "white"})
player_list[name] = nil;
_G.minetest.chat_send_all("remaining players: " .. get_players())
player:setpos({x=0,y=5,z=0})
end
--expose campers
local p = data.pos;
dist = math.max(math.abs(pos.x-p.x),math.abs(pos.y-p.y),math.abs(pos.z-p.z));
--say( name .. " dist " .. dist .. " t " .. data.t)
if dist<8 then
data.t = data.t+1;
if not data.camp then
if data.t>25 and not data.camp then
_G.minetest.chat_send_player(name, "# HIDE AND SEEK: move in 5s or be exposed")
data.camp = true
end
elseif data.t>=30 then
pos.x=math.ceil(pos.x);pos.y=math.ceil(pos.y);pos.z=math.ceil(pos.z);
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. name .. " is camping at " .. pos.x .. " " .. pos.z)
data.camp = false; data.t = 0
end
else
data.t = 0; data.pos = player:getpos(); data.camp = false
end
end
end
self.label(count)
if count<=1 then
if count==1 then
for name,_ in pairs(player_list) do
local player0=_G.minetest.get_player_by_name(name)
if player0 then
_G.minetest.chat_send_all(colorize("red","****** HIDE AND SEEK: ".. name .. " wins ******"))
local inv = player0:get_inventory();
inv:add_item("main",_G.ItemStack(prize))
player0:set_properties({nametag_color = "white"})
player0:setpos({x=0,y=5,z=0})
end
s=2
end
else
_G.minetest.chat_send_all("# HIDE AND SEEK: no players left")
s=2
end
end
elseif s==2 then
player_list = {}
init_game()
end

View File

@ -0,0 +1,83 @@
-- minesweeper
if not data then
m=24;n=22; minescount = m*n/5;
reward = 30;
if not find_player(4) then error("minesweeper: no players near") end
self.spam(1)
t0 = _G.minetest.get_gametime();
data = {}; spawnpos = self.spawnpos() -- place mines
for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end
if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area
data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0;
minescount = 0;
for i = 1,m do for j = 1,n do -- render game
if data[i] and data[i][j] == 1 then minescount = minescount + 1 end
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:button808080"})
end
end end
puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
get_mine_count = function(i,j)
if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0
for k = -1,1 do for l = -1,1 do
if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end
end end
return count
end
chk_mines = function()
local count = minescount;
for i=1,m do for j=1,n do
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonFF8080" and data[i] and data[i][j]==1 then
count=count-1
end
end end
return count
end
say("minesweeper " .. m .. "x" ..n .. " with " .. minescount .. " mines ")
self.label("find all hidden mines! mark mine by standing on top of block and punch,\notherwise it will uncover the block (and possibly explode).")
end
event = keyboard.get();
if event then
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
if x<1 or x>m or z<1 or z>n then
if x == 0 and z == 1 then
local count = chk_mines();
if count == 0 then
t0 = _G.minetest.get_gametime() - t0;
say("congratulations! " .. event.puncher .. " discovered all mines in " .. t0 .. " s")
_G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.ItemStack("default:gold_ingot "..reward)) -- diamond reward
else
reward = reward*(1-(count/minescount))^(1.5); reward = math.floor(reward);
say("FAIL! " .. count .. " mines remaining. You get " .. reward .. " gold for found mines")
_G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.ItemStack("default:gold_ingot "..reward)) -- diamond reward
end
self.remove()
end
else --if event.type == 2 then
local ppos = player.getpos(event.puncher)
if ppos and math.abs(ppos.x-event.x)<0.5 and math.abs(ppos.z-event.z)<0.5 then -- just mark mine
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:button808080"})
else
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonFF8080"})
end
else
if data[x] and data[x][z]==1 then
say("boom! "..event.puncher .. " is dead ");puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttonFF8080"});
local player_ = puzzle.get_player(event.puncher);
player_:setpos({x=spawnpos.x-1,y=spawnpos.y+1,z=spawnpos.z-1});
self.remove()
else
local count = get_mine_count(x,z);
if count == 0 then puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button80FF80"})
else puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button"..count}) end
end
end
end
end

259
scripts/games/nonogram.lua Normal file
View File

@ -0,0 +1,259 @@
-- nonogram game, created in 1hr 40 min by rnd
-- INIT
if not grid then
n=6
solved = false -- do we render solution or blank?
-- _G.math.randomseed(3)
self.spam(1)
function get_score_from_string(score)
--say(score)
local scores = {};
local j=1; --j k l
for i=0,5 do -- 0 - 999 1 - 999 2 - 999 3 - 999 4 - 999 5 - 999
j = string.find(score," ", j+1);
local k = string.find(score," ", j+1);
local l = string.find(score," ", k+1);
if i==5 then l = string.len(score)+1 end
scores[i] = {string.sub(score,j+1,k-1),tonumber(string.sub(score,k+1,l-1))};
j=l
end
return scores
end
if not rom.score then _,rom.score = book.read(1) end
--rom.score = "0 - 999 1 - 999 2 - 999 3 - 999 4 - 999 5 - 999" -- default
highscore = get_score_from_string(rom.score)
--self.label(string.gsub(_G.dump(highscore), "\n",""))
function get_score_string(scores)
local out = ""
for i = 0,5 do
out = out .. i .. " " ..
scores[i][1] .. " " ..
scores[i][2] .. " "
end
return out
end
t0 = _G.minetest.get_gametime()
local intro ="numbers at beginning of each row (coloumn) tell how many\nred blocks are together in each row ( coloumn )." ..
"\npunch gray blocks to toggle them and reveal hidden red blocks.\npunch green to check solution. If you give up punch blue.";
self.label(intro)
grid = {}
spawnpos = self.spawnpos();
offsetx = 10 - math.ceil(n/2); offsetz = math.floor(n/2);
spawnpos.x = spawnpos.x - offsetx; spawnpos.z = spawnpos.z - offsetz;
spawnpos.y = spawnpos.y+3
for i=1,n do
grid[i]={};
for j=1,n do
grid[i][j]=math.random(2)-1
end
end
getcounts = function(grid)
local rowdata = {};
for i=1,n do
rowdata[i]={}; local data = rowdata[i];
local s=0;local c=0;
for j = 1, n do
if s == 0 and grid[i][j]==1 then s=1;c=0 end
if s == 1 then
if grid[i][j]==1 then
c=c+1
if j == n then data[#data+1]=c end
else
data[#data+1]=c; s=0
end
end
end
end
local coldata = {};
for j=1,n do
coldata[j]={}; local data = coldata[j];
local s=0;local c=0;
for i = 1, n do
if s == 0 and grid[i][j]==1 then s=1;c=0 end
if s == 1 then
if grid[i][j]==1 then
c=c+1
if i == n then data[#data+1]=c end
else
data[#data+1]=c; s=0
end
end
end
end
return rowdata,coldata
end
read_field = function()
local grid = {};
for i = 1, n do
grid[i]={};
for j = 1,n do
local typ = keyboard.read({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+i});
if typ == "basic_robot:button808080" then grid[i][j] = 0 else grid[i][j] = 1 end
end
end
return grid
end
rowdata,coldata = getcounts(grid)
check_solution = function()
local rdata,cdata;
rdata,cdata = getcounts(read_field())
for i = 1,#rdata do
if #rdata[i]~=#rowdata[i] then return false end
for j = 1, #rdata[i] do
if rdata[i][j]~=rowdata[i][j] then return false end
end
end
for i = 1,#cdata do
if #cdata[i]~=#coldata[i] then return false end
for j = 1, #rdata[i] do
if cdata[i][j]~=coldata[i][j] then return false end
end
end
return true
end
get_difficulty = function()
local easy = 0;
for k = 1, n do
local sum=0
for i = 1,#rowdata[k]-1 do
sum = sum + rowdata[k][i]+1;
end
if #rowdata[k]>0 then sum = sum + rowdata[k][#rowdata[k]] else sum = n end
if sum == n then easy = easy + 1 end
end
for k = 1, n do
local sum=0
for i = 1,#coldata[k]-1 do
sum = sum + coldata[k][i]+1;
end
if #coldata[k]>0 then sum = sum + coldata[k][#coldata[k]] else sum = n end
if sum == n then easy = easy + 1 end
end
easy = 5-easy;
if easy < 0 then easy = 0 end
return easy
end
-- render game
for i=1,n do
for j =1,n do
keyboard.set({x=spawnpos.x-n+j,y=spawnpos.y,z=spawnpos.z+i},0) -- clear
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+2*n-i+1},0) -- clear
local typ;
if grid[j][i]==0 then typ = 2 else typ = 3 end
if not solved then typ = 2 end
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ) --board
end
end
--render counts rows
for i=1,n do
length = #rowdata[i]
for k = 1,length do
keyboard.set({x=spawnpos.x-length+k,y=spawnpos.y,z=spawnpos.z+i},rowdata[i][k]+7)
end
end
--render counts coloumns
for j=1,n do
length = #coldata[j]
for k = 1,length do
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+k+n},coldata[j][k]+7)
end
end
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},4) -- game check button
keyboard.set({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},5) -- game check button
--self.label()
--self.label(string.gsub(_G.dump(read_field()),"\n","") )
difficulty = get_difficulty()
reward = 0; limit = 0;
if difficulty == 5 then limit = 120 reward = 10
elseif difficulty == 4 then limit = 115 reward = 9 -- 60s
elseif difficulty == 3 then limit = 100 reward = 8
elseif difficulty == 2 then limit = 80 reward = 7
elseif difficulty <= 1 then limit = 70 reward = 6
end
say("nonogram difficulty " .. difficulty .. ". you will get " .. reward .. " gold if you solve it in faster than " .. limit .."s" ..
". Current record " .. highscore[difficulty][2] .. " by " .. highscore[difficulty][1])
end
event = keyboard.get()
if event then
if event.y == spawnpos.y and event.z == spawnpos.z then
if event.x == spawnpos.x+1 then -- check solution
if check_solution() then
t = _G.minetest.get_gametime(); t = t- t0;
local msg = "";
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},2)
msg = n .. "x" .. n .. " nonogram (difficuly " .. difficulty .. ") solved by " .. event.puncher .. " in " .. t .. " seconds. "
if t < limit then
msg = msg .. " He gets " .. reward .. " gold for quick solve.";
else
reward = reward*2*(1-2*(t-limit)/limit)/2; if reward<0 then reward = 0 end
reward = math.floor(reward);
msg = msg .. " Your time was more than " .. limit .. ", you get " .. reward .. " gold ";
end
-- highscore
if t<highscore[difficulty][2] then
say("new record! old record " .. highscore[difficulty][2] .. "s by " .. highscore[difficulty][1])
highscore[difficulty] = {event.puncher, t}
rom.score = get_score_string(highscore)
book.write(1,"scores", rom.score)
end
if reward>0 then
local player = _G.minetest.get_player_by_name(event.puncher);
if player then
local inv = player:get_inventory();
inv:add_item("main",_G.ItemStack("default:gold_ingot " .. reward))
end
end
say(msg)
self.remove()
else self.label("FAIL") end
elseif event.x == spawnpos.x+2 then -- solve
say("you gave up on game, displaying solution")
for i=1,n do
for j =1,n do
local typ;
if grid[j][i]==0 then typ = 2 else typ = 3 end
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ)
end
end
self.remove()
end
else
local i = event.x-spawnpos.x;local j = event.z-spawnpos.z;
if i>0 and i<=n and j>0 and j<=n then
local typ = keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j});
local newtyp;
if typ == "basic_robot:button808080" then newtyp = 3
else newtyp = 2
end
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},newtyp);
end
end
end

View File

@ -0,0 +1,74 @@
-- sliding unscramble game by rnd, made in 20 minutes
if not init then
init = true
spos = self.spawnpos(); spos.y = spos.y + 1
board = {};
size = 3;
create_board = function(n)
local k = 0;
local ret = scramble(n*n, os.time())
for i = 1,n do
board[i]={};
for j = 1,n do
k=k+1
board[i][j]=7+ret[k] -- 7 numbers, 82 letters
end
end
board[math.random(n)][math.random(n)] = 0
end
render_board = function()
local n = #board;
for i = 1,n do
for j = 1,n do
keyboard.set({x=spos.x+i, y = spos.y, z=spos.z+j}, board[i][j])
end
end
end
find_hole = function(i,j)
if board[i][j] == 0 then return i,j end
if i>1 and board[i-1][j] == 0 then return i-1,j end
if i<#board and board[i+1][j] == 0 then return i+1,j end
if j>1 and board[i][j-1] == 0 then return i,j-1 end
if j<#board and board[i][j+1] == 0 then return i,j+1 end
return nil
end
scramble = function(n,seed)
_G.math.randomseed(seed);
local ret = {}; for i = 1,n do ret[i]=i end
for j = n,2,-1 do
local k = math.random(j);
if k~=j then
local tmp = ret[k]; ret[k] = ret[j]; ret[j] = tmp
end
end
return ret
end
create_board(size)
render_board()
end
event = keyboard.get();
if event and event.y == spos.y then
local x = event.x-spos.x;
local z = event.z-spos.z;
if x<1 or x>size or z<1 or z>size then
else
local i,j = find_hole(x,z);
if i then
local tmp = board[x][z];
keyboard.set({x=spos.x+x, y = spos.y, z=spos.z+z}, board[i][j])
board[x][z] = board[i][j]
board[i][j] = tmp;
keyboard.set({x=spos.x+i, y = spos.y, z=spos.z+j}, tmp)
end
end
end

View File

@ -0,0 +1,175 @@
-- SOKOBAN GAME, by rnd, robots port
if not sokoban then
sokoban = {};
local players = find_player(5);
if not players then error("sokoban: no player near") end
name = players[1];
self.show_form(name,
"size[2,1.25]"..
"label[0,0;SELECT LEVEL 1-90]"..
"field[0.25,1;1,1;LVL;LEVEL;1]"..
"button_exit[1.25,0.75;1,1;OK;OK]"
)
state = 1 -- will wait for form receive otherwise game play
player_ = puzzle.get_player(name); -- get player entity - player must be present in area
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0});player_:set_physics_override({jump=1}) -- reset player
self.spam(1)
sokoban.push_time = 0
sokoban.blocks = 0;sokoban.level = 0; sokoban.moves=0;
imax = 0; jmax = 0
sokoban.load=0;sokoban.playername =""; sokoban.pos = {};
SOKOBAN_WALL = "default:brick"
SOKOBAN_FLOOR = "default:stonebrick"
SOKOBAN_GOAL = "default:diamondblock"
SOKOBAN_BOX = "basic_robot:button8080FF"
load_level = function(lvl)
local pos = self.spawnpos(); pos.x=pos.x+1;pos.y=pos.y+1;
sokoban.pos = pos;
sokoban.playername = name
if lvl == nil then return end
if lvl <0 or lvl >89 then return end
local file = _G.io.open(minetest.get_modpath("basic_robot").."\\scripts\\sokoban.txt","r")
if not file then return end
local str = ""; local s; local p = {x=pos.x,y=pos.y,z=pos.z}; local i,j;i=0;
local lvl_found = false
while str~= nil do
str = file:read("*line");
if str~=nil and str =="; "..lvl then lvl_found=true break end
end
if not lvl_found then file:close();return end
sokoban.blocks = 0;sokoban.level = lvl+1; sokoban.moves=0;
imax=0; jmax = 0;
while str~= nil do
str = file:read("*line");
if str~=nil then
if string.sub(str,1,1)==";" then
imax=i;
file:close();
player_:set_physics_override({jump=0})
player_:set_eye_offset({x=0,y=20,z=0},{x=0,y=0,z=0})
say("games: sokoban level "..sokoban.level .." loaded by ".. name .. ". It has " .. sokoban.blocks .. " boxes to push. "); return
end
i=i+1;
if string.len(str)>jmax then jmax = string.len(str) end -- determine max dimensions
for j = 1,string.len(str) do
p.x=pos.x+i;p.y=pos.y; p.z=pos.z+j; s=string.sub(str,j,j);
p.y=p.y-1;
if puzzle.get_node(p).name~=SOKOBAN_FLOOR then puzzle.set_node(p,{name=SOKOBAN_FLOOR}); end -- clear floor
p.y=p.y+1;
if s==" " and puzzle.get_node(p).name~="air" then puzzle.set_node(p,{name="air"}) end
if s=="#" and puzzle.get_node(p).name~=SOKOBAN_WALL then puzzle.set_node(p,{name=SOKOBAN_WALL}) end
if s=="$" then puzzle.set_node(p,{name=SOKOBAN_BOX});sokoban.blocks=sokoban.blocks+1 end
if s=="." then p.y=p.y-1;puzzle.set_node(p,{name=SOKOBAN_GOAL}); p.y=p.y+1;puzzle.set_node(p,{name="air"}) end
--starting position
if s=="@" then
player_:setpos({x=p.x,y=p.y+1,z=p.z}); -- move player to start position
--p.y=p.y-1;puzzle.set_node(p,{name="default:glass"});
puzzle.set_node(p,{name="air"})
p.y=p.y+1;puzzle.set_node(p,{name="air"})
--p.y=p.y+2;puzzle.set_node(p,{name="default:ladder"})
end
if s~="@" then p.y = pos.y+2;puzzle.set_node(p,{name="air"}); -- ceiling default:obsidian_glass
else --p.y=pos.y+2;puzzle.set_node(p,{name="default:ladder"})
end -- roof above to block jumps
end
end
end
file:close();
end
end
if state == 1 then
sender,fields = self.read_form(); -- get fields from form submittal
if sender then
--say(serialize(fields))
if fields.LVL then
load_level((tonumber(fields.LVL) or 1)-1)
state = 0
self.label("stand close to blue box and punch it one time to push it. you can only push 1 box\nand cant pull. goal is to get all boxes pushed on diamond blocks")
end
end
else
local ppos = player_:getpos()
if math.abs(ppos.y-sokoban.pos.y)~= 0.5 then say(colorize("red", "SOKOBAN: " .. name .. " QUITS ! "));
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0});player_:set_physics_override({jump=1}); self.remove() end
event = keyboard.get();
if event then
local pname = event.puncher
if pname ~= name then goto quit end
local pos = {x=event.x, y = event.y, z = event.z};
local p=player.getpos(pname);local q={x=pos.x,y=pos.y,z=pos.z}
p.x=p.x-q.x;p.y=p.y-q.y;p.z=p.z-q.z
if math.abs(p.y+0.5)>0 then goto quit end
if math.abs(p.x)>math.abs(p.z) then -- determine push direction
if p.z<-0.5 or p.z>0.5 or math.abs(p.x)>1.5 then goto quit end
if p.x+q.x>q.x then q.x= q.x-1
else q.x = q.x+1
end
else
if p.x<-0.5 or p.x>0.5 or math.abs(p.z)>1.5 then goto quit end
if p.z+q.z>q.z then q.z= q.z-1
else q.z = q.z+1
end
end
if minetest.get_node(q).name=="air" then -- push crate
sokoban.moves = sokoban.moves+1
local old_infotext = minetest.get_meta(pos):get_string("infotext");
minetest.set_node(pos,{name="air"})
minetest.set_node(q,{name=SOKOBAN_BOX})
minetest.sound_play("default_dig_dig_immediate", {pos=q,gain=1.0,max_hear_distance = 24,}) -- sound of pushing
local meta = minetest.get_meta(q);
q.y=q.y-1;
if minetest.get_node(q).name==SOKOBAN_GOAL then
if old_infotext~="GOAL REACHED" then
sokoban.blocks = sokoban.blocks -1;
end
meta:set_string("infotext", "GOAL REACHED")
else
if old_infotext=="GOAL REACHED" then
sokoban.blocks = sokoban.blocks +1
end
--meta:set_string("infotext", "push crate on top of goal block")
end
end
if sokoban.blocks~=0 then -- how many blocks left
--say("move " .. sokoban.moves .. " : " ..sokoban.blocks .. " crates left ");
else
say("games: ".. name .. " just solved sokoban level ".. sokoban.level .. " in " .. sokoban.moves .. " moves.");
player_:set_physics_override({jump=1})
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
local i,j;
for i = 1,imax do
for j=1,jmax do
minetest.set_node({x= sokoban.pos.x+i,y=sokoban.pos.y,z=sokoban.pos.z+j}, {name = "air"}); -- clear level
end
end
sokoban.playername = ""; sokoban.level = 1
end
::quit::
end
end

View File

@ -0,0 +1,85 @@
-- rnd 2017
-- instructions: put 7 buttons around bot(top one left empty)
-- clockwise: empty, green, yellow,blue, red, blue,yellow,green.
-- those buttons serve as controls
if not s then
name = self.name();
direction = 1;
s=0;
self.label("TANK ROBOT. control with colored buttons")
user=find_player(4); if user then user = user[1] end
speed = 7 + math.random(7);turn.angle(math.random(360));
pitch = 0
gravity = 1+math.random(2);
if user then
say("TANK ROBOT, ready. ".. user .. " in control")
else
say("no player found nearby. deactivating"); self.remove()
s=-1
end
pos = self.spawnpos();
end
ppos = player.getpos(user); ppos.x=ppos.x-pos.x;ppos.y=ppos.y-pos.y;ppos.z=ppos.z-pos.z;
if ppos.x^2+ppos.y^2+ppos.z^2>10 then
local obj = _G.minetest.get_player_by_name(user);
if obj then say("deserter " .. user .. " killed for abandoning the tank!") obj:set_hp(0) end
self.remove()
else
local obj = _G.minetest.get_player_by_name(user);
if obj then
if obj:get_hp() == 0 then
say("TANK DESTROYED!")
self.remove()
end
end
end
if s == 0 then
event = keyboard.get();
if event and event.puncher==user then
--self.label(event.x-pos.x .. " " .. event.y-pos.y .. " " .. event.z-pos.z .. " T " .. event.type)
event.x = event.x-pos.x;event.y = event.y-pos.y;event.z = event.z-pos.z;
if event.x == 0 and event.y == 0 and event.z == 1 then
self.fire(speed, pitch,gravity)
s=1;self.label("BOOM")
_G.minetest.sound_play("tnt_explode",{pos = self.pos(), max_hear_distance = 256, gain = 1})
elseif event.x == direction*1 and event.y == 0 and event.z == direction*1 then
turn.angle(2)
elseif event.x == -1*direction and event.y == 0 and event.z == 1*direction then
turn.angle(-2)
elseif event.x == 1*direction and event.y == 0 and event.z == 0 then
turn.angle(40)
elseif event.x == -1*direction and event.y == 0 and event.z == 0 then
turn.angle(-40)
elseif event.x == 1*direction and event.y == 0 and event.z == -1*direction then
pitch = pitch + 5; if pitch> 85 then pitch = 85 end
self.label("pitch " .. pitch)
elseif event.x == -1*direction and event.y == 0 and event.z == -1*direction then
pitch = pitch - 5; if pitch<-10 then pitch = -10 end
self.label("pitch " .. pitch)
end
end
end
if s == 1 then
local pos = self.fire_pos();
if pos then
self.label("HIT")
msg = "";
_G.minetest.sound_play("tnt_explode",{pos = pos, max_hear_distance = 256, gain = 1})
local objs=_G.minetest.get_objects_inside_radius(pos, 4);
for _,obj in pairs(objs) do
if obj:is_player() then
obj:set_hp(0)
msg = msg .. obj:get_player_name() .. " is dead, "
end
end
s = 0
if msg~="" then say(msg) end
end
end

View File

@ -0,0 +1,92 @@
-- robot can construct classic fractals like menger sponge, jerusalem cube, sierpinski triangles,..
-- use: build a pattern at position 1,1,1 relative to robot. when run robot will analyse pattern and construct fractal
if not init then
minetest.forceload_block(self.pos(),true)
init = true; local spos = self.spawnpos();
offsets = {["default:dirt"] = 0, ["default:wood"] = -1, ["default:cobble"] = 1}
read_form = function(fractal) -- read shape from world
local form = {}; local i = 0;
local spos = self.spawnpos(); spos.x = spos.x+1;spos.y = spos.y+1;spos.z = spos.z+1;
local nx = 0; local ny = 0; local nz = 0;
fractal.form = {}
for x = 0,fractal.nx-1 do
for y = 0,fractal.ny-1 do
for z = 0,fractal.nz-1 do
local node = _G.minetest.get_node({x=spos.x+x,y=spos.y+y,z=spos.z+z}).name;
local offset = offsets[node] or 0;
if node~= "air" then
form[i] = {x,y,z,offset}; i=i+1
if nx<x then nx = x end
if ny<y then ny = y end
if nz<z then nz = z end
end
end
end
end
form[0] = nil;
fractal.form = form;
fractal.nx = nx+1; fractal.ny = ny+1; fractal.nz = nz+1;
end
iterate = function(fractal)
local m = #sponge;
local nx = fractal.nx;
for j = 1, #sponge do
local scoords = sponge[j];
for i = 1, #(fractal.form) do
local coords = (fractal.form)[i];
sponge[#sponge+1] = {scoords[1] + (coords[1]+coords[4]/nx)*sidex, scoords[2] + coords[2]*sidey, scoords[3] + coords[3]*sidez};
end
end
sidex = sidex * fractal.nx;
sidey = sidey * fractal.ny;
sidez = sidez * fractal.nz;
end
make = function(fractal, iter)
sidex = 1;sidey = 1;sidez = 1;
sponge = {{0,0,0}};
for i = 1, iter do
iterate(fractal)
end
end
build = function(sponge)
local grid = 2^2;
local spos = self.spawnpos(); spos.x = spos.x+1;spos.y = spos.y+1;spos.z = spos.z+1;
for j = 1, #sponge do
local scoords = sponge[j];
--local color = (math.floor(scoords[1]/grid) + math.floor(scoords[3]/grid)) % 2;
local nodename = "default:stonebrick"
--if color == 0 then nodename = "default:goldblock" else nodename = "default:diamondblock" end
minetest.swap_node({x=spos.x+scoords[1],y=spos.y+scoords[2],z=spos.z+scoords[3]},{name = nodename})
end
end
clear = function()
local grid = 2^2;
local spos = self.spawnpos(); spos.x = spos.x+1;spos.y = spos.y+1;spos.z = spos.z+1;
for j = 1, #sponge do
local scoords = sponge[j];
minetest.swap_node({x=spos.x+scoords[1],y=spos.y+scoords[2],z=spos.z+scoords[3]},{name = "air"})
end
end
fractal0 = { nx = 5, ny = 5, nz = 5, form = {} }
read_form(fractal0)
self.label("form count: " .. 1+#fractal0.form .. " dim " .. fractal0.nx .. " " .. fractal0.ny .. " " .. fractal0.nz)
make(fractal0,3);
build(sponge)
end
--self.remove()

View File

@ -0,0 +1,184 @@
if not number then
number = {};
number.base = 10; -- what base: 2-10
number.data = {};
number.size = -1;
function number:tostring()
local ret = ""
--say("tostring size " .. self.size)
for i = self.size,1,-1 do ret = ret .. (self.data[i] or "X").."" end
return ret
end
function number:new(data)
local o = {};_G.setmetatable(o, self); o.data = {};
for i = 1,#data do o.data[i] = data[i] end -- do copy otherwise it just saves reference
o.size = #data;
self.__index = self; return o
end
number.add = function (lhs, rhs,res)
local n1 = lhs.size;local n2 = rhs.size;local n = math.max(n1,n2);
local carry=0, sum; local base = lhs.base;
local out = false;
if not res then res = number:new({}) out = true end
local data = res.data
for i = 1,n do
sum = (lhs.data[i] or 0)+(rhs.data[i] or 0)+carry;
if carry>0 then carry = 0 end
if sum>=base then data[i]=sum-base; carry = 1 else data[i] = sum end
end
if carry>0 then data[n+1]=1 res.size = n+1 else res.size = n end
if out then return res end
end
number.__add = add;
function number:set(m)
local data = self.data;
local mdata = m.data;
for i=1,#mdata do
data[i]=mdata[i];
end
self.size = m.size;
end
-- 'slow' long multiply
number.multiply = function (lhs, rhs, res)
local n1 = lhs.size;local n2 = rhs.size;local n = n1+n2;
--say("multiply sizes " .. n1 .. "," .. n2)
local out = false;
if not res then res = number:new({}); out = true end;
res.size = n1+n2-1;
res.data = {} -- if data not cleared it will interfere with result!
local data = res.data;
local c,prod,carry = 0; local base = lhs.base;
for i=1,n1 do
carry = 0;
c = lhs.data[i] or 0;
for j = 1,n2 do -- multiply with i-th digit and add to result
prod = (data[i+j-1] or 0)+c*(rhs.data[j] or 0)+carry;
carry = math.floor(prod / base);
prod = prod % base;
data[i+j-1] = (prod)%base;
end
if carry>0 then data[i+n2] = (data[i+n2] or 0)+ carry ;if res.size<i+n2 then res.size = i+n2 end end
end
if out then return res end
end
--TO DO
number.karatsuba_multiply = function(lhs,rhs,res)
local n1 = lhs.size;local n2 = rhs.size;
local n0 = math.max(n1,n2);
if n0< 2 then -- normal multiply for "normal" sized numbers
number.multiply(lhs, rhs, res)
return
end
n0 = math.floor(n0/2);
local n = n1+n2;
local a1 = number:new({});
local tdata = a1.data; local sdata = lhs.data;
for i = 1,n0 do tdata[i] = sdata[i] or 0 end; a1.size = n0;
local a2 = number:new({}); tdata = a2.data;
for i = n0+1,n1 do tdata[i-n0] = sdata[i] or 0 end; a2.size = n1-n0;
local b1 = number:new({});
local tdata = b1.data; sdata = rhs.data;
for i = 1,n0 do tdata[i] = sdata[i] or 0 end; b1.size = n0;
local b2 = number:new({}); tdata = b2.data;
for i = n0+1,n1 do tdata[i-n0] = sdata[i] or 0 end; b2.size = n1-n0;
--say("a1 " .. a1:tostring())
--say("a2 " .. a2:tostring())
--say("b1 " .. b1:tostring())
--say("b2 " .. b2:tostring())
local A = number:new({}); number.karatsuba_multiply(a1,b1,A);
local B = number:new({}); number.karatsuba_multiply(a2,b2,B);
local C = number:new({}); number.karatsuba_multiply(a1+a2,b1+b2,C);
--== C-A-B
--TODO minus, reassemble together..
end
karatsuba_multiply_test = function()
--local in2 = number:new({2,1,1})
--local in1 = number:new({2,1,1})
local res = number:new({});
local in1 = number:new({3,1,4}); --413
local in2 = number:new({7,2,5}); -- 527
number.karatsuba_multiply(in1,in2,res)
end
karatsuba_multiply_test()
multiply_test = function()
--local in2 = number:new({2,1,1})
--local in1 = number:new({2,1,1})
local res = number:new({});
local in1 = number:new({4})
number.multiply(in1,in1,res)
say("mult check 1 " .. res:tostring())
--say("mult check 2 " .. number.multiply(in1,in2):tostring())
end
--multiply_test()
number.__mul = number.multiply;
number.power = function(n,power_) -- calculate high powers efficiently - number of steps is log_2(power)
local power = power_;
local input = number:new(n.data);
local out = number:new({});
local count = 0;
local r; local powerplan = {}; -- 0: just square a->a^2, 1 = square and multiply a-> a*a^2
while (power>0) do
r=power%2; powerplan[#powerplan+1] = r; power = (power-r)/2
end
for i = #powerplan-1,1,-1 do
number.multiply(input,input,out);
if powerplan[i] == 1 then
input,out = out, input;
number.multiply(input,n,out); count = count + 2
else count = count + 1;
end
input,out = out, input;
end
return input
end
split = function(s,k)
local ret = "";
local j=1,length; length = string.len(s)/k
for i = 1, length do
j = (i-1)*k+1;
ret = ret .. string.sub(s,j,j+k-1) .. "\n"
end
--say("j " .. j)
if j>1 then j = j+k end
ret = ret .. string.sub(s,j)
return ret
end
self.spam(1)
-- little endian ! lower bits first ..
--n = number:new({7,1,0,2}); local power = 2017;
--self.label(split(n:tostring().."^"..power .. " = " .. number.power(n,power):tostring(),100))
--2017^2017 = 3906...
end

View File

@ -0,0 +1,83 @@
if not perm2cycles then
perm2cycles = function(perm)
local n = #perm;
local i = 1; -- already reached number
local ret = {};
local visited = {};
local step = 0;
while (true) do
local cycle = {i}
local j=i;
while (true) do
step = step +1
if step > 2*n then return {} end
j=perm[j];
visited[j] = 1;
if j and j~=cycle[1] then cycle[#cycle+1]=j else break end
end
i=n+1;
for k=1,n do -- find smallest non visited yet
if not visited[k] and k<i then i = k end
end
ret[#ret+1] = cycle;
if i == n+1 then return ret end
end
end
random_permute = function(arr)
local n = #arr;
for i = n,3,-1 do
local j = math.random(i);
local tmp = arr[j]; arr[j] = arr[i]; arr[i] = tmp;
end
end
get_permutations = function(n)
free = {}; --[1] = {stack of free for 1 : head, a1,..., a_head}
isfree = {}; -- [i]=1 if item i free, 0 if not
current = 1; --{1,..., current element, ... , n}
selection = {};
local data = free[1]; for i=1,n do data[i]=i isfree[i]=1 end data[0] = n;
--1. pick free spot from free stack ( if not possible backtrack ) and move on onto next element ( if not possible stay at this one)
-- backtrack: current--
local data = free[current];
if data[0]<1 then -- backtrack
isfree[selection[current]] = 1;
current = current - 1;
if current <=0 then return end -- exhausted all options
else
local i = data[data[0]]; -- free possibility
selection[current] = i; isfree[i] = 0;
data[0]=data[0]-1; -- pop the stack
--try move forward
if current<n then
current = current+1;
-- get new free spots for new current
local data = free[current]; data = {};
for i = 1,n do if isfree[i] == 1 then data[#data+1]=i; break end end;
data[0]=#data;
if data[0] == 0 then -- nothing free, backtrack
isfree[selection[current]] = 1;
current = current - 1;
end
end
end
end
arr2string = function(arr)
return string.gsub(_G.dump(arr),"\n","")
end
local arr = {}; for i =1,10 do arr[i] =i end; random_permute(arr);
local cycles = perm2cycles(arr);
say("random permutation = " .. arr2string(arr) .. " => cycles = " .. arr2string(cycles) )
end

View File

@ -0,0 +1,65 @@
-- PINE TREE HARVEST by rnd1
if not harvest then
harvest = {};
harvest.s = -1 -- -1 idle, 0 expect tree
harvest.tree = "default:pine_tree";harvest.wood = "default:wood";harvest.sapling = "default:pine_sapling";
harvest.step = function()
local s=harvest.s;
if s == 0 then -- did we bump into tree
local node = read_node.forward();
if node == harvest.tree then
dig.forward(); move.forward(); harvest.s = 1 -- found tree, moving in
self.label("im digging up tree ")
end
elseif s == 1 then -- climbing up
dig.up(); move.up(); place.down(harvest.wood);
local node = read_node.up();
if node ~= harvest.tree then
harvest.s = 2 -- top
self.label("i reached top of tree")
end
elseif s == 2 then -- going down
local node = read_node.down();
if node == harvest.wood then
dig.down(); move.down()
self.label("im going back down")
else
pickup(8);
move.backward();place.forward(harvest.sapling);move.forward();
harvest.s = -1 -- idle
self.label("i finished cutting tree")
end
end
end
end
--harvest walk init
if not angle then
sender,mail = self.read_mail(); if sender == "rnd1" then harvest.s = tonumber(mail) or 0 end
wall = "default:cobble";
angle = 90
end
if harvest.s~=-1 then
harvest.step()
elseif harvest.s==-1 then
node = read_node.forward();
if node==harvest.tree then
harvest.s = 0;
self.label("i found tree")
else
self.label("im walking")
if not move.forward() then
if node == wall then
self.label("i hit wall")
turn.angle(angle);
if move.forward() then
move.forward();move.forward();turn.angle(angle); angle = -angle
else
turn.angle(-angle);angle = - angle
end
end
end
end
end
self.send_mail("rnd1",harvest.s) -- remember state in case of reactivation

View File

@ -0,0 +1,59 @@
N = 30; -- length of program (without ])
desired_frequencies = {
[">"] = 10,
["<"] = 10,
["-"]=10,
["+"]=20,
["."]=10,
[","]=10,
["["]=10, -- matching "]" will be inserted automatically!
}
matching_parenthesis = "]";
routine_lower = 1; routine_higher = 5; -- specify range, how many characters in routine [.....]
generate_selections = function(desired_frequency)
local sum = 0
for k,v in pairs(desired_frequency) do sum = sum + v end
local isum = 0; local count = 0; local selections = {}
for k,v in pairs(desired_frequency) do count = count +1 isum = isum + desired_frequency[k]/sum; selections[count] = {isum,k} end
return selections
end
choose = function(selections, rnd)
local low, mid, high;
low = 1; high = #selections; mid = math.floor((low+high)/2)
local step = 0;
while high-low>1 and step < 20 do
step = step + 1
if rnd <= selections[mid][1] then high = mid else low = mid end
mid = math.floor((low+high)/2)
end
return selections[mid][2]
end
generate_program = function(desired_frequencies,N, routine_lower, routine_higher)
local selections = generate_selections(desired_frequencies);
local ret = {};
local count = 0
local stack = {};
for count = 1, N do
local choice = choose(selections, math.random());
if choice == "[" then
local i = count + math.random(routine_lower,routine_higher)
if i > N then i = N end
stack[#stack+1] = i;
end
ret[count] = choice
end
for i = 1,#stack do local j = stack[i] ret[j]=ret[j]..matching_parenthesis end
return table.concat(ret)
end
say(generate_program(desired_frequencies,N, routine_lower, routine_higher))
self.remove()

View File

@ -0,0 +1,66 @@
-- BRAINFUCK interpreter by rnd, 2017
-- https://en.wikipedia.org/wiki/Brainfuck
if not ram then
prog = "+++.>++++++.<[->+<]>."
ramsize = 10
maxsteps = 100; step=0; -- for RUN state only
n = string.len(prog);ram = {};for i = 1, ramsize do ram[i]=0 end -- init ram
pointer = 1 -- ram pointer
instruction = 1 -- instruction pointer
self.spam(1)
RUNNING = 1; END = 2; RUN = 3;
state = RUNNING
get_ram = function() msg = "" for i = 1,ramsize do msg = msg .. ram[i] .. "," end return msg end
cmdset = {
[">"] = function() pointer = pointer + 1; if pointer > ramsize then pointer = 1 end end,
["<"] = function() pointer = pointer - 1; if pointer > ramsize then pointer = 1 end end,
["+"] = function() ram[pointer]=ram[pointer]+1 end,
["-"] = function() ram[pointer]=ram[pointer]-1 end,
["."] = function() say(ram[pointer]) end,
[","] = function() ram[pointer] = tonumber(read_text.forward("infotext") or "") or 0 end,
["["] = function()
if ram[pointer] == 0 then
local lvl = 0
for j = instruction, n, 1 do
if string.sub(prog,j,j) == "]" then lvl = lvl - 1 if lvl == 0 then
self.label("JMP " .. j ) instruction = j return
end end
if string.sub(prog,j,j) == "[" then lvl = lvl + 1 end
end
end
end,
["]"] = function()
if ram[pointer] ~= 0 then
local lvl = 0
for j = instruction, 1, -1 do
if string.sub(prog,j,j) == "]" then lvl = lvl - 1 end
if string.sub(prog,j,j) == "[" then lvl = lvl + 1 if lvl == 0 then
self.label("JMP " .. j ) instruction = j return
end end
end
end
end,
}
end
-- EXECUTION
if state == RUNNING then
c = string.sub(prog,instruction,instruction) or "";
if c and cmdset[c] then cmdset[c]() end
self.label("ins ptr " .. instruction .. ", ram ptr " .. pointer .. ": " .. ram[pointer] .. "\n" .. string.sub(prog, instruction).."\n"..get_ram())
instruction = instruction + 1; if instruction > n then state = END end
-- RUN THROUGH
elseif state == RUN then
while (step<maxsteps) do
step = step + 1
c = string.sub(prog,instruction,instruction) or "";
if c and cmdset[c] then cmdset[c]() end
instruction = instruction + 1; if instruction > n then self.label("ram : " .. get_ram()) step = maxsteps state = END end
end
end

View File

@ -0,0 +1,114 @@
-- demo bot
if not s then
-- move.forward();--turn.angle(180)
s=0;t=0
mag = 3;
boot = function()
self.display_text("RND technologies\n(inc) 2016\n\n\nmemchk "..(t*1024).. "kb ",16,mag)
t=t+1; if t == 8 then s = 0.5 t = 0 end
end
boot_memchk = function()
self.display_text("RND technologies\n(inc) 2016\n\n ".. (8*1024).. "kb READY",16,mag)
t=t+1; if t==3 then t=0 s = 1 end
end
os_load = function()
if t == 0 then self.display_text("============\nrndos v2.5\n============\n\nloading...\nkernel v12.2 ",12,mag) end
t=t+1; if t == 7 then s = 2 t = 0 end
end
main_menu = function()
if t==0 then self.display_text("MAIN MENU \n\n1) ip lister\n2) kick player\n3) teleport\n4) give fly\n5) kill\n6) turn off\n\n0 to return here from app",16,mag) end
text = read_text.backward();
if text and text~="" then
write_text.backward("")
if text == "1" then s = 3 t = 0
elseif text == "2" then s = 4 t = 0
elseif text == "3" then s=5 t =0
elseif text == "4" then s=6 t =0
elseif text == "5" then s=7 t =0
elseif text == "6" then self.remove()
end
end
end
ip_lister = function()
if t%5 == 0 then
players = _G.minetest.get_connected_players(); msg = "IP LISTER\n\n";
for _, player in pairs(players) do
local name = player:get_player_name(); ip = _G.minetest.get_player_ip(name) or "";
msg = msg .. name .. " " .. ip .. "\n";
end
self.display_text(msg,30,mag)
t=0
end
t=t+1
if read_text.backward() == "0" then s=2 t=0 end
end
act_on_player = function(mode)
if t==0 then
msg = get_player_list()
local txt = {[1]="KICK WHO?\n", [2] = "TELEPORT WHO HERE?\n", [3] = "GIVE FLY TO WHOM?\n", [4] = "KILL WHO?\n"}
text = txt[mode] or "";
self.display_text(text..msg,30,mag) t=1
end
text = read_text.backward();
if text then
if text=="0" then s=2 t=0 else
write_text.backward("");
if mode ==1 then
_G.minetest.kick_player(player_list[tonumber(text)] or "");
elseif mode ==2 then
player =_G.minetest.get_player_by_name(player_list[tonumber(text)] or "");
if player then player:setpos(self.spawnpos()) end
elseif mode ==3 then
player=_G.minetest.get_player_by_name(player_list[tonumber(text)] or "");
if player then player:set_physics_override({gravity=0.1}) end
elseif mode ==4 then
player=_G.minetest.get_player_by_name(player_list[tonumber(text)] or "");
if player then player:set_hp(0) end
end
end
end
end
player_list = {}
get_player_list = function()
local players = _G.minetest.get_connected_players(); local msg = ""; local i=0;
for _, player in pairs(players) do
local name = player:get_player_name();
i=i+1;msg = msg .. i ..") " .. name .. "\n";
player_list[i]=name;
end
return msg
end
end
self.label(s)
if s == 0 then
boot()
elseif s==0.5 then
boot_memchk()
elseif s==1 then
os_load()
elseif s==2 then
main_menu()
elseif s==3 then
ip_lister()
elseif s==4 then
act_on_player(1)
elseif s==5 then
act_on_player(2)
elseif s==6 then
act_on_player(3)
elseif s==7 then
act_on_player(4)
end

View File

@ -0,0 +1,271 @@
-- rnd 2017
-- call stack, subroutines, recursive subroutines, if jumps, loops, variables
if not cmd then
prog = "\n"..
"<fd M(loop) f NNOT(air)[<] G(loop)";
pause = 0
self.label(prog)
build = {};
cmd = {
["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,
["p"] = function() place.forward_down("default:dirt") end,
["P"] = function() place.forward("default:dirt") end,
["F"] = function() dig.forward() end,
["L"] = function() dig.left() end,
["R"] = function() dig.right() end,
["U"] = function() dig.up() end,
["D"] = function() dig.down() end,
["<"] = function() turn.left() end,
[">"] = function() turn.right() end,
};
build.debug =true;
build.stackdepth = 16;
build.ignored = {["]"]=true,["["]=true};
-- RESERVED: Ex(y)[A] : if x == y do A end, N(node)[A] : if read_node.forward()==node then do A end
-- G(label) .. GOTO GR(label) .. CALL SUBROUTINE +a(b),-a(b),=a(b)
set_routine = function(i)
local jr = string.find(prog,"%[",i+1)
if not jr then say("error, missing [ after position " .. i+1); self.remove() end
build.count = get_var(string.sub(prog,i+1,jr-1)) or 1
local kr = string.find(prog,"]",jr+1);
if not kr then say("error, missing ] after position " .. jr+1); self.remove() end
return jr,kr --returns routine limits jr,kr
end
error_msg = function(i)
local callstack = "";
for _,v in pairs(build.callstack) do
callstack = callstack.. call_marks[v].. ",";
end
return "ERROR: " ..string.sub(prog,i) .. "\nCALL STACK: " .. callstack
end
run_routine = function(i,jr,kr)
local count = build.count;
if count > 0 then
if i == kr then
count = count - 1 i = jr+1
end
--say(" i " .. i .. " kr " .. kr)
if count > 0 then
c=string.sub(prog,i,i)
if c == "G" then i=go_to(i); build.state = 0 else -- exit routine
if cmd[c] then cmd[c]() else
if not ignored[c] then
self.label("run routine: invalid instruction at position " .. i .. "\n" .. error_msg(i));
self.debug = false; build.state = -1
end
end
end
end
else
i=kr-- exit,jump to next instruction
build.state = 0
if build.debug then self.label("["..build.state .. "]" .. i .. "\nROUTINE EXIT") end
end
build.count = count
return i -- return next execution address
end
push_callstack = function(val) -- addresses where to continue after function ends
if #build.callstack > build.stackdepth then say("error: stack depth limit " .. build.stackdepth .. " exceeded "); self.remove() end
build.callstack[#build.callstack+1] = val;
end
pop_callstack = function()
local val = build.callstack[#build.callstack];
build.callstack[#build.callstack] = nil;
return val
end
go_to = function(i)
local j = string.find(prog,"%(",i+1); local k = string.find(prog,"%)",j+1)
local call = false;
if string.sub(prog,i+1,j-1) == "R" then call = true push_callstack(k) end -- function call, save call exit address to return here
local target = string.sub(prog,j+1,k-1);
if target == "" then -- marking end of routine
i = pop_callstack();
if build.debug then self.label("["..build.state .. "]" .. i .. "\nEXITING ROUTINE to " .. i .. ", stack level " .. #build.callstack) end
else
i = go_to_mark[target]-1;
if call == false then
if build.debug then self.label("["..build.state .. "]" .. i .. "\nGOTO " .. target .. "=".. i ) end
else
if build.debug then self.label("["..build.state .. "]" .. i .. "\nCALL SUBROUTINE " .. target .. "=".. i .. "\ncall stack = " .. string.gsub(_G.dump(build.callstack),"\n","")) end
end
end
return i;
end
-- scan for go_to markers
go_to_mark = {};
call_marks = {}; -- OPTIONAL for nicer error messages
scan_go_to = function()
local i = 0;
while ( i < string.len(prog)) do
i=i+1;
if string.sub(prog,i,i+1) == "M(" then
local j = string.find(prog,"%(",i+1)
local k = string.find(prog,"%)",j+1)
local name = string.sub(prog,j+1,k-1);
prog = string.sub(prog,1,i-1)..string.sub(prog,k+1)
go_to_mark[name] = i;
end
end
i=0 -- OPTIONAL call marks scanning
while ( i < string.len(prog)) do
i=i+1;
if string.sub(prog,i,i+2) == "GR(" then
local j = string.find(prog,"%(",i+1)
local k = string.find(prog,"%)",j+1)
local name = string.sub(prog,j+1,k-1);
call_marks[k] = name;
end
end
end
get_var = function(s)
local ns = tonumber(s);
if _G.tostring(ns)==s then return ns else return build.var[s] end
end
prog = string.gsub(prog, " ", "") -- remove all spaces
prog = string.gsub(prog, "\n", "") -- remove all newlines
scan_go_to()
build.n=string.len(prog)
build.i=1;
build.count = 1;
build.state = 0;
build.callstack = {};
build.var = {};
self.spam(1)
end
build.run = function()
local i=build.i; -- get current execution address
local jr,kr -- routine execution boundaries
local jc, kc
--i=i+1; if i>build.n then i = 1 end end
c=string.sub(prog,i,i)
if build.state == 0 then
if c == "R" then
jr,kr=set_routine(i); i = jr; -- set up execution point i=jr
build.state = 1
elseif c == "=" then
jc = string.find(prog,"%(",i+1)
kc = string.find(prog,"%)",jc+1)
local var1 = string.sub(prog,i+1,jc-1);
local var2 = get_var(string.sub(prog,jc+1,kc-1));
build.var[var1]=var2
i=kc
elseif c == "+" then
jc = string.find(prog,"%(",i+1)
kc = string.find(prog,"%)",jc+1)
local var1 = string.sub(prog,i+1,jc-1);
local var2 = get_var(string.sub(prog,jc+1,kc-1));
build.var[var1]=build.var[var1]+var2
i=kc
elseif c == "-" then
jc = string.find(prog,"%(",i+1)
kc = string.find(prog,"%)",jc+1)
local var1 = string.sub(prog,i+1,jc-1);
local var2 = get_var(string.sub(prog,jc+1,kc-1));
build.var[var1]=build.var[var1]-var2
i=kc
elseif c == "E" then
jc = string.find(prog,"%(",i+1)
kc = string.find(prog,"%)",jc+1)
local INOT = string.sub(prog,i+1,i+3) == "NOT";
local trigger; local var1; local var2;
if INOT then
var1 = get_var(string.sub(prog,i+4,jc-1));
var2 = get_var(string.sub(prog,jc+4,kc-1));
else
var1 = get_var(string.sub(prog,i+1,jc-1));
var2 = get_var(string.sub(prog,jc+1,kc-1));
end
trigger = (var1 == var2)
if (not INOT and trigger) or (INOT and not trigger)then
i=kc;
jr,kr=set_routine(i);i=jr
build.state = 1
else
kc = string.find(prog,"]",kc+1)
i = kc
end
elseif c == "N" then
jc = string.find(prog,"%(",i+1)
kc = string.find(prog,"%)",jc+1)
local node = string.sub(prog,jc+1,kc-1) or "air";
local INOT = string.sub(prog,i+1,jc-1) == "NOT";
local trigger;
trigger = read_node.forward() == node;
if (not INOT and trigger) or (INOT and not trigger)then
i=kc;
jr,kr=set_routine(i); i = jr
build.state = 1
else
kc = string.find(prog,"]",kc+1)
i = kc
end
elseif c == "G" then
i=go_to(i);
elseif c == "C" then
jc = string.find(prog,"%(",i+1)
kc = string.find(prog,"%)",jc+1)
var = string.sub(prog,jc+1,kc-1);
i = kc
self.label(var .. "=" .. get_var(var))
else
if cmd[c] then cmd[c]() else
if not build.ignored[c] then
self.label("run main: invalid instruction at position " .. i.. "\n" .. error_msg(i));
build.state = -1; self.debug = false;
end
end
end
elseif build.state == 1 then -- routine
jr = build.jr; kr = build.kr;
i=run_routine(i,jr,kr)
end
i=i+1; if i>build.n then i = 1 end
build.i = i -- update execution address
build.jr = jr;
build.kr = kr;
end
if build.debug then self.label("["..build.state .. "]" .. build.i .. "\n" .. string.sub(prog,build.i)) end
build.run()

View File

@ -0,0 +1,335 @@
if not init then
rom.best_player = nil
init = true
depth = 4; -- how many moves does random player evaluate
error_rate = 0.25; -- players make wrong decision with this probability
generation = 10; -- how many times we repeat
steps = 100; -- how many steps each generation
bestc = 0; -- how many times was new best player picked
mode = 2; -- 1, evolution!, 2 play game
-- game pay offs
rules = {
{
{2., 2.}, -- first player cooperate, second player cooperate: +2,+2
{-1, 3}, -- first player cooperate, second player cheat: -1,+3
},
{
{3,-1}, -- first player cheats, second player cooperate
{0,0}, -- first player cheats, second player cheat
}
};
copytable = function(tab)
if type(tab)~="table" then return tab end
local ret = {};
for k,v in pairs(tab) do ret[k] = copytable(v) end return
ret
end
copycat = {
rules = {
{0}, -- initial: 0 = cooperate
{0,1}, -- after one move : cooperate if other cooperated last turn, cheat if other cheated last turn
},
-- encode decision sequence in binary: 01110 = dec 8+4+2=14
memory = 1, -- how many moves back player consideres?
moves ={}, -- opponent moves
mood = 0, -- probability that player will cheat if he had intention to cooperate
moody = 0.5, -- by how much cheat/cooperate change mood
points = 0,
name = "copycat"
}
cheater = {
rules = {
{1},
},
memory = 0, -- how many moves back player consideres?
moves ={}, -- opponent moves
mood = 0,
moody = 0.5,
points = 0,
name = "cheater"
}
realplayer = {
rules = {
{0},
},
memory = 0, -- how many moves back player consideres?
moves ={}, -- opponent moves
mood = 0,
moody = 0.,
points = 0,
name = "real player",
real = true,
out = 0
}
create_random_player = function(memory)
local rules = {};
for i = 1, memory+1 do
rules[i] = {};
for j = 1,2^(i-1) do
rules[i][j] = math.random(2)-1
end
end
return {rules = rules, memory = memory, moves = {}, mood = 0, moody = math.random(), points = 0, name = "randomplayer"}
end
-- player makes next move according to his memory of moves so far
play = function(player)
if player.real then return player.out end -- real player
local moves = player.moves;
local n = #moves;
if n > player.memory then n = player.memory end -- there are many moves, examine only what we can
local rules = player.rules[n+1]
local state = bin2dec(player.moves,n); -- examine last n moves
--say("n " .. n .. " state " .. state)
return rules[state+1]
end
group_play = function(playrs) -- each randomplayer plays with every other player in lower group
local n = #playrs;
local m = 10; -- play m games with each opponent, random pair order
for i = 1,10 do
for j = 11,20 do -- i plays with j, randomized order
playrs[i].moves = {}; playrs[j].moves = {}; -- reset remembered moves before paired match!
playrs[i].mood = 0;
for k = 1,m do
if math.random(2) == 1 then
interact(playrs[i],playrs[j])
else
interact(playrs[j],playrs[i])
end
end
end
end
end
sort_players = function(pl)
table.sort(pl,
function(p1,p2) return p1.points<p2.points end
) -- sorts in ascending order of points
end
genetics = function(playrs)
local population = {}
for i = 11,20 do -- pick out only "randomplayer"s
population[#population+1] = playrs[i] --copytable()
end
sort_players(population); -- sort from worst to best
for i = 1,5 do -- replace 5 worst players with new random players
local points2 = population[#population-i+1].points; -- points of i-th best player
if points2 then
local points1 = population[i].points;
if points1<points2 or (points1==points2 and math.random(2) == 1) then --
population[i] = create_random_player(depth);
--if i == 1 then say(serialize(population[i].rules)) end
population[i].points = 0 --points2;
population[i].name = "randomplayer"
end
end
end
--say("best random points " .. population[#population].points)
for i = 11,20 do -- pick out only "randomplayer"s
playrs[i] = population[i-10]
end
end
-- paired interaction: player1 plays with player2, then player2 plays with player1
interact = function(player1,player2)
local res1 = play(player1);
local mood = player1.mood;
if not player1.real and math.random(1000)<=1000*error_rate then res1=1-res1 end
if res1 == 0 and math.random()<= mood then res1 = 1 end
local moves = player2.moves; moves[#moves+1 ] = res1;
--say("1 moves : " .. serialize(moves) .. " res1 " .. res1)
local res2 = play(player2);
mood = player2.mood;
if math.random(1000)<=1000*error_rate then res2=1-res2 end
if res2 == 0 and math.random()<= mood then res2 = 1 end
moves = player1.moves; moves[#moves+1] = res2;
--say("2 moves : " .. serialize(moves) .. " res2 " .. res2)
local res = rules[res1+1][res2+1];
player1.points = player1.points + res[1];
player2.points = player2.points + res[2];
if res2 == 0 then -- player2 cooperated, mood change
if res1==1 then
mood = mood + player2.moody;
else
mood = mood - player2.moody;
end
if mood>1 then mood = 1 elseif mood<0 then mood = 0 end
player2.mood = mood
end
if res1 == 0 then -- mood change for player1
mood = player1.mood;
if res2==1 then
mood = mood + player1.moody;
else
mood = mood - player1.moody;
end
if mood>1 then mood = 1 elseif mood<0 then mood = 0 end
player1.mood = mood
end
end
dec2bin = function(input)
local ret = {};
if input == 0 then return {0} end
while input~=0 do
local r=input%2; input = (input -r)/2
ret[#ret+1] = r;
end
local n = #ret;
local rret = {}
for i = 1, n do
rret[i]=ret[n-i+1]
end
return rret
end
bin2dec = function(bin, length) -- length= how many last elements we take
if length == 0 then return 0 end
if not length then length = #bin end
local offset = #bin - length; if offset<0 then offset = 0 end
local ret = 0;
for i = 1,#bin-offset do
ret = 2*ret + bin[i+offset]
end
return ret
end
get_results = function(players)
local ret = {} for i=1,#players do ret[i] = players[i].name .. " " .. players[i].points .. "M " .. players[i].mood .. "(" .. players[i].moody .. ")" end return table.concat(ret,"\n")
end
players = {} -- start with 5 cheaters, 5 copycats and 10 randomplayers
if mode == 1 then
for i = 1,5 do players[i] = copytable(cheater) end
for i = 1,5 do players[5+i] = copytable(copycat) end
for i = 1,10 do players[10+i] = create_random_player(depth) end -- last 10 players are random
age = 0
rom.best_player = nil;
elseif mode == 2 then
players = {copytable(realplayer), copytable( create_random_player(4) ) } ;
self.listen(1)
end
--players[20] = copytable(rom.best_player) or create_random_player(depth) -- add best player from before
--players[20].name = "randomplayer"
end
if mode == 1 then
local bestpoints = 0
for k = 1, generation do -- repeat experiment generation*
--rom.best_player = nil
for i = 1,#players do players[i].points = 0 end
for j = 1, steps do -- several steps to see who is best long term on average
--for i = 1,#players do players[i].points = 0 end
group_play(players)
end
bestpoints = 0
genetics(players) -- remove 5 worst randomplayers & replace them by new randoms
local population = {}
bestrandom = 0
for i = 11,20 do
if players[i].points >= bestrandom then bestrandom = players[i].points end
population[#population+1] = players[i]
end
--say("randomplayer population size " .. #population)
sort_players(population);
if rom.best_player then
lastbest = rom.best_player.points
if bestrandom >= lastbest then -- PICK NEW BEST
bestc = bestc+1
rom.best_player = copytable(population[#population]); -- remember best randomplayer for next experiment
end
else
rom.best_player = copytable(population[#population]); -- remember best randomplayer for next experiment
end
end
age = age + generation
--display results!
msg = ""
msg = msg .. "Planet Earth (galactical name Halfwits), age " .. age .. ", error_rate " .. error_rate .. ", steps " .. steps .. ", generations " .. generation .. ":\n"
msg = msg .."\nlast round\n"
--sort_players(players)
bestpoints = 0
for i =1,#players do
if players[i].points>bestpoints then bestpoints = players[i].points end
msg = msg .. players[i].name .. ": " .. players[i].points .. " M " .. players[i].mood .. "(" .. players[i].moody .. ")\n"
end
local rules = rom.best_player.rules;
msg = msg .. "BEST: " .. bestpoints .. "\n\n## alltime best random player no. " .. bestc .. ", points " .. rom.best_player.points .. " moody " .. rom.best_player.moody ..
"\ncurrent best random player/max current score: ".. math.floor(100*bestrandom/bestpoints*100)/100 .. "% \nrules " .. serialize(rules) .. " )\n";
local msg1 = "{" .. rules[1][1] .. "}\n"
for i = 2,#rules do
local rule = rules[i];
msg1 = msg1.. "{"
for j = 1,#rule do
local rule_string = table.concat(dec2bin(j-1),"");
rule_string = string.rep("0",i-string.len(rule_string)-1) .. rule_string;
msg1 = msg1 .. rule_string .."="..rule[j]..","
end
msg1 = msg1 .. "}\n"
end
self.label(msg .. msg1)
elseif mode == 2 then -- play vs player
speaker,msg = self.listen_msg();
if msg then
if msg == "0" or msg == "1" then
local nextmove = tonumber(msg);
if nextmove == 1 and players[1].out == 1 then
say("look buddy, we dont like cheaters around here. dont cheat twice in a row")
else
players[1].out = nextmove
interact(players[1], players[2])
say("input " .. players[1].out .. ", BOT MOVES: " .. serialize(players[1].moves) .. " BOT MOOD " .. players[2].mood .. "(" .. players[2].moody .. ") SCORE: you " .. players[1].points .. " bot " .. players[2].points)
end
end
end
end

View File

@ -0,0 +1,153 @@
-- rnd's robot swarm assembly algorithm 2017
-- https://www.youtube.com/watch?v=xK54Bu9HFRw&feature=youtu.be&list=PLC7119C2D50BEA077
-- notes:
-- 1. limitation: there must be room for diagonal move
-- this is not big limitation: assume bots are circles of radius 1, then to allow diagonal movement
-- just spread them by factor sqrt(2)~1.4 initially
-- 2. initial random placement(not part of move algorithm): due to collision some bots may occupy same place
if not pos then
n=50; m = 500;
stuck = m;
state = 0;
step = 0
pos = {}; tpos = {};
-- INIT
for i = 1, m do
--local r = i % n;local c = (i-r)/n;pos[i]={n-c,r+1}; -- regular rectangle shape
pos[i]={math.random(n),math.random(n)};
--tpos[i]={math.random(n),math.random(n)}; -- random shape
local r = i % n;local c = (i-r)/n;tpos[i]={c+1,r+1}; -- regular rectangle shape
end
doswap = true -- use closest swap or not?
-- initially swap ids so that i-th bot is closest to i-th target
permute2closest = function()
-- swap bot i with one closest to i-th target
free = {}; for i = 1, m do free[i] = i end -- list of available ids for swapping
local opos = {};
for i=1,m do opos[i] = {pos[i][1],pos[i][2]} end
closest = {};
for i = 1,m do
-- find closest bot to i-th point
local dmin = 2*n;
local jmin = -1;
local tp = tpos[i];
for j = 1,#free do
local p = opos[free[j]];
local d = math.sqrt((p[1]-tp[1])^2+(p[2]-tp[2])^2);
if d< dmin then dmin = d; jmin = j end
end
if jmin>0 then
local newj = free[jmin];
pos[i] = {opos[newj][1], opos[newj][2]}; -- reassign id
table.remove(free,jmin);
end
end
end
if doswap then
permute2closest()
else
for i=1,m do pos[i] = opos[i] end -- just copy positions
end
data = {};
for i = 1,n do data[i]={}; for j=1,n do data[i][j] = {0,0,1} end end -- 0/1 present, id, move status?
for i = 1,#pos do data[pos[i][1]][pos[i][2]] = {1,i,1} end -- 1=present,i = id, 1=move status
step_move = function()
local count = 0;
for i = 1, #pos do
local p = pos[i];
local tp = tpos[i];
local x = tp[1]-p[1];
local y = tp[2]-p[2];
local d = math.sqrt(x^2+y^2);
if d~=0 then
x=x/d;y=y/d
x=p[1]+x;y=p[2]+y;
x=math.floor(x+0.5);y=math.floor(y+0.5);
if data[x][y][1]==0 then -- target is empty
data[p[1]][p[2]][1] = 0; data[x][y][1] = 1
pos[i]={x,y}; data[x][y][2] = i; data[x][y][3] = 1;
end
else
data[p[1]][p[2]][3] = 0 -- already at position
count = count +1
end
end
return m-count -- how many missaligned
end
render = function()
out = "";
for i = 1,n do
for j= 1,n do
if data[i][j][1]==1 then
local id = data[i][j][2]; id = id % 10;
if data[i][j][3] == 0 then
out = out .. id
else
out = out .. "S" -- didnt move last step
end
else
out = out .. "_" -- empty
end
end
out = out .. "\n"
end
return out
end
s=1
self.listen(1)
end
speaker,msg = self.listen_msg()
if speaker == "rnd" then
if msg == "p" then
say("permute2closest()")
permute2closest()
end
end
if s == 1 then
step = step + 1
local c = step_move();
--state = how many times stuck count was constant; if more than 3x then perhaps it stabilized?
-- stuck = how many robots not yet in position
if c<stuck then stuck = c else state = state + 1; if state > 3 then state = 0 s = 2 end end
self.label(render().. "\nleft " .. stuck .. "="..(100*stuck/m) .. "%")
if stuck == 0 then say("*** COMPLETED! in " .. step .." steps ***") s = 3 end
elseif s == 2 then
-- do swaps of stuck ones..
for i = 1, #pos do
local p = {pos[i][1], pos[i][2]};
local tp = tpos[i];
local x = tp[1]-p[1];
local y = tp[2]-p[2];
local d = math.sqrt(x^2+y^2);
if d~=0 then
x=x/d;y=y/d
x=p[1]+x;y=p[2]+y;
x=math.floor(x+0.5);y=math.floor(y+0.5); -- see whats going on in attempted move direction
if data[x][y][1]==1 then -- there is obstruction, do id swap
local x1,y1;
x1 = x; y1 = y;
local idb = data[x][y][2]; -- blocker id, stuck robot id is i
pos[i]={x,y}; -- new position for id-i is position of blocker
pos[idb] = {p[1],p[2]}; -- new position for blocker is position of stuck robot
-- reset stuck status
data[x][y][3]=1;data[p[1]][y][p[2]]=1;
end
end
end
s=1
end
--TO DO: if robots stuck do permute2closest again

View File

@ -0,0 +1,132 @@
-- rnd 2017
if not data then
m=50;n=50; minescount = m*n/14;
t0 = _G.minetest.get_gametime();
rom.data = {}; rom.rooms = {} -- so we dont make new tables everytime
data = rom.data; spawnpos = self.spawnpos();
rooms = rom.rooms;
for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end
get_mine_count = function(i,j)
if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0
for k = -1,1 do for l = -1,1 do
if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end
end end
return count
end
-- generate level data
for i = 1,m do rooms[i]={}; for j = 1,n do
if get_mine_count(i,j) > 0 or (data[i] and data[i][j] == 1) then
rooms[i][j] = 1
else
rooms[i][j] = 0
end
end end
-- find passages
for i = 2,m-1 do for j = 2,n-1 do
if rooms[i][j] == 0 then
local A11 = rooms[i-1][j-1]; local A21 = rooms[i][j-1];local A31 = rooms[i+1][j-1];
local A12 = rooms[i-1][j]; local A32 = rooms[i+1][j];
local A13 = rooms[i-1][j+1]; local A23 = rooms[i][j+1];local A33 = rooms[i+1][j+1];
if (A12~=1 and A32~=1 and A21 == 1 and A23 == 1) or
(A12==1 and A32==1 and A21 ~= 1 and A23 ~= 1)
then
rooms[i][j] = 2; -- passage
end
end
end end
read_room = function(i,j)
if i<1 or i > m then return nil end
if j<1 or j > n then return nil end
return rooms[i][j]
end
render_rooms = function()
for i = 1,m do for j = 1,n do
local tile = rooms[i][j];
if tile == 0 then
_G.minetest.swap_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}, {name = "air"})
_G.minetest.swap_node({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+j}, {name = "air"})
elseif tile == 1 then
_G.minetest.swap_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}, {name = "basic_robot:buttonFFFFFF"})
_G.minetest.swap_node({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+j}, {name = "basic_robot:buttonFFFFFF"})
elseif tile == 2 then -- passage, insert 1 door in it
--determine direction
local dir = {0,0}
if read_room(i+1,j) == 2 then dir = {1,0}
elseif read_room(i-1,j) == 2 then dir = {-1,0}
elseif read_room(i,j+1) == 2 then dir = {0,1}
elseif read_room(i,j-1) == 2 then dir = {0,-1}
elseif read_room(i-1,j) ~= 0 or read_room(i+1,j) ~= 0 then dir = {0,1}
else dir = {1,0}
end
local k1 = 0; local k2 = 0;
for k = 1, 10 do
if read_room(i+dir[1]*k,j+dir[2]*k)~= 2 then k1 = k-1 break
else
if rooms[i+dir[1]*k] then rooms[i+dir[1]*k][j+dir[2]*k] = 0 end
_G.minetest.swap_node({x=spawnpos.x+i+dir[1]*k,y=spawnpos.y,z=spawnpos.z+j+dir[2]*k}, {name = "air"})
end
end
for k = 1, 10 do
if read_room(i-dir[1]*k,j-dir[2]*k)~= 2 then k2 = -(k-1) break
else
if rooms[i+dir[1]*k] then rooms[i+dir[1]*k][j+dir[2]*k] = 0 end
_G.minetest.swap_node({x=spawnpos.x+i-dir[1]*k,y=spawnpos.y,z=spawnpos.z+j-dir[2]*k}, {name = "air"})
end
end
local k = math.floor((k1+k2)/2);
--place door
local param = 1
if dir[1]~=0 then param = 2 end
_G.minetest.swap_node({x=spawnpos.x+i+dir[1]*k,y=spawnpos.y+1,z=spawnpos.z+j+dir[2]*k}, {name = "air"})
if param == 1 then
_G.minetest.swap_node({x=spawnpos.x+i+dir[1]*k,y=spawnpos.y,z=spawnpos.z+j+dir[2]*k}, {name = "doors:door_wood_a", param2 = 2})
else
_G.minetest.swap_node({x=spawnpos.x+i+dir[1]*k,y=spawnpos.y,z=spawnpos.z+j+dir[2]*k}, {name = "doors:door_wood_a", param2 = 1})
end
elseif tile == 3 then
_G.minetest.swap_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}, {name = "default:stonebrick"})
end
end end
end
render_rooms()
fill_room = function(x,y, roomIdx) -- room index: 1,2,3,... will be written as -1,-2,.. in rooms
local tile = rooms[i][j];
if tile ~= 0 then return false end
rooms[i][j] = -roomIdx;
local stk = {{i,j}}; -- stack to place border tiles
local tmpstk = {}; -- temporary stack
local free = true; -- are there any free room tiles
while free do
-- loop all stack tiles
for i=1,#stk do
local p = stk[i];
tile = rooms[p[1]][p[2]];
end
end
end
end
self.remove()

View File

@ -0,0 +1,70 @@
-- rnd 2017
if not data then
data = {FUEL = 1.8,TV=0,T=0,P=0,E=0;}
generate_nuclear_power = function(CONTROL,COOLING)
if COOLING>1 then COOLING = 1 elseif COOLING<0 then COOLING = 0 end
if CONTROL>1 then CONTROL = 1 elseif CONTROL<0 then CONTROL = 0 end
--data = ...
local FUEL = data.FUEL;
local TV = data.TV;
local T = data.T;
local P = data.P;
local E = data.E;
-- reactor specifications
local TVmax = 10000;
local FUELC = 2; -- critical mass for fuel
local DECAYRATE = 1-0.01; -- how much fuel decays per time step
local COOLINGCOEF = 1; -- how efficient is cooling per 1 unit of power (how many degrees are cooled)
local PCOEF = 1; -- how efficiently temperature is converted to power
local TGV = FUEL/(1-(FUEL/FUELC)^2);
if TGV>TVmax then TGV = TVmax end; if FUEL>FUELC then TGV = TVmax end -- basic temperature generation speed generated in core
TV = TV + TGV* CONTROL - P*COOLING*COOLINGCOEF; -- temperature change speed
T = T + TV ;
P = 0.5*P + T*PCOEF; P = P - P*COOLING -- produced power
FUEL = FUEL*DECAYRATE;
if P<0 then P = 0 end if T<0 then T = 0 end E=E+P;
data.FUEL = FUEL;
data.T = T;
data.TV = TV;
data.P = P;
data.E = E
return E, P, T, FUEL, TV
end
render = function(data) -- data should be normalized [0,1]
local tname = "pix.png";
local obj = _G.basic_robot.data[self.name()].obj;
local n = 150; local m = n;
local length = #data; if length == 0 then return end
local hsize = 1; local wsize=hsize;
local tex = "[combine:"..(wsize*m).."x"..(hsize*n);
for i = 1,length do
j=math.floor((1-data[i])*m);
local ix = math.floor((i/length)*n)
tex = tex .. ":"..(ix*wsize).."," .. (j*hsize) .. "="..tname
end
obj:set_properties({visual = "sprite",textures = {tex}})
end
tdata = {};
COOLING = 0.03
end
-- generate_nuclear_power(CONTROL, COOLING)
-- CONTROL = 0.20; -- control rods; 1 = no control, between 0 and 1
-- COOLING = 0.03; -- how much power assigned for cooling, in ratio of output power P; between 0 and 1
E,P,T,FUEL,TV = generate_nuclear_power(0.2,COOLING)
-- cooling strategy
if TV < 0 then COOLING = 0.0 elseif T>90 then COOLING = 0.03 else COOLING = 0 end
tdata[#tdata+1]=math.min(T/100,1);
render(tdata)
self.label( "T " .. T .. "\nTV " .. TV .. "\nP ".. P .. "\nFUEL " .. FUEL .. "\nTOTAL ENERGY PRODUCED " .. E )

View File

@ -0,0 +1,448 @@
-- REDSTONE EMULATOR & EDITOR
--v 10/14a
if not init then
local players = find_player(5);
if not players then
name = "";
else
name = players[1]
player_ = puzzle.get_player(name)
local inv = player_:get_inventory();
inv:set_stack("main", 8, puzzle.ItemStack("basic_robot:control 1 0 \"@\"")) -- add controller in players inventory
--add items for building
inv:set_stack("main", 1, puzzle.ItemStack("default:pick_diamond"))
inv:set_stack("main", 2, puzzle.ItemStack("basic_robot:button_273 999")) -- switch 9 = 273/274
inv:set_stack("main", 3, puzzle.ItemStack("basic_robot:button_275 999")) -- button 7 = 275/276
inv:set_stack("main", 4, puzzle.ItemStack("basic_robot:button_277 999")) -- equalizer 61 = 277
inv:set_stack("main", 5, puzzle.ItemStack("basic_robot:button_278 999")) -- setter 15 = 278
inv:set_stack("main", 6, puzzle.ItemStack("basic_robot:button_279 999")) -- piston 171 = 279
inv:set_stack("main", 7, puzzle.ItemStack("basic_robot:button_282 999")) -- delayer 232 = 282
inv:set_stack("main", 9, puzzle.ItemStack("basic_robot:button_281 999")) -- NOT 33 = 281
inv:set_stack("main", 10, puzzle.ItemStack("basic_robot:button_280 999")) -- diode 175 = 280
inv:set_stack("main", 11, puzzle.ItemStack("basic_robot:button_283 999")) -- platform 22 = 283
local round = math.floor; protector_position = function(pos) local r = 32;local ry = 2*r; return {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry,z=round(pos.z/r+0.5)*r}; end
local spawnblock = protector_position(self.spawnpos())
local meta = puzzle.get_meta(spawnblock);
meta:set_string("shares", name) -- add player to protection!
puzzle.chat_send_player(name,colorize("yellow","#EDITOR: if you need any blocks get them by using 'give me' in craft guide. you can now use controller to make links from pointed at blocks. In addition hold SHIFT to display infos. Reset block links by selecting block 2x"))
end
init = true
self.spam(1)
self.label(colorize("orange","REDSTONE EMULATOR/EDITOR"))
-- 1. EMULATOR CODE
TTL = 16 -- signal propagates so many steps before dissipate
--self.label(colorize("red","REDSTONE")..colorize("yellow","EMULATOR"))
-- DEFINITIONS OF BLOCKS THAT CAN BE ACTIVATED
toggle_button_action = function(mode,pos,ttl) -- SIMPLE TOGGLE BUTTONS - SWITCH
if not ttl or ttl <=0 then return end
if mode == 1 then -- turn on
puzzle.set_node(pos,{name = "basic_robot:button_274"})
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
for i = 1,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
else -- turn off
puzzle.set_node(pos,{name = "basic_robot:button_273"})
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
for i = 1,n do activate(0,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
end
end
button_action = function(mode,pos,ttl) -- SIMPLE ON BUTTON, TOGGLES BACK OFF after 1s
if not ttl or ttl <=0 then return end
if mode == 0 then return end
puzzle.set_node(pos,{name = "basic_robot:button_276"})
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
minetest.after(1, function()
puzzle.set_node(pos,{name = "basic_robot:button_275"})
for i = 1,n do activate(0,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
end)
for i = 1,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
end
equalizer_action = function(mode,pos,ttl) -- CHECK NODES AT TARGET1,TARGET2. IF EQUAL ACTIVATE TARGET3,TARGET4,...
if not ttl or ttl <=0 then return end
if mode == 0 then return end
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
local node1 = puzzle.get_node({x=meta:get_int("x1")+pos.x,y=meta:get_int("y1")+pos.y,z=meta:get_int("z1")+pos.z}).name
local node2 = puzzle.get_node({x=meta:get_int("x2")+pos.x,y=meta:get_int("y2")+pos.y,z=meta:get_int("z2")+pos.z}).name
if node1==node2 then
for i = 3,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
else
for i = 3,n do activate(0,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
end
end
delayer_action = function(mode,pos,ttl) -- DELAY FORWARD SIGNAL, delay determined by distance of target1 from delayer ( in seconds)
if not ttl or ttl <=0 then return end
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
local pos1 = {x=meta:get_int("x1"),y=meta:get_int("y1"),z=meta:get_int("z1")}
local delay = math.sqrt(pos1.x^2+pos1.y^2+pos1.z^2);
if delay > 0 then
minetest.after(delay, function()
if mode == 1 then
for i = 2,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
else
for i = 2,n do activate(0,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
end
end)
end
end
diode_action = function(mode,pos,ttl) -- ONLY pass through ON signal
if not ttl or ttl <=0 then return end
if mode ~= 1 then return end
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
for i = 1,n do activate(1,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
end
not_action = function(mode,pos,ttl) -- negate signal: 0 <-> 1
if not ttl or ttl <=0 then return end
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
for i = 1,n do activate(1-mode,{x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},ttl) end
end
setter_action = function(mode,pos,ttl) -- SETS NODES IN TARGET AREA TO PRESELECTED NODE
if not ttl or ttl <=0 then return end
if mode == 0 then return end
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
if n ~= 3 then say("#setter: error, needs to be set with 3 links"); return end
local node1 = puzzle.get_node({x=meta:get_int("x1")+pos.x,y=meta:get_int("y1")+pos.y,z=meta:get_int("z1")+pos.z})
local pos1 = {x=meta:get_int("x2")+pos.x,y=meta:get_int("y2")+pos.y,z=meta:get_int("z2")+pos.z}
local pos2 = {x=meta:get_int("x3")+pos.x,y=meta:get_int("y3")+pos.y,z=meta:get_int("z3")+pos.z}
if pos1.x>pos2.x then pos1.x,pos2.x = pos2.x,pos1.x end
if pos1.y>pos2.y then pos1.y,pos2.y = pos2.y,pos1.y end
if pos1.z>pos2.z then pos1.z,pos2.z = pos2.z,pos1.z end
local size = (pos2.x-pos1.x+1)*(pos2.y-pos1.y+1)*(pos2.z-pos1.z+1)
if size > 27 then say("#setter: target area too large, more than 27 blocks!"); return end
for x = pos1.x,pos2.x do
for y = pos1.y,pos2.y do
for z = pos1.z,pos2.z do
puzzle.set_node({x=x,y=y,z=z},node1)
end
end
end
end
local piston_displaceable_nodes = {["air"] = 1,["default:water_flowing"] = 1}
piston_action = function(mode,pos,ttl) -- PUSH NODE AT TARGET1 AWAY FROM PISTON
if not ttl or ttl <=0 then return end
--if mode == 0 then return end
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
if n < 1 or n>2 then say("#piston: error, needs to be set with at least link and most two"); return end
local pos1 = {x=meta:get_int("x1")+pos.x,y=meta:get_int("y1")+pos.y,z=meta:get_int("z1")+pos.z}
-- determine direction
local dir = {x=pos1.x-pos.x, y= pos1.y-pos.y, z= pos1.z-pos.z};
local dirabs = {x=math.abs(dir.x), y= math.abs(dir.y), z= math.abs(dir.z)};
local dirmax = math.max(dirabs.x,dirabs.y,dirabs.z);
if dirabs.x == dirmax then dir = { x = dir.x>0 and 1 or -1, y = 0,z = 0 }
elseif dirabs.y == dirmax then dir = { x = 0, y = dir.y>0 and 1 or -1, z=0}
else dir = {x = 0, y = 0, z = dir.z>0 and 1 or -1}
end
local pos2 = {x=pos1.x+dir.x,y=pos1.y+dir.y,z=pos1.z+dir.z};
if mode == 0 then pos1,pos2 = pos2,pos1 end
local node1 = puzzle.get_node(pos1)
if node1.name == "air" then return end
if piston_displaceable_nodes[puzzle.get_node(pos2).name] then
puzzle.set_node(pos2, node1)
puzzle.set_node(pos1, {name = "air"})
minetest.check_for_falling(pos2)
self.sound("doors_door_open",1,pos)
end
end
platform_action = function(mode,pos,ttl) -- SPAWN MOVING PLATFORM
if mode~=1 then return end
local meta = puzzle.get_meta(pos); local n = meta:get_int("n");
if n ~= 2 then say("#platform: error, needs to be set with 2 targets"); return end
local pos1 = {x=meta:get_int("x1")+pos.x,y=meta:get_int("y1")+pos.y,z=meta:get_int("z1")+pos.z}
local pos2 = {x=meta:get_int("x2")+pos.x,y=meta:get_int("y2")+pos.y,z=meta:get_int("z2")+pos.z}
-- determine direction
local dir = {x=pos2.x-pos1.x, y= pos2.y-pos1.y, z= pos2.z-pos1.z};
local obj = minetest.add_entity(pos1, "basic_robot:projectile");
if not obj then return end
obj:setvelocity(dir);
--obj:setacceleration({x=0,y=-gravity,z=0});
local luaent = obj:get_luaentity();
luaent.name = name;
luaent.spawnpos = pos1;
local nodename = puzzle.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name;
local tiles = minetest.registered_nodes[nodename].tiles; tiles = tiles or {};
local texture = tiles[1] or "default_stone";
obj:set_properties({visual = "cube",textures = {texture,texture,texture,texture,texture,texture},visual_size = {x=1,y=1},
collisionbox={-0.5,-0.5,-0.5,0.5,0.5,0.5}})
end
-- HOW TO ACTIVATE TARGET ELEMENT - adds mesecons/basic machines compatibility
activate = function(mode, pos, ttl)
if not ttl or ttl <=0 then return end
local nodename = puzzle.get_node(pos).name;
local active_element = active_elements[nodename];
if active_element then
active_element(mode,pos,ttl-1)
else -- try mesecons activate
local nodename = puzzle.get_node(pos).name
local table = minetest.registered_nodes[nodename];
if table and table.mesecons then else return end
local effector=table.mesecons.effector;
if mode == 1 then
if effector.action_on then
effector.action_on(pos,node,ttl)
end
else
if effector.action_off then
effector.action_off(pos,node,ttl)
end
end
end
end
-- THESE REACT WHEN PUNCHED
interactive_elements = {
[275] = {button_action,1}, -- BUTTON, 1 means it activates(ON) on punch
[273] = {toggle_button_action,1}, -- TOGGLE BUTTON_OFF
[274] = {toggle_button_action,0} -- TOGGLE BUTTON_ON, 0 means it deactivates
--TODO
-- inventory checker(taker) : basic_robot:button_63 -> if player has stuff it will activate items after punch
-- inventory give: give item that is at position1 and activate selected machine at position2
}
-- THESE CAN BE ACTIVATED WITH SIGNAL
active_elements = {
["basic_robot:button_275"] = button_action, -- BUTTON, what action to do on activate
["basic_robot:button_273"] = toggle_button_action, -- TOGGLE BUTTON_OFF
["basic_robot:button_274"] = toggle_button_action, -- TOGGLE BUTTON_ON
["basic_robot:button_278"] = setter_action, -- SETTER
["basic_robot:button_277"] = equalizer_action, -- EQUALIZER
["basic_robot:button_279"] = piston_action, -- PISTON
["basic_robot:button_283"] = platform_action, -- PLATFORM
["basic_robot:button_282"] = delayer_action, -- DELAYER
["basic_robot:button_280"] = diode_action, -- DIODE
["basic_robot:button_281"] = not_action, -- NOT
}
-- EDITOR CODE --
edit = {};
edit.state = 1; -- tool state
edit.source = {}; edit.sourcenode = ""; -- selected source
-- blocks that can be activated
edit.active_elements = {
["basic_robot:button_275"] = "button: now select one or more targets", -- button
["basic_robot:button_273"] = "switch: now select one or more targets", -- switch OFF
["basic_robot:button_274"] = "switch: now select one or more targets", -- switch ON
["basic_robot:button_278"] = "setter: set block at target region {target2,target3} to block at target1", -- equalizer
["basic_robot:button_277"] = "equalizer: target1 and target2 are for comparison, other targets are activated", -- equalizer
["basic_robot:button_279"] = "piston: push block at target1 in direction away from piston", -- equalizer
["basic_robot:button_283"] = "platform: select target1 to set origin, target2 for direction", -- PLATFORM
["basic_robot:button_282"] = "delayer: distance from delayer to target1 determines delay", -- delayer
["basic_robot:button_280"] = "diode: only pass through ON signal", -- DIODE
["basic_robot:button_281"] = "NOT gate: negates the signal", -- NOT
}
linker_use = function(pos)
if not pos then return end
--say(serialize(player_:get_player_control()))
if edit.state < 0 then -- link edit mode!
local meta = puzzle.get_meta(edit.source);
local i = -edit.state;
meta:set_int("x" ..i, pos.x-edit.source.x); meta:set_int("y" ..i, pos.y-edit.source.y); meta:set_int("z" ..i, pos.z-edit.source.z)
puzzle.chat_send_player(name, colorize("red", "EDIT ".. " target " .. i .. " changed"))
edit.state = 1
goto display_particle
end
if player_:get_player_control().sneak then -- SHOW LINKS
local meta = puzzle.get_meta(pos);
local n = meta:get_int("n");
local nodename = puzzle.get_node(pos).name;
local active_element = edit.active_elements[nodename]
if active_element and edit.source.x == pos.x and edit.source.y == pos.y and edit.source.z == pos.z then -- gui with more info
local form = "size[4,"..(0.75*n).."] label[0,-0.25; "..active_element .."]" ;
for i = 1,n do -- add targets as lines
form = form ..
"button[0,".. (0.75*i-0.5) .. ";1,1;".."S"..i..";" .. "show " .. i .. "]"..
"button_exit[1,".. (0.75*i-0.5) .. ";1,1;".."E"..i..";" .. "edit " .. "]" ..
"button_exit[2,".. (0.75*i-0.5) .. ";1,1;".."D"..i..";" .. "delete " .. "]"..
"label[3,".. (0.75*i-0.25) .. "; " .. meta:get_int("x"..i) .. " " .. meta:get_int("y"..i) .. " " .. meta:get_int("z"..i) .."]"
end
self.show_form(name,form);
edit.state = 3;
return
end
edit.source = {x=pos.x,y=pos.y, z=pos.z};
edit.state = 1
if not active_element then return end
local i = string.find(active_element,":");
if not i then return end
puzzle.chat_send_player(name,colorize("red","#INFO ".. string.sub(active_element,1,i-1) ..":") .." has " .. n .. " targets. Select again for more info.")
meta:set_string("infotext",string.sub(active_element,1,i-1)) -- write name of element on it!
for i = 1, n do
minetest.add_particle(
{
pos = {x=meta:get_int("x"..i)+pos.x,y=meta:get_int("y"..i)+pos.y,z=meta:get_int("z"..i)+pos.z},
expirationtime = 5,
velocity = {x=0, y=0,z=0},
size = 18,
texture = "010.png",
acceleration = {x=0,y=0,z=0},
collisiondetection = true,
collision_removal = true,
}
)
end
return
end
if edit.state == 1 then -- SET SOURCE
local nodename = puzzle.get_node(pos).name;
local active_element = edit.active_elements[nodename]
if not active_element then puzzle.chat_send_player(name,colorize("red","#ERROR linker:").. " source must be valid element like switch"); return end
edit.source = {x=pos.x,y=pos.y, z=pos.z};
sourcenode = nodename;
puzzle.chat_send_player(name, colorize("yellow","SETUP " ..edit.state .. ": ").. active_element)
edit.state = 2
else -- SET TARGET
local meta = puzzle.get_meta(edit.source);
local n = meta:get_int("n");
if edit.state == 2 and pos.x == edit.source.x and pos.y == edit.source.y and pos.z == edit.source.z then -- RESET LINK FOR SOURCE
local meta = puzzle.get_meta(pos);meta:set_int("n",0) -- reset links
puzzle.chat_send_player(name, colorize("red", "SETUP " .. edit.state .. ":") .. " resetted links for selected source.")
edit.state = 1;return
else
n=n+1;
meta:set_int("x"..n, pos.x-edit.source.x);meta:set_int("y"..n, pos.y-edit.source.y);meta:set_int("z"..n, pos.z-edit.source.z) -- relative to source!
meta:set_int("n",n)
puzzle.chat_send_player(name, colorize("red", "SETUP "..edit.state .. ":") .. " added target #" .. n)
edit.state = 1
end
end
-- display
::display_particle::
minetest.add_particle(
{
pos = pos,
expirationtime = 5,
velocity = {x=0, y=0,z=0},
size = 18,
texture = "009.png",
acceleration = {x=0,y=0,z=0},
collisiondetection = true,
collision_removal = true,
}
)
end
tools = {
["basic_robot:control"] = linker_use
}
------ END OF EDIT PROGRAM
end
event = keyboard.get() -- handle keyboard
if event then
if event.type == 0 then -- EDITING
if event.puncher == name then -- players in protection can edit -- not minetest.is_protected({x=event.x,y=event.y,z=event.z},event.puncher)
local wield_item = player_:get_wielded_item():get_name()
local tool = tools[wield_item]
if tool then tool({x=event.x,y=event.y,z=event.z}) end
end
else -- EMULATOR
local typ = event.type;
local interactive_element = interactive_elements[typ]
if interactive_element then
interactive_element[1](interactive_element[2],{x=event.x,y=event.y,z=event.z},TTL)
self.sound("doors_glass_door_open",1,{x=event.x,y=event.y,z=event.z})
end
end
end
sender,fields = self.read_form() -- handle gui for editing
if sender then
edit.state = 1
for k,_ in pairs(fields) do
local c = string.sub(k,1,1);
local i = tonumber(string.sub(k,2)) or 1;
if c == "S" then
local meta = puzzle.get_meta(edit.source);
minetest.add_particle(
{
pos = {x=meta:get_int("x"..i)+edit.source.x,y=meta:get_int("y"..i)+edit.source.y,z=meta:get_int("z"..i)+edit.source.z},
expirationtime = 5,
velocity = {x=0, y=0,z=0},
size = 18,
texture = "010.png",
acceleration = {x=0,y=0,z=0},
collisiondetection = true,
collision_removal = true,
}
)
elseif c == "E" then
edit.state = -i;
puzzle.chat_send_player(name, colorize("yellow", "#EDIT: select target " .. i));
elseif c == "D" then
local meta = puzzle.get_meta(edit.source);
local n = meta:get_int("n")
if n > 0 then
for j = i,n-1 do
meta:set_int("x"..j, meta:get_int("x"..(j+1)))
meta:set_int("y"..j, meta:get_int("y"..(j+1)))
meta:set_int("z"..j, meta:get_int("z"..(j+1)))
end
meta:set_int("n",n-1)
end
puzzle.chat_send_player(name, colorize("red", "#EDIT: target " .. i .. " deleted"));
end
--say(serialize(fields))
end
end

View File

@ -0,0 +1,266 @@
-- cheat trust game by rnd, made in 60 minutes
-- http://ncase.me/trust/
--[[
TO DO:
hierarchies, they determine who plays with who (boss plays only with his direct underlings)
fakers: they give fake +points
--]]
if not init then
init = true
if not find_player(6) then error("#TRUST GAME: no players near") end
rules = {
{
{2., 2.}, -- first player cooperate, second player cooperate: +2,+2
{-1, 3}, -- first player cooperate, second player cheat: -1,+3
},
{
{3,-1}, -- first player cheats, second player cooperate
{0,0}, -- first player cheats, second player cheat
}
};
error_rate = 0.0; -- 10% probability we take wrong decision
grudger =
{
name = "grudger",
opponent = {}, -- list of opponent moves from previous games,
state = 1, -- internal state, for grudger it means how he plays next move
reset = function(self)
self.state = 1; self.opponent = {};
end,
game = function(self) -- how will we play next move
if self.state == 1 then
local opp = self.opponent;
if #opp>0 and opp[#opp] == 2 then self.state = 2 end -- you cheat me once and we are done, pardner.
end
return self.state
end,
err = error_rate, -- probability we make different decision
}
cheater =
{
name = "cheater",
opponent = {}, -- list of opponent moves from previous games,
reset = function(self)
self.opponent = {};
end,
game = function(self)
return 2
end,
err = error_rate, -- probability we make different decision
}
cooperator =
{
name = "cooperator",
opponent = {},
reset = function(self)
self.opponent = {};
end,
game = function(self)
return 1
end,
err = error_rate, -- probability we make different decision
}
copycat =
{
name = "copycat",
opponent = {},
reset = function(self)
self.opponent = {};
end,
game = function(self)
local opp = self.opponent;
if #opp>0 then return opp[#opp] else return 1 end -- i do to you what you did to me last move
end,
err = error_rate, -- probability we make different decision
}
fcopycat =
{
name = "forgiving copycat",
opponent = {},
reset = function(self)
self.opponent = {}; self.state = 0; self.cheat = 0;
end,
state = 0,
cheat = 0,
game = function(self)
local opp = self.opponent;
if #opp>0 then
if opp[#opp] == 2 then -- you cheat me
if self.state == 1 then self.cheat = self.cheat+ 1 else self.state = 1 end -- cheat in a row
else
self.state = 0
self.cheat = 0
end
if self.cheat >= 1 then -- fk you
return 2
else -- you cheated me less than 2x, its still cool
return 1
end
else -- first time
return 1
end
end,
err = error_rate, -- probability we make different decision
}
detective =
{
name = "detective",
opponent = {},
moves = {1,2,1,1}, -- starting 4 moves
step = 0, -- what move we played so far
state = 0,
reset = function(self)
self.state = 0; self.step = 0; self.opponent = {};
end,
game = function(self) -- how will we play next move
local st = self.step+1;
self.step = st;
local opp = self.opponent;
if st < 5 then
if self.state == 0 and opp[#opp] == 2 then self.state = 1 end -- i caught you cheating!
return self.moves[st]
end
if self.state == 0 then -- exploiter
return 2
else -- copycat
if #opp>0 then return opp[#opp] end -- copycat
end
return self.state
end,
err = error_rate, -- probability we make different decision
}
-- internal functions
Player = {}
function Player:new (o)
ret = {}; _G.setmetatable(ret, self); self.__index = self
for k,v in pairs(o) do ret[k] = v end
ret.points = 0
return ret
end
gamestep = function(player1,player2)
local res1 = player1:game(); if math.random(1000)<=1000*player1.err then res1 = 3-res1 end
local opponent = player2.opponent;
opponent[#opponent+1] = res1; -- player2 remembers player1 move
local res2 = player2:game(); if math.random(1000)<=1000*player2.err then res2 = 3-res2 end
opponent = player1.opponent;
opponent[#opponent+1] = res2; -- player1 remembers player2 move
local res = rules[res1][res2];
player1.points = player1.points + res[1];
player2.points = player2.points + res[2];
return res1,res2 -- return what players did
end
paired_match = function(player1,player2, rounds)
player1:reset();player2:reset()
for i = 1, rounds do
gamestep(player1,player2)
end
end
sort_players = function(players)
table.sort(players,
function(p1,p2) return p1.points<p2.points end
) -- sorts in ascending order of points
end
group_match = function(players,elimination) -- each player plays once with every other player
local n = #players;
local m = 10; -- play m games with each opponent
for i = 2,n do
for j = 1,i-1 do
if math.random(2) == 1 then
paired_match(players[i],players[j],m)
else
paired_match(players[j],players[i],m)
end
end
end
if elimination then
sort_players(players)
for i = 1,5 do -- replace 5 worse players with clones of 5 best players
local points2 = players[#players-i+1].points;
if points2 then
local points1 = players[i].points;
if points1<points2 or (points1==points2 and math.random(2) == 1) then
players[i] = Player:new( players[#players-i+1] );
players[i].points = points2;
end
end
end
end
end
get_results = function(players)
local msg = colorize("red","player results\n")
for j = 1, #players do -- display final results
msg = msg .. j .. ". " .. players[j].name .. ": points " .. players[j].points .. "\n"
end
return msg
end
-- SIMULATION START
self.spam(1)
_G.math.randomseed(os.time())
players = {Player:new(grudger), Player:new(cheater), Player:new(cooperator), Player:new(copycat),Player:new(detective)} --,Player:new(fcopycat)}
M = 10000; -- do 1000 matches, make average later
for i = 1, M do
group_match(players) -- SIMPLE GROUP MATCH, everyone play 1x vs everyone else (random player ordering in single match)
end
for i =1,#players do players[i].points = players[i].points/M end
-- players = {}
-- for i = 1, 5 do players[#players+1 ] = Player:new(grudger) end
-- for i = 1, 5 do players[#players+1 ] = Player:new(cheater) end
-- for i = 1, 5 do players[#players+1 ] = Player:new(cooperator) end
-- for i = 1, 5 do players[#players+1 ] = Player:new(copycat) end
-- for i = 1, 5 do players[#players+1 ] = Player:new(detective) end
-- group_match(players)
-- for i = 1, 10 do-- play 10 matches with elimination
-- group_match(players,true)
-- end
sort_players(players)
self.label("10000 rounds + averaged, error rate = " .. error_rate .."\n" .. get_results(players) .. "comment: under 6.2% error copycats more succesful, but above 6.2% cheaters. at 50% error everyone same")
players = nil; -- clear up
--STEP BY STEP DUAL VS 2 PLAYERS
-- players = {Player:new(grudger),Player:new(detective)};
-- step = 0;
-- say("#game start")
-- for i = 1, 10 do
-- step = step +1
-- local res1,res2;
-- res1,res2 = gamestep(players[1],players[2])
-- say("step " .. step .. ": " .. players[1].name .. " " .. res1 .. " -> " .. players[1].points .. " VS " .. players[2].name .. " " .. res2 .. " -> " .. players[2].points);
-- end
end

View File

@ -0,0 +1,28 @@
if not cmd then
cmd = {
["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,
["a"] = function() activate.forward(1) end,
["<"] = function() turn.left() end,
[">"] = function() turn.right() end,
}
i=0;
prog = read_text.right(); s=0
prog = string.gsub(prog,"%s","");
--say(prog)
self.label("RUNNING PROGRAM: " .. prog);n=string.len(prog);
if string.sub(prog,1,1) == " " then self.label("WRITE A PROGRAM FIRST!") s=1 end
end
if s == 0 then
i=i+1; if i > n then self.label("PROGRAM ENDED");s=1 end;
if s == 0 then
c=string.sub(prog,i,i)
if cmd[c] then cmd[c]() else self.label("INVALID PROGRAM INSTRUCTION : " .. c) s=1 end
end
end

62
scripts/spawn_quiz.lua Normal file
View File

@ -0,0 +1,62 @@
if not s then
s=0
t=0
option = {"A","B","C","D","E"}
generate_question = function()
local a = math.random(10)+0;
local b = math.random(10)+0;
local c = math.random(20)-10;
local d = a*b+c;
msg = "To get out solve the math problem\n";
msg = msg .. colorize("LawnGreen",a.." * "..b.." + "..c .. " = ?\n\n")
problem = a.."*"..b.."+"..c .. " = ?";
correct = math.random(5);
local frm = "";
for i =1,5 do
local offset = 0;
if i~=correct then offset = math.random(10)-5; if offset == 0 then offset = -1 end end
frm = frm .. "button_exit[".. -0.1+(i-1)*1.25 ..",0.75;1.25,1;" .. i .. ";".. d + offset .. "]"
end
local form = "size[6,1.25]" .. "label[0.05,-0.3;".. msg.."] "..frm .. "button_exit[4.9,-0.25;1.2,1;cancel;cancel]";
return form, correct
end
selection = 1;
question = "";
problem = "";
end
if t%4 == 0 then
t = 0; form,selection = generate_question();
for _,obj in pairs(_G.minetest.get_objects_inside_radius({x=2,y=2,z=0}, 1)) do
if obj:is_player() then
local pname = obj:get_player_name();
self.show_form(pname,form)
end
end
end
t=t+1;
sender,fields = self.read_form()
if sender then
player = _G.minetest.get_player_by_name(sender);
if player then
answer = 0;
for i = 1,5 do if fields[_G.tostring(i)] then answer = i end end
if answer == correct then
player:setpos({x=0,y=2,z=3})
--inv = player:get_inventory(); inv:add_item("main", "default:apple")
--_G.minetest.chat_send_player(sender,"<MATH ROBOT> congratulations, here is an apple.")
elseif answer ~= 0 then
player:setpos({x=0,y=-6,z=-1})
say(sender .. " failed to solve the problem " .. problem)
self.show_form(sender, "size[1.25,0.5] label[0,0; WRONG]")
end
end
end

112
scripts/tree_harvest.lua Normal file
View File

@ -0,0 +1,112 @@
-- rnd, 2017
if not tree then
tree = {};
wood = "default:tree";
support = "default:tree";
leaves = "default:leaves";
sapling = "default:sapling";
tree.s = 0 -- searching
tree.st = 0
end
tree_step = function()
if tree.s == 0 then -- search
node = read_node.forward()
if node == wood then tree.s = 1 end
elseif tree.s==1 then -- found
dig.forward();
move.forward();
tree.s=2
elseif tree.s==2 then -- dig up
node = read_node.up()
dig.up()
move.up()
place.down(support)
if node ~= wood then
tree.s=3 tree.st = 0
end
elseif tree.s==3 then -- on top
if tree.st == 0 then
move.up();
turn.right();place.forward_down(support);
dig.forward()
turn.angle(180); place.forward_down(support);
tree.st=1
elseif tree.st == 1 then
dig.forward(); move.forward();
tree.st=2
elseif tree.st == 2 then
turn.left(); dig.forward(); turn.angle(180)
tree.st=3
elseif tree.st == 3 then
dig.forward(); turn.right(); tree.st = 4
elseif tree.st == 4 then
dig.down();move.forward(); move.forward(); tree.st = 5
elseif tree.st == 5 then
turn.left(); dig.forward(); turn.angle(180)
tree.st=6
elseif tree.st == 6 then
dig.forward(); turn.right(); tree.st = 7
elseif tree.st == 7 then
dig.down();move.forward();
turn.right();
tree.st = 0; tree.s = 4
end
elseif tree.s == 4 then -- going down
node = read_node.down()
if node == wood then
dig.down();
move.down();
else
pickup(8); move.forward();
place.backward(sapling)
tree.s=5
end
end
end
-- walk around
if not s then
wall = "basic_robot:buttonFFFFFF";
s=0
if rom.tree and rom.s then
tree.s = rom.tree.s; tree.st = rom.tree.st
s = rom.s;
rom.s = nil;
else
rom.tree = {}
end;
angle = 90
end
if s==0 then -- walk
if not move.forward() then
node = read_node.forward();
if node == wood then
s = 1
else
turn.angle(angle); node = read_node.forward()
if node == wall then
turn.angle(180);move.forward();turn.angle(-angle)
else
move.forward(); turn.angle(angle)angle=-angle;
end
end
end
elseif s==1 then
tree_step();
if tree.s == 5 then s = 0; tree.s = 0 end
end
rom.s = s;rom.tree.s = tree.s; rom.tree.st = tree.st -- remember whats it doing
--self.label(s .. " " .. tree.s .. " " .. tree.st)

46
scripts/utils/chatlog.lua Normal file
View File

@ -0,0 +1,46 @@
--rnd 2017
if not logdata then
self.label("chatlog bot");
_G.minetest.forceload_block(self.pos(),true)
n = 250;
idx = 1;
logdata = {};
insert = function(text) -- insert new message
idx = idx +1;
if idx > n then idx = 1 end
logdata[idx] = text;
end
last = function(k,filter) -- return last k messages
if k > n then k = 30 end
local i,j,ret;
i=idx;j=0; ret = ""
for j = 1,k do
if not logdata[i] then break end
if filter and not string.find(logdata[i], filter) then
else
ret = ret .. logdata[i] .. "\n";
end
i=i-1; if i < 1 then i = n end
end
return ret
end
self.listen(1)
end
speaker, msg = self.listen_msg()
if msg then
if string.sub(msg,1,4) == "?log" then
local j = string.find(msg," ",6);
local k = tonumber(string.sub(msg,6) or "") or n;
local text;
if j then text = last(k,string.sub(msg,j+1)) else text = last(k) end
local form = "size[8,8]".. "textarea[0.,0;11.,9.5;text;chatlog;".. text .. "]"
self.show_form(speaker, form)
else
insert(os.date("%X") .. " " .. speaker .. "> " .. msg)
end
end

View File

@ -0,0 +1,123 @@
if not dict then
lang = "german"
dict = {};
fname = "F:\\games\\rpg\\minetest-0415server\\mods\\basic_translate\\"..lang;
local f = _G.assert(_G.io.open(fname, "r"));local dicts = f:read("*all");f:close()
step = 0; maxwords = 10000;
i=0
while(step<maxwords) do
step=step+1
i1 = string.find(dicts,"\t",i+1)
i2 = string.find(dicts,"\n",i+1)
if not i2 then break end
local word = string.sub(dicts, i+1,i1-1);
local tword = string.sub(dicts, i1+1,i2-1);
local word1; local word2;local data;
i12 = string.find(word," ");
if i12 and i12<i2 then
word1 = string.sub(word,1,i12-1); word2 = string.sub(word,i12+1)
data = dict[word1];
if not data then
dict[word1] = {{[word2] = tword}}
else
data[#data+1] = {[word2] = tword};
end
else
data = dict[word];
if not data then
dict[word] = {{[""] = tword}}
else
data[#data+1] = {[""] = tword};
end
end
--say("X"..word.."X"..tword)
i=i2
end
say(lang .. " dictionary: ".. step .. " words loaded")
-- self.label(string.gsub(_G.dump(dict),"\n",""))
local deb = false;
translate = function(input)
local out = "";
input = string.lower(input)
local i = 0; local n = string.len(input)
local step = 0
while i and i<n and step < 100 do
step = step + 1
local i1 = string.find(input," ",i+1);
local word;
if not i1 then --end
word = string.sub(input, i+1)
else -- just take one word until " "
word = string.sub(input, i+1, i1-1)
end
i1 = i+string.len(word)+1
if deb then say("parsed word " .. word .. " remainder '" .. string.sub(input, i1).."'") end
local data = dict[word];
if data then
if #data == 1 then
local newout = data[1][""];
if not newout then
for key,v in pairs(data[1]) do newout = v; i1 = i1 + string.len(key)+1 break end
end
out = out .. " " .. newout
if deb then say("immediate trans for " .. word) end
else -- more possibilities
if deb then say("more possibilities : ".. #data) end
--check patterns for match:like a de -> c or a b -> d, where data for a = {{[de] = c},{[b] = d}
local found = false
local defaultv = ""
for j=1,#data do
for key,v in pairs(data[j]) do
local keylen = string.len(key)
local pattern = string.sub(input,i1+1,i1+keylen)
if deb then say("pattern '" .. pattern .. "' key '" .. key .. "' len " .. keylen) end
if key == "" then defaultv = v
elseif pattern == key then
found = true;
if deb then say(word .. " " .. pattern .. " -> match key " .. key) end
out = out .. " " .. v; i1 = i1+string.len(key)+1 -- skip to after key
end
end
if found then break end
end
if not found then out = out .. " " .. defaultv end
end
else
out = out .. " " .. word
end
i=i1
if deb then say("next word at i " .. i1 .. " remainder " .. string.sub(input,i1)) end
end
return out
end
-- say(translate("hello world"))
self.listen(1)
end
speaker,msg = self.listen_msg()
if msg then
if string.sub(msg,1,1) == "?" then
msg = string.sub(msg,2)
local transmsg = translate(msg);
_G.minetest.chat_send_all("TRANSLATOR> " .. transmsg)
end
end

View File

@ -0,0 +1,76 @@
--SERVER ROBOT : can send various data to other robots that requested it
if not cmds then
-- user auth data
auth = {["rnd1"]=2};
-- server commands
cmds = {
list = {
run = function()
local ret = ""; for i,_ in pairs(cmds) do ret = ret .. " " .. i end; return ret
end,
help = "list all commands",
level = 0
},
help = {
run = function(words)
local arg = words[2];
if not arg then return "help: missing argument" end
local cmd = cmds[arg];
if not cmd then return "help: nonexistent command" end
return cmd.help or ""
end,
help = "display help for command",
level = 0
},
chat = {
run = function(words)
words[1] = "";_G.minetest.chat_send_all("#server bot : " .. table.concat(words," ") or ""); return true;
end,
help = "prints text globally",
level = 2
},
minetest = {
run = function() return minetest end,
help = "returns minetest namespace",
level = 3
}
};
LISTENING = 0; --states
state = LISTENING; -- init
_G.minetest.forceload_block(self.pos(),true)
end
if state == LISTENING then
sender,mail = self.read_mail()
if mail then
if type(mail)~="string" then mail = "" end
self.label("received request " .. mail);
local words = {};
for word in string.gmatch(mail,"%S+") do words[#words+1]=word end -- get arguments
if not words or not words[1] then
self.send_mail(sender,"error: nil request")
else
local cmd = cmds[words[1]];
if not cmd or not cmd.run then
self.send_mail(sender,"error: illegal command")
elseif (auth[sender] or 0) < cmd.level then
self.send_mail(sender,"error: auth level " .. (auth[sender] or 0) ..", need level " .. cmd.level)
else
self.send_mail(sender,cmd.run(words));
self.label("sending data to " .. sender .. " ...")
end
end
else
self.label("listening...")
end
end

View File

@ -0,0 +1,34 @@
-- rnd 2017
if not pos then
pos = self.spawnpos();
n = 6; -- width
m = 4; -- height
door = math.floor(n/2)+1; -- door place
plan = {};
build_cube = function(x,y,z)
plan[#plan+1] = {c= math.random(10)+6, pos={x=pos.x+x,y=pos.y+y,z=pos.z+z}};
end
--floor
y=0;for z=1,n do for x=1,n do build_cube(x,y,z) end end --bottom
z=1;for y=1,m do for x=1,n do build_cube(x,y,z) end end --wall 1
z=n;for y=1,m do for x=1,n do build_cube(x,y,z) end end --wall2
x=n;for y=1,m do for z=2,n-1 do build_cube(x,y,z) end end -- wall3
x=1;for y=1,m do for z=2,n-1 do if z~=door then build_cube(x,y,z) end end end -- wall4
x=1;z=door;for y=3,m do build_cube(x,y,z) end -- door hole
y=m;for x = 2,n-1 do for z = 2,n-1 do build_cube(x,y,z) end end -- ceiling
s=0
--self.remove()
end
s=s+1;
if plan[s] then
keyboard.set(plan[s].pos,plan[s].c)
else
self.remove()
end

BIN
textures/face-back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

BIN
textures/face3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
textures/left-hand.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

BIN
textures/legs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

BIN
textures/right-hand.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

BIN
textures/robot_side.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
textures/topface.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B