diff --git a/commands.lua b/commands.lua index cff46ab..53b2705 100644 --- a/commands.lua +++ b/commands.lua @@ -825,6 +825,84 @@ basic_robot.commands.craft = function(item, mode, idx,amount, name) return true end + +--pathfinding: find_path, walk_path +basic_robot.commands.find_path = function(name,pos2) + local obj = basic_robot.data[name].obj; + local pos1 = obj:getpos(); + + 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" + end + check_operations(name,6,true) + local data = basic_robot.data[name] + energy = data.menergy or 0; -- machine energy + if energy<1 then + return nil,"1: not enough energy" + end + data.menergy = energy - 1 + --{current pathnode, path} + + --start position is very sensitive, noninteger coordinates do not seem to work + local round = math.floor + pos1.x = pos1.x>0 and round(pos1.x+0.5) or -round(-pos1.x+0.5) + pos1.y = pos1.y>0 and round(pos1.y+0.5) or -round(-pos1.y+0.5) + pos1.z = pos1.z>0 and round(pos1.z+0.5) or -round(-pos1.z+0.5) + + --TODO: tweak parameters, minetest find_path seems sometimes buggy + local path = minetest.find_path(pos1,pos2,10,1,1,"Dijkstra"); -- pos1,pos2, search_distance, max_jump, max_drop + basic_robot.data[name].pathdata = {1,path} + + if path then return #path else return nil end -- return length of found path or nil +end + +basic_robot.commands.walk_path = function(name) + check_operations(name,2,true) + + local pathdata = basic_robot.data[name].pathdata; + if not pathdata then return nil end + local path = pathdata[2]; + if not path then return 0 end + + local idx = pathdata[1]; + if idx > #path then return 0 end -- reached end of path + + local pos2 = path[idx] + local obj = basic_robot.data[name].obj; + local pos1 = obj:getpos(); + + 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 + + --turn in correct direction according to movement + pos1.x = pos2.x-pos1.x; pos1.z = pos2.z-pos1.z + local yaw = 0 + if math.abs(pos1.x)> math.abs(pos1.z) then + if pos1.x>0 then + yaw = 0; + -- {1,0} + else + yaw = math.pi; + -- {-1,0} + end + else + if pos1.z>0 then + -- {0,1} + yaw = math.pi/2 + else + -- {0,-1} + yaw = -math.pi/2 + end + end + yaw = yaw - math.pi/2 + obj:setyaw(yaw); + + pathdata[1] = idx + 1 -- target next node + obj:moveto(pos2, true) + + return #path-idx+1 -- return remaining length of path +end + --FORMS basic_robot.commands.show_form = function(name, playername, form) minetest.show_formspec(playername, "robot_form".. name, form) @@ -1473,14 +1551,4 @@ end function Vplayer:get_eye_offset() end - -- code for act borrowed from: https://github.com/minetest-mods/pipeworks/blob/fa4817136c8d1e62dafd6ab694821cba255b5206/wielder.lua, line 372 - - - - - - - - - - + -- code for act borrowed from: https://github.com/minetest-mods/pipeworks/blob/fa4817136c8d1e62dafd6ab694821cba255b5206/wielder.lua, line 372 \ No newline at end of file diff --git a/init.lua b/init.lua index 826b39b..fccd0ef 100644 --- a/init.lua +++ b/init.lua @@ -217,6 +217,13 @@ function getSandboxEnv (name) return commands.display_text(obj,text,linesize,size) end, + find_path = function(pos) -- compute path + return commands.find_path(name,pos) + end, + + walk_path = function() -- walk to next node of path + return commands.walk_path(name) + end, }, machine = {-- adds technic like functionality to robots: power generation, smelting, grinding, compressing @@ -635,8 +642,6 @@ end -- COMPILATION ---todo: 2018/12 this suddenly stopped working, wtf?? - preprocess_code = function(script, call_limit) -- version 07/24/2018 --[[ idea: in each local a = function (args) ... end insert counter like: @@ -882,7 +887,7 @@ end -local function init_robot(obj) +local function init_robot(obj, resetSandbox) local self = obj:get_luaentity(); local name = self.name; -- robot name @@ -899,7 +904,7 @@ local function init_robot(obj) obj:set_properties({nametag = "[" .. name.."]",nametag_color = "LawnGreen"}); obj:set_armor_groups({fleshy=0}) - initSandbox ( name ) + if resetSandbox then initSandbox ( name ) end end minetest.register_entity("basic_robot:robot",{ @@ -943,7 +948,7 @@ minetest.register_entity("basic_robot:robot",{ self.authlevel = data.authlevel; self.spawnpos = {x=data.spawnpos.x,y=data.spawnpos.y,z=data.spawnpos.z}; - init_robot(self.object); + init_robot(self.object, false); -- do not reset sandbox to keep all variables, just wake up self.running = 1; @@ -1065,7 +1070,7 @@ local spawn_robot = function(pos,node,ttl) local name = owner..id; - if id <= 0 then -- just compile code and run it, no robot spawn + if id <= 0 then -- just compile code and run it, no robot entity spawn local codechange = false; if meta:get_int("codechange") == 1 then meta:set_int("codechange",0); @@ -1074,7 +1079,7 @@ local spawn_robot = function(pos,node,ttl) -- compile code & run it local err; local data = basic_robot.data[name]; - if codechange or (not data) then + if codechange or (not data) then -- reset all, sandbox will change too basic_robot.data[name] = {}; data = basic_robot.data[name]; meta:set_string("infotext",minetest.get_gametime().. " code changed ") data.owner = owner; @@ -1138,10 +1143,10 @@ local spawn_robot = function(pos,node,ttl) return end return - end + end -- end of entityless robot code - -- if robot already exists do nothing + -- if robot entity already exists refresh it if basic_robot.data[name] and basic_robot.data[name].obj then minetest.chat_send_player(owner,"#ROBOT: ".. name .. " already active, removing ") basic_robot.data[name].obj:remove(); @@ -1178,7 +1183,7 @@ local spawn_robot = function(pos,node,ttl) data.spawnpos = {x=pos.x,y=pos.y-1,z=pos.z}; - init_robot(obj); -- set properties, init sandbox + init_robot(obj,true); -- set properties, resetSandbox = true local self = obj:get_luaentity(); local err = setCode( self.name, self.code ); -- compile code @@ -1624,7 +1629,7 @@ minetest.register_on_chat_message( function(name, message) local hidden = false; if string.sub(message,1,1) == "\\" then hidden = true; message = string.sub(message,2) end - local listeners = basic_robot.data.listening; + local listeners = basic_robot.data.listening; -- which robots are listening? for pname,_ in pairs(listeners) do local data = basic_robot.data[pname]; data.listen_msg = message; diff --git a/robogui.lua b/robogui.lua index ba996db..6c236b4 100644 --- a/robogui.lua +++ b/robogui.lua @@ -232,6 +232,10 @@ local help_pages = { " self.label(text) changes robot label", " self.display_text(text,linesize,size) displays text instead of robot face,", " if no size just return texture string", + " self.find_path(pos) attempts to find path to pos (coordinates must be", + " integer). On success return length of path, otherwise nil", + " self.walk_path() attempts to walk path it previously found. On success ", + " returns number of remaining nodes, on fail it returns -next node distance or 0", " self.sound(sample,volume, opt. pos) plays sound named 'sample' at", " robot, location (optional pos)", " rom is aditional table that can store persistent data, like rom.x=1",