Advertisement
Gallent

Crafty

Mar 19th, 2025 (edited)
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.07 KB | None | 0 0
  1. -- Current plan:
  2. -- Create somewhere the bot can access the network. (supply)
  3. -- Give it another inventory it can move things into, and from there suck into the turtle
  4.  
  5. -- Have loop using the parallel api.
  6. -- Make it listen for chat. Format of "crafty <routine> <amount> <return to current>"
  7. -- "crafty stop" should make the bot immediately cease the program and, if possible, return to base station or wherever it started.
  8.  
  9. -- first argument should accept stuff like fleshAuto, sourceGems, essence, etc.
  10. -- instead of running the actual files, these will set the the information that the computer has to use.
  11. -- Namely, target (the type of device to use), materials (a table of possible materials), and results
  12. -- If the last argument is true, then save the current location as tempHome.
  13. -- teleport to the access point, read through the network until you find the correct item id, move it to the other inventory in slot 1, then suck into turtle
  14. -- teleport to correct point ("imbuer" for source gems, "basin" for leather, etc), then execute normal program
  15.  
  16. -- when done or stopped, check if that last argument was true. If not, return to the access point, deposit the result, send message to me, then either remain there or return to a default
  17. -- if true, then check how much fuel it takes to return. If it's too expensive, still return to base point and deposit the result
  18. -- otherwise, if argument is true and if there is enough fuel to return to starting location, do so
  19.  
  20.  
  21. -- Possibly set up "crafty echo"/"crafty say" program so that I can make crafty speak.
  22. -- preprogrammed responses? "Hey Crafty, say hello" could make crafty send a message to the whole server like "Hello, I'm Crafty! Ivy's autocrafting bot! Pleased to meet you all!"
  23. -- table of responses to the phrase "Hello Crafty" based on each user.
  24.  
  25.  
  26. local programTable
  27. programTable = {
  28.     sourceGems={
  29.         target="ars_nouveau:imbuement_chamber",
  30.         materials = {
  31.             --insert valid ingredients here
  32.             ["minecraft:amethyst_shard"]=true,
  33.             ["minecraft:lapis_lazuli"]=true
  34.         },
  35.         results = {
  36.             --Insert desired results here
  37.             ["ars_nouveau:source_gem"] = true
  38.         },
  39.         location="imbuer"
  40.     },
  41.     fleshAuto = {
  42.         target="integrateddynamics:drying_basin",
  43.         materials = {
  44.             --insert valid ingredients here
  45.             ["minecraft:rotten_flesh"]=true
  46.         },
  47.         results = {
  48.             ["minecraft:leather"]=true
  49.         },
  50.         location="basin"
  51.     }
  52. }
  53.  
  54. local storageNames={
  55.     drawers="functionalstorage:storage_controller_0",
  56.     chests="sophisticatedstorage:controller_0"
  57. }
  58.  
  59. local storageModems={}
  60.  
  61. local function storageSync() for k,v in storageNames do storageModems[k]=peripheral.wrap(v) end end
  62.  
  63. local queue={}
  64. local stopped=false
  65. local suck,drop
  66.  
  67. local fuelList = {
  68.     ["minecraft:charcoal"]=80,
  69.     ["minecraft:coal"]=80,
  70.     ["modern_industrialization:lignite_coal"]=80
  71. }
  72.  
  73. local chatBox = peripheral.find("chatBox")
  74. local automata = peripheral.find("endAutomata")
  75.  
  76. local sideSearch = {
  77.     front=function()
  78.         suck = turtle.suck()
  79.         drop = turtle.drop()
  80.         return true
  81.     end,
  82.     left=function()
  83.         turtle.turnLeft()
  84.         suck = turtle.suck()
  85.         drop = turtle.drop()
  86.     return true end,
  87.     right=function()
  88.         turtle.turnRight()
  89.         suck = turtle.suck()
  90.         drop = turtle.drop()
  91.     return true end,
  92.     back=function ()
  93.         turtle.turnLeft()
  94.         turtle.turnLeft()
  95.         suck = turtle.suck()
  96.         drop = turtle.drop()
  97.         return true
  98.     end,
  99.     top=function ()
  100.         suck=turtle.suckUp
  101.         drop=turtle.dropUp
  102.     end,
  103.     bottom=function ()
  104.         suck=turtle.suckDown
  105.         drop=turtle.dropDown
  106.     end
  107. }
  108.  
  109. local function warpFuel(location)
  110.     local targetNumber = automata.estimateWarpCost(location) - turtle.getFuelLevel()
  111.     if targetNumber <= 0 then return true end
  112.     local solution={}
  113.  
  114.     for k,v in pairs(fuelList) do
  115.         if targetNumber <= 0 then break end
  116.         for i=16,1,-1 do
  117.             if turtle.getItemDetail(i) ~= nil and k == turtle.getItemDetail(i).name then
  118.                 if turtle.getItemDetail(i).count * v >= targetNumber then
  119.                     solution[#solution+1] = {i,math.ceil(targetNumber/v)}
  120.                     targetNumber=0
  121.                     break
  122.                 else
  123.                     solution[#solution+1] = {i,turtle.getItemDetail(i).count}
  124.                     targetNumber = targetNumber - (turtle.getItemDetail(i).count*v)
  125.                 end
  126.             end
  127.         end
  128.     end
  129.    
  130.     if targetNumber > 0 then return false
  131.     else
  132.         for k,v in pairs(solution) do
  133.             turtle.select(v[1])
  134.             turtle.refuel(v[2])
  135.         end
  136.         return true
  137.     end
  138. end
  139.  
  140. local function refuelFromStorage(targetNum)
  141.     local targetNumber = targetNum - turtle.getFuelLevel()
  142.     local solution={}
  143.     for fuel,fuelVal in pairs(fuelList) do
  144.         if targetNumber <= 0 then break end
  145.         for _,modem in pairs(storageModems) do
  146.             if targetNumber <= 0 then break end
  147.             for slot,item in pairs(modem.list()) do
  148.                
  149.                 if item.name == fuel then
  150.                     if item.count*fuelVal >= targetNumber then
  151.                         targetNumber=0
  152.                         solution[#solution+1] = {modem,slot, math.ceil(targetNumber/fuelVal)}
  153.                         break
  154.                     else
  155.                         targetNumber=targetNumber-(item.count*fuelVal)
  156.                         solution[#solution+1] = {modem,slot, item.count}
  157.                     end
  158.                 end
  159.  
  160.             end
  161.         end
  162.     end
  163.  
  164.     if targetNumber<=0 then
  165.         local chest = peripheral.wrap("bottom")
  166.         --move items to chest to be put into turtle
  167.         for _,v in pairs(solution) do
  168.             v[1].pushItems("bottom",v[2],v[3])
  169.         end
  170.  
  171.         for i=16,1,-1 do
  172.             if turtle.getItemDetail(i) == nil then turtle.select(i) break end
  173.         end
  174.  
  175.         for k,v in pairs(bottom.list()) do
  176.             bottom.pushItems("bottom",k,nil,1)
  177.             turtle.suck()
  178.             turtle.refuel()
  179.         end
  180.         return true
  181.     else
  182.         return false
  183.     end
  184. end
  185.  
  186. local function warp(location)
  187.     local function tryWarp(destination)
  188.         local success = automata.warpToPoint(destination)
  189.  
  190.         if not success then
  191.             local nearestPoint
  192.  
  193.             for _,v in pairs(automata.points()) do
  194.                 if nearestPoint == nil or automata.distanceToPoint(v)<automata.distanceToPoint(nearestPoint) then nearestPoint=v end
  195.             end
  196.             chatBox.sendFormattedMessageToPlayer(textutils.serialiseJSON({
  197.                 {text="I'm sorry, but something went wrong when trying to warp! I'm closest to "},
  198.                 {text=nearestPoint,color="gold"},
  199.                 {", though. Please come pick me up!"}
  200.             }), "Gallent_Bristle", "Crafty")
  201.             return false
  202.         else return true
  203.         end
  204.     end
  205.  
  206.  
  207.     if automata.estimateWarpCost(location) >= turtle.getFuelLevel() or warpFuel(location) then
  208.         return tryWarp(location)
  209.     elseif automata.estimateWarpCost("supply") >= turtle.getFuelLevel()  or warpFuel("supply") then
  210.         chatBox.sendFormattedMessageToPlayer(textutils.serialiseJSON({
  211.             {text="Have to refuel before I can get to "},
  212.             {text=location,color="gold"},
  213.             {text=", but I'll be right there!"}
  214.         }),"Gallent_Bristle", "Crafty")
  215.         if not tryWarp("supply") then
  216.             return false
  217.         end
  218.        
  219.         if refuelFromStorage(automata.estimateWarpCost(location)) then
  220.             if refuelFromStorage(automata.estimateWarpCost(location)*2)then
  221.                 chatBox.sendMessageToPlayer("Alright, all fueled up and ready to go!", "Gallent_Bristle", "Crafty")
  222.             else
  223.                 chatBox.sendMessageToPlayer("We don't have enough fuel for a return trip. Should I make the jump?", "Gallent_Bristle", "Crafty")
  224.                 local jumping = true
  225.  
  226.                 parallel.waitForAny(
  227.                     function()
  228.                         while true do
  229.                             local _, username, message, uuid, isHidden = os.pullEvent("chat")
  230.  
  231.                             if isHidden and uuid == "58b2110a-ceb4-4781-9359-1a764ac57edc" then
  232.                                 lowerString = string.lower(message)
  233.                                 if lowerString:find("deny") == 1 or lowerString:find("crafty deny") == 1
  234.                                 or lowerString:find("no") == 1 or lowerString:find("crafty no") == 1
  235.                                 or lowerString:find("cancel") == 1 then
  236.  
  237.                                     jumping = false
  238.                                     chatBox.sendMessageToPlayer("Alright, I'll stay at the base!", "Gallent_Bristle", "Crafty")
  239.                                     break
  240.                                 elseif message:find("confirm") or message:find("yes") then
  241.                                     chatBox.sendMessageToPlayer("Ok, warping now!", "Gallent_Bristle", "Crafty")
  242.                                     break
  243.                                 end
  244.                             end
  245.                         end
  246.                     end,
  247.                     function ()
  248.                         sleep(60)
  249.                         chatBox.sendMessageToPlayer("I didn't get a response, should I warp?", "Gallent_Bristle", "Crafty")
  250.                         sleep(60)
  251.                         chatBox.sendFormattedMessageToPlayer(textutils.serialiseJSON({
  252.                             {text="I'm going to warp now, but I'll be over by "},
  253.                             {text=location,color="gold"},
  254.                             {text=" so you can pick me up there."}
  255.                         }), "Gallent_Bristle", "Crafty")
  256.                     end
  257.                 )
  258.  
  259.                 if jumping then return tryWarp(location) end
  260.             end
  261.            
  262.         else
  263.             chatBox.sendMessageToPlayer("I'm sorry, we don't have enough fuel to make it to the crafting station! Please bring more and try again.", "Gallent_Bristle", "Crafty")
  264.             return false
  265.         end
  266.     else
  267.         local nearestPoint
  268.  
  269.         for _,v in pairs(automata.points()) do
  270.             if nearestPoint == nil or automata.distanceToPoint(v)<automata.distanceToPoint(nearestPoint) then nearestPoint=v end
  271.         end
  272.  
  273.         chatBox.sendFormattedMessageToPlayer(textutils.serialiseJSON({
  274.             {text="I'm sorry, but I can't warp right now! I don't have enough fuel! I'm closest to "},
  275.             {text=nearestPoint,color="gold"},
  276.             {", though. Please come pick me up, or at least refuel me."}
  277.         }), "Gallent_Bristle", "Crafty")
  278.         return false
  279.     end
  280. end
  281.  
  282.  
  283. local function processMats(args)
  284.     --go to supply area
  285.     if not warp("supply") then return end
  286.  
  287.     local amount
  288.     if args.amount ~= nil then amount = args.amount else amount = 64 end
  289.     local details = programTable[args.name]
  290.  
  291.     --Withdraw materials
  292.     local startingMats={}
  293.     for _,modem in pairs(storageModems) do
  294.         for slot,item in pairs(modem.list()) do
  295.             if details.materials[item.name] then
  296.                 startingMats[#startingMats+1] = {modem,slot,item.count}
  297.             end
  298.         end
  299.     end
  300.     while amount > 0 and next(startingMats) ~= nil do
  301.         local mostItems=1
  302.         for k,v in pairs(startingMats) do
  303.             if v[3] > startingMats[mostItems][3] then mostItems=k end
  304.         end
  305.  
  306.         if startingMats[mostItems][3] >= amount then
  307.             startingMats[mostItems][1].pushItems("bottom", startingMats[mostItems][2], amount)
  308.             amount = 0
  309.             break
  310.         else
  311.             startingMats[mostItems][1].pushItems("bottom",startingMats[mostItems][2])
  312.             amount = amount-startingMats[mostItems][3]
  313.             startingMats[mostItems]=nil
  314.         end
  315.     end
  316.  
  317.     for k,v in pairs(peripheral.wrap("bottom").list()) do
  318.         peripheral.wrap("bottom").pushItems("bottom",k,nil,1)
  319.         for i=1,16 do
  320.             if turtle.getItemDetail(i) == nil or (turtle.getItemDetail(i) ~= nil and turtle.getItemDetail(i).name == v.name) then turtle.select(i) break end
  321.         end
  322.         turtle.suckDown()
  323.     end
  324.  
  325.     -- go to area
  326.     if not warp(details.location) then return end
  327.  
  328.     --find device
  329.     local target = peripheral.find(details.target)
  330.     if target== nil then
  331.         turtle.turnLeft()
  332.         target = peripheral.find(details.target)
  333.         if target == nil then
  334.             chatBox.sendFormattedMessageToPlayer(
  335.                 textutils.serialiseJSON({
  336.                     {text="I'm sorry, I cannot find the block id "},
  337.                     {text=details.target, color="red"},
  338.                     {text=" at this location. Did you move it, perhaps? Be sure to update the point named "},
  339.                     {text=details.location, color="gold"},
  340.                     {text=" when you are able!"}
  341.                 }), "Gallent_Bristle", "Crafty"
  342.             )
  343.             return
  344.         end
  345.     end
  346.     sideSearch[target]()
  347.  
  348.     --start creating items
  349.     local input,output
  350.  
  351.     if details.input ~= nil then input = details.input else input = 1 end
  352.     if details.output ~= nil then output = details.output else output = target.size() end
  353.     local matSlots = {}
  354.     for i=1,16 do
  355.         if turtle.getItemDetail(i) ~= nil and
  356.         (details.materials[turtle.getItemDetail(i).name])
  357.         then
  358.             table.insert(matSlots,i)
  359.         end
  360.     end
  361.    
  362.     local resultCell=0
  363.     local function emptyCheck()
  364.         for i=1,16 do
  365.             if turtle.getItemDetail(i) == nil then
  366.                 if resultCell == 0 then resultCell=i end
  367.             elseif (details.results[turtle.getItemDetail(i).name] and turtle.getItemDetail(i).count < turtle.getItemDetail(i,true).maxCount) then
  368.                 resultCell=i
  369.                 break
  370.             end
  371.         end
  372.         return resultCell
  373.     end
  374.  
  375.     local function makeItem(currentSlot)
  376.         turtle.select(currentSlot)
  377.         emptyCheck()
  378.        
  379.         while true do
  380.             if target.getItemDetail(1) ~= nil and not details.materials[target.getItemDetail(1).name] then
  381.                 turtle.select(resultCell)
  382.                 suck(1)
  383.                 local detail = turtle.getItemDetail(resultCell,true)
  384.                 if not details.results[detail.name] or detail.count==detail.maxCount then emptyCheck() end
  385.                 turtle.select(currentSlot)
  386.             end
  387.            
  388.             if target.getItemDetail(1) == nil then
  389.                 local check = turtle.getItemDetail(currentSlot)
  390.                 if check ~= nil and details.materials[check.name] then drop(1)
  391.                     else break
  392.                 end
  393.             end
  394.         end
  395.     end
  396.      
  397.     for _,v in pairs(matSlots) do
  398.         makeItem(v)
  399.     end
  400.  
  401.     --return and deposit items, or if argument 4 is true, return to tempHome
  402.     if (not args.altReturn) and warp("supply") then
  403.         for i=1,16 do
  404.             if turtle.getItemDetail(i) ~= nil and details.results[turtle.getItemDetail(i)] then
  405.                 turtle.select(i)
  406.                 turtle.dropUp()
  407.             end
  408.         end
  409.     else
  410.         warp("tempHome")
  411.     end
  412.  
  413.  
  414. end
  415.  
  416. parallel.waitForAny(
  417.     function()
  418.     local username, message, uuid, isHidden
  419.    
  420.     while true do
  421.         _, username, message, uuid, isHidden = os.pullEvent("chat")
  422.        
  423.         if isHidden and uuid == "58b2110a-ceb4-4781-9359-1a764ac57edc" then
  424.            
  425.             local args = {}
  426.             for word in message:gmatch("%S+") do args[#args+1] = word end
  427.  
  428.             if args[1]:lower() == "crafty" then
  429.                 if args[2]:lower() == "echo" then
  430.                     local sayThis = message:gsub(args[1].." "..args[2].." ","")
  431.                     chatBox.sendMessageToPlayer(sayThis, username, "Crafty")
  432.                    
  433.                 end
  434.  
  435.                 if args[2]:lower() == "say" then
  436.                     local sayThis = message:gsub(args[1].." "..args[2].." ","")
  437.                     chatBox.sendMessage(sayThis, "Crafty")
  438.                    
  439.                 end
  440.  
  441.                 if args[2]:lower() == "stop" then return end
  442.             end
  443.  
  444.         elseif select(1, message:lower():gsub("[^%w%s]+", "")):find("crafty say hello") and uuid == "58b2110a-ceb4-4781-9359-1a764ac57edc" then
  445.             chatBox.sendMessage("Hello, I'm Crafty! Ivy's new robot meant to assist with many tasks and automation! It's a huge pleasure to meet you all! ^.^", "Crafty")
  446.         end
  447.  
  448.     end end,
  449.     function() while true do
  450.         local tasks = {}
  451.         if next(queue) ~= nil then
  452.             tasks=queue
  453.             queue={}
  454.         end
  455.         if next(tasks) ~= nil then
  456.             for k,v in pairs(tasks) do
  457.                 if v.args ~= nil then v.func(v.args) else v.func() end
  458.             end
  459.         end
  460.         os.sleep(0)
  461.     end end
  462. )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement