fixes and new scripts

master
ac-minetest 2021-01-07 11:30:01 +01:00
parent 1680a70ea8
commit 79bbe6c2af
26 changed files with 3777 additions and 736 deletions

View File

@ -19,7 +19,7 @@ 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:getyaw();
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
@ -113,7 +113,8 @@ 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();
@ -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,6 +570,31 @@ 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) local register_robot_button = function(R,G,B,type)
minetest.register_node("basic_robot:button"..R..G..B, minetest.register_node("basic_robot:button"..R..G..B,
@ -587,7 +614,9 @@ local register_robot_button = function(R,G,B,type)
local meta = minetest.get_meta(ppos); local meta = minetest.get_meta(ppos);
local name = meta:get_string("name"); local name = meta:get_string("name");
local data = basic_robot.data[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 if data then
write_keyevent(data,pos, player:get_player_name(),type)
end
end end
}) })
@ -600,6 +629,7 @@ minetest.register_node("basic_robot:button"..number,
tiles = {"robot_button".. number .. ".png"}, tiles = {"robot_button".. number .. ".png"},
inventory_image = "robot_button".. number .. ".png", inventory_image = "robot_button".. number .. ".png",
wield_image = "robot_button".. number .. ".png", wield_image = "robot_button".. number .. ".png",
paramtype2 = "facedir",
is_ground_content = false, is_ground_content = false,
groups = {cracky=3}, groups = {cracky=3},
@ -611,7 +641,9 @@ minetest.register_node("basic_robot:button"..number,
local meta = minetest.get_meta(ppos); local meta = minetest.get_meta(ppos);
local name = meta:get_string("name"); local name = meta:get_string("name");
local data = basic_robot.data[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 if data then
write_keyevent(data,pos, player:get_player_name(),type)
end
end end
}) })
end end
@ -626,6 +658,7 @@ minetest.register_node("basic_robot:button_"..number,
wield_image = string.format("%03d",number).. ".png", wield_image = string.format("%03d",number).. ".png",
is_ground_content = false, is_ground_content = false,
groups = {cracky=3}, groups = {cracky=3},
paramtype2 = "facedir",
on_punch = function(pos, node, player) on_punch = function(pos, node, player)
local name = player:get_player_name(); if name==nil then return end local name = player:get_player_name(); if name==nil then return end
local round = math.floor; local round = math.floor;
@ -634,7 +667,10 @@ minetest.register_node("basic_robot:button_"..number,
local meta = minetest.get_meta(ppos); local meta = minetest.get_meta(ppos);
local name = meta:get_string("name"); local name = meta:get_string("name");
local data = basic_robot.data[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 if data then
write_keyevent(data,pos, player:get_player_name(),type)
--data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = player:get_player_name(), type = type}
end
end end
}) })
end end
@ -656,7 +692,10 @@ minetest.register_node("basic_robot:button_"..number,
local meta = minetest.get_meta(ppos); local meta = minetest.get_meta(ppos);
local name = meta:get_string("name"); local name = meta:get_string("name");
local data = basic_robot.data[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 if data then
write_keyevent(data,pos, player:get_player_name(),type)
--data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = player:get_player_name(), type = number}
end
end end
}) })
end end
@ -693,14 +732,21 @@ register_robot_button_custom(285,"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
@ -829,7 +875,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 +915,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
@ -1304,7 +1350,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 +1359,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 +1518,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

View File

@ -26,7 +26,7 @@ basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes invento
basic_robot.http_api = minetest.request_http_api(); basic_robot.http_api = minetest.request_http_api();
basic_robot.version = "2020/10/14a"; basic_robot.version = "2020/11/27a";
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
@ -69,12 +69,12 @@ function getSandboxEnv (name)
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 = {
@ -97,7 +97,7 @@ function getSandboxEnv (name)
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,
@ -171,7 +171,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 +253,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 +277,7 @@ 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, end,
connected = function() connected = function()
@ -536,7 +536,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,
@ -832,7 +832,7 @@ local robot_spawner_update_form = function (pos, mode)
"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,9.8;code;;".. code.."]"..
"button[-0.25,7.5;1.25,1;EDIT;EDIT]".. "button[-0.25,7.5;1.25,1;EDIT;EDIT]"..
"button_exit[-0.25,-0.25;1.25,1;OK;SAVE]".. "button[-0.25,-0.25;1.25,1;OK;SAVE]"..
"button_exit[-0.25, 0.75;1.25,1;spawn;START]".. "button_exit[-0.25, 0.75;1.25,1;spawn;START]"..
"button[-0.25, 1.75;1.25,1;despawn;STOP]".. "button[-0.25, 1.75;1.25,1;despawn;STOP]"..
"field[0.25,3.;1.,1;id;id;"..id.."]".. "field[0.25,3.;1.,1;id;id;"..id.."]"..
@ -882,10 +882,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 +949,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;
@ -1099,7 +1104,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 = {};
@ -1280,6 +1285,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
@ -1663,8 +1670,11 @@ minetest.register_node("basic_robot:spawner", {
param1=1, param1=1,
walkable = true, walkable = true,
alpha = 150, 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 +1691,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 = {
@ -1718,6 +1755,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
@ -1831,9 +1869,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 +1911,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 +1926,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

View File

@ -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 === ","",
@ -201,7 +201,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",
}, },
@ -328,15 +328,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 +349,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)

View File

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

View File

@ -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 = {};

117
scripts/games/checkers.lua Normal file
View File

@ -0,0 +1,117 @@
--checkers by rnd, 1.5 hr
if not init then init=true
spos = self.spawnpos()
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")
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

View File

@ -1,6 +1,7 @@
-- CONNECT, coded in 20 minutes by rnd -- CONNECT, coded in 20 minutes by rnd
if not data then if not data then
m=8;n=8;turn = 0; num = 4; m=10;n=10;turn = 0; num = 5;
-- m=3;n=3;turn = 0; num = 3;
self.spam(1);t0 = _G.minetest.get_gametime(); self.spam(1);t0 = _G.minetest.get_gametime();
spawnpos = self.spawnpos() -- place mines spawnpos = self.spawnpos() -- place mines
state = 0; -- 0 signup 1 game state = 0; -- 0 signup 1 game
@ -34,7 +35,7 @@ if not data then
return c1 return c1
end end
self.label("CONNECT 4 : GREEN starts play. 2 players punch to join game.") self.label("TRY TO GET FIRST " .. num .. " IN A ROW! : GREEN starts play. 2 players punch to join game.")
end end
event = keyboard.get(); event = keyboard.get();
@ -43,10 +44,15 @@ if event then
if x<1 or x>m or z<1 or z>n then if x<1 or x>m or z<1 or z>n then
elseif event.type == 2 then --if event.type == 2 then elseif event.type == 2 then --if event.type == 2 then
if state == 0 then if state == 0 then
if #players<2 then players[#players+1] = event.puncher if #players<2 then players[#players+1] = event.puncher -- 1 is green, turn 0 = green
else state = 1 end else state = 1 end
if #players==2 then state = 1 end if #players==2 then state = 1 end
end end
if event.puncher == players[1] then -- green
if turn~=0 then return end -- ignore if not player turn
else
if turn~=1 then return end
end
keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4+turn); keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4+turn);
data[x][z] = 4+turn; data[x][z] = 4+turn;
if get_count(x,z) == num then say("CONGRATULATIONS! " .. event.puncher .. " has "..num .. " in a row"); self.remove(); goto END end if get_count(x,z) == num then say("CONGRATULATIONS! " .. event.puncher .. " has "..num .. " in a row"); self.remove(); goto END end

View File

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

94
scripts/games/go.lua Normal file
View File

@ -0,0 +1,94 @@
--go by rnd
if not init then init=true
spos = self.spawnpos()
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

View File

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

View File

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

View File

@ -1,89 +1,130 @@
-- '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()
dice = 0
for i = 1,12 do for j = 1,12 do spawns = {
minetest.swap_node({x=pos.x+i,y=pos.y+1,z=pos.z+j},{name = "air"}) {2,2,1,2,2,"basic_robot:buttonFF8080"}, -- xstart,zstart,ystart, dimx, dimz, nodename
end end {2,11,1,2,2,"basic_robot:button8080FF"},
{11,11,1,2,2,"basic_robot:button80FF80"},
for k = 1,#spawns do {11,2,1,2,2,"basic_robot:buttonFFFF80"}, --4 bases
for i = 0,1 do for j = 0,1 do
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]}) {7,3,0,1,4,"basic_robot:buttonFF8080"}, -- red final
end end {3,7,0,4,1,"basic_robot:button8080FF"}, -- blue final
end {7,8,0,1,4,"basic_robot:button80FF80"}, -- green final
{8,7,0,4,1,"basic_robot:buttonFFFF80"}, -- yellow final
keyboard.set({x=pos.x+7,y=pos.y+1,z=pos.z+7},7)
{1,1,0,5,5,"basic_robot:button808080"},{6,1,0,3,1,"basic_robot:button808080"},
end {9,1,0,5,5,"basic_robot:button808080"},{13,6,0,1,3,"basic_robot:button808080"},
{1,9,0,5,5,"basic_robot:button808080"},{1,6,0,1,3,"basic_robot:button808080"},
if state == 0 then {9,9,0,5,5,"basic_robot:button808080"},{6,13,0,3,1,"basic_robot:button808080"},
elseif state == 1 then
event = keyboard.get(); {2,2,0,2,2,"basic_robot:buttonFFFFFF"},
if event then {2,11,0,2,2,"basic_robot:buttonFFFFFF"},
x = event.x-pos.x; y = event.y-pos.y; z = event.z-pos.z {11,11,0,2,2,"basic_robot:buttonFFFFFF"},
--say("type " .. event.type .. " pos " .. x .. " " .. y .. " " .. z) {11,2,0,2,2,"basic_robot:buttonFFFFFF"},
if x == 7 and y == 1 and z == 7 then }
_G.math.randomseed(os.time())
dice = math.random(6); -- build board
keyboard.set({x=pos.x+7,y=pos.y+1,z=pos.z+7},7+dice) for i = 1,12 do for j = 1,12 do
step = step + 1; minetest.swap_node({x=pos.x+i,y=pos.y,z=pos.z+j},{name = "basic_robot:buttonFFFFFF"})
msg = colorize("red","<Mensch argere dich nicht>") .. " STEP " .. step .. ": " ..event.puncher .. " threw dice = " .. dice; minetest.swap_node({x=pos.x+i,y=pos.y+1,z=pos.z+j},{name = "air"})
minetest.chat_send_all(msg) end end
self.label(msg)
punchstate = 1 for k = 1,#spawns do
elseif punchstate == 1 then for i = 0,spawns[k][4]-1 do for j = 0,spawns[k][5]-1 do
if y == 1 and event.type ~= 2 and event.type<7 then 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 = 2; minetest.chat_send_player(event.puncher,colorize("red","<Mensch argere dich nicht>") .. " punch place on board where to move ") end end
punchpos = {x=event.x,y=event.y,z=event.z} end
punchstate = 2
end keyboard.set({x=pos.x+7,y=pos.y+1,z=pos.z+7},7)
elseif punchstate == 2 then
if y == 0 and event.type ~= 2 then msgs = {1} --{idx, msg1, msg2,msg3, msg4, msg5}; -- up to 5 ingame messages displayed
if x<2 or x>12 or z<2 or z>12 then add_msg = function(text)
else local idx = msgs[1] or 1;
local nodename = minetest.get_node(punchpos).name; msgs[idx+1] = text;idx = idx+1; if idx>5 then idx = 1 end msgs[1] = idx
minetest.swap_node({x=event.x, y = event.y+1, z=event.z},{name = nodename}) end
minetest.swap_node(punchpos,{name = "air"}) show_msgs = function() -- last message on top
punchstate = 1; dice = 0 local out = {}; local idx = msgs[1] or 1;
minetest.add_particle( 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
pos = punchpos, self.label(table.concat(out,"\n"))
expirationtime = 15, end
velocity = {x=0, y=0,z=0},
size = 18, end
texture = "default_apple.png",
acceleration = {x=0,y=0,z=0}, if state == 0 then
collisiondetection = true, elseif state == 1 then
collision_removal = true, event = keyboard.get();
} if event then
) x = event.x-pos.x; y = event.y-pos.y; z = event.z-pos.z
msg = colorize("red","<Mensch argere dich nicht>") .. " " .. event.puncher .. " moved."; --say("type " .. event.type .. " pos " .. x .. " " .. y .. " " .. z)
minetest.chat_send_all(msg) if x == 7 and y == 1 and z == 7 then
self.label(msg) _G.math.randomseed(os.time())
end dice = -3+math.random(9);
end keyboard.set({x=pos.x+7,y=pos.y+1,z=pos.z+7},7+math.abs(dice))
if dice<0 then
keyboard.set({x=pos.x+7,y=pos.y+2,z=pos.z+7},7+11)
end else
end 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

View File

@ -1,83 +1,88 @@
-- 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 for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end
if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area
data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0; data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0;
minescount = 0; minescount = 0;
for i = 1,m do for j = 1,n do -- render game for i = 1,m do for j = 1,n do -- render game
if data[i] and data[i][j] == 1 then minescount = minescount + 1 end if data[i] and data[i][j] == 1 then minescount = minescount + 1 end
if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then
puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:button808080"}) puzzle.set_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},{name = "basic_robot:button808080"})
end end
end end end end
puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"}) puzzle.set_node({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
puzzle.set_node({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z+1},{name = "basic_robot:button80FF80"})
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 get_mine_count = function(i,j)
for k = -1,1 do for l = -1,1 do if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0
if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end for k = -1,1 do for l = -1,1 do
end end if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end
return count end end
end return count
chk_mines = function() end
local count = minescount; chk_mines = function()
for i=1,m do for j=1,n do local count = minescount;
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 for i=1,m do for j=1,n do
count=count-1 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
end end end
return count end end
end return count
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).") say("minesweeper " .. m .. "x" ..n .. " with " .. minescount .. " mines ")
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
event = keyboard.get();
if event then event = keyboard.get();
local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z; if event then
if x<1 or x>m or z<1 or z>n then local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z;
if x == 0 and z == 1 then if x<1 or x>m or z<1 or z>n then
local count = chk_mines(); if x == 0 and z == 1 then
if count == 0 then local count = chk_mines();
t0 = _G.minetest.get_gametime() - t0; if count>minescount/2 then
say("congratulations! " .. event.puncher .. " discovered all mines in " .. t0 .. " s") 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
else end
reward = reward*(1-(count/minescount))^(1.5); reward = math.floor(reward); if count == 0 then
say("FAIL! " .. count .. " mines remaining. You get " .. reward .. " gold for found mines") t0 = _G.minetest.get_gametime() - t0;
_G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.ItemStack("default:gold_ingot "..reward)) -- diamond reward say("congratulations! " .. event.puncher .. " discovered all mines in " .. t0 .. " s")
end _G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.ItemStack("default:gold_ingot "..reward)) -- diamond reward
self.remove() else
end reward = reward*(1-(count/minescount))^(1.5); reward = math.floor(reward);
else --if event.type == 2 then say("FAIL! " .. count .. " mines remaining. You get " .. reward .. " gold for found mines")
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 end
if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then self.remove()
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:button808080"}) end
else else --if event.type == 2 then
puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonFF8080"}) local ppos = player.getpos(event.puncher)
end 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
if data[x] and data[x][z]==1 then puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:button808080"})
say("boom! "..event.puncher .. " is dead ");puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttonFF8080"}); else
local player_ = puzzle.get_player(event.puncher); puzzle.set_node({x=event.x,y=event.y,z=event.z},{name = "basic_robot:buttonFF8080"})
player_:setpos({x=spawnpos.x-1,y=spawnpos.y+1,z=spawnpos.z-1}); end
self.remove() else
else if data[x] and data[x][z]==1 then
local count = get_mine_count(x,z); say("boom! "..event.puncher .. " is dead ");puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:buttonFF8080"});
if count == 0 then puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button80FF80"}) local player_ = puzzle.get_player(event.puncher);
else puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button"..count}) end player_:setpos({x=spawnpos.x-1,y=spawnpos.y+1,z=spawnpos.z-1});
end self.remove()
end else
end local count = get_mine_count(x,z);
if count == 0 then puzzle.set_node({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},{name = "basic_robot:button80FF80"})
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

View File

@ -1,264 +1,247 @@
-- 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=6 -- size
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) init_score = function(levels, tops, default_value) -- [level] = {{name,score}, ...}
local scores = {}; local data = {} for i = 1, levels do data[i] = {} for j = 1,tops do data[i][j] = {"-",default_value} end end return data
local j=1; --j k l end
for i=0,5 do -- 0 - 999 1 - 999 2 - 999 3 - 999 4 - 999 5 - 999
j = string.find(score," ", j+1); add_score = function(data,name,score,level)
local k = string.find(score," ", j+1); local datal = data[level]; local tops = #datal; local j;for i = 1,tops do
local l = string.find(score," ", k+1); if score>datal[i][2] then j = i break end end
if i==5 then l = string.len(score)+1 end 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
scores[i] = {string.sub(score,j+1,k-1),tonumber(string.sub(score,k+1,l-1))}; datal[j] = {name,score} return true
j=l end
end
return scores _,scores_string = book.read(1); scores = minetest.deserialize(scores_string)
end if not scores then scores = init_score(5,5,-999) end -- 5 levels, 5 top records, smaller time is better (thats why - in top 5, there largest value counts)
if not rom.score then _,rom.score = book.read(1) end t0 = _G.minetest.get_gametime()
if not rom.score then rom.score = "0 - 999 1 - 999 2 - 999 3 - 999 4 - 999 5 - 999" end local intro ="numbers at beginning of each row (coloumn) tell how many\nred blocks are together in each row ( coloumn )." ..
highscore = get_score_from_string(rom.score) "\npunch gray blocks to toggle them and reveal hidden red blocks.\npunch green to check solution. If you give up punch blue.";
--self.label(string.gsub(_G.dump(highscore), "\n","")) self.label(intro)
function get_score_string(scores) grid = {}
local out = "" spawnpos = self.spawnpos();
for i = 0,5 do offsetx = 10 - math.ceil(n/2); offsetz = math.floor(n/2);
out = out .. i .. " " .. spawnpos.x = spawnpos.x - offsetx; spawnpos.z = spawnpos.z - offsetz;
scores[i][1] .. " " .. spawnpos.y = spawnpos.y+3
scores[i][2] .. " "
end for i=1,n do
return out grid[i]={};
end for j=1,n do
grid[i][j]=math.random(2)-1
t0 = _G.minetest.get_gametime() end
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.";
self.label(intro) getcounts = function(grid)
local rowdata = {};
grid = {} for i=1,n do
spawnpos = self.spawnpos(); rowdata[i]={}; local data = rowdata[i];
offsetx = 10 - math.ceil(n/2); offsetz = math.floor(n/2); local s=0;local c=0;
spawnpos.x = spawnpos.x - offsetx; spawnpos.z = spawnpos.z - offsetz; for j = 1, n do
spawnpos.y = spawnpos.y+3 if s == 0 and grid[i][j]==1 then s=1;c=0 end
if s == 1 then
for i=1,n do if grid[i][j]==1 then
grid[i]={}; c=c+1
for j=1,n do if j == n then data[#data+1]=c end
grid[i][j]=math.random(2)-1 else
end data[#data+1]=c; s=0
end end
getcounts = function(grid) end
local rowdata = {}; end
for i=1,n do end
rowdata[i]={}; local data = rowdata[i]; local coldata = {};
local s=0;local c=0; for j=1,n do
for j = 1, n do coldata[j]={}; local data = coldata[j];
if s == 0 and grid[i][j]==1 then s=1;c=0 end local s=0;local c=0;
if s == 1 then for i = 1, n do
if grid[i][j]==1 then if s == 0 and grid[i][j]==1 then s=1;c=0 end
c=c+1 if s == 1 then
if j == n then data[#data+1]=c end if grid[i][j]==1 then
else c=c+1
data[#data+1]=c; s=0 if i == n then data[#data+1]=c end
end else
data[#data+1]=c; s=0
end end
end
end end
local coldata = {}; end
for j=1,n do end
coldata[j]={}; local data = coldata[j]; return rowdata,coldata
local s=0;local c=0; end
for i = 1, n do
if s == 0 and grid[i][j]==1 then s=1;c=0 end read_field = function()
if s == 1 then local grid = {};
if grid[i][j]==1 then for i = 1, n do
c=c+1 grid[i]={};
if i == n then data[#data+1]=c end for j = 1,n do
else local typ = keyboard.read({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+i});
data[#data+1]=c; s=0 if typ == "basic_robot:button808080" then grid[i][j] = 0 else grid[i][j] = 1 end
end end
end
end return grid
end end
end
return rowdata,coldata rowdata,coldata = getcounts(grid)
end
check_solution = function()
read_field = function() local rdata,cdata;
local grid = {}; rdata,cdata = getcounts(read_field())
for i = 1, n do for i = 1,#rdata do
grid[i]={}; if #rdata[i]~=#rowdata[i] then return false end
for j = 1,n do for j = 1, #rdata[i] do
local typ = keyboard.read({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+i}); if rdata[i][j]~=rowdata[i][j] then return false end
if typ == "basic_robot:button808080" then grid[i][j] = 0 else grid[i][j] = 1 end end
end end
end
return grid for i = 1,#cdata do
end if #cdata[i]~=#coldata[i] then return false end
for j = 1, #rdata[i] do
rowdata,coldata = getcounts(grid) if cdata[i][j]~=coldata[i][j] then return false end
end
check_solution = function() end
local rdata,cdata; return true
rdata,cdata = getcounts(read_field()) end
for i = 1,#rdata do
if #rdata[i]~=#rowdata[i] then return false end get_difficulty = function()
for j = 1, #rdata[i] do local easy = 0;
if rdata[i][j]~=rowdata[i][j] then return false end for k = 1, n do
end local sum=0
end for i = 1,#rowdata[k]-1 do
sum = sum + rowdata[k][i]+1;
for i = 1,#cdata do end
if #cdata[i]~=#coldata[i] then return false end if #rowdata[k]>0 then sum = sum + rowdata[k][#rowdata[k]] else sum = n end
for j = 1, #rdata[i] do if sum == n then easy = easy + 1 end
if cdata[i][j]~=coldata[i][j] then return false end end
end
end for k = 1, n do
return true local sum=0
end for i = 1,#coldata[k]-1 do
sum = sum + coldata[k][i]+1;
get_difficulty = function() end
local easy = 0; if #coldata[k]>0 then sum = sum + coldata[k][#coldata[k]] else sum = n end
for k = 1, n do if sum == n then easy = easy + 1 end
local sum=0 end
for i = 1,#rowdata[k]-1 do easy = 5-easy;
sum = sum + rowdata[k][i]+1; if easy < 0 then easy = 0 end
end return easy
if #rowdata[k]>0 then sum = sum + rowdata[k][#rowdata[k]] else sum = n end end
if sum == n then easy = easy + 1 end
end -- render game
for i=1,n do
for k = 1, n do for j =1,n do
local sum=0 keyboard.set({x=spawnpos.x-n+j,y=spawnpos.y,z=spawnpos.z+i},0) -- clear
for i = 1,#coldata[k]-1 do keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+2*n-i+1},0) -- clear
sum = sum + coldata[k][i]+1; local typ;
end if grid[j][i]==0 then typ = 2 else typ = 3 end
if #coldata[k]>0 then sum = sum + coldata[k][#coldata[k]] else sum = n end if not solved then typ = 2 end
if sum == n then easy = easy + 1 end keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ) --board
end end
easy = 5-easy; end
if easy < 0 then easy = 0 end
return easy --render counts rows
end for i=1,n do
length = #rowdata[i]
-- render game for k = 1,length do
for i=1,n do keyboard.set({x=spawnpos.x-length+k,y=spawnpos.y,z=spawnpos.z+i},rowdata[i][k]+7)
for j =1,n do end
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 --render counts coloumns
local typ; for j=1,n do
if grid[j][i]==0 then typ = 2 else typ = 3 end length = #coldata[j]
if not solved then typ = 2 end for k = 1,length do
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ) --board keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+k+n},coldata[j][k]+7)
end end
end end
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},4) -- game check button
--render counts rows keyboard.set({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},5) -- game check button
for i=1,n do
length = #rowdata[i] local players = find_player(6,spawnpos)
for k = 1,length do if not players then error("nonogram: no players near") end
keyboard.set({x=spawnpos.x-length+k,y=spawnpos.y,z=spawnpos.z+i},rowdata[i][k]+7) local pname = players[1];
end
end difficulty = get_difficulty()
--render counts coloumns reward = 0; limit = 0;
for j=1,n do
length = #coldata[j] if difficulty == 5 then limit = 120 reward = 10
for k = 1,length do elseif difficulty == 4 then limit = 115 reward = 9 -- 60s
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+k+n},coldata[j][k]+7) elseif difficulty == 3 then limit = 100 reward = 8
end elseif difficulty == 2 then limit = 80 reward = 7
end elseif difficulty <= 1 then limit = 70 reward = 6
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},4) -- game check button end
keyboard.set({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},5) -- game check button minetest.chat_send_player(pname, "nonogram difficulty " .. difficulty .. ". you will get " .. reward .. " gold if you solve it in faster than " .. limit .."s" ..
". Current record " .. -scores[difficulty][1][2] .. " by " .. scores[difficulty][1][1])
local players = find_player(4,spawnpos)
if not players then error("minesweeper: no players near") end
local pname = players[1]; end
event = keyboard.get()
--self.label() if event then
if event.y == spawnpos.y and event.z == spawnpos.z then
--self.label(string.gsub(_G.dump(read_field()),"\n","") ) if event.x == spawnpos.x+1 then -- check solution
difficulty = get_difficulty() if check_solution() then
reward = 0; limit = 0; t = _G.minetest.get_gametime(); t = t- t0;
local msg = "";
if difficulty == 5 then limit = 120 reward = 10 keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},2)
elseif difficulty == 4 then limit = 115 reward = 9 -- 60s msg = n .. "x" .. n .. " nonogram (difficuly " .. difficulty .. ") solved by " .. event.puncher .. " in " .. t .. " seconds. "
elseif difficulty == 3 then limit = 100 reward = 8
elseif difficulty == 2 then limit = 80 reward = 7 if t < limit then
elseif difficulty <= 1 then limit = 70 reward = 6 msg = msg .. " He gets " .. reward .. " gold for quick solve.";
end else
minetest.chat_send_player(pname, "nonogram difficulty " .. difficulty .. ". you will get " .. reward .. " gold if you solve it in faster than " .. limit .."s" .. reward = reward*2*(1-2*(t-limit)/limit)/2; if reward<0 then reward = 0 end
". Current record " .. highscore[difficulty][2] .. " by " .. highscore[difficulty][1]) reward = math.floor(reward);
msg = msg .. " Your time was more than " .. limit .. ", you get " .. reward .. " gold ";
end end
event = keyboard.get() -- highscore
if event then if add_score(scores,event.puncher,-t,difficulty) then
if event.y == spawnpos.y and event.z == spawnpos.z then say("nonogram difficulty " .. difficulty .. ": new record " .. t .. " s !")
if event.x == spawnpos.x+1 then -- check solution local sdata = scores[difficulty];
if check_solution() then 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," "))
t = _G.minetest.get_gametime(); t = t- t0; book.write(1,"scores", minetest.serialize(scores))
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. "
if reward>0 then
if t < limit then local player = _G.minetest.get_player_by_name(event.puncher);
msg = msg .. " He gets " .. reward .. " gold for quick solve."; if player then
else local inv = player:get_inventory();
reward = reward*2*(1-2*(t-limit)/limit)/2; if reward<0 then reward = 0 end inv:add_item("main",_G.ItemStack("default:gold_ingot " .. reward))
reward = math.floor(reward); end
msg = msg .. " Your time was more than " .. limit .. ", you get " .. reward .. " gold "; end
end minetest.chat_send_player(event.puncher,msg)
-- highscore self.remove()
if t<highscore[difficulty][2] then
say("nonogram: new record " .. t .. " s ! old record " .. highscore[difficulty][2] .. "s by " .. highscore[difficulty][1]) else self.label("FAIL") end
highscore[difficulty] = {event.puncher, t} elseif event.x == spawnpos.x+2 then -- solve
rom.score = get_score_string(highscore) minetest.chat_send_player(event.puncher,"you gave up on game, displaying solution")
book.write(1,"scores", rom.score) for i=1,n do
end for j =1,n do
local typ;
if reward>0 then if grid[j][i]==0 then typ = 2 else typ = 3 end
local player = _G.minetest.get_player_by_name(event.puncher); keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ)
if player then end
local inv = player:get_inventory(); end
inv:add_item("main",_G.ItemStack("default:gold_ingot " .. reward)) self.remove()
end end
end else
minetest.chat_send_player(event.puncher,msg) local i = event.x-spawnpos.x;local j = event.z-spawnpos.z;
if i>0 and i<=n and j>0 and j<=n then
self.remove() local typ = keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j});
local newtyp;
else self.label("FAIL") end if typ == "basic_robot:button808080" then newtyp = 3
elseif event.x == spawnpos.x+2 then -- solve else newtyp = 2
minetest.chat_send_player(event.puncher,"you gave up on game, displaying solution") end
for i=1,n do keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},newtyp);
for j =1,n do end
local typ; end
if grid[j][i]==0 then typ = 2 else typ = 3 end
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ)
end
end
self.remove()
end
else
local i = event.x-spawnpos.x;local j = event.z-spawnpos.z;
if i>0 and i<=n and j>0 and j<=n then
local typ = keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j});
local newtyp;
if typ == "basic_robot:button808080" then newtyp = 3
else newtyp = 2
end
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},newtyp);
end
end
end end

View File

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

1398
scripts/games/sokoban.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,189 +1,233 @@
-- 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; sokoban.push_time = 0
sokoban.playername = name sokoban.blocks = 0;sokoban.level = 0; sokoban.moves=0;
imax = 0; jmax = 0
if lvl == nil then return end
if lvl <0 or lvl >89 then return end sokoban.load=0;sokoban.playername =""; sokoban.pos = {};
SOKOBAN_WALL = "moreblocks:cactus_brick"
local file = _G.io.open(minetest.get_modpath("basic_robot").."\\scripts\\sokoban.txt","r") SOKOBAN_FLOOR = "default:silver_sandstone"
if not file then return end SOKOBAN_GOAL = "default:aspen_tree"
local str = ""; local s; local p = {x=pos.x,y=pos.y,z=pos.z}; local i,j;i=0; SOKOBAN_BOX = "basic_robot:buttonFFFFFF"
local lvl_found = false
while str~= nil do
str = file:read("*line"); load_level = function(lvl)
if str~=nil and str =="; "..lvl then lvl_found=true break end
end local pos = self.spawnpos(); pos.x=pos.x+1;pos.y=pos.y+1;
if not lvl_found then file:close();return end sokoban.pos = pos;
sokoban.playername = name
sokoban.blocks = 0;sokoban.level = lvl+1; sokoban.moves=0;
imax=0; jmax = 0; if lvl == nil then return end
while str~= nil do if lvl <0 or lvl >89 then return end
str = file:read("*line");
if str~=nil then local file = _G.io.open(minetest.get_modpath("basic_robot").."/scripts/games/sokoban.txt","r")
if string.sub(str,1,1)==";" then if not file then return end
imax=i; local str = ""; local s; local p = {x=pos.x,y=pos.y,z=pos.z}; local i,j;i=0;
file:close(); local lvl_found = false
player_:set_physics_override({jump=0}) while str~= nil do
player_:set_eye_offset({x=0,y=20,z=0},{x=0,y=0,z=0}); str = file:read("*line");
return if str~=nil and str =="; "..lvl then lvl_found=true break end
end end
i=i+1; if not lvl_found then file:close();return end
if string.len(str)>jmax then jmax = string.len(str) end -- determine max dimensions
for j = 1,string.len(str) do sokoban.blocks = 0;sokoban.level = lvl+1; sokoban.moves=0;
p.x=pos.x+i;p.y=pos.y; p.z=pos.z+j; s=string.sub(str,j,j); imax=0; jmax = 0;
p.y=p.y-1; while str~= nil do
if puzzle.get_node(p).name~=SOKOBAN_FLOOR then puzzle.set_node(p,{name=SOKOBAN_FLOOR}); end -- clear floor str = file:read("*line");
p.y=p.y+1; if str~=nil then
if s==" " and puzzle.get_node(p).name~="air" then puzzle.set_node(p,{name="air"}) end if string.sub(str,1,1)==";" then
if s=="#" and puzzle.get_node(p).name~=SOKOBAN_WALL then puzzle.set_node(p,{name=SOKOBAN_WALL}) end imax=i;
if s=="$" then puzzle.set_node(p,{name=SOKOBAN_BOX});sokoban.blocks=sokoban.blocks+1 end file:close();
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 player_:set_physics_override({jump=0})
--starting position player_:set_eye_offset({x=0,y=20,z=0},{x=0,y=0,z=0});
if s=="@" then return
player_:setpos({x=p.x,y=p.y-0.5,z=p.z}); -- move player to start position end
--p.y=p.y-1;puzzle.set_node(p,{name="default:glass"}); i=i+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+1;puzzle.set_node(p,{name="air"}) for j = 1,string.len(str) do
--p.y=p.y+2;puzzle.set_node(p,{name="default:ladder"}) p.x=pos.x+i;p.y=pos.y; p.z=pos.z+j; s=string.sub(str,j,j);
end p.y=p.y-1;
if s~="@" then p.y = pos.y+2;puzzle.set_node(p,{name="air"}); -- ceiling default:obsidian_glass if puzzle.get_node(p).name~=SOKOBAN_FLOOR then puzzle.set_node(p,{name=SOKOBAN_FLOOR}); end -- clear floor
else --p.y=pos.y+2;puzzle.set_node(p,{name="default:ladder"}) p.y=p.y+1;
end -- roof above to block jumps if s==" " and puzzle.get_node(p).name~="air" then puzzle.set_node(p,{name="air"}) 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
end --starting position
if s=="@" then
file:close(); player_:set_pos({x=p.x,y=p.y-0.5,z=p.z}); -- move player to start position
end --p.y=p.y-1;puzzle.set_node(p,{name="default:glass"});
puzzle.set_node(p,{name="air"})
clear_game = function() p.y=p.y+1;puzzle.set_node(p,{name="air"})
local pos = self.spawnpos(); pos.x=pos.x+1;pos.y=pos.y+1; --p.y=p.y+2;puzzle.set_node(p,{name="default:ladder"})
for i = 1, 20 do end
for j = 1,20 do if s~="@" then p.y = pos.y+2;puzzle.set_node(p,{name="air"}); -- ceiling default:obsidian_glass
local node = minetest.get_node({x=pos.x+i,y=pos.y-1,z=pos.z+j}).name else --p.y=pos.y+2;puzzle.set_node(p,{name="default:ladder"})
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 end -- roof above to block jumps
node = minetest.get_node({x=pos.x+i,y=pos.y,z=pos.z+j}).name
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
file:close();
end end
clear_game = function()
if state == 1 then local pos = self.spawnpos(); pos.x=pos.x+1;pos.y=pos.y+1;
clear_game() for i = 1, 20 do
load_level(20) for j = 1,20 do
state = 0 local node = minetest.get_node({x=pos.x+i,y=pos.y-1,z=pos.z+j}).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") 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 node = minetest.get_node({x=pos.x+i,y=pos.y,z=pos.z+j}).name
if node ~= "air" then minetest.set_node({x=pos.x+i,y=pos.y,z=pos.z+j}, {name = "air"}) end
local ppos = player_:getpos() 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
event = keyboard.get(); force_load = function()
local lvl = 0 -- 1st level at idx 0 - sokoban level 1
if event then clear_game()
if gamedata and gamedata[name] then lvl = gamedata[name].lvl end -- load next level to play
local pname = event.puncher load_level(lvl)
if pname ~= name then goto quit end state = 0
local pos = {x=event.x, y = event.y, z = event.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")
local p=player.getpos(pname);local q={x=pos.x,y=pos.y,z=pos.z}
p.x=p.x-q.x;p.y=p.y-q.y;p.z=p.z-q.z end
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 if load_player_progress then
if p.z<-0.5 or p.z>0.5 or math.abs(p.x)>1.5 then goto quit end force_load() -- this prevents selecting custom level and loads players progress if any
if p.x+q.x>q.x then q.x= q.x-1 end
else q.x = q.x+1
end end
else
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 if state == 1 then -- wait to load game
else q.z = q.z+1 sender,fields = self.read_form()
end if fields then
end if fields.OK then
local lvl = tonumber(fields.LVL or 1)-1;
clear_game()
if minetest.get_node(q).name=="air" then -- push crate load_level(lvl)
sokoban.moves = sokoban.moves+1 state = 0
local old_infotext = minetest.get_meta(pos):get_string("infotext"); 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(pos,{name="air"}) else
minetest.set_node(q,{name=SOKOBAN_BOX}) self.remove()
minetest.sound_play("default_dig_dig_immediate", {pos=q,gain=1.0,max_hear_distance = 24,}) -- sound of pushing end
local meta = minetest.get_meta(q); end
q.y=q.y-1;
if minetest.get_node(q).name==SOKOBAN_GOAL then
if old_infotext~="GOAL REACHED" then else -- game
sokoban.blocks = sokoban.blocks -1;
end local ppos = player_:get_pos()
meta:set_string("infotext", "GOAL REACHED") if math.abs(ppos.y-sokoban.pos.y)~= 0.5 then minetest.chat_send_player(name,colorize("red", "SOKOBAN: " .. name .. " QUITS ! "));
else 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
if old_infotext=="GOAL REACHED" then
sokoban.blocks = sokoban.blocks +1 event = keyboard.get();
end
--meta:set_string("infotext", "push crate on top of goal block") if event then
end
end local pname = event.puncher
if pname ~= name then goto quit end
if sokoban.blocks~=0 then -- how many blocks left local pos = {x=event.x, y = event.y, z = event.z};
--say("move " .. sokoban.moves .. " : " ..sokoban.blocks .. " crates left "); if minetest.get_node(pos).name == "air" then return end -- ignore move, block wasnt punched
else local p=player.getpos(pname);local q={x=pos.x,y=pos.y,z=pos.z}
say("games: ".. name .. " just solved sokoban level ".. sokoban.level .. " in " .. sokoban.moves .. " moves."); p.x=p.x-q.x;p.y=p.y-q.y;p.z=p.z-q.z
player_:set_physics_override({jump=1}) if math.abs(p.y+0.5)>0 then goto quit end
player_:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0}) 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
local player = _G.minetest.get_player_by_name(event.puncher); if p.x+q.x>q.x then q.x= q.x-1
if player then else q.x = q.x+1
local inv = player:get_inventory(); end
inv:add_item("main",_G.ItemStack("skyblock:sokoban 4 ")) 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
local i,j; else q.z = q.z+1
for i = 1,imax do end
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 if minetest.get_node(q).name=="air" then -- push crate
sokoban.moves = sokoban.moves+1
sokoban.playername = ""; sokoban.level = 1 local old_infotext = minetest.get_meta(pos):get_string("infotext");
end minetest.set_node(pos,{name="air"})
::quit:: minetest.set_node(q,{name=SOKOBAN_BOX})
end 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
name = "_"
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)
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 speaker == name and string.sub(msg,1,2) == "t " then
render_text(string.sub(msg,3))
end

View File

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