custom buttons fix. redstone script fix

master
ac-minetest 2022-08-28 09:52:37 +02:00
parent 2020477700
commit 8c9d0fd68f
30 changed files with 2442 additions and 1229 deletions

View File

@ -595,6 +595,8 @@ local write_keyevent = function(data,pos, puncher,type)
end
basic_robot.commands.write_keyevent = write_keyevent;
local button_punched = function(pos, node, player,type)
local name = player:get_player_name(); if name==nil then return end
local round = math.floor;
@ -609,8 +611,10 @@ local button_punched = function(pos, node, player,type)
end
end
local register_robot_button = function(R,G,B,type)
minetest.register_node("basic_robot:button"..R..G..B,
local buttoncolors = {};
local register_robot_button = function(R,G,B,colorname,type)
buttoncolors[type] = "basic_robot:button"..colorname;
minetest.register_node("basic_robot:button"..colorname,
{
description = "robot button",
tiles = {"robot_button.png^[colorize:#"..R..G..B..":180"},
@ -624,12 +628,14 @@ local register_robot_button = function(R,G,B,type)
end
local register_robot_button_number = function(number,type)
local idx = number+48
local texname = "robochars.png^[sheet:16x16:" .. idx % 16 .. "," .. math.floor(idx/ 16).."^[invert:rgb";
minetest.register_node("basic_robot:button"..number,
{
description = "robot button",
tiles = {"robot_button".. number .. ".png"},
inventory_image = "robot_button".. number .. ".png",
wield_image = "robot_button".. number .. ".png",
tiles = {texname},
inventory_image = texname,
wield_image = texname,
paramtype2 = "facedir",
is_ground_content = false,
@ -640,12 +646,14 @@ end
local register_robot_button_char = function(number,type)
local texname = "robochars.png^[sheet:16x16:" .. number % 16 .. "," .. math.floor(number/ 16);
-- local texname = string.format("%03d",number).. ".png";
minetest.register_node("basic_robot:button_"..number,
{
description = "robot button",
tiles = {string.format("%03d",number).. ".png"},
inventory_image = string.format("%03d",number).. ".png",
wield_image = string.format("%03d",number).. ".png",
tiles = {texname},
inventory_image = texname,
wield_image = texname,
is_ground_content = false,
groups = {cracky=3,not_in_craft_guide = 1},
paramtype2 = "facedir",
@ -654,7 +662,8 @@ minetest.register_node("basic_robot:button_"..number,
end
local register_robot_button_custom = function(number,texture)
minetest.register_node("basic_robot:button_"..number,
local type = number
minetest.register_node("basic_robot:button_"..number,
{
description = "robot button",
tiles = {texture .. ".png"},
@ -666,33 +675,66 @@ minetest.register_node("basic_robot:button_"..number,
})
end
--[[ colors!
0 white 8 green
1 yellow 9 dark green
2 orange 10 brown
3 red 11 tan
4 magenta 12 light grey
5 purple 13 medium grey
6 blue 14 dark grey
7 cyan 15 black
--]]
--16-color palette from macintosh II, 1987
register_robot_button("FF","FF","FF","white",1); -- white
register_robot_button("FC","F4","00","yellow",2); -- yellow
register_robot_button("FF","64","00","orange",3); -- orange
register_robot_button("DD","02","02","red",4); -- red
register_robot_button("F0","02","85","magenta",5); -- magenta
register_robot_button("46","00","A5","purple",6); -- purple
register_robot_button("00","00","D5","blue",7); -- blue
register_robot_button("00","AE","E9","cyan",8); -- cyan
register_robot_button("1A","B9","0C","green",9); -- green
register_robot_button("00","64","08","dark_green",10);-- dark_green
register_robot_button("57","28","00","brown",11);-- brown
register_robot_button("91","71","35","tan",12);-- tan
register_robot_button("C1","C1","C1","light_grey",13);-- light_grey
register_robot_button("81","81","81","medium_grey",14);-- medium_grey
register_robot_button("3E","3E","3E","dark_grey",15);-- dark_grey
register_robot_button("00","00","00","black",16);-- black
--[[ -- old colors
register_robot_button("FF","FF","FF",1);
register_robot_button("80","80","80",2);
register_robot_button("FF","80","80",3);
register_robot_button("80","FF","80",4);
register_robot_button("80","80","FF",5);
register_robot_button("FF","FF","80",6);
--]]
for i = 0,9 do register_robot_button_number(i,i+7) end
for i = 0,255 do register_robot_button_char(i,i+17) end
for i = 0,9 do register_robot_button_number(i,i+17) end -- all buttons shift by 10 from old version!
for i = 0,255 do register_robot_button_char(i,i+27) end
register_robot_button_custom(273,"puzzle_switch_off")
register_robot_button_custom(274,"puzzle_switch_on")
register_robot_button_custom(275,"puzzle_button_off")
register_robot_button_custom(276,"puzzle_button_on")
register_robot_button_custom(283,"puzzle_switch_off")
register_robot_button_custom(284,"puzzle_switch_on")
register_robot_button_custom(285,"puzzle_button_off")
register_robot_button_custom(286,"puzzle_button_on")
register_robot_button_custom(277,"puzzle_equalizer")
register_robot_button_custom(278,"puzzle_setter")
register_robot_button_custom(279,"puzzle_piston")
register_robot_button_custom(287,"puzzle_equalizer")
register_robot_button_custom(288,"puzzle_setter")
register_robot_button_custom(289,"puzzle_piston")
register_robot_button_custom(280,"puzzle_diode")
register_robot_button_custom(281,"puzzle_NOT")
register_robot_button_custom(282,"puzzle_delayer")
register_robot_button_custom(283,"puzzle_platform")
register_robot_button_custom(290,"puzzle_diode")
register_robot_button_custom(291,"puzzle_NOT")
register_robot_button_custom(292,"puzzle_delayer")
register_robot_button_custom(293,"puzzle_platform")
register_robot_button_custom(284,"puzzle_giver")
register_robot_button_custom(285,"puzzle_checker")
register_robot_button_custom(294,"puzzle_giver")
register_robot_button_custom(295,"puzzle_checker")
@ -730,22 +772,12 @@ basic_robot.commands.keyboard = {
local nodename;
if type == 0 then
nodename = "air"
elseif type == 1 then
nodename = "basic_robot:buttonFFFFFF";
elseif type == 2 then
nodename = "basic_robot:button808080";
elseif type == 3 then
nodename = "basic_robot:buttonFF8080";
elseif type == 4 then
nodename = "basic_robot:button80FF80";
elseif type == 5 then
nodename = "basic_robot:button8080FF";
elseif type == 6 then
nodename = "basic_robot:buttonFFFF80";
elseif type>=7 and type <= 16 then
nodename = "basic_robot:button"..(type-7);
elseif type < 17 then
nodename = buttoncolors[type]
elseif type>=17 and type <= 26 then
nodename = "basic_robot:button"..(type-17);
else
nodename = "basic_robot:button_"..(type-17);
nodename = "basic_robot:button_"..(type-27);
end
minetest.swap_node(pos, {name = nodename})
@ -988,7 +1020,7 @@ basic_robot.commands.machine = {
check_operations(name,6, true)
if amount and amount>0 then -- attempt to generate power from builtin generator
if amount and amount>0 and amount<10^6 then -- attempt to generate power from builtin generator
local pos = basic_robot.data[name].spawnpos; -- position of spawner block
local inv = minetest.get_meta(pos):get_inventory();
local level = amount*40; -- to generate 1 unit ( coal lump per second ) we need at least upgrade 40
@ -1162,9 +1194,8 @@ basic_robot.commands.machine = {
local energy = 0; -- can only do one step at a run time
energy = data.menergy or 0;
if amount>energy or amount<0 then return nil,"energy too low" end
if amount>energy or amount<0 or amount>10^6 then return nil,"energy too low" end
if not tdata.menergy then tdata.menergy = 0 end
tdata.menergy = tdata.menergy + amount

View File

@ -1,32 +1,11 @@
-- basic_robot by rnd, 2016-2021
-- basic_robot by rnd, 2016-2022
basic_robot = {};
------ SETTINGS --------
basic_robot.call_limit = {50,200,1500,10^9}; -- how many execution calls per script run allowed, for auth levels 0,1,2 (normal, robot, puzzle, admin)
basic_robot.count = {2,6,16,128} -- how many robots player can have
basic_robot.version = "2022/02/02b";
basic_robot.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches
basic_robot.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running mod, password used for authentifications
dofile(minetest.get_modpath("basic_robot").."/settings.lua") -- read configuration SETTINGS
basic_robot.admin_bot_pos = {x=0,y=1,z=0} -- position of admin robot spawner that will be run automatically on server start
basic_robot.maxoperations = 10; -- how many operations (dig, place,move,...,generate energy,..) available per run, 0 = unlimited
basic_robot.dig_require_energy = true; -- does robot require energy to dig stone?
basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
["moreblocks:circular_saw"] = true,
["craft_guide:sign_wall"] = true,
["basic_machines:battery_0"] = true,
["basic_machines:battery_1"] = true,
["basic_machines:battery_2"] = true,
["basic_machines:generator"] = true,
}
----- END OF SETTINGS ------
basic_robot.http_api = minetest.request_http_api();
basic_robot.version = "2021/06/28a";
-- structures for storing robot data
basic_robot.gui = {}; local robogui = basic_robot.gui -- gui management
basic_robot.data = {}; -- stores all robot related data
@ -50,7 +29,6 @@ local check_code, preprocess_code,is_inside_string;
-- SANDBOX for running lua code isolated and safely
function getSandboxEnv (name)
local authlevel = basic_robot.data[name].authlevel or 0;
@ -61,7 +39,11 @@ function getSandboxEnv (name)
left_up = 11, right_up = 12, forward_up = 13, backward_up = 14
}
if not basic_robot.data[name].rom then basic_robot.data[name].rom = {} end -- create rom if not yet existing
local pname = string.sub(name,1,-2)
if not basic_robot.data[pname] then basic_robot.data[pname] = {} end
-- all robots by player share same rom now
if not basic_robot.data[pname].rom then basic_robot.data[pname].rom = {} end -- create rom if not yet existing
local env =
{
_Gerror = error,
@ -93,9 +75,11 @@ function getSandboxEnv (name)
return commands.craft(item, mode, idx, amount, name)
end,
pause = function() -- pause coroutine
pause = function(amount) -- pause coroutine
if not basic_robot.data[name].cor then error("you must start program with '--coroutine' to use pause()") return end
if not amount or basic_robot.data[name].operations<amount then
coroutine.yield()
end
end,
self = {
@ -103,7 +87,7 @@ function getSandboxEnv (name)
spawnpos = function() local pos = basic_robot.data[name].spawnpos; return {x=pos.x,y=pos.y,z=pos.z} end,
name = function() return name end,
operations = function() return basic_robot.data[name].operations end,
viewdir = function() local yaw = basic_robot.data[name].obj:getyaw(); return {x=math.cos(yaw), y = 0, z=math.sin(yaw)} end,
viewdir = function() local yaw = basic_robot.data[name].obj:getyaw(); return {x=-math.sin(yaw), y = 0, z=math.cos(yaw)} end,
set_properties = function(properties)
if not properties then return end; local obj = basic_robot.data[name].obj;
@ -173,7 +157,7 @@ function getSandboxEnv (name)
reset = function()
local pos = basic_robot.data[name].spawnpos;
local obj = basic_robot.data[name].obj;
obj:set_pos({x=pos.x,y=pos.y+1,z=pos.z}); obj:setyaw(0);
obj:set_pos({x=pos.x,y=pos.y+1,z=pos.z}); obj:set_yaw(0);
end,
set_libpos = function(pos)
@ -351,6 +335,8 @@ function getSandboxEnv (name)
write = function(i,title,text)
if i<=0 or i > 32 then return nil end
local inv = minetest.get_meta(basic_robot.data[name].spawnpos):get_inventory();
local stackname = inv:get_stack("library",i):get_name();
if basic_robot.data[name].authlevel<3 and (stackname ~= "default:book_written" and stackname~= "default:book") then return nil end
local stack = basic_robot.commands.write_book(basic_robot.data[name].owner,title,text);
if stack then inv:set_stack("library", i, stack) end
end
@ -369,7 +355,7 @@ function getSandboxEnv (name)
end,
},
rom = basic_robot.data[name].rom,
rom = basic_robot.data[pname].rom,
string = {
byte = string.byte, char = string.char,
@ -525,7 +511,7 @@ function getSandboxEnv (name)
setfenv( ScriptFunc, basic_robot.data[name].sandbox )
local Result, RuntimeError = pcall( ScriptFunc );
local _, RuntimeError = pcall( ScriptFunc );
if RuntimeError then
minetest.chat_send_player(name, "#code.run: run error " .. RuntimeError )
return false
@ -592,10 +578,13 @@ function getSandboxEnv (name)
end
-- code checker
-- bugfixes:
-- player Midskip found problem with code checking, fixed
check_code = function(code)
--"while ", "for ", "do ","goto ",
local bad_code = {"repeat", "until", "_G", "while%(", "while{", "pcall","%.%.[^%.]"} --,"\\\"", "%[=*%[","--[["}
local bad_code = {"repeat", "until", "_G", "while%(", "while{", "pcall","[^%.]%.%.[^%.]","\\\"","\\\'","%[=*%["}
for _, v in pairs(bad_code) do
if string.find(code, v) then
return v .. " is not allowed!";
@ -603,8 +592,7 @@ check_code = function(code)
end
end
local identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
local i = 0; local j; local _; local length = string.len(code);
local mode = 0; -- 0: not in string, 1: in '...' string, 2: in "..." string, 3. in [==[ ... ]==] string
@ -622,8 +610,12 @@ local identify_strings = function(code) -- returns list of positions {start,end}
for k=1,#modes do
j = string.find(code,modes[k][1],i);
if j and j<jmin then -- pick closest one
if string.sub(code,j-1,j-1) ~="\\" then
jmin = j
mode = k
else
j=j+1;
end
end
end
if mode ~= 0 then -- found something
@ -634,10 +626,12 @@ local identify_strings = function(code) -- returns list of positions {start,end}
else
_,j = string.find(code,modes[mode][2],i); -- search for closing pair
if not j then break end
if (mode~=2 or (string.sub(code,j-1,j-1) ~= "\\") or string.sub(code,j-2,j-1) == "\\\\") then -- not (" and not \" - but "\\" is allowed)
local pchar = string.sub(code,j-1,j-1)
if (mode~=2 or (pchar ~= "\\") or string.sub(code,j-2,j-1) == "\\\\") then -- not (" and not \" - but "\\" is allowed)
ret[#ret][2] = j
mode = 0
end
if pchar == "\\" then j=j+1 end
end
i=j -- move to next position
end
@ -683,8 +677,8 @@ preprocess_code = function(script, call_limit) -- version 07/24/2018
when counter exceeds limit exit with error
--]]
script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-[^\n]*\n","\n") -- strip comments
--script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-[^\n]*\n","\n") -- strip comments
script = string.gsub(script,"%-%-[^\n]+\n","\n") -- strip single line comments, multiline not allowed
-- process script to insert call counter in every function
local _increase_ccounter = " _Gc = _Gc + 1; if _Gc > " .. call_limit ..
" then _Gerror(\"Execution count \".. _Gc .. \" exceeded ".. call_limit .. "\") end; "
@ -746,7 +740,7 @@ preprocess_code = function(script, call_limit) -- version 07/24/2018
-- must reset ccounter when paused, but user should not be able to force reset by modifying pause!
-- (suggestion about 'pause' by Kimapr, 09/26/2019)
return "_Gc = 0 local _Gpause = pause pause = function() _Gc = 0; _Gpause() end " .. script;
return "_Gc = 0 local _Gpause = pause pause = function(amount) _Gc = 0; _Gpause(amount) end " .. script;
--return script:gsub("pause%(%)", "_c_ = 0; pause()") -- reset ccounter at pause
end
@ -803,7 +797,7 @@ local function runSandbox( name)
end
data.operations = basic_robot.maxoperations;
data.t = os.clock()
data.t = os.clock() -- timing
setfenv( ScriptFunc, data.sandbox )
@ -1052,7 +1046,7 @@ minetest.register_entity("basic_robot:robot",{
minetest.set_node(pos, {name = "air"});
--local privs = core.get_player_privs(self.owner);privs.interact = false;
--core.set_player_privs(self.owner, privs); minetest.auth_reload()
minetest.kick_player(self.owner, "#basic_robot: stack overflow")
minetest.kick_player(self.owner, "#basic_robot: stack overflow at " .. pos.x.. " " .. pos.y .. " " .. pos.z)
end
local name = self.name;
@ -1224,7 +1218,6 @@ local spawn_robot = function(pos,node,ttl)
if data == nil then
basic_robot.data[name] = {};
data = basic_robot.data[name];
--data.rom = {};
end
data.owner = owner;
@ -1707,7 +1700,6 @@ minetest.register_node("basic_robot:spawner", {
paramtype = "light",
param1=1,
walkable = true,
alpha = 150,
after_place_node = function(pos, placer)
@ -1830,6 +1822,8 @@ end
-- remote control
local write_keyevent = basic_robot.commands.write_keyevent;
minetest.register_craftitem("basic_robot:control", {
description = "Robot remote control",
inventory_image = "control.png",
@ -1868,7 +1862,9 @@ minetest.register_craftitem("basic_robot:control", {
local hppos = minetest.hash_node_position(ppos)
local rname = basic_robot.data.punchareas[hppos];
local data = basic_robot.data[rname];
if data then data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = owner, type = 0} end
if data then
write_keyevent(data,pos, owner,0)
end
return
end

4
mod.conf Normal file
View File

@ -0,0 +1,4 @@
name = basic_robot
depends = default
optional_depends =
description = your ingame robot companion. learn how to program and make games

View File

@ -145,7 +145,8 @@ local help_pages = {
" 7. [TECHNIC FUNCTIONALITY]",
" 8. [CRYPTOGRAPHY]",
" 9. [PUZZLE]",
" 10.[COROUTINES] - easier alternative to finite state machines",
" 10.[COROUTINES AND LIBRARIES AND ROM] - easier alternative to",
" finite state machines",
},
["MOVEMENT DIGGING PLACING NODE SENSING"] = {
@ -312,20 +313,32 @@ local help_pages = {
" add_particle(def)"
},
["COROUTINES"] = {
["COROUTINES AND LIBRARIES AND ROM"] = {
"back to [Commands reference]",
"COROUTINES","",
"robot can run code using lua coroutines. To enable this mode just put the word",
"coroutine in the first 32 characters of your program. Example: ", "",
"robot can run code using lua coroutines. To enable this mode just put",
"the word coroutine in the first 32 characters of your program. Example:",
" --testing program for coroutine",
" for i = 1,5 do ",
" say(i); dig.forward(); move.forward()",
" pause()",
" end",
"pause(amount) temporarily stops if available operations are less than",
" amount","",
"LIBRARIES","",
"you can define functions for robot in another robot and re-use them later.",
"for example do: rom.lib_src = \"f1 = function(x) return 2*x end\" and later",
"in another robot recreate function with: ",
"if not f1 then code.run(rom.lib_src) end ",
"self.label(f1(1))","",
"ROM","",
"all robots by a player share same \"rom\" variable that can be used to",
"store more persistent data like numbers, strings or tables",
},
}
for k,v in pairs(help_pages) do
local pages = help_pages[k]; for i = 1,#pages do pages[i] = minetest.formspec_escape(pages[i]) end

View File

@ -0,0 +1,141 @@
-- 2d rubik cube slide puzzle by rnd in 40 mins
if not init then init = true
m=4;
n=m;
data = {};
nodelist = {};
for i = 1,m do
for j = 1,n do
nodelist[(i-1)*n+j] = "basic_robot:button_"..(64+(n-j+1-1)*n+i)
end
end
for i = 1,m do
data[i] = {};local dat = data[i];
for j = 1,n do
dat[j] = (i-1)*n+j;
end
end
spos = self.spawnpos(); spos.x=spos.x+1; spos.z=spos.z+1
render = function(t,mode) -- mode 1:row, 2: coloumn
if not mode then
for i=1,m do
for j = 1,n do
minetest.swap_node({x=spos.x+i,y=spos.y,z=spos.z+j},{name = nodelist[data[i][j]]})
end
end
return
end
if mode == 1 then -- row only
for i=1,m do
minetest.swap_node({x=spos.x+i,y=spos.y,z=spos.z+t},{name = nodelist[data[i][t]]})
end
return
else -- coloumn only
for j=1,n do
minetest.swap_node({x=spos.x+t,y=spos.y,z=spos.z+j},{name = nodelist[data[t][j]]})
end
return
end
end
pnames = find_player(4);
if not pnames then self.remove() end
player = minetest.get_player_by_name(pnames[1]);
check_rot_dir = function()
local vdir = player:get_look_dir()
local mode = 0;
if math.abs(vdir.x)<math.abs(vdir.z) then
if vdir.z>0 then
mode = 2
else
mode = -2
end
else
if vdir.x>0 then
mode = 1
else
mode = -1
end
end -- rotate in z dir
return mode
end
rotx = function(col,dir)
if dir > 0 then
local tmp = data[1][col]
for i = 1,m-1 do
data[i][col] = data[i+1][col]
end
data[m][col] = tmp
else
local tmp = data[m][col]
for i = m,2,-1 do
data[i][col] = data[i-1][col]
end
data[1][col] = tmp
end
end
rotz = function(row,dir)
if dir > 0 then
local tmp = data[row][1]
for j = 1,n-1 do
data[row][j] = data[row][j+1]
end
data[row][m] = tmp
else
local tmp = data[row][n]
for j = n,2,-1 do
data[row][j] = data[row][j-1]
end
data[row][1] = tmp
end
end
rndshuffle = function(steps)
for step = 1,steps do
local mode = math.random(4);
if mode <=2 then
local z = math.random(m);
if mode == 2 then mode = -1 end
rotx(z,mode)
else
local x = math.random(n);
if mode == 3 then mode = -2 else mode = 2 end
rotz(x,mode)
end
end
end
self.listen_punch(self.pos())
self.label("try to get all letters sorted started with A top left")
rndshuffle(m*n)
render()
end
event = keyboard.get()
if event then
--self.label(serialize(event))
local x = event.x-spos.x;
local z = event.z-spos.z;
local mode = check_rot_dir()
if x>0 and x<=m and z>0 and z<=n then
if math.abs(mode) == 1 then
rotx(z,-mode)
render(z,1)
else
rotz(x,-mode)
render(x,2)
end
end
end

View File

@ -3,10 +3,10 @@
if not data then
-- novice: 8x8, 4
m=8;n=8;
atoms = 8
m=9;n=9;
atoms = 16
attempts = 1;turn = 0;
spawnpos = self.spawnpos(); spawnpos.x = spawnpos.x-m/2; spawnpos.y = spawnpos.y+2; spawnpos.z = spawnpos.z-n/2
spawnpos = self.spawnpos(); spawnpos.x = spawnpos.x-math.floor(m/2); spawnpos.y = spawnpos.y+2; spawnpos.z = spawnpos.z-math.floor(n/2)
local players = find_player(5,spawnpos);
if not player then self.remove() else pname = players[1] end
@ -26,11 +26,11 @@ if not data then
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)
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:buttongray" then
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},15) -- 2 gray
end
else
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},3)
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},4) --on 3
end
end end
end
@ -126,8 +126,8 @@ if not data then
-- 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,z=spawnpos.z+0},7) keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+n+1},7) end
for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y,z=spawnpos.z+j},7) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y,z=spawnpos.z+j},7) 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
@ -135,28 +135,28 @@ if not data then
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
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" 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
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" 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
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" 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
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" then
border_start_ray(x,z)
end
end
@ -164,7 +164,7 @@ if not data then
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 keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}) == "basic_robot:buttonred" then -- red
if data[i][j]~=1 then return false end
else
if data[i][j]~=0 then return false end
@ -176,8 +176,8 @@ if not data then
--render board
render_board(0)
keyboard.set({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z-1},4)
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z-1},5)
keyboard.set({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z-1},9)
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z-1},7)
self.label("BLACKBOX with " .. atoms .. " atoms")
end
@ -185,23 +185,24 @@ 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;
--self.label(serialize(event))
if x<1 or x>m or z<1 or z>n then
if event.type == 4 then
if event.type == 9 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
elseif event.type == 5 then
elseif event.type == 7 then
say("#BLACKBOX : DISPLAYING SOLUTION",pname)
render_board(1)
self.remove()
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
nodetype = 4;
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonred" then
nodetype = 15
end
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype);
end

