custom buttons fix. redstone script fix
parent
2020477700
commit
8c9d0fd68f
137
commands.lua
137
commands.lua
|
@ -595,6 +595,8 @@ local write_keyevent = function(data,pos, puncher,type)
|
|||
|
||||
end
|
||||
|
||||
basic_robot.commands.write_keyevent = write_keyevent;
|
||||
|
||||
local button_punched = function(pos, node, player,type)
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
local round = math.floor;
|
||||
|
@ -609,8 +611,10 @@ local button_punched = function(pos, node, player,type)
|
|||
end
|
||||
end
|
||||
|
||||
local register_robot_button = function(R,G,B,type)
|
||||
minetest.register_node("basic_robot:button"..R..G..B,
|
||||
local buttoncolors = {};
|
||||
local register_robot_button = function(R,G,B,colorname,type)
|
||||
buttoncolors[type] = "basic_robot:button"..colorname;
|
||||
minetest.register_node("basic_robot:button"..colorname,
|
||||
{
|
||||
description = "robot button",
|
||||
tiles = {"robot_button.png^[colorize:#"..R..G..B..":180"},
|
||||
|
@ -624,12 +628,14 @@ local register_robot_button = function(R,G,B,type)
|
|||
end
|
||||
|
||||
local register_robot_button_number = function(number,type)
|
||||
local idx = number+48
|
||||
local texname = "robochars.png^[sheet:16x16:" .. idx % 16 .. "," .. math.floor(idx/ 16).."^[invert:rgb";
|
||||
minetest.register_node("basic_robot:button"..number,
|
||||
{
|
||||
description = "robot button",
|
||||
tiles = {"robot_button".. number .. ".png"},
|
||||
inventory_image = "robot_button".. number .. ".png",
|
||||
wield_image = "robot_button".. number .. ".png",
|
||||
tiles = {texname},
|
||||
inventory_image = texname,
|
||||
wield_image = texname,
|
||||
paramtype2 = "facedir",
|
||||
|
||||
is_ground_content = false,
|
||||
|
@ -640,12 +646,14 @@ end
|
|||
|
||||
|
||||
local register_robot_button_char = function(number,type)
|
||||
local texname = "robochars.png^[sheet:16x16:" .. number % 16 .. "," .. math.floor(number/ 16);
|
||||
-- local texname = string.format("%03d",number).. ".png";
|
||||
minetest.register_node("basic_robot:button_"..number,
|
||||
{
|
||||
{
|
||||
description = "robot button",
|
||||
tiles = {string.format("%03d",number).. ".png"},
|
||||
inventory_image = string.format("%03d",number).. ".png",
|
||||
wield_image = string.format("%03d",number).. ".png",
|
||||
tiles = {texname},
|
||||
inventory_image = texname,
|
||||
wield_image = texname,
|
||||
is_ground_content = false,
|
||||
groups = {cracky=3,not_in_craft_guide = 1},
|
||||
paramtype2 = "facedir",
|
||||
|
@ -654,45 +662,79 @@ minetest.register_node("basic_robot:button_"..number,
|
|||
end
|
||||
|
||||
local register_robot_button_custom = function(number,texture)
|
||||
minetest.register_node("basic_robot:button_"..number,
|
||||
{
|
||||
description = "robot button",
|
||||
tiles = {texture .. ".png"},
|
||||
inventory_image = texture .. ".png",
|
||||
wield_image = texture .. ".png",
|
||||
is_ground_content = false,
|
||||
groups = {cracky=3,not_in_craft_guide = 1},
|
||||
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
|
||||
local type = number
|
||||
minetest.register_node("basic_robot:button_"..number,
|
||||
{
|
||||
description = "robot button",
|
||||
tiles = {texture .. ".png"},
|
||||
inventory_image = texture .. ".png",
|
||||
wield_image = texture .. ".png",
|
||||
is_ground_content = false,
|
||||
groups = {cracky=3,not_in_craft_guide = 1},
|
||||
on_punch = function(pos, node,player) button_punched(pos, node,player,type) 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);
|
||||
register_robot_button("80","80","80",2);
|
||||
--16-color palette from macintosh II, 1987
|
||||
|
||||
register_robot_button("FF","FF","FF","white",1); -- white
|
||||
register_robot_button("FC","F4","00","yellow",2); -- yellow
|
||||
register_robot_button("FF","64","00","orange",3); -- orange
|
||||
register_robot_button("DD","02","02","red",4); -- red
|
||||
register_robot_button("F0","02","85","magenta",5); -- magenta
|
||||
register_robot_button("46","00","A5","purple",6); -- purple
|
||||
register_robot_button("00","00","D5","blue",7); -- blue
|
||||
register_robot_button("00","AE","E9","cyan",8); -- cyan
|
||||
register_robot_button("1A","B9","0C","green",9); -- green
|
||||
register_robot_button("00","64","08","dark_green",10);-- dark_green
|
||||
register_robot_button("57","28","00","brown",11);-- brown
|
||||
register_robot_button("91","71","35","tan",12);-- tan
|
||||
register_robot_button("C1","C1","C1","light_grey",13);-- light_grey
|
||||
register_robot_button("81","81","81","medium_grey",14);-- medium_grey
|
||||
register_robot_button("3E","3E","3E","dark_grey",15);-- dark_grey
|
||||
register_robot_button("00","00","00","black",16);-- black
|
||||
|
||||
|
||||
|
||||
--[[ -- old colors
|
||||
register_robot_button("FF","FF","FF",1);
|
||||
register_robot_button("80","80","80",2);
|
||||
register_robot_button("FF","80","80",3);
|
||||
register_robot_button("80","FF","80",4);
|
||||
register_robot_button("80","80","FF",5);
|
||||
register_robot_button("FF","FF","80",6);
|
||||
--]]
|
||||
|
||||
for i = 0,9 do register_robot_button_number(i,i+7) end
|
||||
for i = 0,255 do register_robot_button_char(i,i+17) end
|
||||
for i = 0,9 do register_robot_button_number(i,i+17) end -- all buttons shift by 10 from old version!
|
||||
for i = 0,255 do register_robot_button_char(i,i+27) end
|
||||
|
||||
register_robot_button_custom(273,"puzzle_switch_off")
|
||||
register_robot_button_custom(274,"puzzle_switch_on")
|
||||
register_robot_button_custom(275,"puzzle_button_off")
|
||||
register_robot_button_custom(276,"puzzle_button_on")
|
||||
register_robot_button_custom(283,"puzzle_switch_off")
|
||||
register_robot_button_custom(284,"puzzle_switch_on")
|
||||
register_robot_button_custom(285,"puzzle_button_off")
|
||||
register_robot_button_custom(286,"puzzle_button_on")
|
||||
|
||||
register_robot_button_custom(277,"puzzle_equalizer")
|
||||
register_robot_button_custom(278,"puzzle_setter")
|
||||
register_robot_button_custom(279,"puzzle_piston")
|
||||
register_robot_button_custom(287,"puzzle_equalizer")
|
||||
register_robot_button_custom(288,"puzzle_setter")
|
||||
register_robot_button_custom(289,"puzzle_piston")
|
||||
|
||||
register_robot_button_custom(280,"puzzle_diode")
|
||||
register_robot_button_custom(281,"puzzle_NOT")
|
||||
register_robot_button_custom(282,"puzzle_delayer")
|
||||
register_robot_button_custom(283,"puzzle_platform")
|
||||
register_robot_button_custom(290,"puzzle_diode")
|
||||
register_robot_button_custom(291,"puzzle_NOT")
|
||||
register_robot_button_custom(292,"puzzle_delayer")
|
||||
register_robot_button_custom(293,"puzzle_platform")
|
||||
|
||||
register_robot_button_custom(284,"puzzle_giver")
|
||||
register_robot_button_custom(285,"puzzle_checker")
|
||||
register_robot_button_custom(294,"puzzle_giver")
|
||||
register_robot_button_custom(295,"puzzle_checker")
|
||||
|
||||
|
||||
|
||||
|
@ -730,22 +772,12 @@ basic_robot.commands.keyboard = {
|
|||
local nodename;
|
||||
if type == 0 then
|
||||
nodename = "air"
|
||||
elseif type == 1 then
|
||||
nodename = "basic_robot:buttonFFFFFF";
|
||||
elseif type == 2 then
|
||||
nodename = "basic_robot:button808080";
|
||||
elseif type == 3 then
|
||||
nodename = "basic_robot:buttonFF8080";
|
||||
elseif type == 4 then
|
||||
nodename = "basic_robot:button80FF80";
|
||||
elseif type == 5 then
|
||||
nodename = "basic_robot:button8080FF";
|
||||
elseif type == 6 then
|
||||
nodename = "basic_robot:buttonFFFF80";
|
||||
elseif type>=7 and type <= 16 then
|
||||
nodename = "basic_robot:button"..(type-7);
|
||||
elseif type < 17 then
|
||||
nodename = buttoncolors[type]
|
||||
elseif type>=17 and type <= 26 then
|
||||
nodename = "basic_robot:button"..(type-17);
|
||||
else
|
||||
nodename = "basic_robot:button_"..(type-17);
|
||||
nodename = "basic_robot:button_"..(type-27);
|
||||
end
|
||||
|
||||
minetest.swap_node(pos, {name = nodename})
|
||||
|
@ -988,7 +1020,7 @@ basic_robot.commands.machine = {
|
|||
|
||||
check_operations(name,6, true)
|
||||
|
||||
if amount and amount>0 then -- attempt to generate power from builtin generator
|
||||
if amount and amount>0 and amount<10^6 then -- attempt to generate power from builtin generator
|
||||
local pos = basic_robot.data[name].spawnpos; -- position of spawner block
|
||||
local inv = minetest.get_meta(pos):get_inventory();
|
||||
local level = amount*40; -- to generate 1 unit ( coal lump per second ) we need at least upgrade 40
|
||||
|
@ -1162,9 +1194,8 @@ basic_robot.commands.machine = {
|
|||
|
||||
local energy = 0; -- can only do one step at a run time
|
||||
|
||||
|
||||
energy = data.menergy or 0;
|
||||
if amount>energy or amount<0 then return nil,"energy too low" end
|
||||
if amount>energy or amount<0 or amount>10^6 then return nil,"energy too low" end
|
||||
|
||||
if not tdata.menergy then tdata.menergy = 0 end
|
||||
tdata.menergy = tdata.menergy + amount
|
||||
|
|
92
init.lua
92
init.lua
|
@ -1,32 +1,11 @@
|
|||
-- basic_robot by rnd, 2016-2021
|
||||
|
||||
-- basic_robot by rnd, 2016-2022
|
||||
|
||||
basic_robot = {};
|
||||
------ SETTINGS --------
|
||||
basic_robot.call_limit = {50,200,1500,10^9}; -- how many execution calls per script run allowed, for auth levels 0,1,2 (normal, robot, puzzle, admin)
|
||||
basic_robot.count = {2,6,16,128} -- how many robots player can have
|
||||
basic_robot.version = "2022/02/02b";
|
||||
|
||||
basic_robot.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches
|
||||
basic_robot.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running mod, password used for authentifications
|
||||
dofile(minetest.get_modpath("basic_robot").."/settings.lua") -- read configuration SETTINGS
|
||||
|
||||
basic_robot.admin_bot_pos = {x=0,y=1,z=0} -- position of admin robot spawner that will be run automatically on server start
|
||||
|
||||
basic_robot.maxoperations = 10; -- how many operations (dig, place,move,...,generate energy,..) available per run, 0 = unlimited
|
||||
basic_robot.dig_require_energy = true; -- does robot require energy to dig stone?
|
||||
|
||||
basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
|
||||
["moreblocks:circular_saw"] = true,
|
||||
["craft_guide:sign_wall"] = true,
|
||||
["basic_machines:battery_0"] = true,
|
||||
["basic_machines:battery_1"] = true,
|
||||
["basic_machines:battery_2"] = true,
|
||||
["basic_machines:generator"] = true,
|
||||
}
|
||||
----- END OF SETTINGS ------
|
||||
|
||||
basic_robot.http_api = minetest.request_http_api();
|
||||
|
||||
basic_robot.version = "2021/06/28a";
|
||||
-- structures for storing robot data
|
||||
|
||||
basic_robot.gui = {}; local robogui = basic_robot.gui -- gui management
|
||||
basic_robot.data = {}; -- stores all robot related data
|
||||
|
@ -50,7 +29,6 @@ local check_code, preprocess_code,is_inside_string;
|
|||
|
||||
|
||||
-- SANDBOX for running lua code isolated and safely
|
||||
|
||||
function getSandboxEnv (name)
|
||||
|
||||
local authlevel = basic_robot.data[name].authlevel or 0;
|
||||
|
@ -61,7 +39,11 @@ function getSandboxEnv (name)
|
|||
left_up = 11, right_up = 12, forward_up = 13, backward_up = 14
|
||||
}
|
||||
|
||||
if not basic_robot.data[name].rom then basic_robot.data[name].rom = {} end -- create rom if not yet existing
|
||||
local pname = string.sub(name,1,-2)
|
||||
if not basic_robot.data[pname] then basic_robot.data[pname] = {} end
|
||||
-- all robots by player share same rom now
|
||||
if not basic_robot.data[pname].rom then basic_robot.data[pname].rom = {} end -- create rom if not yet existing
|
||||
|
||||
local env =
|
||||
{
|
||||
_Gerror = error,
|
||||
|
@ -93,9 +75,11 @@ function getSandboxEnv (name)
|
|||
return commands.craft(item, mode, idx, amount, name)
|
||||
end,
|
||||
|
||||
pause = function() -- pause coroutine
|
||||
pause = function(amount) -- pause coroutine
|
||||
if not basic_robot.data[name].cor then error("you must start program with '--coroutine' to use pause()") return end
|
||||
coroutine.yield()
|
||||
if not amount or basic_robot.data[name].operations<amount then
|
||||
coroutine.yield()
|
||||
end
|
||||
end,
|
||||
|
||||
self = {
|
||||
|
@ -103,7 +87,7 @@ function getSandboxEnv (name)
|
|||
spawnpos = function() local pos = basic_robot.data[name].spawnpos; return {x=pos.x,y=pos.y,z=pos.z} end,
|
||||
name = function() return name end,
|
||||
operations = function() return basic_robot.data[name].operations end,
|
||||
viewdir = function() local yaw = basic_robot.data[name].obj:getyaw(); return {x=math.cos(yaw), y = 0, z=math.sin(yaw)} end,
|
||||
viewdir = function() local yaw = basic_robot.data[name].obj:getyaw(); return {x=-math.sin(yaw), y = 0, z=math.cos(yaw)} end,
|
||||
|
||||
set_properties = function(properties)
|
||||
if not properties then return end; local obj = basic_robot.data[name].obj;
|
||||
|
@ -173,7 +157,7 @@ function getSandboxEnv (name)
|
|||
reset = function()
|
||||
local pos = basic_robot.data[name].spawnpos;
|
||||
local obj = basic_robot.data[name].obj;
|
||||
obj:set_pos({x=pos.x,y=pos.y+1,z=pos.z}); obj:setyaw(0);
|
||||
obj:set_pos({x=pos.x,y=pos.y+1,z=pos.z}); obj:set_yaw(0);
|
||||
end,
|
||||
|
||||
set_libpos = function(pos)
|
||||
|
@ -351,6 +335,8 @@ function getSandboxEnv (name)
|
|||
write = function(i,title,text)
|
||||
if i<=0 or i > 32 then return nil end
|
||||
local inv = minetest.get_meta(basic_robot.data[name].spawnpos):get_inventory();
|
||||
local stackname = inv:get_stack("library",i):get_name();
|
||||
if basic_robot.data[name].authlevel<3 and (stackname ~= "default:book_written" and stackname~= "default:book") then return nil end
|
||||
local stack = basic_robot.commands.write_book(basic_robot.data[name].owner,title,text);
|
||||
if stack then inv:set_stack("library", i, stack) end
|
||||
end
|
||||
|
@ -369,8 +355,8 @@ function getSandboxEnv (name)
|
|||
end,
|
||||
},
|
||||
|
||||
rom = basic_robot.data[name].rom,
|
||||
|
||||
rom = basic_robot.data[pname].rom,
|
||||
|
||||
string = {
|
||||
byte = string.byte, char = string.char,
|
||||
find = string.find,
|
||||
|
@ -525,7 +511,7 @@ function getSandboxEnv (name)
|
|||
|
||||
setfenv( ScriptFunc, basic_robot.data[name].sandbox )
|
||||
|
||||
local Result, RuntimeError = pcall( ScriptFunc );
|
||||
local _, RuntimeError = pcall( ScriptFunc );
|
||||
if RuntimeError then
|
||||
minetest.chat_send_player(name, "#code.run: run error " .. RuntimeError )
|
||||
return false
|
||||
|
@ -592,10 +578,13 @@ function getSandboxEnv (name)
|
|||
end
|
||||
|
||||
-- code checker
|
||||
-- bugfixes:
|
||||
-- player Midskip found problem with code checking, fixed
|
||||
|
||||
|
||||
check_code = function(code)
|
||||
--"while ", "for ", "do ","goto ",
|
||||
local bad_code = {"repeat", "until", "_G", "while%(", "while{", "pcall","%.%.[^%.]"} --,"\\\"", "%[=*%[","--[["}
|
||||
local bad_code = {"repeat", "until", "_G", "while%(", "while{", "pcall","[^%.]%.%.[^%.]","\\\"","\\\'","%[=*%["}
|
||||
for _, v in pairs(bad_code) do
|
||||
if string.find(code, v) then
|
||||
return v .. " is not allowed!";
|
||||
|
@ -603,8 +592,7 @@ check_code = function(code)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
local identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
|
||||
identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
|
||||
|
||||
local i = 0; local j; local _; local length = string.len(code);
|
||||
local mode = 0; -- 0: not in string, 1: in '...' string, 2: in "..." string, 3. in [==[ ... ]==] string
|
||||
|
@ -622,8 +610,12 @@ local identify_strings = function(code) -- returns list of positions {start,end}
|
|||
for k=1,#modes do
|
||||
j = string.find(code,modes[k][1],i);
|
||||
if j and j<jmin then -- pick closest one
|
||||
jmin = j
|
||||
mode = k
|
||||
if string.sub(code,j-1,j-1) ~="\\" then
|
||||
jmin = j
|
||||
mode = k
|
||||
else
|
||||
j=j+1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if mode ~= 0 then -- found something
|
||||
|
@ -634,10 +626,12 @@ local identify_strings = function(code) -- returns list of positions {start,end}
|
|||
else
|
||||
_,j = string.find(code,modes[mode][2],i); -- search for closing pair
|
||||
if not j then break end
|
||||
if (mode~=2 or (string.sub(code,j-1,j-1) ~= "\\") or string.sub(code,j-2,j-1) == "\\\\") then -- not (" and not \" - but "\\" is allowed)
|
||||
local pchar = string.sub(code,j-1,j-1)
|
||||
if (mode~=2 or (pchar ~= "\\") or string.sub(code,j-2,j-1) == "\\\\") then -- not (" and not \" - but "\\" is allowed)
|
||||
ret[#ret][2] = j
|
||||
mode = 0
|
||||
end
|
||||
if pchar == "\\" then j=j+1 end
|
||||
end
|
||||
i=j -- move to next position
|
||||
end
|
||||
|
@ -683,8 +677,8 @@ preprocess_code = function(script, call_limit) -- version 07/24/2018
|
|||
when counter exceeds limit exit with error
|
||||
--]]
|
||||
|
||||
script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-[^\n]*\n","\n") -- strip comments
|
||||
|
||||
--script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-[^\n]*\n","\n") -- strip comments
|
||||
script = string.gsub(script,"%-%-[^\n]+\n","\n") -- strip single line comments, multiline not allowed
|
||||
-- process script to insert call counter in every function
|
||||
local _increase_ccounter = " _Gc = _Gc + 1; if _Gc > " .. call_limit ..
|
||||
" then _Gerror(\"Execution count \".. _Gc .. \" exceeded ".. call_limit .. "\") end; "
|
||||
|
@ -746,7 +740,7 @@ preprocess_code = function(script, call_limit) -- version 07/24/2018
|
|||
-- must reset ccounter when paused, but user should not be able to force reset by modifying pause!
|
||||
-- (suggestion about 'pause' by Kimapr, 09/26/2019)
|
||||
|
||||
return "_Gc = 0 local _Gpause = pause pause = function() _Gc = 0; _Gpause() end " .. script;
|
||||
return "_Gc = 0 local _Gpause = pause pause = function(amount) _Gc = 0; _Gpause(amount) end " .. script;
|
||||
|
||||
--return script:gsub("pause%(%)", "_c_ = 0; pause()") -- reset ccounter at pause
|
||||
end
|
||||
|
@ -803,7 +797,7 @@ local function runSandbox( name)
|
|||
end
|
||||
|
||||
data.operations = basic_robot.maxoperations;
|
||||
data.t = os.clock()
|
||||
data.t = os.clock() -- timing
|
||||
|
||||
setfenv( ScriptFunc, data.sandbox )
|
||||
|
||||
|
@ -1052,7 +1046,7 @@ minetest.register_entity("basic_robot:robot",{
|
|||
minetest.set_node(pos, {name = "air"});
|
||||
--local privs = core.get_player_privs(self.owner);privs.interact = false;
|
||||
--core.set_player_privs(self.owner, privs); minetest.auth_reload()
|
||||
minetest.kick_player(self.owner, "#basic_robot: stack overflow")
|
||||
minetest.kick_player(self.owner, "#basic_robot: stack overflow at " .. pos.x.. " " .. pos.y .. " " .. pos.z)
|
||||
end
|
||||
|
||||
local name = self.name;
|
||||
|
@ -1224,7 +1218,6 @@ local spawn_robot = function(pos,node,ttl)
|
|||
if data == nil then
|
||||
basic_robot.data[name] = {};
|
||||
data = basic_robot.data[name];
|
||||
--data.rom = {};
|
||||
end
|
||||
|
||||
data.owner = owner;
|
||||
|
@ -1707,7 +1700,6 @@ minetest.register_node("basic_robot:spawner", {
|
|||
paramtype = "light",
|
||||
param1=1,
|
||||
walkable = true,
|
||||
alpha = 150,
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
|
||||
|
@ -1830,6 +1822,8 @@ end
|
|||
|
||||
|
||||
-- remote control
|
||||
|
||||
local write_keyevent = basic_robot.commands.write_keyevent;
|
||||
minetest.register_craftitem("basic_robot:control", {
|
||||
description = "Robot remote control",
|
||||
inventory_image = "control.png",
|
||||
|
@ -1868,7 +1862,9 @@ minetest.register_craftitem("basic_robot:control", {
|
|||
local hppos = minetest.hash_node_position(ppos)
|
||||
local rname = basic_robot.data.punchareas[hppos];
|
||||
local data = basic_robot.data[rname];
|
||||
if data then data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = owner, type = 0} end
|
||||
if data then
|
||||
write_keyevent(data,pos, owner,0)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
name = basic_robot
|
||||
depends = default
|
||||
optional_depends =
|
||||
description = your ingame robot companion. learn how to program and make games
|
21
robogui.lua
21
robogui.lua
|
@ -145,7 +145,8 @@ local help_pages = {
|
|||
" 7. [TECHNIC FUNCTIONALITY]",
|
||||
" 8. [CRYPTOGRAPHY]",
|
||||
" 9. [PUZZLE]",
|
||||
" 10.[COROUTINES] - easier alternative to finite state machines",
|
||||
" 10.[COROUTINES AND LIBRARIES AND ROM] - easier alternative to",
|
||||
" finite state machines",
|
||||
},
|
||||
|
||||
["MOVEMENT DIGGING PLACING NODE SENSING"] = {
|
||||
|
@ -312,17 +313,29 @@ local help_pages = {
|
|||
" add_particle(def)"
|
||||
},
|
||||
|
||||
["COROUTINES"] = {
|
||||
["COROUTINES AND LIBRARIES AND ROM"] = {
|
||||
"back to [Commands reference]",
|
||||
"COROUTINES","",
|
||||
"robot can run code using lua coroutines. To enable this mode just put the word",
|
||||
"coroutine in the first 32 characters of your program. Example: ", "",
|
||||
"robot can run code using lua coroutines. To enable this mode just put",
|
||||
"the word coroutine in the first 32 characters of your program. Example:",
|
||||
" --testing program for coroutine",
|
||||
" for i = 1,5 do ",
|
||||
" say(i); dig.forward(); move.forward()",
|
||||
" pause()",
|
||||
" end",
|
||||
"pause(amount) temporarily stops if available operations are less than",
|
||||
" amount","",
|
||||
"LIBRARIES","",
|
||||
"you can define functions for robot in another robot and re-use them later.",
|
||||
"for example do: rom.lib_src = \"f1 = function(x) return 2*x end\" and later",
|
||||
"in another robot recreate function with: ",
|
||||
"if not f1 then code.run(rom.lib_src) end ",
|
||||
"self.label(f1(1))","",
|
||||
"ROM","",
|
||||
"all robots by a player share same \"rom\" variable that can be used to",
|
||||
"store more persistent data like numbers, strings or tables",
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -1,210 +1,211 @@
|
|||
--black box by rnd, 03/18/2017
|
||||
--https://en.wikipedia.org/wiki/Black_Box_(game)
|
||||
|
||||
if not data then
|
||||
-- novice: 8x8, 4
|
||||
m=8;n=8;
|
||||
atoms = 8
|
||||
attempts = 1;turn = 0;
|
||||
spawnpos = self.spawnpos(); spawnpos.x = spawnpos.x-m/2; spawnpos.y = spawnpos.y+2; spawnpos.z = spawnpos.z-n/2
|
||||
|
||||
local players = find_player(5,spawnpos);
|
||||
if not player then self.remove() else pname = players[1] end
|
||||
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
self.spam(1);t0 = _G.minetest.get_gametime();
|
||||
data = {};
|
||||
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
|
||||
data[math.random(m)][math.random(n)] = 1
|
||||
end
|
||||
|
||||
atoms = 0
|
||||
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
|
||||
for i = 1,m do for j = 1,n do -- render game
|
||||
if mode == 0 or data[i][j] == 0 then
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
|
||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2)
|
||||
end
|
||||
else
|
||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},3)
|
||||
end
|
||||
end end
|
||||
end
|
||||
|
||||
get_dirl = function(dir)
|
||||
local dirl; -- direction left
|
||||
if dir[1] > 0.5 then dirl = {0,-1}
|
||||
elseif dir[1] < -0.5 then dirl = {0,1}
|
||||
elseif dir[2] > 0.5 then dirl = {-1,0}
|
||||
elseif dir[2] < -0.5 then dirl = {1,0}
|
||||
end
|
||||
return dirl
|
||||
end
|
||||
|
||||
read_pos = function(x,z)
|
||||
if x<1 or x>m or z<1 or z>n then return nil end
|
||||
return data[x][z]
|
||||
end
|
||||
|
||||
newdir = function(x,z,dir) -- where will ray go next
|
||||
local retdir = {dir[1],dir[2]};
|
||||
local xf = x+dir[1]; local zf = z+dir[2] -- forward
|
||||
local dirl = get_dirl(dir)
|
||||
|
||||
local nodef = read_pos(xf,zf)
|
||||
local nodel = read_pos(xf + dirl[1],zf + dirl[2])
|
||||
local noder = read_pos(xf - dirl[1],zf - dirl[2])
|
||||
if nodef == 1 then
|
||||
retdir = {0,0} -- ray hit something
|
||||
elseif nodel == 1 and noder ~= 1 then
|
||||
retdir = {-dirl[1],-dirl[2]}
|
||||
elseif nodel ~= 1 and noder == 1 then
|
||||
retdir = {dirl[1],dirl[2]}
|
||||
elseif nodel == 1 and noder == 1 then
|
||||
retdir = {-dir[1],-dir[2]}
|
||||
end
|
||||
return retdir
|
||||
end
|
||||
|
||||
shootray = function(x,z,dir)
|
||||
--say("ray starts " .. x .. " " .. z .. " dir " .. dir[1] .. " " .. dir[2])
|
||||
local xp = x; local zp = z;
|
||||
local dirp = {dir[1],dir[2]};
|
||||
local maxstep = m*n;
|
||||
|
||||
for i = 1,maxstep do
|
||||
dirp = newdir(xp,zp,dirp);
|
||||
if dirp[1]==0 and dirp[2]==0 then return -i end -- hit
|
||||
xp=xp+dirp[1];zp=zp+dirp[2];
|
||||
if xp<1 or xp>m or zp<1 or zp>n then return i,{xp,zp} end -- out
|
||||
end
|
||||
return 0 -- hit
|
||||
end
|
||||
|
||||
count = 0; -- how many letters were used up
|
||||
border_start_ray = function(x,z)
|
||||
local rdir
|
||||
if x==0 then rdir = {1,0}
|
||||
elseif x == m+1 then rdir = {-1,0}
|
||||
elseif z == 0 then rdir = {0,1}
|
||||
elseif z == n+1 then rdir = {0,-1}
|
||||
end
|
||||
if rdir then
|
||||
local result,out = shootray(x,z,rdir);
|
||||
if result >= 0 then
|
||||
|
||||
if out then
|
||||
if out[1]==x and out[2]==z then -- got back where it originated, reflection
|
||||
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},1);
|
||||
else
|
||||
if result<=1 then
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},6); -- immediate bounce off
|
||||
else
|
||||
local nodename = "basic_robot:button_"..(65+count);
|
||||
_G.minetest.set_node(
|
||||
{x=spawnpos.x+out[1],y=spawnpos.y+1,z=spawnpos.z+out[2]},
|
||||
{name = nodename, param2 = 1})
|
||||
_G.minetest.set_node(
|
||||
{x=spawnpos.x+x,y=spawnpos.y+1,z=spawnpos.z+z},
|
||||
{name = nodename, param2 = 1})
|
||||
count = count + 1;
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4);
|
||||
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},4);
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif result<0 then
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3); -- hit
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- initial border loop and marking
|
||||
|
||||
--render blue border
|
||||
for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+0},5) keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+n+1},5) end
|
||||
for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y,z=spawnpos.z+j},5) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y,z=spawnpos.z+j},5) end
|
||||
|
||||
for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+0},0) keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+n+1},0) end
|
||||
for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y+1,z=spawnpos.z+j},0) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y+1,z=spawnpos.z+j},0) end
|
||||
|
||||
|
||||
z=0 -- bottom
|
||||
for x = 1,m do
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
|
||||
border_start_ray(x,z)
|
||||
end
|
||||
end
|
||||
|
||||
x=m+1 -- right
|
||||
for z = 1,n do
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
|
||||
border_start_ray(x,z)
|
||||
end
|
||||
end
|
||||
|
||||
z=n+1 -- top
|
||||
for x = m,1,-1 do
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
|
||||
border_start_ray(x,z)
|
||||
end
|
||||
end
|
||||
|
||||
x=0 -- left
|
||||
for z = n,1,-1 do
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
|
||||
border_start_ray(x,z)
|
||||
end
|
||||
end
|
||||
|
||||
check_solution = function()
|
||||
for i = 1,m do
|
||||
for j = 1,n do
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}) == "basic_robot:buttonFF8080" then -- red
|
||||
if data[i][j]~=1 then return false end
|
||||
else
|
||||
if data[i][j]~=0 then return false end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--render board
|
||||
render_board(0)
|
||||
keyboard.set({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z-1},4)
|
||||
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z-1},5)
|
||||
self.label("BLACKBOX with " .. atoms .. " atoms")
|
||||
|
||||
end
|
||||
|
||||
event = keyboard.get();
|
||||
if event then
|
||||
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
||||
if x<1 or x>m or z<1 or z>n then
|
||||
if event.type == 4 then
|
||||
if check_solution() then
|
||||
say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove()
|
||||
else
|
||||
say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.")
|
||||
attempts = attempts+1
|
||||
end
|
||||
elseif event.type == 5 then
|
||||
say("#BLACKBOX : DISPLAYING SOLUTION",pname)
|
||||
render_board(1)
|
||||
self.remove()
|
||||
end
|
||||
else -- interior punch
|
||||
nodetype = 2;
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button808080" then
|
||||
nodetype = 3
|
||||
end
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype);
|
||||
end
|
||||
|
||||
end
|
||||
--black box by rnd, 03/18/2017
|
||||
--https://en.wikipedia.org/wiki/Black_Box_(game)
|
||||
|
||||
if not data then
|
||||
-- novice: 8x8, 4
|
||||
m=9;n=9;
|
||||
atoms = 16
|
||||
attempts = 1;turn = 0;
|
||||
spawnpos = self.spawnpos(); spawnpos.x = spawnpos.x-math.floor(m/2); spawnpos.y = spawnpos.y+2; spawnpos.z = spawnpos.z-math.floor(n/2)
|
||||
|
||||
local players = find_player(5,spawnpos);
|
||||
if not player then self.remove() else pname = players[1] end
|
||||
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
self.spam(1);t0 = _G.minetest.get_gametime();
|
||||
data = {};
|
||||
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
|
||||
data[math.random(m)][math.random(n)] = 1
|
||||
end
|
||||
|
||||
atoms = 0
|
||||
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
|
||||
for i = 1,m do for j = 1,n do -- render game
|
||||
if mode == 0 or data[i][j] == 0 then
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:buttongray" then
|
||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},15) -- 2 gray
|
||||
end
|
||||
else
|
||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},4) --on 3
|
||||
end
|
||||
end end
|
||||
end
|
||||
|
||||
get_dirl = function(dir)
|
||||
local dirl; -- direction left
|
||||
if dir[1] > 0.5 then dirl = {0,-1}
|
||||
elseif dir[1] < -0.5 then dirl = {0,1}
|
||||
elseif dir[2] > 0.5 then dirl = {-1,0}
|
||||
elseif dir[2] < -0.5 then dirl = {1,0}
|
||||
end
|
||||
return dirl
|
||||
end
|
||||
|
||||
read_pos = function(x,z)
|
||||
if x<1 or x>m or z<1 or z>n then return nil end
|
||||
return data[x][z]
|
||||
end
|
||||
|
||||
newdir = function(x,z,dir) -- where will ray go next
|
||||
local retdir = {dir[1],dir[2]};
|
||||
local xf = x+dir[1]; local zf = z+dir[2] -- forward
|
||||
local dirl = get_dirl(dir)
|
||||
|
||||
local nodef = read_pos(xf,zf)
|
||||
local nodel = read_pos(xf + dirl[1],zf + dirl[2])
|
||||
local noder = read_pos(xf - dirl[1],zf - dirl[2])
|
||||
if nodef == 1 then
|
||||
retdir = {0,0} -- ray hit something
|
||||
elseif nodel == 1 and noder ~= 1 then
|
||||
retdir = {-dirl[1],-dirl[2]}
|
||||
elseif nodel ~= 1 and noder == 1 then
|
||||
retdir = {dirl[1],dirl[2]}
|
||||
elseif nodel == 1 and noder == 1 then
|
||||
retdir = {-dir[1],-dir[2]}
|
||||
end
|
||||
return retdir
|
||||
end
|
||||
|
||||
shootray = function(x,z,dir)
|
||||
--say("ray starts " .. x .. " " .. z .. " dir " .. dir[1] .. " " .. dir[2])
|
||||
local xp = x; local zp = z;
|
||||
local dirp = {dir[1],dir[2]};
|
||||
local maxstep = m*n;
|
||||
|
||||
for i = 1,maxstep do
|
||||
dirp = newdir(xp,zp,dirp);
|
||||
if dirp[1]==0 and dirp[2]==0 then return -i end -- hit
|
||||
xp=xp+dirp[1];zp=zp+dirp[2];
|
||||
if xp<1 or xp>m or zp<1 or zp>n then return i,{xp,zp} end -- out
|
||||
end
|
||||
return 0 -- hit
|
||||
end
|
||||
|
||||
count = 0; -- how many letters were used up
|
||||
border_start_ray = function(x,z)
|
||||
local rdir
|
||||
if x==0 then rdir = {1,0}
|
||||
elseif x == m+1 then rdir = {-1,0}
|
||||
elseif z == 0 then rdir = {0,1}
|
||||
elseif z == n+1 then rdir = {0,-1}
|
||||
end
|
||||
if rdir then
|
||||
local result,out = shootray(x,z,rdir);
|
||||
if result >= 0 then
|
||||
|
||||
if out then
|
||||
if out[1]==x and out[2]==z then -- got back where it originated, reflection
|
||||
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},1);
|
||||
else
|
||||
if result<=1 then
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},6); -- immediate bounce off
|
||||
else
|
||||
local nodename = "basic_robot:button_"..(65+count);
|
||||
_G.minetest.set_node(
|
||||
{x=spawnpos.x+out[1],y=spawnpos.y+1,z=spawnpos.z+out[2]},
|
||||
{name = nodename, param2 = 1})
|
||||
_G.minetest.set_node(
|
||||
{x=spawnpos.x+x,y=spawnpos.y+1,z=spawnpos.z+z},
|
||||
{name = nodename, param2 = 1})
|
||||
count = count + 1;
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4);
|
||||
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},4);
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif result<0 then
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3); -- hit
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- initial border loop and marking
|
||||
|
||||
--render blue border
|
||||
for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+0},7) keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+n+1},7) end
|
||||
for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y,z=spawnpos.z+j},7) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y,z=spawnpos.z+j},7) end
|
||||
|
||||
for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+0},0) keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+n+1},0) end
|
||||
for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y+1,z=spawnpos.z+j},0) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y+1,z=spawnpos.z+j},0) end
|
||||
|
||||
|
||||
z=0 -- bottom
|
||||
for x = 1,m do
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" then
|
||||
border_start_ray(x,z)
|
||||
end
|
||||
end
|
||||
|
||||
x=m+1 -- right
|
||||
for z = 1,n do
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" then
|
||||
border_start_ray(x,z)
|
||||
end
|
||||
end
|
||||
|
||||
z=n+1 -- top
|
||||
for x = m,1,-1 do
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" then
|
||||
border_start_ray(x,z)
|
||||
end
|
||||
end
|
||||
|
||||
x=0 -- left
|
||||
for z = n,1,-1 do
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" then
|
||||
border_start_ray(x,z)
|
||||
end
|
||||
end
|
||||
|
||||
check_solution = function()
|
||||
for i = 1,m do
|
||||
for j = 1,n do
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}) == "basic_robot:buttonred" then -- red
|
||||
if data[i][j]~=1 then return false end
|
||||
else
|
||||
if data[i][j]~=0 then return false end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--render board
|
||||
render_board(0)
|
||||
keyboard.set({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z-1},9)
|
||||
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z-1},7)
|
||||
self.label("BLACKBOX with " .. atoms .. " atoms")
|
||||
|
||||
end
|
||||
|
||||
event = keyboard.get();
|
||||
if event then
|
||||
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
||||
--self.label(serialize(event))
|
||||
if x<1 or x>m or z<1 or z>n then
|
||||
if event.type == 9 then
|
||||
if check_solution() then
|
||||
say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove()
|
||||
else
|
||||
say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.")
|
||||
attempts = attempts+1
|
||||
end
|
||||
elseif event.type == 7 then
|
||||
say("#BLACKBOX : DISPLAYING SOLUTION",pname)
|
||||
render_board(1)
|
||||
self.remove()
|
||||
end
|
||||
else -- interior punch
|
||||
nodetype = 4;
|
||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonred" then
|
||||
nodetype = 15
|
||||
end
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype);
|
||||
end
|
||||
|
||||
end
|
||||
::END::
|
|
@ -1,67 +1,67 @@
|
|||
-- CONNECT, coded in 20 minutes by rnd
|
||||
if not data then
|
||||
m=10;n=10;turn = 0; num = 5;
|
||||
-- m=3;n=3;turn = 0; num = 3;
|
||||
self.spam(1);t0 = _G.minetest.get_gametime();
|
||||
spawnpos = self.spawnpos() -- place mines
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
state = 0; -- 0 signup 1 game
|
||||
players = {};
|
||||
data = {};
|
||||
for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end
|
||||
for i = 1,m do for j = 1,n do -- render game
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
|
||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2)
|
||||
end
|
||||
end end
|
||||
|
||||
get_count_in_dir = function(dir,x,y)
|
||||
local r = num; -- num=4? in a row
|
||||
local snode = data[x][y];local count = 1;
|
||||
for j = 1,2 do
|
||||
for i = 1,r-1 do
|
||||
local x1 = x + dir[1]*i;local y1 = y + dir[2]*i;
|
||||
if not data[x1] or not data[x1][y1] then break end; if data[x1][y1]~= snode then break end
|
||||
count = count +1
|
||||
end
|
||||
dir[1]=-dir[1];dir[2]=-dir[2];
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
get_count = function(x,y)
|
||||
local c1 = get_count_in_dir({0,1},x,y); local c2 = get_count_in_dir({1,0},x,y)
|
||||
local c3 = get_count_in_dir({1,1},x,y); local c4 = get_count_in_dir({1,-1},x,y)
|
||||
if c2>c1 then c1 = c2 end; if c3>c1 then c1 = c3 end; if c4>c1 then c1 = c4 end
|
||||
return c1
|
||||
end
|
||||
|
||||
self.label("TRY TO GET FIRST " .. num .. " IN A ROW! : GREEN starts play. 2 players punch to join game.")
|
||||
end
|
||||
|
||||
event = keyboard.get();
|
||||
if event then
|
||||
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
||||
if x<1 or x>m or z<1 or z>n then
|
||||
elseif event.type == 2 then --if event.type == 2 then
|
||||
if state == 0 then
|
||||
if #players<2 then players[#players+1] = event.puncher -- 1 is green, turn 0 = green
|
||||
else state = 1 end
|
||||
if #players==2 then state = 1 end
|
||||
end
|
||||
if event.puncher == players[1] then -- green
|
||||
if turn~=0 then return end -- ignore if not player turn
|
||||
else
|
||||
if turn~=1 then return end
|
||||
end
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4+turn);
|
||||
data[x][z] = 4+turn;
|
||||
if get_count(x,z) == num then say("CONGRATULATIONS! " .. event.puncher .. " has "..num .. " in a row"); self.remove(); goto END end
|
||||
turn = 1-turn
|
||||
if state == 1 then
|
||||
local msg = ""; if turn == 0 then msg = "GREEN " else msg = "BLUE" end
|
||||
self.label(msg .. " : " .. players[turn+1])
|
||||
end
|
||||
end
|
||||
end
|
||||
-- CONNECT, coded in 20 minutes by rnd
|
||||
if not data then
|
||||
m=10;n=10;turn = 0; num = 4;
|
||||
|
||||
self.spam(1);t0 = _G.minetest.get_gametime();
|
||||
spawnpos = self.spawnpos() -- place mines
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
state = 0; -- 0 signup 1 game
|
||||
players = {};
|
||||
data = {};
|
||||
for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end
|
||||
for i = 1,m do for j = 1,n do -- render game
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:buttonlight_gray" then
|
||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},13)
|
||||
end
|
||||
end end
|
||||
|
||||
get_count_in_dir = function(dir,x,y)
|
||||
local r = num; -- num=4? in a row
|
||||
local snode = data[x][y];local count = 1;
|
||||
for j = 1,2 do
|
||||
for i = 1,r-1 do
|
||||
local x1 = x + dir[1]*i;local y1 = y + dir[2]*i;
|
||||
if not data[x1] or not data[x1][y1] then break end; if data[x1][y1]~= snode then break end
|
||||
count = count +1
|
||||
end
|
||||
dir[1]=-dir[1];dir[2]=-dir[2];
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
get_count = function(x,y)
|
||||
local c1 = get_count_in_dir({0,1},x,y); local c2 = get_count_in_dir({1,0},x,y)
|
||||
local c3 = get_count_in_dir({1,1},x,y); local c4 = get_count_in_dir({1,-1},x,y)
|
||||
if c2>c1 then c1 = c2 end; if c3>c1 then c1 = c3 end; if c4>c1 then c1 = c4 end
|
||||
return c1
|
||||
end
|
||||
|
||||
self.label("TRY TO GET FIRST " .. num .. " IN A ROW! : GREEN starts play. 2 players punch to join game.")
|
||||
end
|
||||
|
||||
event = keyboard.get();
|
||||
if event then
|
||||
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
||||
if x<1 or x>m or z<1 or z>n then
|
||||
elseif event.type == 13 then --if event.type == 2 then
|
||||
if state == 0 then
|
||||
if #players<2 then players[#players+1] = event.puncher -- 1 is green, turn 0 = green
|
||||
else state = 1 end
|
||||
if #players==2 then state = 1 end
|
||||
end
|
||||
if event.puncher == players[1] then -- green
|
||||
if turn~=0 then return end -- ignore if not player turn
|
||||
else
|
||||
if turn~=1 then return end
|
||||
end
|
||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4+turn);
|
||||
data[x][z] = 4+turn;
|
||||
if get_count(x,z) == num then say("CONGRATULATIONS! " .. event.puncher .. " has "..num .. " in a row"); self.remove(); goto END end
|
||||
turn = 1-turn
|
||||
if state == 1 then
|
||||
local msg = ""; if turn == 0 then msg = "GREEN " else msg = "BLUE" end
|
||||
self.label(msg .. " : " .. players[turn+1])
|
||||
end
|
||||
end
|
||||
end
|
||||
::END::
|
|
@ -1,106 +1,140 @@
|
|||
--HIDE AND SEEK game robot, by rnd
|
||||
if not gamemaster then
|
||||
timeout = 10;
|
||||
gamemaster = "rnd"
|
||||
player_list = {};
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK .. say #hide to join play")
|
||||
s=0;t=0; count = 0;
|
||||
_G.minetest.forceload_block(self.pos(),true)
|
||||
self.listen(1); self.label(colorize("yellow","HIDE&SEEK"))
|
||||
end
|
||||
|
||||
speaker,msg = self.listen_msg();
|
||||
|
||||
if s==0 then
|
||||
if msg =="#hide" then
|
||||
player_list[speaker]={};
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. speaker .. " joined the game")
|
||||
local player = _G.minetest.get_player_by_name(speaker);
|
||||
if player then
|
||||
player:setpos({x=0,y=5,z=0});player:set_properties({nametag_color = "0x0"})
|
||||
end
|
||||
|
||||
end
|
||||
if msg == "#start" and speaker == gamemaster then s = 0.5 _G.minetest.chat_send_all("# HIDE AND SEEK STARTS in " .. timeout .. " SECONDS!") end
|
||||
|
||||
elseif s==0.5 then
|
||||
t=t+1
|
||||
if t==timeout then
|
||||
t=0;s = 1; count = 0;
|
||||
for pname,_ in pairs(player_list) do
|
||||
local player = _G.minetest.get_player_by_name(pname);
|
||||
if player then
|
||||
player_list[pname].hp = player:get_hp();
|
||||
player_list[pname].pos = player:getpos()
|
||||
player_list[pname].t = 0;
|
||||
count = count+1
|
||||
end
|
||||
end
|
||||
if count == 1 then
|
||||
gamemaster = false; _G.minetest.chat_send_all("# HIDE AND SEEK only 1 player, aborting.")
|
||||
else
|
||||
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK STARTS NOW WITH " .. count .. " PLAYERS. You are out if: 1.your health changes, 2. leave spawn. If stay in same area for too long or you will be exposed."))
|
||||
end
|
||||
|
||||
end
|
||||
elseif s==1 then
|
||||
players = _G.minetest.get_connected_players();
|
||||
count = 0;
|
||||
for _,player in pairs(players) do
|
||||
local name = player:get_player_name();
|
||||
local data = player_list[name];
|
||||
if data then
|
||||
count=count+1
|
||||
local pos = player:getpos();
|
||||
local dist = math.max(math.abs(pos.x),math.abs(pos.y),math.abs(pos.z));
|
||||
if dist>50 or (not _G.minetest.get_player_by_name(name)) then
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! went too far away " )
|
||||
player:set_properties({nametag_color = "white"})
|
||||
player_list[name] = nil;
|
||||
end
|
||||
if data.hp ~= player:get_hp() then
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! his health changed!" )
|
||||
player:set_properties({nametag_color = "white"})
|
||||
player_list[name] = nil;
|
||||
end
|
||||
|
||||
--expose campers
|
||||
local p = data.pos;
|
||||
dist = math.max(math.abs(pos.x-p.x),math.abs(pos.y-p.y),math.abs(pos.z-p.z));
|
||||
--say( name .. " dist " .. dist .. " t " .. data.t)
|
||||
if dist<8 then
|
||||
data.t = data.t+1;
|
||||
if not data.camp then
|
||||
if data.t>15 and not data.camp then
|
||||
_G.minetest.chat_send_player(name, "# HIDE AND SEEK: move in 5s or be exposed")
|
||||
data.camp = true
|
||||
end
|
||||
elseif data.t>=20 then
|
||||
pos.x=math.ceil(pos.x);pos.y=math.ceil(pos.y);pos.z=math.ceil(pos.z);
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. name .. " is camping at " .. pos.x .. " " .. pos.z)
|
||||
data.camp = false; data.t = 0
|
||||
end
|
||||
else
|
||||
data.t = 0; data.pos = player:getpos(); data.camp = false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
self.label(count)
|
||||
|
||||
if count<=1 then
|
||||
if count==1 then
|
||||
for name,_ in pairs(player_list) do
|
||||
player0=_G.minetest.get_player_by_name(name)
|
||||
_G.minetest.chat_send_all(colorize("red","****** HIDE AND SEEK: ".. name .. " wins ******"))
|
||||
player0:set_properties({nametag_color = "white"})
|
||||
gamemaster = false;
|
||||
end
|
||||
else
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK: no players left")
|
||||
gamemaster = false;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
--HIDE AND SEEK game robot, by rnd
|
||||
if not gamemaster then
|
||||
timeout = 20;
|
||||
fardist = 300
|
||||
gamemaster = "rnd"
|
||||
|
||||
_G.minetest.forceload_block(self.pos(),true)
|
||||
self.listen(1);
|
||||
centerpos = {x=160,y= 606,z= 227};
|
||||
|
||||
init_game = function()
|
||||
self.label(colorize("yellow","HIDE&SEEK .. waiting for players .. say #hide to join"))
|
||||
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK .. say #hide to join play, when all joined say #start to start game."))
|
||||
s=0;t=0; count = 0;
|
||||
player_list = {}
|
||||
end
|
||||
|
||||
reset_name = function(name)
|
||||
if name then
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return end
|
||||
player:set_properties({nametag_color = "white"})
|
||||
return
|
||||
end
|
||||
local players = _G.minetest.get_connected_players();
|
||||
for _,player in pairs(players) do
|
||||
local name = player:get_player_name();
|
||||
local data = player_list[name];
|
||||
if data then
|
||||
player:set_properties({nametag_color = "white"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
show_players = function()
|
||||
local ret = {}
|
||||
for k,v in pairs(player_list) do
|
||||
ret[#ret+1]=k
|
||||
end
|
||||
self.label("hide and seek, players: " .. table.concat(ret,", "))
|
||||
end
|
||||
init_game()
|
||||
end
|
||||
|
||||
speaker,msg = self.listen_msg();
|
||||
|
||||
if s==0 then
|
||||
if msg =="#hide" then
|
||||
player_list[speaker]={};
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. speaker .. " joined the game")
|
||||
local player = _G.minetest.get_player_by_name(speaker);
|
||||
if player then
|
||||
player:setpos(centerpos);player:set_properties({nametag_color = "0x0"})
|
||||
end
|
||||
|
||||
end
|
||||
if msg == "#start" and speaker == gamemaster then s = 0.5 _G.minetest.chat_send_all("# HIDE AND SEEK STARTS in " .. timeout .. " SECONDS!") end
|
||||
|
||||
elseif s==0.5 then
|
||||
t=t+1
|
||||
if t==timeout then
|
||||
t=0;s = 1; count = 0;
|
||||
for pname,_ in pairs(player_list) do
|
||||
local player = _G.minetest.get_player_by_name(pname);
|
||||
if player then
|
||||
player_list[pname].hp = player:get_hp();
|
||||
player_list[pname].pos = player:getpos()
|
||||
player_list[pname].t = 0;
|
||||
count = count+1
|
||||
end
|
||||
end
|
||||
if count == 1 then
|
||||
gamemaster = false; _G.minetest.chat_send_all("# HIDE AND SEEK only 1 player, aborting.")
|
||||
else
|
||||
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK STARTS NOW WITH " .. count .. " PLAYERS. You are out if: 1.your health changes, 2. leave spawn. If stay in same area for too long or you will be exposed."))
|
||||
end
|
||||
|
||||
end
|
||||
elseif s==1 then
|
||||
players = _G.minetest.get_connected_players();
|
||||
count = 0;
|
||||
for _,player in pairs(players) do
|
||||
local name = player:get_player_name();
|
||||
local data = player_list[name];
|
||||
if data then
|
||||
count=count+1
|
||||
local pos = player:getpos();
|
||||
local dist = math.max(math.abs(pos.x-centerpos.x),math.abs(pos.y-centerpos.y),math.abs(pos.z-centerpos.z));
|
||||
if dist>fardist or (not _G.minetest.get_player_by_name(name)) then
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! went too far away " )
|
||||
reset_name(name)
|
||||
show_players()
|
||||
player_list[name] = nil;
|
||||
end
|
||||
if data.hp < player:get_hp() then
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! his health changed!" )
|
||||
player:set_properties({nametag_color = "white"})
|
||||
player:setpos(centerpos)
|
||||
player_list[name] = nil;
|
||||
show_players()
|
||||
end
|
||||
|
||||
--expose campers
|
||||
local p = data.pos;
|
||||
dist = math.max(math.abs(pos.x-p.x),math.abs(pos.y-p.y),math.abs(pos.z-p.z));
|
||||
--say( name .. " dist " .. dist .. " t " .. data.t)
|
||||
if dist<8 then
|
||||
data.t = data.t+1;
|
||||
if not data.camp then
|
||||
if data.t>15 and not data.camp then
|
||||
_G.minetest.chat_send_player(name, "# HIDE AND SEEK: move in 5s or be exposed")
|
||||
data.camp = true
|
||||
end
|
||||
elseif data.t>=20 then
|
||||
pos.x=math.ceil(pos.x);pos.y=math.ceil(pos.y);pos.z=math.ceil(pos.z);
|
||||
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. name .. " is camping at " .. pos.x .. " " .. pos.z)
|
||||
data.camp = false; data.t = 0
|
||||
end
|
||||
else
|
||||
data.t = 0; data.pos = player:getpos(); data.camp = false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -8,21 +8,22 @@ if not data then
|
|||
self.spam(1)
|
||||
t0 = _G.minetest.get_gametime();
|
||||
data = {}; spawnpos = self.spawnpos() -- place mines
|
||||
self.listen_punch(self.pos()); -- attach punch listener
|
||||
self.listen_punch(spawnpos); -- attach punch listener
|
||||
|
||||
for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end
|
||||
if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area
|
||||
data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0;
|
||||
|
||||
|
||||
minescount = 0;
|
||||
for i = 1,m do for j = 1,n do -- render game
|
||||
if data[i] and data[i][j] == 1 then minescount = minescount + 1 end
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
|
||||
puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:button808080"})
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:buttonlight_grey" then
|
||||
puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:buttonlight_grey"})
|
||||
end
|
||||
end end
|
||||
puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
|
||||
puzzle.set_node({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
|
||||
puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttondark_green"})
|
||||
puzzle.set_node({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttonblue"})
|
||||
|
||||
get_mine_count = function(i,j)
|
||||
if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0
|
||||
|
@ -34,7 +35,7 @@ if not data then
|
|||
chk_mines = function()
|
||||
local count = minescount;
|
||||
for i=1,m do for j=1,n do
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonFF8080" and data[i] and data[i][j]==1 then
|
||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonred" and data[i] and data[i][j]==1 then
|
||||
count=count-1
|
||||
end
|
||||
end end
|
||||
|
@ -47,9 +48,10 @@ end
|
|||
|
||||
event = keyboard.get();
|
||||
if event then
|
||||
|
||||
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
||||
if x<1 or x>m or z<1 or z>n then
|
||||
if x == 0 and z == 1 then
|
||||
if x == 1 and z == 0 then
|
||||
local count = chk_mines();
|
||||
if count>minescount/2 then
|
||||
say("fail, more than 50% of mines remaining ")
|
||||
|
@ -69,20 +71,20 @@ if event then
|
|||
else --if event.type == 2 then
|
||||
local ppos = player.getpos(event.puncher)
|
||||
if ppos and math.abs(ppos.x-event.x)<0.5 and math.abs(ppos.z-event.z)<0.5 then -- just mark mine
|
||||
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then
|
||||
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:button808080"})
|
||||
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:buttonlight_grey" then
|
||||
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonlight_grey"})
|
||||
else
|
||||
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonFF8080"})
|
||||
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonred"})
|
||||
end
|
||||
else
|
||||
if data[x] and data[x][z]==1 then
|
||||
say("boom! "..event.puncher .. " is dead ");puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttonFF8080"});
|
||||
say("boom! "..event.puncher .. " is dead ");puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttonred"});
|
||||
local player_ = puzzle.get_player(event.puncher);
|
||||
player_:setpos({x=spawnpos.x-1,y=spawnpos.y+1,z=spawnpos.z-1});
|
||||
self.remove()
|
||||
else
|
||||
local count = get_mine_count(x,z);
|
||||
if count == 0 then puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button80FF80"})
|
||||
if count == 0 then puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttongreen"})
|
||||
else puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button"..count}) end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
-- INIT
|
||||
if not grid then
|
||||
n=6
|
||||
n=9
|
||||
solved = false -- do we render solution or blank?
|
||||
-- _G.math.randomseed(3)
|
||||
|
||||
|
@ -21,7 +21,7 @@ if not grid then
|
|||
end
|
||||
|
||||
_,scores_string = book.read(1); scores = minetest.deserialize(scores_string)
|
||||
if not scores then scores = init_score(5,5,-999) end -- 5 levels, 5 top records
|
||||
if not scores then scores = init_score(n-1,n-1,-999) end -- 5 levels, 5 top records
|
||||
|
||||
t0 = _G.minetest.get_gametime()
|
||||
local intro ="numbers at beginning of each row (coloumn) tell how many\nred blocks are together in each row ( coloumn )." ..
|
||||
|
@ -85,7 +85,7 @@ if not grid then
|
|||
grid[i]={};
|
||||
for j = 1,n do
|
||||
local typ = keyboard.read({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+i});
|
||||
if typ == "basic_robot:button808080" then grid[i][j] = 0 else grid[i][j] = 1 end
|
||||
if typ == "basic_robot:buttonlight_grey" then grid[i][j] = 0 else grid[i][j] = 1 end
|
||||
end
|
||||
end
|
||||
return grid
|
||||
|
@ -131,7 +131,7 @@ if not grid then
|
|||
if #coldata[k]>0 then sum = sum + coldata[k][#coldata[k]] else sum = n end
|
||||
if sum == n then easy = easy + 1 end
|
||||
end
|
||||
easy = 5-easy;
|
||||
easy = n-1-easy;
|
||||
if easy < 0 then easy = 0 end
|
||||
return easy
|
||||
end
|
||||
|
@ -142,8 +142,8 @@ if not grid then
|
|||
keyboard.set({x=spawnpos.x-n+j,y=spawnpos.y,z=spawnpos.z+i},0) -- clear
|
||||
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+2*n-i+1},0) -- clear
|
||||
local typ;
|
||||
if grid[j][i]==0 then typ = 2 else typ = 3 end
|
||||
if not solved then typ = 2 end
|
||||
if grid[j][i]==0 then typ = 13 else typ = 2 end
|
||||
if not solved then typ = 13 end
|
||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ) --board
|
||||
end
|
||||
end
|
||||
|
@ -152,18 +152,18 @@ if not grid then
|
|||
for i=1,n do
|
||||
length = #rowdata[i]
|
||||
for k = 1,length do
|
||||
keyboard.set({x=spawnpos.x-length+k,y=spawnpos.y,z=spawnpos.z+i},rowdata[i][k]+7)
|
||||
keyboard.set({x=spawnpos.x-length+k,y=spawnpos.y,z=spawnpos.z+i},rowdata[i][k]+17)
|
||||
end
|
||||
end
|
||||
--render counts coloumns
|
||||
for j=1,n do
|
||||
length = #coldata[j]
|
||||
for k = 1,length do
|
||||
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+k+n},coldata[j][k]+7)
|
||||
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+k+n},coldata[j][k]+17)
|
||||
end
|
||||
end
|
||||
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},4) -- game check button
|
||||
keyboard.set({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},5) -- game check button
|
||||
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},9) -- game check button
|
||||
keyboard.set({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},7) -- game check button
|
||||
|
||||
local players = find_player(6,spawnpos)
|
||||
if not players then error("nonogram: no players near") end
|
||||
|
@ -183,6 +183,9 @@ if not grid then
|
|||
elseif difficulty == 2 then limit = 80 reward = 7
|
||||
elseif difficulty <= 1 then limit = 70 reward = 6
|
||||
end
|
||||
if not scores[difficulty] then scores[difficulty] = {{"-",-999}} end
|
||||
if not scores[difficulty][1] then scores[difficulty][1] = {"-",-999} end
|
||||
|
||||
minetest.chat_send_player(pname, "nonogram difficulty " .. difficulty .. ". you will get " .. reward .. " gold if you solve it in faster than " .. limit .."s" ..
|
||||
". Current record " .. -scores[difficulty][1][2] .. " by " .. scores[difficulty][1][1])
|
||||
|
||||
|
@ -233,7 +236,7 @@ if event then
|
|||
for i=1,n do
|
||||
for j =1,n do
|
||||
local typ;
|
||||
if grid[j][i]==0 then typ = 2 else typ = 3 end
|
||||
if grid[j][i]==0 then typ = 13 else typ = 2 end
|
||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ)
|
||||
end
|
||||
end
|
||||
|
@ -244,7 +247,7 @@ if event then
|
|||
if i>0 and i<=n and j>0 and j<=n then
|
||||
local typ = keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j});
|
||||
local newtyp;
|
||||
if typ == "basic_robot:button808080" then newtyp = 3
|
||||
if typ ~= "basic_robot:buttonlight_grey" then newtyp = 13
|
||||
else newtyp = 2
|
||||
end
|
||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},newtyp);
|
||||
|
|
|
@ -1,112 +1,112 @@
|
|||
-- paint canvas by rnd, 2018
|
||||
if not init then
|
||||
colors = {
|
||||
"black","blue","brown","cyan","dark_green","dark_grey","green","grey",
|
||||
"magenta","orange","pink","red","violet","white","yellow"
|
||||
}
|
||||
invcolors = {}; for i = 1,#colors do invcolors[colors[i]] = i end
|
||||
|
||||
color = 1;
|
||||
size = 16;
|
||||
|
||||
init = true
|
||||
|
||||
local ent = _G.basic_robot.data[self.name()].obj:get_luaentity();
|
||||
ent.timestep = 0.5
|
||||
|
||||
players = find_player(5); if not players then self.remove() end
|
||||
player = _G.minetest.get_player_by_name(players[1])
|
||||
self.label("-> " .. players[1])
|
||||
|
||||
spos = self.spawnpos(); spos.y=spos.y+1;
|
||||
|
||||
canvasn = "wool:white"
|
||||
reset_canvas = function()
|
||||
for i = 1, size do
|
||||
for j = 1, size do
|
||||
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = canvasn})
|
||||
end
|
||||
end
|
||||
end
|
||||
reset_canvas()
|
||||
|
||||
save_image = function()
|
||||
local ret = {};
|
||||
for i = 1, size do
|
||||
for j = 1, size do
|
||||
local nname = string.sub(minetest.get_node({x=spos.x +i , y = spos.y + j, z = spos.z }).name,6)
|
||||
local pcolor = invcolors[nname] or 1;
|
||||
ret[#ret+1]= string.char(96+pcolor)
|
||||
end
|
||||
end
|
||||
return table.concat(ret,"")
|
||||
end
|
||||
|
||||
load_image = function(image)
|
||||
if not image then return end
|
||||
local ret = {}; local k = 0;
|
||||
for i = 1, size do
|
||||
for j = 1, size do
|
||||
k=k+1;
|
||||
local pcolor = colors[string.byte(image,k)-96] or "black";
|
||||
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = "wool:"..pcolor})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--draw buttons
|
||||
for i = 1,#colors do
|
||||
minetest.set_node({x=spos.x +i , y = spos.y , z = spos.z },{name = "wool:"..colors[i]})
|
||||
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 +2 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_76"})
|
||||
|
||||
|
||||
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};
|
||||
|
||||
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 b = vn.x*v.x + vn.y*v.y + vn.z*v.z
|
||||
if b<=0 then return nil end
|
||||
if a<=0 then return nil end
|
||||
local t = a / b
|
||||
return {x = p.x+v.x*t, y= p.y+v.y*t, z = p.z+v.z*t}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if player:get_player_control().LMB then -- player interacts with 'virtual canvas gui'
|
||||
local v = player:get_look_dir();
|
||||
local p = player:get_pos(); p.y = p.y + 1.5
|
||||
local c = get_intersect(vn,T0,p,v);
|
||||
if c then
|
||||
|
||||
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 y>0 then -- above: painting
|
||||
c.z = c.z+0.5
|
||||
minetest.set_node(c, {name = "wool:" .. colors[color]})
|
||||
elseif y>-1 then -- color selection
|
||||
x = 1+math.floor(x)
|
||||
if colors[x] then
|
||||
color = x;
|
||||
self.label(colors[x])
|
||||
end
|
||||
else -- save,load button row
|
||||
x = 1+math.floor(x)
|
||||
if x==1 then
|
||||
self.label("SAVED.")
|
||||
book.write(1,"ROBOT_IMAGE",save_image())
|
||||
elseif x==2 then
|
||||
local _,image = book.read(1)
|
||||
load_image(image);
|
||||
self.label("LOADED.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
-- paint canvas by rnd, 2018
|
||||
if not init then
|
||||
colors = {
|
||||
"white","yellow","orange","red","magenta","purple","blue","cyan",
|
||||
"green","dark_green","brown","tan","light_grey","medium_grey","dark_grey","black"
|
||||
}
|
||||
invcolors = {}; for i = 1,#colors do invcolors[colors[i]] = i end
|
||||
|
||||
color = invcolors["black"];
|
||||
size = 16;
|
||||
|
||||
init = true
|
||||
|
||||
local ent = _G.basic_robot.data[self.name()].obj:get_luaentity();
|
||||
ent.timestep = 0.125
|
||||
|
||||
players = find_player(5); if not players then self.remove() end
|
||||
player = _G.minetest.get_player_by_name(players[1])
|
||||
self.label("-> " .. players[1])
|
||||
|
||||
spos = self.spawnpos(); spos.y=spos.y+1;
|
||||
canvasn = "basic_robot:buttonwhite"
|
||||
reset_canvas = function()
|
||||
for i = 1, size do
|
||||
for j = 1, size do
|
||||
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = canvasn})
|
||||
end
|
||||
end
|
||||
end
|
||||
reset_canvas()
|
||||
|
||||
save_image = function()
|
||||
local ret = {};
|
||||
for i = 1, size do
|
||||
for j = 1, size do
|
||||
local nname = string.sub(minetest.get_node({x=spos.x +i , y = spos.y + j, z = spos.z }).name,19)
|
||||
local pcolor = invcolors[nname] or 1;
|
||||
ret[#ret+1]= string.char(96+pcolor)
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(ret,"")
|
||||
end
|
||||
|
||||
load_image = function(image)
|
||||
if not image then return end
|
||||
local ret = {}; local k = 0;
|
||||
for i = 1, size do
|
||||
for j = 1, size do
|
||||
k=k+1;
|
||||
local pcolor = colors[string.byte(image,k)-96] or "black";
|
||||
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = "basic_robot:button"..pcolor})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--draw buttons
|
||||
for i = 1,#colors do
|
||||
minetest.set_node({x=spos.x +i , y = spos.y , z = spos.z },{name = "basic_robot:button"..colors[i]})
|
||||
end
|
||||
|
||||
minetest.set_node({x=spos.x +1 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_83"})
|
||||
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};
|
||||
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)
|
||||
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
|
||||
if b<=0 then return nil end
|
||||
if a<=0 then return nil end
|
||||
local t = a / b
|
||||
return {x = p.x+v.x*t, y= p.y+v.y*t, z = p.z+v.z*t}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if player:get_player_control().LMB then -- player interacts with 'virtual canvas gui'
|
||||
local v = player:get_look_dir();
|
||||
local p = player:get_pos(); p.y = p.y + 1.5
|
||||
local c = get_intersect(vn,T0,p,v);
|
||||
if c then
|
||||
|
||||
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 y>0 then -- above: painting
|
||||
c.z = c.z+0.5
|
||||
minetest.set_node(c, {name = "basic_robot:button" .. colors[color]})
|
||||
elseif y>-1 then -- color selection
|
||||
x = 1+math.floor(x)
|
||||
if colors[x] then
|
||||
color = x;
|
||||
self.label(colors[x])
|
||||
end
|
||||
else -- save,load button row
|
||||
x = 1+math.floor(x)
|
||||
if x==1 then
|
||||
self.label("SAVED.")
|
||||
book.write(1,"ROBOT_IMAGE",save_image())
|
||||
elseif x==2 then
|
||||
local _,image = book.read(1)
|
||||
load_image(image);
|
||||
self.label("LOADED.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -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
|
||||
--
|
|
@ -1,56 +1,59 @@
|
|||
-- simple box pushing game, rnd
|
||||
|
||||
if not init then
|
||||
spos = self.spawnpos(); spos.x = spos.x +5; spos.z = spos.z +5;
|
||||
|
||||
for i = 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"})
|
||||
end
|
||||
end
|
||||
|
||||
init = true
|
||||
players = find_player(5);
|
||||
if not players then say("no players nearby") self.remove() end
|
||||
say("BOX PUSH demo. punch the white box to move it around ")
|
||||
|
||||
pushables = {[1] = true} -- button types
|
||||
canpushnodes = {["air"] = 1, ["basic_robot:button8080FF"] = 2} -- 1 push node, 2 absorb node
|
||||
end
|
||||
|
||||
event = keyboard.get()
|
||||
if event then
|
||||
local boxtype = event.type
|
||||
if pushables[boxtype] then
|
||||
player = puzzle.get_player(event.puncher)
|
||||
local pos = player:getpos();
|
||||
local boxpos = {x = event.x, y = event.y, z = event.z};
|
||||
local diff = { pos.x-boxpos.x, pos.z-boxpos.z};
|
||||
|
||||
local newx,newz
|
||||
if math.abs(diff[1])>math.abs(diff[2]) then -- punch in x-direction
|
||||
newx = boxpos.x - (diff[1]>0 and 1 or -1)
|
||||
newz = boxpos.z
|
||||
else
|
||||
newx = boxpos.x
|
||||
newz = boxpos.z - (diff[2]>0 and 1 or -1)
|
||||
end
|
||||
|
||||
local newnode = puzzle.get_node({x=newx, y= boxpos.y, z= newz}).name
|
||||
|
||||
|
||||
local canpush = canpushnodes[newnode]
|
||||
if canpush then
|
||||
local oldnode = puzzle.get_node(boxpos).name
|
||||
puzzle.set_node(boxpos,{name= "air"}) -- remove node
|
||||
if canpush == 1 then -- simply move the box
|
||||
newnode = oldnode
|
||||
elseif canpush == 2 then -- absorb the box
|
||||
newnode = newnode
|
||||
end
|
||||
|
||||
puzzle.set_node({x=newx, y= boxpos.y, z= newz}, {name = newnode})
|
||||
end
|
||||
end
|
||||
--say(serialize(event))
|
||||
-- simple box pushing game, rnd
|
||||
|
||||
if not init then
|
||||
spos = self.spawnpos(); spos.x = spos.x +5; spos.z = spos.z +5;
|
||||
|
||||
for i = 1, 2 do -- set up 4 boxes
|
||||
for j = 1,2 do
|
||||
puzzle.set_node({x=spos.x+i,y=spos.y,z=spos.z+j}, {name = "basic_robot:buttonwhite"})
|
||||
end
|
||||
end
|
||||
|
||||
init = true
|
||||
players = find_player(5);
|
||||
if not players then say("no players nearby") self.remove() end
|
||||
self.label("BOX PUSH demo. punch the white box to move it around.\npush it into blue block to make it disappear.")
|
||||
|
||||
pushables = {[1] = true} -- button types
|
||||
canpushnodes = {["air"] = 1, ["basic_robot:buttonblue"] = 2} -- 1 push node, 2 absorb node
|
||||
|
||||
self.listen_punch(self.pos()) -- robot will now read punch button events in 32x32 box area
|
||||
end
|
||||
|
||||
event = keyboard.get()
|
||||
|
||||
if event then -- there was punch event
|
||||
local boxtype = event.type
|
||||
if pushables[boxtype] then
|
||||
player = puzzle.get_player(event.puncher)
|
||||
local pos = player:getpos();
|
||||
local boxpos = {x = event.x, y = event.y, z = event.z};
|
||||
local diff = { pos.x-boxpos.x, pos.z-boxpos.z};
|
||||
|
||||
local newx,newz
|
||||
if math.abs(diff[1])>math.abs(diff[2]) then -- punch in x-direction
|
||||
newx = boxpos.x - (diff[1]>0 and 1 or -1)
|
||||
newz = boxpos.z
|
||||
else
|
||||
newx = boxpos.x
|
||||
newz = boxpos.z - (diff[2]>0 and 1 or -1)
|
||||
end
|
||||
|
||||
local newnode = puzzle.get_node({x=newx, y= boxpos.y, z= newz}).name
|
||||
|
||||
|
||||
local canpush = canpushnodes[newnode]
|
||||
if canpush then
|
||||
local oldnode = puzzle.get_node(boxpos).name
|
||||
puzzle.set_node(boxpos,{name= "air"}) -- remove node
|
||||
if canpush == 1 then -- simply move the box
|
||||
newnode = oldnode
|
||||
elseif canpush == 2 then -- absorb the box
|
||||
newnode = newnode
|
||||
end
|
||||
|
||||
puzzle.set_node({x=newx, y= boxpos.y, z= newz}, {name = newnode})
|
||||
end
|
||||
end
|
||||
--say(serialize(event))
|
||||
end
|
|
@ -19,7 +19,7 @@ if not init then
|
|||
board[i]={};
|
||||
for j = 1,n do
|
||||
k=k+1
|
||||
board[i][j]=7+ret[k] -- 7 numbers, 82 letters
|
||||
board[i][j]=17+ret[k] -- 7 numbers, 82 letters
|
||||
end
|
||||
end
|
||||
board[math.random(n)][math.random(n)] = 0
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
|
||||
self.spam(1)
|
||||
self.listen_punch(self.pos()); -- attach punch listener
|
||||
self.listen_punch(self.pos()); -- attach punch listener
|
||||
sokoban.push_time = 0
|
||||
sokoban.blocks = 0;sokoban.level = 0; sokoban.moves=0;
|
||||
imax = 0; jmax = 0
|
||||
|
@ -43,7 +43,7 @@
|
|||
SOKOBAN_WALL = "moreblocks:cactus_brick"
|
||||
SOKOBAN_FLOOR = "default:silver_sandstone"
|
||||
SOKOBAN_GOAL = "default:aspen_tree"
|
||||
SOKOBAN_BOX = "basic_robot:buttonFFFFFF"
|
||||
SOKOBAN_BOX = "basic_robot:buttonwhite"
|
||||
|
||||
|
||||
load_level = function(lvl)
|
||||
|
|
|
@ -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
|
|
@ -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"))
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
@ -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
|
|
@ -1,41 +1,45 @@
|
|||
-- minetest object listen in radius 100 around robot
|
||||
|
||||
if not init then init = false
|
||||
|
||||
local objs = minetest.get_objects_inside_radius(self.pos(), 100);
|
||||
local ret = {};
|
||||
|
||||
local round = function(x) return math.floor(x/5)*5 end
|
||||
local ret = {};
|
||||
|
||||
for i = 1, #objs do
|
||||
local p = objs[i]:get_pos();
|
||||
local luaent = objs[i]:get_luaentity();
|
||||
local entname = ""
|
||||
if luaent then
|
||||
entname = luaent.itemstring
|
||||
if entname == "robot" then entname = entname .. " " .. luaent.name end
|
||||
elseif objs[i]:is_player() then
|
||||
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 .. ", "
|
||||
end
|
||||
|
||||
local out = {};
|
||||
for k,v in pairs(ret) do
|
||||
out[#out+1] = {k,v}
|
||||
end
|
||||
|
||||
--table.sort(out, function(a,b) return a[2]>b[2] end) -- additional stuff here - optional
|
||||
local res = {};
|
||||
for i = 1, #out do
|
||||
res[#res+1] = out[i][1] .. " = " .. out[i][2]
|
||||
end
|
||||
|
||||
self.label("#objects " .. #objs .. "\n" .. table.concat(res, "\n"))
|
||||
|
||||
|
||||
|
||||
-- minetest object listen in radius 100 around robot
|
||||
|
||||
if not init then init = false
|
||||
|
||||
local objs = minetest.get_objects_inside_radius(self.pos(), 100);
|
||||
local ret = {};
|
||||
|
||||
local round = function(x) return math.floor(x/5)*5 end
|
||||
local ret = {};
|
||||
|
||||
for i = 1, #objs do
|
||||
local p = objs[i]:get_pos();
|
||||
local luaent = objs[i]:get_luaentity();
|
||||
local entname = ""
|
||||
if luaent then
|
||||
--entname = serialize(luaent)
|
||||
entname = luaent.itemstring
|
||||
if entname == "robot" then entname = entname .. " " .. luaent.name end
|
||||
elseif objs[i]:is_player() then
|
||||
entname = "PLAYER " .. objs[i]:get_player_name()
|
||||
end
|
||||
|
||||
local phash = round(p.x) .. " " .. round(p.y) .. " " .. round(p.z);
|
||||
if entname then ret[phash] = (ret[phash] or "") .. entname .. ", " end
|
||||
end
|
||||
|
||||
local out = {};
|
||||
for k,v in pairs(ret) do
|
||||
out[#out+1] = {k,v}
|
||||
end
|
||||
|
||||
--table.sort(out, function(a,b) return a[2]>b[2] end) -- additional stuff here - optional
|
||||
local res = {};
|
||||
for i = 1, #out do
|
||||
res[#res+1] = out[i][1] .. " = " .. out[i][2]
|
||||
end
|
||||
|
||||
self.label("#objects " .. #objs .. "\n" .. table.concat(res, "\n"))
|
||||
|
||||
--book.write(1,"",("#objects " .. #objs .. "\n" .. table.concat(res, "\n")))
|
||||
--self.remove()
|
||||
|
||||
|
||||
|
||||
end
|
|
@ -3,7 +3,7 @@
|
|||
-- say: t TEXT\nTEXT...
|
||||
|
||||
if not init then init = true
|
||||
name = "_"
|
||||
names = {["rnd"]=true,["PrairieWind"] = true}
|
||||
|
||||
get_dir = function(view)
|
||||
local dir
|
||||
|
@ -15,7 +15,7 @@ if not init then init = true
|
|||
return dir
|
||||
end
|
||||
|
||||
render_text = function(text)
|
||||
render_text = function(text,name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
local pos = player:get_pos()
|
||||
local dir = get_dir(player:get_look_dir())
|
||||
|
@ -37,7 +37,7 @@ if not init then init = true
|
|||
end
|
||||
|
||||
speaker,msg = self.listen_msg()
|
||||
if speaker == name and string.sub(msg,1,2) == "t " then
|
||||
if names[speaker] and string.sub(msg,1,2) == "t " then
|
||||
|
||||
render_text(string.sub(msg,3))
|
||||
render_text(string.sub(msg,3),speaker)
|
||||
end
|
|
@ -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()
|
|
@ -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>
|
|
@ -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 "")
|
|
@ -0,0 +1 @@
|
|||
D:\prog\programming\Python\Python37-32\python https_server.py
|
|
@ -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();
|
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
Loading…
Reference in New Issue