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,45 +662,79 @@ 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", {
tiles = {texture .. ".png"}, description = "robot button",
inventory_image = texture .. ".png", tiles = {texture .. ".png"},
wield_image = texture .. ".png", inventory_image = texture .. ".png",
is_ground_content = false, wield_image = texture .. ".png",
groups = {cracky=3,not_in_craft_guide = 1}, is_ground_content = false,
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end groups = {cracky=3,not_in_craft_guide = 1},
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
}) })
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
--]]
register_robot_button("FF","FF","FF",1); --16-color palette from macintosh II, 1987
register_robot_button("80","80","80",2);
register_robot_button("FF","FF","FF","white",1); -- white
register_robot_button("FC","F4","00","yellow",2); -- yellow
register_robot_button("FF","64","00","orange",3); -- orange
register_robot_button("DD","02","02","red",4); -- red
register_robot_button("F0","02","85","magenta",5); -- magenta
register_robot_button("46","00","A5","purple",6); -- purple
register_robot_button("00","00","D5","blue",7); -- blue
register_robot_button("00","AE","E9","cyan",8); -- cyan
register_robot_button("1A","B9","0C","green",9); -- green
register_robot_button("00","64","08","dark_green",10);-- dark_green
register_robot_button("57","28","00","brown",11);-- brown
register_robot_button("91","71","35","tan",12);-- tan
register_robot_button("C1","C1","C1","light_grey",13);-- light_grey
register_robot_button("81","81","81","medium_grey",14);-- medium_grey
register_robot_button("3E","3E","3E","dark_grey",15);-- dark_grey
register_robot_button("00","00","00","black",16);-- black
--[[ -- old colors
register_robot_button("FF","FF","FF",1);
register_robot_button("80","80","80",2);
register_robot_button("FF","80","80",3); register_robot_button("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
coroutine.yield() if not amount or basic_robot.data[name].operations<amount then
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,8 +355,8 @@ 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,
find = string.find, find = string.find,
@ -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
jmin = j if string.sub(code,j-1,j-1) ~="\\" then
mode = k jmin = j
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,17 +313,29 @@ 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",
}, },

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

@ -1,210 +1,211 @@
--black box by rnd, 03/18/2017 --black box by rnd, 03/18/2017
--https://en.wikipedia.org/wiki/Black_Box_(game) --https://en.wikipedia.org/wiki/Black_Box_(game)
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
self.listen_punch(self.pos()) -- attach punch listener self.listen_punch(self.pos()) -- attach punch listener
self.spam(1);t0 = _G.minetest.get_gametime(); self.spam(1);t0 = _G.minetest.get_gametime();
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,atoms do -- put in atoms randomly for i=1,atoms do -- put in atoms randomly
data[math.random(m)][math.random(n)] = 1 data[math.random(m)][math.random(n)] = 1
end end
atoms = 0 atoms = 0
for i = 1,m do for j = 1,n do if data[i][j]==1 then atoms = atoms + 1 end end end for i = 1,m do for j = 1,n do if data[i][j]==1 then atoms = atoms + 1 end end end
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
get_dirl = function(dir) get_dirl = function(dir)
local dirl; -- direction left local dirl; -- direction left
if dir[1] > 0.5 then dirl = {0,-1} if dir[1] > 0.5 then dirl = {0,-1}
elseif dir[1] < -0.5 then dirl = {0,1} elseif dir[1] < -0.5 then dirl = {0,1}
elseif dir[2] > 0.5 then dirl = {-1,0} elseif dir[2] > 0.5 then dirl = {-1,0}
elseif dir[2] < -0.5 then dirl = {1,0} elseif dir[2] < -0.5 then dirl = {1,0}
end end
return dirl return dirl
end end
read_pos = function(x,z) read_pos = function(x,z)
if x<1 or x>m or z<1 or z>n then return nil end if x<1 or x>m or z<1 or z>n then return nil end
return data[x][z] return data[x][z]
end end
newdir = function(x,z,dir) -- where will ray go next newdir = function(x,z,dir) -- where will ray go next
local retdir = {dir[1],dir[2]}; local retdir = {dir[1],dir[2]};
local xf = x+dir[1]; local zf = z+dir[2] -- forward local xf = x+dir[1]; local zf = z+dir[2] -- forward
local dirl = get_dirl(dir) local dirl = get_dirl(dir)
local nodef = read_pos(xf,zf) local nodef = read_pos(xf,zf)
local nodel = read_pos(xf + dirl[1],zf + dirl[2]) local nodel = read_pos(xf + dirl[1],zf + dirl[2])
local noder = read_pos(xf - dirl[1],zf - dirl[2]) local noder = read_pos(xf - dirl[1],zf - dirl[2])
if nodef == 1 then if nodef == 1 then
retdir = {0,0} -- ray hit something retdir = {0,0} -- ray hit something
elseif nodel == 1 and noder ~= 1 then elseif nodel == 1 and noder ~= 1 then
retdir = {-dirl[1],-dirl[2]} retdir = {-dirl[1],-dirl[2]}
elseif nodel ~= 1 and noder == 1 then elseif nodel ~= 1 and noder == 1 then
retdir = {dirl[1],dirl[2]} retdir = {dirl[1],dirl[2]}
elseif nodel == 1 and noder == 1 then elseif nodel == 1 and noder == 1 then
retdir = {-dir[1],-dir[2]} retdir = {-dir[1],-dir[2]}
end end
return retdir return retdir
end end
shootray = function(x,z,dir) shootray = function(x,z,dir)
--say("ray starts " .. x .. " " .. z .. " dir " .. dir[1] .. " " .. dir[2]) --say("ray starts " .. x .. " " .. z .. " dir " .. dir[1] .. " " .. dir[2])
local xp = x; local zp = z; local xp = x; local zp = z;
local dirp = {dir[1],dir[2]}; local dirp = {dir[1],dir[2]};
local maxstep = m*n; local maxstep = m*n;
for i = 1,maxstep do for i = 1,maxstep do
dirp = newdir(xp,zp,dirp); dirp = newdir(xp,zp,dirp);
if dirp[1]==0 and dirp[2]==0 then return -i end -- hit if dirp[1]==0 and dirp[2]==0 then return -i end -- hit
xp=xp+dirp[1];zp=zp+dirp[2]; xp=xp+dirp[1];zp=zp+dirp[2];
if xp<1 or xp>m or zp<1 or zp>n then return i,{xp,zp} end -- out if xp<1 or xp>m or zp<1 or zp>n then return i,{xp,zp} end -- out
end end
return 0 -- hit return 0 -- hit
end end
count = 0; -- how many letters were used up count = 0; -- how many letters were used up
border_start_ray = function(x,z) border_start_ray = function(x,z)
local rdir local rdir
if x==0 then rdir = {1,0} if x==0 then rdir = {1,0}
elseif x == m+1 then rdir = {-1,0} elseif x == m+1 then rdir = {-1,0}
elseif z == 0 then rdir = {0,1} elseif z == 0 then rdir = {0,1}
elseif z == n+1 then rdir = {0,-1} elseif z == n+1 then rdir = {0,-1}
end end
if rdir then if rdir then
local result,out = shootray(x,z,rdir); local result,out = shootray(x,z,rdir);
if result >= 0 then if result >= 0 then
if out then if out then
if out[1]==x and out[2]==z then -- got back where it originated, reflection if out[1]==x and out[2]==z then -- got back where it originated, reflection
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},1); keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},1);
else else
if result<=1 then if result<=1 then
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},6); -- immediate bounce off keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},6); -- immediate bounce off
else else
local nodename = "basic_robot:button_"..(65+count); local nodename = "basic_robot:button_"..(65+count);
_G.minetest.set_node( _G.minetest.set_node(
{x=spawnpos.x+out[1],y=spawnpos.y+1,z=spawnpos.z+out[2]}, {x=spawnpos.x+out[1],y=spawnpos.y+1,z=spawnpos.z+out[2]},
{name = nodename, param2 = 1}) {name = nodename, param2 = 1})
_G.minetest.set_node( _G.minetest.set_node(
{x=spawnpos.x+x,y=spawnpos.y+1,z=spawnpos.z+z}, {x=spawnpos.x+x,y=spawnpos.y+1,z=spawnpos.z+z},
{name = nodename, param2 = 1}) {name = nodename, param2 = 1})
count = count + 1; count = count + 1;
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4); keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4);
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},4); keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},4);
end end
end end
end end
elseif result<0 then elseif result<0 then
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3); -- hit keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3); -- hit
end end
end end
end end
-- 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
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
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
end end
end end
end end
return true return true
end end
--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
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 --self.label(serialize(event))
if event.type == 4 then if x<1 or x>m or z<1 or z>n then
if check_solution() then if event.type == 9 then
say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove() if check_solution() then
else say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove()
say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.") else
attempts = attempts+1 say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.")
end attempts = attempts+1
elseif event.type == 5 then end
say("#BLACKBOX : DISPLAYING SOLUTION",pname) elseif event.type == 7 then
render_board(1) say("#BLACKBOX : DISPLAYING SOLUTION",pname)
self.remove() render_board(1)
end self.remove()
else -- interior punch end
nodetype = 2; else -- interior punch
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button808080" then nodetype = 4;
nodetype = 3 if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonred" then
end nodetype = 15
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype); end
end keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype);
end
end
end
::END:: ::END::

View File

@ -1,67 +1,67 @@
-- 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
state = 0; -- 0 signup 1 game state = 0; -- 0 signup 1 game
players = {}; players = {};
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
get_count_in_dir = function(dir,x,y) get_count_in_dir = function(dir,x,y)
local r = num; -- num=4? in a row local r = num; -- num=4? in a row
local snode = data[x][y];local count = 1; local snode = data[x][y];local count = 1;
for j = 1,2 do for j = 1,2 do
for i = 1,r-1 do for i = 1,r-1 do
local x1 = x + dir[1]*i;local y1 = y + dir[2]*i; local x1 = x + dir[1]*i;local y1 = y + dir[2]*i;
if not data[x1] or not data[x1][y1] then break end; if data[x1][y1]~= snode then break end if not data[x1] or not data[x1][y1] then break end; if data[x1][y1]~= snode then break end
count = count +1 count = count +1
end end
dir[1]=-dir[1];dir[2]=-dir[2]; dir[1]=-dir[1];dir[2]=-dir[2];
end end
return count return count
end end
get_count = function(x,y) get_count = function(x,y)
local c1 = get_count_in_dir({0,1},x,y); local c2 = get_count_in_dir({1,0},x,y) local c1 = get_count_in_dir({0,1},x,y); local c2 = get_count_in_dir({1,0},x,y)
local c3 = get_count_in_dir({1,1},x,y); local c4 = get_count_in_dir({1,-1},x,y) local c3 = get_count_in_dir({1,1},x,y); local c4 = get_count_in_dir({1,-1},x,y)
if c2>c1 then c1 = c2 end; if c3>c1 then c1 = c3 end; if c4>c1 then c1 = c4 end if c2>c1 then c1 = c2 end; if c3>c1 then c1 = c3 end; if c4>c1 then c1 = c4 end
return c1 return c1
end end
self.label("TRY TO GET FIRST " .. num .. " IN A ROW! : GREEN starts play. 2 players punch to join game.") self.label("TRY TO GET FIRST " .. num .. " IN A ROW! : GREEN starts play. 2 players punch to join game.")
end 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
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
if #players==2 then state = 1 end if #players==2 then state = 1 end
end end
if event.puncher == players[1] then -- green if event.puncher == players[1] then -- green
if turn~=0 then return end -- ignore if not player turn if turn~=0 then return end -- ignore if not player turn
else else
if turn~=1 then return end if turn~=1 then return end
end end
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4+turn); keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4+turn);
data[x][z] = 4+turn; data[x][z] = 4+turn;
if get_count(x,z) == num then say("CONGRATULATIONS! " .. event.puncher .. " has "..num .. " in a row"); self.remove(); goto END end if get_count(x,z) == num then say("CONGRATULATIONS! " .. event.puncher .. " has "..num .. " in a row"); self.remove(); goto END end
turn = 1-turn turn = 1-turn
if state == 1 then if state == 1 then
local msg = ""; if turn == 0 then msg = "GREEN " else msg = "BLUE" end local msg = ""; if turn == 0 then msg = "GREEN " else msg = "BLUE" end
self.label(msg .. " : " .. players[turn+1]) self.label(msg .. " : " .. players[turn+1])
end end
end end
end end
::END:: ::END::

View File

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

View File

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

View File

@ -8,21 +8,22 @@ if not data then
self.spam(1) 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,112 +1,112 @@
-- 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 minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = canvasn})
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = canvasn}) end
end end
end end
end reset_canvas()
reset_canvas()
save_image = function()
save_image = function() 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,19)
local nname = string.sub(minetest.get_node({x=spos.x +i , y = spos.y + j, z = spos.z }).name,6) 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
load_image = function(image) load_image = function(image)
if not image then return end if not image then return end
local ret = {}; local k = 0; local ret = {}; local k = 0;
for i = 1, size do for i = 1, size do
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
--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"})
minetest.set_node({x=spos.x +2 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_76"}) minetest.set_node({x=spos.x +2 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_76"})
vn = {x=0,y=0,z=1}; vn = {x=0,y=0,z=1};
T0 = {x=spos.x+0.5,y=spos.y+0.5,z=spos.z-0.5*vn.z}; T0 = {x=spos.x+0.5,y=spos.y+0.5,z=spos.z-0.5*vn.z};
get_intersect = function(vn, T0, p, v) get_intersect = function(vn, T0, p, v)
local a = (T0.x-p.x)*vn.x + (T0.y-p.y)*vn.y + (T0.z-p.z)*vn.z; local a = (T0.x-p.x)*vn.x + (T0.y-p.y)*vn.y + (T0.z-p.z)*vn.z;
local b = vn.x*v.x + vn.y*v.y + vn.z*v.z local b = vn.x*v.x + vn.y*v.y + vn.z*v.z
if b<=0 then return nil end if b<=0 then return nil end
if a<=0 then return nil end if a<=0 then return nil end
local t = a / b local t = a / b
return {x = p.x+v.x*t, y= p.y+v.y*t, z = p.z+v.z*t} return {x = p.x+v.x*t, y= p.y+v.y*t, z = p.z+v.z*t}
end end
end end
if player:get_player_control().LMB then -- player interacts with 'virtual canvas gui' if player:get_player_control().LMB then -- player interacts with 'virtual canvas gui'
local v = player:get_look_dir(); local v = player:get_look_dir();
local p = player:get_pos(); p.y = p.y + 1.5 local p = player:get_pos(); p.y = p.y + 1.5
local c = get_intersect(vn,T0,p,v); local c = get_intersect(vn,T0,p,v);
if c then if c then
local x = c.x - T0.x; local y = c.y - T0.y local x = c.x - T0.x; local y = c.y - T0.y
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
color = x; color = x;
self.label(colors[x]) self.label(colors[x])
end end
else -- save,load button row else -- save,load button row
x = 1+math.floor(x) x = 1+math.floor(x)
if x==1 then if x==1 then
self.label("SAVED.") self.label("SAVED.")
book.write(1,"ROBOT_IMAGE",save_image()) book.write(1,"ROBOT_IMAGE",save_image())
elseif x==2 then elseif x==2 then
local _,image = book.read(1) local _,image = book.read(1)
load_image(image); load_image(image);
self.label("LOADED.") self.label("LOADED.")
end end
end end
end end
end end
end end

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

@ -1,56 +1,59 @@
-- simple box pushing game, rnd -- simple box pushing game, rnd
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
end
self.listen_punch(self.pos()) -- robot will now read punch button events in 32x32 box area
event = keyboard.get() end
if event then
local boxtype = event.type event = keyboard.get()
if pushables[boxtype] then
player = puzzle.get_player(event.puncher) if event then -- there was punch event
local pos = player:getpos(); local boxtype = event.type
local boxpos = {x = event.x, y = event.y, z = event.z}; if pushables[boxtype] then
local diff = { pos.x-boxpos.x, pos.z-boxpos.z}; player = puzzle.get_player(event.puncher)
local pos = player:getpos();
local newx,newz local boxpos = {x = event.x, y = event.y, z = event.z};
if math.abs(diff[1])>math.abs(diff[2]) then -- punch in x-direction local diff = { pos.x-boxpos.x, pos.z-boxpos.z};
newx = boxpos.x - (diff[1]>0 and 1 or -1)
newz = boxpos.z local newx,newz
else if math.abs(diff[1])>math.abs(diff[2]) then -- punch in x-direction
newx = boxpos.x newx = boxpos.x - (diff[1]>0 and 1 or -1)
newz = boxpos.z - (diff[2]>0 and 1 or -1) newz = boxpos.z
end else
newx = boxpos.x
local newnode = puzzle.get_node({x=newx, y= boxpos.y, z= newz}).name newz = boxpos.z - (diff[2]>0 and 1 or -1)
end
local canpush = canpushnodes[newnode] local newnode = puzzle.get_node({x=newx, y= boxpos.y, z= newz}).name
if canpush then
local oldnode = puzzle.get_node(boxpos).name
puzzle.set_node(boxpos,{name= "air"}) -- remove node local canpush = canpushnodes[newnode]
if canpush == 1 then -- simply move the box if canpush then
newnode = oldnode local oldnode = puzzle.get_node(boxpos).name
elseif canpush == 2 then -- absorb the box puzzle.set_node(boxpos,{name= "air"}) -- remove node
newnode = newnode if canpush == 1 then -- simply move the box
end newnode = oldnode
elseif canpush == 2 then -- absorb the box
puzzle.set_node({x=newx, y= boxpos.y, z= newz}, {name = newnode}) newnode = newnode
end end
end
--say(serialize(event)) puzzle.set_node({x=newx, y= boxpos.y, z= newz}, {name = newnode})
end
end
--say(serialize(event))
end end

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

@ -34,7 +34,7 @@
self.spam(1) self.spam(1)
self.listen_punch(self.pos()); -- attach punch listener self.listen_punch(self.pos()); -- attach punch listener
sokoban.push_time = 0 sokoban.push_time = 0
sokoban.blocks = 0;sokoban.level = 0; sokoban.moves=0; sokoban.blocks = 0;sokoban.level = 0; sokoban.moves=0;
imax = 0; jmax = 0 imax = 0; jmax = 0
@ -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

File diff suppressed because it is too large Load Diff

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

@ -1,41 +1,45 @@
-- minetest object listen in radius 100 around robot -- minetest object listen in radius 100 around robot
if not init then init = false if not init then init = false
local objs = minetest.get_objects_inside_radius(self.pos(), 100); local objs = minetest.get_objects_inside_radius(self.pos(), 100);
local ret = {}; local ret = {};
local round = function(x) return math.floor(x/5)*5 end local round = function(x) return math.floor(x/5)*5 end
local ret = {}; local ret = {};
for i = 1, #objs do for i = 1, #objs do
local p = objs[i]:get_pos(); local p = objs[i]:get_pos();
local luaent = objs[i]:get_luaentity(); local luaent = objs[i]:get_luaentity();
local entname = "" local entname = ""
if luaent then if luaent then
entname = luaent.itemstring --entname = serialize(luaent)
if entname == "robot" then entname = entname .. " " .. luaent.name end entname = luaent.itemstring
elseif objs[i]:is_player() then if entname == "robot" then entname = entname .. " " .. luaent.name end
entname = "PLAYER " .. objs[i]:get_player_name() elseif objs[i]:is_player() then
end entname = "PLAYER " .. objs[i]:get_player_name()
end
local phash = round(p.x) .. " " .. round(p.y) .. " " .. round(p.z);
ret[phash] = (ret[phash] or "") .. entname .. ", " local phash = round(p.x) .. " " .. round(p.y) .. " " .. round(p.z);
end if entname then ret[phash] = (ret[phash] or "") .. entname .. ", " end
end
local out = {};
for k,v in pairs(ret) do local out = {};
out[#out+1] = {k,v} for k,v in pairs(ret) do
end out[#out+1] = {k,v}
end
--table.sort(out, function(a,b) return a[2]>b[2] end) -- additional stuff here - optional
local res = {}; --table.sort(out, function(a,b) return a[2]>b[2] end) -- additional stuff here - optional
for i = 1, #out do local res = {};
res[#res+1] = out[i][1] .. " = " .. out[i][2] for i = 1, #out do
end res[#res+1] = out[i][1] .. " = " .. out[i][2]
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