View File

@ -1,7 +1,7 @@
-- CONNECT, coded in 20 minutes by rnd
if not data then
m=10;n=10;turn = 0; num = 5;
-- m=3;n=3;turn = 0; num = 3;
m=10;n=10;turn = 0; num = 4;
self.spam(1);t0 = _G.minetest.get_gametime();
spawnpos = self.spawnpos() -- place mines
self.listen_punch(self.pos()) -- attach punch listener
@ -10,8 +10,8 @@ if not data then
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)
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:buttonlight_gray" then
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},13)
end
end end
@ -43,7 +43,7 @@ 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
elseif event.type == 13 then --if event.type == 2 then
if state == 0 then
if #players<2 then players[#players+1] = event.puncher -- 1 is green, turn 0 = green
else state = 1 end

View File

@ -1,12 +1,45 @@
--HIDE AND SEEK game robot, by rnd
if not gamemaster then
timeout = 10;
timeout = 20;
fardist = 300
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"))
self.listen(1);
centerpos = {x=160,y= 606,z= 227};
init_game = function()
self.label(colorize("yellow","HIDE&SEEK .. waiting for players .. say #hide to join"))
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK .. say #hide to join play, when all joined say #start to start game."))
s=0;t=0; count = 0;
player_list = {}
end
reset_name = function(name)
if name then
local player = minetest.get_player_by_name(name)
if not player then return end
player:set_properties({nametag_color = "white"})
return
end
local players = _G.minetest.get_connected_players();
for _,player in pairs(players) do
local name = player:get_player_name();
local data = player_list[name];
if data then
player:set_properties({nametag_color = "white"})
end
end
end
show_players = function()
local ret = {}
for k,v in pairs(player_list) do
ret[#ret+1]=k
end
self.label("hide and seek, players: " .. table.concat(ret,", "))
end
init_game()
end
speaker,msg = self.listen_msg();
@ -17,7 +50,7 @@ if s==0 then
_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"})
player:setpos(centerpos);player:set_properties({nametag_color = "0x0"})
end
end
@ -52,16 +85,19 @@ elseif s==1 then
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
local dist = math.max(math.abs(pos.x-centerpos.x),math.abs(pos.y-centerpos.y),math.abs(pos.z-centerpos.z));
if dist>fardist 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"})
reset_name(name)
show_players()
player_list[name] = nil;
end
if data.hp ~= player:get_hp() then
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:setpos(centerpos)
player_list[name] = nil;
show_players()
end
--expose campers
@ -87,20 +123,18 @@ elseif s==1 then
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;
reset_name(name)
init_game();
end
else
_G.minetest.chat_send_all("# HIDE AND SEEK: no players left")
gamemaster = false;
init_game()
end
end
end

View File

@ -0,0 +1,162 @@
--coroutine
--lights out by dopik
if not init then init = true
self.listen_punch(self.pos());
end
size = 5
score = 1000 --highest score possible
function generateField()
local tbl = {}
for i = 1, size^2 do
tbl[i] = math.random(0,1)
end
local field = {}
for i = 1, size^2 do
local x,z = (i-1) % size, math.floor((i-1) / size)
local val = tbl[i]
val = val + (x > 0 and tbl[(x-1) + (z*size) +1] or 0)
val = val + (x+1 < size and tbl[(x+1) + (z*size) +1] or 0)
val = val + (z > 0 and tbl[x + ((z-1)*size) +1] or 0)
val = val + (z+1 < size and tbl[x + ((z+1)*size) +1] or 0)
field[i] = val % 2
end
return field
end
function placeField(field)
for i = 1, size^2 do
local dx,dz = (i-1) % size +1, math.floor((i-1) / size) +1
local pos = self.spawnpos()
pos.x = pos.x + dx
pos.z = pos.z + dz
keyboard.set(pos, field[i]*6 + 1)
end
end
function hitKey(pos)
local c
if keyboard.read(pos) == "basic_robot:buttonwhite" then
c = true
keyboard.set(pos, 7)
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
keyboard.set(pos, 1)
end
pos.x = pos.x - 1
if keyboard.read(pos) == "basic_robot:buttonwhite" then
c = true
keyboard.set(pos, 7)
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
keyboard.set(pos, 1)
end
pos.x = pos.x + 2
if keyboard.read(pos) == "basic_robot:buttonwhite" then
c = true
keyboard.set(pos, 7)
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
keyboard.set(pos, 1)
end
pos.x = pos.x - 1
pos.z = pos.z - 1
if keyboard.read(pos) == "basic_robot:buttonwhite" then
c = true
keyboard.set(pos, 7)
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
keyboard.set(pos, 1)
end
pos.z = pos.z + 2
if keyboard.read(pos) == "basic_robot:buttonwhite" then
c = true
keyboard.set(pos, 7)
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
keyboard.set(pos, 1)
end
score = math.max(0, score - 1)
if not c then
return won()
end
end
function won()
for i = 1, size^2 do
local pos = self.spawnpos()
pos.x = pos.x + 1 + i % size
pos.z = pos.z + 1 + math.floor(i / size)
if keyboard.read(pos) == "basic_robot:buttonblue" then
return false
end
end
return win()
end
function win()
puzzle.chat_send_player(pname, "\27(c@#ff0)###Lights Out### \27(c@#fff)You won!")
puzzle.chat_send_player(pname, string.concat({"\27(c@#ff0)###Lights Out### \27(c@#fff)Your score is \27(c@#ff0) ", score}))
for i = 1, size^2 do
local dx,dz = (i-1) % size +1, math.floor((i-1) / size) +1
local pos = self.spawnpos()
pos.x = pos.x + dx
pos.z = pos.z + dz
puzzle.set_node(pos, {name="default:dirt"})
end
self.remove()
end
function init()
local players = find_player(5, self.spawnpos())
if not players then
self.remove()
return
end
pname = players[1]
local field = generateField(size)
placeField(field)
puzzle.chat_send_player(pname, "\27(c@#ff0)###Lights Out### \27(c@#fff)Game started")
self.label("Turn all lights off (=white) to win\nPunch a light to switch it on/off")
return main()
end
function main()
local event = keyboard.get()
local pos = self.spawnpos()
if event then
if event.x <= pos.x + size and event.x > pos.x
and event.z <= pos.z + size and event.z > pos.z
and event.y == pos.y then
hitKey({x=event.x,y=event.y, z=event.z})
end
end
pause()
return main()
end
init()

View File

@ -8,21 +8,22 @@ if not data then
self.spam(1)
t0 = _G.minetest.get_gametime();
data = {}; spawnpos = self.spawnpos() -- place mines
self.listen_punch(self.pos()); -- attach punch listener
self.listen_punch(spawnpos); -- attach punch listener
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"})
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:buttonlight_grey" then
puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:buttonlight_grey"})
end
end end
puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
puzzle.set_node({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttondark_green"})
puzzle.set_node({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttonblue"})
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
@ -34,7 +35,7 @@ if not data then
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
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonred" and data[i] and data[i][j]==1 then
count=count-1
end
end end
@ -47,9 +48,10 @@ 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
if x == 1 and z == 0 then
local count = chk_mines();
if count>minescount/2 then
say("fail, more than 50% of mines remaining ")
@ -69,20 +71,20 @@ if event then
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"})
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:buttonlight_grey" then
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonlight_grey"})
else
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonFF8080"})
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonred"})
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"});
say("boom! "..event.puncher .. " is dead ");puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttonred"});
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"})
if count == 0 then puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttongreen"})
else puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button"..count}) end
end
end

View File

@ -2,7 +2,7 @@
-- INIT
if not grid then
n=6
n=9
solved = false -- do we render solution or blank?
-- _G.math.randomseed(3)
@ -21,7 +21,7 @@ if not grid then
end
_,scores_string = book.read(1); scores = minetest.deserialize(scores_string)
if not scores then scores = init_score(5,5,-999) end -- 5 levels, 5 top records
if not scores then scores = init_score(n-1,n-1,-999) end -- 5 levels, 5 top records
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 )." ..
@ -85,7 +85,7 @@ if not grid then
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
if typ == "basic_robot:buttonlight_grey" then grid[i][j] = 0 else grid[i][j] = 1 end
end
end
return grid
@ -131,7 +131,7 @@ if not grid then
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;
easy = n-1-easy;
if easy < 0 then easy = 0 end
return easy
end
@ -142,8 +142,8 @@ if not grid then
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
if grid[j][i]==0 then typ = 13 else typ = 2 end
if not solved then typ = 13 end
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ) --board
end
end
@ -152,18 +152,18 @@ if not grid then
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)
keyboard.set({x=spawnpos.x-length+k,y=spawnpos.y,z=spawnpos.z+i},rowdata[i][k]+17)
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)
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+k+n},coldata[j][k]+17)
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
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},9) -- game check button
keyboard.set({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},7) -- game check button
local players = find_player(6,spawnpos)
if not players then error("nonogram: no players near") end
@ -183,6 +183,9 @@ if not grid then
elseif difficulty == 2 then limit = 80 reward = 7
elseif difficulty <= 1 then limit = 70 reward = 6
end
if not scores[difficulty] then scores[difficulty] = {{"-",-999}} end
if not scores[difficulty][1] then scores[difficulty][1] = {"-",-999} end
minetest.chat_send_player(pname, "nonogram difficulty " .. difficulty .. ". you will get " .. reward .. " gold if you solve it in faster than " .. limit .."s" ..
". Current record " .. -scores[difficulty][1][2] .. " by " .. scores[difficulty][1][1])
@ -233,7 +236,7 @@ if event then
for i=1,n do
for j =1,n do
local typ;
if grid[j][i]==0 then typ = 2 else typ = 3 end
if grid[j][i]==0 then typ = 13 else typ = 2 end
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ)
end
end
@ -244,7 +247,7 @@ if event then
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
if typ ~= "basic_robot:buttonlight_grey" then newtyp = 13
else newtyp = 2
end
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},newtyp);

