Compare commits
7 Commits
1680a70ea8
...
8c9d0fd68f
Author | SHA1 | Date |
---|---|---|
ac-minetest | 8c9d0fd68f | |
ac-minetest | 2020477700 | |
ac-minetest | c3a021d1fc | |
ac-minetest | bf7002b1c3 | |
ac-minetest | 79bbe6c2af | |
ac-minetest | e237985e8e | |
ac-minetest | 5d94e03351 |
331
commands.lua
331
commands.lua
|
@ -18,8 +18,8 @@ end
|
||||||
local pi = math.pi;
|
local pi = math.pi;
|
||||||
|
|
||||||
local function pos_in_dir(obj, dir) -- position after we move in specified direction
|
local function pos_in_dir(obj, dir) -- position after we move in specified direction
|
||||||
local yaw = obj:getyaw();
|
local yaw = obj:get_yaw();
|
||||||
local pos = obj:getpos();
|
local pos = obj:get_pos();
|
||||||
|
|
||||||
if dir == 1 then -- left
|
if dir == 1 then -- left
|
||||||
yaw = yaw + pi/2;
|
yaw = yaw + pi/2;
|
||||||
|
@ -88,7 +88,7 @@ basic_robot.commands.move = function(name,dir)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
obj:moveto(pos, true)
|
obj:move_to(pos, true)
|
||||||
|
|
||||||
-- sit and stand up for model - doesnt work for overwriten obj export
|
-- sit and stand up for model - doesnt work for overwriten obj export
|
||||||
-- if dir == 5 then-- up
|
-- if dir == 5 then-- up
|
||||||
|
@ -105,15 +105,16 @@ basic_robot.commands.turn = function (name, angle)
|
||||||
local yaw;
|
local yaw;
|
||||||
-- more precise turns by 1 degree resolution
|
-- more precise turns by 1 degree resolution
|
||||||
local mult = math.pi/180;
|
local mult = math.pi/180;
|
||||||
local yaw = obj:getyaw();
|
local yaw = obj:get_yaw();
|
||||||
yaw = math.floor((yaw+angle)/mult+0.5)*mult;
|
yaw = math.floor((yaw+angle)/mult+0.5)*mult;
|
||||||
obj:setyaw(yaw);
|
obj:set_yaw(yaw);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
basic_robot.digcosts = { -- 1 energy = 1 coal
|
basic_robot.digcosts = { -- 1 energy = 1 coal
|
||||||
["default:stone"] = 1/25,
|
["default:stone"] = 1/25,
|
||||||
["default:cloud"] = 10^8,
|
["gloopblocks:pumice_cooled"] = 1/25,
|
||||||
|
["default:cloud"] = 10^9,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -273,7 +274,7 @@ basic_robot.commands.pickup = function(r,name)
|
||||||
if r>8 then return false end
|
if r>8 then return false end
|
||||||
|
|
||||||
check_operations(name,4,true)
|
check_operations(name,4,true)
|
||||||
local pos = basic_robot.data[name].obj:getpos();
|
local pos = basic_robot.data[name].obj:get_pos();
|
||||||
local spos = basic_robot.data[name].spawnpos; -- position of spawner block
|
local spos = basic_robot.data[name].spawnpos; -- position of spawner block
|
||||||
local meta = minetest.get_meta(spos);
|
local meta = minetest.get_meta(spos);
|
||||||
local inv = minetest.get_meta(spos):get_inventory();
|
local inv = minetest.get_meta(spos):get_inventory();
|
||||||
|
@ -289,7 +290,7 @@ basic_robot.commands.pickup = function(r,name)
|
||||||
picklist[#picklist+1]=detected_obj;
|
picklist[#picklist+1]=detected_obj;
|
||||||
if inv:room_for_item("main", stack) then
|
if inv:room_for_item("main", stack) then
|
||||||
inv:add_item("main", stack);
|
inv:add_item("main", stack);
|
||||||
obj:setpos({x=0,y=0,z=0}) -- no dupe
|
obj:set_pos({x=0,y=0,z=0}) -- no dupe
|
||||||
end
|
end
|
||||||
obj:remove();
|
obj:remove();
|
||||||
end
|
end
|
||||||
|
@ -382,8 +383,8 @@ basic_robot.commands.attack = function(name, target) -- attack range 4, damage 5
|
||||||
local tplayer = minetest.get_player_by_name(target);
|
local tplayer = minetest.get_player_by_name(target);
|
||||||
if not tplayer then return false end
|
if not tplayer then return false end
|
||||||
local obj = basic_robot.data[name].obj;
|
local obj = basic_robot.data[name].obj;
|
||||||
local pos = obj:getpos();
|
local pos = obj:get_pos();
|
||||||
local tpos = tplayer:getpos();
|
local tpos = tplayer:get_pos();
|
||||||
|
|
||||||
if math.abs(pos.x-tpos.x)> reach or math.abs(pos.y-tpos.y)> reach or math.abs(pos.z-tpos.z)> reach then
|
if math.abs(pos.x-tpos.x)> reach or math.abs(pos.y-tpos.y)> reach or math.abs(pos.z-tpos.z)> reach then
|
||||||
return false
|
return false
|
||||||
|
@ -400,8 +401,8 @@ basic_robot.commands.grab = function(name,target)
|
||||||
local tplayer = minetest.get_player_by_name(target);
|
local tplayer = minetest.get_player_by_name(target);
|
||||||
if not tplayer then return false end
|
if not tplayer then return false end
|
||||||
local obj = basic_robot.data[name].obj;
|
local obj = basic_robot.data[name].obj;
|
||||||
local pos = obj:getpos();
|
local pos = obj:get_pos();
|
||||||
local tpos = tplayer:getpos();
|
local tpos = tplayer:get_pos();
|
||||||
|
|
||||||
if math.abs(pos.x-tpos.x)> reach or math.abs(pos.y-tpos.y)> reach or math.abs(pos.z-tpos.z)> reach then
|
if math.abs(pos.x-tpos.x)> reach or math.abs(pos.y-tpos.y)> reach or math.abs(pos.z-tpos.z)> reach then
|
||||||
return false
|
return false
|
||||||
|
@ -444,8 +445,9 @@ basic_robot.commands.write_book = function(name,title,text) -- returns itemstack
|
||||||
local data = {}
|
local data = {}
|
||||||
|
|
||||||
if title == "" or not title then title = "program book "..minetest.get_gametime() end
|
if title == "" or not title then title = "program book "..minetest.get_gametime() end
|
||||||
data.title = title or ""
|
if text == "" or not text then text = "empty" end
|
||||||
data.text = text or ""
|
data.text = text
|
||||||
|
data.title = title
|
||||||
data.text_len = #data.text
|
data.text_len = #data.text
|
||||||
data.page = 1
|
data.page = 1
|
||||||
data.description = title or ""
|
data.description = title or ""
|
||||||
|
@ -568,9 +570,51 @@ basic_robot.commands.activate = function(name,mode, dir)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local write_keyevent = function(data,pos, puncher,type)
|
||||||
|
local keyevent = data.keyevent;
|
||||||
|
if not keyevent then -- init
|
||||||
|
data.keyevent = {5,1,1,{}} -- how many events buffer holds, input idx, output idx, buffer data
|
||||||
|
keyevent = data.keyevent;
|
||||||
|
end
|
||||||
|
|
||||||
|
local iidx = keyevent[2]; -- input idx
|
||||||
|
-- write event at input idx
|
||||||
|
keyevent[4][iidx] = {x=pos.x,y=pos.y,z=pos.z, puncher = puncher, type = type}
|
||||||
|
|
||||||
|
local oidx = keyevent[3]; -- output idx
|
||||||
|
|
||||||
|
iidx=iidx+1; if iidx>keyevent[1] then iidx = 1 end -- advance idx for next input write
|
||||||
|
keyevent[2] = iidx
|
||||||
|
|
||||||
|
if iidx == oidx then -- old event was overwritten, lets increase output idx
|
||||||
|
oidx = oidx+1
|
||||||
|
if oidx>keyevent[1] then oidx = 1 end
|
||||||
|
keyevent[3] = oidx
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
local register_robot_button = function(R,G,B,type)
|
basic_robot.commands.write_keyevent = write_keyevent;
|
||||||
minetest.register_node("basic_robot:button"..R..G..B,
|
|
||||||
|
local button_punched = function(pos, node, player,type)
|
||||||
|
local name = player:get_player_name(); if name==nil then return end
|
||||||
|
local round = math.floor;
|
||||||
|
local r = basic_robot.radius; local ry = 2*r;
|
||||||
|
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
|
||||||
|
|
||||||
|
local hppos = minetest.hash_node_position(ppos)
|
||||||
|
local rname = basic_robot.data.punchareas[hppos];
|
||||||
|
local data = basic_robot.data[rname];
|
||||||
|
if data then
|
||||||
|
write_keyevent(data,pos, player:get_player_name(),type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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",
|
description = "robot button",
|
||||||
tiles = {"robot_button.png^[colorize:#"..R..G..B..":180"},
|
tiles = {"robot_button.png^[colorize:#"..R..G..B..":180"},
|
||||||
|
@ -578,129 +622,139 @@ local register_robot_button = function(R,G,B,type)
|
||||||
wield_image = "robot_button.png^[colorize:#"..R..G..B..":180",
|
wield_image = "robot_button.png^[colorize:#"..R..G..B..":180",
|
||||||
|
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
groups = {cracky=3},
|
groups = {cracky=3,not_in_craft_guide = 1},
|
||||||
on_punch = function(pos, node, player)
|
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
|
||||||
local name = player:get_player_name(); if name==nil then return end
|
|
||||||
local round = math.floor;
|
|
||||||
local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted
|
|
||||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
|
|
||||||
local meta = minetest.get_meta(ppos);
|
|
||||||
local name = meta:get_string("name");
|
|
||||||
local data = basic_robot.data[name];
|
|
||||||
if data then data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = player:get_player_name(), type = type} end
|
|
||||||
end
|
|
||||||
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
local register_robot_button_number = function(number,type)
|
local register_robot_button_number = function(number,type)
|
||||||
|
local idx = number+48
|
||||||
|
local texname = "robochars.png^[sheet:16x16:" .. idx % 16 .. "," .. math.floor(idx/ 16).."^[invert:rgb";
|
||||||
minetest.register_node("basic_robot:button"..number,
|
minetest.register_node("basic_robot:button"..number,
|
||||||
{
|
{
|
||||||
description = "robot button",
|
description = "robot button",
|
||||||
tiles = {"robot_button".. number .. ".png"},
|
tiles = {texname},
|
||||||
inventory_image = "robot_button".. number .. ".png",
|
inventory_image = texname,
|
||||||
wield_image = "robot_button".. number .. ".png",
|
wield_image = texname,
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
groups = {cracky=3},
|
groups = {cracky=3,not_in_craft_guide = 1},
|
||||||
on_punch = function(pos, node, player)
|
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
|
||||||
local name = player:get_player_name(); if name==nil then return end
|
|
||||||
local round = math.floor;
|
|
||||||
local r = basic_robot.radius; local ry = 2*r;
|
|
||||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
|
|
||||||
local meta = minetest.get_meta(ppos);
|
|
||||||
local name = meta:get_string("name");
|
|
||||||
local data = basic_robot.data[name];
|
|
||||||
if data then data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = player:get_player_name(), type = type} end
|
|
||||||
end
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local register_robot_button_char = function(number,type)
|
local register_robot_button_char = function(number,type)
|
||||||
|
local texname = "robochars.png^[sheet:16x16:" .. number % 16 .. "," .. math.floor(number/ 16);
|
||||||
|
-- local texname = string.format("%03d",number).. ".png";
|
||||||
minetest.register_node("basic_robot:button_"..number,
|
minetest.register_node("basic_robot:button_"..number,
|
||||||
{
|
{
|
||||||
description = "robot button",
|
description = "robot button",
|
||||||
tiles = {string.format("%03d",number).. ".png"},
|
tiles = {texname},
|
||||||
inventory_image = string.format("%03d",number).. ".png",
|
inventory_image = texname,
|
||||||
wield_image = string.format("%03d",number).. ".png",
|
wield_image = texname,
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
groups = {cracky=3},
|
groups = {cracky=3,not_in_craft_guide = 1},
|
||||||
on_punch = function(pos, node, player)
|
paramtype2 = "facedir",
|
||||||
local name = player:get_player_name(); if name==nil then return end
|
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
|
||||||
local round = math.floor;
|
|
||||||
local r = basic_robot.radius; local ry = 2*r;
|
|
||||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
|
|
||||||
local meta = minetest.get_meta(ppos);
|
|
||||||
local name = meta:get_string("name");
|
|
||||||
local data = basic_robot.data[name];
|
|
||||||
if data then data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = player:get_player_name(), type = type} end
|
|
||||||
end
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
local register_robot_button_custom = function(number,texture)
|
local register_robot_button_custom = function(number,texture)
|
||||||
minetest.register_node("basic_robot:button_"..number,
|
local type = number
|
||||||
{
|
minetest.register_node("basic_robot:button_"..number,
|
||||||
description = "robot button",
|
{
|
||||||
tiles = {texture .. ".png"},
|
description = "robot button",
|
||||||
inventory_image = texture .. ".png",
|
tiles = {texture .. ".png"},
|
||||||
wield_image = texture .. ".png",
|
inventory_image = texture .. ".png",
|
||||||
is_ground_content = false,
|
wield_image = texture .. ".png",
|
||||||
groups = {cracky=3},
|
is_ground_content = false,
|
||||||
on_punch = function(pos, node, player)
|
groups = {cracky=3,not_in_craft_guide = 1},
|
||||||
local name = player:get_player_name(); if name==nil then return end
|
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
|
||||||
local round = math.floor;
|
|
||||||
local r = basic_robot.radius; local ry = 2*r;
|
|
||||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
|
|
||||||
local meta = minetest.get_meta(ppos);
|
|
||||||
local name = meta:get_string("name");
|
|
||||||
local data = basic_robot.data[name];
|
|
||||||
if data then data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = player:get_player_name(), type = number} end
|
|
||||||
end
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--[[ colors!
|
||||||
|
0 — white 8 — green
|
||||||
|
1 — yellow 9 — dark green
|
||||||
|
2 — orange 10 — brown
|
||||||
|
3 — red 11 — tan
|
||||||
|
4 — magenta 12 — light grey
|
||||||
|
5 — purple 13 — medium grey
|
||||||
|
6 — blue 14 — dark grey
|
||||||
|
7 — cyan 15 — black
|
||||||
|
--]]
|
||||||
|
|
||||||
register_robot_button("FF","FF","FF",1);
|
--16-color palette from macintosh II, 1987
|
||||||
register_robot_button("80","80","80",2);
|
|
||||||
|
register_robot_button("FF","FF","FF","white",1); -- white
|
||||||
|
register_robot_button("FC","F4","00","yellow",2); -- yellow
|
||||||
|
register_robot_button("FF","64","00","orange",3); -- orange
|
||||||
|
register_robot_button("DD","02","02","red",4); -- red
|
||||||
|
register_robot_button("F0","02","85","magenta",5); -- magenta
|
||||||
|
register_robot_button("46","00","A5","purple",6); -- purple
|
||||||
|
register_robot_button("00","00","D5","blue",7); -- blue
|
||||||
|
register_robot_button("00","AE","E9","cyan",8); -- cyan
|
||||||
|
register_robot_button("1A","B9","0C","green",9); -- green
|
||||||
|
register_robot_button("00","64","08","dark_green",10);-- dark_green
|
||||||
|
register_robot_button("57","28","00","brown",11);-- brown
|
||||||
|
register_robot_button("91","71","35","tan",12);-- tan
|
||||||
|
register_robot_button("C1","C1","C1","light_grey",13);-- light_grey
|
||||||
|
register_robot_button("81","81","81","medium_grey",14);-- medium_grey
|
||||||
|
register_robot_button("3E","3E","3E","dark_grey",15);-- dark_grey
|
||||||
|
register_robot_button("00","00","00","black",16);-- black
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[ -- old colors
|
||||||
|
register_robot_button("FF","FF","FF",1);
|
||||||
|
register_robot_button("80","80","80",2);
|
||||||
register_robot_button("FF","80","80",3);
|
register_robot_button("FF","80","80",3);
|
||||||
register_robot_button("80","FF","80",4);
|
register_robot_button("80","FF","80",4);
|
||||||
register_robot_button("80","80","FF",5);
|
register_robot_button("80","80","FF",5);
|
||||||
register_robot_button("FF","FF","80",6);
|
register_robot_button("FF","FF","80",6);
|
||||||
|
--]]
|
||||||
|
|
||||||
for i = 0,9 do register_robot_button_number(i,i+7) end
|
for i = 0,9 do register_robot_button_number(i,i+17) end -- all buttons shift by 10 from old version!
|
||||||
for i = 0,255 do register_robot_button_char(i,i+17) end
|
for i = 0,255 do register_robot_button_char(i,i+27) end
|
||||||
|
|
||||||
register_robot_button_custom(273,"puzzle_switch_off")
|
register_robot_button_custom(283,"puzzle_switch_off")
|
||||||
register_robot_button_custom(274,"puzzle_switch_on")
|
register_robot_button_custom(284,"puzzle_switch_on")
|
||||||
register_robot_button_custom(275,"puzzle_button_off")
|
register_robot_button_custom(285,"puzzle_button_off")
|
||||||
register_robot_button_custom(276,"puzzle_button_on")
|
register_robot_button_custom(286,"puzzle_button_on")
|
||||||
|
|
||||||
register_robot_button_custom(277,"puzzle_equalizer")
|
register_robot_button_custom(287,"puzzle_equalizer")
|
||||||
register_robot_button_custom(278,"puzzle_setter")
|
register_robot_button_custom(288,"puzzle_setter")
|
||||||
register_robot_button_custom(279,"puzzle_piston")
|
register_robot_button_custom(289,"puzzle_piston")
|
||||||
|
|
||||||
register_robot_button_custom(280,"puzzle_diode")
|
register_robot_button_custom(290,"puzzle_diode")
|
||||||
register_robot_button_custom(281,"puzzle_NOT")
|
register_robot_button_custom(291,"puzzle_NOT")
|
||||||
register_robot_button_custom(282,"puzzle_delayer")
|
register_robot_button_custom(292,"puzzle_delayer")
|
||||||
register_robot_button_custom(283,"puzzle_platform")
|
register_robot_button_custom(293,"puzzle_platform")
|
||||||
|
|
||||||
register_robot_button_custom(284,"puzzle_giver")
|
register_robot_button_custom(294,"puzzle_giver")
|
||||||
register_robot_button_custom(285,"puzzle_checker")
|
register_robot_button_custom(295,"puzzle_checker")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- interactive button for robot: place robot on top of protector to intercept events
|
-- interactive button for robot: place robot on top of protector to intercept events
|
||||||
|
|
||||||
|
local dout = minetest.chat_send_all
|
||||||
|
|
||||||
basic_robot.commands.keyboard = {
|
basic_robot.commands.keyboard = {
|
||||||
|
|
||||||
get = function(name)
|
get = function(name) -- read keyboard event
|
||||||
local data = basic_robot.data[name];
|
local data = basic_robot.data[name];
|
||||||
if data.keyboard then
|
if data.keyevent then
|
||||||
local keyboard = data.keyboard;
|
local keyevent = data.keyevent;
|
||||||
local event = {x=keyboard.x,y=keyboard.y,z=keyboard.z, puncher = keyboard.puncher, type = keyboard.type};
|
local oidx = keyevent[3];
|
||||||
data.keyboard = nil;
|
local iidx = keyevent[2];
|
||||||
|
if oidx == iidx then return nil end --just read past last written event, nothing to read anymore
|
||||||
|
local event = keyevent[4][oidx];
|
||||||
|
-- move oidx (read position ) to newer event
|
||||||
|
oidx = oidx+1; if oidx>keyevent[1] then oidx = 1 end
|
||||||
|
keyevent[3] = oidx
|
||||||
return event
|
return event
|
||||||
else
|
else
|
||||||
return nil
|
return nil
|
||||||
|
@ -718,22 +772,12 @@ basic_robot.commands.keyboard = {
|
||||||
local nodename;
|
local nodename;
|
||||||
if type == 0 then
|
if type == 0 then
|
||||||
nodename = "air"
|
nodename = "air"
|
||||||
elseif type == 1 then
|
elseif type < 17 then
|
||||||
nodename = "basic_robot:buttonFFFFFF";
|
nodename = buttoncolors[type]
|
||||||
elseif type == 2 then
|
elseif type>=17 and type <= 26 then
|
||||||
nodename = "basic_robot:button808080";
|
nodename = "basic_robot:button"..(type-17);
|
||||||
elseif type == 3 then
|
|
||||||
nodename = "basic_robot:buttonFF8080";
|
|
||||||
elseif type == 4 then
|
|
||||||
nodename = "basic_robot:button80FF80";
|
|
||||||
elseif type == 5 then
|
|
||||||
nodename = "basic_robot:button8080FF";
|
|
||||||
elseif type == 6 then
|
|
||||||
nodename = "basic_robot:buttonFFFF80";
|
|
||||||
elseif type>=7 and type <= 16 then
|
|
||||||
nodename = "basic_robot:button"..(type-7);
|
|
||||||
else
|
else
|
||||||
nodename = "basic_robot:button_"..(type-17);
|
nodename = "basic_robot:button_"..(type-27);
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.swap_node(pos, {name = nodename})
|
minetest.swap_node(pos, {name = nodename})
|
||||||
|
@ -829,7 +873,7 @@ end
|
||||||
--pathfinding: find_path, walk_path
|
--pathfinding: find_path, walk_path
|
||||||
basic_robot.commands.find_path = function(name,pos2)
|
basic_robot.commands.find_path = function(name,pos2)
|
||||||
local obj = basic_robot.data[name].obj;
|
local obj = basic_robot.data[name].obj;
|
||||||
local pos1 = obj:getpos();
|
local pos1 = obj:get_pos();
|
||||||
|
|
||||||
if (pos1.x-pos2.x)^2+(pos1.y-pos2.y)^2+(pos1.z-pos2.z)^2> 50^2 then
|
if (pos1.x-pos2.x)^2+(pos1.y-pos2.y)^2+(pos1.z-pos2.z)^2> 50^2 then
|
||||||
return nil,"2: distance too large"
|
return nil,"2: distance too large"
|
||||||
|
@ -869,7 +913,7 @@ basic_robot.commands.walk_path = function(name)
|
||||||
|
|
||||||
local pos2 = path[idx]
|
local pos2 = path[idx]
|
||||||
local obj = basic_robot.data[name].obj;
|
local obj = basic_robot.data[name].obj;
|
||||||
local pos1 = obj:getpos();
|
local pos1 = obj:get_pos();
|
||||||
|
|
||||||
local ndist = (pos1.x-pos2.x)^2+(pos1.y-pos2.y)^2+(pos1.z-pos2.z)^2
|
local ndist = (pos1.x-pos2.x)^2+(pos1.y-pos2.y)^2+(pos1.z-pos2.z)^2
|
||||||
if ndist> 4 then return -ndist end -- too far away from next node
|
if ndist> 4 then return -ndist end -- too far away from next node
|
||||||
|
@ -895,7 +939,7 @@ basic_robot.commands.walk_path = function(name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
yaw = yaw - math.pi/2
|
yaw = yaw - math.pi/2
|
||||||
obj:setyaw(yaw);
|
obj:set_yaw(yaw);
|
||||||
|
|
||||||
pathdata[1] = idx + 1 -- target next node
|
pathdata[1] = idx + 1 -- target next node
|
||||||
obj:moveto(pos2, true)
|
obj:moveto(pos2, true)
|
||||||
|
@ -976,7 +1020,7 @@ basic_robot.commands.machine = {
|
||||||
|
|
||||||
check_operations(name,6, true)
|
check_operations(name,6, true)
|
||||||
|
|
||||||
if amount and amount>0 then -- attempt to generate power from builtin generator
|
if amount and amount>0 and amount<10^6 then -- attempt to generate power from builtin generator
|
||||||
local pos = basic_robot.data[name].spawnpos; -- position of spawner block
|
local pos = basic_robot.data[name].spawnpos; -- position of spawner block
|
||||||
local inv = minetest.get_meta(pos):get_inventory();
|
local inv = minetest.get_meta(pos):get_inventory();
|
||||||
local level = amount*40; -- to generate 1 unit ( coal lump per second ) we need at least upgrade 40
|
local level = amount*40; -- to generate 1 unit ( coal lump per second ) we need at least upgrade 40
|
||||||
|
@ -1150,9 +1194,8 @@ basic_robot.commands.machine = {
|
||||||
|
|
||||||
local energy = 0; -- can only do one step at a run time
|
local energy = 0; -- can only do one step at a run time
|
||||||
|
|
||||||
|
|
||||||
energy = data.menergy or 0;
|
energy = data.menergy or 0;
|
||||||
if amount>energy or amount<0 then return nil,"energy too low" end
|
if amount>energy or amount<0 or amount>10^6 then return nil,"energy too low" end
|
||||||
|
|
||||||
if not tdata.menergy then tdata.menergy = 0 end
|
if not tdata.menergy then tdata.menergy = 0 end
|
||||||
tdata.menergy = tdata.menergy + amount
|
tdata.menergy = tdata.menergy + amount
|
||||||
|
@ -1160,6 +1203,52 @@ basic_robot.commands.machine = {
|
||||||
return true
|
return true
|
||||||
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
place_seed = function(name,dir,seedbookname) -- use basic_farming seedbook to place seed
|
||||||
|
if not basic_farming then return end
|
||||||
|
local obj = basic_robot.data[name].obj;
|
||||||
|
local pos = pos_in_dir(obj, dir)
|
||||||
|
|
||||||
|
local spos = obj:get_luaentity().spawnpos;
|
||||||
|
local inv = minetest.get_meta(spos):get_inventory();
|
||||||
|
local idx = 0; -- where is seedbook?
|
||||||
|
|
||||||
|
for i = 1,inv:get_size("main") do -- where in inventory is seedbook?
|
||||||
|
if inv:get_stack("main", i):get_name() == seedbookname then idx = i; break end
|
||||||
|
end
|
||||||
|
if idx == 0 then return end -- no book in inventory!
|
||||||
|
|
||||||
|
local itemstack = basic_farming.seed_on_place(inv:get_stack("main", idx), nil, {type = "node",above = pos})
|
||||||
|
inv:set_stack("main", idx, itemstack) -- refresh stack in inventory
|
||||||
|
end,
|
||||||
|
|
||||||
|
dig_seed = function(name, dir)
|
||||||
|
if not basic_farming then return end
|
||||||
|
local obj = basic_robot.data[name].obj;
|
||||||
|
local pos = pos_in_dir(obj, dir)
|
||||||
|
|
||||||
|
local nodename = minetest.get_node(pos).name;
|
||||||
|
local basename,stage
|
||||||
|
basename,stage=string.match(nodename,"%w+:(%w+)_(%d+)") -- modname:basename_stage
|
||||||
|
if not basename then return end
|
||||||
|
|
||||||
|
local spos = basic_robot.data[name].spawnpos; -- position of spawner block
|
||||||
|
local inv = minetest.get_meta(spos):get_inventory();
|
||||||
|
|
||||||
|
local itemstack = ItemStack("basic_farming:seedbook_" .. basename)
|
||||||
|
|
||||||
|
local seeds = tostring(minetest.get_meta(pos):get_int("gene"));
|
||||||
|
-- possibly several seeds?
|
||||||
|
local count = minetest.get_meta(pos):get_int("count"); if count == 0 then count = 1 end
|
||||||
|
|
||||||
|
local data = {name = basename, items = string.rep(seeds.. " ",count-1) .. seeds }
|
||||||
|
minetest.set_node(pos,{name = "air"})
|
||||||
|
local meta = itemstack:get_meta()
|
||||||
|
meta:from_table({fields = data})
|
||||||
|
|
||||||
|
inv:add_item("main",itemstack);
|
||||||
|
end,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-- CRPYTOGRAPHY
|
-- CRPYTOGRAPHY
|
||||||
|
@ -1304,7 +1393,7 @@ local cmd_get_player = function(data,pname) -- return player for further manipul
|
||||||
local player = minetest.get_player_by_name(pname)
|
local player = minetest.get_player_by_name(pname)
|
||||||
if not player then error("player does not exist"); return end
|
if not player then error("player does not exist"); return end
|
||||||
local spos = data.spawnpos;
|
local spos = data.spawnpos;
|
||||||
local ppos = player:getpos();
|
local ppos = player:get_pos();
|
||||||
if not is_same_block(ppos,spos) then error("can not get player in another protection zone") return end
|
if not is_same_block(ppos,spos) then error("can not get player in another protection zone") return end
|
||||||
return player
|
return player
|
||||||
end
|
end
|
||||||
|
@ -1313,7 +1402,7 @@ local cmd_get_player_inv = function(data,pname)
|
||||||
local player = minetest.get_player_by_name(pname)
|
local player = minetest.get_player_by_name(pname)
|
||||||
if not player then return end
|
if not player then return end
|
||||||
local spos = data.spawnpos;
|
local spos = data.spawnpos;
|
||||||
local ppos = player:getpos();
|
local ppos = player:get_pos();
|
||||||
if not is_same_block(ppos,spos) then error("can not get player in another protection zone") return end
|
if not is_same_block(ppos,spos) then error("can not get player in another protection zone") return end
|
||||||
return player:get_inventory();
|
return player:get_inventory();
|
||||||
end
|
end
|
||||||
|
@ -1472,7 +1561,7 @@ function Vplayer:new(name) -- constructor
|
||||||
end
|
end
|
||||||
|
|
||||||
-- functions
|
-- functions
|
||||||
function Vplayer:getpos() return self.obj:getpos() end
|
function Vplayer:get_pos() return self.obj:get_pos() end
|
||||||
function Vplayer:remove() end
|
function Vplayer:remove() end
|
||||||
function Vplayer:setpos() end
|
function Vplayer:setpos() end
|
||||||
function Vplayer:move_to() end
|
function Vplayer:move_to() end
|
||||||
|
|
266
init.lua
266
init.lua
|
@ -1,32 +1,11 @@
|
||||||
-- basic_robot by rnd, 2016
|
-- basic_robot by rnd, 2016-2022
|
||||||
|
|
||||||
|
|
||||||
basic_robot = {};
|
basic_robot = {};
|
||||||
------ SETTINGS --------
|
basic_robot.version = "2022/02/02b";
|
||||||
basic_robot.call_limit = {50,200,1500,10^9}; -- how many execution calls per script run allowed, for auth levels 0,1,2 (normal, robot, puzzle, admin)
|
|
||||||
basic_robot.count = {2,6,16,128} -- how many robots player can have
|
|
||||||
|
|
||||||
basic_robot.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches
|
dofile(minetest.get_modpath("basic_robot").."/settings.lua") -- read configuration SETTINGS
|
||||||
basic_robot.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running mod, password used for authentifications
|
|
||||||
|
|
||||||
basic_robot.admin_bot_pos = {x=0,y=1,z=0} -- position of admin robot spawner that will be run automatically on server start
|
-- structures for storing robot data
|
||||||
|
|
||||||
basic_robot.maxoperations = 10; -- how many operations (dig, place,move,...,generate energy,..) available per run, 0 = unlimited
|
|
||||||
basic_robot.dig_require_energy = true; -- does robot require energy to dig stone?
|
|
||||||
|
|
||||||
basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
|
|
||||||
["moreblocks:circular_saw"] = true,
|
|
||||||
["craft_guide:sign_wall"] = true,
|
|
||||||
["basic_machines:battery_0"] = true,
|
|
||||||
["basic_machines:battery_1"] = true,
|
|
||||||
["basic_machines:battery_2"] = true,
|
|
||||||
["basic_machines:generator"] = true,
|
|
||||||
}
|
|
||||||
----- END OF SETTINGS ------
|
|
||||||
|
|
||||||
basic_robot.http_api = minetest.request_http_api();
|
|
||||||
|
|
||||||
basic_robot.version = "2020/10/14a";
|
|
||||||
|
|
||||||
basic_robot.gui = {}; local robogui = basic_robot.gui -- gui management
|
basic_robot.gui = {}; local robogui = basic_robot.gui -- gui management
|
||||||
basic_robot.data = {}; -- stores all robot related data
|
basic_robot.data = {}; -- stores all robot related data
|
||||||
|
@ -40,6 +19,7 @@ basic_robot.ids = {}; -- stores maxid for each player
|
||||||
basic_robot.virtual_players = {}; -- this way robot can interact with the world as "player" TODO
|
basic_robot.virtual_players = {}; -- this way robot can interact with the world as "player" TODO
|
||||||
|
|
||||||
basic_robot.data.listening = {}; -- which robots listen to chat
|
basic_robot.data.listening = {}; -- which robots listen to chat
|
||||||
|
basic_robot.data.punchareas = {}; -- where robots listen punch events, [hashes of 32 sized chunk] = robot name
|
||||||
|
|
||||||
dofile(minetest.get_modpath("basic_robot").."/robogui.lua") -- gui stuff
|
dofile(minetest.get_modpath("basic_robot").."/robogui.lua") -- gui stuff
|
||||||
dofile(minetest.get_modpath("basic_robot").."/commands.lua")
|
dofile(minetest.get_modpath("basic_robot").."/commands.lua")
|
||||||
|
@ -49,7 +29,6 @@ local check_code, preprocess_code,is_inside_string;
|
||||||
|
|
||||||
|
|
||||||
-- SANDBOX for running lua code isolated and safely
|
-- SANDBOX for running lua code isolated and safely
|
||||||
|
|
||||||
function getSandboxEnv (name)
|
function getSandboxEnv (name)
|
||||||
|
|
||||||
local authlevel = basic_robot.data[name].authlevel or 0;
|
local authlevel = basic_robot.data[name].authlevel or 0;
|
||||||
|
@ -60,21 +39,26 @@ function getSandboxEnv (name)
|
||||||
left_up = 11, right_up = 12, forward_up = 13, backward_up = 14
|
left_up = 11, right_up = 12, forward_up = 13, backward_up = 14
|
||||||
}
|
}
|
||||||
|
|
||||||
if not basic_robot.data[name].rom then basic_robot.data[name].rom = {} end -- create rom if not yet existing
|
local pname = string.sub(name,1,-2)
|
||||||
|
if not basic_robot.data[pname] then basic_robot.data[pname] = {} end
|
||||||
|
-- all robots by player share same rom now
|
||||||
|
if not basic_robot.data[pname].rom then basic_robot.data[pname].rom = {} end -- create rom if not yet existing
|
||||||
|
|
||||||
local env =
|
local env =
|
||||||
{
|
{
|
||||||
|
_Gerror = error,
|
||||||
pcall=pcall,
|
pcall=pcall,
|
||||||
robot_version = function() return basic_robot.version end,
|
robot_version = function() return basic_robot.version end,
|
||||||
|
|
||||||
boost = function(v)
|
boost = function(v)
|
||||||
if math.abs(v)>2 then v = 0 end; local obj = basic_robot.data[name].obj;
|
if math.abs(v)>2 then v = 0 end; local obj = basic_robot.data[name].obj;
|
||||||
if v == 0 then
|
if v == 0 then
|
||||||
local pos = obj:getpos(); pos.x = math.floor(pos.x+0.5);pos.y = math.floor(pos.y+0.5); pos.z = math.floor(pos.z+0.5);
|
local pos = obj:get_pos(); pos.x = math.floor(pos.x+0.5);pos.y = math.floor(pos.y+0.5); pos.z = math.floor(pos.z+0.5);
|
||||||
obj:setpos(pos); obj:set_velocity({x=0,y=0,z=0});
|
obj:setpos(pos); obj:set_velocity({x=0,y=0,z=0});
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local yaw = obj:get_yaw();
|
local yaw = obj:get_yaw();
|
||||||
obj:set_velocity({x=v*math.cos(yaw),y=0,z=v*math.sin(yaw)});
|
obj:set_velocity({x=-v*math.sin(yaw),y=0,z=v*math.cos(yaw)});
|
||||||
end,
|
end,
|
||||||
|
|
||||||
turn = {
|
turn = {
|
||||||
|
@ -91,17 +75,19 @@ function getSandboxEnv (name)
|
||||||
return commands.craft(item, mode, idx, amount, name)
|
return commands.craft(item, mode, idx, amount, name)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
pause = function() -- pause coroutine
|
pause = function(amount) -- pause coroutine
|
||||||
if not basic_robot.data[name].cor then error("you must start program with '--coroutine' to use pause()") return end
|
if not basic_robot.data[name].cor then error("you must start program with '--coroutine' to use pause()") return end
|
||||||
coroutine.yield()
|
if not amount or basic_robot.data[name].operations<amount then
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
self = {
|
self = {
|
||||||
pos = function() return basic_robot.data[name].obj:getpos() end,
|
pos = function() return basic_robot.data[name].obj:get_pos() end,
|
||||||
spawnpos = function() local pos = basic_robot.data[name].spawnpos; return {x=pos.x,y=pos.y,z=pos.z} end,
|
spawnpos = function() local pos = basic_robot.data[name].spawnpos; return {x=pos.x,y=pos.y,z=pos.z} end,
|
||||||
name = function() return name end,
|
name = function() return name end,
|
||||||
operations = function() return basic_robot.data[name].operations end,
|
operations = function() return basic_robot.data[name].operations end,
|
||||||
viewdir = function() local yaw = basic_robot.data[name].obj:getyaw(); return {x=math.cos(yaw), y = 0, z=math.sin(yaw)} end,
|
viewdir = function() local yaw = basic_robot.data[name].obj:getyaw(); return {x=-math.sin(yaw), y = 0, z=math.cos(yaw)} end,
|
||||||
|
|
||||||
set_properties = function(properties)
|
set_properties = function(properties)
|
||||||
if not properties then return end; local obj = basic_robot.data[name].obj;
|
if not properties then return end; local obj = basic_robot.data[name].obj;
|
||||||
|
@ -113,7 +99,7 @@ function getSandboxEnv (name)
|
||||||
obj:set_animation({x=anim_start,y=anim_end}, anim_speed, anim_stand_start)
|
obj:set_animation({x=anim_start,y=anim_end}, anim_speed, anim_stand_start)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
listen = function (mode)
|
listen = function (mode) -- will robot listen to chat?
|
||||||
if mode == 1 then
|
if mode == 1 then
|
||||||
basic_robot.data.listening[name] = true
|
basic_robot.data.listening[name] = true
|
||||||
else
|
else
|
||||||
|
@ -121,6 +107,24 @@ function getSandboxEnv (name)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
listen_punch = function(pos, is_remove) -- robot will listen to punch events in 32 sized chunk containing pos
|
||||||
|
local round = math.floor;
|
||||||
|
local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted
|
||||||
|
if not pos then return end
|
||||||
|
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
|
||||||
|
local hppos = minetest.hash_node_position(ppos)
|
||||||
|
local rname = basic_robot.data.punchareas[hppos];
|
||||||
|
if is_remove then -- remove listener
|
||||||
|
basic_robot.data.punchareas[hppos] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if rname then -- area already registered for listening
|
||||||
|
return rname
|
||||||
|
end
|
||||||
|
basic_robot.data.punchareas[hppos] = name; -- register robot name
|
||||||
|
end,
|
||||||
|
|
||||||
listen_msg = function()
|
listen_msg = function()
|
||||||
local msg = basic_robot.data[name].listen_msg;
|
local msg = basic_robot.data[name].listen_msg;
|
||||||
local speaker = basic_robot.data[name].listen_speaker;
|
local speaker = basic_robot.data[name].listen_speaker;
|
||||||
|
@ -153,7 +157,7 @@ function getSandboxEnv (name)
|
||||||
reset = function()
|
reset = function()
|
||||||
local pos = basic_robot.data[name].spawnpos;
|
local pos = basic_robot.data[name].spawnpos;
|
||||||
local obj = basic_robot.data[name].obj;
|
local obj = basic_robot.data[name].obj;
|
||||||
obj:setpos({x=pos.x,y=pos.y+1,z=pos.z}); obj:setyaw(0);
|
obj:set_pos({x=pos.x,y=pos.y+1,z=pos.z}); obj:set_yaw(0);
|
||||||
end,
|
end,
|
||||||
|
|
||||||
set_libpos = function(pos)
|
set_libpos = function(pos)
|
||||||
|
@ -171,7 +175,7 @@ function getSandboxEnv (name)
|
||||||
|
|
||||||
fire = function(speed, pitch,gravity, texture, is_entity) -- experimental: fires an projectile
|
fire = function(speed, pitch,gravity, texture, is_entity) -- experimental: fires an projectile
|
||||||
local obj = basic_robot.data[name].obj;
|
local obj = basic_robot.data[name].obj;
|
||||||
local pos = obj:getpos();
|
local pos = obj:get_pos();
|
||||||
local yaw = obj:getyaw()+ math.pi/2;
|
local yaw = obj:getyaw()+ math.pi/2;
|
||||||
pitch = pitch*math.pi/180
|
pitch = pitch*math.pi/180
|
||||||
local velocity = {x=speed*math.cos(yaw)*math.cos(pitch), y=speed*math.sin(pitch),z=speed*math.sin(yaw)*math.cos(pitch)};
|
local velocity = {x=speed*math.cos(yaw)*math.cos(pitch), y=speed*math.sin(pitch),z=speed*math.sin(yaw)*math.cos(pitch)};
|
||||||
|
@ -253,16 +257,16 @@ function getSandboxEnv (name)
|
||||||
find_nodes =
|
find_nodes =
|
||||||
function(nodename,r)
|
function(nodename,r)
|
||||||
if r>8 then return false end
|
if r>8 then return false end
|
||||||
local q = minetest.find_node_near(basic_robot.data[name].obj:getpos(), r, nodename);
|
local q = minetest.find_node_near(basic_robot.data[name].obj:get_pos(), r, nodename);
|
||||||
if q==nil then return false end
|
if q==nil then return false end
|
||||||
local p = basic_robot.data[name].obj:getpos()
|
local p = basic_robot.data[name].obj:get_pos()
|
||||||
return math.sqrt((p.x-q.x)^2+(p.y-q.y)^2+(p.z-q.z)^2)
|
return math.sqrt((p.x-q.x)^2+(p.y-q.y)^2+(p.z-q.z)^2)
|
||||||
end, -- in radius around position
|
end, -- in radius around position
|
||||||
|
|
||||||
find_player =
|
find_player =
|
||||||
function(r,pos)
|
function(r,pos)
|
||||||
pos = pos or basic_robot.data[name].obj:getpos();
|
pos = pos or basic_robot.data[name].obj:get_pos();
|
||||||
if r>10 then return false end
|
if r<0 or r>10 then return false end
|
||||||
local objects = minetest.get_objects_inside_radius(pos, r);
|
local objects = minetest.get_objects_inside_radius(pos, r);
|
||||||
local plist = {};
|
local plist = {};
|
||||||
for _,obj in pairs(objects) do
|
for _,obj in pairs(objects) do
|
||||||
|
@ -277,7 +281,12 @@ function getSandboxEnv (name)
|
||||||
player = {
|
player = {
|
||||||
getpos = function(name)
|
getpos = function(name)
|
||||||
local player = minetest.get_player_by_name(name);
|
local player = minetest.get_player_by_name(name);
|
||||||
if player then return player:getpos() else return nil end
|
if player then return player:get_pos() else return nil end
|
||||||
|
end,
|
||||||
|
|
||||||
|
getview = function(name)
|
||||||
|
local player = minetest.get_player_by_name(name);
|
||||||
|
if player then return player:get_look_dir() else return nil end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
connected = function()
|
connected = function()
|
||||||
|
@ -326,6 +335,8 @@ function getSandboxEnv (name)
|
||||||
write = function(i,title,text)
|
write = function(i,title,text)
|
||||||
if i<=0 or i > 32 then return nil end
|
if i<=0 or i > 32 then return nil end
|
||||||
local inv = minetest.get_meta(basic_robot.data[name].spawnpos):get_inventory();
|
local inv = minetest.get_meta(basic_robot.data[name].spawnpos):get_inventory();
|
||||||
|
local stackname = inv:get_stack("library",i):get_name();
|
||||||
|
if basic_robot.data[name].authlevel<3 and (stackname ~= "default:book_written" and stackname~= "default:book") then return nil end
|
||||||
local stack = basic_robot.commands.write_book(basic_robot.data[name].owner,title,text);
|
local stack = basic_robot.commands.write_book(basic_robot.data[name].owner,title,text);
|
||||||
if stack then inv:set_stack("library", i, stack) end
|
if stack then inv:set_stack("library", i, stack) end
|
||||||
end
|
end
|
||||||
|
@ -344,8 +355,8 @@ function getSandboxEnv (name)
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
|
|
||||||
rom = basic_robot.data[name].rom,
|
rom = basic_robot.data[pname].rom,
|
||||||
|
|
||||||
string = {
|
string = {
|
||||||
byte = string.byte, char = string.char,
|
byte = string.byte, char = string.char,
|
||||||
find = string.find,
|
find = string.find,
|
||||||
|
@ -460,6 +471,14 @@ function getSandboxEnv (name)
|
||||||
for dir, dir_id in pairs(directions) do
|
for dir, dir_id in pairs(directions) do
|
||||||
env.write_text[dir] = function(text) return commands.write_text(name, dir_id,text) end
|
env.write_text[dir] = function(text) return commands.write_text(name, dir_id,text) end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--farming specials
|
||||||
|
env.machine.place_seed = {}; local env_machine_place_seed = env.machine.place_seed
|
||||||
|
env.machine.dig_seed = {}; local env_machine_dig_seed = env.machine.dig_seed;
|
||||||
|
for dir, dir_id in pairs(directions) do
|
||||||
|
env_machine_place_seed[dir] = function(seedbookname) return commands.machine.place_seed(name,dir_id,seedbookname) end
|
||||||
|
env_machine_dig_seed[dir] = function(dir) return commands.machine.dig_seed(name,dir_id) end
|
||||||
|
end
|
||||||
|
|
||||||
if authlevel>=1 then -- robot privs
|
if authlevel>=1 then -- robot privs
|
||||||
|
|
||||||
|
@ -492,7 +511,7 @@ function getSandboxEnv (name)
|
||||||
|
|
||||||
setfenv( ScriptFunc, basic_robot.data[name].sandbox )
|
setfenv( ScriptFunc, basic_robot.data[name].sandbox )
|
||||||
|
|
||||||
local Result, RuntimeError = pcall( ScriptFunc );
|
local _, RuntimeError = pcall( ScriptFunc );
|
||||||
if RuntimeError then
|
if RuntimeError then
|
||||||
minetest.chat_send_player(name, "#code.run: run error " .. RuntimeError )
|
minetest.chat_send_player(name, "#code.run: run error " .. RuntimeError )
|
||||||
return false
|
return false
|
||||||
|
@ -536,7 +555,7 @@ function getSandboxEnv (name)
|
||||||
set_triggers = function(triggers) commands.puzzle.set_triggers(pdata,triggers) end, -- FIX THIS!
|
set_triggers = function(triggers) commands.puzzle.set_triggers(pdata,triggers) end, -- FIX THIS!
|
||||||
check_triggers = function(pname)
|
check_triggers = function(pname)
|
||||||
local player = minetest.get_player_by_name(pname); if not player then return end
|
local player = minetest.get_player_by_name(pname); if not player then return end
|
||||||
commands.puzzle.checkpos(pdata,player:getpos(),pname)
|
commands.puzzle.checkpos(pdata,player:get_pos(),pname)
|
||||||
end,
|
end,
|
||||||
add_particle = function(def) minetest.add_particle(def) end,
|
add_particle = function(def) minetest.add_particle(def) end,
|
||||||
count_objects = function(pos,radius) return #minetest.get_objects_inside_radius(pos, math.min(radius,5)) end,
|
count_objects = function(pos,radius) return #minetest.get_objects_inside_radius(pos, math.min(radius,5)) end,
|
||||||
|
@ -559,10 +578,13 @@ function getSandboxEnv (name)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- code checker
|
-- code checker
|
||||||
|
-- bugfixes:
|
||||||
|
-- player Midskip found problem with code checking, fixed
|
||||||
|
|
||||||
|
|
||||||
check_code = function(code)
|
check_code = function(code)
|
||||||
--"while ", "for ", "do ","goto ",
|
--"while ", "for ", "do ","goto ",
|
||||||
local bad_code = {"repeat", "until", "_c_", "_G", "while%(", "while{", "pcall","%.%.[^%.]"} --,"\\\"", "%[=*%[","--[["}
|
local bad_code = {"repeat", "until", "_G", "while%(", "while{", "pcall","[^%.]%.%.[^%.]","\\\"","\\\'","%[=*%["}
|
||||||
for _, v in pairs(bad_code) do
|
for _, v in pairs(bad_code) do
|
||||||
if string.find(code, v) then
|
if string.find(code, v) then
|
||||||
return v .. " is not allowed!";
|
return v .. " is not allowed!";
|
||||||
|
@ -570,8 +592,7 @@ check_code = function(code)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
|
||||||
local identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
|
|
||||||
|
|
||||||
local i = 0; local j; local _; local length = string.len(code);
|
local i = 0; local j; local _; local length = string.len(code);
|
||||||
local mode = 0; -- 0: not in string, 1: in '...' string, 2: in "..." string, 3. in [==[ ... ]==] string
|
local mode = 0; -- 0: not in string, 1: in '...' string, 2: in "..." string, 3. in [==[ ... ]==] string
|
||||||
|
@ -589,8 +610,12 @@ local identify_strings = function(code) -- returns list of positions {start,end}
|
||||||
for k=1,#modes do
|
for k=1,#modes do
|
||||||
j = string.find(code,modes[k][1],i);
|
j = string.find(code,modes[k][1],i);
|
||||||
if j and j<jmin then -- pick closest one
|
if j and j<jmin then -- pick closest one
|
||||||
jmin = j
|
if string.sub(code,j-1,j-1) ~="\\" then
|
||||||
mode = k
|
jmin = j
|
||||||
|
mode = k
|
||||||
|
else
|
||||||
|
j=j+1;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if mode ~= 0 then -- found something
|
if mode ~= 0 then -- found something
|
||||||
|
@ -601,10 +626,12 @@ local identify_strings = function(code) -- returns list of positions {start,end}
|
||||||
else
|
else
|
||||||
_,j = string.find(code,modes[mode][2],i); -- search for closing pair
|
_,j = string.find(code,modes[mode][2],i); -- search for closing pair
|
||||||
if not j then break end
|
if not j then break end
|
||||||
if (mode~=2 or (string.sub(code,j-1,j-1) ~= "\\") or string.sub(code,j-2,j-1) == "\\\\") then -- not (" and not \" - but "\\" is allowed)
|
local pchar = string.sub(code,j-1,j-1)
|
||||||
|
if (mode~=2 or (pchar ~= "\\") or string.sub(code,j-2,j-1) == "\\\\") then -- not (" and not \" - but "\\" is allowed)
|
||||||
ret[#ret][2] = j
|
ret[#ret][2] = j
|
||||||
mode = 0
|
mode = 0
|
||||||
end
|
end
|
||||||
|
if pchar == "\\" then j=j+1 end
|
||||||
end
|
end
|
||||||
i=j -- move to next position
|
i=j -- move to next position
|
||||||
end
|
end
|
||||||
|
@ -650,11 +677,11 @@ preprocess_code = function(script, call_limit) -- version 07/24/2018
|
||||||
when counter exceeds limit exit with error
|
when counter exceeds limit exit with error
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-[^\n]*\n","\n") -- strip comments
|
--script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-[^\n]*\n","\n") -- strip comments
|
||||||
|
script = string.gsub(script,"%-%-[^\n]+\n","\n") -- strip single line comments, multiline not allowed
|
||||||
-- process script to insert call counter in every function
|
-- process script to insert call counter in every function
|
||||||
local _increase_ccounter = " _c_ = _c_ + 1; if _c_ > " .. call_limit ..
|
local _increase_ccounter = " _Gc = _Gc + 1; if _Gc > " .. call_limit ..
|
||||||
" then _G.error(\"Execution count \".. _c_ .. \" exceeded ".. call_limit .. "\") end; "
|
" then _Gerror(\"Execution count \".. _Gc .. \" exceeded ".. call_limit .. "\") end; "
|
||||||
|
|
||||||
local i1=0; local i2 = 0;
|
local i1=0; local i2 = 0;
|
||||||
local found = true;
|
local found = true;
|
||||||
|
@ -713,7 +740,7 @@ preprocess_code = function(script, call_limit) -- version 07/24/2018
|
||||||
-- must reset ccounter when paused, but user should not be able to force reset by modifying pause!
|
-- must reset ccounter when paused, but user should not be able to force reset by modifying pause!
|
||||||
-- (suggestion about 'pause' by Kimapr, 09/26/2019)
|
-- (suggestion about 'pause' by Kimapr, 09/26/2019)
|
||||||
|
|
||||||
return "_c_ = 0 local _pause_ = pause pause = function() _c_ = 0; _pause_() end " .. script;
|
return "_Gc = 0 local _Gpause = pause pause = function(amount) _Gc = 0; _Gpause(amount) end " .. script;
|
||||||
|
|
||||||
--return script:gsub("pause%(%)", "_c_ = 0; pause()") -- reset ccounter at pause
|
--return script:gsub("pause%(%)", "_c_ = 0; pause()") -- reset ccounter at pause
|
||||||
end
|
end
|
||||||
|
@ -770,7 +797,7 @@ local function runSandbox( name)
|
||||||
end
|
end
|
||||||
|
|
||||||
data.operations = basic_robot.maxoperations;
|
data.operations = basic_robot.maxoperations;
|
||||||
data.t = os.clock()
|
data.t = os.clock() -- timing
|
||||||
|
|
||||||
setfenv( ScriptFunc, data.sandbox )
|
setfenv( ScriptFunc, data.sandbox )
|
||||||
|
|
||||||
|
@ -830,25 +857,28 @@ local robot_spawner_update_form = function (pos, mode)
|
||||||
|
|
||||||
form =
|
form =
|
||||||
"size[9.5,8]" .. -- width, height
|
"size[9.5,8]" .. -- width, height
|
||||||
"textarea[1.25,-0.25;8.75,9.8;code;;".. code.."]"..
|
"style_type[textarea;font_size=12;font=mono;bgcolor=#000000;textcolor=#00FF00;border=false]"..
|
||||||
"button[-0.25,7.5;1.25,1;EDIT;EDIT]"..
|
"style_type[button;font_size=14;font=mono;bgcolor=#000000;border=false]"..
|
||||||
"button_exit[-0.25,-0.25;1.25,1;OK;SAVE]"..
|
"style_type[button_exit;font_size=14;font=mono;bgcolor=#000000;border=false]"..
|
||||||
"button_exit[-0.25, 0.75;1.25,1;spawn;START]"..
|
"textarea[1.25,-0.25;8.8,10.25;code;;".. code.."]"..
|
||||||
"button[-0.25, 1.75;1.25,1;despawn;STOP]"..
|
"button[-0.15,7.5;1.25,1;EDIT;EDIT]"..
|
||||||
"field[0.25,3.;1.,1;id;id;"..id.."]"..
|
"button[-0.15,-0.25;1.25,1;OK;"..minetest.colorize("yellow","SAVE").."]"..
|
||||||
"button[-0.25, 3.6;1.25,1;inventory;storage]"..
|
"button_exit[-0.15, 0.75;1.25,1;spawn;"..minetest.colorize("green","START").."]"..
|
||||||
"button[-0.25, 4.6;1.25,1;library;library]"..
|
"button[-0.15, 1.75;1.25,1;despawn;"..minetest.colorize("red","STOP").."]"..
|
||||||
"button[-0.25, 5.6;1.25,1;help;help]";
|
"field[0.15,3.;1.2,1;id;id;"..id.."]"..
|
||||||
|
"button[-0.15, 3.6;1.25,1;inventory;STORAGE]"..
|
||||||
|
"button[-0.15, 4.6;1.25,1;library;LIBRARY]"..
|
||||||
|
"button[-0.15, 5.6;1.25,1;help;HELP]";
|
||||||
|
|
||||||
else -- when robot clicked
|
else -- when robot clicked
|
||||||
form =
|
form =
|
||||||
"size[9.5,8]" .. -- width, height
|
"size[9.5,8]" .. -- width, height
|
||||||
"textarea[1.25,-0.25;8.75,9.8;code;;".. code.."]"..
|
"textarea[1.25,-0.25;8.75,10.25;code;;".. code.."]"..
|
||||||
"button_exit[-0.25,-0.25;1.25,1;OK;SAVE]"..
|
"button_exit[-0.15,-0.25;1.25,1;OK;SAVE]"..
|
||||||
"button[-0.25, 1.75;1.25,1;despawn;STOP]"..
|
"button[-0.15, 1.75;1.25,1;despawn;STOP]"..
|
||||||
"button[-0.25, 3.6;1.25,1;inventory;storage]"..
|
"button[-0.15, 3.6;1.25,1;inventory;storage]"..
|
||||||
"button[-0.25, 4.6;1.25,1;library;library]"..
|
"button[-0.15, 4.6;1.25,1;library;library]"..
|
||||||
"button[-0.25, 5.6;1.25,1;help;help]";
|
"button[-0.15, 5.6;1.25,1;help;help]";
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -882,10 +912,10 @@ code_edit_form = function(pos,name)
|
||||||
local list = "";
|
local list = "";
|
||||||
for _,line in pairs(lines) do list = list .. minetest.formspec_escape(line) .. "," end
|
for _,line in pairs(lines) do list = list .. minetest.formspec_escape(line) .. "," end
|
||||||
local form = "size[12,9.25]" .. "textlist[0,0;12,8;listname;" .. list .. ";"..selection..";false]" ..
|
local form = "size[12,9.25]" .. "textlist[0,0;12,8;listname;" .. list .. ";"..selection..";false]" ..
|
||||||
"button[10,8;2,1;INSERT;INSERT LINE]" ..
|
"button[10,8;2.25,1;INSERT;INSERT LINE]" ..
|
||||||
"button[10,8.75;2,1;DELETE;DELETE LINE]" ..
|
"button[10,8.75;2.25,1;DELETE;DELETE LINE]" ..
|
||||||
"button_exit[2,8.75;2,1;SAVE;SAVE CODE]" ..
|
"button_exit[2.25,8.75;2.25,1;SAVE;SAVE CODE]" ..
|
||||||
"button[0,8.75;2,1;UPDATE;UPDATE LINE]"..
|
"button[0,8.75;2.25,1;UPDATE;UPDATE LINE] label[4.25,9; LINE " .. selection .."]"..
|
||||||
"textarea[0.25,8;10,1;input;;".. input .. "]"
|
"textarea[0.25,8;10,1;input;;".. input .. "]"
|
||||||
return form
|
return form
|
||||||
end
|
end
|
||||||
|
@ -949,6 +979,11 @@ minetest.register_entity("basic_robot:robot",{
|
||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if data.object and data.object~=self.object then -- is there another one already?
|
||||||
|
self.object:remove();
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
self.owner = data.owner;
|
self.owner = data.owner;
|
||||||
self.authlevel = data.authlevel;
|
self.authlevel = data.authlevel;
|
||||||
|
|
||||||
|
@ -1011,7 +1046,7 @@ minetest.register_entity("basic_robot:robot",{
|
||||||
minetest.set_node(pos, {name = "air"});
|
minetest.set_node(pos, {name = "air"});
|
||||||
--local privs = core.get_player_privs(self.owner);privs.interact = false;
|
--local privs = core.get_player_privs(self.owner);privs.interact = false;
|
||||||
--core.set_player_privs(self.owner, privs); minetest.auth_reload()
|
--core.set_player_privs(self.owner, privs); minetest.auth_reload()
|
||||||
minetest.kick_player(self.owner, "#basic_robot: stack overflow")
|
minetest.kick_player(self.owner, "#basic_robot: stack overflow at " .. pos.x.. " " .. pos.y .. " " .. pos.z)
|
||||||
end
|
end
|
||||||
|
|
||||||
local name = self.name;
|
local name = self.name;
|
||||||
|
@ -1038,8 +1073,6 @@ minetest.register_entity("basic_robot:robot",{
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local spawn_robot = function(pos,node,ttl)
|
local spawn_robot = function(pos,node,ttl)
|
||||||
if type(ttl) ~= "number" then ttl = 0 end
|
if type(ttl) ~= "number" then ttl = 0 end
|
||||||
if ttl<0 then return end
|
if ttl<0 then return end
|
||||||
|
@ -1076,7 +1109,9 @@ local spawn_robot = function(pos,node,ttl)
|
||||||
|
|
||||||
|
|
||||||
if id <= 0 then -- just compile code and run it, no robot entity spawn
|
if id <= 0 then -- just compile code and run it, no robot entity spawn
|
||||||
local codechange = false;
|
local codechange = false; -- was code changed by editing?
|
||||||
|
local poschange = false; -- are we running from different spawner?
|
||||||
|
|
||||||
if meta:get_int("codechange") == 1 then
|
if meta:get_int("codechange") == 1 then
|
||||||
meta:set_int("codechange",0);
|
meta:set_int("codechange",0);
|
||||||
codechange = true;
|
codechange = true;
|
||||||
|
@ -1099,7 +1134,7 @@ local spawn_robot = function(pos,node,ttl)
|
||||||
if not data.obj then
|
if not data.obj then
|
||||||
--create virtual robot that reports position and other properties
|
--create virtual robot that reports position and other properties
|
||||||
local obj = {};
|
local obj = {};
|
||||||
function obj:getpos() return {x=pos.x,y=pos.y,z=pos.z} end
|
function obj:get_pos() return {x=pos.x,y=pos.y,z=pos.z} end
|
||||||
function obj:getyaw() return 0 end
|
function obj:getyaw() return 0 end
|
||||||
function obj:get_luaentity()
|
function obj:get_luaentity()
|
||||||
local luaent = {};
|
local luaent = {};
|
||||||
|
@ -1113,8 +1148,10 @@ local spawn_robot = function(pos,node,ttl)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local hashpos = minetest.hash_node_position(pos)
|
||||||
|
if data.lastpos~= hashpos then data.lastpos = hashpos; poschange = true end
|
||||||
|
|
||||||
if not data.bytecode then
|
if not data.bytecode or poschange then -- compile again
|
||||||
local script = meta:get_string("code");
|
local script = meta:get_string("code");
|
||||||
|
|
||||||
if data.authlevel<3 then -- not admin
|
if data.authlevel<3 then -- not admin
|
||||||
|
@ -1181,7 +1218,6 @@ local spawn_robot = function(pos,node,ttl)
|
||||||
if data == nil then
|
if data == nil then
|
||||||
basic_robot.data[name] = {};
|
basic_robot.data[name] = {};
|
||||||
data = basic_robot.data[name];
|
data = basic_robot.data[name];
|
||||||
--data.rom = {};
|
|
||||||
end
|
end
|
||||||
|
|
||||||
data.owner = owner;
|
data.owner = owner;
|
||||||
|
@ -1280,6 +1316,8 @@ local on_receive_robot_form = function(pos, formname, fields, sender)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
minetest.chat_send_player(name,"#ROBOT: code saved " .. os.date("%H:%M:%S"))
|
||||||
meta:set_string("code", code); meta:set_int("codechange",1)
|
meta:set_string("code", code); meta:set_int("codechange",1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1509,9 +1547,9 @@ minetest.register_on_player_receive_fields(
|
||||||
local title,text = basic_robot.commands.read_book(itemstack);
|
local title,text = basic_robot.commands.read_book(itemstack);
|
||||||
title = title or ""; text = text or "";
|
title = title or ""; text = text or "";
|
||||||
local dtitle = minetest.formspec_escape(title);
|
local dtitle = minetest.formspec_escape(title);
|
||||||
local form = "size [8,8] textarea[0.,0.;8.75,8.5;book; TITLE : " .. minetest.formspec_escape(title) .. ";" ..
|
local form = "size [8,8] textarea[0.,0.15;8.75,8.35;book; TITLE : " .. minetest.formspec_escape(title) .. ";" ..
|
||||||
minetest.formspec_escape(text) .. "] button_exit[-0.25,7.5;1.25,1;OK;SAVE] "..
|
minetest.formspec_escape(text) .. "] button_exit[-0.25,7.5;1.25,1;OK;SAVE] "..
|
||||||
"button_exit[1.,7.5;2.75,1;LOAD;USE AS PROGRAM] field[4,8;4.5,0.5;title;title;"..dtitle.."]";
|
"button_exit[0.9,7.5;3,1;LOAD;USE AS PROGRAM] field[4,8;4.5,0.5;title;title;"..dtitle.."]";
|
||||||
minetest.show_formspec(player:get_player_name(), "robot_book_".. sel.. ":".. minetest.pos_to_string(libpos), form);
|
minetest.show_formspec(player:get_player_name(), "robot_book_".. sel.. ":".. minetest.pos_to_string(libpos), form);
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -1662,9 +1700,11 @@ minetest.register_node("basic_robot:spawner", {
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
param1=1,
|
param1=1,
|
||||||
walkable = true,
|
walkable = true,
|
||||||
alpha = 150,
|
|
||||||
after_place_node = function(pos, placer)
|
after_place_node = function(pos, placer)
|
||||||
local meta = minetest.env:get_meta(pos)
|
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
--local meta = minetest.env:get_meta(pos) -- THIS WORKS, DOES CHANGING THIS CAUSE META PROBLEM?
|
||||||
local owner = placer:get_player_name();
|
local owner = placer:get_player_name();
|
||||||
meta:set_string("owner", owner);
|
meta:set_string("owner", owner);
|
||||||
|
|
||||||
|
@ -1681,11 +1721,38 @@ minetest.register_node("basic_robot:spawner", {
|
||||||
meta:set_string("infotext", "robot spawner (owned by ".. placer:get_player_name() .. ")")
|
meta:set_string("infotext", "robot spawner (owned by ".. placer:get_player_name() .. ")")
|
||||||
meta:set_string("libpos",pos.x .. " " .. pos.y .. " " .. pos.z)
|
meta:set_string("libpos",pos.x .. " " .. pos.y .. " " .. pos.z)
|
||||||
|
|
||||||
|
local inv = meta:get_inventory(); -- spawner inventory
|
||||||
|
inv:set_size("main",32);
|
||||||
|
inv:set_size("library",16); --4*4
|
||||||
|
|
||||||
robot_spawner_update_form(pos);
|
robot_spawner_update_form(pos);
|
||||||
|
--[[
|
||||||
|
local meta = minetest:get_meta(pos)
|
||||||
|
local owner = placer:get_player_name();
|
||||||
|
meta:set_string("owner", owner);
|
||||||
|
|
||||||
|
local authlevel = get_authlevel(placer:get_player_name());
|
||||||
|
|
||||||
|
meta:set_int("authlevel",authlevel)
|
||||||
|
local sec_hash = minetest.get_password_hash("",authlevel .. owner .. basic_robot.password) -- 'digitally sign' authlevel using password
|
||||||
|
meta:set_string("sec_hash", sec_hash);
|
||||||
|
|
||||||
|
meta:set_string("code","");
|
||||||
|
meta:set_int("id",1); -- initial robot id
|
||||||
|
meta:set_string("name", placer:get_player_name().."1")
|
||||||
|
|
||||||
|
meta:set_string("infotext", "robot spawner (owned by ".. placer:get_player_name() .. ")")
|
||||||
|
|
||||||
|
--WTF: here it reads correct meta but later there is none!!
|
||||||
|
minetest.chat_send_all("D meta info " .. meta:get_string("infotext"))
|
||||||
|
|
||||||
|
meta:set_string("libpos",pos.x .. " " .. pos.y .. " " .. pos.z)
|
||||||
|
|
||||||
local inv = meta:get_inventory(); -- spawner inventory
|
local inv = meta:get_inventory(); -- spawner inventory
|
||||||
inv:set_size("main",32);
|
inv:set_size("main",32);
|
||||||
inv:set_size("library",16); --4*4
|
inv:set_size("library",16); --4*4
|
||||||
|
robot_spawner_update_form(pos);
|
||||||
|
--]]
|
||||||
end,
|
end,
|
||||||
|
|
||||||
mesecons = {effector = {
|
mesecons = {effector = {
|
||||||
|
@ -1694,6 +1761,11 @@ minetest.register_node("basic_robot:spawner", {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
effector = {
|
||||||
|
action_on = spawn_robot,
|
||||||
|
action_off = despawn_robot
|
||||||
|
},
|
||||||
|
|
||||||
on_receive_fields = on_receive_robot_form,
|
on_receive_fields = on_receive_robot_form,
|
||||||
|
|
||||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
|
@ -1718,6 +1790,7 @@ minetest.register_node("basic_robot:spawner", {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
can_dig = function(pos, player)
|
can_dig = function(pos, player)
|
||||||
|
if not player then return end
|
||||||
if minetest.is_protected(pos, player:get_player_name()) then return false end
|
if minetest.is_protected(pos, player:get_player_name()) then return false end
|
||||||
local meta = minetest.get_meta(pos);
|
local meta = minetest.get_meta(pos);
|
||||||
if not meta:get_inventory():is_empty("main") or not meta:get_inventory():is_empty("library") then return false end
|
if not meta:get_inventory():is_empty("main") or not meta:get_inventory():is_empty("library") then return false end
|
||||||
|
@ -1749,6 +1822,8 @@ end
|
||||||
|
|
||||||
|
|
||||||
-- remote control
|
-- remote control
|
||||||
|
|
||||||
|
local write_keyevent = basic_robot.commands.write_keyevent;
|
||||||
minetest.register_craftitem("basic_robot:control", {
|
minetest.register_craftitem("basic_robot:control", {
|
||||||
description = "Robot remote control",
|
description = "Robot remote control",
|
||||||
inventory_image = "control.png",
|
inventory_image = "control.png",
|
||||||
|
@ -1783,10 +1858,13 @@ minetest.register_craftitem("basic_robot:control", {
|
||||||
local pos = pointed_thing.under
|
local pos = pointed_thing.under
|
||||||
if not pos then return end
|
if not pos then return end
|
||||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
|
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
|
||||||
local meta = minetest.get_meta(ppos);
|
|
||||||
local name = meta:get_string("name");
|
local hppos = minetest.hash_node_position(ppos)
|
||||||
local data = basic_robot.data[name];
|
local rname = basic_robot.data.punchareas[hppos];
|
||||||
if data then data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = owner, type = 0} end
|
local data = basic_robot.data[rname];
|
||||||
|
if data then
|
||||||
|
write_keyevent(data,pos, owner,0)
|
||||||
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1831,9 +1909,9 @@ minetest.register_craftitem("basic_robot:control", {
|
||||||
minetest.chat_send_player(owner, "#remote control: compile error " .. CompileError )
|
minetest.chat_send_player(owner, "#remote control: compile error " .. CompileError )
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
script = preprocess_code(script,basic_robot.call_limit[data.authlevel+1]);
|
||||||
|
|
||||||
setfenv( ScriptFunc, basic_robot.data[name].sandbox )
|
setfenv( ScriptFunc, basic_robot.data[name].sandbox )
|
||||||
|
|
||||||
local Result, RuntimeError = pcall( ScriptFunc );
|
local Result, RuntimeError = pcall( ScriptFunc );
|
||||||
if RuntimeError then
|
if RuntimeError then
|
||||||
minetest.chat_send_player(owner, "#remote control: run error " .. RuntimeError )
|
minetest.chat_send_player(owner, "#remote control: run error " .. RuntimeError )
|
||||||
|
@ -1873,7 +1951,7 @@ minetest.register_entity(
|
||||||
if (self.oldvel.x~=0 and vel.x==0) or (self.oldvel.y~=0 and vel.y==0) or (self.oldvel.z~=0 and vel.z==0) then -- hit
|
if (self.oldvel.x~=0 and vel.x==0) or (self.oldvel.y~=0 and vel.y==0) or (self.oldvel.z~=0 and vel.z==0) then -- hit
|
||||||
local data = basic_robot.data[self.name];
|
local data = basic_robot.data[self.name];
|
||||||
if data then
|
if data then
|
||||||
data.fire_pos = self.object:getpos();
|
data.fire_pos = self.object:get_pos();
|
||||||
end
|
end
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
|
@ -1888,7 +1966,7 @@ minetest.register_entity(
|
||||||
if not self.state then return nil end
|
if not self.state then return nil end
|
||||||
local data = basic_robot.data[self.name];
|
local data = basic_robot.data[self.name];
|
||||||
if data then
|
if data then
|
||||||
data.fire_pos = self.object:getpos();
|
data.fire_pos = self.object:get_pos();
|
||||||
end
|
end
|
||||||
self.object:remove();
|
self.object:remove();
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
name = basic_robot
|
||||||
|
depends = default
|
||||||
|
optional_depends =
|
||||||
|
description = your ingame robot companion. learn how to program and make games
|
85
robogui.lua
85
robogui.lua
|
@ -105,7 +105,7 @@ minetest.register_on_player_receive_fields(
|
||||||
-- })
|
-- })
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
local help_address = {}; -- array containing current page name for player
|
local help_address = {}; -- table containing current page name for player [name] = {address = ..., sel = ..}
|
||||||
local help_pages = {
|
local help_pages = {
|
||||||
["main"] = {
|
["main"] = {
|
||||||
" === ROBOT HELP - MAIN SCREEN === ","",
|
" === ROBOT HELP - MAIN SCREEN === ","",
|
||||||
|
@ -145,7 +145,8 @@ local help_pages = {
|
||||||
" 7. [TECHNIC FUNCTIONALITY]",
|
" 7. [TECHNIC FUNCTIONALITY]",
|
||||||
" 8. [CRYPTOGRAPHY]",
|
" 8. [CRYPTOGRAPHY]",
|
||||||
" 9. [PUZZLE]",
|
" 9. [PUZZLE]",
|
||||||
" 10.[COROUTINES] - easier alternative to finite state machines",
|
" 10.[COROUTINES AND LIBRARIES AND ROM] - easier alternative to",
|
||||||
|
" finite state machines",
|
||||||
},
|
},
|
||||||
|
|
||||||
["MOVEMENT DIGGING PLACING NODE SENSING"] = {
|
["MOVEMENT DIGGING PLACING NODE SENSING"] = {
|
||||||
|
@ -201,7 +202,7 @@ local help_pages = {
|
||||||
" attack(target) attempts to attack target player if nearby",
|
" attack(target) attempts to attack target player if nearby",
|
||||||
" grab(target) attempt to grab target player if nearby and returns",
|
" grab(target) attempt to grab target player if nearby and returns",
|
||||||
" true if succesful",
|
" true if succesful",
|
||||||
" player.getpos(name) return position of player, player.connected()",
|
" player.get_pos(name) return position of player, player.connected()",
|
||||||
" returns list of connected players names",
|
" returns list of connected players names",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -244,12 +245,14 @@ local help_pages = {
|
||||||
["KEYBOARD AND USER INTERACTIONS"] = {
|
["KEYBOARD AND USER INTERACTIONS"] = {
|
||||||
"back to [Commands reference]",
|
"back to [Commands reference]",
|
||||||
"KEYBOARD","",
|
"KEYBOARD","",
|
||||||
" EVENTS : place spawner at coordinates (r*i,2*r*j+1,r*k) to monitor",
|
" EVENTS : first attach listener to robot with self.listen_punch",
|
||||||
" events. value of r is ".. basic_robot.radius,
|
" self.listen_punch(pos,is_remove) robot will listen to punch events in ",
|
||||||
|
" ".. basic_robot.radius .. " sized chunk containing position",
|
||||||
|
" pos = {x=.., y=.., z=..}. if is_remove==true then remove listener",
|
||||||
" keyboard.get() returns table {x=..,y=..,z=..,puncher = .. , type = .. }",
|
" keyboard.get() returns table {x=..,y=..,z=..,puncher = .. , type = .. }",
|
||||||
" for keyboard event",
|
" if there was keyboard event, nil if there was none",
|
||||||
" keyboard.set(pos,type) set key at pos of type 0=air,1-6,7-15,16-271,",
|
" keyboard.set(pos,type) set key as a node in world at pos of type",
|
||||||
" limited to range 10 around spawner",
|
" 0=air,1-6,7-15,16-271, limited to range 10 around spawner",
|
||||||
" keyboard.read(pos) return node name at pos",
|
" keyboard.read(pos) return node name at pos",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -272,6 +275,9 @@ local help_pages = {
|
||||||
" materials",
|
" materials",
|
||||||
" compress(input) - requires upgrades - energy intensive process",
|
" compress(input) - requires upgrades - energy intensive process",
|
||||||
" transfer_power(amount,target_robot_name)",
|
" transfer_power(amount,target_robot_name)",
|
||||||
|
" dig_seed.direction digs seed node and transforms it to seed book",
|
||||||
|
" place_seed.direction(seedbookname) takes oldest seed from seed book",
|
||||||
|
" and plants it",
|
||||||
},
|
},
|
||||||
|
|
||||||
["CRYPTOGRAPHY"] = {
|
["CRYPTOGRAPHY"] = {
|
||||||
|
@ -307,17 +313,29 @@ local help_pages = {
|
||||||
" add_particle(def)"
|
" add_particle(def)"
|
||||||
},
|
},
|
||||||
|
|
||||||
["COROUTINES"] = {
|
["COROUTINES AND LIBRARIES AND ROM"] = {
|
||||||
"back to [Commands reference]",
|
"back to [Commands reference]",
|
||||||
"COROUTINES","",
|
"COROUTINES","",
|
||||||
"robot can run code using lua coroutines. To enable this mode just put the word",
|
"robot can run code using lua coroutines. To enable this mode just put",
|
||||||
"coroutine in the first 32 characters of your program. Example: ", "",
|
"the word coroutine in the first 32 characters of your program. Example:",
|
||||||
" --testing program for coroutine",
|
" --testing program for coroutine",
|
||||||
" for i = 1,5 do ",
|
" for i = 1,5 do ",
|
||||||
" say(i); dig.forward(); move.forward()",
|
" say(i); dig.forward(); move.forward()",
|
||||||
" pause()",
|
" pause()",
|
||||||
" end",
|
" end",
|
||||||
|
"pause(amount) temporarily stops if available operations are less than",
|
||||||
|
" amount","",
|
||||||
|
"LIBRARIES","",
|
||||||
|
"you can define functions for robot in another robot and re-use them later.",
|
||||||
|
"for example do: rom.lib_src = \"f1 = function(x) return 2*x end\" and later",
|
||||||
|
"in another robot recreate function with: ",
|
||||||
|
"if not f1 then code.run(rom.lib_src) end ",
|
||||||
|
"self.label(f1(1))","",
|
||||||
|
"ROM","",
|
||||||
|
"all robots by a player share same \"rom\" variable that can be used to",
|
||||||
|
"store more persistent data like numbers, strings or tables",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -328,15 +346,18 @@ end
|
||||||
|
|
||||||
|
|
||||||
local robot_show_help = function(pname) --formname: robot_help
|
local robot_show_help = function(pname) --formname: robot_help
|
||||||
local address = help_address[pname] or "main";
|
local data = help_address[pname];
|
||||||
|
if not data then help_address[pname] = {address = "main", sel = 1} data = help_address[pname] end
|
||||||
|
local address = data.address;
|
||||||
|
|
||||||
--minetest.chat_send_all("D DISPLAY HELP for ".. address )
|
--minetest.chat_send_all("D DISPLAY HELP for ".. address )
|
||||||
local pages = help_pages[address];
|
local pages = help_pages[address];
|
||||||
|
if not pages then return end
|
||||||
|
|
||||||
local content = table.concat(pages,",")
|
local content = table.concat(pages,",")
|
||||||
local size = 9; local vsize = 8.75;
|
local size = 9.5; local vsize = 8.75;
|
||||||
|
|
||||||
local form = "size[" .. size .. "," .. size .. "] textlist[-0.25,-0.25;" .. (size+1) .. "," .. (vsize+1) .. ";wiki;".. content .. ";1]";
|
local form = "size[" .. size .. "," .. size .. "] button[-0.25,".. size-0.15 ..";1,0.5;go;go] textlist[-0.25,-0.25;" .. (size+1) .. "," .. (vsize+0.25) .. ";wiki;".. content .. ";1]";
|
||||||
--minetest.chat_send_all("D " .. form)
|
--minetest.chat_send_all("D " .. form)
|
||||||
minetest.show_formspec(pname, "robot_help", form)
|
minetest.show_formspec(pname, "robot_help", form)
|
||||||
return
|
return
|
||||||
|
@ -346,19 +367,31 @@ end
|
||||||
robogui["robot_help"] = {
|
robogui["robot_help"] = {
|
||||||
response = function(player,formname,fields)
|
response = function(player,formname,fields)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
|
|
||||||
local fsel = fields.wiki;
|
local fsel = fields.wiki;
|
||||||
if fsel and string.sub(fsel,1,3) == "DCL" then
|
--minetest.chat_send_all("D " .. minetest.serialize(fields))
|
||||||
local sel = tonumber(string.sub(fsel,5)) or 1; -- selected line
|
|
||||||
local address = help_address[name] or "main";
|
|
||||||
local pages = help_pages[address];
|
local go = false;
|
||||||
|
if fsel then
|
||||||
local link = string.match(pages[sel] or "", "\\%[([%w%s]+)\\%]")
|
help_address[name].sel = tonumber(string.sub(fsel or "",5)) or 1
|
||||||
if help_pages[link] then
|
if string.sub(fsel,1,3) == "CHG" then return end -- just select topic, dont go there
|
||||||
help_address[name] = link;
|
go = true -- we want to go to selected page
|
||||||
robot_show_help(name)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if fields.go then go = true end
|
||||||
|
if not go then return end
|
||||||
|
|
||||||
|
local sel = help_address[name].sel; -- selected line
|
||||||
|
local address = help_address[name].address;
|
||||||
|
local pages = help_pages[address];
|
||||||
|
|
||||||
|
local link = string.match(pages[sel] or "", "\\%[([%w%s]+)\\%]")
|
||||||
|
if help_pages[link] then
|
||||||
|
help_address[name].address = link
|
||||||
|
help_address[name].sel = 1
|
||||||
|
robot_show_help(name)
|
||||||
|
end
|
||||||
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
getForm = function(player_name)
|
getForm = function(player_name)
|
||||||
|
|
|
@ -1,9 +1,33 @@
|
||||||
|
--battle bots
|
||||||
|
|
||||||
|
-- example program for team 4, other team is 5. each of players writes program and puts it in book,
|
||||||
|
-- book 1 program for team 4, book 2 program for team 5
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
DEMO PROGRAM: just move all your bots in direction 1,0 and attack while moving
|
||||||
|
|
||||||
|
for i = 1,#bots[TYPE] do -- move all bots of team 4 in direction {x=1,z=0}
|
||||||
|
if read_bots(TYPE,i) then -- is bot alive?
|
||||||
|
move_bot(i,1,0)
|
||||||
|
attack_bot(i,1,0) -- try to attack in move direction
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
if not s then
|
if not s then
|
||||||
-- init
|
-- init
|
||||||
bots = {[4] = {}, [5] = {}}; -- [type] = {{1,1,10}, {3,2,10}}; -- {x,y,hp}
|
bots = {[4] = {}, [5] = {}}; -- [type] = {{1,1,10}, {3,2,10}}; -- {x,y,hp}
|
||||||
arena = {}; --[x][z] = {type, idx}
|
arena = {}; --[x][z] = {type, idx}
|
||||||
for i = -10,10 do arena[i] = {} for j=-10,10 do arena[i][j] = {0,0} end end
|
|
||||||
centerpos = self.spawnpos(); centerpos.y = centerpos.y+2
|
centerpos = self.spawnpos(); centerpos.y = centerpos.y+2
|
||||||
|
for i = -10,10 do arena[i] = {} for j=-10,10 do
|
||||||
|
arena[i][j] = {0,0}
|
||||||
|
keyboard.set({x=centerpos.x+i,y=centerpos.y-1,z=centerpos.z+j},1) -- build arena
|
||||||
|
keyboard.set({x=centerpos.x+i,y=centerpos.y,z=centerpos.z+j},0)
|
||||||
|
end end
|
||||||
|
|
||||||
TYPE = 4; -- 4,5 defines which bots are on the move/attack
|
TYPE = 4; -- 4,5 defines which bots are on the move/attack
|
||||||
DIR = 1
|
DIR = 1
|
||||||
s=0
|
s=0
|
||||||
|
@ -67,7 +91,7 @@ prog1, _ = _G.loadstring( script1 ); prog2, _ = _G.loadstring( script2 );
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if t%10 == 0 then
|
if t%10 == 0 then -- spawn new bot for each time every 10 seconds!
|
||||||
spawn_bot(0,-10,4)
|
spawn_bot(0,-10,4)
|
||||||
spawn_bot(0,10,5)
|
spawn_bot(0,10,5)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
-- COPY PASTE ROBOT by rnd: c1 c2 r = markers, c = copy p = paste
|
-- 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
|
||||||
|
|
||||||
if not paste then
|
if not paste then
|
||||||
_G.minetest.forceload_block(self.pos(),true)
|
_G.minetest.forceload_block(self.pos(),true)
|
||||||
|
@ -18,36 +25,38 @@ if not paste then
|
||||||
pos = pos,
|
pos = pos,
|
||||||
expirationtime = 10,
|
expirationtime = 10,
|
||||||
velocity = {x=0, y=0,z=0},
|
velocity = {x=0, y=0,z=0},
|
||||||
size = 18,
|
size = 9,
|
||||||
texture = label..".png",
|
texture = label..".png",
|
||||||
acceleration = {x=0,y=0,z=0},
|
acceleration = {x=0,y=0,z=0},
|
||||||
collisiondetection = true,
|
|
||||||
collision_removal = true,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self.listen(1)
|
self.listen(1)
|
||||||
self.label("COPY-PASTE MASTER v1.2 gold edition. commands: c1 c2 r c p")
|
self.label("")
|
||||||
|
-- self.label("WorldEdit Bot\ncommands: c1 c2 r c p s rotz")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
speaker, msg = self.listen_msg()
|
speaker, msg = self.listen_msg()
|
||||||
|
|
||||||
if speaker == "rnd" then
|
if speaker == "_" or speaker == "test" 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 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);
|
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 p.y<0 then p.y = p.y +1 end -- needed cause of minetest bug
|
||||||
if msg == "c1" then
|
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)
|
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,"099") -- c
|
display_marker(p,"099") -- c
|
||||||
elseif msg == "c2" then
|
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)
|
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,"099") -- c
|
display_marker(p,"099") -- c
|
||||||
elseif msg == "r" then
|
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)
|
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,"114") -- r
|
display_marker(p,"114") -- r
|
||||||
elseif msg == "c" then -- copy
|
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 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 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 = {};
|
local count = 0; data = {};
|
||||||
|
@ -65,7 +74,7 @@ if speaker == "rnd" then
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
say(count .. " nodes copied ");
|
say(count .. " nodes copied ");
|
||||||
elseif msg == "p" then -- paste
|
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 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 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;
|
local count = 0; p.x = p.x-paste.ref.x; p.y = p.y-paste.ref.y; p.z = p.z-paste.ref.z;
|
||||||
|
@ -85,6 +94,82 @@ if speaker == "rnd" then
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
say(count .. " nodes pasted ");
|
say(count .. " nodes pasted ",speaker);
|
||||||
|
elseif args[1] == "s" then -- set node
|
||||||
|
local nodename = args[2] or "air"
|
||||||
|
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
|
||||||
|
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] == "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
|
||||||
end
|
end
|
|
@ -0,0 +1,141 @@
|
||||||
|
-- 2d rubik cube slide puzzle by rnd in 40 mins
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
m=4;
|
||||||
|
n=m;
|
||||||
|
data = {};
|
||||||
|
|
||||||
|
nodelist = {};
|
||||||
|
for i = 1,m do
|
||||||
|
for j = 1,n do
|
||||||
|
nodelist[(i-1)*n+j] = "basic_robot:button_"..(64+(n-j+1-1)*n+i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1,m do
|
||||||
|
data[i] = {};local dat = data[i];
|
||||||
|
for j = 1,n do
|
||||||
|
dat[j] = (i-1)*n+j;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
spos = self.spawnpos(); spos.x=spos.x+1; spos.z=spos.z+1
|
||||||
|
|
||||||
|
|
||||||
|
render = function(t,mode) -- mode 1:row, 2: coloumn
|
||||||
|
if not mode then
|
||||||
|
for i=1,m do
|
||||||
|
for j = 1,n do
|
||||||
|
minetest.swap_node({x=spos.x+i,y=spos.y,z=spos.z+j},{name = nodelist[data[i][j]]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if mode == 1 then -- row only
|
||||||
|
for i=1,m do
|
||||||
|
minetest.swap_node({x=spos.x+i,y=spos.y,z=spos.z+t},{name = nodelist[data[i][t]]})
|
||||||
|
end
|
||||||
|
return
|
||||||
|
else -- coloumn only
|
||||||
|
for j=1,n do
|
||||||
|
minetest.swap_node({x=spos.x+t,y=spos.y,z=spos.z+j},{name = nodelist[data[t][j]]})
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pnames = find_player(4);
|
||||||
|
if not pnames then self.remove() end
|
||||||
|
player = minetest.get_player_by_name(pnames[1]);
|
||||||
|
|
||||||
|
|
||||||
|
check_rot_dir = function()
|
||||||
|
local vdir = player:get_look_dir()
|
||||||
|
local mode = 0;
|
||||||
|
if math.abs(vdir.x)<math.abs(vdir.z) then
|
||||||
|
if vdir.z>0 then
|
||||||
|
mode = 2
|
||||||
|
else
|
||||||
|
mode = -2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if vdir.x>0 then
|
||||||
|
mode = 1
|
||||||
|
else
|
||||||
|
mode = -1
|
||||||
|
end
|
||||||
|
end -- rotate in z dir
|
||||||
|
return mode
|
||||||
|
end
|
||||||
|
|
||||||
|
rotx = function(col,dir)
|
||||||
|
if dir > 0 then
|
||||||
|
local tmp = data[1][col]
|
||||||
|
for i = 1,m-1 do
|
||||||
|
data[i][col] = data[i+1][col]
|
||||||
|
end
|
||||||
|
data[m][col] = tmp
|
||||||
|
else
|
||||||
|
local tmp = data[m][col]
|
||||||
|
for i = m,2,-1 do
|
||||||
|
data[i][col] = data[i-1][col]
|
||||||
|
end
|
||||||
|
data[1][col] = tmp
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
rotz = function(row,dir)
|
||||||
|
if dir > 0 then
|
||||||
|
local tmp = data[row][1]
|
||||||
|
for j = 1,n-1 do
|
||||||
|
data[row][j] = data[row][j+1]
|
||||||
|
end
|
||||||
|
data[row][m] = tmp
|
||||||
|
else
|
||||||
|
local tmp = data[row][n]
|
||||||
|
for j = n,2,-1 do
|
||||||
|
data[row][j] = data[row][j-1]
|
||||||
|
end
|
||||||
|
data[row][1] = tmp
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
rndshuffle = function(steps)
|
||||||
|
for step = 1,steps do
|
||||||
|
local mode = math.random(4);
|
||||||
|
if mode <=2 then
|
||||||
|
local z = math.random(m);
|
||||||
|
if mode == 2 then mode = -1 end
|
||||||
|
rotx(z,mode)
|
||||||
|
else
|
||||||
|
local x = math.random(n);
|
||||||
|
if mode == 3 then mode = -2 else mode = 2 end
|
||||||
|
rotz(x,mode)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.listen_punch(self.pos())
|
||||||
|
|
||||||
|
self.label("try to get all letters sorted started with A top left")
|
||||||
|
rndshuffle(m*n)
|
||||||
|
render()
|
||||||
|
end
|
||||||
|
|
||||||
|
event = keyboard.get()
|
||||||
|
if event then
|
||||||
|
--self.label(serialize(event))
|
||||||
|
local x = event.x-spos.x;
|
||||||
|
local z = event.z-spos.z;
|
||||||
|
local mode = check_rot_dir()
|
||||||
|
if x>0 and x<=m and z>0 and z<=n then
|
||||||
|
if math.abs(mode) == 1 then
|
||||||
|
rotx(z,-mode)
|
||||||
|
render(z,1)
|
||||||
|
else
|
||||||
|
rotz(x,-mode)
|
||||||
|
render(x,2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,3 +1,5 @@
|
||||||
|
-- battle minesweeper, 2 player
|
||||||
|
|
||||||
if not data then
|
if not data then
|
||||||
m=10;n=10;
|
m=10;n=10;
|
||||||
players = {};
|
players = {};
|
||||||
|
@ -13,6 +15,7 @@ if not data then
|
||||||
state = SIGNUP
|
state = SIGNUP
|
||||||
|
|
||||||
t0 = _G.minetest.get_gametime();spawnpos = self.spawnpos() -- place mines
|
t0 = _G.minetest.get_gametime();spawnpos = self.spawnpos() -- place mines
|
||||||
|
self.listen_punch(self.pos()); -- attach punch listener
|
||||||
data = {};
|
data = {};
|
||||||
|
|
||||||
init_game = function()
|
init_game = function()
|
||||||
|
|
|
@ -1,208 +1,211 @@
|
||||||
--black box by rnd, 03/18/2017
|
--black box by rnd, 03/18/2017
|
||||||
--https://en.wikipedia.org/wiki/Black_Box_(game)
|
--https://en.wikipedia.org/wiki/Black_Box_(game)
|
||||||
|
|
||||||
if not data then
|
if not data then
|
||||||
m=16;n=16;
|
-- novice: 8x8, 4
|
||||||
atoms = 32
|
m=9;n=9;
|
||||||
attempts = 1;turn = 0;
|
atoms = 16
|
||||||
spawnpos = self.spawnpos(); spawnpos.x = spawnpos.x-m/2; spawnpos.y = spawnpos.y+2; spawnpos.z = spawnpos.z-n/2
|
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
|
local players = find_player(5,spawnpos);
|
||||||
|
if not player then self.remove() else pname = players[1] end
|
||||||
self.spam(1);t0 = _G.minetest.get_gametime();
|
|
||||||
data = {};
|
self.listen_punch(self.pos()) -- attach punch listener
|
||||||
for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end
|
self.spam(1);t0 = _G.minetest.get_gametime();
|
||||||
|
data = {};
|
||||||
for i=1,atoms do -- put in atoms randomly
|
for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end
|
||||||
data[math.random(m)][math.random(n)] = 1
|
|
||||||
end
|
for i=1,atoms do -- put in atoms randomly
|
||||||
|
data[math.random(m)][math.random(n)] = 1
|
||||||
atoms = 0
|
end
|
||||||
for i = 1,m do for j = 1,n do if data[i][j]==1 then atoms = atoms + 1 end end end
|
|
||||||
|
atoms = 0
|
||||||
render_board = function(mode) -- mode 0 : render without solution, 1: render solution
|
for i = 1,m do for j = 1,n do if data[i][j]==1 then atoms = atoms + 1 end end end
|
||||||
for i = 1,m do for j = 1,n do -- render game
|
|
||||||
if mode == 0 or data[i][j] == 0 then
|
render_board = function(mode) -- mode 0 : render without solution, 1: render solution
|
||||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
|
for i = 1,m do for j = 1,n do -- render game
|
||||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2)
|
if mode == 0 or data[i][j] == 0 then
|
||||||
end
|
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:buttongray" then
|
||||||
else
|
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},15) -- 2 gray
|
||||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},3)
|
end
|
||||||
end
|
else
|
||||||
end end
|
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},4) --on 3
|
||||||
end
|
end
|
||||||
|
end end
|
||||||
get_dirl = function(dir)
|
end
|
||||||
local dirl; -- direction left
|
|
||||||
if dir[1] > 0.5 then dirl = {0,-1}
|
get_dirl = function(dir)
|
||||||
elseif dir[1] < -0.5 then dirl = {0,1}
|
local dirl; -- direction left
|
||||||
elseif dir[2] > 0.5 then dirl = {-1,0}
|
if dir[1] > 0.5 then dirl = {0,-1}
|
||||||
elseif dir[2] < -0.5 then dirl = {1,0}
|
elseif dir[1] < -0.5 then dirl = {0,1}
|
||||||
end
|
elseif dir[2] > 0.5 then dirl = {-1,0}
|
||||||
return dirl
|
elseif dir[2] < -0.5 then dirl = {1,0}
|
||||||
end
|
end
|
||||||
|
return dirl
|
||||||
read_pos = function(x,z)
|
end
|
||||||
if x<1 or x>m or z<1 or z>n then return nil end
|
|
||||||
return data[x][z]
|
read_pos = function(x,z)
|
||||||
end
|
if x<1 or x>m or z<1 or z>n then return nil end
|
||||||
|
return data[x][z]
|
||||||
newdir = function(x,z,dir) -- where will ray go next
|
end
|
||||||
local retdir = {dir[1],dir[2]};
|
|
||||||
local xf = x+dir[1]; local zf = z+dir[2] -- forward
|
newdir = function(x,z,dir) -- where will ray go next
|
||||||
local dirl = get_dirl(dir)
|
local retdir = {dir[1],dir[2]};
|
||||||
|
local xf = x+dir[1]; local zf = z+dir[2] -- forward
|
||||||
local nodef = read_pos(xf,zf)
|
local dirl = get_dirl(dir)
|
||||||
local nodel = read_pos(xf + dirl[1],zf + dirl[2])
|
|
||||||
local noder = read_pos(xf - dirl[1],zf - dirl[2])
|
local nodef = read_pos(xf,zf)
|
||||||
if nodef == 1 then
|
local nodel = read_pos(xf + dirl[1],zf + dirl[2])
|
||||||
retdir = {0,0} -- ray hit something
|
local noder = read_pos(xf - dirl[1],zf - dirl[2])
|
||||||
elseif nodel == 1 and noder ~= 1 then
|
if nodef == 1 then
|
||||||
retdir = {-dirl[1],-dirl[2]}
|
retdir = {0,0} -- ray hit something
|
||||||
elseif nodel ~= 1 and noder == 1 then
|
elseif nodel == 1 and noder ~= 1 then
|
||||||
retdir = {dirl[1],dirl[2]}
|
retdir = {-dirl[1],-dirl[2]}
|
||||||
elseif nodel == 1 and noder == 1 then
|
elseif nodel ~= 1 and noder == 1 then
|
||||||
retdir = {-dir[1],-dir[2]}
|
retdir = {dirl[1],dirl[2]}
|
||||||
end
|
elseif nodel == 1 and noder == 1 then
|
||||||
return retdir
|
retdir = {-dir[1],-dir[2]}
|
||||||
end
|
end
|
||||||
|
return retdir
|
||||||
shootray = function(x,z,dir)
|
end
|
||||||
--say("ray starts " .. x .. " " .. z .. " dir " .. dir[1] .. " " .. dir[2])
|
|
||||||
local xp = x; local zp = z;
|
shootray = function(x,z,dir)
|
||||||
local dirp = {dir[1],dir[2]};
|
--say("ray starts " .. x .. " " .. z .. " dir " .. dir[1] .. " " .. dir[2])
|
||||||
local maxstep = m*n;
|
local xp = x; local zp = z;
|
||||||
|
local dirp = {dir[1],dir[2]};
|
||||||
for i = 1,maxstep do
|
local maxstep = m*n;
|
||||||
dirp = newdir(xp,zp,dirp);
|
|
||||||
if dirp[1]==0 and dirp[2]==0 then return -i end -- hit
|
for i = 1,maxstep do
|
||||||
xp=xp+dirp[1];zp=zp+dirp[2];
|
dirp = newdir(xp,zp,dirp);
|
||||||
if xp<1 or xp>m or zp<1 or zp>n then return i,{xp,zp} end -- out
|
if dirp[1]==0 and dirp[2]==0 then return -i end -- hit
|
||||||
end
|
xp=xp+dirp[1];zp=zp+dirp[2];
|
||||||
return 0 -- hit
|
if xp<1 or xp>m or zp<1 or zp>n then return i,{xp,zp} end -- out
|
||||||
end
|
end
|
||||||
|
return 0 -- hit
|
||||||
count = 0; -- how many letters were used up
|
end
|
||||||
border_start_ray = function(x,z)
|
|
||||||
local rdir
|
count = 0; -- how many letters were used up
|
||||||
if x==0 then rdir = {1,0}
|
border_start_ray = function(x,z)
|
||||||
elseif x == m+1 then rdir = {-1,0}
|
local rdir
|
||||||
elseif z == 0 then rdir = {0,1}
|
if x==0 then rdir = {1,0}
|
||||||
elseif z == n+1 then rdir = {0,-1}
|
elseif x == m+1 then rdir = {-1,0}
|
||||||
end
|
elseif z == 0 then rdir = {0,1}
|
||||||
if rdir then
|
elseif z == n+1 then rdir = {0,-1}
|
||||||
local result,out = shootray(x,z,rdir);
|
end
|
||||||
if result >= 0 then
|
if rdir then
|
||||||
|
local result,out = shootray(x,z,rdir);
|
||||||
if out then
|
if result >= 0 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);
|
if out then
|
||||||
else
|
if out[1]==x and out[2]==z then -- got back where it originated, reflection
|
||||||
if result<=1 then
|
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},1);
|
||||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},6); -- immediate bounce off
|
else
|
||||||
else
|
if result<=1 then
|
||||||
local nodename = "basic_robot:button_"..(65+count);
|
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},6); -- immediate bounce off
|
||||||
_G.minetest.set_node(
|
else
|
||||||
{x=spawnpos.x+out[1],y=spawnpos.y+1,z=spawnpos.z+out[2]},
|
local nodename = "basic_robot:button_"..(65+count);
|
||||||
{name = nodename, param2 = 1})
|
_G.minetest.set_node(
|
||||||
_G.minetest.set_node(
|
{x=spawnpos.x+out[1],y=spawnpos.y+1,z=spawnpos.z+out[2]},
|
||||||
{x=spawnpos.x+x,y=spawnpos.y+1,z=spawnpos.z+z},
|
{name = nodename, param2 = 1})
|
||||||
{name = nodename, param2 = 1})
|
_G.minetest.set_node(
|
||||||
count = count + 1;
|
{x=spawnpos.x+x,y=spawnpos.y+1,z=spawnpos.z+z},
|
||||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4);
|
{name = nodename, param2 = 1})
|
||||||
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},4);
|
count = count + 1;
|
||||||
end
|
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4);
|
||||||
end
|
keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},4);
|
||||||
end
|
end
|
||||||
elseif result<0 then
|
end
|
||||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3); -- hit
|
end
|
||||||
end
|
elseif result<0 then
|
||||||
end
|
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3); -- hit
|
||||||
end
|
end
|
||||||
|
end
|
||||||
-- initial border loop and marking
|
end
|
||||||
|
|
||||||
--render blue border
|
-- initial border loop and marking
|
||||||
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
|
--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 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,z=spawnpos.z+j},7) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y,z=spawnpos.z+j},7) end
|
||||||
for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y+1,z=spawnpos.z+j},0) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y+1,z=spawnpos.z+j},0) end
|
|
||||||
|
for 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
|
z=0 -- bottom
|
||||||
border_start_ray(x,z)
|
for x = 1,m do
|
||||||
end
|
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" then
|
||||||
end
|
border_start_ray(x,z)
|
||||||
|
end
|
||||||
x=m+1 -- right
|
end
|
||||||
for z = 1,n do
|
|
||||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
|
x=m+1 -- right
|
||||||
border_start_ray(x,z)
|
for z = 1,n do
|
||||||
end
|
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" then
|
||||||
end
|
border_start_ray(x,z)
|
||||||
|
end
|
||||||
z=n+1 -- top
|
end
|
||||||
for x = m,1,-1 do
|
|
||||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
|
z=n+1 -- top
|
||||||
border_start_ray(x,z)
|
for x = m,1,-1 do
|
||||||
end
|
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" then
|
||||||
end
|
border_start_ray(x,z)
|
||||||
|
end
|
||||||
x=0 -- left
|
end
|
||||||
for z = n,1,-1 do
|
|
||||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then
|
x=0 -- left
|
||||||
border_start_ray(x,z)
|
for z = n,1,-1 do
|
||||||
end
|
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonblue" then
|
||||||
end
|
border_start_ray(x,z)
|
||||||
|
end
|
||||||
check_solution = function()
|
end
|
||||||
for i = 1,m do
|
|
||||||
for j = 1,n do
|
check_solution = function()
|
||||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}) == "basic_robot:buttonFF8080" then -- red
|
for i = 1,m do
|
||||||
if data[i][j]~=1 then return false end
|
for j = 1,n do
|
||||||
else
|
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}) == "basic_robot:buttonred" then -- red
|
||||||
if data[i][j]~=0 then return false end
|
if data[i][j]~=1 then return false end
|
||||||
end
|
else
|
||||||
end
|
if data[i][j]~=0 then return false end
|
||||||
end
|
end
|
||||||
return true
|
end
|
||||||
end
|
end
|
||||||
|
return true
|
||||||
--render board
|
end
|
||||||
render_board(0)
|
|
||||||
keyboard.set({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z-1},4)
|
--render board
|
||||||
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z-1},5)
|
render_board(0)
|
||||||
self.label("BLACKBOX with " .. atoms .. " atoms")
|
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)
|
||||||
end
|
self.label("BLACKBOX with " .. atoms .. " atoms")
|
||||||
|
|
||||||
event = keyboard.get();
|
end
|
||||||
if event then
|
|
||||||
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
event = keyboard.get();
|
||||||
if x<1 or x>m or z<1 or z>n then
|
if event then
|
||||||
if event.type == 4 then
|
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
||||||
if check_solution() then
|
--self.label(serialize(event))
|
||||||
say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove()
|
if x<1 or x>m or z<1 or z>n then
|
||||||
else
|
if event.type == 9 then
|
||||||
say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.")
|
if check_solution() then
|
||||||
attempts = attempts+1
|
say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove()
|
||||||
end
|
else
|
||||||
elseif event.type == 5 then
|
say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.")
|
||||||
say("#BLACKBOX : DISPLAYING SOLUTION",pname)
|
attempts = attempts+1
|
||||||
render_board(1)
|
end
|
||||||
self.remove()
|
elseif event.type == 7 then
|
||||||
end
|
say("#BLACKBOX : DISPLAYING SOLUTION",pname)
|
||||||
else -- interior punch
|
render_board(1)
|
||||||
nodetype = 2;
|
self.remove()
|
||||||
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button808080" then
|
end
|
||||||
nodetype = 3
|
else -- interior punch
|
||||||
end
|
nodetype = 4;
|
||||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype);
|
if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:buttonred" then
|
||||||
end
|
nodetype = 15
|
||||||
|
end
|
||||||
end
|
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
::END::
|
::END::
|
|
@ -0,0 +1,121 @@
|
||||||
|
--checkers by rnd, 1.5 hr
|
||||||
|
if not init then init=true
|
||||||
|
spos = self.spawnpos()
|
||||||
|
self.listen_punch(self.pos()) -- attach punch listener
|
||||||
|
sizex = 8; sizez= 8
|
||||||
|
|
||||||
|
gamepieces = {
|
||||||
|
{ -- player1: regular piece, queen
|
||||||
|
"basic_robot:buttonFFFF80","basic_robot:buttonFF8080"
|
||||||
|
},
|
||||||
|
{ -- player2
|
||||||
|
"basic_robot:button80FF80","basic_robot:button8080FF"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
show_mark = function(pos)
|
||||||
|
minetest.add_particle(
|
||||||
|
{
|
||||||
|
pos = pos,
|
||||||
|
expirationtime = 5,
|
||||||
|
velocity = {x=0, y=0,z=0},
|
||||||
|
size = 18,
|
||||||
|
texture = "default_apple.png",
|
||||||
|
acceleration = {x=0,y=0,z=0},
|
||||||
|
collisiondetection = true,
|
||||||
|
collision_removal = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
build_game = function()
|
||||||
|
for i = 1,sizez do
|
||||||
|
for j = 1,2 do
|
||||||
|
minetest.swap_node({x=spos.x+j,y=spos.y,z=spos.z+i},{name = "basic_robot:button_131"})
|
||||||
|
minetest.swap_node({x=spos.x+j,y=spos.y+1,z=spos.z+i},{name = "air"})
|
||||||
|
end
|
||||||
|
minetest.swap_node({x=spos.x+3,y=spos.y,z=spos.z+i},{name = "basic_robot:button_".. (48+i), param2 = 3})
|
||||||
|
end
|
||||||
|
for i = 1,sizex do
|
||||||
|
minetest.swap_node({x=spos.x+3+i,y=spos.y,z=spos.z},{name = "basic_robot:button_".. (64+i)})
|
||||||
|
minetest.swap_node({x=spos.x+3+i,y=spos.y,z=spos.z+sizez+1},{name = "basic_robot:button_".. (64+i), param2 = 2})
|
||||||
|
end
|
||||||
|
local white = true;
|
||||||
|
for i = 1,sizex do
|
||||||
|
for j = 1,sizez do
|
||||||
|
if white then
|
||||||
|
minetest.swap_node({x=spos.x+3+i,y=spos.y,z=spos.z+j},{name = "basic_robot:button_0"})
|
||||||
|
else
|
||||||
|
minetest.swap_node({x=spos.x+3+i,y=spos.y,z=spos.z+j},{name = "basic_robot:button808080"})
|
||||||
|
end
|
||||||
|
white = not white
|
||||||
|
minetest.swap_node({x=spos.x+3+i,y=spos.y+1,z=spos.z+j},{name = "air"})
|
||||||
|
end
|
||||||
|
white = not white
|
||||||
|
end
|
||||||
|
minetest.swap_node({x=spos.x+1,y=spos.y+1,z=spos.z+1},{name = gamepieces[1][1]})
|
||||||
|
minetest.swap_node({x=spos.x+1,y=spos.y+2,z=spos.z+1},{name = gamepieces[1][2]})
|
||||||
|
|
||||||
|
minetest.swap_node({x=spos.x+1,y=spos.y+1,z=spos.z+sizez},{name = gamepieces[2][1]})
|
||||||
|
minetest.swap_node({x=spos.x+1,y=spos.y+2,z=spos.z+sizez},{name = gamepieces[2][2]})
|
||||||
|
|
||||||
|
for i=1,sizex,2 do
|
||||||
|
minetest.swap_node({x=spos.x+4+i,y=spos.y+1,z=spos.z+1},{name = gamepieces[1][1]})
|
||||||
|
minetest.swap_node({x=spos.x+3+i,y=spos.y+1,z=spos.z+2},{name = gamepieces[1][1]})
|
||||||
|
|
||||||
|
minetest.swap_node({x=spos.x+4+i,y=spos.y+1,z=spos.z+sizez-1},{name = gamepieces[2][1]})
|
||||||
|
minetest.swap_node({x=spos.x+3+i,y=spos.y+1,z=spos.z+sizez},{name = gamepieces[2][1]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
msgs = {1} --{idx, msg1, msg2,msg3, msg4, msg5}; -- up to 5 ingame messages displayed
|
||||||
|
add_msg = function(text)
|
||||||
|
local idx = msgs[1] or 1;
|
||||||
|
msgs[idx+1] = text;idx = idx+1; if idx>5 then idx = 1 end msgs[1] = idx
|
||||||
|
end
|
||||||
|
show_msgs = function() -- last message on top
|
||||||
|
local out = {}; local idx = msgs[1] or 1;
|
||||||
|
for i = idx,2,-1 do out[#out+1] = msgs[i] or "" end
|
||||||
|
for i = 6, idx+1,-1 do out[#out+1] = msgs[i] or "" end
|
||||||
|
self.label(table.concat(out,"\n"))
|
||||||
|
end
|
||||||
|
|
||||||
|
build_game()
|
||||||
|
punchpos = nil; -- pos of last punched piece
|
||||||
|
step = 0;
|
||||||
|
self.label("checkers\npunch piece then punch board to move\n"..
|
||||||
|
"RULES\n\n1. move only diagonal and forward. capture pieces by jumping over them.\nif you can capture you must\n"..
|
||||||
|
"2. once you reach end of board you get king. it can move backward too"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
event = keyboard.get()
|
||||||
|
|
||||||
|
|
||||||
|
if event then
|
||||||
|
--self.label(serialize(event))
|
||||||
|
if event.y==spos.y+1 then -- piece was punched to be moved
|
||||||
|
punchpos = {x=event.x,y=event.y,z=event.z}
|
||||||
|
elseif event.y==spos.y and event.x~=spos.x+3 then -- board was punched
|
||||||
|
if not punchpos then return end
|
||||||
|
|
||||||
|
step = step+1
|
||||||
|
local x1 = punchpos.x-spos.x-3; local z1 = punchpos.z-spos.z
|
||||||
|
local x2 = event.x-spos.x-3; local z2 = event.z-spos.z
|
||||||
|
add_msg(minetest.colorize("red","MOVE " .. step) .. ": " .. event.puncher .. " " .. string.char(64+x1) .. z1 .. " to " .. string.char(64+x2) .. z2); show_msgs()
|
||||||
|
|
||||||
|
local nodename = minetest.get_node(punchpos).name
|
||||||
|
minetest.swap_node(punchpos,{name = "air"})
|
||||||
|
show_mark(punchpos)
|
||||||
|
|
||||||
|
-- promotion of pieces to queen when reaching the opposite side
|
||||||
|
if nodename == gamepieces[1][1] and event.z==spos.z+sizez and event.x>spos.x+3 then
|
||||||
|
nodename = gamepieces[1][2]
|
||||||
|
elseif nodename == gamepieces[2][1] and event.z==spos.z+1 and event.x>spos.x+3 then
|
||||||
|
nodename = gamepieces[2][2]
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.swap_node({x=event.x,y=event.y+1,z=event.z},{name = nodename})
|
||||||
|
show_mark({x=event.x,y=event.y+2,z=event.z})
|
||||||
|
punchpos = nil
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,60 +1,67 @@
|
||||||
-- CONNECT, coded in 20 minutes by rnd
|
-- CONNECT, coded in 20 minutes by rnd
|
||||||
if not data then
|
if not data then
|
||||||
m=8;n=8;turn = 0; num = 4;
|
m=10;n=10;turn = 0; num = 4;
|
||||||
self.spam(1);t0 = _G.minetest.get_gametime();
|
|
||||||
spawnpos = self.spawnpos() -- place mines
|
self.spam(1);t0 = _G.minetest.get_gametime();
|
||||||
state = 0; -- 0 signup 1 game
|
spawnpos = self.spawnpos() -- place mines
|
||||||
players = {};
|
self.listen_punch(self.pos()) -- attach punch listener
|
||||||
data = {};
|
state = 0; -- 0 signup 1 game
|
||||||
for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end
|
players = {};
|
||||||
for i = 1,m do for j = 1,n do -- render game
|
data = {};
|
||||||
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
|
for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end
|
||||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2)
|
for i = 1,m do for j = 1,n do -- render game
|
||||||
end
|
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:buttonlight_gray" then
|
||||||
end end
|
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},13)
|
||||||
|
end
|
||||||
get_count_in_dir = function(dir,x,y)
|
end end
|
||||||
local r = num; -- num=4? in a row
|
|
||||||
local snode = data[x][y];local count = 1;
|
get_count_in_dir = function(dir,x,y)
|
||||||
for j = 1,2 do
|
local r = num; -- num=4? in a row
|
||||||
for i = 1,r-1 do
|
local snode = data[x][y];local count = 1;
|
||||||
local x1 = x + dir[1]*i;local y1 = y + dir[2]*i;
|
for j = 1,2 do
|
||||||
if not data[x1] or not data[x1][y1] then break end; if data[x1][y1]~= snode then break end
|
for i = 1,r-1 do
|
||||||
count = count +1
|
local x1 = x + dir[1]*i;local y1 = y + dir[2]*i;
|
||||||
end
|
if not data[x1] or not data[x1][y1] then break end; if data[x1][y1]~= snode then break end
|
||||||
dir[1]=-dir[1];dir[2]=-dir[2];
|
count = count +1
|
||||||
end
|
end
|
||||||
return count
|
dir[1]=-dir[1];dir[2]=-dir[2];
|
||||||
end
|
end
|
||||||
|
return count
|
||||||
get_count = function(x,y)
|
end
|
||||||
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)
|
get_count = function(x,y)
|
||||||
if c2>c1 then c1 = c2 end; if c3>c1 then c1 = c3 end; if c4>c1 then c1 = c4 end
|
local c1 = get_count_in_dir({0,1},x,y); local c2 = get_count_in_dir({1,0},x,y)
|
||||||
return c1
|
local c3 = get_count_in_dir({1,1},x,y); local c4 = get_count_in_dir({1,-1},x,y)
|
||||||
end
|
if c2>c1 then c1 = c2 end; if c3>c1 then c1 = c3 end; if c4>c1 then c1 = c4 end
|
||||||
|
return c1
|
||||||
self.label("CONNECT 4 : GREEN starts play. 2 players punch to join game.")
|
end
|
||||||
end
|
|
||||||
|
self.label("TRY TO GET FIRST " .. num .. " IN A ROW! : GREEN starts play. 2 players punch to join game.")
|
||||||
event = keyboard.get();
|
end
|
||||||
if event then
|
|
||||||
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
event = keyboard.get();
|
||||||
if x<1 or x>m or z<1 or z>n then
|
if event then
|
||||||
elseif event.type == 2 then --if event.type == 2 then
|
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
||||||
if state == 0 then
|
if x<1 or x>m or z<1 or z>n then
|
||||||
if #players<2 then players[#players+1] = event.puncher
|
elseif event.type == 13 then --if event.type == 2 then
|
||||||
else state = 1 end
|
if state == 0 then
|
||||||
if #players==2 then state = 1 end
|
if #players<2 then players[#players+1] = event.puncher -- 1 is green, turn 0 = green
|
||||||
end
|
else state = 1 end
|
||||||
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4+turn);
|
if #players==2 then state = 1 end
|
||||||
data[x][z] = 4+turn;
|
end
|
||||||
if get_count(x,z) == num then say("CONGRATULATIONS! " .. event.puncher .. " has "..num .. " in a row"); self.remove(); goto END end
|
if event.puncher == players[1] then -- green
|
||||||
turn = 1-turn
|
if turn~=0 then return end -- ignore if not player turn
|
||||||
if state == 1 then
|
else
|
||||||
local msg = ""; if turn == 0 then msg = "GREEN " else msg = "BLUE" end
|
if turn~=1 then return end
|
||||||
self.label(msg .. " : " .. players[turn+1])
|
end
|
||||||
end
|
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4+turn);
|
||||||
end
|
data[x][z] = 4+turn;
|
||||||
end
|
if get_count(x,z) == num then say("CONGRATULATIONS! " .. event.puncher .. " has "..num .. " in a row"); self.remove(); goto END end
|
||||||
|
turn = 1-turn
|
||||||
|
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::
|
::END::
|
|
@ -0,0 +1,64 @@
|
||||||
|
--cyberpunk 2077 'breach protocol puzzle' generator
|
||||||
|
--by rnd, 20 min
|
||||||
|
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
n=4; -- size of square
|
||||||
|
steps = n*n; -- length of sequence
|
||||||
|
tries = n*10; -- how many tries in current row/col before giving up
|
||||||
|
|
||||||
|
tb = {};
|
||||||
|
for i = 1,n do
|
||||||
|
tb[i] ={}; local tbi = tb[i]
|
||||||
|
for j = 1,n do
|
||||||
|
tbi[j] = (i-1)*n+j
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--make random path col/row/col... starting at random position
|
||||||
|
|
||||||
|
row = true;
|
||||||
|
posi = 1; -- row
|
||||||
|
posj = 1; -- col
|
||||||
|
path = {}
|
||||||
|
used = {}; -- [num] = true, when taken
|
||||||
|
|
||||||
|
for i = 1, steps do
|
||||||
|
if row then
|
||||||
|
local tmp = posj;
|
||||||
|
local s = 0
|
||||||
|
while (tmp == posj or used[tb[posi][tmp]]) and s < tries do
|
||||||
|
tmp = math.random(n);
|
||||||
|
s=s+1
|
||||||
|
end
|
||||||
|
if s == tries then say("stuck at lenght " .. #path) break end
|
||||||
|
posj = tmp
|
||||||
|
else
|
||||||
|
local tmp = posi;
|
||||||
|
local s = 0
|
||||||
|
while (tmp == posi or used[tb[tmp][posj]]) and s < tries do
|
||||||
|
tmp = math.random(n);
|
||||||
|
s=s+1
|
||||||
|
end
|
||||||
|
if s == tries then say("stuck at lenght " .. #path) break end
|
||||||
|
posi = tmp
|
||||||
|
end
|
||||||
|
row = not row
|
||||||
|
path[#path+1] = tb[posi][posj];
|
||||||
|
used[path[#path]] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local ret = {};
|
||||||
|
for i = 1,n do
|
||||||
|
for j = 1,n do
|
||||||
|
ret[#ret+1] = string.format("%02d",(i-1)*n+j).." ";
|
||||||
|
end
|
||||||
|
ret[#ret+1] = "\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
self.label(table.concat(path," ") .. "\n\n"..table.concat(ret))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
|
-- 'hacking' game from Fallout, by rnd
|
||||||
if not init then
|
if not init then
|
||||||
init = true
|
init = true
|
||||||
|
|
||||||
|
max_guesses = 4 -- how many guesses player gets
|
||||||
|
n = 40; -- how many options
|
||||||
|
pass_length=5
|
||||||
|
charset_size=10 -- a,b,c,d,e,...?
|
||||||
|
cols = 4;
|
||||||
|
rows = math.ceil(n/cols);
|
||||||
|
|
||||||
generate_random_string = function(n,m)
|
generate_random_string = function(n,m)
|
||||||
local ret = {};
|
local ret = {};
|
||||||
|
@ -18,21 +26,18 @@ if not init then
|
||||||
end
|
end
|
||||||
|
|
||||||
get_form = function()
|
get_form = function()
|
||||||
|
|
||||||
local n = #passlist;
|
local n = #passlist;
|
||||||
|
|
||||||
local frm = "label[0,0;" .. intro_msg .. "] " .. "label[0,8.5;" .. msg .. "] "
|
local frm = "label[0,0;" .. intro_msg .. "] " .. "label[0,8.5;" .. msg .. "] "
|
||||||
|
local k = 0
|
||||||
for i = 1,10 do
|
for i=0,cols-1 do
|
||||||
frm = frm .. "button[0,".. (i)*0.75 ..";2,1;" .. i .. ";".. passlist[i] .. "] "
|
for j = 1,rows do
|
||||||
end
|
k=k+1; if k>n then break end
|
||||||
|
frm = frm .. "button[" .. 2*i.. ",".. j*0.75 ..";2,1;" .. k .. ";".. passlist[k] .. "] "
|
||||||
for i = 11,n do
|
end
|
||||||
frm = frm .. "button[2,".. (i-11+1)*0.75 ..";2,1;" .. i .. ";".. passlist[i] .. "] "
|
end
|
||||||
end
|
local form = "size[" .. 2*cols .. "," .. 9 .. "]" .. frm;
|
||||||
|
return form
|
||||||
local form = "size[6," .. 9 .. "]" .. frm;
|
|
||||||
return form
|
|
||||||
end
|
end
|
||||||
|
|
||||||
_G.math.randomseed(os.time())
|
_G.math.randomseed(os.time())
|
||||||
|
@ -40,15 +45,17 @@ if not init then
|
||||||
msg = "" --TEST\nTEST\nTEST";
|
msg = "" --TEST\nTEST\nTEST";
|
||||||
passlist = {}; passdict = {}
|
passlist = {}; passdict = {}
|
||||||
|
|
||||||
n = 20; -- how many options
|
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
while count< n do
|
while count< n do
|
||||||
local pass = generate_random_string(5,5); -- password length, charset size
|
local pass = generate_random_string(pass_length,charset_size); -- password length, charset size
|
||||||
if not passdict[pass] then passlist[#passlist+1] = pass; passdict[pass] = true; count = count + 1 end
|
if not passdict[pass] then passlist[#passlist+1] = pass; passdict[pass] = true; count = count + 1 end
|
||||||
end
|
end
|
||||||
correct = math.random(n)
|
correct = math.random(n)
|
||||||
|
-- say(passlist[correct])
|
||||||
guesses = 0
|
guesses = 0
|
||||||
max_guesses = 4
|
|
||||||
|
|
||||||
rom.data = {};
|
rom.data = {};
|
||||||
if not rom.data then rom.data = {} end
|
if not rom.data then rom.data = {} end
|
||||||
|
@ -57,7 +64,7 @@ if not init then
|
||||||
local players = find_player(4);
|
local players = find_player(4);
|
||||||
if not players then say("#fallout hacking game: no players") self.remove() end
|
if not players then say("#fallout hacking game: no players") self.remove() end
|
||||||
pname = players[1];
|
pname = players[1];
|
||||||
say("#fallout hacking game, player " .. pname)
|
minetest.chat_send_player(pname,"#fallout hacking game, player " .. pname)
|
||||||
|
|
||||||
--if rom.data[pname] then say("password is locked out!") self.remove() end
|
--if rom.data[pname] then say("password is locked out!") self.remove() end
|
||||||
|
|
||||||
|
@ -76,18 +83,19 @@ sender,fields = self.read_form()
|
||||||
if selected>0 then
|
if selected>0 then
|
||||||
guesses = guesses + 1
|
guesses = guesses + 1
|
||||||
if selected == correct then
|
if selected == correct then
|
||||||
say("password " .. passlist[correct] .. " is correct! " .. guesses .. " guesses.")
|
minetest.chat_send_all("#FALLOUT HACKING: " .. pname .. " guessed the password " .. passlist[correct] .. " after " .. guesses .. " guesses.")
|
||||||
self.show_form(pname, "size[1,1] label[0,0.5;" .. minetest.colorize("lawngreen", "ACCESS GRANTED") .. "]")
|
self.show_form(pname, "size[3,1] label[0,0.5;" .. minetest.colorize("lawngreen", "ACCESS GRANTED") .. "]")
|
||||||
self.remove()
|
self.remove()
|
||||||
--correct: do something with player
|
--correct: do something with player
|
||||||
else
|
else
|
||||||
|
if guesses == 3 then msg = msg .. "\n" end
|
||||||
msg = msg .. " " .. minetest.colorize("yellow",guesses .. ". " .. passlist[selected]) .. " (" .. get_similiarity(passlist[correct], passlist[selected]) .. " match)"
|
msg = msg .. " " .. minetest.colorize("yellow",guesses .. ". " .. passlist[selected]) .. " (" .. get_similiarity(passlist[correct], passlist[selected]) .. " match)"
|
||||||
self.show_form(pname, get_form())
|
self.show_form(pname, get_form())
|
||||||
end
|
end
|
||||||
if guesses>=max_guesses then
|
if guesses>=max_guesses then
|
||||||
msg = minetest.colorize("red","A C C E S S D E N I E D!")
|
msg = minetest.colorize("red","A C C E S S D E N I E D!")
|
||||||
self.show_form(pname, get_form())
|
self.show_form(pname, get_form())
|
||||||
say("too many false guesses. password locked out!") rom.data[pname] = 1; self.remove()
|
minetest.chat_send_player(pname,"too many false guesses. password locked out!") rom.data[pname] = 1; self.remove()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if fields.quit then self.remove() end
|
if fields.quit then self.remove() end
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
--go by rnd
|
||||||
|
if not init then init=true
|
||||||
|
spos = self.spawnpos()
|
||||||
|
self.listen_punch(self.pos()) -- attach punch listener
|
||||||
|
sizex = 9; sizez = 9
|
||||||
|
|
||||||
|
gamepieces = {
|
||||||
|
{ -- player black
|
||||||
|
"basic_robot:buttonFF8080"
|
||||||
|
},
|
||||||
|
{ -- player white - blue
|
||||||
|
"basic_robot:button8080FF"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
show_mark = function(pos)
|
||||||
|
minetest.add_particle(
|
||||||
|
{
|
||||||
|
pos = pos,
|
||||||
|
expirationtime = 10,
|
||||||
|
velocity = {x=0, y=0,z=0},
|
||||||
|
size = 5,
|
||||||
|
texture = "default_apple.png",
|
||||||
|
acceleration = {x=0,y=0,z=0},
|
||||||
|
collisiondetection = true,
|
||||||
|
collision_removal = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
build_game = function()
|
||||||
|
for i = 1,sizex do
|
||||||
|
minetest.swap_node({x=spos.x+i,y=spos.y,z=spos.z+sizez+1},{name = "basic_robot:button_"..(64+i), param2=2})
|
||||||
|
minetest.swap_node({x=spos.x+i,y=spos.y,z=spos.z},{name = "basic_robot:button_"..(64+i)})
|
||||||
|
for j = 1,sizez do
|
||||||
|
minetest.swap_node({x=spos.x+i,y=spos.y,z=spos.z+j},{name = "basic_robot:button808080"})
|
||||||
|
minetest.swap_node({x=spos.x+i,y=spos.y+1,z=spos.z+j},{name = "air"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for j = 1,sizez do
|
||||||
|
minetest.swap_node({x=spos.x,y=spos.y,z=spos.z+j},{name = "basic_robot:button_".. (48+j), param2=3})
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
msgs = {1} --{idx, msg1, msg2,msg3, msg4, msg5}; -- up to 5 ingame messages displayed
|
||||||
|
add_msg = function(text)
|
||||||
|
local idx = msgs[1] or 1;
|
||||||
|
msgs[idx+1] = text;idx = idx+1; if idx>5 then idx = 1 end msgs[1] = idx
|
||||||
|
end
|
||||||
|
show_msgs = function() -- last message on top
|
||||||
|
local out = {}; local idx = msgs[1] or 1;
|
||||||
|
for i = idx,2,-1 do out[#out+1] = msgs[i] or "" end
|
||||||
|
for i = 6, idx+1,-1 do out[#out+1] = msgs[i] or "" end
|
||||||
|
self.label(table.concat(out,"\n"))
|
||||||
|
end
|
||||||
|
|
||||||
|
build_game()
|
||||||
|
punchnode = nil; -- name of piece to place
|
||||||
|
step = 0;
|
||||||
|
turn = 0;
|
||||||
|
self.label("go\n\n" ..
|
||||||
|
"RULES:\n\n"..
|
||||||
|
"1. liberty of block is free position next to block (not diagonally). block\n"..
|
||||||
|
"is alive if it has liberties left. group of connected (not diagonally) blocks\n"..
|
||||||
|
"is alive if at least one block in group is alive.\n"..
|
||||||
|
"2. dead blocks are immediately removed from game.\n"..
|
||||||
|
"3.to get score count how much territory your blocks occupy, including blocks\n"..
|
||||||
|
"themselves. If not clear which blocks are dead, continue game until it is clear\n\n"..
|
||||||
|
"punch board to place your red/blue piece. blue starts first.")
|
||||||
|
end
|
||||||
|
|
||||||
|
event = keyboard.get()
|
||||||
|
|
||||||
|
|
||||||
|
if event then
|
||||||
|
--self.label(serialize(event))
|
||||||
|
local x = event.x-spos.x; local z = event.z-spos.z;
|
||||||
|
if event.y~= spos.y then return end
|
||||||
|
if x<1 or x>sizex or z<1 or z>sizez then return end
|
||||||
|
|
||||||
|
turn = 1- turn
|
||||||
|
step = step+1
|
||||||
|
local x2 = event.x-spos.x; local z2 = event.z-spos.z
|
||||||
|
if turn == 0 then
|
||||||
|
add_msg(minetest.colorize("red",step) .. ": " .. event.puncher .. " " .. string.char(64+x2) .. z2);
|
||||||
|
else
|
||||||
|
add_msg(minetest.colorize("blue",step) .. ": " .. event.puncher .. " " .. string.char(64+x2) .. z2);
|
||||||
|
end
|
||||||
|
|
||||||
|
show_msgs()
|
||||||
|
|
||||||
|
minetest.swap_node({x=event.x,y=event.y+1,z=event.z},{name = gamepieces[turn+1][1]})
|
||||||
|
punchnode = nil
|
||||||
|
show_mark({x=event.x,y=event.y+2,z=event.z})
|
||||||
|
end
|
|
@ -1,106 +1,140 @@
|
||||||
--HIDE AND SEEK game robot, by rnd
|
--HIDE AND SEEK game robot, by rnd
|
||||||
if not gamemaster then
|
if not gamemaster then
|
||||||
timeout = 10;
|
timeout = 20;
|
||||||
gamemaster = "rnd"
|
fardist = 300
|
||||||
player_list = {};
|
gamemaster = "rnd"
|
||||||
_G.minetest.chat_send_all("# HIDE AND SEEK .. say #hide to join play")
|
|
||||||
s=0;t=0; count = 0;
|
_G.minetest.forceload_block(self.pos(),true)
|
||||||
_G.minetest.forceload_block(self.pos(),true)
|
self.listen(1);
|
||||||
self.listen(1); self.label(colorize("yellow","HIDE&SEEK"))
|
centerpos = {x=160,y= 606,z= 227};
|
||||||
end
|
|
||||||
|
init_game = function()
|
||||||
speaker,msg = self.listen_msg();
|
self.label(colorize("yellow","HIDE&SEEK .. waiting for players .. say #hide to join"))
|
||||||
|
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK .. say #hide to join play, when all joined say #start to start game."))
|
||||||
if s==0 then
|
s=0;t=0; count = 0;
|
||||||
if msg =="#hide" then
|
player_list = {}
|
||||||
player_list[speaker]={};
|
end
|
||||||
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. speaker .. " joined the game")
|
|
||||||
local player = _G.minetest.get_player_by_name(speaker);
|
reset_name = function(name)
|
||||||
if player then
|
if name then
|
||||||
player:setpos({x=0,y=5,z=0});player:set_properties({nametag_color = "0x0"})
|
local player = minetest.get_player_by_name(name)
|
||||||
end
|
if not player then return end
|
||||||
|
player:set_properties({nametag_color = "white"})
|
||||||
end
|
return
|
||||||
if msg == "#start" and speaker == gamemaster then s = 0.5 _G.minetest.chat_send_all("# HIDE AND SEEK STARTS in " .. timeout .. " SECONDS!") end
|
end
|
||||||
|
local players = _G.minetest.get_connected_players();
|
||||||
elseif s==0.5 then
|
for _,player in pairs(players) do
|
||||||
t=t+1
|
local name = player:get_player_name();
|
||||||
if t==timeout then
|
local data = player_list[name];
|
||||||
t=0;s = 1; count = 0;
|
if data then
|
||||||
for pname,_ in pairs(player_list) do
|
player:set_properties({nametag_color = "white"})
|
||||||
local player = _G.minetest.get_player_by_name(pname);
|
end
|
||||||
if player then
|
end
|
||||||
player_list[pname].hp = player:get_hp();
|
end
|
||||||
player_list[pname].pos = player:getpos()
|
|
||||||
player_list[pname].t = 0;
|
show_players = function()
|
||||||
count = count+1
|
local ret = {}
|
||||||
end
|
for k,v in pairs(player_list) do
|
||||||
end
|
ret[#ret+1]=k
|
||||||
if count == 1 then
|
end
|
||||||
gamemaster = false; _G.minetest.chat_send_all("# HIDE AND SEEK only 1 player, aborting.")
|
self.label("hide and seek, players: " .. table.concat(ret,", "))
|
||||||
else
|
end
|
||||||
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK STARTS NOW WITH " .. count .. " PLAYERS. You are out if: 1.your health changes, 2. leave spawn. If stay in same area for too long or you will be exposed."))
|
init_game()
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
speaker,msg = self.listen_msg();
|
||||||
elseif s==1 then
|
|
||||||
players = _G.minetest.get_connected_players();
|
if s==0 then
|
||||||
count = 0;
|
if msg =="#hide" then
|
||||||
for _,player in pairs(players) do
|
player_list[speaker]={};
|
||||||
local name = player:get_player_name();
|
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. speaker .. " joined the game")
|
||||||
local data = player_list[name];
|
local player = _G.minetest.get_player_by_name(speaker);
|
||||||
if data then
|
if player then
|
||||||
count=count+1
|
player:setpos(centerpos);player:set_properties({nametag_color = "0x0"})
|
||||||
local pos = player:getpos();
|
end
|
||||||
local dist = math.max(math.abs(pos.x),math.abs(pos.y),math.abs(pos.z));
|
|
||||||
if dist>50 or (not _G.minetest.get_player_by_name(name)) then
|
end
|
||||||
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! went too far away " )
|
if msg == "#start" and speaker == gamemaster then s = 0.5 _G.minetest.chat_send_all("# HIDE AND SEEK STARTS in " .. timeout .. " SECONDS!") end
|
||||||
player:set_properties({nametag_color = "white"})
|
|
||||||
player_list[name] = nil;
|
elseif s==0.5 then
|
||||||
end
|
t=t+1
|
||||||
if data.hp ~= player:get_hp() then
|
if t==timeout then
|
||||||
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! his health changed!" )
|
t=0;s = 1; count = 0;
|
||||||
player:set_properties({nametag_color = "white"})
|
for pname,_ in pairs(player_list) do
|
||||||
player_list[name] = nil;
|
local player = _G.minetest.get_player_by_name(pname);
|
||||||
end
|
if player then
|
||||||
|
player_list[pname].hp = player:get_hp();
|
||||||
--expose campers
|
player_list[pname].pos = player:getpos()
|
||||||
local p = data.pos;
|
player_list[pname].t = 0;
|
||||||
dist = math.max(math.abs(pos.x-p.x),math.abs(pos.y-p.y),math.abs(pos.z-p.z));
|
count = count+1
|
||||||
--say( name .. " dist " .. dist .. " t " .. data.t)
|
end
|
||||||
if dist<8 then
|
end
|
||||||
data.t = data.t+1;
|
if count == 1 then
|
||||||
if not data.camp then
|
gamemaster = false; _G.minetest.chat_send_all("# HIDE AND SEEK only 1 player, aborting.")
|
||||||
if data.t>15 and not data.camp then
|
else
|
||||||
_G.minetest.chat_send_player(name, "# HIDE AND SEEK: move in 5s or be exposed")
|
_G.minetest.chat_send_all(colorize("red","# HIDE AND SEEK STARTS NOW WITH " .. count .. " PLAYERS. You are out if: 1.your health changes, 2. leave spawn. If stay in same area for too long or you will be exposed."))
|
||||||
data.camp = true
|
end
|
||||||
end
|
|
||||||
elseif data.t>=20 then
|
end
|
||||||
pos.x=math.ceil(pos.x);pos.y=math.ceil(pos.y);pos.z=math.ceil(pos.z);
|
elseif s==1 then
|
||||||
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. name .. " is camping at " .. pos.x .. " " .. pos.z)
|
players = _G.minetest.get_connected_players();
|
||||||
data.camp = false; data.t = 0
|
count = 0;
|
||||||
end
|
for _,player in pairs(players) do
|
||||||
else
|
local name = player:get_player_name();
|
||||||
data.t = 0; data.pos = player:getpos(); data.camp = false
|
local data = player_list[name];
|
||||||
end
|
if data then
|
||||||
|
count=count+1
|
||||||
end
|
local pos = player:getpos();
|
||||||
end
|
local dist = math.max(math.abs(pos.x-centerpos.x),math.abs(pos.y-centerpos.y),math.abs(pos.z-centerpos.z));
|
||||||
|
if dist>fardist or (not _G.minetest.get_player_by_name(name)) then
|
||||||
self.label(count)
|
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! went too far away " )
|
||||||
|
reset_name(name)
|
||||||
if count<=1 then
|
show_players()
|
||||||
if count==1 then
|
player_list[name] = nil;
|
||||||
for name,_ in pairs(player_list) do
|
end
|
||||||
player0=_G.minetest.get_player_by_name(name)
|
if data.hp < player:get_hp() then
|
||||||
_G.minetest.chat_send_all(colorize("red","****** HIDE AND SEEK: ".. name .. " wins ******"))
|
_G.minetest.chat_send_all("# HIDE AND SEEK: ".. name .. " is OUT! his health changed!" )
|
||||||
player0:set_properties({nametag_color = "white"})
|
player:set_properties({nametag_color = "white"})
|
||||||
gamemaster = false;
|
player:setpos(centerpos)
|
||||||
end
|
player_list[name] = nil;
|
||||||
else
|
show_players()
|
||||||
_G.minetest.chat_send_all("# HIDE AND SEEK: no players left")
|
end
|
||||||
gamemaster = false;
|
|
||||||
end
|
--expose campers
|
||||||
end
|
local p = data.pos;
|
||||||
|
dist = math.max(math.abs(pos.x-p.x),math.abs(pos.y-p.y),math.abs(pos.z-p.z));
|
||||||
end
|
--say( name .. " dist " .. dist .. " t " .. data.t)
|
||||||
|
if dist<8 then
|
||||||
|
data.t = data.t+1;
|
||||||
|
if not data.camp then
|
||||||
|
if data.t>15 and not data.camp then
|
||||||
|
_G.minetest.chat_send_player(name, "# HIDE AND SEEK: move in 5s or be exposed")
|
||||||
|
data.camp = true
|
||||||
|
end
|
||||||
|
elseif data.t>=20 then
|
||||||
|
pos.x=math.ceil(pos.x);pos.y=math.ceil(pos.y);pos.z=math.ceil(pos.z);
|
||||||
|
_G.minetest.chat_send_all("# HIDE AND SEEK: " .. name .. " is camping at " .. pos.x .. " " .. pos.z)
|
||||||
|
data.camp = false; data.t = 0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
data.t = 0; data.pos = player:getpos(); data.camp = false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if count<=1 then
|
||||||
|
if count==1 then
|
||||||
|
for name,_ in pairs(player_list) do
|
||||||
|
_G.minetest.chat_send_all(colorize("red","****** HIDE AND SEEK: ".. name .. " wins ******"))
|
||||||
|
reset_name(name)
|
||||||
|
init_game();
|
||||||
|
end
|
||||||
|
else
|
||||||
|
_G.minetest.chat_send_all("# HIDE AND SEEK: no players left")
|
||||||
|
init_game()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
--HIDE AND SEEK game robot
|
||||||
|
if not init then init = true
|
||||||
|
_G.minetest.forceload_block(self.pos(),true)
|
||||||
|
timeout = 30;
|
||||||
|
|
||||||
|
gamepos = {x=0,y=11,z=0} -- game of hide and seek is played around here
|
||||||
|
maxgamedist = 100; -- how far around gamepos player can go before kicked out of game
|
||||||
|
gameoutpos = {x=0,y=20,z=0} -- position for players that go out of game
|
||||||
|
|
||||||
|
player_list = {};
|
||||||
|
s=0;t=0; count = 0;
|
||||||
|
prize = ""
|
||||||
|
|
||||||
|
announce = function(text) -- show message to all players in game only
|
||||||
|
for name,_ in pairs(player_list) do
|
||||||
|
_G.minetest.chat_send_player(name, text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
get_players = function()
|
||||||
|
local msg = "";
|
||||||
|
for name,_ in pairs(player_list) do
|
||||||
|
msg = msg .. " " .. name
|
||||||
|
end
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
|
||||||
|
init_game = function()
|
||||||
|
|
||||||
|
local msg = get_players();
|
||||||
|
announce(colorize("red","# HIDE AND SEEK : hide from everyone else who is playing. Winner gets DIAMONDS\nsay join to join play. say #start to start game."..
|
||||||
|
" players: " .. msg))
|
||||||
|
s=0;t=0;
|
||||||
|
end
|
||||||
|
|
||||||
|
--show initial message for all players
|
||||||
|
--minetest.chat_send_all(colorize("red","# HIDE AND SEEK : hide from everyone else who is playing. Winner gets DIAMONDS\nsay join to join play. say #start to start game.")
|
||||||
|
|
||||||
|
init_game()
|
||||||
|
_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
|
||||||
|
|
||||||
|
t = t +1
|
||||||
|
if t%30 == 0 then
|
||||||
|
init_game();
|
||||||
|
end
|
||||||
|
|
||||||
|
if msg =="join" then
|
||||||
|
player_list[speaker]={};
|
||||||
|
announce(colorize("red","# HIDE AND SEEK: " .. speaker .. " joined the game"));
|
||||||
|
announce("players: " .. get_players())
|
||||||
|
|
||||||
|
local player = _G.minetest.get_player_by_name(speaker);
|
||||||
|
count = count + 1
|
||||||
|
if player then
|
||||||
|
player:setpos(gamepos);player:set_properties({nametag_color = "0x0"})
|
||||||
|
player:set_hp(20)
|
||||||
|
local inv = player:get_inventory();inv:set_list("main",{})
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
if msg == "#start" and count>1 then s = 0.5 announce(colorize("red","# 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
|
||||||
|
init = false; announce("# HIDE AND SEEK only 1 player, aborting.")
|
||||||
|
else
|
||||||
|
prize = "default:diamond " .. (count-1);
|
||||||
|
announce(colorize("red","# HIDE AND SEEK STARTS NOW WITH " .. count .. " PLAYERS."..
|
||||||
|
"You are out if: 1.your health changes, 2. leave game area. If stay in same area for too long or you will be exposed."))
|
||||||
|
announce(colorize("red","# WINNER WILL GET " .. prize))
|
||||||
|
|
||||||
|
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-gamepos.x),math.abs(pos.y-gamepos.y),math.abs(pos.z-gamepos.z));
|
||||||
|
if dist>maxgamedist or (not _G.minetest.get_player_by_name(name)) then
|
||||||
|
announce("# HIDE AND SEEK: ".. name .. " is OUT! went too far away " )
|
||||||
|
player:set_properties({nametag_color = "white"})
|
||||||
|
player_list[name] = nil;
|
||||||
|
announce("remaining players: " .. get_players())
|
||||||
|
end
|
||||||
|
if data.hp ~= player:get_hp() then
|
||||||
|
announce("# HIDE AND SEEK: ".. name .. " is OUT! his health changed!" )
|
||||||
|
player:set_properties({nametag_color = "white"})
|
||||||
|
player_list[name] = nil;
|
||||||
|
announce("remaining players: " .. get_players())
|
||||||
|
player:setpos(gameoutpos)
|
||||||
|
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>25 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>=30 then
|
||||||
|
pos.x=math.ceil(pos.x);pos.y=math.ceil(pos.y);pos.z=math.ceil(pos.z);
|
||||||
|
announce("# 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
|
||||||
|
local player0=_G.minetest.get_player_by_name(name)
|
||||||
|
if player0 then
|
||||||
|
announce(colorize("red","****** HIDE AND SEEK: ".. name .. " wins ******"))
|
||||||
|
local inv = player0:get_inventory();
|
||||||
|
inv:add_item("main",_G.ItemStack(prize))
|
||||||
|
player0:set_properties({nametag_color = "white"})
|
||||||
|
player0:setpos(gameoutpos)
|
||||||
|
end
|
||||||
|
s=2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
announce("# HIDE AND SEEK: no players left")
|
||||||
|
s=2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif s==2 then
|
||||||
|
player_list = {}
|
||||||
|
init_game()
|
||||||
|
end
|
|
@ -0,0 +1,23 @@
|
||||||
|
-- high scores for multiple levels of game
|
||||||
|
if not init then init = true
|
||||||
|
init_score = function(levels, tops, default_value) -- [level] = {{name,score}, ...}
|
||||||
|
local data = {} for i = 1, levels do data[i] = {} for j = 1,tops do data[i][j] = {"-",default_value} end end return data
|
||||||
|
end
|
||||||
|
|
||||||
|
add_score = function(data,name,score,level)
|
||||||
|
local datal = data[level]; local tops = #datal;
|
||||||
|
local j;for i = 1,tops do if score>datal[i][2] then j = i break end end
|
||||||
|
if not j then return end; for i=tops,j+1,-1 do datal[i][1] = datal[i-1][1];datal[i][2] = datal[i-1][2] end
|
||||||
|
datal[j] = {name,score}
|
||||||
|
end
|
||||||
|
|
||||||
|
_,text = book.read(1); data = minetest.deserialize(text)
|
||||||
|
if not data then data = init_score(1,5,-999) end
|
||||||
|
|
||||||
|
add_score(data,"pl1",-50,1)
|
||||||
|
add_score(data,"pl2",-40,1)
|
||||||
|
|
||||||
|
book.write(1,"score", minetest.serialize(data))
|
||||||
|
|
||||||
|
self.label(serialize(data))
|
||||||
|
end
|
|
@ -0,0 +1,162 @@
|
||||||
|
--coroutine
|
||||||
|
--lights out by dopik
|
||||||
|
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
self.listen_punch(self.pos());
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
size = 5
|
||||||
|
|
||||||
|
score = 1000 --highest score possible
|
||||||
|
|
||||||
|
function generateField()
|
||||||
|
local tbl = {}
|
||||||
|
for i = 1, size^2 do
|
||||||
|
tbl[i] = math.random(0,1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local field = {}
|
||||||
|
for i = 1, size^2 do
|
||||||
|
local x,z = (i-1) % size, math.floor((i-1) / size)
|
||||||
|
local val = tbl[i]
|
||||||
|
val = val + (x > 0 and tbl[(x-1) + (z*size) +1] or 0)
|
||||||
|
val = val + (x+1 < size and tbl[(x+1) + (z*size) +1] or 0)
|
||||||
|
val = val + (z > 0 and tbl[x + ((z-1)*size) +1] or 0)
|
||||||
|
val = val + (z+1 < size and tbl[x + ((z+1)*size) +1] or 0)
|
||||||
|
field[i] = val % 2
|
||||||
|
end
|
||||||
|
|
||||||
|
return field
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function placeField(field)
|
||||||
|
for i = 1, size^2 do
|
||||||
|
local dx,dz = (i-1) % size +1, math.floor((i-1) / size) +1
|
||||||
|
|
||||||
|
local pos = self.spawnpos()
|
||||||
|
pos.x = pos.x + dx
|
||||||
|
pos.z = pos.z + dz
|
||||||
|
|
||||||
|
keyboard.set(pos, field[i]*6 + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function hitKey(pos)
|
||||||
|
local c
|
||||||
|
|
||||||
|
if keyboard.read(pos) == "basic_robot:buttonwhite" then
|
||||||
|
c = true
|
||||||
|
keyboard.set(pos, 7)
|
||||||
|
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
|
||||||
|
keyboard.set(pos, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
pos.x = pos.x - 1
|
||||||
|
if keyboard.read(pos) == "basic_robot:buttonwhite" then
|
||||||
|
c = true
|
||||||
|
keyboard.set(pos, 7)
|
||||||
|
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
|
||||||
|
keyboard.set(pos, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
pos.x = pos.x + 2
|
||||||
|
if keyboard.read(pos) == "basic_robot:buttonwhite" then
|
||||||
|
c = true
|
||||||
|
keyboard.set(pos, 7)
|
||||||
|
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
|
||||||
|
keyboard.set(pos, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
pos.x = pos.x - 1
|
||||||
|
pos.z = pos.z - 1
|
||||||
|
if keyboard.read(pos) == "basic_robot:buttonwhite" then
|
||||||
|
c = true
|
||||||
|
keyboard.set(pos, 7)
|
||||||
|
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
|
||||||
|
keyboard.set(pos, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
pos.z = pos.z + 2
|
||||||
|
if keyboard.read(pos) == "basic_robot:buttonwhite" then
|
||||||
|
c = true
|
||||||
|
keyboard.set(pos, 7)
|
||||||
|
elseif keyboard.read(pos) == "basic_robot:buttonblue" then
|
||||||
|
keyboard.set(pos, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
score = math.max(0, score - 1)
|
||||||
|
|
||||||
|
if not c then
|
||||||
|
return won()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function won()
|
||||||
|
for i = 1, size^2 do
|
||||||
|
local pos = self.spawnpos()
|
||||||
|
pos.x = pos.x + 1 + i % size
|
||||||
|
pos.z = pos.z + 1 + math.floor(i / size)
|
||||||
|
|
||||||
|
if keyboard.read(pos) == "basic_robot:buttonblue" then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return win()
|
||||||
|
end
|
||||||
|
|
||||||
|
function win()
|
||||||
|
puzzle.chat_send_player(pname, "\27(c@#ff0)###Lights Out### \27(c@#fff)You won!")
|
||||||
|
puzzle.chat_send_player(pname, string.concat({"\27(c@#ff0)###Lights Out### \27(c@#fff)Your score is \27(c@#ff0) ", score}))
|
||||||
|
|
||||||
|
for i = 1, size^2 do
|
||||||
|
local dx,dz = (i-1) % size +1, math.floor((i-1) / size) +1
|
||||||
|
|
||||||
|
local pos = self.spawnpos()
|
||||||
|
pos.x = pos.x + dx
|
||||||
|
pos.z = pos.z + dz
|
||||||
|
|
||||||
|
puzzle.set_node(pos, {name="default:dirt"})
|
||||||
|
end
|
||||||
|
|
||||||
|
self.remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
function init()
|
||||||
|
local players = find_player(5, self.spawnpos())
|
||||||
|
if not players then
|
||||||
|
self.remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
pname = players[1]
|
||||||
|
|
||||||
|
local field = generateField(size)
|
||||||
|
placeField(field)
|
||||||
|
|
||||||
|
puzzle.chat_send_player(pname, "\27(c@#ff0)###Lights Out### \27(c@#fff)Game started")
|
||||||
|
self.label("Turn all lights off (=white) to win\nPunch a light to switch it on/off")
|
||||||
|
|
||||||
|
return main()
|
||||||
|
end
|
||||||
|
|
||||||
|
function main()
|
||||||
|
local event = keyboard.get()
|
||||||
|
local pos = self.spawnpos()
|
||||||
|
|
||||||
|
if event then
|
||||||
|
if event.x <= pos.x + size and event.x > pos.x
|
||||||
|
and event.z <= pos.z + size and event.z > pos.z
|
||||||
|
and event.y == pos.y then
|
||||||
|
hitKey({x=event.x,y=event.y, z=event.z})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pause()
|
||||||
|
return main()
|
||||||
|
end
|
||||||
|
|
||||||
|
init()
|
|
@ -1,89 +1,132 @@
|
||||||
|
-- 'Mensch argere Dich nicht'. modified by rnd
|
||||||
if not init then
|
if not init then
|
||||||
|
msg =
|
||||||
msg =
|
"Sorry!/Mensch argere Dich nicht, modified by rnd\n\n" ..
|
||||||
"'Mensch argere Dich nicht' is a German board game (but not a German-style board game), developed by Josef Friedrich Schmidt in 1907/1908.\n"..
|
"1. goal of game is put all 4 of your pieces in your home area by moving clockwise around on white path\n"..
|
||||||
" The players throw a die in turn and can advance any of their pieces in the game by the thrown number of dots on the dice.\n" ..
|
"2. start of game is player trying to move his piece out to start spot next to home by trying 3x to get 6 from dice.\n"..
|
||||||
"Throwing a six means bringing a piece into the game (by placing one from the 'out' area onto the 'start' field) and throwing the dice again. If\n" ..
|
"3. after that player uses dice at start of turn. he moves his playing pieces ( those\n"..
|
||||||
"a piece is on the 'start' field and there are still pieces in the 'out' area, it must be moved as soon as possible. If a piece cannot be\n".. "brought into the game then any other piece in the game must be moved by the thrown number, if that is possible. Pay attention that throwing\n".." dice continuously without moving is forbidden and by each dice throw you have to make a move.\n" ..
|
"on board) so many positions as dice said. negative number means moving back.\n"..
|
||||||
"Pieces can jump over other pieces, and throw out pieces from other players (into that player's 'out' area) if they land on them. A player\n".. "cannot throw out his own pieces though, he can advance further than the last field in the 'home' row. A player can be thrown out if he is on\n"..
|
"4. if player can move his piece he must. if his piece goes backward all the way to start\n"..
|
||||||
"his 'start' field.\n" ..
|
"he must put it back out.If piece lands on opponent piece then opponent piece is put out to initial start.\n"..
|
||||||
"Variation which is played by most players: A player who has no pieces in the game has 3 tries to throw a six"
|
"5. if dice shows 6 he can move 6 or put another piece out if possible. player can move\n"..
|
||||||
self.label(msg)
|
"pieces within home area if possible.\n"..
|
||||||
|
"6. if dice shows 0 you play as one of your opponents for a turn."
|
||||||
init = true;
|
self.label(msg)
|
||||||
state = 1; -- game on
|
|
||||||
step = 0;
|
init = true;
|
||||||
punchstate = 1; -- first punch
|
state = 1; -- game on
|
||||||
punchpos = {}
|
step = 0;
|
||||||
pos = self.spawnpos()
|
punchstate = 1; -- first punch
|
||||||
dice = 0
|
punchpos = {}
|
||||||
spawns = {{2,2,"basic_robot:buttonFF8080"},{2,11,"basic_robot:button8080FF"},{11,11,"basic_robot:button80FF80"},{11,2,"basic_robot:buttonFFFF80"}}
|
pos = self.spawnpos()
|
||||||
|
self.listen_punch(self.pos()) -- attach punch listener
|
||||||
for i = 1,12 do for j = 1,12 do
|
dice = 0
|
||||||
minetest.swap_node({x=pos.x+i,y=pos.y+1,z=pos.z+j},{name = "air"})
|
spawns = {
|
||||||
end end
|
{2,2,1,2,2,"basic_robot:buttonFF8080"}, -- xstart,zstart,ystart, dimx, dimz, nodename
|
||||||
|
{2,11,1,2,2,"basic_robot:button8080FF"},
|
||||||
for k = 1,#spawns do
|
{11,11,1,2,2,"basic_robot:button80FF80"},
|
||||||
for i = 0,1 do for j = 0,1 do
|
{11,2,1,2,2,"basic_robot:buttonFFFF80"}, --4 bases
|
||||||
minetest.swap_node({x=pos.x+i+spawns[k][1],y=pos.y+1,z=pos.z+j+spawns[k][2]},{name = spawns[k][3]})
|
|
||||||
end end
|
{7,3,0,1,4,"basic_robot:buttonFF8080"}, -- red final
|
||||||
end
|
{3,7,0,4,1,"basic_robot:button8080FF"}, -- blue final
|
||||||
|
{7,8,0,1,4,"basic_robot:button80FF80"}, -- green final
|
||||||
keyboard.set({x=pos.x+7,y=pos.y+1,z=pos.z+7},7)
|
{8,7,0,4,1,"basic_robot:buttonFFFF80"}, -- yellow final
|
||||||
|
|
||||||
end
|
{1,1,0,5,5,"basic_robot:button808080"},{6,1,0,3,1,"basic_robot:button808080"},
|
||||||
|
{9,1,0,5,5,"basic_robot:button808080"},{13,6,0,1,3,"basic_robot:button808080"},
|
||||||
if state == 0 then
|
{1,9,0,5,5,"basic_robot:button808080"},{1,6,0,1,3,"basic_robot:button808080"},
|
||||||
elseif state == 1 then
|
{9,9,0,5,5,"basic_robot:button808080"},{6,13,0,3,1,"basic_robot:button808080"},
|
||||||
event = keyboard.get();
|
|
||||||
if event then
|
{2,2,0,2,2,"basic_robot:buttonFFFFFF"},
|
||||||
x = event.x-pos.x; y = event.y-pos.y; z = event.z-pos.z
|
{2,11,0,2,2,"basic_robot:buttonFFFFFF"},
|
||||||
--say("type " .. event.type .. " pos " .. x .. " " .. y .. " " .. z)
|
{11,11,0,2,2,"basic_robot:buttonFFFFFF"},
|
||||||
if x == 7 and y == 1 and z == 7 then
|
{11,2,0,2,2,"basic_robot:buttonFFFFFF"},
|
||||||
_G.math.randomseed(os.time())
|
}
|
||||||
dice = math.random(6);
|
|
||||||
keyboard.set({x=pos.x+7,y=pos.y+1,z=pos.z+7},7+dice)
|
-- build board
|
||||||
step = step + 1;
|
for i = 1,12 do for j = 1,12 do
|
||||||
msg = colorize("red","<Mensch argere dich nicht>") .. " STEP " .. step .. ": " ..event.puncher .. " threw dice = " .. dice;
|
minetest.swap_node({x=pos.x+i,y=pos.y,z=pos.z+j},{name = "basic_robot:buttonFFFFFF"})
|
||||||
minetest.chat_send_all(msg)
|
minetest.swap_node({x=pos.x+i,y=pos.y+1,z=pos.z+j},{name = "air"})
|
||||||
self.label(msg)
|
end end
|
||||||
punchstate = 1
|
|
||||||
elseif punchstate == 1 then
|
for k = 1,#spawns do
|
||||||
if y == 1 and event.type ~= 2 and event.type<7 then
|
for i = 0,spawns[k][4]-1 do for j = 0,spawns[k][5]-1 do
|
||||||
punchpos = 2; minetest.chat_send_player(event.puncher,colorize("red","<Mensch argere dich nicht>") .. " punch place on board where to move ")
|
minetest.swap_node({x=pos.x+i+spawns[k][1],y=pos.y+spawns[k][3],z=pos.z+j+spawns[k][2]},{name = spawns[k][6]})
|
||||||
punchpos = {x=event.x,y=event.y,z=event.z}
|
end end
|
||||||
punchstate = 2
|
end
|
||||||
end
|
|
||||||
elseif punchstate == 2 then
|
keyboard.set({x=pos.x+7,y=pos.y+1,z=pos.z+7},7)
|
||||||
if y == 0 and event.type ~= 2 then
|
|
||||||
if x<2 or x>12 or z<2 or z>12 then
|
msgs = {1} --{idx, msg1, msg2,msg3, msg4, msg5}; -- up to 5 ingame messages displayed
|
||||||
else
|
add_msg = function(text)
|
||||||
local nodename = minetest.get_node(punchpos).name;
|
local idx = msgs[1] or 1;
|
||||||
minetest.swap_node({x=event.x, y = event.y+1, z=event.z},{name = nodename})
|
msgs[idx+1] = text;idx = idx+1; if idx>5 then idx = 1 end msgs[1] = idx
|
||||||
minetest.swap_node(punchpos,{name = "air"})
|
end
|
||||||
punchstate = 1; dice = 0
|
show_msgs = function()
|
||||||
minetest.add_particle(
|
local out = {};
|
||||||
{
|
local idx = msgs[1] or 1;
|
||||||
pos = punchpos,
|
for i = idx,2,-1 do out[#out+1] = msgs[i] or "" end
|
||||||
expirationtime = 15,
|
for i = 6, idx+1,-1 do out[#out+1] = msgs[i] or "" end
|
||||||
velocity = {x=0, y=0,z=0},
|
self.label(table.concat(out,"\n"))
|
||||||
size = 18,
|
end
|
||||||
texture = "default_apple.png",
|
|
||||||
acceleration = {x=0,y=0,z=0},
|
end
|
||||||
collisiondetection = true,
|
|
||||||
collision_removal = true,
|
if state == 0 then
|
||||||
}
|
elseif state == 1 then
|
||||||
)
|
event = keyboard.get();
|
||||||
msg = colorize("red","<Mensch argere dich nicht>") .. " " .. event.puncher .. " moved.";
|
if event then
|
||||||
minetest.chat_send_all(msg)
|
x = event.x-pos.x; y = event.y-pos.y; z = event.z-pos.z
|
||||||
self.label(msg)
|
--say("type " .. event.type .. " pos " .. x .. " " .. y .. " " .. z)
|
||||||
end
|
if x == 7 and y == 1 and z == 7 then
|
||||||
end
|
_G.math.randomseed(os.time())
|
||||||
|
dice = -3+math.random(9);
|
||||||
|
keyboard.set({x=pos.x+7,y=pos.y+1,z=pos.z+7},7+math.abs(dice))
|
||||||
end
|
if dice<0 then
|
||||||
end
|
keyboard.set({x=pos.x+7,y=pos.y+2,z=pos.z+7},7+11)
|
||||||
|
else
|
||||||
|
keyboard.set({x=pos.x+7,y=pos.y+2,z=pos.z+7},0)
|
||||||
|
end
|
||||||
|
step = step + 1;
|
||||||
|
msg = minetest.colorize("red","STEP ".. step) .. ": " ..event.puncher .. " threw dice = " .. dice;
|
||||||
|
add_msg(msg); show_msgs()
|
||||||
|
|
||||||
|
|
||||||
|
punchstate = 1
|
||||||
|
elseif punchstate == 1 then
|
||||||
|
if y == 1 and event.type ~= 2 and event.type<7 then
|
||||||
|
punchpos = 2; minetest.chat_send_player(event.puncher,colorize("red","<Mensch argere dich nicht>") .. " punch place on board where to move ")
|
||||||
|
punchpos = {x=event.x,y=event.y,z=event.z}
|
||||||
|
punchstate = 2
|
||||||
|
end
|
||||||
|
elseif punchstate == 2 then
|
||||||
|
if y == 0 and event.type ~= 2 then
|
||||||
|
if x<2 or x>12 or z<2 or z>12 then
|
||||||
|
else
|
||||||
|
local nodename = minetest.get_node(punchpos).name;
|
||||||
|
minetest.swap_node({x=event.x, y = event.y+1, z=event.z},{name = nodename})
|
||||||
|
minetest.swap_node(punchpos,{name = "air"})
|
||||||
|
punchstate = 1; dice = 0
|
||||||
|
minetest.add_particle(
|
||||||
|
{
|
||||||
|
pos = punchpos,
|
||||||
|
expirationtime = 15,
|
||||||
|
velocity = {x=0, y=0,z=0},
|
||||||
|
size = 18,
|
||||||
|
texture = "default_apple.png",
|
||||||
|
acceleration = {x=0,y=0,z=0},
|
||||||
|
collisiondetection = true,
|
||||||
|
collision_removal = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = event.puncher .. " moved.";
|
||||||
|
add_msg(msg); show_msgs()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
|
@ -1,83 +1,92 @@
|
||||||
-- minesweeper
|
-- minesweeper
|
||||||
if not data then
|
if not data then
|
||||||
m=24;n=22; minescount = m*n/5;
|
m=24;n=22; minescount = m*n/5;
|
||||||
reward = 30;
|
reward = 30;
|
||||||
|
|
||||||
if not find_player(4) then error("minesweeper: no players near") end
|
if not find_player(6) then error("minesweeper: no players near") end
|
||||||
|
|
||||||
self.spam(1)
|
self.spam(1)
|
||||||
t0 = _G.minetest.get_gametime();
|
t0 = _G.minetest.get_gametime();
|
||||||
data = {}; spawnpos = self.spawnpos() -- place mines
|
data = {}; spawnpos = self.spawnpos() -- place mines
|
||||||
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
|
self.listen_punch(spawnpos); -- attach punch listener
|
||||||
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;
|
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
|
||||||
minescount = 0;
|
data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 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
|
minescount = 0;
|
||||||
puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:button808080"})
|
for i = 1,m do for j = 1,n do -- render game
|
||||||
end
|
if data[i] and data[i][j] == 1 then minescount = minescount + 1 end
|
||||||
end end
|
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+1,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
|
puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:buttonlight_grey"})
|
||||||
|
end
|
||||||
get_mine_count = function(i,j)
|
end end
|
||||||
if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0
|
puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttondark_green"})
|
||||||
for k = -1,1 do for l = -1,1 do
|
puzzle.set_node({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},{name = "basic_robot:buttonblue"})
|
||||||
if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end
|
|
||||||
end end
|
get_mine_count = function(i,j)
|
||||||
return count
|
if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0
|
||||||
end
|
for k = -1,1 do for l = -1,1 do
|
||||||
chk_mines = function()
|
if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end
|
||||||
local count = minescount;
|
end end
|
||||||
for i=1,m do for j=1,n do
|
return count
|
||||||
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
|
end
|
||||||
count=count-1
|
chk_mines = function()
|
||||||
end
|
local count = minescount;
|
||||||
end end
|
for i=1,m do for j=1,n do
|
||||||
return count
|
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
|
||||||
end
|
count=count-1
|
||||||
say("minesweeper " .. m .. "x" ..n .. " with " .. minescount .. " mines ")
|
end
|
||||||
self.label("find all hidden mines! mark mine by standing on top of block and punch,\notherwise it will uncover the block (and possibly explode).")
|
end end
|
||||||
|
return count
|
||||||
end
|
end
|
||||||
|
say("minesweeper " .. m .. "x" ..n .. " with " .. minescount .. " mines ")
|
||||||
event = keyboard.get();
|
self.label("find all hidden mines! mark mine by standing on top of block and punch,\notherwise it will uncover the block (and possibly explode).")
|
||||||
if event then
|
|
||||||
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
end
|
||||||
if x<1 or x>m or z<1 or z>n then
|
|
||||||
if x == 0 and z == 1 then
|
event = keyboard.get();
|
||||||
local count = chk_mines();
|
if event then
|
||||||
if count == 0 then
|
|
||||||
t0 = _G.minetest.get_gametime() - t0;
|
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
|
||||||
say("congratulations! " .. event.puncher .. " discovered all mines in " .. t0 .. " s")
|
if x<1 or x>m or z<1 or z>n then
|
||||||
_G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.ItemStack("default:gold_ingot "..reward)) -- diamond reward
|
if x == 1 and z == 0 then
|
||||||
else
|
local count = chk_mines();
|
||||||
reward = reward*(1-(count/minescount))^(1.5); reward = math.floor(reward);
|
if count>minescount/2 then
|
||||||
say("FAIL! " .. count .. " mines remaining. You get " .. reward .. " gold for found mines")
|
say("fail, more than 50% of mines remaining ")
|
||||||
_G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.ItemStack("default:gold_ingot "..reward)) -- diamond reward
|
return
|
||||||
end
|
end
|
||||||
self.remove()
|
if count == 0 then
|
||||||
end
|
t0 = _G.minetest.get_gametime() - t0;
|
||||||
else --if event.type == 2 then
|
say("congratulations! " .. event.puncher .. " discovered all mines in " .. t0 .. " s")
|
||||||
local ppos = player.getpos(event.puncher)
|
_G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.ItemStack("default:gold_ingot "..reward)) -- diamond reward
|
||||||
if ppos and math.abs(ppos.x-event.x)<0.5 and math.abs(ppos.z-event.z)<0.5 then -- just mark mine
|
else
|
||||||
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then
|
reward = reward*(1-(count/minescount))^(1.5); reward = math.floor(reward);
|
||||||
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:button808080"})
|
say("FAIL! " .. count .. " mines remaining. You get " .. reward .. " gold for found mines")
|
||||||
else
|
_G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.ItemStack("default:gold_ingot "..reward)) -- diamond reward
|
||||||
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonFF8080"})
|
end
|
||||||
end
|
self.remove()
|
||||||
else
|
end
|
||||||
if data[x] and data[x][z]==1 then
|
else --if event.type == 2 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"});
|
local ppos = player.getpos(event.puncher)
|
||||||
local player_ = puzzle.get_player(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
|
||||||
player_:setpos({x=spawnpos.x-1,y=spawnpos.y+1,z=spawnpos.z-1});
|
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:buttonlight_grey" then
|
||||||
self.remove()
|
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonlight_grey"})
|
||||||
else
|
else
|
||||||
local count = get_mine_count(x,z);
|
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonred"})
|
||||||
if count == 0 then puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button80FF80"})
|
end
|
||||||
else puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button"..count}) end
|
else
|
||||||
end
|
if data[x] and data[x][z]==1 then
|
||||||
end
|
say("boom! "..event.puncher .. " is dead ");puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttonred"});
|
||||||
end
|
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:buttongreen"})
|
||||||
|
else puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button"..count}) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -1,264 +1,256 @@
|
||||||
-- nonogram game, created in 1hr 40 min by rnd
|
-- nonogram game, created in 1hr 40 min by rnd
|
||||||
|
|
||||||
-- INIT
|
-- INIT
|
||||||
if not grid then
|
if not grid then
|
||||||
n=6
|
n=9
|
||||||
solved = false -- do we render solution or blank?
|
solved = false -- do we render solution or blank?
|
||||||
-- _G.math.randomseed(3)
|
-- _G.math.randomseed(3)
|
||||||
|
|
||||||
self.spam(1)
|
self.spam(1)
|
||||||
function get_score_from_string(score)
|
|
||||||
--say(score)
|
|
||||||
local scores = {};
|
init_score = function(levels, tops, default_value) -- [level] = {{name,score}, ...}
|
||||||
local j=1; --j k l
|
local data = {} for i = 1, levels do data[i] = {} for j = 1,tops do data[i][j] = {"-",default_value} end end return data
|
||||||
for i=0,5 do -- 0 - 999 1 - 999 2 - 999 3 - 999 4 - 999 5 - 999
|
end
|
||||||
j = string.find(score," ", j+1);
|
|
||||||
local k = string.find(score," ", j+1);
|
add_score = function(data,name,score,level)
|
||||||
local l = string.find(score," ", k+1);
|
local datal = data[level]; local tops = #datal; local j;for i = 1,tops do
|
||||||
if i==5 then l = string.len(score)+1 end
|
if score>datal[i][2] then j = i break end end
|
||||||
scores[i] = {string.sub(score,j+1,k-1),tonumber(string.sub(score,k+1,l-1))};
|
if not j then return false end; for i=tops,j+1,-1 do datal[i][1] = datal[i-1][1];datal[i][2] = datal[i-1][2] end
|
||||||
j=l
|
datal[j] = {name,score} return true
|
||||||
end
|
end
|
||||||
return scores
|
|
||||||
end
|
_,scores_string = book.read(1); scores = minetest.deserialize(scores_string)
|
||||||
|
if not scores then scores = init_score(n-1,n-1,-999) end -- 5 levels, 5 top records
|
||||||
if not rom.score then _,rom.score = book.read(1) end
|
|
||||||
if not rom.score then rom.score = "0 - 999 1 - 999 2 - 999 3 - 999 4 - 999 5 - 999" end
|
t0 = _G.minetest.get_gametime()
|
||||||
highscore = get_score_from_string(rom.score)
|
local intro ="numbers at beginning of each row (coloumn) tell how many\nred blocks are together in each row ( coloumn )." ..
|
||||||
--self.label(string.gsub(_G.dump(highscore), "\n",""))
|
"\npunch gray blocks to toggle them and reveal hidden red blocks.\npunch green to check solution. If you give up punch blue.";
|
||||||
|
self.label(intro)
|
||||||
function get_score_string(scores)
|
|
||||||
local out = ""
|
grid = {}
|
||||||
for i = 0,5 do
|
spawnpos = self.spawnpos();
|
||||||
out = out .. i .. " " ..
|
offsetx = 10 - math.ceil(n/2); offsetz = math.floor(n/2);
|
||||||
scores[i][1] .. " " ..
|
spawnpos.x = spawnpos.x - offsetx; spawnpos.z = spawnpos.z - offsetz;
|
||||||
scores[i][2] .. " "
|
spawnpos.y = spawnpos.y+3
|
||||||
end
|
|
||||||
return out
|
for i=1,n do
|
||||||
end
|
grid[i]={};
|
||||||
|
for j=1,n do
|
||||||
t0 = _G.minetest.get_gametime()
|
grid[i][j]=math.random(2)-1
|
||||||
local intro ="numbers at beginning of each row (coloumn) tell how many\nred blocks are together in each row ( coloumn )." ..
|
end
|
||||||
"\npunch gray blocks to toggle them and reveal hidden red blocks.\npunch green to check solution. If you give up punch blue.";
|
end
|
||||||
self.label(intro)
|
|
||||||
|
getcounts = function(grid)
|
||||||
grid = {}
|
local rowdata = {};
|
||||||
spawnpos = self.spawnpos();
|
for i=1,n do
|
||||||
offsetx = 10 - math.ceil(n/2); offsetz = math.floor(n/2);
|
rowdata[i]={}; local data = rowdata[i];
|
||||||
spawnpos.x = spawnpos.x - offsetx; spawnpos.z = spawnpos.z - offsetz;
|
local s=0;local c=0;
|
||||||
spawnpos.y = spawnpos.y+3
|
for j = 1, n do
|
||||||
|
if s == 0 and grid[i][j]==1 then s=1;c=0 end
|
||||||
for i=1,n do
|
if s == 1 then
|
||||||
grid[i]={};
|
if grid[i][j]==1 then
|
||||||
for j=1,n do
|
c=c+1
|
||||||
grid[i][j]=math.random(2)-1
|
if j == n then data[#data+1]=c end
|
||||||
end
|
else
|
||||||
end
|
data[#data+1]=c; s=0
|
||||||
|
end
|
||||||
getcounts = function(grid)
|
|
||||||
local rowdata = {};
|
end
|
||||||
for i=1,n do
|
end
|
||||||
rowdata[i]={}; local data = rowdata[i];
|
end
|
||||||
local s=0;local c=0;
|
local coldata = {};
|
||||||
for j = 1, n do
|
for j=1,n do
|
||||||
if s == 0 and grid[i][j]==1 then s=1;c=0 end
|
coldata[j]={}; local data = coldata[j];
|
||||||
if s == 1 then
|
local s=0;local c=0;
|
||||||
if grid[i][j]==1 then
|
for i = 1, n do
|
||||||
c=c+1
|
if s == 0 and grid[i][j]==1 then s=1;c=0 end
|
||||||
if j == n then data[#data+1]=c end
|
if s == 1 then
|
||||||
else
|
if grid[i][j]==1 then
|
||||||
data[#data+1]=c; s=0
|
c=c+1
|
||||||
end
|
if i == n then data[#data+1]=c end
|
||||||
|
else
|
||||||
end
|
data[#data+1]=c; s=0
|
||||||
end
|
end
|
||||||
end
|
|
||||||
local coldata = {};
|
end
|
||||||
for j=1,n do
|
end
|
||||||
coldata[j]={}; local data = coldata[j];
|
end
|
||||||
local s=0;local c=0;
|
return rowdata,coldata
|
||||||
for i = 1, n do
|
end
|
||||||
if s == 0 and grid[i][j]==1 then s=1;c=0 end
|
|
||||||
if s == 1 then
|
read_field = function()
|
||||||
if grid[i][j]==1 then
|
local grid = {};
|
||||||
c=c+1
|
for i = 1, n do
|
||||||
if i == n then data[#data+1]=c end
|
grid[i]={};
|
||||||
else
|
for j = 1,n do
|
||||||
data[#data+1]=c; s=0
|
local typ = keyboard.read({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+i});
|
||||||
end
|
if typ == "basic_robot:buttonlight_grey" then grid[i][j] = 0 else grid[i][j] = 1 end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
return grid
|
||||||
end
|
end
|
||||||
return rowdata,coldata
|
|
||||||
end
|
rowdata,coldata = getcounts(grid)
|
||||||
|
|
||||||
read_field = function()
|
check_solution = function()
|
||||||
local grid = {};
|
local rdata,cdata;
|
||||||
for i = 1, n do
|
rdata,cdata = getcounts(read_field())
|
||||||
grid[i]={};
|
for i = 1,#rdata do
|
||||||
for j = 1,n do
|
if #rdata[i]~=#rowdata[i] then return false end
|
||||||
local typ = keyboard.read({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+i});
|
for j = 1, #rdata[i] do
|
||||||
if typ == "basic_robot:button808080" then grid[i][j] = 0 else grid[i][j] = 1 end
|
if rdata[i][j]~=rowdata[i][j] then return false end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return grid
|
|
||||||
end
|
for i = 1,#cdata do
|
||||||
|
if #cdata[i]~=#coldata[i] then return false end
|
||||||
rowdata,coldata = getcounts(grid)
|
for j = 1, #rdata[i] do
|
||||||
|
if cdata[i][j]~=coldata[i][j] then return false end
|
||||||
check_solution = function()
|
end
|
||||||
local rdata,cdata;
|
end
|
||||||
rdata,cdata = getcounts(read_field())
|
return true
|
||||||
for i = 1,#rdata do
|
end
|
||||||
if #rdata[i]~=#rowdata[i] then return false end
|
|
||||||
for j = 1, #rdata[i] do
|
get_difficulty = function()
|
||||||
if rdata[i][j]~=rowdata[i][j] then return false end
|
local easy = 0;
|
||||||
end
|
for k = 1, n do
|
||||||
end
|
local sum=0
|
||||||
|
for i = 1,#rowdata[k]-1 do
|
||||||
for i = 1,#cdata do
|
sum = sum + rowdata[k][i]+1;
|
||||||
if #cdata[i]~=#coldata[i] then return false end
|
end
|
||||||
for j = 1, #rdata[i] do
|
if #rowdata[k]>0 then sum = sum + rowdata[k][#rowdata[k]] else sum = n end
|
||||||
if cdata[i][j]~=coldata[i][j] then return false end
|
if sum == n then easy = easy + 1 end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
return true
|
for k = 1, n do
|
||||||
end
|
local sum=0
|
||||||
|
for i = 1,#coldata[k]-1 do
|
||||||
get_difficulty = function()
|
sum = sum + coldata[k][i]+1;
|
||||||
local easy = 0;
|
end
|
||||||
for k = 1, n do
|
if #coldata[k]>0 then sum = sum + coldata[k][#coldata[k]] else sum = n end
|
||||||
local sum=0
|
if sum == n then easy = easy + 1 end
|
||||||
for i = 1,#rowdata[k]-1 do
|
end
|
||||||
sum = sum + rowdata[k][i]+1;
|
easy = n-1-easy;
|
||||||
end
|
if easy < 0 then easy = 0 end
|
||||||
if #rowdata[k]>0 then sum = sum + rowdata[k][#rowdata[k]] else sum = n end
|
return easy
|
||||||
if sum == n then easy = easy + 1 end
|
end
|
||||||
end
|
|
||||||
|
-- render game
|
||||||
for k = 1, n do
|
for i=1,n do
|
||||||
local sum=0
|
for j =1,n do
|
||||||
for i = 1,#coldata[k]-1 do
|
keyboard.set({x=spawnpos.x-n+j,y=spawnpos.y,z=spawnpos.z+i},0) -- clear
|
||||||
sum = sum + coldata[k][i]+1;
|
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+2*n-i+1},0) -- clear
|
||||||
end
|
local typ;
|
||||||
if #coldata[k]>0 then sum = sum + coldata[k][#coldata[k]] else sum = n end
|
if grid[j][i]==0 then typ = 13 else typ = 2 end
|
||||||
if sum == n then easy = easy + 1 end
|
if not solved then typ = 13 end
|
||||||
end
|
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ) --board
|
||||||
easy = 5-easy;
|
end
|
||||||
if easy < 0 then easy = 0 end
|
end
|
||||||
return easy
|
|
||||||
end
|
--render counts rows
|
||||||
|
for i=1,n do
|
||||||
-- render game
|
length = #rowdata[i]
|
||||||
for i=1,n do
|
for k = 1,length do
|
||||||
for j =1,n do
|
keyboard.set({x=spawnpos.x-length+k,y=spawnpos.y,z=spawnpos.z+i},rowdata[i][k]+17)
|
||||||
keyboard.set({x=spawnpos.x-n+j,y=spawnpos.y,z=spawnpos.z+i},0) -- clear
|
end
|
||||||
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+2*n-i+1},0) -- clear
|
end
|
||||||
local typ;
|
--render counts coloumns
|
||||||
if grid[j][i]==0 then typ = 2 else typ = 3 end
|
for j=1,n do
|
||||||
if not solved then typ = 2 end
|
length = #coldata[j]
|
||||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ) --board
|
for k = 1,length do
|
||||||
end
|
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+k+n},coldata[j][k]+17)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
--render counts rows
|
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},9) -- game check button
|
||||||
for i=1,n do
|
keyboard.set({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},7) -- game check button
|
||||||
length = #rowdata[i]
|
|
||||||
for k = 1,length do
|
local players = find_player(6,spawnpos)
|
||||||
keyboard.set({x=spawnpos.x-length+k,y=spawnpos.y,z=spawnpos.z+i},rowdata[i][k]+7)
|
if not players then error("nonogram: no players near") end
|
||||||
end
|
local pname = players[1];
|
||||||
end
|
|
||||||
--render counts coloumns
|
self.listen_punch(self.pos()) -- attach punch listener
|
||||||
for j=1,n do
|
|
||||||
length = #coldata[j]
|
--self.label()
|
||||||
for k = 1,length do
|
|
||||||
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+k+n},coldata[j][k]+7)
|
--self.label(string.gsub(_G.dump(read_field()),"\n","") )
|
||||||
end
|
difficulty = get_difficulty()
|
||||||
end
|
reward = 0; limit = 0;
|
||||||
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
|
if difficulty == 5 then limit = 120 reward = 10
|
||||||
|
elseif difficulty == 4 then limit = 115 reward = 9 -- 60s
|
||||||
local players = find_player(4,spawnpos)
|
elseif difficulty == 3 then limit = 100 reward = 8
|
||||||
if not players then error("minesweeper: no players near") end
|
elseif difficulty == 2 then limit = 80 reward = 7
|
||||||
local pname = players[1];
|
elseif difficulty <= 1 then limit = 70 reward = 6
|
||||||
|
end
|
||||||
|
if not scores[difficulty] then scores[difficulty] = {{"-",-999}} end
|
||||||
--self.label()
|
if not scores[difficulty][1] then scores[difficulty][1] = {"-",-999} end
|
||||||
|
|
||||||
--self.label(string.gsub(_G.dump(read_field()),"\n","") )
|
minetest.chat_send_player(pname, "nonogram difficulty " .. difficulty .. ". you will get " .. reward .. " gold if you solve it in faster than " .. limit .."s" ..
|
||||||
difficulty = get_difficulty()
|
". Current record " .. -scores[difficulty][1][2] .. " by " .. scores[difficulty][1][1])
|
||||||
reward = 0; limit = 0;
|
|
||||||
|
|
||||||
if difficulty == 5 then limit = 120 reward = 10
|
end
|
||||||
elseif difficulty == 4 then limit = 115 reward = 9 -- 60s
|
|
||||||
elseif difficulty == 3 then limit = 100 reward = 8
|
event = keyboard.get()
|
||||||
elseif difficulty == 2 then limit = 80 reward = 7
|
if event then
|
||||||
elseif difficulty <= 1 then limit = 70 reward = 6
|
if event.y == spawnpos.y and event.z == spawnpos.z then
|
||||||
end
|
if event.x == spawnpos.x+1 then -- check solution
|
||||||
minetest.chat_send_player(pname, "nonogram difficulty " .. difficulty .. ". you will get " .. reward .. " gold if you solve it in faster than " .. limit .."s" ..
|
if check_solution() then
|
||||||
". Current record " .. highscore[difficulty][2] .. " by " .. highscore[difficulty][1])
|
t = _G.minetest.get_gametime(); t = t- t0;
|
||||||
|
local msg = "";
|
||||||
end
|
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},2)
|
||||||
|
msg = n .. "x" .. n .. " nonogram (difficuly " .. difficulty .. ") solved by " .. event.puncher .. " in " .. t .. " seconds. "
|
||||||
event = keyboard.get()
|
|
||||||
if event then
|
if t < limit then
|
||||||
if event.y == spawnpos.y and event.z == spawnpos.z then
|
msg = msg .. " He gets " .. reward .. " gold for quick solve.";
|
||||||
if event.x == spawnpos.x+1 then -- check solution
|
else
|
||||||
if check_solution() then
|
reward = reward*2*(1-2*(t-limit)/limit)/2; if reward<0 then reward = 0 end
|
||||||
t = _G.minetest.get_gametime(); t = t- t0;
|
reward = math.floor(reward);
|
||||||
local msg = "";
|
msg = msg .. " Your time was more than " .. limit .. ", you get " .. reward .. " gold ";
|
||||||
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},2)
|
end
|
||||||
msg = n .. "x" .. n .. " nonogram (difficuly " .. difficulty .. ") solved by " .. event.puncher .. " in " .. t .. " seconds. "
|
|
||||||
|
-- highscore
|
||||||
if t < limit then
|
if add_score(scores,event.puncher,-t,difficulty) then
|
||||||
msg = msg .. " He gets " .. reward .. " gold for quick solve.";
|
say("nonogram difficulty " .. difficulty .. ": new record " .. t .. " s !")
|
||||||
else
|
local sdata = scores[difficulty];
|
||||||
reward = reward*2*(1-2*(t-limit)/limit)/2; if reward<0 then reward = 0 end
|
local out = {"TOP 5 PLAYERS/TIMES: "}; for i=1,#sdata do out[#out+1] = sdata[i][1] .. " " .. -sdata[i][2].."," end say(table.concat(out," "))
|
||||||
reward = math.floor(reward);
|
book.write(1,"scores", minetest.serialize(scores))
|
||||||
msg = msg .. " Your time was more than " .. limit .. ", you get " .. reward .. " gold ";
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- highscore
|
if reward>0 then
|
||||||
if t<highscore[difficulty][2] then
|
local player = _G.minetest.get_player_by_name(event.puncher);
|
||||||
say("nonogram: new record " .. t .. " s ! old record " .. highscore[difficulty][2] .. "s by " .. highscore[difficulty][1])
|
if player then
|
||||||
highscore[difficulty] = {event.puncher, t}
|
local inv = player:get_inventory();
|
||||||
rom.score = get_score_string(highscore)
|
inv:add_item("main",_G.ItemStack("default:gold_ingot " .. reward))
|
||||||
book.write(1,"scores", rom.score)
|
end
|
||||||
end
|
end
|
||||||
|
minetest.chat_send_player(event.puncher,msg)
|
||||||
if reward>0 then
|
|
||||||
local player = _G.minetest.get_player_by_name(event.puncher);
|
self.remove()
|
||||||
if player then
|
|
||||||
local inv = player:get_inventory();
|
else self.label("FAIL") end
|
||||||
inv:add_item("main",_G.ItemStack("default:gold_ingot " .. reward))
|
elseif event.x == spawnpos.x+2 then -- solve
|
||||||
end
|
minetest.chat_send_player(event.puncher,"you gave up on game, displaying solution")
|
||||||
end
|
for i=1,n do
|
||||||
minetest.chat_send_player(event.puncher,msg)
|
for j =1,n do
|
||||||
|
local typ;
|
||||||
self.remove()
|
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)
|
||||||
else self.label("FAIL") end
|
end
|
||||||
elseif event.x == spawnpos.x+2 then -- solve
|
end
|
||||||
minetest.chat_send_player(event.puncher,"you gave up on game, displaying solution")
|
self.remove()
|
||||||
for i=1,n do
|
end
|
||||||
for j =1,n do
|
else
|
||||||
local typ;
|
local i = event.x-spawnpos.x;local j = event.z-spawnpos.z;
|
||||||
if grid[j][i]==0 then typ = 2 else typ = 3 end
|
if i>0 and i<=n and j>0 and j<=n then
|
||||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ)
|
local typ = keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j});
|
||||||
end
|
local newtyp;
|
||||||
end
|
if typ ~= "basic_robot:buttonlight_grey" then newtyp = 13
|
||||||
self.remove()
|
else newtyp = 2
|
||||||
end
|
end
|
||||||
else
|
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},newtyp);
|
||||||
local i = event.x-spawnpos.x;local j = event.z-spawnpos.z;
|
end
|
||||||
if i>0 and i<=n and j>0 and j<=n then
|
end
|
||||||
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
|
|
||||||
else newtyp = 2
|
|
||||||
end
|
|
||||||
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},newtyp);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
|
@ -1,112 +1,112 @@
|
||||||
-- paint canvas by rnd, 2018
|
-- paint canvas by rnd, 2018
|
||||||
if not init then
|
if not init then
|
||||||
colors = {
|
colors = {
|
||||||
"black","blue","brown","cyan","dark_green","dark_grey","green","grey",
|
"white","yellow","orange","red","magenta","purple","blue","cyan",
|
||||||
"magenta","orange","pink","red","violet","white","yellow"
|
"green","dark_green","brown","tan","light_grey","medium_grey","dark_grey","black"
|
||||||
}
|
}
|
||||||
invcolors = {}; for i = 1,#colors do invcolors[colors[i]] = i end
|
invcolors = {}; for i = 1,#colors do invcolors[colors[i]] = i end
|
||||||
|
|
||||||
color = 1;
|
color = invcolors["black"];
|
||||||
size = 16;
|
size = 16;
|
||||||
|
|
||||||
init = true
|
init = true
|
||||||
|
|
||||||
local ent = _G.basic_robot.data[self.name()].obj:get_luaentity();
|
local ent = _G.basic_robot.data[self.name()].obj:get_luaentity();
|
||||||
ent.timestep = 0.5
|
ent.timestep = 0.125
|
||||||
|
|
||||||
players = find_player(5); if not players then self.remove() end
|
players = find_player(5); if not players then self.remove() end
|
||||||
player = _G.minetest.get_player_by_name(players[1])
|
player = _G.minetest.get_player_by_name(players[1])
|
||||||
self.label("-> " .. players[1])
|
self.label("-> " .. players[1])
|
||||||
|
|
||||||
spos = self.spawnpos(); spos.y=spos.y+1;
|
spos = self.spawnpos(); spos.y=spos.y+1;
|
||||||
|
canvasn = "basic_robot:buttonwhite"
|
||||||
canvasn = "wool:white"
|
reset_canvas = function()
|
||||||
reset_canvas = function()
|
for i = 1, size do
|
||||||
for i = 1, size do
|
for j = 1, size do
|
||||||
for j = 1, size do
|
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = canvasn})
|
||||||
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = canvasn})
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
reset_canvas()
|
||||||
reset_canvas()
|
|
||||||
|
save_image = function()
|
||||||
save_image = function()
|
local ret = {};
|
||||||
local ret = {};
|
for i = 1, size do
|
||||||
for i = 1, size do
|
for j = 1, size do
|
||||||
for j = 1, size do
|
local nname = string.sub(minetest.get_node({x=spos.x +i , y = spos.y + j, z = spos.z }).name,19)
|
||||||
local nname = string.sub(minetest.get_node({x=spos.x +i , y = spos.y + j, z = spos.z }).name,6)
|
local pcolor = invcolors[nname] or 1;
|
||||||
local pcolor = invcolors[nname] or 1;
|
ret[#ret+1]= string.char(96+pcolor)
|
||||||
ret[#ret+1]= string.char(96+pcolor)
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
return table.concat(ret,"")
|
return table.concat(ret,"")
|
||||||
end
|
end
|
||||||
|
|
||||||
load_image = function(image)
|
load_image = function(image)
|
||||||
if not image then return end
|
if not image then return end
|
||||||
local ret = {}; local k = 0;
|
local ret = {}; local k = 0;
|
||||||
for i = 1, size do
|
for i = 1, size do
|
||||||
for j = 1, size do
|
for j = 1, size do
|
||||||
k=k+1;
|
k=k+1;
|
||||||
local pcolor = colors[string.byte(image,k)-96] or "black";
|
local pcolor = colors[string.byte(image,k)-96] or "black";
|
||||||
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = "wool:"..pcolor})
|
minetest.set_node({x=spos.x +i , y = spos.y + j, z = spos.z },{name = "basic_robot:button"..pcolor})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--draw buttons
|
--draw buttons
|
||||||
for i = 1,#colors do
|
for i = 1,#colors do
|
||||||
minetest.set_node({x=spos.x +i , y = spos.y , z = spos.z },{name = "wool:"..colors[i]})
|
minetest.set_node({x=spos.x +i , y = spos.y , z = spos.z },{name = "basic_robot:button"..colors[i]})
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.set_node({x=spos.x +1 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_83"})
|
minetest.set_node({x=spos.x +1 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_83"})
|
||||||
minetest.set_node({x=spos.x +2 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_76"})
|
minetest.set_node({x=spos.x +2 , y = spos.y-1 , z = spos.z },{name = "basic_robot:button_76"})
|
||||||
|
|
||||||
|
|
||||||
vn = {x=0,y=0,z=1};
|
vn = {x=0,y=0,z=1};
|
||||||
T0 = {x=spos.x+0.5,y=spos.y+0.5,z=spos.z-0.5*vn.z};
|
T0 = {x=spos.x+0.5,y=spos.y+0.5,z=spos.z-0.5*vn.z};
|
||||||
|
|
||||||
get_intersect = function(vn, T0, p, v)
|
get_intersect = function(vn, T0, p, v)
|
||||||
local a = (T0.x-p.x)*vn.x + (T0.y-p.y)*vn.y + (T0.z-p.z)*vn.z;
|
local a = (T0.x-p.x)*vn.x + (T0.y-p.y)*vn.y + (T0.z-p.z)*vn.z;
|
||||||
local b = vn.x*v.x + vn.y*v.y + vn.z*v.z
|
local b = vn.x*v.x + vn.y*v.y + vn.z*v.z
|
||||||
if b<=0 then return nil end
|
if b<=0 then return nil end
|
||||||
if a<=0 then return nil end
|
if a<=0 then return nil end
|
||||||
local t = a / b
|
local t = a / b
|
||||||
return {x = p.x+v.x*t, y= p.y+v.y*t, z = p.z+v.z*t}
|
return {x = p.x+v.x*t, y= p.y+v.y*t, z = p.z+v.z*t}
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if player:get_player_control().LMB then -- player interacts with 'virtual canvas gui'
|
if player:get_player_control().LMB then -- player interacts with 'virtual canvas gui'
|
||||||
local v = player:get_look_dir();
|
local v = player:get_look_dir();
|
||||||
local p = player:get_pos(); p.y = p.y + 1.5
|
local p = player:get_pos(); p.y = p.y + 1.5
|
||||||
local c = get_intersect(vn,T0,p,v);
|
local c = get_intersect(vn,T0,p,v);
|
||||||
if c then
|
if c then
|
||||||
|
|
||||||
local x = c.x - T0.x; local y = c.y - T0.y
|
local x = c.x - T0.x; local y = c.y - T0.y
|
||||||
if x>0 and x<size and y>-2 and y<size then
|
if x>0 and x<size and y>-2 and y<size then
|
||||||
if y>0 then -- above: painting
|
if y>0 then -- above: painting
|
||||||
c.z = c.z+0.5
|
c.z = c.z+0.5
|
||||||
minetest.set_node(c, {name = "wool:" .. colors[color]})
|
minetest.set_node(c, {name = "basic_robot:button" .. colors[color]})
|
||||||
elseif y>-1 then -- color selection
|
elseif y>-1 then -- color selection
|
||||||
x = 1+math.floor(x)
|
x = 1+math.floor(x)
|
||||||
if colors[x] then
|
if colors[x] then
|
||||||
color = x;
|
color = x;
|
||||||
self.label(colors[x])
|
self.label(colors[x])
|
||||||
end
|
end
|
||||||
else -- save,load button row
|
else -- save,load button row
|
||||||
x = 1+math.floor(x)
|
x = 1+math.floor(x)
|
||||||
if x==1 then
|
if x==1 then
|
||||||
self.label("SAVED.")
|
self.label("SAVED.")
|
||||||
book.write(1,"ROBOT_IMAGE",save_image())
|
book.write(1,"ROBOT_IMAGE",save_image())
|
||||||
elseif x==2 then
|
elseif x==2 then
|
||||||
local _,image = book.read(1)
|
local _,image = book.read(1)
|
||||||
load_image(image);
|
load_image(image);
|
||||||
self.label("LOADED.")
|
self.label("LOADED.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -0,0 +1,221 @@
|
||||||
|
-- Rubik Cube
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
self.listen_punch(self.pos())
|
||||||
|
pname = find_player(5); if not pname then say("no players!");self.remove() end; pname = pname[1];
|
||||||
|
player = minetest.get_player_by_name(pname)
|
||||||
|
say("rubik cube. rotation is indicated by your view direction")
|
||||||
|
|
||||||
|
n=3;
|
||||||
|
-- top left first
|
||||||
|
|
||||||
|
yz1 = { -- size n^2, side looking toward x-
|
||||||
|
7,1,8,
|
||||||
|
1,1,1,
|
||||||
|
9,1,1
|
||||||
|
}
|
||||||
|
|
||||||
|
yz2 = { -- size n^2, side looking toward x+
|
||||||
|
7,2,8,
|
||||||
|
2,2,2,
|
||||||
|
9,2,2
|
||||||
|
}
|
||||||
|
|
||||||
|
xy1 = { -- size n^2, side looking toward z-
|
||||||
|
7,3,8,
|
||||||
|
3,3,3,
|
||||||
|
9,3,3
|
||||||
|
}
|
||||||
|
|
||||||
|
xy2 = { -- size n^2, side looking toward z+
|
||||||
|
7,4,8,
|
||||||
|
4,4,4,
|
||||||
|
9,4,4,
|
||||||
|
}
|
||||||
|
|
||||||
|
xz1 = { -- size n^2, side looking toward y-
|
||||||
|
7,5,8,
|
||||||
|
5,5,5,
|
||||||
|
9,5,5,
|
||||||
|
}
|
||||||
|
|
||||||
|
xz2 = { -- size n^2, side looking toward y+
|
||||||
|
7,6,8,
|
||||||
|
6,6,6,
|
||||||
|
9,6,6,
|
||||||
|
}
|
||||||
|
|
||||||
|
surfdata = {
|
||||||
|
["yz1"]={
|
||||||
|
rotations = {
|
||||||
|
[0] = "face cw",
|
||||||
|
[1] = "face ccw",
|
||||||
|
[2] = "horizontal +",
|
||||||
|
[3] = "horizontal -",
|
||||||
|
[4] = "vertical +",
|
||||||
|
[5] = "vertical -",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
blocks = {
|
||||||
|
"basic_robot:button808080",
|
||||||
|
"basic_robot:buttonFF8080",
|
||||||
|
"basic_robot:button80FF80",
|
||||||
|
"basic_robot:button8080FF",
|
||||||
|
"basic_robot:buttonFFFF80",
|
||||||
|
"basic_robot:buttonFFFFFF",
|
||||||
|
"basic_robot:button_48", --7
|
||||||
|
"basic_robot:button_49", --8
|
||||||
|
"basic_robot:button_50", --9
|
||||||
|
}
|
||||||
|
|
||||||
|
render_cube = function()
|
||||||
|
local p = self.pos();
|
||||||
|
for y=1,n do
|
||||||
|
for z=1,n do
|
||||||
|
minetest.swap_node({x=p.x+1,y=p.y+y+1,z=p.z+z},{name = blocks[yz1[n*(y-1)+z]]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for y=1,n do
|
||||||
|
for z=1,n do
|
||||||
|
minetest.swap_node({x=p.x+n+2,y=p.y+y+1,z=p.z+z},{name = blocks[yz2[n*(y-1)+z]]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for x=1,n do
|
||||||
|
for y=1,n do
|
||||||
|
minetest.swap_node({x=p.x+x+1,y=p.y+y+1,z=p.z},{name = blocks[xy1[n*(x-1)+y]]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for x=1,n do
|
||||||
|
for y=1,n do
|
||||||
|
minetest.swap_node({x=p.x+x+1,y=p.y+y+1,z=p.z+n+1},{name = blocks[xy2[n*(x-1)+y]]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for x=1,n do
|
||||||
|
for z=1,n do
|
||||||
|
minetest.swap_node({x=p.x+x+1,y=p.y+1,z=p.z+z},{name = blocks[xz1[n*(x-1)+z]]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for x=1,n do
|
||||||
|
for z=1,n do
|
||||||
|
minetest.swap_node({x=p.x+x+1,y=p.y+n+2,z=p.z+z},{name = blocks[xz2[n*(x-1)+z]]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
rotccw = function(tab)
|
||||||
|
local newtab = {}
|
||||||
|
local n = (#tab)^0.5
|
||||||
|
for i = 1,n do
|
||||||
|
for j = 1,n do
|
||||||
|
newtab[(i-1)*n+j] = tab[(j-1)*n+n-i+1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return newtab
|
||||||
|
end
|
||||||
|
|
||||||
|
rotcw = function(tab)
|
||||||
|
local newtab = {}
|
||||||
|
local n = (#tab)^0.5
|
||||||
|
for i = 1,n do
|
||||||
|
for j = 1,n do
|
||||||
|
newtab[(j-1)*n+n-i+1] = tab[(i-1)*n+j]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return newtab
|
||||||
|
end
|
||||||
|
|
||||||
|
viewlim = 0.9; --how close to perpendicular need to look to rotate face
|
||||||
|
p = self.pos();
|
||||||
|
render_cube()
|
||||||
|
end
|
||||||
|
|
||||||
|
event = keyboard.get()
|
||||||
|
if event then
|
||||||
|
-- rotate depending where player looks, if he looks close to normal to surface rotate cw or ccw
|
||||||
|
local view = player:get_look_dir()
|
||||||
|
-- which way? face or horizontal or vertical?
|
||||||
|
local rot = 0; -- rotation mode
|
||||||
|
local face = "";
|
||||||
|
local x=1;local y=1;
|
||||||
|
|
||||||
|
if event.x == p.x+1 then
|
||||||
|
face= "yz1"
|
||||||
|
if math.abs(view.x)>viewlim then
|
||||||
|
rot = 0; -- face cw
|
||||||
|
yz1 = rotcw(yz1); -- face cw rotate
|
||||||
|
--slice x=1 rotate:
|
||||||
|
--[[{
|
||||||
|
xz2,row 1,rev
|
||||||
|
xy1,row 1,rev
|
||||||
|
xz1,row 1,ord
|
||||||
|
xy2,col 3,ord
|
||||||
|
|
||||||
|
}
|
||||||
|
note this same rotation can be reused for faces xz1,xy1,xz1,xy2
|
||||||
|
|
||||||
|
maybe:
|
||||||
|
|
||||||
|
rotslice(
|
||||||
|
{xz2,1=row mode, 1 = row index, -1 = reverse},
|
||||||
|
{xy1,1, 1, -1},
|
||||||
|
{xz1,1, 1, 1 = ordinary},
|
||||||
|
{xy2,2=col mode,3 = col index, 1}
|
||||||
|
)
|
||||||
|
|
||||||
|
--]]
|
||||||
|
elseif math.abs(view.y)<math.abs(view.z) then -- horizontal
|
||||||
|
if view.z>0 then rot = 2 else rot = 3 end
|
||||||
|
else
|
||||||
|
if view.y>0 then rot = 4 else rot = 5 end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.label("face: " .. face ..", rotation: " .. surfdata[face].rotations[rot])
|
||||||
|
|
||||||
|
render_cube()
|
||||||
|
elseif event.x == p.x+n+2 then
|
||||||
|
self.label("yz2")
|
||||||
|
if math.abs(view.x)>viewlim then
|
||||||
|
yz2 = rotccw(yz2);
|
||||||
|
end
|
||||||
|
render_cube()
|
||||||
|
elseif event.z == p.z then
|
||||||
|
self.label("xy1")
|
||||||
|
if math.abs(view.z)>viewlim then
|
||||||
|
xy1 = rotcw(xy1);
|
||||||
|
end
|
||||||
|
render_cube()
|
||||||
|
elseif event.z == p.z+n+1 then
|
||||||
|
self.label("xy2")
|
||||||
|
if math.abs(view.z)>viewlim then
|
||||||
|
xy2 = rotccw(xy2);
|
||||||
|
end
|
||||||
|
render_cube()
|
||||||
|
elseif event.y == p.y+1 then
|
||||||
|
if math.abs(view.y)>viewlim then
|
||||||
|
xz1 = rotccw(xz1);
|
||||||
|
end
|
||||||
|
render_cube()
|
||||||
|
self.label("xz1")
|
||||||
|
elseif event.y == p.y+n+2 then
|
||||||
|
self.label("xz2")
|
||||||
|
if math.abs(view.y)>viewlim then
|
||||||
|
xz2 = rotcw(xz2);
|
||||||
|
end
|
||||||
|
render_cube()
|
||||||
|
end
|
||||||
|
--self.label(serialize(event))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ideas:
|
||||||
|
-- use whole full cube : array with n^3 elements, only border rendered.
|
||||||
|
-- PROS: easy to get slices then and rotate them! CONS: much more memory used for larger cubes
|
||||||
|
--
|
|
@ -1,56 +1,59 @@
|
||||||
-- simple box pushing game, rnd
|
-- simple box pushing game, rnd
|
||||||
|
|
||||||
if not init then
|
if not init then
|
||||||
spos = self.spawnpos(); spos.x = spos.x +5; spos.z = spos.z +5;
|
spos = self.spawnpos(); spos.x = spos.x +5; spos.z = spos.z +5;
|
||||||
|
|
||||||
for i = 1, 2 do
|
for i = 1, 2 do -- set up 4 boxes
|
||||||
for j = 1,2 do
|
for j = 1,2 do
|
||||||
puzzle.set_node({x=spos.x+i,y=spos.y,z=spos.z+j}, {name = "basic_robot:buttonFFFFFF"})
|
puzzle.set_node({x=spos.x+i,y=spos.y,z=spos.z+j}, {name = "basic_robot:buttonwhite"})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
init = true
|
init = true
|
||||||
players = find_player(5);
|
players = find_player(5);
|
||||||
if not players then say("no players nearby") self.remove() end
|
if not players then say("no players nearby") self.remove() end
|
||||||
say("BOX PUSH demo. punch the white box to move it around ")
|
self.label("BOX PUSH demo. punch the white box to move it around.\npush it into blue block to make it disappear.")
|
||||||
|
|
||||||
pushables = {[1] = true} -- button types
|
pushables = {[1] = true} -- button types
|
||||||
canpushnodes = {["air"] = 1, ["basic_robot:button8080FF"] = 2} -- 1 push node, 2 absorb node
|
canpushnodes = {["air"] = 1, ["basic_robot:buttonblue"] = 2} -- 1 push node, 2 absorb node
|
||||||
end
|
|
||||||
|
self.listen_punch(self.pos()) -- robot will now read punch button events in 32x32 box area
|
||||||
event = keyboard.get()
|
end
|
||||||
if event then
|
|
||||||
local boxtype = event.type
|
event = keyboard.get()
|
||||||
if pushables[boxtype] then
|
|
||||||
player = puzzle.get_player(event.puncher)
|
if event then -- there was punch event
|
||||||
local pos = player:getpos();
|
local boxtype = event.type
|
||||||
local boxpos = {x = event.x, y = event.y, z = event.z};
|
if pushables[boxtype] then
|
||||||
local diff = { pos.x-boxpos.x, pos.z-boxpos.z};
|
player = puzzle.get_player(event.puncher)
|
||||||
|
local pos = player:getpos();
|
||||||
local newx,newz
|
local boxpos = {x = event.x, y = event.y, z = event.z};
|
||||||
if math.abs(diff[1])>math.abs(diff[2]) then -- punch in x-direction
|
local diff = { pos.x-boxpos.x, pos.z-boxpos.z};
|
||||||
newx = boxpos.x - (diff[1]>0 and 1 or -1)
|
|
||||||
newz = boxpos.z
|
local newx,newz
|
||||||
else
|
if math.abs(diff[1])>math.abs(diff[2]) then -- punch in x-direction
|
||||||
newx = boxpos.x
|
newx = boxpos.x - (diff[1]>0 and 1 or -1)
|
||||||
newz = boxpos.z - (diff[2]>0 and 1 or -1)
|
newz = boxpos.z
|
||||||
end
|
else
|
||||||
|
newx = boxpos.x
|
||||||
local newnode = puzzle.get_node({x=newx, y= boxpos.y, z= newz}).name
|
newz = boxpos.z - (diff[2]>0 and 1 or -1)
|
||||||
|
end
|
||||||
|
|
||||||
local canpush = canpushnodes[newnode]
|
local newnode = puzzle.get_node({x=newx, y= boxpos.y, z= newz}).name
|
||||||
if canpush then
|
|
||||||
local oldnode = puzzle.get_node(boxpos).name
|
|
||||||
puzzle.set_node(boxpos,{name= "air"}) -- remove node
|
local canpush = canpushnodes[newnode]
|
||||||
if canpush == 1 then -- simply move the box
|
if canpush then
|
||||||
newnode = oldnode
|
local oldnode = puzzle.get_node(boxpos).name
|
||||||
elseif canpush == 2 then -- absorb the box
|
puzzle.set_node(boxpos,{name= "air"}) -- remove node
|
||||||
newnode = newnode
|
if canpush == 1 then -- simply move the box
|
||||||
end
|
newnode = oldnode
|
||||||
|
elseif canpush == 2 then -- absorb the box
|
||||||
puzzle.set_node({x=newx, y= boxpos.y, z= newz}, {name = newnode})
|
newnode = newnode
|
||||||
end
|
end
|
||||||
end
|
|
||||||
--say(serialize(event))
|
puzzle.set_node({x=newx, y= boxpos.y, z= newz}, {name = newnode})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--say(serialize(event))
|
||||||
end
|
end
|
|
@ -0,0 +1,24 @@
|
||||||
|
if not data then
|
||||||
|
m=50;n=50; minescount = m*n/10;
|
||||||
|
|
||||||
|
t0 = _G.minetest.get_gametime();
|
||||||
|
data = {}; spawnpos = self.spawnpos();
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
for k = -1,1 do for l = -1,1 do
|
||||||
|
if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end
|
||||||
|
end end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1,m do for j = 1,n do
|
||||||
|
if get_mine_count(i,j) > 0 or (data[i] and data[i][j] == 1) then
|
||||||
|
_G.minetest.swap_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}, {name = "basic_robot:buttonFFFFFF"})
|
||||||
|
else
|
||||||
|
_G.minetest.swap_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}, {name = "default:dirt"})
|
||||||
|
end
|
||||||
|
end end
|
||||||
|
end
|
||||||
|
self.remove()
|
|
@ -19,7 +19,7 @@ if not init then
|
||||||
board[i]={};
|
board[i]={};
|
||||||
for j = 1,n do
|
for j = 1,n do
|
||||||
k=k+1
|
k=k+1
|
||||||
board[i][j]=7+ret[k] -- 7 numbers, 82 letters
|
board[i][j]=17+ret[k] -- 7 numbers, 82 letters
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
board[math.random(n)][math.random(n)] = 0
|
board[math.random(n)][math.random(n)] = 0
|
||||||
|
@ -71,7 +71,8 @@ if not init then
|
||||||
|
|
||||||
create_board(size)
|
create_board(size)
|
||||||
render_board()
|
render_board()
|
||||||
|
self.listen_punch(self.pos()) -- attach punch listener
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
event = keyboard.get();
|
event = keyboard.get();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,189 +1,234 @@
|
||||||
-- SOKOBAN GAME, by rnd, robots port
|
-- SOKOBAN GAME, by rnd, robots port
|
||||||
|
|
||||||
|
if not sokoban then
|
||||||
if not sokoban then
|
load_player_progress = true -- true will disable level loading and load saved player progress
|
||||||
sokoban = {};
|
sokoban = {};
|
||||||
local players = find_player(8);
|
local players = find_player(8);
|
||||||
if not players then error("sokoban: no player near") end
|
if not players then error("sokoban: no player near") end
|
||||||
name = players[1];
|
name = players[1];
|
||||||
|
|
||||||
-- self.show_form(name,
|
_, text = book.read(1)
|
||||||
-- "size[2,1.25]"..
|
gamedata = minetest.deserialize(text);
|
||||||
-- "label[0,0;SELECT LEVEL 1-90]"..
|
|
||||||
-- "field[0.25,1;1,1;LVL;LEVEL;1]"..
|
if gamedata and gamedata[name] then
|
||||||
-- "button_exit[1.25,0.75;1,1;OK;OK]"
|
say("#sokoban: welcome back " .. name .. ", loading level " .. gamedata[name].lvl+1)
|
||||||
-- )
|
else
|
||||||
state = 1 -- will wait for form receive otherwise game play
|
say("sokoban: welcome new player " .. name)
|
||||||
self.label("stand close to white box and punch it one time to push it. you can only push 1 box\nand cant pull. goal is to get all white boxes pushed on aspen blocks")
|
end
|
||||||
|
|
||||||
player_ = puzzle.get_player(name); -- get player entity - player must be present in area
|
if not load_player_progress then
|
||||||
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0});player_:set_physics_override({jump=1}) -- reset player
|
self.show_form(name,
|
||||||
|
"size[3,1.25]"..
|
||||||
|
"label[0,0;SELECT LEVEL 1-90]"..
|
||||||
self.spam(1)
|
"field[0.25,1;1.25,1;LVL;LEVEL;1]"..
|
||||||
sokoban.push_time = 0
|
"button_exit[1.25,0.75;1,1;OK;OK]"
|
||||||
sokoban.blocks = 0;sokoban.level = 0; sokoban.moves=0;
|
)
|
||||||
imax = 0; jmax = 0
|
self.read_form() -- clear inputs
|
||||||
|
end
|
||||||
sokoban.load=0;sokoban.playername =""; sokoban.pos = {};
|
|
||||||
SOKOBAN_WALL = "moreblocks:cactus_brick"
|
state = 1 -- will wait for form receive otherwise game play
|
||||||
SOKOBAN_FLOOR = "default:silver_sandstone"
|
self.label("stand close to white box and punch it one time to push it. you can only push 1 box\nand cant pull. goal is to get all white boxes pushed on aspen blocks")
|
||||||
SOKOBAN_GOAL = "default:aspen_tree"
|
|
||||||
SOKOBAN_BOX = "basic_robot:buttonFFFFFF"
|
player_ = puzzle.get_player(name); -- get player entity - player must be present in area
|
||||||
|
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0});player_:set_physics_override({jump=1}) -- reset player
|
||||||
load_level = function(lvl)
|
|
||||||
|
|
||||||
local pos = self.spawnpos(); pos.x=pos.x+1;pos.y=pos.y+1;
|
self.spam(1)
|
||||||
sokoban.pos = pos;
|
self.listen_punch(self.pos()); -- attach punch listener
|
||||||
sokoban.playername = name
|
sokoban.push_time = 0
|
||||||
|
sokoban.blocks = 0;sokoban.level = 0; sokoban.moves=0;
|
||||||
if lvl == nil then return end
|
imax = 0; jmax = 0
|
||||||
if lvl <0 or lvl >89 then return end
|
|
||||||
|
sokoban.load=0;sokoban.playername =""; sokoban.pos = {};
|
||||||
local file = _G.io.open(minetest.get_modpath("basic_robot").."\\scripts\\sokoban.txt","r")
|
SOKOBAN_WALL = "moreblocks:cactus_brick"
|
||||||
if not file then return end
|
SOKOBAN_FLOOR = "default:silver_sandstone"
|
||||||
local str = ""; local s; local p = {x=pos.x,y=pos.y,z=pos.z}; local i,j;i=0;
|
SOKOBAN_GOAL = "default:aspen_tree"
|
||||||
local lvl_found = false
|
SOKOBAN_BOX = "basic_robot:buttonwhite"
|
||||||
while str~= nil do
|
|
||||||
str = file:read("*line");
|
|
||||||
if str~=nil and str =="; "..lvl then lvl_found=true break end
|
load_level = function(lvl)
|
||||||
end
|
|
||||||
if not lvl_found then file:close();return end
|
local pos = self.spawnpos(); pos.x=pos.x+1;pos.y=pos.y+1;
|
||||||
|
sokoban.pos = pos;
|
||||||
sokoban.blocks = 0;sokoban.level = lvl+1; sokoban.moves=0;
|
sokoban.playername = name
|
||||||
imax=0; jmax = 0;
|
|
||||||
while str~= nil do
|
if lvl == nil then return end
|
||||||
str = file:read("*line");
|
if lvl <0 or lvl >89 then return end
|
||||||
if str~=nil then
|
|
||||||
if string.sub(str,1,1)==";" then
|
local file = _G.io.open(minetest.get_modpath("basic_robot").."/scripts/games/sokoban.txt","r")
|
||||||
imax=i;
|
if not file then return end
|
||||||
file:close();
|
local str = ""; local s; local p = {x=pos.x,y=pos.y,z=pos.z}; local i,j;i=0;
|
||||||
player_:set_physics_override({jump=0})
|
local lvl_found = false
|
||||||
player_:set_eye_offset({x=0,y=20,z=0},{x=0,y=0,z=0});
|
while str~= nil do
|
||||||
return
|
str = file:read("*line");
|
||||||
end
|
if str~=nil and str =="; "..lvl then lvl_found=true break end
|
||||||
i=i+1;
|
end
|
||||||
if string.len(str)>jmax then jmax = string.len(str) end -- determine max dimensions
|
if not lvl_found then file:close();return end
|
||||||
for j = 1,string.len(str) do
|
|
||||||
p.x=pos.x+i;p.y=pos.y; p.z=pos.z+j; s=string.sub(str,j,j);
|
sokoban.blocks = 0;sokoban.level = lvl+1; sokoban.moves=0;
|
||||||
p.y=p.y-1;
|
imax=0; jmax = 0;
|
||||||
if puzzle.get_node(p).name~=SOKOBAN_FLOOR then puzzle.set_node(p,{name=SOKOBAN_FLOOR}); end -- clear floor
|
while str~= nil do
|
||||||
p.y=p.y+1;
|
str = file:read("*line");
|
||||||
if s==" " and puzzle.get_node(p).name~="air" then puzzle.set_node(p,{name="air"}) end
|
if str~=nil then
|
||||||
if s=="#" and puzzle.get_node(p).name~=SOKOBAN_WALL then puzzle.set_node(p,{name=SOKOBAN_WALL}) end
|
if string.sub(str,1,1)==";" then
|
||||||
if s=="$" then puzzle.set_node(p,{name=SOKOBAN_BOX});sokoban.blocks=sokoban.blocks+1 end
|
imax=i;
|
||||||
if s=="." then p.y=p.y-1;puzzle.set_node(p,{name=SOKOBAN_GOAL}); p.y=p.y+1;puzzle.set_node(p,{name="air"}) end
|
file:close();
|
||||||
--starting position
|
player_:set_physics_override({jump=0})
|
||||||
if s=="@" then
|
player_:set_eye_offset({x=0,y=20,z=0},{x=0,y=0,z=0});
|
||||||
player_:setpos({x=p.x,y=p.y-0.5,z=p.z}); -- move player to start position
|
return
|
||||||
--p.y=p.y-1;puzzle.set_node(p,{name="default:glass"});
|
end
|
||||||
puzzle.set_node(p,{name="air"})
|
i=i+1;
|
||||||
p.y=p.y+1;puzzle.set_node(p,{name="air"})
|
if string.len(str)>jmax then jmax = string.len(str) end -- determine max dimensions
|
||||||
--p.y=p.y+2;puzzle.set_node(p,{name="default:ladder"})
|
for j = 1,string.len(str) do
|
||||||
end
|
p.x=pos.x+i;p.y=pos.y; p.z=pos.z+j; s=string.sub(str,j,j);
|
||||||
if s~="@" then p.y = pos.y+2;puzzle.set_node(p,{name="air"}); -- ceiling default:obsidian_glass
|
p.y=p.y-1;
|
||||||
else --p.y=pos.y+2;puzzle.set_node(p,{name="default:ladder"})
|
if puzzle.get_node(p).name~=SOKOBAN_FLOOR then puzzle.set_node(p,{name=SOKOBAN_FLOOR}); end -- clear floor
|
||||||
end -- roof above to block jumps
|
p.y=p.y+1;
|
||||||
|
if s==" " and puzzle.get_node(p).name~="air" then puzzle.set_node(p,{name="air"}) end
|
||||||
end
|
if s=="#" and puzzle.get_node(p).name~=SOKOBAN_WALL then puzzle.set_node(p,{name=SOKOBAN_WALL}) end
|
||||||
end
|
if s=="$" then puzzle.set_node(p,{name=SOKOBAN_BOX});sokoban.blocks=sokoban.blocks+1 end
|
||||||
end
|
if s=="." then p.y=p.y-1;puzzle.set_node(p,{name=SOKOBAN_GOAL}); p.y=p.y+1;puzzle.set_node(p,{name="air"}) end
|
||||||
|
--starting position
|
||||||
file:close();
|
if s=="@" then
|
||||||
end
|
player_:set_pos({x=p.x,y=p.y-0.5,z=p.z}); -- move player to start position
|
||||||
|
--p.y=p.y-1;puzzle.set_node(p,{name="default:glass"});
|
||||||
clear_game = function()
|
puzzle.set_node(p,{name="air"})
|
||||||
local pos = self.spawnpos(); pos.x=pos.x+1;pos.y=pos.y+1;
|
p.y=p.y+1;puzzle.set_node(p,{name="air"})
|
||||||
for i = 1, 20 do
|
--p.y=p.y+2;puzzle.set_node(p,{name="default:ladder"})
|
||||||
for j = 1,20 do
|
end
|
||||||
local node = minetest.get_node({x=pos.x+i,y=pos.y-1,z=pos.z+j}).name
|
if s~="@" then p.y = pos.y+2;puzzle.set_node(p,{name="air"}); -- ceiling default:obsidian_glass
|
||||||
if node ~= "default:silver_sandstone" then minetest.set_node({x=pos.x+i,y=pos.y-1,z=pos.z+j}, {name = "default:silver_sandstone"}) end
|
else --p.y=pos.y+2;puzzle.set_node(p,{name="default:ladder"})
|
||||||
node = minetest.get_node({x=pos.x+i,y=pos.y,z=pos.z+j}).name
|
end -- roof above to block jumps
|
||||||
if node ~= "air" then minetest.set_node({x=pos.x+i,y=pos.y,z=pos.z+j}, {name = "air"}) end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
file:close();
|
||||||
|
end
|
||||||
|
|
||||||
if state == 1 then
|
clear_game = function()
|
||||||
clear_game()
|
local pos = self.spawnpos(); pos.x=pos.x+1;pos.y=pos.y+1;
|
||||||
load_level(20)
|
for i = 1, 20 do
|
||||||
state = 0
|
for j = 1,20 do
|
||||||
self.label("stand close to white box and punch it one time to push it. you can only push 1 box\nand cant pull. goal is to get all white boxes pushed on aspen blocks")
|
local node = minetest.get_node({x=pos.x+i,y=pos.y-1,z=pos.z+j}).name
|
||||||
else
|
if node ~= "default:silver_sandstone" then minetest.set_node({x=pos.x+i,y=pos.y-1,z=pos.z+j}, {name = "default:silver_sandstone"}) end
|
||||||
|
node = minetest.get_node({x=pos.x+i,y=pos.y,z=pos.z+j}).name
|
||||||
local ppos = player_:getpos()
|
if node ~= "air" then minetest.set_node({x=pos.x+i,y=pos.y,z=pos.z+j}, {name = "air"}) end
|
||||||
if math.abs(ppos.y-sokoban.pos.y)~= 0.5 then minetest.chat_send_player(name,colorize("red", "SOKOBAN: " .. name .. " QUITS ! "));
|
end
|
||||||
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0});player_:set_physics_override({jump=1}); self.remove() end
|
end
|
||||||
|
end
|
||||||
event = keyboard.get();
|
|
||||||
|
force_load = function()
|
||||||
if event then
|
local lvl = 0 -- 1st level at idx 0 - sokoban level 1
|
||||||
|
clear_game()
|
||||||
local pname = event.puncher
|
if gamedata and gamedata[name] then lvl = gamedata[name].lvl end -- load next level to play
|
||||||
if pname ~= name then goto quit end
|
load_level(lvl)
|
||||||
local pos = {x=event.x, y = event.y, z = event.z};
|
state = 0
|
||||||
local p=player.getpos(pname);local q={x=pos.x,y=pos.y,z=pos.z}
|
self.label("stand close to white box and punch it one time to push it. you can only push 1 box\nand can't pull. goal is to get all white boxes pushed on aspen blocks")
|
||||||
p.x=p.x-q.x;p.y=p.y-q.y;p.z=p.z-q.z
|
|
||||||
if math.abs(p.y+0.5)>0 then goto quit end
|
end
|
||||||
if math.abs(p.x)>math.abs(p.z) then -- determine push direction
|
|
||||||
if p.z<-0.5 or p.z>0.5 or math.abs(p.x)>1.5 then goto quit end
|
if load_player_progress then
|
||||||
if p.x+q.x>q.x then q.x= q.x-1
|
force_load() -- this prevents selecting custom level and loads players progress if any
|
||||||
else q.x = q.x+1
|
end
|
||||||
end
|
|
||||||
else
|
end
|
||||||
if p.x<-0.5 or p.x>0.5 or math.abs(p.z)>1.5 then goto quit end
|
|
||||||
if p.z+q.z>q.z then q.z= q.z-1
|
|
||||||
else q.z = q.z+1
|
if state == 1 then -- wait to load game
|
||||||
end
|
sender,fields = self.read_form()
|
||||||
end
|
if fields then
|
||||||
|
if fields.OK then
|
||||||
|
local lvl = tonumber(fields.LVL or 1)-1;
|
||||||
if minetest.get_node(q).name=="air" then -- push crate
|
clear_game()
|
||||||
sokoban.moves = sokoban.moves+1
|
load_level(lvl)
|
||||||
local old_infotext = minetest.get_meta(pos):get_string("infotext");
|
state = 0
|
||||||
minetest.set_node(pos,{name="air"})
|
self.label("stand close to white box and punch it one time to push it. you can only push 1 box\nand cant pull. goal is to get all white boxes pushed on aspen blocks")
|
||||||
minetest.set_node(q,{name=SOKOBAN_BOX})
|
else
|
||||||
minetest.sound_play("default_dig_dig_immediate", {pos=q,gain=1.0,max_hear_distance = 24,}) -- sound of pushing
|
self.remove()
|
||||||
local meta = minetest.get_meta(q);
|
end
|
||||||
q.y=q.y-1;
|
end
|
||||||
if minetest.get_node(q).name==SOKOBAN_GOAL then
|
|
||||||
if old_infotext~="GOAL REACHED" then
|
|
||||||
sokoban.blocks = sokoban.blocks -1;
|
else -- game
|
||||||
end
|
|
||||||
meta:set_string("infotext", "GOAL REACHED")
|
local ppos = player_:get_pos()
|
||||||
else
|
if math.abs(ppos.y-sokoban.pos.y)~= 0.5 then minetest.chat_send_player(name,colorize("red", "SOKOBAN: " .. name .. " QUITS ! "));
|
||||||
if old_infotext=="GOAL REACHED" then
|
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0});player_:set_physics_override({jump=1}); self.remove() end
|
||||||
sokoban.blocks = sokoban.blocks +1
|
|
||||||
end
|
event = keyboard.get();
|
||||||
--meta:set_string("infotext", "push crate on top of goal block")
|
|
||||||
end
|
if event then
|
||||||
end
|
|
||||||
|
local pname = event.puncher
|
||||||
if sokoban.blocks~=0 then -- how many blocks left
|
if pname ~= name then goto quit end
|
||||||
--say("move " .. sokoban.moves .. " : " ..sokoban.blocks .. " crates left ");
|
local pos = {x=event.x, y = event.y, z = event.z};
|
||||||
else
|
if minetest.get_node(pos).name == "air" then return end -- ignore move, block wasnt punched
|
||||||
say("games: ".. name .. " just solved sokoban level ".. sokoban.level .. " in " .. sokoban.moves .. " moves.");
|
local p=player.getpos(pname);local q={x=pos.x,y=pos.y,z=pos.z}
|
||||||
player_:set_physics_override({jump=1})
|
p.x=p.x-q.x;p.y=p.y-q.y;p.z=p.z-q.z
|
||||||
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
if math.abs(p.y+0.5)>0 then goto quit end
|
||||||
|
if math.abs(p.x)>math.abs(p.z) then -- determine push direction
|
||||||
local player = _G.minetest.get_player_by_name(event.puncher);
|
if p.z<-0.5 or p.z>0.5 or math.abs(p.x)>1.5 then goto quit end
|
||||||
if player then
|
if p.x+q.x>q.x then q.x= q.x-1
|
||||||
local inv = player:get_inventory();
|
else q.x = q.x+1
|
||||||
inv:add_item("main",_G.ItemStack("skyblock:sokoban 4 "))
|
end
|
||||||
end
|
else
|
||||||
|
if p.x<-0.5 or p.x>0.5 or math.abs(p.z)>1.5 then goto quit end
|
||||||
local i,j;
|
if p.z+q.z>q.z then q.z= q.z-1
|
||||||
for i = 1,imax do
|
else q.z = q.z+1
|
||||||
for j=1,jmax do
|
end
|
||||||
minetest.set_node({x= sokoban.pos.x+i,y=sokoban.pos.y,z=sokoban.pos.z+j}, {name = "air"}); -- clear level
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
if minetest.get_node(q).name=="air" then -- push crate
|
||||||
sokoban.playername = ""; sokoban.level = 1
|
sokoban.moves = sokoban.moves+1
|
||||||
end
|
local old_infotext = minetest.get_meta(pos):get_string("infotext");
|
||||||
::quit::
|
minetest.set_node(pos,{name="air"})
|
||||||
end
|
minetest.set_node(q,{name=SOKOBAN_BOX})
|
||||||
|
minetest.sound_play("default_dig_dig_immediate", {pos=q,gain=1.0,max_hear_distance = 24,}) -- sound of pushing
|
||||||
|
local meta = minetest.get_meta(q);
|
||||||
|
q.y=q.y-1;
|
||||||
|
if minetest.get_node(q).name==SOKOBAN_GOAL then
|
||||||
|
if old_infotext~="GOAL REACHED" then
|
||||||
|
sokoban.blocks = sokoban.blocks -1;
|
||||||
|
end
|
||||||
|
meta:set_string("infotext", "GOAL REACHED")
|
||||||
|
else
|
||||||
|
if old_infotext=="GOAL REACHED" then
|
||||||
|
sokoban.blocks = sokoban.blocks +1
|
||||||
|
end
|
||||||
|
--meta:set_string("infotext", "push crate on top of goal block")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if sokoban.blocks~=0 then -- how many blocks left
|
||||||
|
--say("move " .. sokoban.moves .. " : " ..sokoban.blocks .. " crates left ");
|
||||||
|
else
|
||||||
|
say("games: ".. name .. " just solved sokoban level ".. sokoban.level .. " in " .. sokoban.moves .. " moves.");
|
||||||
|
|
||||||
|
if not gamedata then gamedata = {} end
|
||||||
|
gamedata[name] = {lvl = sokoban.level}; -- increased level
|
||||||
|
book.write(1,"sokoban players", minetest.serialize(gamedata))
|
||||||
|
|
||||||
|
player_:set_physics_override({jump=1})
|
||||||
|
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
||||||
|
|
||||||
|
local player = _G.minetest.get_player_by_name(event.puncher);
|
||||||
|
if player then
|
||||||
|
local inv = player:get_inventory();
|
||||||
|
inv:add_item("main",_G.ItemStack("default:gold_ingot " .. 2*sokoban.level))
|
||||||
|
end
|
||||||
|
|
||||||
|
local i,j;
|
||||||
|
for i = 1,imax do
|
||||||
|
for j=1,jmax do
|
||||||
|
minetest.set_node({x= sokoban.pos.x+i,y=sokoban.pos.y,z=sokoban.pos.z+j}, {name = "air"}); -- clear level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sokoban.playername = ""; sokoban.level = 1
|
||||||
|
end
|
||||||
|
::quit::
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -79,6 +79,7 @@ render_lights(); render_switches(true)
|
||||||
|
|
||||||
|
|
||||||
self.label("GOAL OF GAME: punch buttons with numbers in correct order to turn all blocks to 0")
|
self.label("GOAL OF GAME: punch buttons with numbers in correct order to turn all blocks to 0")
|
||||||
|
self.listen_punch(self.pos()) -- attach punch listener
|
||||||
|
|
||||||
--self.label(serialize(switches))
|
--self.label(serialize(switches))
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
--wordle game by rnd (2022), made in 15 minutes
|
||||||
|
|
||||||
|
-- 5 letter word is picked randomly
|
||||||
|
-- you have 6 tries to guess the word, write it in and it will color letters:
|
||||||
|
-- green = correct letter, correct place, yellow = correct letter, wrong place,
|
||||||
|
-- gray = letter not in word!
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
|
||||||
|
-- load this from file..
|
||||||
|
wordlist = {
|
||||||
|
"pulse", "audio", "solar", "bacon", "laser", "pizza", "maybe", "guess", "stuff",
|
||||||
|
"seven", "world", "about", "again", "heart", "water", "happy", "sixty", "board",
|
||||||
|
"month", "angel", "death", "green", "music", "fifty", "three", "party", "piano",
|
||||||
|
"mouth", "woman", "sugar", "amber", "dream", "apple", "laugh", "tiger", "faith",
|
||||||
|
"earth", "river", "money", "peace", "forty", "words", "smile", "abate", "house",
|
||||||
|
"alone", "watch", "lemon", "south", "erica", "anime", "after", "santa", "admin",
|
||||||
|
"jesus", "china", "blood", "megan", "thing", "light", "david", "cough", "story",
|
||||||
|
"power", "india", "point", "today", "anger", "night", "glory", "april", "candy",
|
||||||
|
"puppy", "above", "phone", "vegan", "forum", "irish", "birth", "other", "grace",
|
||||||
|
"queen", "pasta", "plant", "smart", "knife", "magic", "jelly", "black", "media",
|
||||||
|
--100
|
||||||
|
"honor", "cycle", "truth", "zebra", "train", "bully", "brain", "mango", "under",
|
||||||
|
"dirty", "robot", "eight", "fruit", "panda", "truck", "field", "bible", "radio",
|
||||||
|
"dance", "voice", "smith", "sorry", "paris", "being", "lover", "never", "royal",
|
||||||
|
"venus", "metal", "penny", "honey", "color", "cloud", "scarf", "state", "value",
|
||||||
|
"mouse", "north", "bread", "daily", "paper", "beard", "alive", "place", "chair",
|
||||||
|
"badge", "worth", "crazy", "photo", "dress", "table", "cross", "clear", "white",
|
||||||
|
"march", "ocean", "belly", "ninja", "young", "range", "maria", "great", "sweet",
|
||||||
|
"karen", "scent", "beach", "space", "clock", "allah", "peach", "sound", "fever",
|
||||||
|
"youth", "union", "daisy", "plate", "eagle", "human", "start", "funny", "right",
|
||||||
|
"molly", "guard", "witch", "dough", "think", "image", "album", "socks", "catch",
|
||||||
|
--200
|
||||||
|
"sleep", "below", "organ", "peter", "cupid", "storm", "silly", "berry", "rhyme",
|
||||||
|
"carol", "olive", "leave", "whale", "james", "brave", "asian", "every", "arrow",
|
||||||
|
"there", "ebola", "later", "bacon", "local", "graph", "super", "obama", "brown",
|
||||||
|
"onion", "simon", "globe", "alley", "stick", "spain", "daddy", "scare", "quiet",
|
||||||
|
"touch", "clean", "liver", "lucky", "given", "lunch", "child", "clone", "glove",
|
||||||
|
"meter", "nancy", "plain", "solid", "uncle", "shout", "bored", "early", "video",
|
||||||
|
"brian", "cheer", "texas", "often", "sushi", "chaos", "tulip", "alien", "apart",
|
||||||
|
"fight", "coach", "force", "trust", "angle", "beast", "craft", "chess", "skull",
|
||||||
|
"order", "judge", "swing", "drive", "shine", "stand", "stage", "oscar", "ember",
|
||||||
|
"worry", "drama", "raven", "sight", "short", "botox", "unity", "horse", "trout",
|
||||||
|
--300
|
||||||
|
"devil", "spoon", "clown", "grand", "gnome", "binge", "paula", "award", "quick",
|
||||||
|
"cause", "close", "scout", "snail", "purse", "topic", "teeth", "sauce", "share",
|
||||||
|
"along", "worse", "movie", "reach", "giant", "quack", "shark", "first", "count",
|
||||||
|
"agent", "shelf", "grape", "drink", "skate", "wrong", "cream", "snake", "heavy",
|
||||||
|
"tooth", "heard", "idiot", "scary", "chain", "break", "valve", "agony", "salad",
|
||||||
|
"shell", "scope", "tupac", "track", "final", "crown", "group", "wagon", "doing",
|
||||||
|
"robin", "false", "small", "block", "brush", "salsa", "grain", "wings", "arian",
|
||||||
|
"allow", "habit", "stove", "tower", "stars", "total", "plane", "comet", "tweet",
|
||||||
|
"abide", "frown", "roman", "grant", "ready", "blast", "treat", "poppy", "biome",
|
||||||
|
"oasis", "roger", "ghost", "abode", "abort", "court", "petal", "flood", "cider",
|
||||||
|
--400
|
||||||
|
"orion", "extra", "pearl", "gator", "rough", "koala", "melon", "price", "alpha",
|
||||||
|
"smell", "chase", "fresh", "quest", "store", "grove", "round", "sense", "chest",
|
||||||
|
"fancy", "loose", "match", "pluto", "sport", "sheep", "crime", "grade", "pride",
|
||||||
|
"lance", "billy", "virus", "twerp", "kenya", "model", "ledge", "tired", "level",
|
||||||
|
"juice", "quart", "amish", "flame", "event", "offer", "twist", "actor", "maple",
|
||||||
|
"hinge", "proud", "boone", "nasty", "hyper", "paint", "press", "patch", "mercy",
|
||||||
|
"baker", "broom", "rhino", "putin", "greed", "inter", "curve", "giver", "flute",
|
||||||
|
"class", "hyena", "stock", "sting", "fable", "loved", "chant", "focus", "bench",
|
||||||
|
"birds", "brand", "otter", "goose", "ought", "boron", "dodge", "sloth", "eager",
|
||||||
|
"serve", "fella", "cover", "genre", "cable", "apron", "worst", "tommy", "egypt"
|
||||||
|
--500
|
||||||
|
}
|
||||||
|
|
||||||
|
word = wordlist[math.random(#wordlist)];
|
||||||
|
letters = {}
|
||||||
|
for i = 1,string.len(word) do letters[string.sub(word,i,i)] = true end
|
||||||
|
responses = {};
|
||||||
|
maxtries = 6
|
||||||
|
self.label("GUESSWORD " .. word)
|
||||||
|
self.label("WORDLE GAME\n\nINSTRUCTIONS:\ntry to guess 5 letter word by typing it in chat like\n\n:guess\n\nyou have " .. maxtries .. " tries.\n"..
|
||||||
|
"gray color indicates letter is not in word, yellow color indicates letter is\nin word but not in correct position. green color indicates correct letter at\ncorrect position")
|
||||||
|
self.listen(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
speaker,msg = self.listen_msg()
|
||||||
|
|
||||||
|
if #responses == maxtries then
|
||||||
|
responses[#responses+1] = minetest.colorize("red","GAME OVER! correct word was " .. word)
|
||||||
|
self.label(table.concat(responses,"\n"))
|
||||||
|
end
|
||||||
|
|
||||||
|
if msg and #responses<maxtries and string.sub(msg,1,1)==":" and string.len(msg)-1 == string.len(word) then
|
||||||
|
|
||||||
|
msg = string.sub(msg,2)
|
||||||
|
local out = {}
|
||||||
|
local guessed = true
|
||||||
|
|
||||||
|
for i = 1,string.len(word) do
|
||||||
|
local c = string.sub(msg,i,i)
|
||||||
|
local color = "white"
|
||||||
|
if not letters[c] then
|
||||||
|
color = "gray"
|
||||||
|
elseif c == string.sub(word,i,i) then
|
||||||
|
color = "green"
|
||||||
|
else color = "yellow"
|
||||||
|
end
|
||||||
|
if color ~= "green" then guessed = false end
|
||||||
|
out[#out+1] = minetest.colorize(color, c)
|
||||||
|
end
|
||||||
|
responses[#responses+1] = (#responses+1) .. ". " .. table.concat(out)
|
||||||
|
if guessed == true then
|
||||||
|
responses[#responses+1] = "YOU WIN!"
|
||||||
|
for i = 1,maxtries-#responses do responses[#responses+1] = " " end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.label(table.concat(responses,"\n"))
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,40 @@
|
||||||
|
-- calender by rnd, 30 minutes with bugfixes
|
||||||
|
|
||||||
|
dayofweek = function(y,m,d)
|
||||||
|
local offsets = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
|
||||||
|
if m<3 then y=y-1 end
|
||||||
|
return (y+math.floor(y/4)-math.floor(y/100)+math.floor(y/400)+offsets[m]+d) % 7+1
|
||||||
|
end
|
||||||
|
|
||||||
|
y=2000
|
||||||
|
m=8
|
||||||
|
d=1
|
||||||
|
--say(dayofweek(y,m,d))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
make_calender = function(y,m)
|
||||||
|
local start_day = dayofweek(y,m,1)
|
||||||
|
local months = {31,29,31,30,31,30,31,31,30,31,30,31};
|
||||||
|
if y%4==0 and (y%100~=0 or y%400 == 0) then months[2]= 30 end -- feb has 30 days on leap year
|
||||||
|
local out = minetest.colorize("red",m.."/"..y).."\nsun mon tue wed thu fri sat\n"
|
||||||
|
out = out .. string.rep("__ ",start_day-1)
|
||||||
|
local i = start_day;
|
||||||
|
local idx = 1;
|
||||||
|
while idx<=months[m] do
|
||||||
|
out = out .. string.format("%02d",idx) .. " ";
|
||||||
|
if i%7 ==0 then out = out .."\n" end
|
||||||
|
idx = idx+1
|
||||||
|
i=i+1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
ret = {}
|
||||||
|
for m = 1,12 do
|
||||||
|
ret[#ret+1]=make_calender(y,m)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.label(table.concat(ret,"\n\n"))
|
|
@ -0,0 +1,59 @@
|
||||||
|
-- mandelbrot by rnd,2022 , made in 30 mins
|
||||||
|
if not init then init = true
|
||||||
|
|
||||||
|
n=100
|
||||||
|
local itermin = 10; -- check quicker if diverge!
|
||||||
|
local itermax = 250; -- max iterations
|
||||||
|
local delta = 0.00001^2; -- convergence difference
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
"white","yellow","orange","red",
|
||||||
|
"magenta","purple","blue","cyan",
|
||||||
|
"green","dark_green","brown","tan",
|
||||||
|
"light_grey","medium_grey","dark_grey","black"
|
||||||
|
}
|
||||||
|
for i = 1,#nodes do nodes[i] = "basic_robot:button"..nodes[i] end
|
||||||
|
|
||||||
|
get_pixel = function()
|
||||||
|
local iter = 0
|
||||||
|
local zr=0 ; local zi=0 ;
|
||||||
|
for i = 1, itermin do
|
||||||
|
local zrn=zr^2-zi^2+cr;
|
||||||
|
local zin=2*zr*zi+ci
|
||||||
|
zr=zrn
|
||||||
|
zi=zin
|
||||||
|
end
|
||||||
|
if zr^2+zi^2>1 then return -1 end
|
||||||
|
|
||||||
|
local zrn=zr^2-zi^2+cr;
|
||||||
|
local zin=2*zr*zi+ci
|
||||||
|
if (zrn-zr)^2+(zin-zi)^2< delta then return 1 end
|
||||||
|
|
||||||
|
for i = 1, itermax do
|
||||||
|
local zrn=zr^2-zi^2+cr;
|
||||||
|
local zin=2*zr*zi+ci
|
||||||
|
if (zrn-zr)^2+(zin-zi)^2< delta then return i-1 end
|
||||||
|
zr=zrn
|
||||||
|
zi=zin
|
||||||
|
end
|
||||||
|
return itermax-1
|
||||||
|
end
|
||||||
|
|
||||||
|
pos = self.pos()
|
||||||
|
local nnodes = #nodes
|
||||||
|
for x=1,n do
|
||||||
|
for y=1,n do
|
||||||
|
cr=2*x/n-1; ci=2*y/n-1
|
||||||
|
local col = get_pixel()
|
||||||
|
if col>0 then
|
||||||
|
col = math.floor(nnodes*col/itermax)
|
||||||
|
minetest.swap_node({x=pos.x+x,y=pos.y,z=pos.z+y},{name = nodes[col+1]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.remove()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
--ALL UNICODE by rnd, 2021
|
||||||
|
|
||||||
|
-- range to 32-1550, then 7400-10000
|
||||||
|
--cyrillic 0410-042F: 1040-1071
|
||||||
|
--cyrilic 0430-044F: 1072-1103
|
||||||
|
if not init then init = true
|
||||||
|
|
||||||
|
function utf8(decimal)
|
||||||
|
local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
|
||||||
|
if decimal<128 then return string.char(decimal) end
|
||||||
|
local charbytes = {}
|
||||||
|
for bytes,vals in ipairs(bytemarkers) do
|
||||||
|
if decimal<=vals[1] then
|
||||||
|
for b=bytes+1,2,-1 do
|
||||||
|
local mod = decimal%64
|
||||||
|
decimal = (decimal-mod)/64
|
||||||
|
charbytes[b] = string.char(128+mod)
|
||||||
|
end
|
||||||
|
charbytes[1] = string.char(vals[2]+decimal)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(charbytes)
|
||||||
|
end
|
||||||
|
|
||||||
|
ret= {"ALL UNICODE\n0 = "}
|
||||||
|
|
||||||
|
for i = 1550, 4000 do
|
||||||
|
if i%25==0 then ret[#ret+1] = "\n"..(i).. " = " end
|
||||||
|
ret[#ret+1] = utf8(i)
|
||||||
|
end
|
||||||
|
self.label(table.concat(ret))
|
||||||
|
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,27 @@
|
||||||
|
-- coal maker mod idea in 30 minutes by rnd
|
||||||
|
-- build dirt box around 3x3x3 area filled with wood, remove one boundary wood (lower one) and start fire there. start robot then!
|
||||||
|
|
||||||
|
check_firebox = function(pos)
|
||||||
|
local p = minetest.find_node_near(pos, 5, "fire:basic_flame") -- locate fire nearby!
|
||||||
|
if not p or minetest.get_node(p).name ~= "fire:basic_flame" then say("light fire first!"); self.remove() end
|
||||||
|
d=3; -- inner size of box, area filled with wood
|
||||||
|
local dirs = {{-1,0,0},{1,0,0},{0,0,-1},{0,0,1}};local dir1,dir2; -- position of vertices on dirt box
|
||||||
|
for i = 1,#dirs do
|
||||||
|
local dir = dirs[i];
|
||||||
|
if minetest.get_node({x=p.x+d*dir[1],y=p.y+d*dir[2],z=p.z+d*dir[3]}).name == "default:dirt" and
|
||||||
|
minetest.get_node({x=p.x+(d-1)*dir[1],y=p.y+(d-1)*dir[2],z=p.z+(d-1)*dir[3]}).name == "default:wood" then dir2 = dirs[i]; break end
|
||||||
|
end
|
||||||
|
if not dir2 then say("error, place fire in correct place in correctly built dirt box!") self.remove() end
|
||||||
|
dir1 = {dir2[3], dir2[2], -dir2[1]};
|
||||||
|
local v1 = {x=p.x-(d-1)*dir1[1]-dir2[1],y=p.y-1,z=p.z-(d-1)*dir1[3]-dir2[3]}
|
||||||
|
local v2 = {x=p.x+(d-1)*dir1[1]+(d)*dir2[1],y=p.y+d,z=p.z+(d-1)*dir1[3]+(d)*dir2[3]}
|
||||||
|
local res = minetest.find_nodes_in_area(v1,v2,{"default:wood","default:dirt"},true);
|
||||||
|
if (#(res["default:dirt"] or {})) == 97 and #(res["default:wood"] or {})==26 then
|
||||||
|
say("all ok. making charcoal now!")
|
||||||
|
minetest.swap_node(p,{name = "air"}) -- turn off fire!
|
||||||
|
else say("fail! check that you built dirt box/wood correctly!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
check_firebox(self.pos())
|
||||||
|
self.remove()
|
|
@ -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
|
|
@ -0,0 +1,121 @@
|
||||||
|
--rnd music robot v12/10/2019, 22:00
|
||||||
|
--tuning by Jozet
|
||||||
|
|
||||||
|
--@F2 E D C G3 G F2 E D C G3 G F2 A A F E G G E D E F D C3 C
|
||||||
|
|
||||||
|
if not init then
|
||||||
|
_G.minetest.forceload_block(self.pos(),true)
|
||||||
|
song = nil
|
||||||
|
self.listen(1)
|
||||||
|
local ent = _G.basic_robot.data[self.name()].obj:get_luaentity();
|
||||||
|
dt = 0.001
|
||||||
|
ent.timestep = dt -- time step
|
||||||
|
|
||||||
|
pitches = { -- definitions of note pitches
|
||||||
|
0.59,
|
||||||
|
0.62,
|
||||||
|
0.67,
|
||||||
|
0.7,
|
||||||
|
0.74,
|
||||||
|
0.79,
|
||||||
|
0.845,
|
||||||
|
0.89,
|
||||||
|
0.945,
|
||||||
|
1,
|
||||||
|
1.05,
|
||||||
|
1.12,
|
||||||
|
1.19,
|
||||||
|
1.25,
|
||||||
|
1.34,
|
||||||
|
1.41,
|
||||||
|
1.48,
|
||||||
|
1.58,
|
||||||
|
1.68,
|
||||||
|
1.78,
|
||||||
|
1.88,
|
||||||
|
2.0,
|
||||||
|
2.15,
|
||||||
|
2.28
|
||||||
|
}
|
||||||
|
|
||||||
|
notenames = { -- definition of note names
|
||||||
|
C = 1,
|
||||||
|
Db = 2,
|
||||||
|
D = 3,
|
||||||
|
Eb = 4,
|
||||||
|
E = 5,
|
||||||
|
F = 6,
|
||||||
|
Gb = 7,
|
||||||
|
G = 8,
|
||||||
|
Ab = 9,
|
||||||
|
A = 10,
|
||||||
|
Bb = 11,
|
||||||
|
B = 12,
|
||||||
|
["2C"] = 13,
|
||||||
|
["2Db"] = 14,
|
||||||
|
["2D"] = 15,
|
||||||
|
["2Eb"] = 16,
|
||||||
|
["2E"] = 17,
|
||||||
|
["2F"] = 18,
|
||||||
|
["2Gb"] = 19,
|
||||||
|
["2G"] = 20,
|
||||||
|
["2Ab"] = 21,
|
||||||
|
["2A"] = 22,
|
||||||
|
["2Bb"] = 23,
|
||||||
|
["2B"] = 24
|
||||||
|
}
|
||||||
|
|
||||||
|
say("available notes : C Db D Eb E F Gb G Ab A Bb B 2C 2Db 2D 2Eb 2E 2F 2Gb 2G 2Ab 2A 2Bb 2B . example: @A5 A A A A10 A A A , number after note name denotes change of tempo. To replay last song do @R")
|
||||||
|
|
||||||
|
|
||||||
|
songdata = {}
|
||||||
|
t=0 -- current timer
|
||||||
|
idx = 0 -- current note to play
|
||||||
|
tempo = 1 -- default pause
|
||||||
|
|
||||||
|
parse_song = function()
|
||||||
|
songdata = {} -- reset song data
|
||||||
|
for notepart in string.gmatch(song,"([^ ]+)") do -- parse song
|
||||||
|
if notepart then
|
||||||
|
local note,duration;
|
||||||
|
note,duration = _G.string.match(notepart,"(%d*%a+)(%d*)")
|
||||||
|
if not duration or duration == "" then duration = 0 end
|
||||||
|
songdata[#songdata+1] = {notenames[note], tonumber(duration)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
tempo = 3; -- default tempo
|
||||||
|
t=0
|
||||||
|
idx = 0 -- reset current idx
|
||||||
|
end
|
||||||
|
|
||||||
|
init = true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if not song then
|
||||||
|
speaker,msg = self.listen_msg()
|
||||||
|
if msg and string.find(msg,"@") then
|
||||||
|
song = string.sub(msg,2)
|
||||||
|
if song ~= "R" then -- R for replay
|
||||||
|
parse_song()
|
||||||
|
self.label("playing song by " .. speaker.. ", " .. song )
|
||||||
|
else
|
||||||
|
idx = 0; t = 0; -- try play again!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif t<=1 then -- play next note!
|
||||||
|
idx = idx+1
|
||||||
|
if idx>#songdata then
|
||||||
|
self.label("song " .. song .. ". ended.")
|
||||||
|
song = nil
|
||||||
|
else
|
||||||
|
if songdata[idx][2]>0 then tempo = songdata[idx][2] end
|
||||||
|
t = tempo;
|
||||||
|
self.sound( "piano",{
|
||||||
|
pos = self.pos(), gain = 1000.0, pitch = pitches[ songdata[idx][1] ],
|
||||||
|
max_hear_distance = 1000000
|
||||||
|
})
|
||||||
|
end
|
||||||
|
else
|
||||||
|
t=t-1
|
||||||
|
end
|
|
@ -0,0 +1,108 @@
|
||||||
|
if not get_hash then
|
||||||
|
|
||||||
|
get_hash = function(s,p)
|
||||||
|
if not s then return end
|
||||||
|
local h = 0; local n = string.len(s);local m = 4; -- put 4 characters together
|
||||||
|
local r = 0;local i = 0;
|
||||||
|
while i<n do
|
||||||
|
i=i+1;r = 256*r+ string.byte(s,i);
|
||||||
|
if i%m == 0 then h=h+(r%p) r=0 end
|
||||||
|
end
|
||||||
|
if i%m~=0 then h=h+(r%p) end
|
||||||
|
return h%p
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
hashdb = {}; --array with entries: [hash] = list of possible hits
|
||||||
|
|
||||||
|
insert = function(key,value)
|
||||||
|
local hash = get_hash(key,10011);
|
||||||
|
local data = hashdb[hash]; if data == nil then hashdb[hash] = {}; data = hashdb[hash] end
|
||||||
|
data[#data+1]={key,value};
|
||||||
|
return hash
|
||||||
|
end
|
||||||
|
|
||||||
|
lookup = function(key)
|
||||||
|
local hash = get_hash(key,10011);
|
||||||
|
if not hash then return end
|
||||||
|
local data = hashdb[hash];
|
||||||
|
if not data then return nil end
|
||||||
|
for i = 1,#data do
|
||||||
|
if data[i][1]==key then return data[i][2] end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
analyse = function()
|
||||||
|
local count = 0; local maxlen = 0; local maxidx = 1; local n = #hashdb;
|
||||||
|
for i = 1, 10000 do
|
||||||
|
local data = hashdb[i];
|
||||||
|
if data then
|
||||||
|
local length = #data;
|
||||||
|
if length > maxlen then maxlen = length; maxidx = i end
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if maxlen>0 then
|
||||||
|
local data = hashdb[maxidx];
|
||||||
|
say("number of used hash entries is " .. count .. ", average " .. (step/count) .. " entries per hash, "..
|
||||||
|
" max length of list is " .. maxlen .. " at hash ".. maxidx )--.. " : " ..
|
||||||
|
--string.gsub(_G.dump(data),"\n","") )
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- LOAD DICTIONARY WORDS into hashtable
|
||||||
|
|
||||||
|
lang = "german"
|
||||||
|
|
||||||
|
fname = "F:\\games\\rpg\\minetest-0415server\\mods\\basic_translate\\"..lang;
|
||||||
|
local f = _G.assert(_G.io.open(fname, "r"));local dicts = f:read("*all");f:close()
|
||||||
|
|
||||||
|
step = 0; maxwords = 10000;
|
||||||
|
i=0
|
||||||
|
dict = {}; -- for comparison
|
||||||
|
|
||||||
|
while(step<maxwords) do
|
||||||
|
|
||||||
|
step=step+1
|
||||||
|
i1 = string.find(dicts,"\t",i+1)
|
||||||
|
i2 = string.find(dicts,"\n",i+1)
|
||||||
|
|
||||||
|
if not i2 then break end
|
||||||
|
|
||||||
|
local word = string.sub(dicts, i+1,i1-1);
|
||||||
|
local tword = string.sub(dicts, i1+1,i2-1);
|
||||||
|
insert(word, tword) -- load into hashtable
|
||||||
|
dict[word]=tword
|
||||||
|
i=i2
|
||||||
|
end
|
||||||
|
|
||||||
|
self.listen(1)
|
||||||
|
self.spam(1)
|
||||||
|
say(step .. " words loaded")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle chat event
|
||||||
|
speaker,msg = self.listen_msg()
|
||||||
|
|
||||||
|
if msg then
|
||||||
|
if msg == "?*" then
|
||||||
|
local n = 1000000; local msg = "hello"
|
||||||
|
local ret = "";
|
||||||
|
local t1 = os.clock();
|
||||||
|
for i = 1, n do ret = lookup(msg) end; t1 = os.clock()-t1;
|
||||||
|
local t2 = os.clock();
|
||||||
|
for i = 1, n do ret = dict[msg] end
|
||||||
|
t2 = os.clock()-t2;
|
||||||
|
say(t1 .. " " .. t2)
|
||||||
|
|
||||||
|
elseif msg == "??" then
|
||||||
|
analyse()
|
||||||
|
elseif string.sub(msg,1,1)=="?" then
|
||||||
|
msg = string.sub(msg,2);
|
||||||
|
local ret = lookup(msg);
|
||||||
|
if ret then say("found entry for " .. msg .. " : " .. ret) else say("entry not found") end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,187 @@
|
||||||
|
-- "natural language" programming demo by rnd, 2021
|
||||||
|
-- input is lines of 'natural' language, will be translated into lua code
|
||||||
|
|
||||||
|
--[[
|
||||||
|
move forward 3
|
||||||
|
turn left
|
||||||
|
dig left
|
||||||
|
if see dirt turn left and move forward
|
||||||
|
|
||||||
|
subroutine circle commands..
|
||||||
|
|
||||||
|
--> TRANSFORMED into lua :
|
||||||
|
|
||||||
|
for i = 1,3 do move.forward(); pause(); end
|
||||||
|
turn.left(); pause();
|
||||||
|
dig.left(); pause()
|
||||||
|
if read_node.forward()=="dirt" then turn.left();pause(); move.forward(); pause() end
|
||||||
|
|
||||||
|
TODO: integrate into robots, maybe command: code.natural(..)
|
||||||
|
--]]
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
|
||||||
|
prog = [[
|
||||||
|
subroutine walk
|
||||||
|
if see air move forward and move down
|
||||||
|
if see dirt move up
|
||||||
|
if see wood turn right
|
||||||
|
subroutine end
|
||||||
|
|
||||||
|
walk
|
||||||
|
]]
|
||||||
|
|
||||||
|
subroutines = {}; -- [subname] = true , so we know its subroutine
|
||||||
|
|
||||||
|
nodenames = -- translation of block names into minetest
|
||||||
|
{
|
||||||
|
["dirt"] = "default:dirt",
|
||||||
|
["cobble"] = "default:cobble",
|
||||||
|
["stone"] = "default:stone",
|
||||||
|
["wood"] = "default:wood",
|
||||||
|
["water"] = "default:water_source",
|
||||||
|
}
|
||||||
|
|
||||||
|
keywords = {
|
||||||
|
["quit"] = function() return "break;" end,
|
||||||
|
["move"] = {
|
||||||
|
["forward"] = function() return "if move.forward() then pause();paused=true; end;" end,
|
||||||
|
["backward"] = function() return "if move.backward() then pause();paused=true; end;" end,
|
||||||
|
["left"] = function() return "if move.left() then pause();paused=true; end;" end,
|
||||||
|
["right"] = function() return "if move.right() then pause();paused=true; end;" end,
|
||||||
|
["up"] = function() return "if move.up() then pause();paused=true; end;" end,
|
||||||
|
["down"] = function() return "if move.down() then pause();paused=true; end;" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
["turn"] = {
|
||||||
|
["left"] = function() return "turn.left(); pause();paused=true;" end,
|
||||||
|
["right"] = function() return "turn.right(); pause();paused=true;" end,
|
||||||
|
["random"] = function() return "if math.random(2)==1 then turn.right() else turn.left() end; pause(); paused=true;" end
|
||||||
|
},
|
||||||
|
|
||||||
|
["dig"] = function() return "dig.forward(); pause();" end, --TODO: remember to set robot energy to large value at start
|
||||||
|
|
||||||
|
["place"] = function(line)
|
||||||
|
local pattern1 = "place";
|
||||||
|
local i = string.find(line,pattern1)+ string.len(pattern1)+1
|
||||||
|
local nodename = string.sub(line, i) -- what are we placing?
|
||||||
|
if nodenames[nodename] then nodename = nodenames[nodename] end -- translate name
|
||||||
|
return "place.forward('" .. nodename .. "'); pause();"
|
||||||
|
end,
|
||||||
|
|
||||||
|
["if"] = {
|
||||||
|
["see"] = function(line)
|
||||||
|
|
||||||
|
local pattern1 = "see";
|
||||||
|
local pattern2 = "and" .. " "; -- important, space after 'and'
|
||||||
|
|
||||||
|
local i = string.find(line,pattern1) + string.len(pattern1) + 1
|
||||||
|
--nodename command
|
||||||
|
local j = string.find(line," ",i)
|
||||||
|
local nodename, command
|
||||||
|
nodename = string.sub(line,i,j-1)
|
||||||
|
if nodenames[nodename] then nodename = nodenames[nodename] end -- translate name
|
||||||
|
-- maybe command has several parts separated by 'and' ?
|
||||||
|
--cmd1 and cmd2 and cmd3
|
||||||
|
j = j+1; local cmds = {}; local found = false
|
||||||
|
while true do
|
||||||
|
local k = string.find(line,pattern2,j+1)
|
||||||
|
if not k then-- no more AND
|
||||||
|
if found then
|
||||||
|
cmds[#cmds+1] = string.sub(line,j + string.len(pattern2)) break
|
||||||
|
else
|
||||||
|
cmds[#cmds+1] = string.sub(line,j) break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if found then
|
||||||
|
cmds[#cmds+1] = string.sub(line,j+string.len(pattern2),k-1)
|
||||||
|
else
|
||||||
|
cmds[#cmds+1] = string.sub(line,j,k-1)
|
||||||
|
end
|
||||||
|
found = true
|
||||||
|
j=k
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1,#cmds do
|
||||||
|
cmds[i] = parse_line(cmds[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
return "if read_node.forward()=='" ..nodename .. "' then " .. table.concat(cmds," ") .. " end"
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_line = function(line)
|
||||||
|
local struct = keywords;
|
||||||
|
for word in string.gmatch(line,"%S+") do
|
||||||
|
local matched = struct[word]
|
||||||
|
local issub = subroutines[word]
|
||||||
|
if matched or issub then
|
||||||
|
--say(word .. " = " .. type(matched))
|
||||||
|
if type(matched) == "table" then
|
||||||
|
struct = matched; -- climb deeper into structure
|
||||||
|
else
|
||||||
|
local instruction;
|
||||||
|
if issub then
|
||||||
|
instruction = word.."();"
|
||||||
|
else
|
||||||
|
instruction = matched(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- do we have need to repeat instruction?
|
||||||
|
local i = string.find(line,word) + string.len(word) + 1
|
||||||
|
local snum = tonumber(string.sub(line,i)) or 1 -- repeating?
|
||||||
|
if snum>1 and snum<10 then
|
||||||
|
return "for i = 1,"..snum .." do " .. instruction .. " end;"
|
||||||
|
end
|
||||||
|
return instruction
|
||||||
|
end
|
||||||
|
else
|
||||||
|
say("error in line: " .. line .. ", unknown command " .. word) return ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
parse_prog = function(code)
|
||||||
|
local out = {};
|
||||||
|
local subdef = false; -- are we defining subroutine?
|
||||||
|
local subname;
|
||||||
|
local subcmds = {}
|
||||||
|
local pattern1 = "subroutine"
|
||||||
|
|
||||||
|
for line in string.gmatch(code,"[^\n]+") do -- line by line
|
||||||
|
|
||||||
|
local i = string.find(line,pattern1)
|
||||||
|
if i then -- do we define new subroutine command?
|
||||||
|
local j = i+string.len(pattern1)+1
|
||||||
|
local sname = string.sub(line,j)
|
||||||
|
if subdef and sname == "end" then -- end of subroutine
|
||||||
|
subdef = false
|
||||||
|
if not keywords[subname] then
|
||||||
|
out[#out+1 ] = "function " .. subname .. "()\n" .. table.concat(subcmds,"\n") .. "\nend"
|
||||||
|
subroutines[subname] = true;
|
||||||
|
else
|
||||||
|
-- error, subroutine name is reserved keyword
|
||||||
|
end
|
||||||
|
subcmds = {};
|
||||||
|
else
|
||||||
|
subdef = true -- all commands will now register with subroutine
|
||||||
|
subname = sname
|
||||||
|
end
|
||||||
|
else -- normal command
|
||||||
|
if subdef then
|
||||||
|
subcmds[#subcmds+1] = parse_line(line)
|
||||||
|
else
|
||||||
|
out[#out+1] = parse_line(line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
return "--coroutine NaturalLanguage autogenerated\nwhile true do paused = false; "..table.concat(out,"\n") .."if not paused then pause() end end"
|
||||||
|
end
|
||||||
|
|
||||||
|
parsed_prog = parse_prog(prog)
|
||||||
|
self.label(prog .. "\n\n==>\n\n" .. parsed_prog)
|
||||||
|
code.set(parsed_prog) -- actually run code by robot
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,158 @@
|
||||||
|
-- Natural language compiler, outputs lua code
|
||||||
|
-- (C) rnd 2021
|
||||||
|
-- TODO: add IF: if condition arg1 ACTION1 else ACTION2 ?
|
||||||
|
-- ADD SUBROUTINE: sub NAME = enter subroutine definition mode, sub end = ends definition mode
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
dtext = {};
|
||||||
|
dout = function(text) dtext[#dtext+1] = text end
|
||||||
|
text =
|
||||||
|
[[
|
||||||
|
if cond1 value action1 and action2 and action3 else actiona1 and actiona2
|
||||||
|
]]
|
||||||
|
|
||||||
|
translate = { -- dictionary of used words
|
||||||
|
["forward"] = "forward",
|
||||||
|
["backward"] = "backward",
|
||||||
|
["left"] = "left",
|
||||||
|
["right"] = "right",
|
||||||
|
["random"] = "random",
|
||||||
|
["dirt"] = "default:dirt",
|
||||||
|
["wood"]= "default:wood",
|
||||||
|
["cobble"] = "default:cobble",
|
||||||
|
}
|
||||||
|
|
||||||
|
cmds = {
|
||||||
|
["if"] = function(code,ibeg,iend) -- if COND value ACTION1 and ACTION2 and ... ACTIONn else(optional) ACTION1 and ... and ACTIONm
|
||||||
|
-- COND: 'see' nodename (block right in front), 'var = value' value of variable?,...
|
||||||
|
local ELSE = " else"
|
||||||
|
local AND = " and"
|
||||||
|
local i,j,condtype,value;
|
||||||
|
condtype, j = get_next_word(code,ibeg,iend)
|
||||||
|
local out = {};
|
||||||
|
dout(condtype)
|
||||||
|
|
||||||
|
if condtype== "see" then
|
||||||
|
value, j = get_next_word(code,j,iend)
|
||||||
|
value = translate(value or "");
|
||||||
|
if not minetest.registered_nodename(value) then say("error: unknown block name " .. value .. "used in 'if'") return "" end
|
||||||
|
out[#out+1] = "if read_node.forward() == " .. value .. " then ";
|
||||||
|
else
|
||||||
|
say("error: unknown condition " .. condtype .. " used in 'if'") return "" end
|
||||||
|
end
|
||||||
|
-- now after j left: ACTION1 else(optional) ACTION2, ACTION can be multiple, separated by ' and '
|
||||||
|
|
||||||
|
|
||||||
|
-- parse and before else
|
||||||
|
local k = j;
|
||||||
|
lcoal cmds = {}
|
||||||
|
while k do
|
||||||
|
k = string.find(code,AND,j)
|
||||||
|
if k and k<ielse then
|
||||||
|
cmds[#cmds+1] = string.sub(code,j,k-1)
|
||||||
|
j=k+1;
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
dout(table.concat(cmds,"\n"))
|
||||||
|
|
||||||
|
|
||||||
|
--j=...
|
||||||
|
out[#out+1] = "end"
|
||||||
|
|
||||||
|
|
||||||
|
return table.concat(out," "),j
|
||||||
|
|
||||||
|
end,
|
||||||
|
|
||||||
|
["move"] = function(code,ibeg,iend)
|
||||||
|
-- move forward count
|
||||||
|
local i,direction,count
|
||||||
|
direction,i = get_next_word(code,ibeg,iend)
|
||||||
|
direction = translate[direction];
|
||||||
|
if not direction then say("error: unknown direction used in 'turn'") return "" end
|
||||||
|
return "move."..direction .."(); pause();",i;
|
||||||
|
end,
|
||||||
|
|
||||||
|
["turn"] = function(code,ibeg,iend)
|
||||||
|
-- move forward count
|
||||||
|
local i,direction,count
|
||||||
|
direction,i = get_next_word(code,ibeg,iend)
|
||||||
|
|
||||||
|
direction = translate[direction];
|
||||||
|
if not direction then say("error: unknown direction used in 'turn'") return "" end
|
||||||
|
local c;
|
||||||
|
if direction == "random" then
|
||||||
|
c = "if math.random(2) == 1 then turn.left() else turn.right() end;";
|
||||||
|
else
|
||||||
|
c = "turn."..direction .."();"
|
||||||
|
end
|
||||||
|
return c.." pause();",i
|
||||||
|
end,
|
||||||
|
|
||||||
|
["dig"] = function() return "dig.forward(); pause();" end,
|
||||||
|
|
||||||
|
["place"] = function(code,ibeg,iend)
|
||||||
|
-- place nodename
|
||||||
|
local nodename,i
|
||||||
|
nodename,i = get_next_word(code,ibeg,iend)
|
||||||
|
nodename = translate[nodename]
|
||||||
|
if not nodename then say("error: unknown nodename used in 'place'") return "" end
|
||||||
|
|
||||||
|
return "place.forward('" .. nodename .. "'); pause();",i
|
||||||
|
end,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
-- given position ibeg in string find next word, return it and then return position immediately after word.
|
||||||
|
-- word is defined as a sequence of alphanumeric characters (%w)
|
||||||
|
-- example 'hello world', ibeg = 1. -> 'hello', 6
|
||||||
|
|
||||||
|
get_next_word = function(code, ibeg,iend) -- attempt to return next word, starting from position ibeg. returns word, index after word
|
||||||
|
if not ibeg or not iend then return end
|
||||||
|
local j = string.find(code,"%w",ibeg); -- where is start of word?
|
||||||
|
if not j or j>iend then return "", iend+1 end -- no words present
|
||||||
|
ibeg = j;
|
||||||
|
j = string.find(code,"%W",j);--where is end of word?
|
||||||
|
if not j or j>iend then return string.sub(code,ibeg,iend-1),iend+1 end
|
||||||
|
return string.sub(code,ibeg,j-1), j
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
parse_code = function(code)
|
||||||
|
local out = {};
|
||||||
|
local ibeg,iend,word;
|
||||||
|
local clen = string.len(code)
|
||||||
|
local step =0
|
||||||
|
|
||||||
|
iend = 1; ibeg = 1;
|
||||||
|
while step < 10 do
|
||||||
|
if ibeg>clen then break end
|
||||||
|
step = step+1
|
||||||
|
iend = string.find(code, "\n", ibeg)
|
||||||
|
if not iend then iend = clen end -- get out of loop, no more lines to process
|
||||||
|
|
||||||
|
word, ibeg = get_next_word(code,ibeg,iend)
|
||||||
|
--dout("rem " .. string.sub(code,ibeg,iend))
|
||||||
|
--dout("Dword '" .. word .. "' " .. ibeg .. " " .. iend)
|
||||||
|
local cmd = cmds[word];
|
||||||
|
|
||||||
|
if cmd then out[#out+1],ibeg = cmd(code,ibeg,iend) end
|
||||||
|
if not ibeg then ibeg = iend+1 end
|
||||||
|
if ibeg<=iend then -- still some space remaining in line, last parameter is repetition
|
||||||
|
local count,i
|
||||||
|
count,i = get_next_word(code,ibeg,iend);
|
||||||
|
count = tonumber(count) or 1
|
||||||
|
if count>9 then count = 9 elseif count<1 then count=1 end
|
||||||
|
if count > 1 then out[#out] = "for i=1,"..count.. " do " .. out[#out] .. " end" end
|
||||||
|
end
|
||||||
|
ibeg = iend +1 -- go new line
|
||||||
|
end
|
||||||
|
return table.concat(out,"\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
self.label(parse_code(text) .. "\n\n" .. table.concat(dtext,"\n"))
|
||||||
|
end
|
|
@ -0,0 +1,40 @@
|
||||||
|
-- given position ibeg in string find next word, return it and then return position immediately after word.
|
||||||
|
-- word is a sequence of alphanumeric characters
|
||||||
|
-- example 'hello world', ibeg = 1. -> 'hello', 6
|
||||||
|
|
||||||
|
get_next_word = function(code, ibeg,iend) -- attempt to return next word, starting from position ibeg. returns word, index after word
|
||||||
|
if not ibeg or not iend then return end
|
||||||
|
local j = string.find(code,"%w",ibeg); -- where is start of word?
|
||||||
|
if not j or j>iend then return "", iend+1 end -- no words present
|
||||||
|
ibeg = j;
|
||||||
|
j = string.find(code,"%W",j);--where is end of word?
|
||||||
|
if not j or j>iend then return string.sub(code,ibeg,iend-1),iend+1 end
|
||||||
|
return string.sub(code,ibeg,j-1), j
|
||||||
|
end
|
||||||
|
|
||||||
|
text = [[
|
||||||
|
hello world
|
||||||
|
today
|
||||||
|
day night
|
||||||
|
]]
|
||||||
|
ibeg = 1; iend = string.find(text,"\n",ibeg) or string.len(text) -- where is next new line
|
||||||
|
say("INIT LINE " .. ibeg .. " " .. iend .. " LINE '" .. string.sub(text,ibeg,iend-1) .."'")
|
||||||
|
|
||||||
|
|
||||||
|
for i = 1,10 do
|
||||||
|
|
||||||
|
|
||||||
|
word, ibeg = get_next_word(text,ibeg,iend)
|
||||||
|
say("word '" .. word.."', end " .. ibeg)
|
||||||
|
if ibeg>=iend then -- newline!
|
||||||
|
--say("newline")
|
||||||
|
local j = ibeg;
|
||||||
|
iend = string.find(text,"\n", iend+1) -- find next newline
|
||||||
|
|
||||||
|
if not iend then say("END") iend = string.len(text) break end -- end of text!
|
||||||
|
say("LINE " .. ibeg .. " " .. iend .. " LINE '" .. string.sub(text,ibeg,iend-1) .."'")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self.remove()
|
|
@ -0,0 +1,83 @@
|
||||||
|
if not perm2cycles then
|
||||||
|
|
||||||
|
perm2cycles = function(perm)
|
||||||
|
local n = #perm;
|
||||||
|
local i = 1; -- already reached number
|
||||||
|
local ret = {};
|
||||||
|
local visited = {};
|
||||||
|
local step = 0;
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
local cycle = {i}
|
||||||
|
local j=i;
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
step = step +1
|
||||||
|
if step > 2*n then return {} end
|
||||||
|
j=perm[j];
|
||||||
|
visited[j] = 1;
|
||||||
|
if j and j~=cycle[1] then cycle[#cycle+1]=j else break end
|
||||||
|
end
|
||||||
|
|
||||||
|
i=n+1;
|
||||||
|
for k=1,n do -- find smallest non visited yet
|
||||||
|
if not visited[k] and k<i then i = k end
|
||||||
|
end
|
||||||
|
|
||||||
|
ret[#ret+1] = cycle;
|
||||||
|
if i == n+1 then return ret end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
random_permute = function(arr)
|
||||||
|
local n = #arr;
|
||||||
|
for i = n,3,-1 do
|
||||||
|
local j = math.random(i);
|
||||||
|
local tmp = arr[j]; arr[j] = arr[i]; arr[i] = tmp;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
get_permutations = function(n)
|
||||||
|
free = {}; --[1] = {stack of free for 1 : head, a1,..., a_head}
|
||||||
|
isfree = {}; -- [i]=1 if item i free, 0 if not
|
||||||
|
current = 1; --{1,..., current element, ... , n}
|
||||||
|
selection = {};
|
||||||
|
local data = free[1]; for i=1,n do data[i]=i isfree[i]=1 end data[0] = n;
|
||||||
|
|
||||||
|
--1. pick free spot from free stack ( if not possible backtrack ) and move on onto next element ( if not possible stay at this one)
|
||||||
|
-- backtrack: current--
|
||||||
|
local data = free[current];
|
||||||
|
if data[0]<1 then -- backtrack
|
||||||
|
isfree[selection[current]] = 1;
|
||||||
|
current = current - 1;
|
||||||
|
if current <=0 then return end -- exhausted all options
|
||||||
|
else
|
||||||
|
local i = data[data[0]]; -- free possibility
|
||||||
|
selection[current] = i; isfree[i] = 0;
|
||||||
|
data[0]=data[0]-1; -- pop the stack
|
||||||
|
--try move forward
|
||||||
|
if current<n then
|
||||||
|
current = current+1;
|
||||||
|
-- get new free spots for new current
|
||||||
|
local data = free[current]; data = {};
|
||||||
|
for i = 1,n do if isfree[i] == 1 then data[#data+1]=i; break end end;
|
||||||
|
data[0]=#data;
|
||||||
|
if data[0] == 0 then -- nothing free, backtrack
|
||||||
|
isfree[selection[current]] = 1;
|
||||||
|
current = current - 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
arr2string = function(arr)
|
||||||
|
return string.gsub(_G.dump(arr),"\n","")
|
||||||
|
end
|
||||||
|
|
||||||
|
local arr = {}; for i =1,10 do arr[i] =i end; random_permute(arr);
|
||||||
|
local cycles = perm2cycles(arr);
|
||||||
|
say("random permutation = " .. arr2string(arr) .. " => cycles = " .. arr2string(cycles) )
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,104 @@
|
||||||
|
if not integer_sort then
|
||||||
|
-- sorts input according to keys, changes ordering to permutation corresponding to new order
|
||||||
|
integer_sort = function(input, keys, ordering,temp_ordering, m) -- input, keys same length n, m = how many keys, O(2*n+m)
|
||||||
|
|
||||||
|
local n = #input;
|
||||||
|
local freq = {} -- frequencies of keys
|
||||||
|
local kpos = {} -- position of keys in sorted array
|
||||||
|
|
||||||
|
for i=1,n do -- count how many occurences - O(n)
|
||||||
|
local key = keys[ordering[i]]+1;
|
||||||
|
freq[key]=(freq[key] or 0)+1
|
||||||
|
temp_ordering[i]=ordering[i];
|
||||||
|
end
|
||||||
|
|
||||||
|
local curpos = 1;kpos[1]=1;
|
||||||
|
for i =1,m-1 do -- determine positions of keys in final sorted array - O(m)
|
||||||
|
curpos = curpos + (freq[i] or 0);
|
||||||
|
kpos[i+1]=curpos -- {2=3, 3 = 6,..., n-1 = 321}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- actually place values here
|
||||||
|
for i = 1,n do -- O(n)
|
||||||
|
local key = keys[temp_ordering[i]]+1;
|
||||||
|
local pos = kpos[key];
|
||||||
|
ordering[pos] = temp_ordering[i];
|
||||||
|
kpos[key]=kpos[key]+1; -- move to next spot for that key place
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
permutate = function(input,ordering)
|
||||||
|
local output = {};
|
||||||
|
for i =1,#input do
|
||||||
|
output[i] = input[ordering[i]]
|
||||||
|
end
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
get_digits = function(Num,d,base) -- number, how many digits, what base
|
||||||
|
local digits = {};
|
||||||
|
local num = Num;
|
||||||
|
local r;
|
||||||
|
for i = 1, d do
|
||||||
|
r = num % base;
|
||||||
|
digits[#digits+1] = r;
|
||||||
|
num = (num-r)/base
|
||||||
|
end
|
||||||
|
return digits
|
||||||
|
end
|
||||||
|
|
||||||
|
dumparr = function(array)
|
||||||
|
if _G.type(array) ~= "table" then return array end
|
||||||
|
local ret = "{";
|
||||||
|
for i =1,#array-1 do
|
||||||
|
ret = ret .. dumparr(array[i]) .. ","
|
||||||
|
end
|
||||||
|
ret = ret .. dumparr(array[#array])
|
||||||
|
return ret .. "}"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
radix_sort = function(input,d,base) -- array of numbers; base is also number of keys = m, d = how many steps of sorting = number of digits for single number
|
||||||
|
|
||||||
|
out = out .."\nRADIX SORT\n\narray to be sorted " .. dumparr(input)
|
||||||
|
|
||||||
|
local n = #input;
|
||||||
|
local ordering = {}; local temp_ordering = {}; for i = 1, n do ordering[i]=i end
|
||||||
|
local keys = {};
|
||||||
|
local keylist = {};
|
||||||
|
for i = 1,n do
|
||||||
|
keylist[i] = get_digits(input[i],d,base)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
out = out .."\nlist of keys - ".. d .. " digits of base " .. base .. " expansion of numbers : \n" ..
|
||||||
|
dumparr(keylist)
|
||||||
|
|
||||||
|
for step = 1, d do
|
||||||
|
for i =1,n do
|
||||||
|
keys[i] = keylist[i][step];
|
||||||
|
end
|
||||||
|
integer_sort(input, keys, ordering, temp_ordering, base)
|
||||||
|
|
||||||
|
out = out .."\n"..step .. ". pass integer_sort : " .. dumparr(permutate(input,ordering))
|
||||||
|
end
|
||||||
|
|
||||||
|
out = out .. "\nradix sort final result : " .. dumparr(permutate(input,ordering))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--input = {"a","b","c","d","e"}
|
||||||
|
--keys = {5,3,4,1,2}
|
||||||
|
--ordering = {}; temp_ordering = {}; for i = 1, #input do ordering[i]=i end
|
||||||
|
--m=5;
|
||||||
|
|
||||||
|
--integer_sort(input, keys, ordering, temp_ordering,m);
|
||||||
|
--say(string.gsub(_G.dump(ordering),"\n",""))
|
||||||
|
--say(string.gsub(_G.dump(permutate(input,ordering)),"\n",""))
|
||||||
|
out = ""; self.label("")
|
||||||
|
|
||||||
|
input = {23,42,15,8,87};
|
||||||
|
radix_sort(input,5,3) -- d, base
|
||||||
|
self.display_text(out,60,3)
|
||||||
|
end
|
|
@ -0,0 +1,54 @@
|
||||||
|
-- room finder by rnd (45 minutes)
|
||||||
|
-- given starting position it explores 3d world to find enclosed area of room, up to max 2000 nodes
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
local rpos = self.pos()
|
||||||
|
local radius = 16
|
||||||
|
bpos = minetest.find_node_near(rpos, radius,"beds:bed_bottom");bpos.y=bpos.y+1 -- bed
|
||||||
|
--say(bpos.x .. " " .. bpos.y .. " " .. bpos.z)
|
||||||
|
|
||||||
|
|
||||||
|
walls = { -- define possible walls here
|
||||||
|
["default:cobble"]=true, ["default:wood"] = true,
|
||||||
|
["default:obsidian_glass"]=true,["default:glass"] = true,
|
||||||
|
["doors:door_obsidian_glass_a"]=true,["doors:door_obsidian_glass_b"]=true,
|
||||||
|
["doors:hidden"] = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
local find_room = function(bpos)
|
||||||
|
|
||||||
|
|
||||||
|
local cbdata = {bpos} -- explore boundary
|
||||||
|
local cdata = {[minetest.hash_node_position(bpos)] = true} -- db of room pos
|
||||||
|
local dirs = {{x=-1,y=0,z=0},{x=1,y=0,z=0},{x=0,y=-1,z=0},{x=0,y=1,z=0},{x=0,y=0,z=-1},{x=0,y=0,z=1}}
|
||||||
|
local ccount = 1
|
||||||
|
|
||||||
|
crawl_step = function()
|
||||||
|
local pos = cbdata[#cbdata];cbdata[#cbdata] = nil;
|
||||||
|
for i = 1,#dirs do
|
||||||
|
local p = {x=pos.x+dirs[i].x,y=pos.y+dirs[i].y,z=pos.z+dirs[i].z}
|
||||||
|
if not cdata[minetest.hash_node_position(p)] and not walls[minetest.get_node(p).name] then
|
||||||
|
cdata[minetest.hash_node_position(p)] = true
|
||||||
|
cbdata[#cbdata+1] = p
|
||||||
|
ccount = ccount +1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local maxsteps = 2000;
|
||||||
|
local step = 0
|
||||||
|
|
||||||
|
while #cbdata>0 and step<maxsteps do
|
||||||
|
step=step+1; crawl_step()
|
||||||
|
end
|
||||||
|
if #cbdata == 0 then say("found room around bed " .. bpos.x .. " " .. bpos.y .. " " .. bpos.z.. ", room size " .. ccount) else say("no room found. try to fix holes in walls!") end
|
||||||
|
end
|
||||||
|
|
||||||
|
find_room(bpos)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
self.remove()
|
File diff suppressed because it is too large
Load Diff
|
@ -1,46 +1,48 @@
|
||||||
--rnd 2017
|
--rnd 2017
|
||||||
if not logdata then
|
if not logdata then
|
||||||
self.label("chatlog bot");
|
self.label("");--chatlog bot");
|
||||||
_G.minetest.forceload_block(self.pos(),true)
|
_G.minetest.forceload_block(self.pos(),true)
|
||||||
n = 250;
|
n = 500;
|
||||||
idx = 1;
|
idx = 1;
|
||||||
logdata = {};
|
authusers = {["rnd"] = 1} -- who is allowed to use ?log
|
||||||
|
|
||||||
insert = function(text) -- insert new message
|
logdata = {};
|
||||||
idx = idx +1;
|
|
||||||
if idx > n then idx = 1 end
|
insert = function(text) -- insert new message
|
||||||
logdata[idx] = text;
|
idx = idx +1;
|
||||||
end
|
if idx > n then idx = 1 end
|
||||||
|
logdata[idx] = text;
|
||||||
last = function(k,filter) -- return last k messages
|
end
|
||||||
if k > n then k = 30 end
|
|
||||||
local i,j,ret;
|
last = function(k,filter) -- return last k messages
|
||||||
i=idx;j=0; ret = ""
|
if k > n then k = 30 end
|
||||||
|
local i,j,ret;
|
||||||
for j = 1,k do
|
i=idx;j=0; ret = ""
|
||||||
if not logdata[i] then break end
|
|
||||||
if filter and not string.find(logdata[i], filter) then
|
for j = 1,k do
|
||||||
else
|
if not logdata[i] then break end
|
||||||
ret = ret .. logdata[i] .. "\n";
|
if filter and not string.find(logdata[i], filter) then
|
||||||
end
|
else
|
||||||
i=i-1; if i < 1 then i = n end
|
ret = ret .. logdata[i] .. "\n";
|
||||||
end
|
end
|
||||||
return ret
|
i=i-1; if i < 1 then i = n end
|
||||||
end
|
end
|
||||||
|
return ret
|
||||||
self.listen(1)
|
end
|
||||||
end
|
|
||||||
|
self.listen(1)
|
||||||
speaker, msg = self.listen_msg()
|
end
|
||||||
if msg then
|
|
||||||
if string.sub(msg,1,4) == "?log" then
|
speaker, msg = self.listen_msg()
|
||||||
local j = string.find(msg," ",6);
|
if msg then
|
||||||
local k = tonumber(string.sub(msg,6) or "") or n;
|
if string.sub(msg,1,4) == "?log" and authusers[speaker] then
|
||||||
local text;
|
local j = string.find(msg," ",6);
|
||||||
if j then text = last(k,string.sub(msg,j+1)) else text = last(k) end
|
local k = tonumber(string.sub(msg,6) or "") or n;
|
||||||
local form = "size[8,8]".. "textarea[0.,0;11.,9.5;text;chatlog;".. text .. "]"
|
local text;
|
||||||
self.show_form(speaker, form)
|
if j then text = last(k,string.sub(msg,j+1)) else text = last(k) end
|
||||||
else
|
local form = "size[8,8]".. "textarea[0.,0;11.,9.5;text;chatlog;".. minetest.formspec_escape(text) .. "]"
|
||||||
insert(os.date("%X") .. " " .. speaker .. "> " .. msg)
|
self.show_form(speaker, form)
|
||||||
end
|
else
|
||||||
end
|
insert(os.date("%X") .. " " .. speaker .. "> " .. msg)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,204 @@
|
||||||
|
-- COPY PASTE ROBOT by rnd: c1 c2 r = markers, c = copy p = paste, rotz = rotate 90 deg cw z-axis, s = set
|
||||||
|
-- command parameters :
|
||||||
|
-- s nodename node_step
|
||||||
|
-- copy:
|
||||||
|
-- c1,c2 set markers, r set reference, c = copy,
|
||||||
|
-- p = paste at player position (reference is put there)
|
||||||
|
-- rotate:
|
||||||
|
-- c1,c2 set area, rotz = rotate 90 deg around z-axis
|
||||||
|
-- replace:
|
||||||
|
-- c1,c2 set area, then 'replace node1 node2'
|
||||||
|
|
||||||
|
if not paste then
|
||||||
|
_G.minetest.forceload_block(self.pos(),true)
|
||||||
|
paste = {};
|
||||||
|
round = function(x)
|
||||||
|
if x>0 then
|
||||||
|
return math.floor(x+0.5)
|
||||||
|
else
|
||||||
|
return -math.floor(-x+0.5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
data = {};
|
||||||
|
|
||||||
|
display_marker = function(pos,label)
|
||||||
|
minetest.add_particle(
|
||||||
|
{
|
||||||
|
pos = pos,
|
||||||
|
expirationtime = 10,
|
||||||
|
velocity = {x=0, y=0,z=0},
|
||||||
|
size = 9,
|
||||||
|
texture = label..".png",
|
||||||
|
acceleration = {x=0,y=0,z=0},
|
||||||
|
})
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self.listen(1)
|
||||||
|
self.label("")
|
||||||
|
-- self.label("WorldEdit Bot\ncommands: c1 c2 r c p s rotz")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
speaker, msg = self.listen_msg()
|
||||||
|
|
||||||
|
if speaker == "rnd" or speaker == "noah" then
|
||||||
|
local args = {}
|
||||||
|
for word in string.gmatch(msg,"%S+") do args[#args+1]=word end
|
||||||
|
|
||||||
|
local player = _G.minetest.get_player_by_name(speaker);
|
||||||
|
local p = player:getpos(); p.x = round(p.x); p.y=round(p.y); p.z = round(p.z);
|
||||||
|
if p.y<0 then p.y = p.y +1 end -- needed cause of minetest bug
|
||||||
|
if args[1] == "c1" then
|
||||||
|
paste.src1 = {x=p.x,y=p.y,z=p.z};say("marker 1 set at " .. p.x .. " " .. p.y .. " " .. p.z,speaker)
|
||||||
|
display_marker(p,"puzzle_button_off") -- c
|
||||||
|
elseif args[1] == "c2" then
|
||||||
|
paste.src2 = {x=p.x,y=p.y,z=p.z};say("marker 2 set at " .. p.x .. " " .. p.y .. " " .. p.z,speaker)
|
||||||
|
display_marker(p,"puzzle_button_on") -- c
|
||||||
|
elseif args[1] == "r" then
|
||||||
|
paste.ref = {x=p.x,y=p.y,z=p.z};say("reference set at " .. p.x .. " " .. p.y .. " " .. p.z,speaker)
|
||||||
|
display_marker(p,"puzzle_diode") -- r
|
||||||
|
elseif args[1] == "c" then -- copy
|
||||||
|
local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z);
|
||||||
|
local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z);
|
||||||
|
local count = 0; data = {};
|
||||||
|
for i = x1,x2 do
|
||||||
|
for j = y1,y2 do
|
||||||
|
for k = z1,z2 do
|
||||||
|
local node = _G.minetest.get_node({x=i,y=j,z=k});
|
||||||
|
if node.name ~= "air" then
|
||||||
|
if not data[i] then data[i]= {} end
|
||||||
|
if not data[i][j] then data[i][j]= {} end
|
||||||
|
data[i][j][k] = {node, _G.minetest.get_meta({x=i,y=j,z=k}):to_table()}
|
||||||
|
count = count +1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
say(count .. " nodes copied ");
|
||||||
|
elseif args[1] == "p" then -- paste
|
||||||
|
local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z);
|
||||||
|
local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z);
|
||||||
|
local count = 0; p.x = p.x-paste.ref.x; p.y = p.y-paste.ref.y; p.z = p.z-paste.ref.z;
|
||||||
|
for i = x1,x2 do
|
||||||
|
for j = y1,y2 do
|
||||||
|
for k = z1,z2 do
|
||||||
|
local pdata;
|
||||||
|
if data[i] and data[i][j] and data[i][j][k] then
|
||||||
|
pdata = data[i][j][k]
|
||||||
|
end
|
||||||
|
if pdata then
|
||||||
|
count = count + 1
|
||||||
|
_G.minetest.set_node({x=i+p.x,y=j+p.y,z=k+p.z}, pdata[1]);
|
||||||
|
_G.minetest.get_meta({x=i+p.x,y=j+p.y,z=k+p.z}):from_table(pdata[2])
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
say(count .. " nodes pasted ",speaker);
|
||||||
|
elseif args[1] == "s" then -- set node
|
||||||
|
local nodename = args[2] or "air"
|
||||||
|
local randomized = (nodename=="random")
|
||||||
|
local btncolors = {
|
||||||
|
"white","yellow","orange","red","magenta","purple","blue","cyan",
|
||||||
|
"green","dark_green","brown","tan","light_grey","medium_grey","dark_grey","black"
|
||||||
|
}
|
||||||
|
for i = 1,#btncolors do btncolors[i] = "basic_robot:button"..btncolors[i] end
|
||||||
|
|
||||||
|
if not minetest.registered_nodes[nodename] and not randomized then return end
|
||||||
|
local step = args[3] or 1;
|
||||||
|
local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z);
|
||||||
|
local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z);
|
||||||
|
local count = 0;
|
||||||
|
for i = x1,x2,step do
|
||||||
|
for j = y1,y2,step do
|
||||||
|
for k = z1,z2,step do
|
||||||
|
if randomized then nodename = btncolors[math.random(16)] end
|
||||||
|
minetest.set_node({x=i,y=j,z=k}, {name = nodename});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
say((x2-x1+1)*(y2-y1+1)*(z2-z1+1) .. " nodes set to " .. nodename,speaker)
|
||||||
|
elseif args[1] == "replace" then -- replace
|
||||||
|
local node1 = args[2]
|
||||||
|
local node2 = args[3]
|
||||||
|
local count = 0
|
||||||
|
local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z);
|
||||||
|
local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z);
|
||||||
|
for i = x1,x2 do
|
||||||
|
for j = y1,y2 do
|
||||||
|
for k = z1,z2 do
|
||||||
|
local node = _G.minetest.get_node({x=i,y=j,z=k});
|
||||||
|
if node.name == node1 then
|
||||||
|
_G.minetest.swap_node({x=i,y=j,z=k},{name = node2})
|
||||||
|
count = count +1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
say(count .. " nodes replaced ");
|
||||||
|
elseif args[1] == "rotz" then -- rotate around z axis, center of selection
|
||||||
|
local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z);
|
||||||
|
local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z);
|
||||||
|
|
||||||
|
|
||||||
|
local d = x2-x1; if z2-z1<d then z2 = z1+d else d = z2-z1; x2 = x1+d end -- will be rotated as square in xz
|
||||||
|
local rotzd = {
|
||||||
|
[0]=1,[1]=2,[2]=3,[3]=0,
|
||||||
|
[7]=12,[12]=9,[9]=18,[18]=7,
|
||||||
|
[8]=17,[17]=6,[6]=15,[15]=8,
|
||||||
|
[19]=4,[4]=13,[13]=10,[10]=19,
|
||||||
|
[20]=23,[23]=22,[22]=21,[21]=20,
|
||||||
|
}
|
||||||
|
local count = 0; local step = 1
|
||||||
|
|
||||||
|
local data = {}; -- copy first
|
||||||
|
for i = x1,x2 do
|
||||||
|
for j = y1,y2 do
|
||||||
|
for k = z1,z2 do
|
||||||
|
local node = _G.minetest.get_node({x=i,y=j,z=k});
|
||||||
|
minetest.swap_node({x=i,y=j,z=k},{name = "air"})
|
||||||
|
if node.name ~= "air" then
|
||||||
|
if not data[i] then data[i]= {} end
|
||||||
|
if not data[i][j] then data[i][j]= {} end
|
||||||
|
data[i][j][k] = node
|
||||||
|
count = count +1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- (x,z)->(z,-x)
|
||||||
|
-- square rotate around center: x,z -> x-dx/2, z-dz/2 ->z-dz/2,dx/2-x -> (z, dx-x)
|
||||||
|
-- (x,z) -> (z,x1+x2-x)
|
||||||
|
--[[
|
||||||
|
x1,z1
|
||||||
|
*
|
||||||
|
|
||||||
|
* x1,z1
|
||||||
|
add offset to put middle of square into 0,0 and then back..
|
||||||
|
|
||||||
|
x->x-x1-dx/2, z-z1-dz/2 -> z-z1-dz/2, x1-dx/2-x ->
|
||||||
|
z-z1-dz/2+x1+dx/2,x1-dx/2-x+z1+dz/2 =
|
||||||
|
z-z1+x1,z1+x1-x
|
||||||
|
--]]
|
||||||
|
|
||||||
|
for i = x1,x2,step do
|
||||||
|
for j = y1,y2,step do
|
||||||
|
for k = z1,z2,step do
|
||||||
|
local pdata;
|
||||||
|
if data[i] and data[i][j] and data[i][j][k] then
|
||||||
|
pdata = data[i][j][k]
|
||||||
|
end
|
||||||
|
if pdata then -- correct position, rotated 90deg, TODO!
|
||||||
|
local node = pdata
|
||||||
|
node.param2 = rotzd[node.param2] or 0;
|
||||||
|
minetest.swap_node({x=k+x1-z1,y=j,z=x1+z1-i}, node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
say(count .. " nodes rotated around z-axis");
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,16 +1,40 @@
|
||||||
if not init then
|
if not init then
|
||||||
|
|
||||||
|
self.set_properties({
|
||||||
|
visual = "mesh", mesh = "character.b3d",
|
||||||
|
textures = {"character_45.png"},
|
||||||
|
visual_size = {x = 5, y = 5}
|
||||||
|
});
|
||||||
|
move.down()
|
||||||
|
|
||||||
|
animation = {
|
||||||
|
-- Standard animations.
|
||||||
|
stand = { x= 0, y= 79, },
|
||||||
|
lay = { x=162, y=166, },
|
||||||
|
walk = { x=168, y=187, },
|
||||||
|
mine = { x=189, y=198, },
|
||||||
|
walk_mine = { x=200, y=219, },
|
||||||
|
sit = { x= 81, y=160, },
|
||||||
|
}
|
||||||
|
bstate = "walk_mine"
|
||||||
|
bspeed = 5--15
|
||||||
|
self.set_animation(animation[bstate].x,animation[bstate].y, bspeed, 0)
|
||||||
|
|
||||||
init = true; self.listen(1);
|
init = true; self.listen(1);
|
||||||
self.spam(1); self.label("help bot")
|
|
||||||
|
_G.minetest.forceload_block(self.pos(),true)
|
||||||
|
self.spam(1); self.label("") --help bot")
|
||||||
|
|
||||||
talk = function(msg) minetest.chat_send_all("<help bot> " .. msg) end
|
talk = function(msg) minetest.chat_send_all("<help bot> " .. msg) end
|
||||||
keywords = {
|
keywords = {
|
||||||
{"tp", 14},
|
{"tpr", 14},
|
||||||
|
{"tpy",19},
|
||||||
{"help",
|
{"help",
|
||||||
{"robot",6},{"",1}
|
{"robot",6},{"",1}
|
||||||
},
|
},
|
||||||
{"how",
|
{"how",
|
||||||
{"play",1},{"robot", 6},{"stone",4},{"tree",3},{"wood",3},{"lava",5},{"cobble",4},{"dirt",10},
|
{"play",1},{"island",17},{"robot", 6},{"stone",4},{"tree",3},{"wood",3},{"lava",5},{"mossy",16},{"cobble",4},{"dirt",10},{"clay",23},
|
||||||
{"do i get",1},{"do i make",1}, {"to get",1}
|
{"do i get",1},{"do i make",1}, {"to get",1},{"farm",15},
|
||||||
},
|
},
|
||||||
{"i need",
|
{"i need",
|
||||||
{"wood",3}
|
{"wood",3}
|
||||||
|
@ -19,40 +43,77 @@ if not init then
|
||||||
{"hello",2}, -- words matched must appear at beginning
|
{"hello",2}, -- words matched must appear at beginning
|
||||||
{"hi",2},
|
{"hi",2},
|
||||||
{"back",7},
|
{"back",7},
|
||||||
{" hard",{"",9}}, -- word matched can appear anywhere
|
{" 'hard",{"",9}}, -- word matched can appear anywhere
|
||||||
{" died", {"",9}},
|
{" died", {"",9}},
|
||||||
{" die",{"",8}}, {" dead",{"",8}},
|
{" die",{"",8}}, {" dead",{"",8}},
|
||||||
{"rnd",{"",11}},
|
-- {"rnd",{"",11}},
|
||||||
{"bye",{"",12}},
|
{"^bye",{"",12}},
|
||||||
{"!!",{"",9}},
|
{"!!",{"",9}},
|
||||||
|
|
||||||
{"calc", 13},
|
{"calc", 13},
|
||||||
|
{"day",18},
|
||||||
|
{"RESET_LEVEL",20},
|
||||||
|
{"YES",21},
|
||||||
}
|
}
|
||||||
answers = {
|
answers = {
|
||||||
"%s open inventory, click 'Quests' and do them to get more stuff", --1
|
"%s open inventory, click 'Quests' and do them to get more stuff", --1
|
||||||
"hello %s",
|
"hello %s",
|
||||||
"do the dirt quest to get sticks then do sapling quest",
|
"you can get wood from bush stems or trees. tree sapling needs to be planted on fertilized composter with 10 N nutrient",
|
||||||
"get pumice from lava and water. then search craft guide how to make cobble",
|
"get pumice from lava and water. then search craft guide how to make cobble",
|
||||||
"you get lava as compost quest reward or with grinder", -- 5
|
"you get lava as dig tree quest reward. warning - put lava away from flammable blocks. full composter does not burn - its safe.", -- 5
|
||||||
"you have to write a program so that robot knows what to do. for list of commands click 'help' button inside robot.",
|
"you have to write a program so that robot knows what to do. for list of commands click 'help' button inside robot.",
|
||||||
"wb %s",
|
"wb %s",
|
||||||
"dont die, you lose your stuff and it will reset your level on level 1",
|
"dont die, you lose your stuff and it will reset your level on level 1",
|
||||||
"you suck %s!", -- 9
|
"you suck %s!", -- 9
|
||||||
"to get dirt craft composter and use it with leaves", -- 10
|
"to get dirt craft composter, put gravel on it, punch it and wait until its ready. then punch again to get dirt.", -- 10
|
||||||
"rnd is afk. in the meantime i can answer your questions",
|
"rnd is afk. in the meantime i can answer your questions",
|
||||||
"bye %s",
|
"bye %s",
|
||||||
function(speaker,msg) -- 13, calc
|
function(speaker,msg) -- 13, calc
|
||||||
local expr = string.sub(msg,5); if string.find(expr,"%a") then return end
|
local expr = string.sub(msg,5);
|
||||||
local res = _G.loadstring("return " .. expr)(); say(expr .. " = " .. res)
|
if string.find(expr,"%a") then return end;
|
||||||
|
if string.find(expr,"{") then return end;
|
||||||
|
local exprfunc = _G.loadstring("return " .. expr);
|
||||||
|
local res = exprfunc and exprfunc() or say("error in expression: " .. expr);
|
||||||
|
if type(res) == "number" then say(expr .. " = " .. res) end
|
||||||
end,
|
end,
|
||||||
function(speaker,msg) -- 14,tp
|
function(speaker,msg) -- 14,tpr
|
||||||
local p1 = minetest.get_player_by_name(speaker);
|
tpr[1] = speaker
|
||||||
local p2 = minetest.get_player_by_name(string.sub(msg,4));
|
tpr[2] = string.sub(msg,5) or "";
|
||||||
|
minetest.chat_send_player(tpr[2], "#TPR: " .. speaker .. " wants to teleport to you. say \\tpy")
|
||||||
|
end,
|
||||||
|
"to make farm craft composter, put leaves on it,punch and wait until its ready. Then right click composter to see if it has enough nutrients. If yes, plant your crops on top.", -- 15
|
||||||
|
"put cobble near water and wait.", --16
|
||||||
|
"you get your own island when you finish all quests on level 1. before that your island will be reused by other players.", --17
|
||||||
|
function(speaker,msg) -- 18, day
|
||||||
|
minetest.set_timeofday(0.25); say("time set to day")
|
||||||
|
end,
|
||||||
|
function(speaker,msg) -- 19,tpy
|
||||||
|
if tpr[2] ~= speaker then return end;
|
||||||
|
local p1 = minetest.get_player_by_name(tpr[1]);
|
||||||
|
local p2 = minetest.get_player_by_name(tpr[2]);tpr[2] = ""
|
||||||
if p1 and p2 then
|
if p1 and p2 then
|
||||||
p1:setpos(p2:getpos())
|
p1:setpos(p2:getpos())
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
function(speaker,msg) -- 20,RESET_LEVEL
|
||||||
|
say("this will reset your skyblock level to beginning of level 1. are you sure " .. speaker .. "? say YES")
|
||||||
|
qa[1] = speaker; qa[2] = 22
|
||||||
|
end,
|
||||||
|
function(speaker,msg) -- 21,yes to some question
|
||||||
|
if qa[1] ~= speaker then return end
|
||||||
|
answers[qa[2]](speaker,msg)
|
||||||
|
qa[1] = ""
|
||||||
|
end,
|
||||||
|
|
||||||
|
function(speaker,msg) -- 22 reset level
|
||||||
|
say("your level is reset " .. speaker .. ". have a nice day.")
|
||||||
|
end,
|
||||||
|
|
||||||
|
"you get clay by grinding dirt in grinder ( basic_machines ). Either craft grinder from constructor or get as level 3 1st quest reward" -- 23
|
||||||
|
|
||||||
}
|
}
|
||||||
|
tpr = {"",""} -- used for teleport
|
||||||
|
qa = {"",1}; -- speaker
|
||||||
end
|
end
|
||||||
|
|
||||||
speaker,msg = self.listen_msg();
|
speaker,msg = self.listen_msg();
|
||||||
|
@ -71,7 +132,6 @@ if msg then
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,300 @@
|
||||||
|
--[[
|
||||||
|
help bot 2
|
||||||
|
|
||||||
|
'how to make/craft X' = 'how' 'make' 'x'
|
||||||
|
pattern match:
|
||||||
|
word1 word2 ... wordn
|
||||||
|
|
||||||
|
word1 - start of pattern
|
||||||
|
|
||||||
|
patterns = {
|
||||||
|
["pattern_start"] = {
|
||||||
|
{ -- list of possible sequences
|
||||||
|
{{"pattern2", ..},{"pattern3", ..}, ..},"response"} -- { patternsequence, "response"}
|
||||||
|
},
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
_G.minetest.forceload_block(self.pos(),true)
|
||||||
|
patterns = {
|
||||||
|
["calc"] = { {{}, "calc"} },
|
||||||
|
["day"] = { {{}, "day"} },
|
||||||
|
["day4ever"] = { {{}, "day4ever"} },
|
||||||
|
["crazy_mode"] = { {{}, "crazy_mode"} },
|
||||||
|
["normal_mode"] = { {{}, "normal_mode"} },
|
||||||
|
|
||||||
|
["hi"] = { {{}, "greeting"} },
|
||||||
|
["hey"] = { {{}, "greeting"} },
|
||||||
|
["hello"] = { {{}, "greeting"} },
|
||||||
|
|
||||||
|
["bye"] = { {{}, "goodbye"} },
|
||||||
|
|
||||||
|
["help"] = {
|
||||||
|
{
|
||||||
|
{{"play"}}, "play_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{}, "help_general"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
["tell"] = {
|
||||||
|
{
|
||||||
|
{{"bot"}}, "tell_bot"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
["ask"] = {
|
||||||
|
{
|
||||||
|
{{"bot"}}, "ask_bot"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
["how"] = {
|
||||||
|
{
|
||||||
|
{{"plant"},{"tree"}}, "plant_tree_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"play"}}, "play_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"get"},{"island"}}, "getting_island_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"get"},{"tree"}}, "plant_tree_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"get"},{"wood"}}, "getting_wood_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"get"},{"clay"}}, "getting_clay_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"get"},{"stone"}}, "getting_stone_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"get","make"},{"dirt"}}, "getting_dirt_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"get","find"}}, "getting_stuff_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"craft"}}, "craft_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"farm"}}, "farm_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"robot"}}, "robot_help"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{{"craft","make"}}, "craft_help"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
["tpr"] = { {{}, "tpr"} },
|
||||||
|
["tpy"] = { {{}, "tpy"} },
|
||||||
|
}
|
||||||
|
|
||||||
|
bot_knowledge = {}; -- bot knows stuff players tell it
|
||||||
|
chat_data = {} -- various player data
|
||||||
|
--[[
|
||||||
|
[name] = {greet = true} -- already said hi
|
||||||
|
tpr = requester -- someone want to teleport to 'name'
|
||||||
|
--]]
|
||||||
|
|
||||||
|
responses = {
|
||||||
|
["greeting"] = function(name,imatch, iendmatch, words)
|
||||||
|
if imatch>2 then return end
|
||||||
|
if not chat_data[name] then chat_data[name] = {greet = true} elseif chat_data[name].greet then return end
|
||||||
|
|
||||||
|
chat_data[name].greet = true -- remember we said hi
|
||||||
|
|
||||||
|
local ipdata = _G.helloip.players[name]; local country = 'en'
|
||||||
|
if ipdata then country = ipdata.country end
|
||||||
|
|
||||||
|
local greetings = {
|
||||||
|
["ZZ"] = "hi ",
|
||||||
|
["EN"] = "hello and welcome ",
|
||||||
|
["DE"] = "hallo und willkommen ",
|
||||||
|
["FR"] = "bonjour et bienvenue ",
|
||||||
|
["PL"] = "czesc i witaj ",
|
||||||
|
["RU"] = "privet i dobro pozhalovat' ",
|
||||||
|
["NL"] = "hallo en welkom ",
|
||||||
|
}
|
||||||
|
talk((greetings[country] or greetings["EN"]) .. name )
|
||||||
|
end,
|
||||||
|
|
||||||
|
["goodbye"] = function(name,imatch,iendmatch, words)
|
||||||
|
if imatch>2 then return end
|
||||||
|
talk("see you later " .. name)
|
||||||
|
end,
|
||||||
|
["farm_help"] = function(name)
|
||||||
|
_G.basic_robot.gui["farming_help"].show(name)
|
||||||
|
end,
|
||||||
|
["robot_help"] = function(name)
|
||||||
|
_G.basic_robot.gui["robot_help"].show(name)
|
||||||
|
end,
|
||||||
|
["craft_help"] = function(name)
|
||||||
|
local text = "Build 3x3 normal wood table on the ground. Drop items in shape of crafting recipe on the table. Then use craft tool on table to craft item.\n\nIt is important to be looking in direction toward top of recipe.\n\nYou can craft more than 1 item - try dropping 5 of each items in recipe to craft 5 items ...\n\nUsing craft tool on bush will give you wood."
|
||||||
|
local form = "size[8,4.5] textarea[0,0.25;9,5.5;msg;CRAFT HELP;"..text .."]"
|
||||||
|
minetest.show_formspec(name, "basic_craft_help_text",form)
|
||||||
|
end,
|
||||||
|
["plant_tree_help"] = function(name) talk(name .. " you need to plant tree on composter. insert 10 leaves in composter first by putting leaves on top and punching composter. repeat this 10 times.") end,
|
||||||
|
["play_help"] = function(name) talk(name .. " open inventory and read crafting and farming help. Look at quests too and do them to progress. You can make island larger with leaves.") end,
|
||||||
|
["getting_island_help"] = function(name) talk(name .. " you need to complete level 1 to get your own island. for now your island only temporary.") end,
|
||||||
|
["help_general"] = function(name) talk("what you need help with " .. name .. " ?") end,
|
||||||
|
["getting_clay_help"] = function(name) talk("you get clay by grinding dirt in grinder ( basic_machines ). Either craft grinder from constructor or get it as level 3 1st quest reward") end,
|
||||||
|
["getting_wood_help"] = function(name) talk("you can get wood from bush stems or trees - use craft tool on bush stem.") end,
|
||||||
|
["getting_stone_help"] = function(name) talk("get pumice from lava and water. then search craft guide how to make cobble") end,
|
||||||
|
["getting_dirt_help"] = function(name) talk("place gravel on composter and punch composter.when composting done punch again to get out dirt.") end,
|
||||||
|
|
||||||
|
["tpr"] = function(name,imatch, iendmatch, words)
|
||||||
|
local target = words[2]; if not target then return end
|
||||||
|
if not minetest.get_player_by_name(target) then return end
|
||||||
|
local tdata = chat_data[target];
|
||||||
|
if not tdata then chat_data[target] = {}; tdata = chat_data[target] end
|
||||||
|
tdata.tpr = name
|
||||||
|
talk(name .. " wants to teleport to you - say tpy", target)
|
||||||
|
end,
|
||||||
|
["tpy"] = function(name,imatch, iendmatch, words)
|
||||||
|
local data = chat_data[name];
|
||||||
|
if not data then chat_data[name] = {}; data = chat_data[name] end
|
||||||
|
local requester = data.tpr; if not requester then return end
|
||||||
|
|
||||||
|
local rpl = minetest.get_player_by_name(requester)
|
||||||
|
if not rpl then return end
|
||||||
|
rpl:set_pos( minetest.get_player_by_name(name):get_pos() )
|
||||||
|
data.tpr = nil
|
||||||
|
end,
|
||||||
|
["calc"] = function(name,imatch,__,words) -- calculator
|
||||||
|
if imatch~=1 then return end
|
||||||
|
local expr = string.sub(table.concat(words," "),5)
|
||||||
|
if string.find(expr,"%a") then return end;
|
||||||
|
if string.find(expr,"{") then return end;
|
||||||
|
local exprfunc = _G.loadstring("return " .. expr);
|
||||||
|
local res = exprfunc and exprfunc() or say("error in expression: " .. expr);
|
||||||
|
if type(res) == "number" then talk(expr .. " = " .. res) end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["ask_bot"] = function(name,imatch, iendmatch, words)
|
||||||
|
if imatch>1 then return end
|
||||||
|
local expr = string.sub(table.concat(words," "),9)
|
||||||
|
--i = string.find(expr," ")
|
||||||
|
--if i then expr = string.sub(expr,1,i-1) end
|
||||||
|
local answer = bot_knowledge[expr];
|
||||||
|
if not answer then
|
||||||
|
talk("i don't know about " .. expr)
|
||||||
|
else
|
||||||
|
talk(expr .. " " .. answer)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["tell_bot"] = function(name,imatch, iendmatch, words)
|
||||||
|
if imatch>1 then return end
|
||||||
|
local expr = string.sub(table.concat(words," "),10)
|
||||||
|
local i = string.find(expr, " ")
|
||||||
|
if not i then
|
||||||
|
talk("what did you want to tell me about " .. expr .. " ?")
|
||||||
|
else
|
||||||
|
local dwords = {" is ", " are "}
|
||||||
|
local j;
|
||||||
|
for k=1,#dwords do j = string.find(expr,dwords[k]);if j then break end end
|
||||||
|
local topic, value
|
||||||
|
if j then
|
||||||
|
topic = string.sub(expr,1,j-1) value = string.sub(expr,j)
|
||||||
|
else
|
||||||
|
topic = string.sub(expr,1,i-1) value = string.sub(expr,i+1)
|
||||||
|
end
|
||||||
|
bot_knowledge[topic] = value
|
||||||
|
talk("i will remember what you told me about " .. topic, name)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["day"] = function()
|
||||||
|
minetest.set_timeofday(0.25); talk("time set to day")
|
||||||
|
end,
|
||||||
|
["day4ever"] = function()
|
||||||
|
minetest.set_timeofday(0.25); talk("forever day")
|
||||||
|
minetest.settings:set("time_speed",0);
|
||||||
|
end,
|
||||||
|
["crazy_mode"] = function()
|
||||||
|
talk("crazy mode ON")
|
||||||
|
minetest.settings:set("time_speed",500000);
|
||||||
|
end,
|
||||||
|
["normal_mode"] = function()
|
||||||
|
talk("crazy mode OFF")
|
||||||
|
minetest.settings:set("time_speed",72);
|
||||||
|
end
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
talk = function(text,name)
|
||||||
|
if not name then
|
||||||
|
minetest.chat_send_all("<help bot> " .. text)
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(name,"<help bot> " .. text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
check_msg = function(text)
|
||||||
|
local level = 0;
|
||||||
|
local pattern;
|
||||||
|
local words = {}
|
||||||
|
for word in string.gmatch(text,"[^%s,?:]+") do words[#words+1] = word end
|
||||||
|
|
||||||
|
local imatch
|
||||||
|
for i = 1,#words do
|
||||||
|
if patterns[words[i]] then pattern = patterns[words[i]] imatch = i end -- perhaps this will match?
|
||||||
|
end
|
||||||
|
if not imatch then return end
|
||||||
|
--say("possible match: " .. words[imatch])
|
||||||
|
|
||||||
|
-- check out all pattern possibilities
|
||||||
|
local jmatch
|
||||||
|
local iendmatch = imatch
|
||||||
|
|
||||||
|
for j = 1, #pattern do
|
||||||
|
if jmatch then break end -- already got it
|
||||||
|
|
||||||
|
local level = 1
|
||||||
|
local pat = pattern[j]
|
||||||
|
--say("pattern " .. j .. " length :" .. #pat[1]+1)
|
||||||
|
if #pat[1] == 0 then -- empty pattern, we have match
|
||||||
|
jmatch = j; break
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = imatch+1, #words do -- only search from next word
|
||||||
|
if jmatch then break end
|
||||||
|
for k = 1, #pat[1][level] do
|
||||||
|
if words[i] == pat[1][level][k] then
|
||||||
|
level = level +1;
|
||||||
|
if #pat[1]+1 == level then jmatch = j iendmatch = i end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if jmatch then
|
||||||
|
local responseid = pattern[jmatch][2]
|
||||||
|
--say("match: " .. words[imatch] .. ", response " .. responseid)
|
||||||
|
return responses[responseid],imatch,iendmatch, words
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self.listen(1);
|
||||||
|
--self.label("help bot - ask me questions")
|
||||||
|
self.label("")
|
||||||
|
end
|
||||||
|
|
||||||
|
speaker,msg = self.listen_msg()
|
||||||
|
if msg then
|
||||||
|
local response, imatch, iendmatch, words
|
||||||
|
response, imatch,iendmatch, words = check_msg(msg)
|
||||||
|
if response then response(speaker, imatch, iendmatch, words) end
|
||||||
|
end
|
|
@ -1,32 +1,45 @@
|
||||||
-- return minetest object count for 5x5x5 blocks
|
-- minetest object listen in radius 100 around robot
|
||||||
|
|
||||||
if not init then init = true
|
if not init then init = false
|
||||||
|
|
||||||
local objs = minetest.get_objects_inside_radius(self.pos(), 30000);
|
local objs = minetest.get_objects_inside_radius(self.pos(), 100);
|
||||||
local ret = {};
|
local ret = {};
|
||||||
|
|
||||||
local round = function(x) return math.floor(x/5)*5 end
|
local round = function(x) return math.floor(x/5)*5 end
|
||||||
local ret = {};
|
local ret = {};
|
||||||
|
|
||||||
for i = 1, #objs do
|
for i = 1, #objs do
|
||||||
local p = objs[i]:get_pos();
|
local p = objs[i]:get_pos();
|
||||||
local phash = round(p.x) .. " " .. round(p.y) .. " " .. round(p.z);
|
local luaent = objs[i]:get_luaentity();
|
||||||
ret[phash] = (ret[phash] or 0) + 1
|
local entname = ""
|
||||||
end
|
if luaent then
|
||||||
|
--entname = serialize(luaent)
|
||||||
local out = {};
|
entname = luaent.itemstring
|
||||||
for k,v in pairs(ret) do
|
if entname == "robot" then entname = entname .. " " .. luaent.name end
|
||||||
out[#out+1] = {k,v}
|
elseif objs[i]:is_player() then
|
||||||
end
|
entname = "PLAYER " .. objs[i]:get_player_name()
|
||||||
|
end
|
||||||
table.sort(out, function(a,b) return a[2]>b[2] end)
|
|
||||||
local res = {};
|
local phash = round(p.x) .. " " .. round(p.y) .. " " .. round(p.z);
|
||||||
for i = 1, #out do
|
if entname then ret[phash] = (ret[phash] or "") .. entname .. ", " end
|
||||||
res[#res+1] = out[i][1] .. "=" .. out[i][2]
|
end
|
||||||
end
|
|
||||||
|
local out = {};
|
||||||
self.label("#objects " .. #objs .. "\n" .. table.concat(res, "\n"))
|
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
|
end
|
|
@ -0,0 +1,43 @@
|
||||||
|
-- text printer by rnd
|
||||||
|
-- instruction: go to position where text starts and look in desired direction
|
||||||
|
-- say: t TEXT\nTEXT...
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
names = {["rnd"]=true,["PrairieWind"] = true}
|
||||||
|
|
||||||
|
get_dir = function(view)
|
||||||
|
local dir
|
||||||
|
if math.abs(view.x)>math.abs(view.z) then
|
||||||
|
if view.x>0 then dir = {1,0} else dir = {-1,0} end
|
||||||
|
else
|
||||||
|
if view.z>0 then dir = {0,1} else dir = {0,-1} end
|
||||||
|
end
|
||||||
|
return dir
|
||||||
|
end
|
||||||
|
|
||||||
|
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())
|
||||||
|
local i=0;
|
||||||
|
local x=0;local y=0
|
||||||
|
while i<string.len(text) do
|
||||||
|
i=i+1
|
||||||
|
local c = string.sub(text,i,i)
|
||||||
|
if c == "\\" and string.sub(text,i+1,i+1) == "n" then
|
||||||
|
x=0;y=y-1;i=i+2;c = string.sub(text,i,i)
|
||||||
|
end
|
||||||
|
cb = (string.byte(c) or 32)-97
|
||||||
|
minetest.set_node({x=pos.x+dir[1]*x,y=pos.y+y,z=pos.z+dir[2]*x},{name = "basic_robot:button_"..(97+cb)})
|
||||||
|
x=x+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.listen(1)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
speaker,msg = self.listen_msg()
|
||||||
|
if names[speaker] and string.sub(msg,1,2) == "t " then
|
||||||
|
|
||||||
|
render_text(string.sub(msg,3),speaker)
|
||||||
|
end
|
|
@ -0,0 +1,74 @@
|
||||||
|
--text formatting to specified width ( real font width appearance )
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
width = 13; -- desired width of formatted text
|
||||||
|
text = "bereits riskante situationen werden durch die britische variante noch riskanter"
|
||||||
|
dout = function(text) say(text,"_") end
|
||||||
|
|
||||||
|
cwidths = { -- how many chars fit into string lenght of 46 repeated a's
|
||||||
|
["a"] = 46, ["b"] = 46,["c"] = 57,["d"] = 46,["e"] = 46,
|
||||||
|
["f"] = 103,["g"] = 46,["h"] = 46,["i"] = 103,["j"] = 103,
|
||||||
|
["k"] = 52,["l"] = 103,["m"] = 32,["n"] = 46,["o"] = 46,
|
||||||
|
["p"] = 46,["q"] = 46,["r"] = 83,["s"] = 52,["t"] = 103,
|
||||||
|
["u"] = 46, ["v"] = 52,["w"] = 34.5,["x"] = 52,["y"] = 52,
|
||||||
|
["z"] = 52,
|
||||||
|
[" "] = 103,["."] = 103, [","] = 103,[":"]=103,[";"]=103,
|
||||||
|
["?"] = 46,
|
||||||
|
|
||||||
|
["0"] = 52,["1"] = 52,["2"] = 46,["3"] = 46,["4"] = 46,
|
||||||
|
["5"] = 46,["6"] = 46,["7"] = 46,["8"] = 46,["9"] = 46,
|
||||||
|
}
|
||||||
|
|
||||||
|
local ac = cwidths["a"];
|
||||||
|
for k,v in pairs(cwidths) do cwidths[k] = ac/v end -- compute lenghts in widths of 'a'
|
||||||
|
|
||||||
|
format_text = function(text,width,cwidths)
|
||||||
|
local ret = {};
|
||||||
|
local x = 0;
|
||||||
|
for word in string.gmatch(text,"%S+") do
|
||||||
|
local xw = x; -- remember where we were before word
|
||||||
|
local newline = false;
|
||||||
|
|
||||||
|
for i = 1, string.len(word) do
|
||||||
|
local c = string.sub(word,i,i)
|
||||||
|
local w = cwidths[c] or 1
|
||||||
|
if c~="\n" then
|
||||||
|
x=x+w;
|
||||||
|
if x>width then newline = true end
|
||||||
|
else
|
||||||
|
ret[#ret+1]=c;x=0; -- adding new line character
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if newline then -- add word and space between words if not in newline
|
||||||
|
ret[#ret+1] = "\n"..word.. " ";
|
||||||
|
x=x+cwidths[" "]
|
||||||
|
x=x-xw; -- word width in new line
|
||||||
|
else
|
||||||
|
x=x+cwidths[" "]
|
||||||
|
ret[#ret+1] = word.." "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(ret,"")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
display = function(width)
|
||||||
|
local res = format_text(text, width,cwidths)
|
||||||
|
self.label(res)
|
||||||
|
end
|
||||||
|
|
||||||
|
display(width)
|
||||||
|
|
||||||
|
--self.show_form("_",
|
||||||
|
--"size[6,6] label[0,0;"..
|
||||||
|
--res .. "]" )
|
||||||
|
|
||||||
|
--self.remove()
|
||||||
|
self.listen(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
speaker,msg = self.listen_msg()
|
||||||
|
if speaker == "_" then
|
||||||
|
display( tonumber(msg) or width)
|
||||||
|
end
|
|
@ -0,0 +1,22 @@
|
||||||
|
from http.server import HTTPServer,SimpleHTTPRequestHandler
|
||||||
|
|
||||||
|
server_address = ('0.0.0.0', 80) # address 0.0.0.0 makes it listen to all requests from anywhere
|
||||||
|
|
||||||
|
class HTTPRequestHandler(SimpleHTTPRequestHandler):
|
||||||
|
def do_POST(self):
|
||||||
|
content_length = int(self.headers['Content-Length'])
|
||||||
|
body = self.rfile.read(content_length)
|
||||||
|
print(body.decode('utf-8')) #log display
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
print("D " + self.path)
|
||||||
|
SimpleHTTPRequestHandler.do_GET(self) #process using default do_GET
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
httpd = HTTPServer(server_address, HTTPRequestHandler)
|
||||||
|
|
||||||
|
httpd.serve_forever()
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h2>rnd's web robot</h2>
|
||||||
|
|
||||||
|
<form action="" method = "">
|
||||||
|
<label for="cmd">command:</label><br>
|
||||||
|
<input type="text" id="cmd" name="cmd" value=""><br>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,62 @@
|
||||||
|
-- irc_bot, 05/02/2022 by rnd
|
||||||
|
-- adds irc bot commands with password login
|
||||||
|
|
||||||
|
if not init then init = true
|
||||||
|
_G.basic_robot.ircbot = {}; ircbot = _G.basic_robot.ircbot
|
||||||
|
ircbot.user_list = {} -- [user] = true, must login first
|
||||||
|
|
||||||
|
ircbot.auth_data = { -- [user] = {pass_hash,level,robot_name}
|
||||||
|
["r_n_d"] = {"5yfRRkrhJDbomacm2lsvEdg4GyY",3,"rnd1"},
|
||||||
|
["Noah"] = {"5yfRRkrhJDbomacm2lsvEdg4GyY",3,"noah1"}
|
||||||
|
}; --
|
||||||
|
|
||||||
|
robotname = self.name()
|
||||||
|
|
||||||
|
_G.irc.register_bot_command("c", {
|
||||||
|
params = "",
|
||||||
|
description = "",
|
||||||
|
func = function(usr,msg)
|
||||||
|
|
||||||
|
-- user not logged in yet?
|
||||||
|
local lvl = ircbot.user_list[usr.nick]
|
||||||
|
if not lvl then
|
||||||
|
if msg == "" then return false,"basic_robot: login first using: c $password" end
|
||||||
|
if not ircbot.auth_data[usr.nick] then return false, "basic_robot: you are not in user database. please contact server admin." end
|
||||||
|
|
||||||
|
if ircbot.auth_data[usr.nick][1] == minetest.get_password_hash("", msg) then
|
||||||
|
ircbot.user_list[usr.nick] = ircbot.auth_data[usr.nick][2]
|
||||||
|
local msg = "basic_robot: Logged in as " .. usr.nick ..", level " .. ircbot.user_list[usr.nick]
|
||||||
|
lvl = ircbot.auth_data[usr.nick][2]
|
||||||
|
local robotname = ircbot.auth_data[usr.nick][3]
|
||||||
|
if lvl>=3 then msg = msg .. ". you can use 'c !lua_cmd' to run lua_cmd in robot " .. robotname .. " sandbox" end
|
||||||
|
return false, msg
|
||||||
|
else
|
||||||
|
return false,"basic_robot: wrong password!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- action here : DEMO just displays message once logged in
|
||||||
|
local c = string.sub(msg,1,1)
|
||||||
|
if c~="!" or lvl<3 then _G.basic_robot.ircmsg = msg return end
|
||||||
|
|
||||||
|
local ScriptFunc, CompileError = _G.loadstring( string.sub(msg,2))
|
||||||
|
if CompileError then return false, CompileError end
|
||||||
|
|
||||||
|
local robotname = ircbot.auth_data[usr.nick][3]
|
||||||
|
_G.setfenv( ScriptFunc, _G.basic_robot.data[robotname].sandbox ) -- run code in robot sandbox
|
||||||
|
local Result, RuntimeError = _G.pcall( ScriptFunc );
|
||||||
|
if result then return false, _G.tostring(Result) end
|
||||||
|
if RuntimeError then return false,RuntimeError end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
-- how to send msg to irc user
|
||||||
|
ircchat = minetest.registered_chatcommands["irc_msg"].func;
|
||||||
|
name = "r_n_d" -- client on irc you want to send msg too
|
||||||
|
-- ircchat("ROBOT", name .." " .. "hello irc world") -- chat will appear as coming from <ROBOT> on skyblock
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
self.label(_G.basic_robot.ircmsg or "")
|
|
@ -0,0 +1 @@
|
||||||
|
D:\prog\programming\Python\Python37-32\python https_server.py
|
|
@ -0,0 +1,24 @@
|
||||||
|
-- SETTINGS FOR BASIC_ROBOT
|
||||||
|
local b = basic_robot;
|
||||||
|
|
||||||
|
b.call_limit = {50,200,1500,10^9}; -- how many execution calls per script run allowed, for auth levels 0,1,2 (normal, robot, puzzle, admin)
|
||||||
|
b.count = {2,6,16,128} -- how many robots player can have
|
||||||
|
|
||||||
|
b.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches
|
||||||
|
b.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running mod, password used for authentifications
|
||||||
|
|
||||||
|
b.admin_bot_pos = {x=0,y=1,z=0} -- position of admin robot spawner that will be run automatically on server start
|
||||||
|
|
||||||
|
b.maxoperations = 10; -- how many operations (dig, place,move,...,generate energy,..) available per run, 0 = unlimited
|
||||||
|
b.dig_require_energy = true; -- does robot require energy to dig?
|
||||||
|
|
||||||
|
b.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
|
||||||
|
["moreblocks:circular_saw"] = true,
|
||||||
|
["craft_guide:sign_wall"] = true,
|
||||||
|
["basic_machines:battery_0"] = true,
|
||||||
|
["basic_machines:battery_1"] = true,
|
||||||
|
["basic_machines:battery_2"] = true,
|
||||||
|
["basic_machines:generator"] = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
b.http_api = minetest.request_http_api();
|
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
Loading…
Reference in New Issue