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 end
basic_robot.commands.write_keyevent = write_keyevent;
local button_punched = function(pos, node, player,type) local button_punched = function(pos, node, player,type)
local name = player:get_player_name(); if name==nil then return end local name = player:get_player_name(); if name==nil then return end
local round = math.floor; local round = math.floor;
@ -609,8 +611,10 @@ local button_punched = function(pos, node, player,type)
end end
end end
local register_robot_button = function(R,G,B,type) local buttoncolors = {};
minetest.register_node("basic_robot:button"..R..G..B, 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", description = "robot button",
tiles = {"robot_button.png^[colorize:#"..R..G..B..":180"}, tiles = {"robot_button.png^[colorize:#"..R..G..B..":180"},
@ -624,12 +628,14 @@ local register_robot_button = function(R,G,B,type)
end end
local register_robot_button_number = function(number,type) 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, minetest.register_node("basic_robot:button"..number,
{ {
description = "robot button", description = "robot button",
tiles = {"robot_button".. number .. ".png"}, tiles = {texname},
inventory_image = "robot_button".. number .. ".png", inventory_image = texname,
wield_image = "robot_button".. number .. ".png", wield_image = texname,
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false, is_ground_content = false,
@ -640,12 +646,14 @@ end
local register_robot_button_char = function(number,type) 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, minetest.register_node("basic_robot:button_"..number,
{ {
description = "robot button", description = "robot button",
tiles = {string.format("%03d",number).. ".png"}, tiles = {texname},
inventory_image = string.format("%03d",number).. ".png", inventory_image = texname,
wield_image = string.format("%03d",number).. ".png", wield_image = texname,
is_ground_content = false, is_ground_content = false,
groups = {cracky=3,not_in_craft_guide = 1}, groups = {cracky=3,not_in_craft_guide = 1},
paramtype2 = "facedir", paramtype2 = "facedir",
@ -654,7 +662,8 @@ minetest.register_node("basic_robot:button_"..number,
end end
local register_robot_button_custom = function(number,texture) 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", description = "robot button",
tiles = {texture .. ".png"}, tiles = {texture .. ".png"},
@ -666,33 +675,66 @@ minetest.register_node("basic_robot:button_"..number,
}) })
end 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("FF","FF","FF",1);
register_robot_button("80","80","80",2); register_robot_button("80","80","80",2);
register_robot_button("FF","80","80",3); register_robot_button("FF","80","80",3);
register_robot_button("80","FF","80",4); register_robot_button("80","FF","80",4);
register_robot_button("80","80","FF",5); register_robot_button("80","80","FF",5);
register_robot_button("FF","FF","80",6); register_robot_button("FF","FF","80",6);
--]]
for i = 0,9 do register_robot_button_number(i,i+7) 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+17) end 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(283,"puzzle_switch_off")
register_robot_button_custom(274,"puzzle_switch_on") register_robot_button_custom(284,"puzzle_switch_on")
register_robot_button_custom(275,"puzzle_button_off") register_robot_button_custom(285,"puzzle_button_off")
register_robot_button_custom(276,"puzzle_button_on") register_robot_button_custom(286,"puzzle_button_on")
register_robot_button_custom(277,"puzzle_equalizer") register_robot_button_custom(287,"puzzle_equalizer")
register_robot_button_custom(278,"puzzle_setter") register_robot_button_custom(288,"puzzle_setter")
register_robot_button_custom(279,"puzzle_piston") register_robot_button_custom(289,"puzzle_piston")
register_robot_button_custom(280,"puzzle_diode") register_robot_button_custom(290,"puzzle_diode")
register_robot_button_custom(281,"puzzle_NOT") register_robot_button_custom(291,"puzzle_NOT")
register_robot_button_custom(282,"puzzle_delayer") register_robot_button_custom(292,"puzzle_delayer")
register_robot_button_custom(283,"puzzle_platform") register_robot_button_custom(293,"puzzle_platform")
register_robot_button_custom(284,"puzzle_giver") register_robot_button_custom(294,"puzzle_giver")
register_robot_button_custom(285,"puzzle_checker") register_robot_button_custom(295,"puzzle_checker")
@ -730,22 +772,12 @@ basic_robot.commands.keyboard = {
local nodename; local nodename;
if type == 0 then if type == 0 then
nodename = "air" nodename = "air"
elseif type == 1 then elseif type < 17 then
nodename = "basic_robot:buttonFFFFFF"; nodename = buttoncolors[type]
elseif type == 2 then elseif type>=17 and type <= 26 then
nodename = "basic_robot:button808080"; nodename = "basic_robot:button"..(type-17);
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);
else else
nodename = "basic_robot:button_"..(type-17); nodename = "basic_robot:button_"..(type-27);
end end
minetest.swap_node(pos, {name = nodename}) minetest.swap_node(pos, {name = nodename})
@ -988,7 +1020,7 @@ basic_robot.commands.machine = {
check_operations(name,6, true) 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 pos = basic_robot.data[name].spawnpos; -- position of spawner block
local inv = minetest.get_meta(pos):get_inventory(); 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 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 local energy = 0; -- can only do one step at a run time
energy = data.menergy or 0; 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 if not tdata.menergy then tdata.menergy = 0 end
tdata.menergy = tdata.menergy + amount 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 = {}; basic_robot = {};
------ SETTINGS -------- basic_robot.version = "2022/02/02b";
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.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches dofile(minetest.get_modpath("basic_robot").."/settings.lua") -- read configuration SETTINGS
basic_robot.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running mod, password used for authentifications
basic_robot.admin_bot_pos = {x=0,y=1,z=0} -- position of admin robot spawner that will be run automatically on server start -- structures for storing robot data
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";
basic_robot.gui = {}; local robogui = basic_robot.gui -- gui management basic_robot.gui = {}; local robogui = basic_robot.gui -- gui management
basic_robot.data = {}; -- stores all robot related data 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 -- SANDBOX for running lua code isolated and safely
function getSandboxEnv (name) function getSandboxEnv (name)
local authlevel = basic_robot.data[name].authlevel or 0; 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 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 = local env =
{ {
_Gerror = error, _Gerror = error,
@ -93,9 +75,11 @@ function getSandboxEnv (name)
return commands.craft(item, mode, idx, amount, name) return commands.craft(item, mode, idx, amount, name)
end, 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 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() coroutine.yield()
end
end, end,
self = { 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, 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, name = function() return name end,
operations = function() return basic_robot.data[name].operations 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) set_properties = function(properties)
if not properties then return end; local obj = basic_robot.data[name].obj; if not properties then return end; local obj = basic_robot.data[name].obj;
@ -173,7 +157,7 @@ function getSandboxEnv (name)
reset = function() reset = function()
local pos = basic_robot.data[name].spawnpos; local pos = basic_robot.data[name].spawnpos;
local obj = basic_robot.data[name].obj; 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, end,
set_libpos = function(pos) set_libpos = function(pos)
@ -351,6 +335,8 @@ function getSandboxEnv (name)
write = function(i,title,text) write = function(i,title,text)
if i<=0 or i > 32 then return nil end if i<=0 or i > 32 then return nil end
local inv = minetest.get_meta(basic_robot.data[name].spawnpos):get_inventory(); 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); local stack = basic_robot.commands.write_book(basic_robot.data[name].owner,title,text);
if stack then inv:set_stack("library", i, stack) end if stack then inv:set_stack("library", i, stack) end
end end
@ -369,7 +355,7 @@ function getSandboxEnv (name)
end, end,
}, },
rom = basic_robot.data[name].rom, rom = basic_robot.data[pname].rom,
string = { string = {
byte = string.byte, char = string.char, byte = string.byte, char = string.char,
@ -525,7 +511,7 @@ function getSandboxEnv (name)
setfenv( ScriptFunc, basic_robot.data[name].sandbox ) setfenv( ScriptFunc, basic_robot.data[name].sandbox )
local Result, RuntimeError = pcall( ScriptFunc ); local _, RuntimeError = pcall( ScriptFunc );
if RuntimeError then if RuntimeError then
minetest.chat_send_player(name, "#code.run: run error " .. RuntimeError ) minetest.chat_send_player(name, "#code.run: run error " .. RuntimeError )
return false return false
@ -592,10 +578,13 @@ function getSandboxEnv (name)
end end
-- code checker -- code checker
-- bugfixes:
-- player Midskip found problem with code checking, fixed
check_code = function(code) check_code = function(code)
--"while ", "for ", "do ","goto ", --"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 for _, v in pairs(bad_code) do
if string.find(code, v) then if string.find(code, v) then
return v .. " is not allowed!"; return v .. " is not allowed!";
@ -603,8 +592,7 @@ check_code = function(code)
end end
end end
identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
local 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 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 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 for k=1,#modes do
j = string.find(code,modes[k][1],i); j = string.find(code,modes[k][1],i);
if j and j<jmin then -- pick closest one if j and j<jmin then -- pick closest one
if string.sub(code,j-1,j-1) ~="\\" then
jmin = j jmin = j
mode = k mode = k
else
j=j+1;
end
end end
end end
if mode ~= 0 then -- found something if mode ~= 0 then -- found something
@ -634,10 +626,12 @@ local identify_strings = function(code) -- returns list of positions {start,end}
else else
_,j = string.find(code,modes[mode][2],i); -- search for closing pair _,j = string.find(code,modes[mode][2],i); -- search for closing pair
if not j then break end 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 ret[#ret][2] = j
mode = 0 mode = 0
end end
if pchar == "\\" then j=j+1 end
end end
i=j -- move to next position i=j -- move to next position
end end
@ -683,8 +677,8 @@ preprocess_code = function(script, call_limit) -- version 07/24/2018
when counter exceeds limit exit with error 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 -- process script to insert call counter in every function
local _increase_ccounter = " _Gc = _Gc + 1; if _Gc > " .. call_limit .. local _increase_ccounter = " _Gc = _Gc + 1; if _Gc > " .. call_limit ..
" then _Gerror(\"Execution count \".. _Gc .. \" exceeded ".. call_limit .. "\") end; " " 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! -- 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) -- (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 --return script:gsub("pause%(%)", "_c_ = 0; pause()") -- reset ccounter at pause
end end
@ -803,7 +797,7 @@ local function runSandbox( name)
end end
data.operations = basic_robot.maxoperations; data.operations = basic_robot.maxoperations;
data.t = os.clock() data.t = os.clock() -- timing
setfenv( ScriptFunc, data.sandbox ) setfenv( ScriptFunc, data.sandbox )
@ -1052,7 +1046,7 @@ minetest.register_entity("basic_robot:robot",{
minetest.set_node(pos, {name = "air"}); minetest.set_node(pos, {name = "air"});
--local privs = core.get_player_privs(self.owner);privs.interact = false; --local privs = core.get_player_privs(self.owner);privs.interact = false;
--core.set_player_privs(self.owner, privs); minetest.auth_reload() --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 end
local name = self.name; local name = self.name;
@ -1224,7 +1218,6 @@ local spawn_robot = function(pos,node,ttl)
if data == nil then if data == nil then
basic_robot.data[name] = {}; basic_robot.data[name] = {};
data = basic_robot.data[name]; data = basic_robot.data[name];
--data.rom = {};
end end
data.owner = owner; data.owner = owner;
@ -1707,7 +1700,6 @@ minetest.register_node("basic_robot:spawner", {
paramtype = "light", paramtype = "light",
param1=1, param1=1,
walkable = true, walkable = true,
alpha = 150,
after_place_node = function(pos, placer) after_place_node = function(pos, placer)
@ -1830,6 +1822,8 @@ end
-- remote control -- remote control
local write_keyevent = basic_robot.commands.write_keyevent;
minetest.register_craftitem("basic_robot:control", { minetest.register_craftitem("basic_robot:control", {
description = "Robot remote control", description = "Robot remote control",
inventory_image = "control.png", inventory_image = "control.png",
@ -1868,7 +1862,9 @@ minetest.register_craftitem("basic_robot:control", {
local hppos = minetest.hash_node_position(ppos) local hppos = minetest.hash_node_position(ppos)
local rname = basic_robot.data.punchareas[hppos]; local rname = basic_robot.data.punchareas[hppos];
local data = basic_robot.data[rname]; 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 return
end 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]", " 7. [TECHNIC FUNCTIONALITY]",
" 8. [CRYPTOGRAPHY]", " 8. [CRYPTOGRAPHY]",
" 9. [PUZZLE]", " 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"] = { ["MOVEMENT DIGGING PLACING NODE SENSING"] = {
@ -312,20 +313,32 @@ local help_pages = {
" add_particle(def)" " add_particle(def)"
}, },
["COROUTINES"] = { ["COROUTINES AND LIBRARIES AND ROM"] = {
"back to [Commands reference]", "back to [Commands reference]",
"COROUTINES","", "COROUTINES","",
"robot can run code using lua coroutines. To enable this mode just put the word", "robot can run code using lua coroutines. To enable this mode just put",
"coroutine in the first 32 characters of your program. Example: ", "", "the word coroutine in the first 32 characters of your program. Example:",
" --testing program for coroutine", " --testing program for coroutine",
" for i = 1,5 do ", " for i = 1,5 do ",
" say(i); dig.forward(); move.forward()", " say(i); dig.forward(); move.forward()",
" pause()", " pause()",
" end", " 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 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 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 if not data then
-- novice: 8x8, 4 -- novice: 8x8, 4
m=8;n=8; m=9;n=9;
atoms = 8 atoms = 16
attempts = 1;turn = 0; 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); local players = find_player(5,spawnpos);
if not player then self.remove() else pname = players[1] end 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 render_board = function(mode) -- mode 0 : render without solution, 1: render solution
for i = 1,m do for j = 1,n do -- render game for i = 1,m do for j = 1,n do -- render game
if mode == 0 or data[i][j] == 0 then 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 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},2) keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},15) -- 2 gray
end end
else 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 end end
end end
@ -126,8 +126,8 @@ if not data then
-- initial border loop and marking -- initial border loop and marking
--render blue border --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 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},5) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y,z=spawnpos.z+j},5) 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 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 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 z=0 -- bottom
for x = 1,m do 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) border_start_ray(x,z)
end end
end end
x=m+1 -- right x=m+1 -- right
for z = 1,n do 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) border_start_ray(x,z)
end end
end end
z=n+1 -- top z=n+1 -- top
for x = m,1,-1 do 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) border_start_ray(x,z)
end end
end end
x=0 -- left x=0 -- left
for z = n,1,-1 do 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) border_start_ray(x,z)
end end
end end
@ -164,7 +164,7 @@ if not data then
check_solution = function() check_solution = function()
for i = 1,m do for i = 1,m do
for j = 1,n 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 if data[i][j]~=1 then return false end
else else
if data[i][j]~=0 then return false end if data[i][j]~=0 then return false end
@ -176,8 +176,8 @@ if not data then
--render board --render board
render_board(0) render_board(0)
keyboard.set({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z-1},4) 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},5) keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z-1},7)
self.label("BLACKBOX with " .. atoms .. " atoms") self.label("BLACKBOX with " .. atoms .. " atoms")
end end
@ -185,23 +185,24 @@ end
event = keyboard.get(); event = keyboard.get();
if event then if event then
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z; 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 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 if check_solution() then
say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove() say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove()
else else
say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.") say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.")
attempts = attempts+1 attempts = attempts+1
end end
elseif event.type == 5 then elseif event.type == 7 then
say("#BLACKBOX : DISPLAYING SOLUTION",pname) say("#BLACKBOX : DISPLAYING SOLUTION",pname)
render_board(1) render_board(1)
self.remove() self.remove()
end end
else -- interior punch else -- interior punch
nodetype = 2; nodetype = 4;
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button808080" then if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonred" then
nodetype = 3 nodetype = 15
end end
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype); keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype);
end end

View File

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

View File

@ -1,12 +1,45 @@
--HIDE AND SEEK game robot, by rnd --HIDE AND SEEK game robot, by rnd
if not gamemaster then if not gamemaster then
timeout = 10; timeout = 20;
fardist = 300
gamemaster = "rnd" 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) _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 end
speaker,msg = self.listen_msg(); 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") _G.minetest.chat_send_all("# HIDE AND SEEK: " .. speaker .. " joined the game")
local player = _G.minetest.get_player_by_name(speaker); local player = _G.minetest.get_player_by_name(speaker);
if player then 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
end end
@ -52,16 +85,19 @@ elseif s==1 then
if data then if data then
count=count+1 count=count+1
local pos = player:getpos(); local pos = player:getpos();
local dist = math.max(math.abs(pos.x),math.abs(pos.y),math.abs(pos.z)); local dist = math.max(math.abs(pos.x-centerpos.x),math.abs(pos.y-centerpos.y),math.abs(pos.z-centerpos.z));
if dist>50 or (not _G.minetest.get_player_by_name(name)) then 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 " ) _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; player_list[name] = nil;
end 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!" ) _G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! his health changed!" )
player:set_properties({nametag_color = "white"}) player:set_properties({nametag_color = "white"})
player:setpos(centerpos)
player_list[name] = nil; player_list[name] = nil;
show_players()
end end
--expose campers --expose campers
@ -87,20 +123,18 @@ elseif s==1 then
end end
end end
self.label(count)
if count<=1 then if count<=1 then
if count==1 then if count==1 then
for name,_ in pairs(player_list) do 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 ******")) _G.minetest.chat_send_all(colorize("red","****** HIDE AND SEEK: ".. name .. " wins ******"))
player0:set_properties({nametag_color = "white"}) reset_name(name)
gamemaster = false; init_game();
end end
else else
_G.minetest.chat_send_all("# HIDE AND SEEK: no players left") _G.minetest.chat_send_all("# HIDE AND SEEK: no players left")
gamemaster = false; init_game()
end end
end 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) self.spam(1)
t0 = _G.minetest.get_gametime(); t0 = _G.minetest.get_gametime();
data = {}; spawnpos = self.spawnpos() -- place mines 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 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 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; data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0;
minescount = 0; minescount = 0;
for i = 1,m do for j = 1,n do -- render game 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 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 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:button808080"}) puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:buttonlight_grey"})
end end
end 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+1,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttondark_green"})
puzzle.set_node({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"}) puzzle.set_node({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttonblue"})
get_mine_count = function(i,j) 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 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() chk_mines = function()
local count = minescount; local count = minescount;
for i=1,m do for j=1,n do 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 count=count-1
end end
end end end end
@ -47,9 +48,10 @@ end
event = keyboard.get(); event = keyboard.get();
if event then if event then
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z; 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<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(); local count = chk_mines();
if count>minescount/2 then if count>minescount/2 then
say("fail, more than 50% of mines remaining ") say("fail, more than 50% of mines remaining ")
@ -69,20 +71,20 @@ if event then
else --if event.type == 2 then else --if event.type == 2 then
local ppos = player.getpos(event.puncher) 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 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 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:button808080"}) puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonlight_grey"})
else 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 end
else else
if data[x] and data[x][z]==1 then 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); local player_ = puzzle.get_player(event.puncher);
player_:setpos({x=spawnpos.x-1,y=spawnpos.y+1,z=spawnpos.z-1}); player_:setpos({x=spawnpos.x-1,y=spawnpos.y+1,z=spawnpos.z-1});
self.remove() self.remove()
else else
local count = get_mine_count(x,z); 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 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

View File

@ -2,7 +2,7 @@
-- INIT -- INIT
if not grid then if not grid then
n=6 n=9
solved = false -- do we render solution or blank? solved = false -- do we render solution or blank?
-- _G.math.randomseed(3) -- _G.math.randomseed(3)
@ -21,7 +21,7 @@ if not grid then
end end
_,scores_string = book.read(1); scores = minetest.deserialize(scores_string) _,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() 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 )." .. 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]={}; grid[i]={};
for j = 1,n do for j = 1,n do
local typ = keyboard.read({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+i}); 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
end end
return grid 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 #coldata[k]>0 then sum = sum + coldata[k][#coldata[k]] else sum = n end
if sum == n then easy = easy + 1 end if sum == n then easy = easy + 1 end
end end
easy = 5-easy; easy = n-1-easy;
if easy < 0 then easy = 0 end if easy < 0 then easy = 0 end
return easy return easy
end 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-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 keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+2*n-i+1},0) -- clear
local typ; 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
if not solved then 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 keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ) --board
end end
end end
@ -152,18 +152,18 @@ if not grid then
for i=1,n do for i=1,n do
length = #rowdata[i] length = #rowdata[i]
for k = 1,length do 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
end end
--render counts coloumns --render counts coloumns
for j=1,n do for j=1,n do
length = #coldata[j] length = #coldata[j]
for k = 1,length do 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
end end
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},4) -- 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},5) -- 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) local players = find_player(6,spawnpos)
if not players then error("nonogram: no players near") end 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 == 2 then limit = 80 reward = 7
elseif difficulty <= 1 then limit = 70 reward = 6 elseif difficulty <= 1 then limit = 70 reward = 6
end 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" .. 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]) ". Current record " .. -scores[difficulty][1][2] .. " by " .. scores[difficulty][1][1])
@ -233,7 +236,7 @@ if event then
for i=1,n do for i=1,n do
for j =1,n do for j =1,n do
local typ; 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) keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ)
end end
end end
@ -244,7 +247,7 @@ if event then
if i>0 and i<=n and j>0 and j<=n 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 typ = keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j});
local newtyp; local newtyp;
if typ == "basic_robot:button808080" then newtyp = 3 if typ ~= "basic_robot:buttonlight_grey" then newtyp = 13
else newtyp = 2 else newtyp = 2
end end
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},newtyp); 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 -- paint canvas by rnd, 2018
if not init then if not init then
colors = { colors = {
"black","blue","brown","cyan","dark_green","dark_grey","green","grey", "white","yellow","orange","red","magenta","purple","blue","cyan",
"magenta","orange","pink","red","violet","white","yellow" "green","dark_green","brown","tan","light_grey","medium_grey","dark_grey","black"
} }
invcolors = {}; for i = 1,#colors do invcolors[colors[i]] = i end invcolors = {}; for i = 1,#colors do invcolors[colors[i]] = i end
color = 1; color = invcolors["black"];
size = 16; size = 16;
init = true init = true
local ent = _G.basic_robot.data[self.name()].obj:get_luaentity(); 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 players = find_player(5); if not players then self.remove() end
player = _G.minetest.get_player_by_name(players[1]) player = _G.minetest.get_player_by_name(players[1])
self.label("-> " .. players[1]) self.label("-> " .. players[1])
spos = self.spawnpos(); spos.y=spos.y+1; spos = self.spawnpos(); spos.y=spos.y+1;
canvasn = "basic_robot:buttonwhite"
canvasn = "wool:white"
reset_canvas = function() reset_canvas = function()
for i = 1, size do for i = 1, size do
for j = 1, size do for j = 1, size do
@ -34,11 +33,12 @@ if not init then
local ret = {}; local ret = {};
for i = 1, size do for i = 1, size do
for j = 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; local pcolor = invcolors[nname] or 1;
ret[#ret+1]= string.char(96+pcolor) ret[#ret+1]= string.char(96+pcolor)
end end
end end
return table.concat(ret,"") return table.concat(ret,"")
end end
@ -49,7 +49,7 @@ if not init then
for j = 1, size do for j = 1, size do
k=k+1; k=k+1;
local pcolor = colors[string.byte(image,k)-96] or "black"; 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 end
end end
@ -57,7 +57,7 @@ if not init then
--draw buttons --draw buttons
for i = 1,#colors do 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 end
minetest.set_node({x=spos.x +1 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_83"}) 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 x>0 and x<size and y>-2 and y<size then
if y>0 then -- above: painting if y>0 then -- above: painting
c.z = c.z+0.5 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 elseif y>-1 then -- color selection
x = 1+math.floor(x) x = 1+math.floor(x)
if colors[x] then 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 if not init then
spos = self.spawnpos(); spos.x = spos.x +5; spos.z = spos.z +5; 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 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
end end
init = true init = true
players = find_player(5); players = find_player(5);
if not players then say("no players nearby") self.remove() end 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 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 end
event = keyboard.get() event = keyboard.get()
if event then
if event then -- there was punch event
local boxtype = event.type local boxtype = event.type
if pushables[boxtype] then if pushables[boxtype] then
player = puzzle.get_player(event.puncher) player = puzzle.get_player(event.puncher)

View File

@ -19,7 +19,7 @@ if not init then
board[i]={}; board[i]={};
for j = 1,n do for j = 1,n do
k=k+1 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
end end
board[math.random(n)][math.random(n)] = 0 board[math.random(n)][math.random(n)] = 0

View File

@ -43,7 +43,7 @@
SOKOBAN_WALL = "moreblocks:cactus_brick" SOKOBAN_WALL = "moreblocks:cactus_brick"
SOKOBAN_FLOOR = "default:silver_sandstone" SOKOBAN_FLOOR = "default:silver_sandstone"
SOKOBAN_GOAL = "default:aspen_tree" SOKOBAN_GOAL = "default:aspen_tree"
SOKOBAN_BOX = "basic_robot:buttonFFFFFF" SOKOBAN_BOX = "basic_robot:buttonwhite"
load_level = function(lvl) 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 -- REDSTONE EMULATOR & EDITOR
--v 06/28/2018a --v 28/06/2018a, fixed 28/08/2022a
if not init then 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); local players = find_player(5);
if not players then if not players then
name = ""; 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 inv:set_stack("main", 8, puzzle.ItemStack("basic_robot:control 1 0 \"@\"")) -- add controller in players inventory
--add items for building --add items for building
inv:set_stack("main", 1, puzzle.ItemStack("default:pick_diamond")) 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", 2, puzzle.ItemStack("basic_robot:button_283 999")) -- switch 9 = 283/284
inv:set_stack("main", 3, puzzle.ItemStack("basic_robot:button_275 999")) -- button 7 = 275/276 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_277 999")) -- equalizer 61 = 277 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_278 999")) -- setter 15 = 278 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_279 999")) -- piston 171 = 279 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_282 999")) -- delayer 232 = 282 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_281 999")) -- NOT 33 = 281 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_280 999")) -- diode 175 = 280 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_283 999")) -- platform 22 = 283 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_284 999")) -- giver 23 150/284 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_285 999")) -- checker 24 151/285 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 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 end
init = true init = true
self.listen_punch(self.pos()); -- attach punch listener
self.spam(1) self.spam(1)
self.label(colorize("orange","REDSTONE EMULATOR/EDITOR")) 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 toggle_button_action = function(mode,pos,ttl) -- SIMPLE TOGGLE BUTTONS - SWITCH
if not ttl or ttl <=0 then return end if not ttl or ttl <=0 then return end
if mode == 1 then -- turn on 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); local meta = puzzle.get_meta(pos);
if not meta then return end if not meta then return end
local n = meta:get_int("n"); 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 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 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); local meta = puzzle.get_meta(pos);
if not meta then return end if not meta then return end
local n = meta:get_int("n"); 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 button_action = function(mode,pos,ttl) -- SIMPLE ON BUTTON, TOGGLES BACK OFF after 1s
if not ttl or ttl <=0 then return end if not ttl or ttl <=0 then return end
if mode == 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); local meta = puzzle.get_meta(pos);
if not meta then return end if not meta then return end
local n = meta:get_int("n"); local n = meta:get_int("n");
minetest.after(1, function() 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 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)
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 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 -- THESE REACT WHEN PUNCHED
interactive_elements = { interactive_elements = {
[275] = {button_action,1}, -- BUTTON, 1 means it activates(ON) on punch [285] = {button_action,1}, -- BUTTON, 1 means it activates(ON) on punch
[273] = {toggle_button_action,1}, -- TOGGLE BUTTON_OFF [283] = {toggle_button_action,1}, -- TOGGLE BUTTON_OFF
[274] = {toggle_button_action,0}, -- TOGGLE BUTTON_ON, 0 means it deactivates [284] = {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 [294] = {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 [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 -- THESE CAN BE ACTIVATED WITH SIGNAL
active_elements = { active_elements = {
["basic_robot:button_275"] = button_action, -- BUTTON, what action to do on activate ["basic_robot:button_285"] = button_action, -- BUTTON, what action to do on activate
["basic_robot:button_273"] = toggle_button_action, -- TOGGLE BUTTON_OFF ["basic_robot:button_283"] = toggle_button_action, -- TOGGLE BUTTON_OFF
["basic_robot:button_274"] = toggle_button_action, -- TOGGLE BUTTON_ON ["basic_robot:button_284"] = toggle_button_action, -- TOGGLE BUTTON_ON
["basic_robot:button_278"] = setter_action, -- SETTER ["basic_robot:button_288"] = setter_action, -- SETTER
["basic_robot:button_277"] = equalizer_action, -- EQUALIZER ["basic_robot:button_287"] = equalizer_action, -- EQUALIZER
["basic_robot:button_279"] = piston_action, -- PISTON ["basic_robot:button_289"] = piston_action, -- PISTON
["basic_robot:button_283"] = platform_action, -- PLATFORM ["basic_robot:button_293"] = platform_action, -- PLATFORM
["basic_robot:button_282"] = delayer_action, -- DELAYER ["basic_robot:button_292"] = delayer_action, -- DELAYER
["basic_robot:button_280"] = diode_action, -- DIODE ["basic_robot:button_290"] = diode_action, -- DIODE
["basic_robot:button_281"] = not_action, -- NOT ["basic_robot:button_291"] = not_action, -- NOT
} }
@ -324,19 +330,19 @@ if not init then
-- blocks that can be activated -- blocks that can be activated
edit.active_elements = { edit.active_elements = {
["basic_robot:button_275"] = "button: now select one or more targets", -- button ["basic_robot:button_285"] = "button: now select one or more targets", -- button
["basic_robot:button_273"] = "switch: now select one or more targets", -- switch OFF ["basic_robot:button_283"] = "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_284"] = "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_288"] = "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_287"] = "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_289"] = "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_293"] = "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_292"] = "delayer: distance from delayer to target1 determines delay", -- delayer
["basic_robot:button_280"] = "diode: only pass through ON signal", -- DIODE ["basic_robot:button_290"] = "diode: only pass through ON signal", -- DIODE
["basic_robot:button_281"] = "NOT gate: negates the signal", -- NOT ["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_294"] = "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_295"] = "CHECKER: check if player has block below it in inventory, remove it and activate targets after that",
} }
linker_use = function(pos) linker_use = function(pos)
@ -358,12 +364,12 @@ if not init then
local nodename = puzzle.get_node(pos).name; local nodename = puzzle.get_node(pos).name;
local active_element = edit.active_elements[nodename] 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 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 for i = 1,n do -- add targets as lines
form = form .. 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[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) .."]" "label[3,".. (0.75*i-0.25) .. "; " .. meta:get_int("x"..i) .. " " .. meta:get_int("y"..i) .. " " .. meta:get_int("z"..i) .."]"
end end
self.show_form(name,form); self.show_form(name,form);
@ -385,7 +391,7 @@ if not init then
expirationtime = 5, expirationtime = 5,
velocity = {x=0, y=0,z=0}, velocity = {x=0, y=0,z=0},
size = 18, size = 18,
texture = "010.png", texture = "puzzle_button_on.png",
acceleration = {x=0,y=0,z=0}, acceleration = {x=0,y=0,z=0},
collisiondetection = true, collisiondetection = true,
collision_removal = true, collision_removal = true,
@ -429,7 +435,7 @@ if not init then
expirationtime = 5, expirationtime = 5,
velocity = {x=0, y=0,z=0}, velocity = {x=0, y=0,z=0},
size = 18, size = 18,
texture = "009.png", texture = "puzzle_button_off.png",
acceleration = {x=0,y=0,z=0}, acceleration = {x=0,y=0,z=0},
collisiondetection = true, collisiondetection = true,
collision_removal = true, collision_removal = true,
@ -447,7 +453,8 @@ end
opcount = 0 opcount = 0
event = keyboard.get() -- handle keyboard 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.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) 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 wield_item = player_:get_wielded_item():get_name()
@ -480,7 +487,7 @@ if sender then
expirationtime = 5, expirationtime = 5,
velocity = {x=0, y=0,z=0}, velocity = {x=0, y=0,z=0},
size = 18, size = 18,
texture = "010.png", texture = "puzzle_button_on.png",
acceleration = {x=0,y=0,z=0}, acceleration = {x=0,y=0,z=0},
collisiondetection = true, collisiondetection = true,
collision_removal = 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 luaent = objs[i]:get_luaentity();
local entname = "" local entname = ""
if luaent then if luaent then
--entname = serialize(luaent)
entname = luaent.itemstring entname = luaent.itemstring
if entname == "robot" then entname = entname .. " " .. luaent.name end if entname == "robot" then entname = entname .. " " .. luaent.name end
elseif objs[i]:is_player() then elseif objs[i]:is_player() then
@ -20,7 +21,7 @@ for i = 1, #objs do
end end
local phash = round(p.x) .. " " .. round(p.y) .. " " .. round(p.z); 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 end
local out = {}; local out = {};
@ -36,6 +37,9 @@ end
self.label("#objects " .. #objs .. "\n" .. table.concat(res, "\n")) self.label("#objects " .. #objs .. "\n" .. table.concat(res, "\n"))
--book.write(1,"",("#objects " .. #objs .. "\n" .. table.concat(res, "\n")))
--self.remove()
end end

View File

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