View File

@ -1,26 +1,25 @@
-- paint canvas by rnd, 2018
if not init then
colors = {
"black","blue","brown","cyan","dark_green","dark_grey","green","grey",
"magenta","orange","pink","red","violet","white","yellow"
"white","yellow","orange","red","magenta","purple","blue","cyan",
"green","dark_green","brown","tan","light_grey","medium_grey","dark_grey","black"
}
invcolors = {}; for i = 1,#colors do invcolors[colors[i]] = i end
color = 1;
color = invcolors["black"];
size = 16;
init = true
local ent = _G.basic_robot.data[self.name()].obj:get_luaentity();
ent.timestep = 0.5
ent.timestep = 0.125
players = find_player(5); if not players then self.remove() end
player = _G.minetest.get_player_by_name(players[1])
self.label("-> " .. players[1])
spos = self.spawnpos(); spos.y=spos.y+1;
canvasn = "wool:white"
canvasn = "basic_robot:buttonwhite"
reset_canvas = function()
for i = 1, size do
for j = 1, size do
@ -34,11 +33,12 @@ if not init then
local ret = {};
for i = 1, size do
for j = 1, size do
local nname = string.sub(minetest.get_node({x=spos.x +i , y = spos.y + j, z = spos.z }).name,6)
local nname = string.sub(minetest.get_node({x=spos.x +i , y = spos.y + j, z = spos.z }).name,19)
local pcolor = invcolors[nname] or 1;
ret[#ret+1]= string.char(96+pcolor)
end
end
return table.concat(ret,"")
end
@ -49,7 +49,7 @@ if not init then
for j = 1, size do
k=k+1;
local pcolor = colors[string.byte(image,k)-96] or "black";
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = "wool:"..pcolor})
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = "basic_robot:button"..pcolor})
end
end
end
@ -57,7 +57,7 @@ if not init then
--draw buttons
for i = 1,#colors do
minetest.set_node({x=spos.x +i , y = spos.y , z = spos.z },{name = "wool:"..colors[i]})
minetest.set_node({x=spos.x +i , y = spos.y , z = spos.z },{name = "basic_robot:button"..colors[i]})
end
minetest.set_node({x=spos.x +1 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_83"})
@ -88,7 +88,7 @@ if player:get_player_control().LMB then -- player interacts with 'virtual canvas
if x>0 and x<size and y>-2 and y<size then
if y>0 then -- above: painting
c.z = c.z+0.5
minetest.set_node(c, {name = "wool:" .. colors[color]})
minetest.set_node(c, {name = "basic_robot:button" .. colors[color]})
elseif y>-1 then -- color selection
x = 1+math.floor(x)
if colors[x] then

221
scripts/games/rubik.lua Normal file
View File

@ -0,0 +1,221 @@
-- Rubik Cube
if not init then init = true
self.listen_punch(self.pos())
pname = find_player(5); if not pname then say("no players!");self.remove() end; pname = pname[1];
player = minetest.get_player_by_name(pname)
say("rubik cube. rotation is indicated by your view direction")
n=3;
-- top left first
yz1 = { -- size n^2, side looking toward x-
7,1,8,
1,1,1,
9,1,1
}
yz2 = { -- size n^2, side looking toward x+
7,2,8,
2,2,2,
9,2,2
}
xy1 = { -- size n^2, side looking toward z-
7,3,8,
3,3,3,
9,3,3
}
xy2 = { -- size n^2, side looking toward z+
7,4,8,
4,4,4,
9,4,4,
}
xz1 = { -- size n^2, side looking toward y-
7,5,8,
5,5,5,
9,5,5,
}
xz2 = { -- size n^2, side looking toward y+
7,6,8,
6,6,6,
9,6,6,
}
surfdata = {
["yz1"]={
rotations = {
[0] = "face cw",
[1] = "face ccw",
[2] = "horizontal +",
[3] = "horizontal -",
[4] = "vertical +",
[5] = "vertical -",
}
}
}
blocks = {
"basic_robot:button808080",
"basic_robot:buttonFF8080",
"basic_robot:button80FF80",
"basic_robot:button8080FF",
"basic_robot:buttonFFFF80",
"basic_robot:buttonFFFFFF",
"basic_robot:button_48", --7
"basic_robot:button_49", --8
"basic_robot:button_50", --9
}
render_cube = function()
local p = self.pos();
for y=1,n do
for z=1,n do
minetest.swap_node({x=p.x+1,y=p.y+y+1,z=p.z+z},{name = blocks[yz1[n*(y-1)+z]]})
end
end
for y=1,n do
for z=1,n do
minetest.swap_node({x=p.x+n+2,y=p.y+y+1,z=p.z+z},{name = blocks[yz2[n*(y-1)+z]]})
end
end
for x=1,n do
for y=1,n do
minetest.swap_node({x=p.x+x+1,y=p.y+y+1,z=p.z},{name = blocks[xy1[n*(x-1)+y]]})
end
end
for x=1,n do
for y=1,n do
minetest.swap_node({x=p.x+x+1,y=p.y+y+1,z=p.z+n+1},{name = blocks[xy2[n*(x-1)+y]]})
end
end
for x=1,n do
for z=1,n do
minetest.swap_node({x=p.x+x+1,y=p.y+1,z=p.z+z},{name = blocks[xz1[n*(x-1)+z]]})
end
end
for x=1,n do
for z=1,n do
minetest.swap_node({x=p.x+x+1,y=p.y+n+2,z=p.z+z},{name = blocks[xz2[n*(x-1)+z]]})
end
end
end
rotccw = function(tab)
local newtab = {}
local n = (#tab)^0.5
for i = 1,n do
for j = 1,n do
newtab[(i-1)*n+j] = tab[(j-1)*n+n-i+1]
end
end
return newtab
end
rotcw = function(tab)
local newtab = {}
local n = (#tab)^0.5
for i = 1,n do
for j = 1,n do
newtab[(j-1)*n+n-i+1] = tab[(i-1)*n+j]
end
end
return newtab
end
viewlim = 0.9; --how close to perpendicular need to look to rotate face
p = self.pos();
render_cube()
end
event = keyboard.get()
if event then
-- rotate depending where player looks, if he looks close to normal to surface rotate cw or ccw
local view = player:get_look_dir()
-- which way? face or horizontal or vertical?
local rot = 0; -- rotation mode
local face = "";
local x=1;local y=1;
if event.x == p.x+1 then
face= "yz1"
if math.abs(view.x)>viewlim then
rot = 0; -- face cw
yz1 = rotcw(yz1); -- face cw rotate
--slice x=1 rotate:
--[[{
xz2,row 1,rev
xy1,row 1,rev
xz1,row 1,ord
xy2,col 3,ord
}
note this same rotation can be reused for faces xz1,xy1,xz1,xy2
maybe:
rotslice(
{xz2,1=row mode, 1 = row index, -1 = reverse},
{xy1,1, 1, -1},
{xz1,1, 1, 1 = ordinary},
{xy2,2=col mode,3 = col index, 1}
)
--]]
elseif math.abs(view.y)<math.abs(view.z) then -- horizontal
if view.z>0 then rot = 2 else rot = 3 end
else
if view.y>0 then rot = 4 else rot = 5 end
end
self.label("face: " .. face ..", rotation: " .. surfdata[face].rotations[rot])
render_cube()
elseif event.x == p.x+n+2 then
self.label("yz2")
if math.abs(view.x)>viewlim then
yz2 = rotccw(yz2);
end
render_cube()
elseif event.z == p.z then
self.label("xy1")
if math.abs(view.z)>viewlim then
xy1 = rotcw(xy1);
end
render_cube()
elseif event.z == p.z+n+1 then
self.label("xy2")
if math.abs(view.z)>viewlim then
xy2 = rotccw(xy2);
end
render_cube()
elseif event.y == p.y+1 then
if math.abs(view.y)>viewlim then
xz1 = rotccw(xz1);
end
render_cube()
self.label("xz1")
elseif event.y == p.y+n+2 then
self.label("xz2")
if math.abs(view.y)>viewlim then
xz2 = rotcw(xz2);
end
render_cube()
end
--self.label(serialize(event))
end
-- ideas:
-- use whole full cube : array with n^3 elements, only border rendered.
-- PROS: easy to get slices then and rotate them! CONS: much more memory used for larger cubes
--

View File

@ -3,23 +3,26 @@
if not init then
spos = self.spawnpos(); spos.x = spos.x +5; spos.z = spos.z +5;
for i = 1, 2 do
for i = 1, 2 do -- set up 4 boxes
for j = 1,2 do
puzzle.set_node({x=spos.x+i,y=spos.y,z=spos.z+j}, {name = "basic_robot:buttonFFFFFF"})
puzzle.set_node({x=spos.x+i,y=spos.y,z=spos.z+j}, {name = "basic_robot:buttonwhite"})
end
end
init = true
players = find_player(5);
if not players then say("no players nearby") self.remove() end
say("BOX PUSH demo. punch the white box to move it around ")
self.label("BOX PUSH demo. punch the white box to move it around.\npush it into blue block to make it disappear.")
pushables = {[1] = true} -- button types
canpushnodes = {["air"] = 1, ["basic_robot:button8080FF"] = 2} -- 1 push node, 2 absorb node
canpushnodes = {["air"] = 1, ["basic_robot:buttonblue"] = 2} -- 1 push node, 2 absorb node
self.listen_punch(self.pos()) -- robot will now read punch button events in 32x32 box area
end
event = keyboard.get()
if event then
if event then -- there was punch event
local boxtype = event.type
if pushables[boxtype] then
player = puzzle.get_player(event.puncher)

View File

@ -19,7 +19,7 @@ if not init then
board[i]={};
for j = 1,n do
k=k+1
board[i][j]=7+ret[k] -- 7 numbers, 82 letters
board[i][j]=17+ret[k] -- 7 numbers, 82 letters
end
end
board[math.random(n)][math.random(n)] = 0

View File

@ -43,7 +43,7 @@
SOKOBAN_WALL = "moreblocks:cactus_brick"
SOKOBAN_FLOOR = "default:silver_sandstone"
SOKOBAN_GOAL = "default:aspen_tree"
SOKOBAN_BOX = "basic_robot:buttonFFFFFF"
SOKOBAN_BOX = "basic_robot:buttonwhite"
load_level = function(lvl)

113
scripts/games/wordle.lua Normal file
View File

@ -0,0 +1,113 @@
--wordle game by rnd (2022), made in 15 minutes
-- 5 letter word is picked randomly
-- you have 6 tries to guess the word, write it in and it will color letters:
-- green = correct letter, correct place, yellow = correct letter, wrong place,
-- gray = letter not in word!
if not init then init = true
-- load this from file..
wordlist = {
"pulse", "audio", "solar", "bacon", "laser", "pizza", "maybe", "guess", "stuff",
"seven", "world", "about", "again", "heart", "water", "happy", "sixty", "board",
"month", "angel", "death", "green", "music", "fifty", "three", "party", "piano",
"mouth", "woman", "sugar", "amber", "dream", "apple", "laugh", "tiger", "faith",
"earth", "river", "money", "peace", "forty", "words", "smile", "abate", "house",
"alone", "watch", "lemon", "south", "erica", "anime", "after", "santa", "admin",
"jesus", "china", "blood", "megan", "thing", "light", "david", "cough", "story",
"power", "india", "point", "today", "anger", "night", "glory", "april", "candy",
"puppy", "above", "phone", "vegan", "forum", "irish", "birth", "other", "grace",
"queen", "pasta", "plant", "smart", "knife", "magic", "jelly", "black", "media",
--100
"honor", "cycle", "truth", "zebra", "train", "bully", "brain", "mango", "under",
"dirty", "robot", "eight", "fruit", "panda", "truck", "field", "bible", "radio",
"dance", "voice", "smith", "sorry", "paris", "being", "lover", "never", "royal",
"venus", "metal", "penny", "honey", "color", "cloud", "scarf", "state", "value",
"mouse", "north", "bread", "daily", "paper", "beard", "alive", "place", "chair",
"badge", "worth", "crazy", "photo", "dress", "table", "cross", "clear", "white",
"march", "ocean", "belly", "ninja", "young", "range", "maria", "great", "sweet",
"karen", "scent", "beach", "space", "clock", "allah", "peach", "sound", "fever",
"youth", "union", "daisy", "plate", "eagle", "human", "start", "funny", "right",
"molly", "guard", "witch", "dough", "think", "image", "album", "socks", "catch",
--200
"sleep", "below", "organ", "peter", "cupid", "storm", "silly", "berry", "rhyme",
"carol", "olive", "leave", "whale", "james", "brave", "asian", "every", "arrow",
"there", "ebola", "later", "bacon", "local", "graph", "super", "obama", "brown",
"onion", "simon", "globe", "alley", "stick", "spain", "daddy", "scare", "quiet",
"touch", "clean", "liver", "lucky", "given", "lunch", "child", "clone", "glove",
"meter", "nancy", "plain", "solid", "uncle", "shout", "bored", "early", "video",
"brian", "cheer", "texas", "often", "sushi", "chaos", "tulip", "alien", "apart",
"fight", "coach", "force", "trust", "angle", "beast", "craft", "chess", "skull",
"order", "judge", "swing", "drive", "shine", "stand", "stage", "oscar", "ember",
"worry", "drama", "raven", "sight", "short", "botox", "unity", "horse", "trout",
--300
"devil", "spoon", "clown", "grand", "gnome", "binge", "paula", "award", "quick",
"cause", "close", "scout", "snail", "purse", "topic", "teeth", "sauce", "share",
"along", "worse", "movie", "reach", "giant", "quack", "shark", "first", "count",
"agent", "shelf", "grape", "drink", "skate", "wrong", "cream", "snake", "heavy",
"tooth", "heard", "idiot", "scary", "chain", "break", "valve", "agony", "salad",
"shell", "scope", "tupac", "track", "final", "crown", "group", "wagon", "doing",
"robin", "false", "small", "block", "brush", "salsa", "grain", "wings", "arian",
"allow", "habit", "stove", "tower", "stars", "total", "plane", "comet", "tweet",
"abide", "frown", "roman", "grant", "ready", "blast", "treat", "poppy", "biome",
"oasis", "roger", "ghost", "abode", "abort", "court", "petal", "flood", "cider",
--400
"orion", "extra", "pearl", "gator", "rough", "koala", "melon", "price", "alpha",
"smell", "chase", "fresh", "quest", "store", "grove", "round", "sense", "chest",
"fancy", "loose", "match", "pluto", "sport", "sheep", "crime", "grade", "pride",
"lance", "billy", "virus", "twerp", "kenya", "model", "ledge", "tired", "level",
"juice", "quart", "amish", "flame", "event", "offer", "twist", "actor", "maple",
"hinge", "proud", "boone", "nasty", "hyper", "paint", "press", "patch", "mercy",
"baker", "broom", "rhino", "putin", "greed", "inter", "curve", "giver", "flute",
"class", "hyena", "stock", "sting", "fable", "loved", "chant", "focus", "bench",
"birds", "brand", "otter", "goose", "ought", "boron", "dodge", "sloth", "eager",
"serve", "fella", "cover", "genre", "cable", "apron", "worst", "tommy", "egypt"
--500
}
word = wordlist[math.random(#wordlist)];
letters = {}
for i = 1,string.len(word) do letters[string.sub(word,i,i)] = true end
responses = {};
maxtries = 6
self.label("GUESSWORD " .. word)
self.label("WORDLE GAME\n\nINSTRUCTIONS:\ntry to guess 5 letter word by typing it in chat like\n\n:guess\n\nyou have " .. maxtries .. " tries.\n"..
"gray color indicates letter is not in word, yellow color indicates letter is\nin word but not in correct position. green color indicates correct letter at\ncorrect position")
self.listen(1)
end
speaker,msg = self.listen_msg()
if #responses == maxtries then
responses[#responses+1] = minetest.colorize("red","GAME OVER! correct word was " .. word)
self.label(table.concat(responses,"\n"))
end
if msg and #responses<maxtries and string.sub(msg,1,1)==":" and string.len(msg)-1 == string.len(word) then
msg = string.sub(msg,2)
local out = {}
local guessed = true
for i = 1,string.len(word) do
local c = string.sub(msg,i,i)
local color = "white"
if not letters[c] then
color = "gray"
elseif c == string.sub(word,i,i) then
color = "green"
else color = "yellow"
end
if color ~= "green" then guessed = false end
out[#out+1] = minetest.colorize(color, c)
end
responses[#responses+1] = (#responses+1) .. ". " .. table.concat(out)
if guessed == true then
responses[#responses+1] = "YOU WIN!"
for i = 1,maxtries-#responses do responses[#responses+1] = " " end
end
self.label(table.concat(responses,"\n"))
end

40
scripts/math/calender.lua Normal file
View File

@ -0,0 +1,40 @@
-- calender by rnd, 30 minutes with bugfixes
dayofweek = function(y,m,d)
local offsets = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
if m<3 then y=y-1 end
return (y+math.floor(y/4)-math.floor(y/100)+math.floor(y/400)+offsets[m]+d) % 7+1
end
y=2000
m=8
d=1
--say(dayofweek(y,m,d))
make_calender = function(y,m)
local start_day = dayofweek(y,m,1)
local months = {31,29,31,30,31,30,31,31,30,31,30,31};
if y%4==0 and (y%100~=0 or y%400 == 0) then months[2]= 30 end -- feb has 30 days on leap year
local out = minetest.colorize("red",m.."/"..y).."\nsun mon tue wed thu fri sat\n"
out = out .. string.rep("__ ",start_day-1)
local i = start_day;
local idx = 1;
while idx<=months[m] do
out = out .. string.format("%02d",idx) .. " ";
if i%7 ==0 then out = out .."\n" end
idx = idx+1
i=i+1
end
return out
end
ret = {}
for m = 1,12 do
ret[#ret+1]=make_calender(y,m)
end
self.label(table.concat(ret,"\n\n"))

View File

@ -0,0 +1,59 @@
-- mandelbrot by rnd,2022 , made in 30 mins
if not init then init = true
n=100
local itermin = 10; -- check quicker if diverge!
local itermax = 250; -- max iterations
local delta = 0.00001^2; -- convergence difference
nodes = {
"white","yellow","orange","red",
"magenta","purple","blue","cyan",
"green","dark_green","brown","tan",
"light_grey","medium_grey","dark_grey","black"
}
for i = 1,#nodes do nodes[i] = "basic_robot:button"..nodes[i] end
get_pixel = function()
local iter = 0
local zr=0 ; local zi=0 ;
for i = 1, itermin do
local zrn=zr^2-zi^2+cr;
local zin=2*zr*zi+ci
zr=zrn
zi=zin
end
if zr^2+zi^2>1 then return -1 end
local zrn=zr^2-zi^2+cr;
local zin=2*zr*zi+ci
if (zrn-zr)^2+(zin-zi)^2< delta then return 1 end
for i = 1, itermax do
local zrn=zr^2-zi^2+cr;
local zin=2*zr*zi+ci
if (zrn-zr)^2+(zin-zi)^2< delta then return i-1 end
zr=zrn
zi=zin
end
return itermax-1
end
pos = self.pos()
local nnodes = #nodes
for x=1,n do
for y=1,n do
cr=2*x/n-1; ci=2*y/n-1
local col = get_pixel()
if col>0 then
col = math.floor(nnodes*col/itermax)
minetest.swap_node({x=pos.x+x,y=pos.y,z=pos.z+y},{name = nodes[col+1]})
end
end
end
self.remove()
end

View File

@ -0,0 +1,50 @@
if not name then
name = "rnd"
player = minetest.get_player_by_name(name)
texs = {
"flowers_chrysanthemum_green.png",
"flowers_dandelion_white.png",
"flowers_dandelion_yellow.png",
"flowers_geranium.png",
"flowers_mushroom_brown.png",
"flowers_mushroom_red.png",
"flowers_rose.png",
"flowers_tulip.png",
"flowers_tulip_black.png",
"flowers_viola.png",
}
local ent = _G.basic_robot.data[self.name()].obj:get_luaentity();
ent.timestep = 0.25
_G.minetest.forceload_block(self.pos(),true)
add_part = function(pos)
local vdir = player:get_look_dir()
local speed = 8
vdir.x=vdir.x*speed
vdir.y=vdir.y*speed
vdir.z=vdir.z*speed
minetest.add_particle(
{
pos = {x=pos.x, y=pos.y+1.5, z=pos.z},
velocity = vdir, --{x=0, y=0, z=0},
acceleration = {x=0, y=-1, z=0},
expirationtime = 15,
size = 10,
collisiondetection = true,
collision_removal = false,
object_collision = false,
vertical = false,
texture = texs[math.random(#texs)],
glow = 0
})
end
p1 = player:getpos();
end
p2 = player:getpos()
local dist = ((p2.x-p1.x)^2+(p2.y-p1.y)^2+(p2.z-p1.z)^2)^0.5
if player:get_wielded_item():to_string()=="flowers:dandelion_yellow" then add_part(p2) end
--if dist>1 then p1 = player:getpos() add_part(p1) end

View File

@ -1,7 +1,12 @@
-- REDSTONE EMULATOR & EDITOR
--v 06/28/2018a
--v 28/06/2018a, fixed 28/08/2022a
if not init then
dout = function(text) say(text,"rnd") end
seri = function(tab)
local out = {} for k,v in pairs(tab) do if type(v) ~= "function" then out[#out+1] = k .. " = " .. v end end
return "{"..table.concat(out,",") .."}"
end
local players = find_player(5);
if not players then
name = "";
@ -12,17 +17,17 @@ if not init then
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
inv:set_stack("main", 12, puzzle.ItemStack("basic_robot:button_284 999")) -- giver 23 150/284
inv:set_stack("main", 13, puzzle.ItemStack("basic_robot:button_285 999")) -- checker 24 151/285
inv:set_stack("main", 2, puzzle.ItemStack("basic_robot:button_283 999")) -- switch 9 = 283/284
inv:set_stack("main", 3, puzzle.ItemStack("basic_robot:button_285 999")) -- button 7 = 285/286
inv:set_stack("main", 4, puzzle.ItemStack("basic_robot:button_287 999")) -- equalizer 61 = 287
inv:set_stack("main", 5, puzzle.ItemStack("basic_robot:button_288 999")) -- setter 15 = 288
inv:set_stack("main", 6, puzzle.ItemStack("basic_robot:button_289 999")) -- piston 171 = 289
inv:set_stack("main", 7, puzzle.ItemStack("basic_robot:button_292 999")) -- delayer 232 = 292
inv:set_stack("main", 9, puzzle.ItemStack("basic_robot:button_291 999")) -- NOT 33 = 291
inv:set_stack("main", 10, puzzle.ItemStack("basic_robot:button_290 999")) -- diode 175 = 290
inv:set_stack("main", 11, puzzle.ItemStack("basic_robot:button_293 999")) -- platform 22 = 293
inv:set_stack("main", 12, puzzle.ItemStack("basic_robot:button_294 999")) -- giver 23 150/294
inv:set_stack("main", 13, puzzle.ItemStack("basic_robot:button_295 999")) -- checker 24 151/295
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
@ -34,6 +39,7 @@ if not init then
end
init = true
self.listen_punch(self.pos()); -- attach punch listener
self.spam(1)
self.label(colorize("orange","REDSTONE EMULATOR/EDITOR"))
@ -51,13 +57,13 @@ if not init then
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"})
puzzle.set_node(pos,{name = "basic_robot:button_284"})
local meta = puzzle.get_meta(pos);
if not meta then return end
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"})
puzzle.set_node(pos,{name = "basic_robot:button_283"})
local meta = puzzle.get_meta(pos);
if not meta then return end
local n = meta:get_int("n");
@ -69,13 +75,13 @@ if not init then
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"})
puzzle.set_node(pos,{name = "basic_robot:button_286"})
local meta = puzzle.get_meta(pos);
if not meta then return end
local n = meta:get_int("n");
minetest.after(1, function()
puzzle.set_node(pos,{name = "basic_robot:button_275"})
puzzle.set_node(pos,{name = "basic_robot:button_285"})
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
@ -294,25 +300,25 @@ if not init then
-- 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
[284] = {giver_action,0}, -- GIVER: give player item below it when activated and activate targets after that
[285] = {checker_action,0}, -- CHECKER: check if player has block below it in inventory, remove it and activate targets after that
[285] = {button_action,1}, -- BUTTON, 1 means it activates(ON) on punch
[283] = {toggle_button_action,1}, -- TOGGLE BUTTON_OFF
[284] = {toggle_button_action,0}, -- TOGGLE BUTTON_ON, 0 means it deactivates
[294] = {giver_action,0}, -- GIVER: give player item below it when activated and activate targets after that
[295] = {checker_action,0}, -- CHECKER: check if player has block below it in inventory, remove it and activate targets after that
}
-- 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
["basic_robot:button_285"] = button_action, -- BUTTON, what action to do on activate
["basic_robot:button_283"] = toggle_button_action, -- TOGGLE BUTTON_OFF
["basic_robot:button_284"] = toggle_button_action, -- TOGGLE BUTTON_ON
["basic_robot:button_288"] = setter_action, -- SETTER
["basic_robot:button_287"] = equalizer_action, -- EQUALIZER
["basic_robot:button_289"] = piston_action, -- PISTON
["basic_robot:button_293"] = platform_action, -- PLATFORM
["basic_robot:button_292"] = delayer_action, -- DELAYER
["basic_robot:button_290"] = diode_action, -- DIODE
["basic_robot:button_291"] = not_action, -- NOT
}
@ -324,19 +330,19 @@ if not init then
-- 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: target1 defines what material wall will use, target2/3 defines where wall will be", -- setter
["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
["basic_robot:button_285"] = "button: now select one or more targets", -- button
["basic_robot:button_283"] = "switch: now select one or more targets", -- switch OFF
["basic_robot:button_284"] = "switch: now select one or more targets", -- switch ON
["basic_robot:button_288"] = "setter: target1 defines what material wall will use, target2/3 defines where wall will be", -- setter
["basic_robot:button_287"] = "equalizer: target1 and target2 are for comparison, other targets are activated", -- equalizer
["basic_robot:button_289"] = "piston: push block at target1 in direction away from piston", -- equalizer
["basic_robot:button_293"] = "platform: select target1 to set origin, target2 for direction", -- PLATFORM
["basic_robot:button_292"] = "delayer: distance from delayer to target1 determines delay", -- delayer
["basic_robot:button_290"] = "diode: only pass through ON signal", -- DIODE
["basic_robot:button_291"] = "NOT gate: negates the signal", -- NOT
["basic_robot:button_284"] = "GIVER: give player item below it when activated and activate targets after that",
["basic_robot:button_285"] = "CHECKER: check if player has block below it in inventory, remove it and activate targets after that",
["basic_robot:button_294"] = "GIVER: give player item below it when activated and activate targets after that",
["basic_robot:button_295"] = "CHECKER: check if player has block below it in inventory, remove it and activate targets after that",
}
linker_use = function(pos)
@ -358,12 +364,12 @@ if not init then
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 .."]" ;
local form = "size[5,"..(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[0,".. (0.75*i-0.5) .. ";1.25,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 " .. "]"..
"button_exit[2,".. (0.75*i-0.5) .. ";1.25,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);
@ -385,7 +391,7 @@ if not init then
expirationtime = 5,
velocity = {x=0, y=0,z=0},
size = 18,
texture = "010.png",
texture = "puzzle_button_on.png",
acceleration = {x=0,y=0,z=0},
collisiondetection = true,
collision_removal = true,
@ -429,7 +435,7 @@ if not init then
expirationtime = 5,
velocity = {x=0, y=0,z=0},
size = 18,
texture = "009.png",
texture = "puzzle_button_off.png",
acceleration = {x=0,y=0,z=0},
collisiondetection = true,
collision_removal = true,
@ -447,7 +453,8 @@ end
opcount = 0
event = keyboard.get() -- handle keyboard
if event then
if event and not player_:get_player_control().sneak 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()
@ -480,7 +487,7 @@ if sender then
expirationtime = 5,
velocity = {x=0, y=0,z=0},
size = 18,
texture = "010.png",
texture = "puzzle_button_on.png",
acceleration = {x=0,y=0,z=0},
collisiondetection = true,
collision_removal = true,

View File

@ -0,0 +1,204 @@
-- COPY PASTE ROBOT by rnd: c1 c2 r = markers, c = copy p = paste, rotz = rotate 90 deg cw z-axis, s = set
-- command parameters :
-- s nodename node_step
-- copy:
-- c1,c2 set markers, r set reference, c = copy,
-- p = paste at player position (reference is put there)
-- rotate:
-- c1,c2 set area, rotz = rotate 90 deg around z-axis
-- replace:
-- c1,c2 set area, then 'replace node1 node2'
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 = {};
display_marker = function(pos,label)
minetest.add_particle(
{
pos = pos,
expirationtime = 10,
velocity = {x=0, y=0,z=0},
size = 9,
texture = label..".png",
acceleration = {x=0,y=0,z=0},
})
end
self.listen(1)
self.label("")
-- self.label("WorldEdit Bot\ncommands: c1 c2 r c p s rotz")
end
speaker, msg = self.listen_msg()
if speaker == "rnd" or speaker == "noah" then
local args = {}
for word in string.gmatch(msg,"%S+") do args[#args+1]=word end
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 p.y<0 then p.y = p.y +1 end -- needed cause of minetest bug
if args[1] == "c1" then
paste.src1 = {x=p.x,y=p.y,z=p.z};say("marker 1 set at " .. p.x .. " " .. p.y .. " " .. p.z,speaker)
display_marker(p,"puzzle_button_off") -- c
elseif args[1] == "c2" then
paste.src2 = {x=p.x,y=p.y,z=p.z};say("marker 2 set at " .. p.x .. " " .. p.y .. " " .. p.z,speaker)
display_marker(p,"puzzle_button_on") -- c
elseif args[1] == "r" then
paste.ref = {x=p.x,y=p.y,z=p.z};say("reference set at " .. p.x .. " " .. p.y .. " " .. p.z,speaker)
display_marker(p,"puzzle_diode") -- r
elseif args[1] == "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 args[1] == "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 ",speaker);
elseif args[1] == "s" then -- set node
local nodename = args[2] or "air"
local randomized = (nodename=="random")
local btncolors = {
"white","yellow","orange","red","magenta","purple","blue","cyan",
"green","dark_green","brown","tan","light_grey","medium_grey","dark_grey","black"
}
for i = 1,#btncolors do btncolors[i] = "basic_robot:button"..btncolors[i] end
if not minetest.registered_nodes[nodename] and not randomized then return end
local step = args[3] or 1;
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;
for i = x1,x2,step do
for j = y1,y2,step do
for k = z1,z2,step do
if randomized then nodename = btncolors[math.random(16)] end
minetest.set_node({x=i,y=j,z=k}, {name = nodename});
end
end
end
say((x2-x1+1)*(y2-y1+1)*(z2-z1+1) .. " nodes set to " .. nodename,speaker)
elseif args[1] == "replace" then -- replace
local node1 = args[2]
local node2 = args[3]
local count = 0
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);
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 == node1 then
_G.minetest.swap_node({x=i,y=j,z=k},{name = node2})
count = count +1;
end
end
end
end
say(count .. " nodes replaced ");
elseif args[1] == "rotz" then -- rotate around z axis, center of selection
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 d = x2-x1; if z2-z1<d then z2 = z1+d else d = z2-z1; x2 = x1+d end -- will be rotated as square in xz
local rotzd = {
[0]=1,[1]=2,[2]=3,[3]=0,
[7]=12,[12]=9,[9]=18,[18]=7,
[8]=17,[17]=6,[6]=15,[15]=8,
[19]=4,[4]=13,[13]=10,[10]=19,
[20]=23,[23]=22,[22]=21,[21]=20,
}
local count = 0; local step = 1
local data = {}; -- copy first
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});
minetest.swap_node({x=i,y=j,z=k},{name = "air"})
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
count = count +1;
end
end
end
end
-- (x,z)->(z,-x)
-- square rotate around center: x,z -> x-dx/2, z-dz/2 ->z-dz/2,dx/2-x -> (z, dx-x)
-- (x,z) -> (z,x1+x2-x)
--[[
x1,z1
*
* x1,z1
add offset to put middle of square into 0,0 and then back..
x->x-x1-dx/2, z-z1-dz/2 -> z-z1-dz/2, x1-dx/2-x ->
z-z1-dz/2+x1+dx/2,x1-dx/2-x+z1+dz/2 =
z-z1+x1,z1+x1-x
--]]
for i = x1,x2,step do
for j = y1,y2,step do
for k = z1,z2,step 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 -- correct position, rotated 90deg, TODO!
local node = pdata
node.param2 = rotzd[node.param2] or 0;
minetest.swap_node({x=k+x1-z1,y=j,z=x1+z1-i}, node)
end
end
end
end
say(count .. " nodes rotated around z-axis");
end
end

View File

@ -13,6 +13,7 @@ for i = 1, #objs do
local luaent = objs[i]:get_luaentity();
local entname = ""
if luaent then
--entname = serialize(luaent)
entname = luaent.itemstring
if entname == "robot" then entname = entname .. " " .. luaent.name end
elseif objs[i]:is_player() then
@ -20,7 +21,7 @@ for i = 1, #objs do
end
local phash = round(p.x) .. " " .. round(p.y) .. " " .. round(p.z);
ret[phash] = (ret[phash] or "") .. entname .. ", "
if entname then ret[phash] = (ret[phash] or "") .. entname .. ", " end
end
local out = {};
@ -36,6 +37,9 @@ end
self.label("#objects " .. #objs .. "\n" .. table.concat(res, "\n"))
--book.write(1,"",("#objects " .. #objs .. "\n" .. table.concat(res, "\n")))
--self.remove()
end

View File

@ -3,7 +3,7 @@
-- say: t TEXT\nTEXT...
if not init then init = true
name = "_"
names = {["rnd"]=true,["PrairieWind"] = true}
get_dir = function(view)
local dir
@ -15,7 +15,7 @@ if not init then init = true
return dir
end
render_text = function(text)
render_text = function(text,name)
local player = minetest.get_player_by_name(name)
local pos = player:get_pos()
local dir = get_dir(player:get_look_dir())
@ -37,7 +37,7 @@ if not init then init = true
end
speaker,msg = self.listen_msg()
if speaker == name and string.sub(msg,1,2) == "t " then
if names[speaker] and string.sub(msg,1,2) == "t " then
render_text(string.sub(msg,3))
render_text(string.sub(msg,3),speaker)
end

View File

@ -0,0 +1,22 @@
from http.server import HTTPServer,SimpleHTTPRequestHandler
server_address = ('0.0.0.0', 80) # address 0.0.0.0 makes it listen to all requests from anywhere
class HTTPRequestHandler(SimpleHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
print(body.decode('utf-8')) #log display
self.send_response(200)
self.end_headers()
def do_GET(self):
print("D " + self.path)
SimpleHTTPRequestHandler.do_GET(self) #process using default do_GET
httpd = HTTPServer(server_address, HTTPRequestHandler)
httpd.serve_forever()

16
scripts/web/index.html Normal file
View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<body>
<h2>rnd's web robot</h2>
<form action="" method = "">
<label for="cmd">command:</label><br>
<input type="text" id="cmd" name="cmd" value=""><br>
<input type="submit" value="Submit">
</form>
</body>
</html>

62
scripts/web/irc bot.lua Normal file
View File

@ -0,0 +1,62 @@
-- irc_bot, 05/02/2022 by rnd
-- adds irc bot commands with password login
if not init then init = true
_G.basic_robot.ircbot = {}; ircbot = _G.basic_robot.ircbot
ircbot.user_list = {} -- [user] = true, must login first
ircbot.auth_data = { -- [user] = {pass_hash,level,robot_name}
["r_n_d"] = {"5yfRRkrhJDbomacm2lsvEdg4GyY",3,"rnd1"},
["Noah"] = {"5yfRRkrhJDbomacm2lsvEdg4GyY",3,"noah1"}
}; --
robotname = self.name()
_G.irc.register_bot_command("c", {
params = "",
description = "",
func = function(usr,msg)
-- user not logged in yet?
local lvl = ircbot.user_list[usr.nick]
if not lvl then
if msg == "" then return false,"basic_robot: login first using: c $password" end
if not ircbot.auth_data[usr.nick] then return false, "basic_robot: you are not in user database. please contact server admin." end
if ircbot.auth_data[usr.nick][1] == minetest.get_password_hash("", msg) then
ircbot.user_list[usr.nick] = ircbot.auth_data[usr.nick][2]
local msg = "basic_robot: Logged in as " .. usr.nick ..", level " .. ircbot.user_list[usr.nick]
lvl = ircbot.auth_data[usr.nick][2]
local robotname = ircbot.auth_data[usr.nick][3]
if lvl>=3 then msg = msg .. ". you can use 'c !lua_cmd' to run lua_cmd in robot " .. robotname .. " sandbox" end
return false, msg
else
return false,"basic_robot: wrong password!"
end
end
-- action here : DEMO just displays message once logged in
local c = string.sub(msg,1,1)
if c~="!" or lvl<3 then _G.basic_robot.ircmsg = msg return end
local ScriptFunc, CompileError = _G.loadstring( string.sub(msg,2))
if CompileError then return false, CompileError end
local robotname = ircbot.auth_data[usr.nick][3]
_G.setfenv( ScriptFunc, _G.basic_robot.data[robotname].sandbox ) -- run code in robot sandbox
local Result, RuntimeError = _G.pcall( ScriptFunc );
if result then return false, _G.tostring(Result) end
if RuntimeError then return false,RuntimeError end
end
})
-- how to send msg to irc user
ircchat = minetest.registered_chatcommands["irc_msg"].func;
name = "r_n_d" -- client on irc you want to send msg too
-- ircchat("ROBOT", name .." " .. "hello irc world") -- chat will appear as coming from <ROBOT> on skyblock
end
self.label(_G.basic_robot.ircmsg or "")

View File

@ -0,0 +1 @@
D:\prog\programming\Python\Python37-32\python https_server.py

24
settings.lua Normal file
View File

@ -0,0 +1,24 @@
-- SETTINGS FOR BASIC_ROBOT
local b = basic_robot;
b.call_limit = {50,200,1500,10^9}; -- how many execution calls per script run allowed, for auth levels 0,1,2 (normal, robot, puzzle, admin)
b.count = {2,6,16,128} -- how many robots player can have
b.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches
b.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running mod, password used for authentifications
b.admin_bot_pos = {x=0,y=1,z=0} -- position of admin robot spawner that will be run automatically on server start
b.maxoperations = 10; -- how many operations (dig, place,move,...,generate energy,..) available per run, 0 = unlimited
b.dig_require_energy = true; -- does robot require energy to dig?
b.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
["moreblocks:circular_saw"] = true,
["craft_guide:sign_wall"] = true,
["basic_machines:battery_0"] = true,
["basic_machines:battery_1"] = true,
["basic_machines:battery_2"] = true,
["basic_machines:generator"] = true,
}
b.http_api = minetest.request_http_api();

BIN
textures/robochars.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB