sandbox bugfixes
parent
c3a021d1fc
commit
2020477700
76
commands.lua
76
commands.lua
|
@ -595,6 +595,19 @@ local write_keyevent = function(data,pos, puncher,type)
|
|||
|
||||
end
|
||||
|
||||
local button_punched = function(pos, node, player,type)
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
local round = math.floor;
|
||||
local r = basic_robot.radius; local ry = 2*r;
|
||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
|
||||
|
||||
local hppos = minetest.hash_node_position(ppos)
|
||||
local rname = basic_robot.data.punchareas[hppos];
|
||||
local data = basic_robot.data[rname];
|
||||
if data then
|
||||
write_keyevent(data,pos, player:get_player_name(),type)
|
||||
end
|
||||
end
|
||||
|
||||
local register_robot_button = function(R,G,B,type)
|
||||
minetest.register_node("basic_robot:button"..R..G..B,
|
||||
|
@ -605,20 +618,8 @@ local register_robot_button = function(R,G,B,type)
|
|||
wield_image = "robot_button.png^[colorize:#"..R..G..B..":180",
|
||||
|
||||
is_ground_content = false,
|
||||
groups = {cracky=3},
|
||||
on_punch = function(pos, node, player)
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
local round = math.floor;
|
||||
local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted
|
||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
|
||||
local meta = minetest.get_meta(ppos);
|
||||
local name = meta:get_string("name");
|
||||
local data = basic_robot.data[name];
|
||||
if data then
|
||||
write_keyevent(data,pos, player:get_player_name(),type)
|
||||
end
|
||||
end
|
||||
|
||||
groups = {cracky=3,not_in_craft_guide = 1},
|
||||
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -632,19 +633,8 @@ minetest.register_node("basic_robot:button"..number,
|
|||
paramtype2 = "facedir",
|
||||
|
||||
is_ground_content = false,
|
||||
groups = {cracky=3},
|
||||
on_punch = function(pos, node, player)
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
local round = math.floor;
|
||||
local r = basic_robot.radius; local ry = 2*r;
|
||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
|
||||
local meta = minetest.get_meta(ppos);
|
||||
local name = meta:get_string("name");
|
||||
local data = basic_robot.data[name];
|
||||
if data then
|
||||
write_keyevent(data,pos, player:get_player_name(),type)
|
||||
end
|
||||
end
|
||||
groups = {cracky=3,not_in_craft_guide = 1},
|
||||
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -657,21 +647,9 @@ minetest.register_node("basic_robot:button_"..number,
|
|||
inventory_image = string.format("%03d",number).. ".png",
|
||||
wield_image = string.format("%03d",number).. ".png",
|
||||
is_ground_content = false,
|
||||
groups = {cracky=3},
|
||||
groups = {cracky=3,not_in_craft_guide = 1},
|
||||
paramtype2 = "facedir",
|
||||
on_punch = function(pos, node, player)
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
local round = math.floor;
|
||||
local r = basic_robot.radius; local ry = 2*r;
|
||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
|
||||
local meta = minetest.get_meta(ppos);
|
||||
local name = meta:get_string("name");
|
||||
local data = basic_robot.data[name];
|
||||
if data then
|
||||
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
|
||||
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -683,20 +661,8 @@ minetest.register_node("basic_robot:button_"..number,
|
|||
inventory_image = texture .. ".png",
|
||||
wield_image = texture .. ".png",
|
||||
is_ground_content = false,
|
||||
groups = {cracky=3},
|
||||
on_punch = function(pos, node, player)
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
local round = math.floor;
|
||||
local r = basic_robot.radius; local ry = 2*r;
|
||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
|
||||
local meta = minetest.get_meta(ppos);
|
||||
local name = meta:get_string("name");
|
||||
local data = basic_robot.data[name];
|
||||
if data then
|
||||
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
|
||||
groups = {cracky=3,not_in_craft_guide = 1},
|
||||
on_punch = function(pos, node,player) button_punched(pos, node,player,type) end
|
||||
})
|
||||
end
|
||||
|
||||
|
|
63
init.lua
63
init.lua
|
@ -1,4 +1,4 @@
|
|||
-- basic_robot by rnd, 2016
|
||||
-- basic_robot by rnd, 2016-2021
|
||||
|
||||
|
||||
basic_robot = {};
|
||||
|
@ -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.version = "2021/03/02a";
|
||||
basic_robot.version = "2021/06/28a";
|
||||
|
||||
basic_robot.gui = {}; local robogui = basic_robot.gui -- gui management
|
||||
basic_robot.data = {}; -- stores all robot related data
|
||||
|
@ -40,6 +40,7 @@ basic_robot.ids = {}; -- stores maxid for each player
|
|||
basic_robot.virtual_players = {}; -- this way robot can interact with the world as "player" TODO
|
||||
|
||||
basic_robot.data.listening = {}; -- which robots listen to chat
|
||||
basic_robot.data.punchareas = {}; -- where robots listen punch events, [hashes of 32 sized chunk] = robot name
|
||||
|
||||
dofile(minetest.get_modpath("basic_robot").."/robogui.lua") -- gui stuff
|
||||
dofile(minetest.get_modpath("basic_robot").."/commands.lua")
|
||||
|
@ -63,6 +64,7 @@ function getSandboxEnv (name)
|
|||
if not basic_robot.data[name].rom then basic_robot.data[name].rom = {} end -- create rom if not yet existing
|
||||
local env =
|
||||
{
|
||||
_Gerror = error,
|
||||
pcall=pcall,
|
||||
robot_version = function() return basic_robot.version end,
|
||||
|
||||
|
@ -113,7 +115,7 @@ function getSandboxEnv (name)
|
|||
obj:set_animation({x=anim_start,y=anim_end}, anim_speed, anim_stand_start)
|
||||
end,
|
||||
|
||||
listen = function (mode)
|
||||
listen = function (mode) -- will robot listen to chat?
|
||||
if mode == 1 then
|
||||
basic_robot.data.listening[name] = true
|
||||
else
|
||||
|
@ -121,6 +123,24 @@ function getSandboxEnv (name)
|
|||
end
|
||||
end,
|
||||
|
||||
listen_punch = function(pos, is_remove) -- robot will listen to punch events in 32 sized chunk containing pos
|
||||
local round = math.floor;
|
||||
local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted
|
||||
if not pos then return end
|
||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
|
||||
local hppos = minetest.hash_node_position(ppos)
|
||||
local rname = basic_robot.data.punchareas[hppos];
|
||||
if is_remove then -- remove listener
|
||||
basic_robot.data.punchareas[hppos] = nil
|
||||
return
|
||||
end
|
||||
|
||||
if rname then -- area already registered for listening
|
||||
return rname
|
||||
end
|
||||
basic_robot.data.punchareas[hppos] = name; -- register robot name
|
||||
end,
|
||||
|
||||
listen_msg = function()
|
||||
local msg = basic_robot.data[name].listen_msg;
|
||||
local speaker = basic_robot.data[name].listen_speaker;
|
||||
|
@ -153,7 +173,7 @@ function getSandboxEnv (name)
|
|||
reset = function()
|
||||
local pos = basic_robot.data[name].spawnpos;
|
||||
local obj = basic_robot.data[name].obj;
|
||||
obj:setpos({x=pos.x,y=pos.y+1,z=pos.z}); obj:setyaw(0);
|
||||
obj:set_pos({x=pos.x,y=pos.y+1,z=pos.z}); obj:setyaw(0);
|
||||
end,
|
||||
|
||||
set_libpos = function(pos)
|
||||
|
@ -575,7 +595,7 @@ end
|
|||
|
||||
check_code = function(code)
|
||||
--"while ", "for ", "do ","goto ",
|
||||
local bad_code = {"repeat", "until", "_c_", "_G", "while%(", "while{", "pcall","%.%.[^%.]"} --,"\\\"", "%[=*%[","--[["}
|
||||
local bad_code = {"repeat", "until", "_G", "while%(", "while{", "pcall","%.%.[^%.]"} --,"\\\"", "%[=*%[","--[["}
|
||||
for _, v in pairs(bad_code) do
|
||||
if string.find(code, v) then
|
||||
return v .. " is not allowed!";
|
||||
|
@ -666,8 +686,8 @@ preprocess_code = function(script, call_limit) -- version 07/24/2018
|
|||
script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-[^\n]*\n","\n") -- strip comments
|
||||
|
||||
-- process script to insert call counter in every function
|
||||
local _increase_ccounter = " _c_ = _c_ + 1; if _c_ > " .. call_limit ..
|
||||
" then _G.error(\"Execution count \".. _c_ .. \" exceeded ".. call_limit .. "\") end; "
|
||||
local _increase_ccounter = " _Gc = _Gc + 1; if _Gc > " .. call_limit ..
|
||||
" then _Gerror(\"Execution count \".. _Gc .. \" exceeded ".. call_limit .. "\") end; "
|
||||
|
||||
local i1=0; local i2 = 0;
|
||||
local found = true;
|
||||
|
@ -726,7 +746,7 @@ preprocess_code = function(script, call_limit) -- version 07/24/2018
|
|||
-- must reset ccounter when paused, but user should not be able to force reset by modifying pause!
|
||||
-- (suggestion about 'pause' by Kimapr, 09/26/2019)
|
||||
|
||||
return "_c_ = 0 local _pause_ = pause pause = function() _c_ = 0; _pause_() end " .. script;
|
||||
return "_Gc = 0 local _Gpause = pause pause = function() _Gc = 0; _Gpause() end " .. script;
|
||||
|
||||
--return script:gsub("pause%(%)", "_c_ = 0; pause()") -- reset ccounter at pause
|
||||
end
|
||||
|
@ -843,15 +863,18 @@ local robot_spawner_update_form = function (pos, mode)
|
|||
|
||||
form =
|
||||
"size[9.5,8]" .. -- width, height
|
||||
"textarea[1.25,-0.25;8.75,10.25;code;;".. code.."]"..
|
||||
"style_type[textarea;font_size=12;font=mono;bgcolor=#000000;textcolor=#00FF00;border=false]"..
|
||||
"style_type[button;font_size=14;font=mono;bgcolor=#000000;border=false]"..
|
||||
"style_type[button_exit;font_size=14;font=mono;bgcolor=#000000;border=false]"..
|
||||
"textarea[1.25,-0.25;8.8,10.25;code;;".. code.."]"..
|
||||
"button[-0.15,7.5;1.25,1;EDIT;EDIT]"..
|
||||
"button[-0.15,-0.25;1.25,1;OK;"..minetest.colorize("yellow","SAVE").."]"..
|
||||
"button_exit[-0.15, 0.75;1.25,1;spawn;"..minetest.colorize("green","START").."]"..
|
||||
"button[-0.15, 1.75;1.25,1;despawn;"..minetest.colorize("red","STOP").."]"..
|
||||
"field[0.15,3.;1.2,1;id;id;"..id.."]"..
|
||||
"button[-0.15, 3.6;1.25,1;inventory;storage]"..
|
||||
"button[-0.15, 4.6;1.25,1;library;library]"..
|
||||
"button[-0.15, 5.6;1.25,1;help;help]";
|
||||
"button[-0.15, 3.6;1.25,1;inventory;STORAGE]"..
|
||||
"button[-0.15, 4.6;1.25,1;library;LIBRARY]"..
|
||||
"button[-0.15, 5.6;1.25,1;help;HELP]";
|
||||
|
||||
else -- when robot clicked
|
||||
form =
|
||||
|
@ -1531,9 +1554,9 @@ minetest.register_on_player_receive_fields(
|
|||
local title,text = basic_robot.commands.read_book(itemstack);
|
||||
title = title or ""; text = text or "";
|
||||
local dtitle = minetest.formspec_escape(title);
|
||||
local form = "size [8,8] textarea[0.,0.;8.75,8.5;book; TITLE : " .. minetest.formspec_escape(title) .. ";" ..
|
||||
local form = "size [8,8] textarea[0.,0.15;8.75,8.35;book; TITLE : " .. minetest.formspec_escape(title) .. ";" ..
|
||||
minetest.formspec_escape(text) .. "] button_exit[-0.25,7.5;1.25,1;OK;SAVE] "..
|
||||
"button_exit[1.,7.5;2.75,1;LOAD;USE AS PROGRAM] field[4,8;4.5,0.5;title;title;"..dtitle.."]";
|
||||
"button_exit[0.9,7.5;3,1;LOAD;USE AS PROGRAM] field[4,8;4.5,0.5;title;title;"..dtitle.."]";
|
||||
minetest.show_formspec(player:get_player_name(), "robot_book_".. sel.. ":".. minetest.pos_to_string(libpos), form);
|
||||
|
||||
end
|
||||
|
@ -1746,6 +1769,11 @@ minetest.register_node("basic_robot:spawner", {
|
|||
}
|
||||
},
|
||||
|
||||
effector = {
|
||||
action_on = spawn_robot,
|
||||
action_off = despawn_robot
|
||||
},
|
||||
|
||||
on_receive_fields = on_receive_robot_form,
|
||||
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
|
@ -1836,9 +1864,10 @@ minetest.register_craftitem("basic_robot:control", {
|
|||
local pos = pointed_thing.under
|
||||
if not pos then return end
|
||||
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
|
||||
local meta = minetest.get_meta(ppos);
|
||||
local name = meta:get_string("name");
|
||||
local data = basic_robot.data[name];
|
||||
|
||||
local hppos = minetest.hash_node_position(ppos)
|
||||
local rname = basic_robot.data.punchareas[hppos];
|
||||
local data = basic_robot.data[rname];
|
||||
if data then data.keyboard = {x=pos.x,y=pos.y,z=pos.z, puncher = owner, type = 0} end
|
||||
return
|
||||
end
|
||||
|
|
12
robogui.lua
12
robogui.lua
|
@ -244,12 +244,14 @@ local help_pages = {
|
|||
["KEYBOARD AND USER INTERACTIONS"] = {
|
||||
"back to [Commands reference]",
|
||||
"KEYBOARD","",
|
||||
" EVENTS : place spawner at coordinates (r*i,2*r*j+1,r*k) to monitor",
|
||||
" events. value of r is ".. basic_robot.radius,
|
||||
" EVENTS : first attach listener to robot with self.listen_punch",
|
||||
" self.listen_punch(pos,is_remove) robot will listen to punch events in ",
|
||||
" ".. basic_robot.radius .. " sized chunk containing position",
|
||||
" pos = {x=.., y=.., z=..}. if is_remove==true then remove listener",
|
||||
" keyboard.get() returns table {x=..,y=..,z=..,puncher = .. , type = .. }",
|
||||
" for keyboard event",
|
||||
" keyboard.set(pos,type) set key at pos of type 0=air,1-6,7-15,16-271,",
|
||||
" limited to range 10 around spawner",
|
||||
" if there was keyboard event, nil if there was none",
|
||||
" keyboard.set(pos,type) set key as a node in world at pos of type",
|
||||
" 0=air,1-6,7-15,16-271, limited to range 10 around spawner",
|
||||
" keyboard.read(pos) return node name at pos",
|
||||
},
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ if not data then
|
|||
state = SIGNUP
|
||||
|
||||
t0 = _G.minetest.get_gametime();spawnpos = self.spawnpos() -- place mines
|
||||
self.listen_punch(self.pos()); -- attach punch listener
|
||||
data = {};
|
||||
|
||||
init_game = function()
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
--https://en.wikipedia.org/wiki/Black_Box_(game)
|
||||
|
||||
if not data then
|
||||
m=16;n=16;
|
||||
atoms = 32
|
||||
-- novice: 8x8, 4
|
||||
m=8;n=8;
|
||||
atoms = 8
|
||||
attempts = 1;turn = 0;
|
||||
spawnpos = self.spawnpos(); spawnpos.x = spawnpos.x-m/2; spawnpos.y = spawnpos.y+2; spawnpos.z = spawnpos.z-n/2
|
||||
|
||||
local players = find_player(5,spawnpos);
|
||||
if not player then self.remove() else pname = players[1] end
|
||||
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
self.spam(1);t0 = _G.minetest.get_gametime();
|
||||
data = {};
|
||||
for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
--checkers by rnd, 1.5 hr
|
||||
if not init then init=true
|
||||
spos = self.spawnpos()
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
sizex = 8; sizez= 8
|
||||
|
||||
gamepieces = {
|
||||
|
@ -81,7 +82,10 @@ if not init then init=true
|
|||
build_game()
|
||||
punchpos = nil; -- pos of last punched piece
|
||||
step = 0;
|
||||
self.label("checkers\npunch piece then punch board to move")
|
||||
self.label("checkers\npunch piece then punch board to move\n"..
|
||||
"RULES\n\n1. move only diagonal and forward. capture pieces by jumping over them.\nif you can capture you must\n"..
|
||||
"2. once you reach end of board you get king. it can move backward too"
|
||||
)
|
||||
end
|
||||
|
||||
event = keyboard.get()
|
||||
|
|
|
@ -4,6 +4,7 @@ if not data then
|
|||
-- m=3;n=3;turn = 0; num = 3;
|
||||
self.spam(1);t0 = _G.minetest.get_gametime();
|
||||
spawnpos = self.spawnpos() -- place mines
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
state = 0; -- 0 signup 1 game
|
||||
players = {};
|
||||
data = {};
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
--cyberpunk 2077 'breach protocol puzzle' generator
|
||||
--by rnd, 20 min
|
||||
|
||||
|
||||
if not init then init = true
|
||||
n=4; -- size of square
|
||||
steps = n*n; -- length of sequence
|
||||
tries = n*10; -- how many tries in current row/col before giving up
|
||||
|
||||
tb = {};
|
||||
for i = 1,n do
|
||||
tb[i] ={}; local tbi = tb[i]
|
||||
for j = 1,n do
|
||||
tbi[j] = (i-1)*n+j
|
||||
end
|
||||
end
|
||||
|
||||
--make random path col/row/col... starting at random position
|
||||
|
||||
row = true;
|
||||
posi = 1; -- row
|
||||
posj = 1; -- col
|
||||
path = {}
|
||||
used = {}; -- [num] = true, when taken
|
||||
|
||||
for i = 1, steps do
|
||||
if row then
|
||||
local tmp = posj;
|
||||
local s = 0
|
||||
while (tmp == posj or used[tb[posi][tmp]]) and s < tries do
|
||||
tmp = math.random(n);
|
||||
s=s+1
|
||||
end
|
||||
if s == tries then say("stuck at lenght " .. #path) break end
|
||||
posj = tmp
|
||||
else
|
||||
local tmp = posi;
|
||||
local s = 0
|
||||
while (tmp == posi or used[tb[tmp][posj]]) and s < tries do
|
||||
tmp = math.random(n);
|
||||
s=s+1
|
||||
end
|
||||
if s == tries then say("stuck at lenght " .. #path) break end
|
||||
posi = tmp
|
||||
end
|
||||
row = not row
|
||||
path[#path+1] = tb[posi][posj];
|
||||
used[path[#path]] = true
|
||||
end
|
||||
|
||||
local ret = {};
|
||||
for i = 1,n do
|
||||
for j = 1,n do
|
||||
ret[#ret+1] = string.format("%02d",(i-1)*n+j).." ";
|
||||
end
|
||||
ret[#ret+1] = "\n"
|
||||
end
|
||||
|
||||
|
||||
self.label(table.concat(path," ") .. "\n\n"..table.concat(ret))
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
--go by rnd
|
||||
if not init then init=true
|
||||
spos = self.spawnpos()
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
sizex = 9; sizez = 9
|
||||
|
||||
gamepieces = {
|
||||
|
|
|
@ -19,6 +19,7 @@ if not init then
|
|||
punchstate = 1; -- first punch
|
||||
punchpos = {}
|
||||
pos = self.spawnpos()
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
dice = 0
|
||||
spawns = {
|
||||
{2,2,1,2,2,"basic_robot:buttonFF8080"}, -- xstart,zstart,ystart, dimx, dimz, nodename
|
||||
|
@ -61,11 +62,12 @@ if not init then
|
|||
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"))
|
||||
show_msgs = function()
|
||||
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
|
||||
|
||||
end
|
||||
|
|
|
@ -8,6 +8,8 @@ if not data then
|
|||
self.spam(1)
|
||||
t0 = _G.minetest.get_gametime();
|
||||
data = {}; spawnpos = self.spawnpos() -- place mines
|
||||
self.listen_punch(self.pos()); -- attach punch listener
|
||||
|
||||
for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end
|
||||
if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area
|
||||
data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0;
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
-- INIT
|
||||
if not grid then
|
||||
n=6 -- size
|
||||
n=6
|
||||
solved = false -- do we render solution or blank?
|
||||
-- _G.math.randomseed(3)
|
||||
|
||||
self.spam(1)
|
||||
|
||||
|
||||
|
@ -20,7 +21,7 @@ if not grid then
|
|||
end
|
||||
|
||||
_,scores_string = book.read(1); scores = minetest.deserialize(scores_string)
|
||||
if not scores then scores = init_score(5,5,-999) end -- 5 levels, 5 top records, smaller time is better (thats why - in top 5, there largest value counts)
|
||||
if not scores then scores = init_score(5,5,-999) end -- 5 levels, 5 top records
|
||||
|
||||
t0 = _G.minetest.get_gametime()
|
||||
local intro ="numbers at beginning of each row (coloumn) tell how many\nred blocks are together in each row ( coloumn )." ..
|
||||
|
@ -168,6 +169,11 @@ if not grid then
|
|||
if not players then error("nonogram: no players near") end
|
||||
local pname = players[1];
|
||||
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
|
||||
--self.label()
|
||||
|
||||
--self.label(string.gsub(_G.dump(read_field()),"\n","") )
|
||||
difficulty = get_difficulty()
|
||||
reward = 0; limit = 0;
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ if not init then
|
|||
|
||||
create_board(size)
|
||||
render_board()
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
|
||||
self.spam(1)
|
||||
self.listen_punch(self.pos()); -- attach punch listener
|
||||
sokoban.push_time = 0
|
||||
sokoban.blocks = 0;sokoban.level = 0; sokoban.moves=0;
|
||||
imax = 0; jmax = 0
|
||||
|
|
|
@ -79,6 +79,7 @@ render_lights(); render_switches(true)
|
|||
|
||||
|
||||
self.label("GOAL OF GAME: punch buttons with numbers in correct order to turn all blocks to 0")
|
||||
self.listen_punch(self.pos()) -- attach punch listener
|
||||
|
||||
--self.label(serialize(switches))
|
||||
end
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
--ALL UNICODE by rnd, 2021
|
||||
|
||||
-- range to 32-1550, then 7400-10000
|
||||
--cyrillic 0410-042F: 1040-1071
|
||||
--cyrilic 0430-044F: 1072-1103
|
||||
if not init then init = true
|
||||
|
||||
function utf8(decimal)
|
||||
local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
|
||||
if decimal<128 then return string.char(decimal) end
|
||||
local charbytes = {}
|
||||
for bytes,vals in ipairs(bytemarkers) do
|
||||
if decimal<=vals[1] then
|
||||
for b=bytes+1,2,-1 do
|
||||
local mod = decimal%64
|
||||
decimal = (decimal-mod)/64
|
||||
charbytes[b] = string.char(128+mod)
|
||||
end
|
||||
charbytes[1] = string.char(vals[2]+decimal)
|
||||
break
|
||||
end
|
||||
end
|
||||
return table.concat(charbytes)
|
||||
end
|
||||
|
||||
ret= {"ALL UNICODE\n0 = "}
|
||||
|
||||
for i = 1550, 4000 do
|
||||
if i%25==0 then ret[#ret+1] = "\n"..(i).. " = " end
|
||||
ret[#ret+1] = utf8(i)
|
||||
end
|
||||
self.label(table.concat(ret))
|
||||
|
||||
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
-- coal maker mod idea in 30 minutes by rnd
|
||||
-- build dirt box around 3x3x3 area filled with wood, remove one boundary wood (lower one) and start fire there. start robot then!
|
||||
|
||||
check_firebox = function(pos)
|
||||
local p = minetest.find_node_near(pos, 5, "fire:basic_flame") -- locate fire nearby!
|
||||
if not p or minetest.get_node(p).name ~= "fire:basic_flame" then say("light fire first!"); self.remove() end
|
||||
d=3; -- inner size of box, area filled with wood
|
||||
local dirs = {{-1,0,0},{1,0,0},{0,0,-1},{0,0,1}};local dir1,dir2; -- position of vertices on dirt box
|
||||
for i = 1,#dirs do
|
||||
local dir = dirs[i];
|
||||
if minetest.get_node({x=p.x+d*dir[1],y=p.y+d*dir[2],z=p.z+d*dir[3]}).name == "default:dirt" and
|
||||
minetest.get_node({x=p.x+(d-1)*dir[1],y=p.y+(d-1)*dir[2],z=p.z+(d-1)*dir[3]}).name == "default:wood" then dir2 = dirs[i]; break end
|
||||
end
|
||||
if not dir2 then say("error, place fire in correct place in correctly built dirt box!") self.remove() end
|
||||
dir1 = {dir2[3], dir2[2], -dir2[1]};
|
||||
local v1 = {x=p.x-(d-1)*dir1[1]-dir2[1],y=p.y-1,z=p.z-(d-1)*dir1[3]-dir2[3]}
|
||||
local v2 = {x=p.x+(d-1)*dir1[1]+(d)*dir2[1],y=p.y+d,z=p.z+(d-1)*dir1[3]+(d)*dir2[3]}
|
||||
local res = minetest.find_nodes_in_area(v1,v2,{"default:wood","default:dirt"},true);
|
||||
if (#(res["default:dirt"] or {})) == 97 and #(res["default:wood"] or {})==26 then
|
||||
say("all ok. making charcoal now!")
|
||||
minetest.swap_node(p,{name = "air"}) -- turn off fire!
|
||||
else say("fail! check that you built dirt box/wood correctly!")
|
||||
end
|
||||
end
|
||||
|
||||
check_firebox(self.pos())
|
||||
self.remove()
|
|
@ -0,0 +1,187 @@
|
|||
-- "natural language" programming demo by rnd, 2021
|
||||
-- input is lines of 'natural' language, will be translated into lua code
|
||||
|
||||
--[[
|
||||
move forward 3
|
||||
turn left
|
||||
dig left
|
||||
if see dirt turn left and move forward
|
||||
|
||||
subroutine circle commands..
|
||||
|
||||
--> TRANSFORMED into lua :
|
||||
|
||||
for i = 1,3 do move.forward(); pause(); end
|
||||
turn.left(); pause();
|
||||
dig.left(); pause()
|
||||
if read_node.forward()=="dirt" then turn.left();pause(); move.forward(); pause() end
|
||||
|
||||
TODO: integrate into robots, maybe command: code.natural(..)
|
||||
--]]
|
||||
|
||||
if not init then init = true
|
||||
|
||||
prog = [[
|
||||
subroutine walk
|
||||
if see air move forward and move down
|
||||
if see dirt move up
|
||||
if see wood turn right
|
||||
subroutine end
|
||||
|
||||
walk
|
||||
]]
|
||||
|
||||
subroutines = {}; -- [subname] = true , so we know its subroutine
|
||||
|
||||
nodenames = -- translation of block names into minetest
|
||||
{
|
||||
["dirt"] = "default:dirt",
|
||||
["cobble"] = "default:cobble",
|
||||
["stone"] = "default:stone",
|
||||
["wood"] = "default:wood",
|
||||
["water"] = "default:water_source",
|
||||
}
|
||||
|
||||
keywords = {
|
||||
["quit"] = function() return "break;" end,
|
||||
["move"] = {
|
||||
["forward"] = function() return "if move.forward() then pause();paused=true; end;" end,
|
||||
["backward"] = function() return "if move.backward() then pause();paused=true; end;" end,
|
||||
["left"] = function() return "if move.left() then pause();paused=true; end;" end,
|
||||
["right"] = function() return "if move.right() then pause();paused=true; end;" end,
|
||||
["up"] = function() return "if move.up() then pause();paused=true; end;" end,
|
||||
["down"] = function() return "if move.down() then pause();paused=true; end;" end,
|
||||
},
|
||||
|
||||
["turn"] = {
|
||||
["left"] = function() return "turn.left(); pause();paused=true;" end,
|
||||
["right"] = function() return "turn.right(); pause();paused=true;" end,
|
||||
["random"] = function() return "if math.random(2)==1 then turn.right() else turn.left() end; pause(); paused=true;" end
|
||||
},
|
||||
|
||||
["dig"] = function() return "dig.forward(); pause();" end, --TODO: remember to set robot energy to large value at start
|
||||
|
||||
["place"] = function(line)
|
||||
local pattern1 = "place";
|
||||
local i = string.find(line,pattern1)+ string.len(pattern1)+1
|
||||
local nodename = string.sub(line, i) -- what are we placing?
|
||||
if nodenames[nodename] then nodename = nodenames[nodename] end -- translate name
|
||||
return "place.forward('" .. nodename .. "'); pause();"
|
||||
end,
|
||||
|
||||
["if"] = {
|
||||
["see"] = function(line)
|
||||
|
||||
local pattern1 = "see";
|
||||
local pattern2 = "and" .. " "; -- important, space after 'and'
|
||||
|
||||
local i = string.find(line,pattern1) + string.len(pattern1) + 1
|
||||
--nodename command
|
||||
local j = string.find(line," ",i)
|
||||
local nodename, command
|
||||
nodename = string.sub(line,i,j-1)
|
||||
if nodenames[nodename] then nodename = nodenames[nodename] end -- translate name
|
||||
-- maybe command has several parts separated by 'and' ?
|
||||
--cmd1 and cmd2 and cmd3
|
||||
j = j+1; local cmds = {}; local found = false
|
||||
while true do
|
||||
local k = string.find(line,pattern2,j+1)
|
||||
if not k then-- no more AND
|
||||
if found then
|
||||
cmds[#cmds+1] = string.sub(line,j + string.len(pattern2)) break
|
||||
else
|
||||
cmds[#cmds+1] = string.sub(line,j) break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
cmds[#cmds+1] = string.sub(line,j+string.len(pattern2),k-1)
|
||||
else
|
||||
cmds[#cmds+1] = string.sub(line,j,k-1)
|
||||
end
|
||||
found = true
|
||||
j=k
|
||||
end
|
||||
|
||||
for i = 1,#cmds do
|
||||
cmds[i] = parse_line(cmds[i])
|
||||
end
|
||||
|
||||
return "if read_node.forward()=='" ..nodename .. "' then " .. table.concat(cmds," ") .. " end"
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
parse_line = function(line)
|
||||
local struct = keywords;
|
||||
for word in string.gmatch(line,"%S+") do
|
||||
local matched = struct[word]
|
||||
local issub = subroutines[word]
|
||||
if matched or issub then
|
||||
--say(word .. " = " .. type(matched))
|
||||
if type(matched) == "table" then
|
||||
struct = matched; -- climb deeper into structure
|
||||
else
|
||||
local instruction;
|
||||
if issub then
|
||||
instruction = word.."();"
|
||||
else
|
||||
instruction = matched(line)
|
||||
end
|
||||
|
||||
-- do we have need to repeat instruction?
|
||||
local i = string.find(line,word) + string.len(word) + 1
|
||||
local snum = tonumber(string.sub(line,i)) or 1 -- repeating?
|
||||
if snum>1 and snum<10 then
|
||||
return "for i = 1,"..snum .." do " .. instruction .. " end;"
|
||||
end
|
||||
return instruction
|
||||
end
|
||||
else
|
||||
say("error in line: " .. line .. ", unknown command " .. word) return ""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parse_prog = function(code)
|
||||
local out = {};
|
||||
local subdef = false; -- are we defining subroutine?
|
||||
local subname;
|
||||
local subcmds = {}
|
||||
local pattern1 = "subroutine"
|
||||
|
||||
for line in string.gmatch(code,"[^\n]+") do -- line by line
|
||||
|
||||
local i = string.find(line,pattern1)
|
||||
if i then -- do we define new subroutine command?
|
||||
local j = i+string.len(pattern1)+1
|
||||
local sname = string.sub(line,j)
|
||||
if subdef and sname == "end" then -- end of subroutine
|
||||
subdef = false
|
||||
if not keywords[subname] then
|
||||
out[#out+1 ] = "function " .. subname .. "()\n" .. table.concat(subcmds,"\n") .. "\nend"
|
||||
subroutines[subname] = true;
|
||||
else
|
||||
-- error, subroutine name is reserved keyword
|
||||
end
|
||||
subcmds = {};
|
||||
else
|
||||
subdef = true -- all commands will now register with subroutine
|
||||
subname = sname
|
||||
end
|
||||
else -- normal command
|
||||
if subdef then
|
||||
subcmds[#subcmds+1] = parse_line(line)
|
||||
else
|
||||
out[#out+1] = parse_line(line)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
return "--coroutine NaturalLanguage autogenerated\nwhile true do paused = false; "..table.concat(out,"\n") .."if not paused then pause() end end"
|
||||
end
|
||||
|
||||
parsed_prog = parse_prog(prog)
|
||||
self.label(prog .. "\n\n==>\n\n" .. parsed_prog)
|
||||
code.set(parsed_prog) -- actually run code by robot
|
||||
|
||||
end
|
|
@ -0,0 +1,158 @@
|
|||
-- Natural language compiler, outputs lua code
|
||||
-- (C) rnd 2021
|
||||
-- TODO: add IF: if condition arg1 ACTION1 else ACTION2 ?
|
||||
-- ADD SUBROUTINE: sub NAME = enter subroutine definition mode, sub end = ends definition mode
|
||||
|
||||
if not init then init = true
|
||||
dtext = {};
|
||||
dout = function(text) dtext[#dtext+1] = text end
|
||||
text =
|
||||
[[
|
||||
if cond1 value action1 and action2 and action3 else actiona1 and actiona2
|
||||
]]
|
||||
|
||||
translate = { -- dictionary of used words
|
||||
["forward"] = "forward",
|
||||
["backward"] = "backward",
|
||||
["left"] = "left",
|
||||
["right"] = "right",
|
||||
["random"] = "random",
|
||||
["dirt"] = "default:dirt",
|
||||
["wood"]= "default:wood",
|
||||
["cobble"] = "default:cobble",
|
||||
}
|
||||
|
||||
cmds = {
|
||||
["if"] = function(code,ibeg,iend) -- if COND value ACTION1 and ACTION2 and ... ACTIONn else(optional) ACTION1 and ... and ACTIONm
|
||||
-- COND: 'see' nodename (block right in front), 'var = value' value of variable?,...
|
||||
local ELSE = " else"
|
||||
local AND = " and"
|
||||
local i,j,condtype,value;
|
||||
condtype, j = get_next_word(code,ibeg,iend)
|
||||
local out = {};
|
||||
dout(condtype)
|
||||
|
||||
if condtype== "see" then
|
||||
value, j = get_next_word(code,j,iend)
|
||||
value = translate(value or "");
|
||||
if not minetest.registered_nodename(value) then say("error: unknown block name " .. value .. "used in 'if'") return "" end
|
||||
out[#out+1] = "if read_node.forward() == " .. value .. " then ";
|
||||
else
|
||||
say("error: unknown condition " .. condtype .. " used in 'if'") return "" end
|
||||
end
|
||||
-- now after j left: ACTION1 else(optional) ACTION2, ACTION can be multiple, separated by ' and '
|
||||
|
||||
|
||||
-- parse and before else
|
||||
local k = j;
|
||||
lcoal cmds = {}
|
||||
while k do
|
||||
k = string.find(code,AND,j)
|
||||
if k and k<ielse then
|
||||
cmds[#cmds+1] = string.sub(code,j,k-1)
|
||||
j=k+1;
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
dout(table.concat(cmds,"\n"))
|
||||
|
||||
|
||||
--j=...
|
||||
out[#out+1] = "end"
|
||||
|
||||
|
||||
return table.concat(out," "),j
|
||||
|
||||
end,
|
||||
|
||||
["move"] = function(code,ibeg,iend)
|
||||
-- move forward count
|
||||
local i,direction,count
|
||||
direction,i = get_next_word(code,ibeg,iend)
|
||||
direction = translate[direction];
|
||||
if not direction then say("error: unknown direction used in 'turn'") return "" end
|
||||
return "move."..direction .."(); pause();",i;
|
||||
end,
|
||||
|
||||
["turn"] = function(code,ibeg,iend)
|
||||
-- move forward count
|
||||
local i,direction,count
|
||||
direction,i = get_next_word(code,ibeg,iend)
|
||||
|
||||
direction = translate[direction];
|
||||
if not direction then say("error: unknown direction used in 'turn'") return "" end
|
||||
local c;
|
||||
if direction == "random" then
|
||||
c = "if math.random(2) == 1 then turn.left() else turn.right() end;";
|
||||
else
|
||||
c = "turn."..direction .."();"
|
||||
end
|
||||
return c.." pause();",i
|
||||
end,
|
||||
|
||||
["dig"] = function() return "dig.forward(); pause();" end,
|
||||
|
||||
["place"] = function(code,ibeg,iend)
|
||||
-- place nodename
|
||||
local nodename,i
|
||||
nodename,i = get_next_word(code,ibeg,iend)
|
||||
nodename = translate[nodename]
|
||||
if not nodename then say("error: unknown nodename used in 'place'") return "" end
|
||||
|
||||
return "place.forward('" .. nodename .. "'); pause();",i
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
-- given position ibeg in string find next word, return it and then return position immediately after word.
|
||||
-- word is defined as a sequence of alphanumeric characters (%w)
|
||||
-- example 'hello world', ibeg = 1. -> 'hello', 6
|
||||
|
||||
get_next_word = function(code, ibeg,iend) -- attempt to return next word, starting from position ibeg. returns word, index after word
|
||||
if not ibeg or not iend then return end
|
||||
local j = string.find(code,"%w",ibeg); -- where is start of word?
|
||||
if not j or j>iend then return "", iend+1 end -- no words present
|
||||
ibeg = j;
|
||||
j = string.find(code,"%W",j);--where is end of word?
|
||||
if not j or j>iend then return string.sub(code,ibeg,iend-1),iend+1 end
|
||||
return string.sub(code,ibeg,j-1), j
|
||||
end
|
||||
|
||||
|
||||
parse_code = function(code)
|
||||
local out = {};
|
||||
local ibeg,iend,word;
|
||||
local clen = string.len(code)
|
||||
local step =0
|
||||
|
||||
iend = 1; ibeg = 1;
|
||||
while step < 10 do
|
||||
if ibeg>clen then break end
|
||||
step = step+1
|
||||
iend = string.find(code, "\n", ibeg)
|
||||
if not iend then iend = clen end -- get out of loop, no more lines to process
|
||||
|
||||
word, ibeg = get_next_word(code,ibeg,iend)
|
||||
--dout("rem " .. string.sub(code,ibeg,iend))
|
||||
--dout("Dword '" .. word .. "' " .. ibeg .. " " .. iend)
|
||||
local cmd = cmds[word];
|
||||
|
||||
if cmd then out[#out+1],ibeg = cmd(code,ibeg,iend) end
|
||||
if not ibeg then ibeg = iend+1 end
|
||||
if ibeg<=iend then -- still some space remaining in line, last parameter is repetition
|
||||
local count,i
|
||||
count,i = get_next_word(code,ibeg,iend);
|
||||
count = tonumber(count) or 1
|
||||
if count>9 then count = 9 elseif count<1 then count=1 end
|
||||
if count > 1 then out[#out] = "for i=1,"..count.. " do " .. out[#out] .. " end" end
|
||||
end
|
||||
ibeg = iend +1 -- go new line
|
||||
end
|
||||
return table.concat(out,"\n")
|
||||
end
|
||||
|
||||
|
||||
self.label(parse_code(text) .. "\n\n" .. table.concat(dtext,"\n"))
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
-- given position ibeg in string find next word, return it and then return position immediately after word.
|
||||
-- word is a sequence of alphanumeric characters
|
||||
-- example 'hello world', ibeg = 1. -> 'hello', 6
|
||||
|
||||
get_next_word = function(code, ibeg,iend) -- attempt to return next word, starting from position ibeg. returns word, index after word
|
||||
if not ibeg or not iend then return end
|
||||
local j = string.find(code,"%w",ibeg); -- where is start of word?
|
||||
if not j or j>iend then return "", iend+1 end -- no words present
|
||||
ibeg = j;
|
||||
j = string.find(code,"%W",j);--where is end of word?
|
||||
if not j or j>iend then return string.sub(code,ibeg,iend-1),iend+1 end
|
||||
return string.sub(code,ibeg,j-1), j
|
||||
end
|
||||
|
||||
text = [[
|
||||
hello world
|
||||
today
|
||||
day night
|
||||
]]
|
||||
ibeg = 1; iend = string.find(text,"\n",ibeg) or string.len(text) -- where is next new line
|
||||
say("INIT LINE " .. ibeg .. " " .. iend .. " LINE '" .. string.sub(text,ibeg,iend-1) .."'")
|
||||
|
||||
|
||||
for i = 1,10 do
|
||||
|
||||
|
||||
word, ibeg = get_next_word(text,ibeg,iend)
|
||||
say("word '" .. word.."', end " .. ibeg)
|
||||
if ibeg>=iend then -- newline!
|
||||
--say("newline")
|
||||
local j = ibeg;
|
||||
iend = string.find(text,"\n", iend+1) -- find next newline
|
||||
|
||||
if not iend then say("END") iend = string.len(text) break end -- end of text!
|
||||
say("LINE " .. ibeg .. " " .. iend .. " LINE '" .. string.sub(text,ibeg,iend-1) .."'")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.remove()
|
|
@ -1,46 +1,48 @@
|
|||
--rnd 2017
|
||||
if not logdata then
|
||||
self.label("chatlog bot");
|
||||
_G.minetest.forceload_block(self.pos(),true)
|
||||
n = 250;
|
||||
idx = 1;
|
||||
logdata = {};
|
||||
--rnd 2017
|
||||
if not logdata then
|
||||
self.label("");--chatlog bot");
|
||||
_G.minetest.forceload_block(self.pos(),true)
|
||||
n = 500;
|
||||
idx = 1;
|
||||
authusers = {["rnd"] = 1} -- who is allowed to use ?log
|
||||
|
||||
insert = function(text) -- insert new message
|
||||
idx = idx +1;
|
||||
if idx > n then idx = 1 end
|
||||
logdata[idx] = text;
|
||||
end
|
||||
logdata = {};
|
||||
|
||||
last = function(k,filter) -- return last k messages
|
||||
if k > n then k = 30 end
|
||||
local i,j,ret;
|
||||
i=idx;j=0; ret = ""
|
||||
|
||||
for j = 1,k do
|
||||
if not logdata[i] then break end
|
||||
if filter and not string.find(logdata[i], filter) then
|
||||
else
|
||||
ret = ret .. logdata[i] .. "\n";
|
||||
end
|
||||
i=i-1; if i < 1 then i = n end
|
||||
insert = function(text) -- insert new message
|
||||
idx = idx +1;
|
||||
if idx > n then idx = 1 end
|
||||
logdata[idx] = text;
|
||||
end
|
||||
return ret
|
||||
|
||||
last = function(k,filter) -- return last k messages
|
||||
if k > n then k = 30 end
|
||||
local i,j,ret;
|
||||
i=idx;j=0; ret = ""
|
||||
|
||||
for j = 1,k do
|
||||
if not logdata[i] then break end
|
||||
if filter and not string.find(logdata[i], filter) then
|
||||
else
|
||||
ret = ret .. logdata[i] .. "\n";
|
||||
end
|
||||
i=i-1; if i < 1 then i = n end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
self.listen(1)
|
||||
end
|
||||
|
||||
self.listen(1)
|
||||
end
|
||||
|
||||
speaker, msg = self.listen_msg()
|
||||
if msg then
|
||||
if string.sub(msg,1,4) == "?log" then
|
||||
local j = string.find(msg," ",6);
|
||||
local k = tonumber(string.sub(msg,6) or "") or n;
|
||||
local text;
|
||||
if j then text = last(k,string.sub(msg,j+1)) else text = last(k) end
|
||||
local form = "size[8,8]".. "textarea[0.,0;11.,9.5;text;chatlog;".. text .. "]"
|
||||
self.show_form(speaker, form)
|
||||
else
|
||||
insert(os.date("%X") .. " " .. speaker .. "> " .. msg)
|
||||
speaker, msg = self.listen_msg()
|
||||
if msg then
|
||||
if string.sub(msg,1,4) == "?log" and authusers[speaker] then
|
||||
local j = string.find(msg," ",6);
|
||||
local k = tonumber(string.sub(msg,6) or "") or n;
|
||||
local text;
|
||||
if j then text = last(k,string.sub(msg,j+1)) else text = last(k) end
|
||||
local form = "size[8,8]".. "textarea[0.,0;11.,9.5;text;chatlog;".. minetest.formspec_escape(text) .. "]"
|
||||
self.show_form(speaker, form)
|
||||
else
|
||||
insert(os.date("%X") .. " " .. speaker .. "> " .. msg)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue