code preprocessor fix

various demo scripts added
master
rnd 2019-03-05 14:15:59 +01:00
parent ac1817dc9e
commit 8db6acb801
22 changed files with 1088 additions and 87 deletions

View File

@ -136,12 +136,12 @@ basic_robot.commands.dig = function(name,dir)
--require energy to dig
if basic_robot.dig_require_energy then
local digcost = basic_robot.digcosts[nodename];
local digcost = basic_robot.digcosts[nodename] or 1/(5*25); -- default 1/5th of stone dig
if digcost then
local data = basic_robot.data[name];
local energy = (data.menergy or 0) - digcost;
if energy<0 then
error("need " .. digcost .. " energy to dig " .. nodename .. ". Use machine.generate(...) to get some energy.");
error("need " .. digcost .. " energy to dig " .. nodename .. ". Use machine.generate to get some energy.");
end
data.menergy = energy;
end
@ -183,19 +183,6 @@ basic_robot.commands.insert_item = function(name,item, inventory,dir)
local inv = minetest.get_meta(pos):get_inventory();
-- fertilize if soil
if item == "farming:fertilizer" then
local stack = ItemStack(item);
if minetest.get_node(tpos).name == "farming:soil_wet" and (meta:get_int("admin")==1 or inv:contains_item("main", stack)) then
inv:remove_item("main", stack);
local nutrient = tmeta:get_int("nutrient"); nutrient = nutrient + 10; if nutrient>20 then nutrient = 20 end
tmeta:set_int("nutrient",nutrient);
minetest.set_node({x=tpos.x,y=tpos.y+1,z=tpos.z},{name = "air"})
return true
end
end
local tinv = minetest.get_meta(tpos):get_inventory();
if not inventory then inventory = "main"; end
@ -866,30 +853,26 @@ basic_robot.technic = { -- data cache
["default:cobble"] = {1,"default:gravel",1},
["default:gravel"] = {0.5,"default:dirt",1},
["default:dirt"] = {0.5,"default:clay_lump 4",1},
["es:aikerum_crystal"] ={16,"es:aikerum_dust 2",1}, -- added for es mod
["es:ruby_crystal"] = {16,"es:ruby_dust 2",1},
["es:emerald_crystal"] = {16,"es:emerald_dust 2",1},
["es:purpellium_lump"] = {16,"es:purpellium_dust 2",1},
["default:obsidian_shard"] = {199,"default:lava_source",1},
["gloopblocks:basalt"] = {1, "default:cobble",1}, -- enable coble farms with gloopblocks mod
["default:ice"] = {1, "default:snow 4",1},
["darkage:silt_lump"]={1,"darkage:chalk_powder",1},
["default:diamond"] = {16, "basic_machines:diamond_dust_33 2", 1},
["default:diamond"] = {16, "basic_machines:diamond_dust_00 2", 1},
["default:ice"] = {1, "default:snow", 1},
["moreores:tin_lump"] = {4,"basic_machines:tin_dust_33 2",1},
["moreores:tin_lump"] = {4,"basic_machines:tin_dust_00 2",1},
["default:obsidian_shard"] = {199, "default:lava_source",1},
["default:mese_crystal"] = {8, "basic_machines:mese_dust_33 2",1},
["default:mese_crystal"] = {8, "basic_machines:mese_dust_00 2",1},
["moreores:mithril_ingot"] = {16, "basic_machines:mithril_dust_33 2",1},
["moreores:silver_ingot"] = {5, "basic_machines:silver_dust_33 2",1},
["moreores:tin_ingot"] = {4,"basic_machines:tin_dust_33 2",1},
["moreores:tin_ingot"] = {4,"basic_machines:tin_dust_00 2",1},
["moreores:mithril_lump"] = {16, "basic_machines:mithril_dust_33 2",1},
["default:steel_ingot"] = {4, "basic_machines:iron_dust_33 2",1},
["default:steel_ingot"] = {4, "basic_machines:iron_dust_00 2",1},
["moreores:silver_lump"] = {5, "basic_machines:silver_dust_33 2",1},
["default:gold_ingot"] = {6, "basic_machines:gold_dust_33 2", 1},
["default:copper_ingot"] = {4, "basic_machines:copper_dust_33 2",1},
["default:gold_lump"] = {6, "basic_machines:gold_dust_33 2", 1},
["default:iron_lump"] = {4, "basic_machines:iron_dust_33 2",1},
["default:copper_lump"] = {4, "basic_machines:copper_dust_33 2",1},
["default:gold_ingot"] = {6, "basic_machines:gold_dust_00 2", 1},
["default:copper_ingot"] = {4, "basic_machines:copper_dust_00 2",1},
["default:gold_lump"] = {6, "basic_machines:gold_dust_00 2", 1},
["default:iron_lump"] = {4, "basic_machines:iron_dust_00 2",1},
["default:copper_lump"] = {4, "basic_machines:copper_dust_00 2",1},
},
compressor_recipes = { --[in] ={fuel cost, out, quantity of material required for processing}

View File

@ -4,8 +4,8 @@
basic_robot = {};
------ SETTINGS --------
basic_robot.call_limit = {50,200,1500,10^9}; -- how many execution calls per script run allowed, for auth levels 0,1,2 (normal, robot, puzzle, admin)
basic_robot.entry_count = 2 -- how many robots ordinary player can have
basic_robot.advanced_count = 16 -- how many robots player with robot privs can have
basic_robot.count = {2,4,16,128} -- how many robots player can have
basic_robot.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches
basic_robot.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running mod, password used for authentifications
@ -25,7 +25,7 @@ basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes invento
basic_robot.http_api = minetest.request_http_api();
basic_robot.version = "2019/01/13a";
basic_robot.version = "2019/02/16a";
basic_robot.gui = {}; local robogui = basic_robot.gui -- gui management
basic_robot.data = {}; -- stores all robot related data
@ -217,29 +217,6 @@ function getSandboxEnv (name)
return commands.display_text(obj,text,linesize,size)
end,
sound = function(sample,volume, pos)
if pos then
return minetest.sound_play( sample,
{
pos = pos,
gain = volume or 1,
max_hear_distance = 32, -- default, uses an euclidean metric
})
end
local obj = basic_robot.data[name].obj;
return minetest.sound_play( sample,
{
object = obj,
gain = volume or 1,
max_hear_distance = 32, -- default, uses an euclidean metric
})
end,
sound_stop = function(handle)
minetest.sound_stop(handle)
end,
},
machine = {-- adds technic like functionality to robots: power generation, smelting, grinding, compressing
@ -478,7 +455,9 @@ function getSandboxEnv (name)
if authlevel>=1 then -- robot privs
env.self.sound = minetest.sound_play
env.self.sound_stop = minetest.sound_stop
env.table = {
concat = table.concat,
insert = table.insert,
@ -512,7 +491,6 @@ function getSandboxEnv (name)
end
return true
end
env.self.read_form = function()
local fields = basic_robot.data[name].read_form;
@ -590,9 +568,9 @@ local identify_strings = function(code) -- returns list of positions {start,end}
local i = 0; local j; local _; local length = string.len(code);
local mode = 0; -- 0: not in string, 1: in '...' string, 2: in "..." string, 3. in [==[ ... ]==] string
local modes = {
{"'","'"},
{"\"","\""},
{"%[=*%[","%]=*%]"}
{"'","'"}, -- inside ' '
{"\"","\""}, -- inside " "
{"%[=*%[","%]=*%]"}, -- inside [=[ ]=]
}
local ret = {}
while i < length do
@ -615,7 +593,7 @@ local identify_strings = function(code) -- returns list of positions {start,end}
else
_,j = string.find(code,modes[mode][2],i); -- search for closing pair
if not j then break end
if (mode~=2 or string.sub(code,j-1,j-1) ~= "\\") then -- not (" and \")
if (mode~=2 or (string.sub(code,j-1,j-1) ~= "\\") or string.sub(code,j-2,j-1) == "\\\\") then -- not (" and not \" - but "\\" is allowed)
ret[#ret][2] = j
mode = 0
end
@ -626,6 +604,7 @@ local identify_strings = function(code) -- returns list of positions {start,end}
return ret
end
is_inside_string = function(strings,pos) -- is position inside one of the strings?
local low = 1; local high = #strings;
if high == 0 then return false end
@ -805,10 +784,24 @@ end
-- note: to see memory used by lua in kbytes: collectgarbage("count")
local get_authlevel = function(name) -- given player name return auth level
local privs = minetest.get_player_privs(name);
local authlevel = 0;
if privs.privs then -- set auth level depending on privs
authlevel = 3
elseif privs.puzzle then
authlevel = 2
elseif privs.robot then
authlevel = 1
else
authlevel = 0
end
return authlevel
end
local function setupid(owner)
local privs = minetest.get_player_privs(owner); if not privs then return end
local maxid = basic_robot.entry_count;
if privs.robot or privs.puzzle then maxid = basic_robot.advanced_count end -- max id's per user
local maxid = basic_robot.count[get_authlevel(owner)+1] or 2;
basic_robot.ids[owner] = {id = 1, maxid = maxid}; --active id for remove control
end
@ -1584,6 +1577,7 @@ minetest.register_on_player_receive_fields(
data.text = text or ""
data.title = fields.title or ""
data.text_len = #data.text
data.description = fields.title or ""
data.page = 1
data.owner = data.owner or ""
local lpp = 14
@ -1645,17 +1639,7 @@ minetest.register_node("basic_robot:spawner", {
local owner = placer:get_player_name();
meta:set_string("owner", owner);
local privs = minetest.get_player_privs(placer:get_player_name());
local authlevel = 0;
if privs.privs then -- set auth level depending on privs
authlevel = 3
elseif privs.puzzle then
authlevel = 2
elseif privs.robot then
authlevel = 1
else
authlevel = 0
end
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
@ -1749,6 +1733,7 @@ minetest.register_craftitem("basic_robot:control", {
local ids = basic_robot.ids[owner]; if not ids then setupid(owner) end
local id = basic_robot.ids[owner].id or 1; -- read active id for player
local name = owner..id;
local form =
"size[9.5,1.25]" .. -- width, height
"textarea[1.25,-0.25;8.75,2.25;code;;".. code.."]"..

54
misc_commands.lua Normal file
View File

@ -0,0 +1,54 @@
//lua minetest.get_player_by_name("rnd"):set_properties({visual_size = {x=1,y=1}})
local name = "rnd"; local player = minetest.get_player_by_name(name); player:set_properties({visual = "upright_sprite"});player:set_properties({textures={"default_tool_diamondpick.png"}})
// change to robot
local name = "rnd"; local player = minetest.get_player_by_name(name); player:set_properties({visual = "cube"});player:set_properties({textures={"arrow.png^[transformR90","basic_machine_side.png","basic_machine_side.png","basic_machine_side.png","face.png","basic_machine_side.png"}});player:set_properties({collisionbox={-0.5,-0.5,-0.5,0.5,0.5,0.5}})
//LawnGreen
local name = "rnd"; local player = minetest.get_player_by_name(name); player:set_properties({visual = "sprite"});player:set_properties({textures={"farming_bottle_ethanol.png"}});player:set_properties({collisionbox={-0.5,-0.5,-0.5,0.5,0.5,0.5}});player:set_properties({visual_size = {x=2,y=2}})
//farming_blueberry_muffin
local name = "rnd"; local player = minetest.get_player_by_name(name); player:set_properties({visual = "cube"});player:set_properties({textures={"farming_pumpkin_face_off.png","farming_pumpkin_face_off.png","farming_pumpkin_face_off.png","farming_pumpkin_face_off.png","farming_pumpkin_face_off.png","farming_pumpkin_face_off.png"}});player:set_properties({collisionbox={-0.5,-0.5,-0.5,0.5,0.5,0.5}})
--nyan cat
//lua local name = "rnd"; local player = minetest.get_player_by_name(name); player:set_properties({visual = "cube"});player:set_properties({textures = {"nyancat_side.png", "nyancat_side.png", "nyancat_side.png","nyancat_side.png", "nyancat_front.png", "nyancat_back.png"}});player:set_properties({collisionbox={-0.5,-0.5,-0.5,0.5,0.5,0.5}})
local name = "rnd1"; local player = minetest.get_player_by_name(name); player:set_nametag_attributes({text = "Friend of Giorge"});
//lua local player = minetest.get_player_by_name("pro2");minetest.sound_play("nyan",{object = player,gain = 1.0,max_hear_distance = 8,loop = false})
//lua local player = minetest.get_player_by_name("rnd");player:set_properties({visual = "mesh",textures = {"mobs_spider.png"},mesh = "mobs_spider.x",visual_size = {x=7,y=7}})
//lua local player = minetest.get_player_by_name("rnd");player:set_properties({visual = "mesh",textures = {"mobs_dungeon_master.png"},mesh = "mobs_dungeon_master.b3d",visual_size = {x=1,y=1}})
//lua local player = minetest.get_player_by_name("best");player:set_properties({visual = "mesh",textures = {"zmobs_mese_monster.png"},mesh = "zmobs_mese_monster.x",visual_size = {x=1,y=1}})
//lua local player = minetest.get_player_by_name("rnd1");player:set_properties({visual = "mesh",textures = {"mobs_oerkki.png"},mesh = "mobs_oerkki.b3d",visual_size = {x=1,y=1}})
//lua local player = minetest.get_player_by_name("rnd1");player:set_properties({visual = "mesh",textures = {"mobs_stone_monster.png"},mesh = "mobs_stone_monster.b3d",visual_size = {x=1,y=1}})
mesh = "zmobs_lava_flan.x",
textures = {
{"zmobs_lava_flan.png"},
{"zmobs_lava_flan2.png"},
{"zmobs_lava_flan3.png"},
},
----------------------------------------------
//lua local player = minetest.get_player_by_name("towner");player:set_physics_override({speed=0.05})

View File

@ -0,0 +1,56 @@
-- simple box pushing game, rnd
if not init then
spos = self.spawnpos(); spos.x = spos.x +5; spos.z = spos.z +5;
for i = 1, 2 do
for j = 1,2 do
puzzle.set_node({x=spos.x+i,y=spos.y,z=spos.z+j}, {name = "basic_robot:buttonFFFFFF"})
end
end
init = true
players = find_player(5);
if not players then say("no players nearby") self.remove() end
say("BOX PUSH demo. punch the white box to move it around ")
pushables = {[1] = true} -- button types
canpushnodes = {["air"] = 1, ["basic_robot:button8080FF"] = 2} -- 1 push node, 2 absorb node
end
event = keyboard.get()
if event then
local boxtype = event.type
if pushables[boxtype] then
player = puzzle.get_player(event.puncher)
local pos = player:getpos();
local boxpos = {x = event.x, y = event.y, z = event.z};
local diff = { pos.x-boxpos.x, pos.z-boxpos.z};
local newx,newz
if math.abs(diff[1])>math.abs(diff[2]) then -- punch in x-direction
newx = boxpos.x - (diff[1]>0 and 1 or -1)
newz = boxpos.z
else
newx = boxpos.x
newz = boxpos.z - (diff[2]>0 and 1 or -1)
end
local newnode = puzzle.get_node({x=newx, y= boxpos.y, z= newz}).name
local canpush = canpushnodes[newnode]
if canpush then
local oldnode = puzzle.get_node(boxpos).name
puzzle.set_node(boxpos,{name= "air"}) -- remove node
if canpush == 1 then -- simply move the box
newnode = oldnode
elseif canpush == 2 then -- absorb the box
newnode = newnode
end
puzzle.set_node({x=newx, y= boxpos.y, z= newz}, {name = newnode})
end
end
--say(serialize(event))
end

103
scripts/games/sokoban3d.lua Normal file
View File

@ -0,0 +1,103 @@
-- sokoban 3D, rnd
if not init then
spos = self.spawnpos(); spos.x = spos.x +5; spos.z = spos.z +5;
for i = 1, 2 do
for j = 1,2 do
puzzle.set_node({x=spos.x+i,y=spos.y,z=spos.z+j}, {name = "basic_robot:buttonFFFFFF"})
end
end
init = true
players = find_player(5);
if not players then say("no players nearby") self.remove() end
puzzle.get_player(players[1]):set_physics_override({jump = 0.85}) -- just allow jump on 1 block up
say("BOX PUSH demo. punch the white box to move it around ")
self.label(
"SOKOBAN 3D. RULES:\n1. pushable blocks: white,gray,yellow. you can not push block if another block is on top of it,\n2. elevator block: yellow - can push other blocks on top of it,"..
"\n3. if block falls it breaks, unless it falls less than 1 deep onto green block\n"..
"4. if you push block into blue it dissapears\n"..
"5. you can only push block by standing close in front of it, not too low below it or too high above it\n"..
"LEVEL 1: push white block on top of red block")
pushables = {[1] = true,[2] = true,[6] = true} -- button types: white,gray, yellow
canpushnodes = {-- you can push into these nodes, 1 push node, 2 absorb node, 3 = elevator
["air"] = 1,
["basic_robot:button8080FF"] = 2,
["basic_robot:buttonFFFF80"] = 3,
}
end
event = keyboard.get()
if event then
local boxtype = event.type
if pushables[boxtype] then
player = puzzle.get_player(event.puncher)
local pos = player:getpos();
local boxpos = {x = event.x, y = event.y, z = event.z};
local diff = { pos.x-boxpos.x, pos.z-boxpos.z, pos.y - boxpos.y}; -- x,z,y
local newx,newy,newz
newy = boxpos.y
local allowpush = true
--self.label(diff[3])
if diff[3]<-1.5 or diff[3]>0.5 then allowpush = false end -- dont allow to push if height difference to large
if math.abs(diff[1])>math.abs(diff[2]) then -- punch in x-direction
newx = boxpos.x - (diff[1]>0 and 1 or -1)
newz = boxpos.z
if math.abs(diff[1])<0.7 or math.abs(diff[1])>1 then allowpush = false end -- dont allow push if too close
if math.abs(diff[2]) > 0.25 then allowpush = false end -- must stand in front to push, not from side
else
newx = boxpos.x
newz = boxpos.z - (diff[2]>0 and 1 or -1)
if math.abs(diff[2])<0.7 or math.abs(diff[2])>1 then allowpush = false end -- dont allow push if too close
if math.abs(diff[1]) > 0.25 then allowpush = false end -- must stand in front to push, not from side
end
--self.label(diff[1] .. " " .. diff[2] .. " " .. diff[3])
local newnode = puzzle.get_node({x=newx, y= boxpos.y, z= newz}).name
local canpush = canpushnodes[newnode]
if allowpush and canpush then
local oldnode = puzzle.get_node(boxpos).name
if canpush == 1 then -- simply move the box
newnode = oldnode
elseif canpush == 2 then -- absorb the box
newnode = newnode
elseif canpush == 3 then
newnode = oldnode
newy = newy+1
end
local nodeabove = puzzle.get_node({x=boxpos.x, y=boxpos.y+1, z= boxpos.z}).name
if nodeabove ~="air" then allowpush = false end -- no floating nodes allowed
local nodebelow = puzzle.get_node({x=newx, y=newy-1, z= newz}).name
if nodebelow == "air" then
if puzzle.get_node({x=newx, y=newy-2, z= newz}).name ~= "basic_robot:button80FF80" then
newnode = "air"
else
newy=newy-1
end
end -- fall down
if allowpush then
puzzle.set_node(boxpos,{name= "air"}) -- remove node
puzzle.set_node({x=newx, y= newy, z= newz}, {name = newnode})
end
end
end
--say(serialize(event))
end

View File

@ -0,0 +1,23 @@
if not init then
text = " hello world "
name = "rnd"
m = 8;
idx = 0;
n = string.len(text)
player = puzzle.get_player(name)
inv = player:get_inventory()
inv:set_list("main",{})
init = true
end
for i = 1, m do
local j = (idx+i)%n + 1
local c = string.byte(text,j)-97;
if c<0 or c>30 then c = -97 end
inv:set_stack("main", i,puzzle.ItemStack("basic_robot:button_" ..(97+c)))
end
idx = (idx + 1) % n
--self.remove()

View File

@ -25,18 +25,8 @@ if not fetch then
self.label(os.date("%X") ..', cmd : ' .. req)
local i = string.find(req," !")
if i then
local cmd = string.sub(req,i+2)
if cmd == "players" then
local players = minetest.get_connected_players();
out = {};
for i = 1,#players do out[i] = players[i]:get_player_name() end
MT2web("online players : " .. table.concat(out,", "))
else
run_commmand(cmd)
end
run_commmand(string.sub(req,i+2))
end
end
end
@ -59,8 +49,6 @@ if not fetch then
fetch({url = "http://".. address .. "/mtmsg/"..message, timeout = 5}, result)
end
MT2web("minetest robot started and listening.")
self.listen(1)
end

View File

@ -0,0 +1,91 @@
-- ACTIVITY GENERATOR + modified /status
-- makes server appear more active: virtual players join/leave, talk
if not init then
minetest.forceload_block(self.pos(),true)
self.label("activity generator")
local chatc = _G.core.registered_chatcommands["status"];
if chatc then
if not rom.chatc then rom.chatc = chatc end
--self.label(serialize(chatc))
hidden_players = {
rnd = false,
}
extra_players = {
"Piojoblanco","Bryan0911","EmmaBTS","atmaca","pausc05","bobo","marquez","Maike-008","odiseu","jere700182","_z","erick07","elvergalarga01","follow","Mantano10","AW","0987654321","lavraimeriem","formless","kanekii","cuchita","X_Pro_X","Tron","MGPe","Budrow42","lahina","shaahin18","dolphin","Stickman301","Galves58","Appelbaum747jdjxi","agy","E23","Utsler26","Rafael_Aaron_PROOO","cloe","Athans82","Love_Girl","jklu","Marne485hv","xXNicoXx","Dootson22","squad","fatima","Cucuzza62"
}
extra_joined = {};
greetings = {"hi","hello","pls help","help","how to play?", "i have only 2 blocks?","cool",":(","someone help","HI"}
_G.core.registered_chatcommands["status"] =
{
description = "Print server status",
func = function(name, param)
local connected = minetest.get_connected_players();
local ret = {};
for i = 1,#connected do
local pname = connected[i]:get_player_name();
if not hidden_players[pname] then ret[#ret+1] = pname end
end
local clients = table.concat(ret,", ");
local extras = {};
for name,_ in pairs(extra_joined) do extras[#extras+1] = name end
if #extras>0 then clients = clients ..", " .. table.concat(extras, ", ") end
return true, "# Server: version=0.4.17.1, uptime = ".. math.floor(minetest.get_server_uptime()*10)/10 ..", max_lag = 0.1, clients = {".. clients .. "}"
end,
}
--_G.core.registered_chatcommands["status"] = rom.chatc -- uncomment this to restore
end
t=0
init = true
end
t=t+1;
if t%5 == 0 then
local r = math.random(10)
if r <= 2 then -- add random new player
--say(t)
local idx = math.random(#extra_players)
local pname = extra_players[idx];
if pname and not extra_joined[pname] then
extra_joined[pname] = true
minetest.chat_send_all("*** " .. pname .. " joined the game.")
end
elseif r<=4 then -- disconnect random extra
local count = 0;
for pname,_ in pairs(extra_joined) do count = count + 1 end
local idx = math.random(count)
count = 0;
for pname,_ in pairs(extra_joined) do
count = count + 1
if count == idx then
minetest.chat_send_all("*** " .. pname .. " left the game.")
extra_joined[pname] = nil
break
end
end
elseif r<=6 then -- chat
if math.random(5) == 1 then
local count = 0
for pname,_ in pairs(extra_joined) do count = count + 1 end
local idx = math.random(count)
count = 0;
for pname,_ in pairs(extra_joined) do
count = count + 1
if count == idx then
r = math.random(#greetings);
minetest.chat_send_all("<" .. pname .. "> " ..greetings[r])
break
end
end
end
end
end
--self.remove()

View File

@ -0,0 +1,23 @@
-- simple chat board by rnd
if not init then init = true
pos = self.pos()
write_text = function(text,size)
for x=0,size-1 do
for y = size-1,0,-1 do
local c = (string.byte(text, (size-1-y)*size+(x+1)) or 32)-97
puzzle.set_node({x=pos.x+x+1,y=pos.y+y,z=pos.z},{name = "basic_robot:button_"..(97+c)})
end
end
end
self.listen(1)
end
speaker,msg= self.listen_msg()
if msg then
write_text(msg,15)
end

View File

@ -0,0 +1,16 @@
compact_inventory = function(item)
local size = 32
local count = 0
for i = 1,size do
local stringname = check_inventory.self("","main",i);
local itemname, j = stringname:match("(%S+) (%d+)")
if itemname == item then
count = count + tonumber(j)
end
end
say(string.format("total count of %s is %s",item,count))
insert.forward(string.format("%s %s",item,count)) -- will join all items together
end

View File

@ -0,0 +1,297 @@
-- subdivide rectangular area made from various node types into union of disjoint contigious boxes,
-- box count should be small, by rnd 2018
if not init then
init = true -- map saver
local dout = function(msg) minetest.chat_send_player("rnd", msg) end
minidx = 1 -- minimal position index not yet in box collection
blockdata = {}; --[1] = {p1,p2} [2] = list of nodenames, [3] = list [x][y][z] = nodename idx
table_copy = function(tab)
local out = {};
for k,v in pairs(tab) do
out[k] = v
end
return out
end
read_block = function(p1,p2,data)
if p1.x>p2.x or p1.y>p2.y or p1.z>p2.z then return end -- p1 coords must be smaller than p2 coords
data[1] = {{x=p1.x,y=p1.y,z=p1.z},{x=p2.x-p1.x+1,y=p2.y-p1.y+1,z=p2.z-p1.z+1}} -- startpos, dimensions
local nodedb = {} -- [nodename] = node idx
local nodelist = {} -- list of nodes: nodename1, nodename2,...
local nodes = {} -- table containing nodes [x][y][z] = node idx
local ncount = 0;
local idx = 0
for x = p1.x, p2.x do
nodes[x-p1.x+1] = {}
for y = p1.y, p2.y do
nodes[x-p1.x+1][y-p1.y+1] = {}
for z = p1.z, p2.z do
idx=idx+1
local nodename = minetest.get_node({x=x,y=y,z=z}).name
local nidx = nodedb[nodename]
if not nidx then
ncount = ncount + 1
nodedb[nodename] = ncount;
nodelist[ncount] = nodename
nidx = ncount
end
--nodes[idx] = nidx
nodes[x-p1.x+1][y-p1.y+1][z-p1.z+1 ] = nidx
end
end
end
data[2] = nodelist
data[3] = nodes
end
id2pos = function(idx,blockdata) -- idx starts with 0
local dx = blockdata[1][2].x
local dy = blockdata[1][2].y
local dz = blockdata[1][2].z
-- idx = z*dx*dy + y*dx + dx
local x = idx % dx;
idx = (idx - x)/dx
local y = idx % dy; -- y = y % (dy)
local z = (idx - y)/dy
return {x=x, y = y, z=z}
end
pos2id = function(pos,blockdata)
local dx = blockdata[1][2].x
local dy = blockdata[1][2].y
local dz = blockdata[1][2].z
local x = pos.x - blockdata[1][2].x;
local y = pos.y - blockdata[1][2].y;
local z = pos.z - blockdata[1][2].z;
return z*dx*dy + y*dx + dx
end
get_box = function(pos, blockdata, boxdata) -- return p1,p2, nodeidx defining largest contiguos box containing pos (all relative coordinates)
local nodeidx = blockdata[3][pos.x][pos.y][pos.z];
local active_dir = {[1]=true,[2]=true,[3]=true,[4]=true,[5]=true,[6]=true}; -- which dirs to search: x-,x+ y-,y+ z-,z+
local p1 = {x=pos.x,y=pos.y,z=pos.z} -- search limits
local p2 = {x=pos.x,y=pos.y,z=pos.z}
local stop = false;
local steps = 0
while not stop and steps < 10000 do -- steps 'safety'
steps = steps + 1
--dout("step " .. steps .. " p1 " .. serialize(p1) .. " p2 " .. serialize(p2) .. " dirs " .. serialize(active_dir))
stop = true
for idx,_ in pairs(active_dir) do -- try expansion in different directions
stop = false -- still something to do
if idx<=2 then
local x
if idx == 1 then x = p1.x-1 else x=p2.x+1 end
if blockdata[3][x] then
local bdata = blockdata[3][x];
for y = p1.y,p2.y do
for z = p1.z,p2.z do
if bdata[y][z]~= nodeidx or (boxdata and boxdata[x] and boxdata[x][y] and boxdata[x][y][z]) then
active_dir[idx] = nil; goto ex; -- not contiguous anymore
end
end
end
::ex::
else
active_dir[idx] = nil -- out of bounds, remove direction
end
if active_dir[idx] then -- expansion succesful
if idx == 1 then p1.x = p1.x -1 else p2.x = p2.x+1 end
end
elseif idx>=5 then
local z
if idx == 5 then z = p1.z-1 else z=p2.z+1 end
local bdata = blockdata[3]
if bdata[1][1][z] then
for x = p1.x,p2.x do
for y = p1.y,p2.y do
if bdata[x][y][z]~= nodeidx or (boxdata and boxdata[x] and boxdata[x][y] and boxdata[x][y][z]) then
active_dir[idx] = nil;goto ex; -- lua only breaks out of 1 loop :(
end
end
end
::ex::
else
active_dir[idx] = nil -- out of bounds, remove direction
end
if active_dir[idx] then -- expansion succesful
if idx == 5 then p1.z = p1.z -1 else p2.z = p2.z+1 end
end
else
local y
if idx == 3 then y = p1.y-1 else y=p2.y+1 end
local bdata = blockdata[3]
if bdata[1][y] then
for x = p1.x,p2.x do
for z = p1.z,p2.z do
if bdata[x][y][z]~= nodeidx or (boxdata and boxdata[x] and boxdata[x][y] and boxdata[x][y][z]) then
active_dir[idx] = nil; goto ex; -- not contiguous anymore
end
end
end
::ex::
else
active_dir[idx] = nil -- out of bounds, remove direction
end
if active_dir[idx] then -- expansion succesful
if idx == 3 then p1.y = p1.y-1 else p2.y = p2.y+1 end
end
end
end --try to expand: -x +x -y +y -z +z -x +x -y ... when not possible remove direction from list
end
return {p1,p2, nodeidx}
end
get_boxes = function(blockdata,boxdata)
local dx = blockdata[1][2].x
local dy = blockdata[1][2].y
local dz = blockdata[1][2].z
for k,v in pairs(boxdata) do boxdata[k] = nil end
local res = {}; -- list of boxes
for x=1,dx do
boxdata[x] = {}
for y = 1,dy do
boxdata[x][y] = {}
end
end
local xc, yc,zc;
xc = 1 ; yc = 1; zc = 1; -- current 'working' coordinates in block
local steps = 0;
local stop = false;
while not stop and steps < 1000 do
steps = steps + 1
stop = true
-- find 'next' coordinate thats not yet marked: todo - fix bugs here, skipping/unnecessary ...
xc = 1; -- set 1st index ( inner loop) to start
--dout("step " .. steps ..", search start xc yc zc ".. xc .. " " .. yc .. " " .. zc)
local x,y,z;x= xc; y=yc; z = zc;
while (z<=dz) do
while (y<=dy) do
while (x<=dx) do
if not boxdata[x][y][z] then
--dout("step " .. steps .. ", next point: " .. x .. " " .. y .. " " .. z)
stop = false; xc = x; yc=y; zc = z; goto ex
end
x=x+1
end
y=y+1; x=1; -- reset x-loop
end
z=z+1; y=1; -- reset y-loop
end
--dout("no unmarked point left, dim dx dy dz : " .. dx .. " " .. dy .. " " .. dz)
::ex::
if stop then break end
--if box non air add it
local box = get_box({x=xc,y=yc,z=zc},blockdata, boxdata);
if blockdata[2][box[3]]~= "air" then
res[#res+1] = box
end
-- mark box area as done
for x = box[1].x, box[2].x do
for y = box[1].y, box[2].y do
for z = box[1].z, box[2].z do
boxdata[x][y][z] = true
end
end
end
--dout("boxdata " .. serialize(boxdata))
end
return res
end
render_boxes = function(blockdata,boxes)
local dx = blockdata[1][2].x
local dy = blockdata[1][2].y
local dz = blockdata[1][2].z
local x0 = blockdata[1][1].x
local y0 = blockdata[1][1].y
local z0 = blockdata[1][1].z
local nodelist = {
"wool:white","wool:red","wool:green","wool:blue","wool:yellow", "wool:cyan","wool:pink",
"wool:brown","wool:magenta","wool:orange","wool:violet"
}
local nodelen = #nodelist
for x = 1, dx do
for y = 1, dy do
for z = 1, dz do
minetest.set_node({x = x0+x-1, y= y0+y-1+ (dy + 1), z = z0+z-1},{name = "air"})
end
end
end
for i = 1,#boxes do
for x = boxes[i][1].x, boxes[i][2].x do
for y = boxes[i][1].y, boxes[i][2].y do
for z = boxes[i][1].z, boxes[i][2].z do
--minetest.set_node({x = x0+x-1, y= y0+y-1+ (dy + 4), z = z0+z-1},{name = blockdata[2][boxes[i][3] ] })
minetest.set_node({x = x0+x-1, y= y0+y-1+ (dy + 4), z = z0+z-1},{name = nodelist[1+((i-1) % nodelen)]})
end
end
end
end
end
--p1 = {x=-57,y=6,z=14};p2 = {x=-54,y=6,z=17}
p1 = {x=-45,y=502,z=-45};p2 = {x=-30,y=504,z=-30}
read_block(p1,p2,blockdata) -- careful, all p1 coords must be smaller than p2 coords coordinatewise
--self.label(serialize(blockdata))
-- 7 numbers per box: pos1, pos2, nodeidx. There are n^2 numbers for nxn grid, so for boxes to be efficient
-- 7*boxcount<n^3 or boxcount< n^3/7
--box = get_box({x=3,y=1,z=2},blockdata)
--say(serialize(box))
local boxdata = {};
local boxes = get_boxes(blockdata,boxdata);
self.label("dimensions " .. blockdata[1][2].x .. " " .. blockdata[1][2].y .. " " .. blockdata[1][2].z .. ", n^3/7 = " .. blockdata[1][2].x*blockdata[1][2].y*blockdata[1][2].z/7 .. ", boxes " .. #boxes )
--dout(serialize(boxes))
render_boxes(blockdata,boxes)
end

View File

@ -0,0 +1,9 @@
-- send data from robot to irc client, rnd 2018 ( works on vanessae skyblock)
if not init then
ircchat = minetest.registered_chatcommands["irc_msg"].func;
name = "r_n_d" -- client on irc you want to send msg too
ircchat("ROBOT", name .." " .. "hello irc world") -- chat will appear as coming from <ROBOT> on skyblock
init = true
end

View File

@ -0,0 +1,12 @@
local serialize = function(tab) -- helper function
local out = {};
for k,v in pairs(tab) do
if type(v)~= "table" then
out[#out+1] = ""..k .." = " ..v
else
out[#out+1] = ""..k .. " = " .. serialize(v)
end
end
return "{"..table.concat(out,", ").."}"
end

View File

@ -0,0 +1,46 @@
-- simple turtlebot with loops, rnd, 30 mins
if not init then
init = true
commands = {
["f"] = function() move.forward() end,
["l"] = function() move.left() end,
["r"] = function() move.right() end,
["u"] = function() move.up() end,
["d"] = function() move.down() end,
[">"] = function() turn.right() end,
["<"] = function() turn.left() end,
["p"] = function() place.down("default:dirt") end,
["P"] = function() place.forward_down("default:dirt") end,
}
program = "R3[Pfu]<"
loop = {start = 1, quit = 1, count = 1};
step = 1
end
c = string.sub(program,step,step)
if c == "R" then -- loop
local i = string.find(program,"%[",step+1);
loop.count = tonumber(string.sub(program,step+1, i-1)) or 1;
loop.start = i+1;
i = string.find(program,"]",i+1);
loop.quit = i-1
step = loop.start-1
else -- normal command
command = commands[c];
if command then
command()
elseif step>string.len(program) then
step = 0
end
end
self.label(step)
step = step +1
if loop.count>0 then -- are we in loop?
if step>loop.quit then loop.count = loop.count - 1; step = loop.start end
if loop.count == 0 then step = loop.quit + 2 end
end

View File

@ -0,0 +1,89 @@
-- digital money: transform items into key (stand on chest and write \buy) and later get them back (\sell code)
--[[
instructions: put items in chest, stand on top of it and say: \buy. this gives you code, you can later write in
'\sell code' and get stuff back.
--]]
if not init then
self.label("digital banker bot")
password = "super secret password"
buydb = {};
starttime = minetest.get_gametime()
_G.minetest.forceload_block(self.pos(),true)
import_inventory = function(pos) -- read inventory and output digital money
local meta = minetest.get_meta(pos); if not meta then return end
local inv = meta:get_inventory(); if not inv then return end
if not inv:get_size("main") then return end
if inv:is_empty("main") then return end
local invlist = {};
for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i):to_string();
local i = string.find(stack, " ");
local itemname = stack;
local count = 0;
if i then
itemname = string.sub(stack,1,i-1)
count = count + (tonumber(string.sub(stack,i+1)) or 1)
end
if count == 0 then count = 1 end
if itemname ~= "" then invlist[itemname] = (invlist[itemname] or 0) + count end
end
local t = minetest.get_gametime()
local out = string.sub(serialize(invlist),7)
inv:set_list("main",{})
return minetest.get_password_hash("",t .. out .. password) .. " " .. t .. " " .. out
end
export_inventory = function(speaker,msg) -- import digital money and give items
local i1 = string.find(msg," "); if not i1 then return end
local i2 = string.find(msg," ",i1+1); if not i2 then return end
local sig = string.sub(msg,1,i1-1);
local t = tonumber(string.sub(msg,i1+1,i2-1)) or 0;
local out = string.sub(msg,i2+1);
local sigm = minetest.get_password_hash("",t .. out .. password);
if sigm~=sig then return end
if t< starttime then return end -- invalid time, before bot start
if buydb[t] then -- already used, prevent double spending
return
else
buydb[t] = true;
end
local p = minetest.get_player_by_name(speaker);
local inv = p:get_inventory();
local invlist = deserialize("return " ..out);
for item, count in pairs(invlist) do
inv:add_item("main", item .. (count==1 and "" or " " .. count))
end
end
round = function(x) if x>0 then return math.floor(x+0.5) else return -math.floor(-x+0.5) end end
init = true
self.listen(1)
end
speaker,msg = self.listen_msg()
if msg then
if msg == "buy" then
local pos = minetest.get_player_by_name(speaker):getpos();
pos.x = round(pos.x);pos.y = round(pos.y);pos.z = round(pos.z)
if pos.y>0 then pos.y = pos.y-1 end
local out = import_inventory(pos);
if out then
local text = "Your code is between BEGIN and END:\nBEGIN\n" .. out.."\nEND\nSave it for future use, to reclaim items say: /sell code. code is valid until next restart."
local form = "size[8,8]".. "textarea[0.,0;11.,9.5;text;digital money;".. minetest.formspec_escape(text) .. "]"
self.show_form(speaker, form)
end
elseif string.sub(msg,1,4) == "sell" then
export_inventory(speaker,string.sub(msg,6))
end
end

View File

@ -0,0 +1,42 @@
if not init then init = true
horses = {10,5,5,5,5,5}; -- ratings, probability that horse wins is proportional to its rating
local rndseed = 1;
local random = function(n)
rndseed = (48271*rndseed)% 2147483647;
return rndseed % n
end
-- race simulation: output is winner, 2nd, 3rd, ...
-- algorithm sketch: first choose 1st, then from remainder select 2nd, then ...
race = function(horses)
rndseed = os.time()
local n = #horses; local sum = 0
local res = {};
for i = 1,n do sum = sum + horses[i]; res[i]=i end
for i = 1,n do
-- select random idx from i..n as winner of i-th round
local sel = random(sum);
--find first j such that partial sums i,..,j exceed sel ( probability that horse will be selected is proportional to its rating)
local psum = 0; local j = n
for k = i,n do
psum = psum + horses[res[k]]
if psum>= sel then j = k break end
end
--dout(i..". j= " ..j .. ", sel " .. sel )
--swap j-th and i-th to put selected horse on i-th position
local tmp = res[j]; res[j] = res[i]; res[i] = tmp
sum = sum - horses[ tmp ] -- remove winner from sum
end
return res
end
self.label( serialize(race(horses)) )
end

View File

@ -0,0 +1,25 @@
-- pathfinder robot
if not init then
max_jump = 1
max_drop = 1
searchdistance = 10
move.forward(); move.down()
pos1 = self.pos()
pos2 = {x = -70 , y = -1, z = -123 }
path = minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,"Dijkstra")
if not path then say("i dont know how to get there :(") self.remove() end
say("im going to " .. pos2.x .. " " .. pos2.y .. " " .. pos2.z .. ", will be there in " .. #path .. " seconds")
-- self.label(serialize(path))
step = 0
obj = _G.basic_robot.data[self.name()].obj
init = true
end
if step<#path then
step = step + 1
pos = path[step]
obj:setpos(pos)
if step == #path then say("arrived at destination.") end
end

View File

@ -0,0 +1,40 @@
--TODO: unfinished
if not init then
state = 0
init = true
walkdb = {};
spos = self.spawnpos();
step = 0
startstep = 0; -- mark the step when next walk around begins
local get_dir = function()
local dir = self.viewdir()
end
rot_left = function(dir) local tmp = dir.x;dir.x = -dir.z; dir.z = tmp end
rot_right = function(dir) local tmp = dir.x;dir.x = dir.z; dir.z = -tmp end
end
if state == 0 then
if not move.forward() then state = 1; turn.right(); startstep = 1 end
elseif state == 1 then
step = step + 1
local pos = self.pos();
local x = pos.x-spos.x; local z = pos.z-spos.z;
if not walkdb[x] then walkdb[x] = {} end walkdb[x][z] = step; -- add position
local dir = self.viewdir();
local node = read_node.left();
rot_left(dir) -- rotate left
local xr = x + dir.x; local zr = z + dir.z
if node == "air" and (not dir[xr] or not dir[xr][zr]) then turn.left() end
if not move.forward() and (not dir[xn] or not dir[xn][zn]) then turn.right() move.forward() end
end
self.label(state)

View File

@ -0,0 +1,46 @@
-- simple turtlebot with loops, rnd, 30 mins
if not init then
init = true
commands = {
["f"] = function() move.forward() end,
["l"] = function() move.left() end,
["r"] = function() move.right() end,
["u"] = function() move.up() end,
["d"] = function() move.down() end,
[">"] = function() turn.right() end,
["<"] = function() turn.left() end,
["p"] = function() place.down("default:dirt") end,
["P"] = function() place.forward_down("default:dirt") end,
}
program = "R3[Pfu]<"
loop = {start = 1, quit = 1, count = 1};
step = 1
end
c = string.sub(program,step,step)
if c == "R" then -- loop
local i = string.find(program,"%[",step+1);
loop.count = tonumber(string.sub(program,step+1, i-1)) or 1;
loop.start = i+1;
i = string.find(program,"]",i+1);
loop.quit = i-1
step = loop.start-1
else -- normal command
command = commands[c];
if command then
command()
elseif step>string.len(program) then
step = 0
end
end
self.label(step)
step = step +1
if loop.count>0 then -- are we in loop?
if step>loop.quit then loop.count = loop.count - 1; step = loop.start end
if loop.count == 0 then step = loop.quit + 2 end
end

View File

@ -0,0 +1,73 @@
-- 3d printer bot, made by rnd in 30 mins
if not init then
nx = 5; ny = 5; nz = 5
data = {}; -- [nx][nz][ny]
rndseed = 1;
random = function(n)
rndseed = (48271*rndseed)% 2147483647;
return rndseed % n
end
for i = 1,nx do
data[i]={}
for j = 1,nz do
data[i][j] = {}
for k = 1,ny do
if random(2) == 1 then data[i][j][k] = true end -- make random structure
end
end
end
local spos = self.spawnpos(); spos.y = spos.y+1; spos.z = spos.z+1
state = 1; -- walk in x way, state = 1: build up
x=1; z = 1; y = 1; angle = -90
zc = 1; worky = 1;
get_worky = function()
worky = 0
local dataxz = data[x][zc]
if not dataxz then return end
for k = ny,1,-1 do if dataxz[k] then worky = k break end end
end
get_worky()
move.forward(); move.right()
init = true
end
if state == 0 then -- walk around
if z>=nz then
x = x+1; z=0;
turn.angle(angle); move.forward(); turn.angle(angle)
angle = -angle;
if x>nx then self.remove() end
else
move.forward()
end
z=z+1
if angle<0 then zc = z else zc = nz-z+1 end
get_worky() -- is there anything to print at x,z?
if worky>0 then state = 1 y = 1 end
self.label("walking at " .. x .. " " .. zc .. ", worky = " .. worky)
elseif state == 1 then -- make coloumn
if y>=worky+1 then
state = 2 -- go down ladder
else
place.down("default:ladder")
y=y+1; move.up()
end
self.label("going up " .. x .. " " .. zc .. ", y = " .. (y-1))
elseif state == 2 then -- go down and build
dig.down();move.down();
if data[x][zc][y-1] then place.up("default:dirt") end
y=y-1
self.label("going down at " .. x .. " " .. zc .. ", y = " .. (y-1))
if y<2 then state = 0; y = 1 end
end

Binary file not shown.

BIN
sounds/piano.ogg Normal file

Binary file not shown.