custom buttons fix. redstone script fix

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

View File

@ -595,6 +595,8 @@ local write_keyevent = function(data,pos, puncher,type)
end
basic_robot.commands.write_keyevent = write_keyevent;
local button_punched = function(pos, node, player,type)
local name = player:get_player_name(); if name==nil then return end
local round = math.floor;
@ -609,8 +611,10 @@ local button_punched = function(pos, node, player,type)
end
end
local register_robot_button = function(R,G,B,type)
minetest.register_node("basic_robot:button"..R..G..B,
local buttoncolors = {};
local register_robot_button = function(R,G,B,colorname,type)
buttoncolors[type] = "basic_robot:button"..colorname;
minetest.register_node("basic_robot:button"..colorname,
{
description = "robot button",
tiles = {"robot_button.png^[colorize:#"..R..G..B..":180"},
@ -624,12 +628,14 @@ local register_robot_button = function(R,G,B,type)
end
local register_robot_button_number = function(number,type)
local idx = number+48
local texname = "robochars.png^[sheet:16x16:" .. idx % 16 .. "," .. math.floor(idx/ 16).."^[invert:rgb";
minetest.register_node("basic_robot:button"..number,
{
description = "robot button",
tiles = {"robot_button".. number .. ".png"},
inventory_image = "robot_button".. number .. ".png",
wield_image = "robot_button".. number .. ".png",
tiles = {texname},
inventory_image = texname,
wield_image = texname,
paramtype2 = "facedir",
is_ground_content = false,
@ -640,12 +646,14 @@ end
local register_robot_button_char = function(number,type)
local texname = "robochars.png^[sheet:16x16:" .. number % 16 .. "," .. math.floor(number/ 16);
-- local texname = string.format("%03d",number).. ".png";
minetest.register_node("basic_robot:button_"..number,
{
{
description = "robot button",
tiles = {string.format("%03d",number).. ".png"},
inventory_image = string.format("%03d",number).. ".png",
wield_image = string.format("%03d",number).. ".png",
tiles = {texname},
inventory_image = texname,
wield_image = texname,
is_ground_content = false,
groups = {cracky=3,not_in_craft_guide = 1},
paramtype2 = "facedir",
@ -654,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

View File

@ -1,32 +1,11 @@
-- basic_robot by rnd, 2016-2021
-- basic_robot by rnd, 2016-2022
basic_robot = {};
------ SETTINGS --------
basic_robot.call_limit = {50,200,1500,10^9}; -- how many execution calls per script run allowed, for auth levels 0,1,2 (normal, robot, puzzle, admin)
basic_robot.count = {2,6,16,128} -- how many robots player can have
basic_robot.version = "2022/02/02b";
basic_robot.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches
basic_robot.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running mod, password used for authentifications
dofile(minetest.get_modpath("basic_robot").."/settings.lua") -- read configuration SETTINGS
basic_robot.admin_bot_pos = {x=0,y=1,z=0} -- position of admin robot spawner that will be run automatically on server start
basic_robot.maxoperations = 10; -- how many operations (dig, place,move,...,generate energy,..) available per run, 0 = unlimited
basic_robot.dig_require_energy = true; -- does robot require energy to dig stone?
basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
["moreblocks:circular_saw"] = true,
["craft_guide:sign_wall"] = true,
["basic_machines:battery_0"] = true,
["basic_machines:battery_1"] = true,
["basic_machines:battery_2"] = true,
["basic_machines:generator"] = true,
}
----- END OF SETTINGS ------
basic_robot.http_api = minetest.request_http_api();
basic_robot.version = "2021/06/28a";
-- structures for storing robot data
basic_robot.gui = {}; local robogui = basic_robot.gui -- gui management
basic_robot.data = {}; -- stores all robot related data
@ -50,7 +29,6 @@ local check_code, preprocess_code,is_inside_string;
-- SANDBOX for running lua code isolated and safely
function getSandboxEnv (name)
local authlevel = basic_robot.data[name].authlevel or 0;
@ -61,7 +39,11 @@ function getSandboxEnv (name)
left_up = 11, right_up = 12, forward_up = 13, backward_up = 14
}
if not basic_robot.data[name].rom then basic_robot.data[name].rom = {} end -- create rom if not yet existing
local pname = string.sub(name,1,-2)
if not basic_robot.data[pname] then basic_robot.data[pname] = {} end
-- all robots by player share same rom now
if not basic_robot.data[pname].rom then basic_robot.data[pname].rom = {} end -- create rom if not yet existing
local env =
{
_Gerror = error,
@ -93,9 +75,11 @@ function getSandboxEnv (name)
return commands.craft(item, mode, idx, amount, name)
end,
pause = function() -- pause coroutine
pause = function(amount) -- pause coroutine
if not basic_robot.data[name].cor then error("you must start program with '--coroutine' to use pause()") return end
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

4
mod.conf Normal file
View File

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

View File

@ -145,7 +145,8 @@ local help_pages = {
" 7. [TECHNIC FUNCTIONALITY]",
" 8. [CRYPTOGRAPHY]",
" 9. [PUZZLE]",
" 10.[COROUTINES] - easier alternative to finite state machines",
" 10.[COROUTINES AND LIBRARIES AND ROM] - easier alternative to",
" finite state machines",
},
["MOVEMENT DIGGING PLACING NODE SENSING"] = {
@ -312,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",
},

View File

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

View File

@ -1,210 +1,211 @@
--black box by rnd, 03/18/2017
--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::

View File

@ -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::

View File

@ -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

View File

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

View File

@ -8,21 +8,22 @@ if not data then
self.spam(1)
t0 = _G.minetest.get_gametime();
data = {}; spawnpos = self.spawnpos() -- place mines
self.listen_punch(self.pos()); -- attach punch listener
self.listen_punch(spawnpos); -- attach punch listener
for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end
if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area
data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0;
minescount = 0;
for i = 1,m do for j = 1,n do -- render game
if data[i] and data[i][j] == 1 then minescount = minescount + 1 end
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:button808080"})
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:buttonlight_grey" then
puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:buttonlight_grey"})
end
end end
puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
puzzle.set_node({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttondark_green"})
puzzle.set_node({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttonblue"})
get_mine_count = function(i,j)
if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0
@ -34,7 +35,7 @@ if not data then
chk_mines = function()
local count = minescount;
for i=1,m do for j=1,n do
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonFF8080" and data[i] and data[i][j]==1 then
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonred" and data[i] and data[i][j]==1 then
count=count-1
end
end end
@ -47,9 +48,10 @@ end
event = keyboard.get();
if event then
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
if x<1 or x>m or z<1 or z>n then
if x == 0 and z == 1 then
if x == 1 and z == 0 then
local count = chk_mines();
if count>minescount/2 then
say("fail, more than 50% of mines remaining ")
@ -69,20 +71,20 @@ if event then
else --if event.type == 2 then
local ppos = player.getpos(event.puncher)
if ppos and math.abs(ppos.x-event.x)<0.5 and math.abs(ppos.z-event.z)<0.5 then -- just mark mine
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:button808080"})
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:buttonlight_grey" then
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonlight_grey"})
else
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonFF8080"})
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonred"})
end
else
if data[x] and data[x][z]==1 then
say("boom! "..event.puncher .. " is dead ");puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttonFF8080"});
say("boom! "..event.puncher .. " is dead ");puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttonred"});
local player_ = puzzle.get_player(event.puncher);
player_:setpos({x=spawnpos.x-1,y=spawnpos.y+1,z=spawnpos.z-1});
self.remove()
else
local count = get_mine_count(x,z);
if count == 0 then puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button80FF80"})
if count == 0 then puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttongreen"})
else puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button"..count}) end
end
end

View File

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

View File

@ -1,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

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

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

View File

@ -1,56 +1,59 @@
-- simple box pushing game, rnd
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

View File

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

View File

@ -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)

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

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

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

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,41 +1,45 @@
-- minetest object listen in radius 100 around robot
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

View File

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

View File

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

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

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

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

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

View File

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

24
settings.lua Normal file
View File

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

BIN
textures/robochars.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB