1
0

feat: initial commit

This commit is contained in:
Rokas Puzonas 2022-06-10 17:06:30 +03:00
commit 869f10fa52
4 changed files with 343 additions and 0 deletions

6
.luarc.json Normal file
View File

@ -0,0 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
"Lua.diagnostics.globals": [
"turtle"
]
}

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# qturle - Quick turtle
A utility library for dealing with turtles in ComputerCraft.

186
craft.lua Normal file
View File

@ -0,0 +1,186 @@
assert(turtle, "The quickturtle library is for turtles only")
local expect = require("cc.expect")
local crafting_grid = {1, 2, 3, 5, 6, 7, 9, 10, 11}
local non_crafting_grid = {4, 8, 12, 13, 14, 15, 16}
local function countAllItems()
local itemCounts = {}
for i=1, 16 do
local detail = turtle.getItemDetail(i)
if detail then
itemCounts[detail.name] = itemCounts[detail.name] or 0
itemCounts[detail.name] = itemCounts[detail.name] + detail.count
end
end
return itemCounts
end
local function calculcateMaxCraftsAmount(storedItems, minRequiredItems)
local amount = 64
for name, minAmount in pairs(minRequiredItems) do
amount = math.min(amount, math.floor((storedItems[name] or 0) / minAmount))
end
return math.max(amount, 1)
end
local function transferToAnySlot(from_slot, available_slots, target_left_amount)
target_left_amount = target_left_amount or 0
turtle.select(from_slot)
for _, to_slot in pairs(available_slots) do
turtle.transferTo(to_slot, turtle.getItemCount(from_slot) - target_left_amount)
if turtle.getItemCount(from_slot) == target_left_amount then break end
end
end
local function countItems(items)
local count = {}
for _, name in pairs(items) do
count[name] = (count[name] or 0) + 1
end
return count
end
local function dropUnneededItems(slot, stored_items, needed_items)
-- If there are no items in this slot, do nothing
local detail = turtle.getItemDetail(slot)
if not detail then return end
-- Check how many items are unneeded
-- If there are enough items, do nothing
local name = detail.name
local unneeded = stored_items[name] - needed_items[name]
if unneeded <= 0 then return end
-- Drop the unneeded amount and update stored items table
turtle.select(slot)
stored_items[name] = stored_items[name] - math.min(unneeded, turtle.getItemCount())
turtle.drop(unneeded)
end
local function getItemName(slot)
local detail = turtle.getItemDetail(slot)
return detail and detail.name
end
local function craft(recipe, craft_amount)
if not turtle.craft then
return false, "crafting table not found"
end
if craft_amount ~= nil then
expect.expect(craft_amount, "number", "nil")
craft_amount = math.floor(craft_amount)
expect.range(craft_amount, 1, 64)
end
local min_required_items = countItems(recipe)
local stored_items = countAllItems()
local needed_items
-- Ensure that there are enough items before doing anything
do
-- If amount was not given, calculate how many items can be crafted
if not craft_amount then
craft_amount = calculcateMaxCraftsAmount(stored_items, min_required_items)
end
-- Calculate the needed amounts of each item
needed_items = {}
for name, min_amount in pairs(min_required_items) do
needed_items[name] = min_amount * craft_amount
end
-- Check if there are enough items for crafting the amount of items wanted
for name, needed_amount in pairs(needed_items) do
local missing_amount = needed_amount - (stored_items[name] or 0)
if missing_amount > 0 then
return false, ("not enough %s, missing %s"):format(name, missing_amount)
end
end
end
-- Remove every item that is not going to be used up in the recipe
do
-- 1. First prioritize removing items from non crafting slots
for _, slot in ipairs(non_crafting_grid) do
dropUnneededItems(slot, stored_items, needed_items)
end
-- 2. If there are still items that need to be removed remove them from crafting slots
for _, slot in ipairs(crafting_grid) do
dropUnneededItems(slot, stored_items, needed_items)
end
end
-- Rearrange items into their correct slots
for i, slot in pairs(crafting_grid) do
local recipe_item = recipe[i]
-- If the slot is supposed to be empty, remove move all items to
-- a temporary slot
if not recipe_item then
if turtle.getItemCount(slot) > 0 then
transferToAnySlot(slot, non_crafting_grid)
end
else
-- Place item in temporary slot if it's name does not match
local current_item = getItemName(slot)
if current_item and current_item ~= recipe_item then
transferToAnySlot(slot, non_crafting_grid)
end
-- If current slot is empty or not full, find items from other slots
-- First grab items from temporary slots
if turtle.getItemCount(slot) < craft_amount then
for _, search_slot in pairs(non_crafting_grid) do
if getItemName(search_slot) == recipe_item then
local missing_amount = craft_amount - turtle.getItemCount(slot)
turtle.select(search_slot)
turtle.transferTo(slot, missing_amount)
-- If there are enough items, search can be stopped
if turtle.getItemCount(slot) == craft_amount then break end
end
end
end
-- If current slot is empty or not full, find items from other slots
-- Then grab items from other crafting grid slots
if turtle.getItemCount(slot) < craft_amount then
for j, search_slot in pairs(crafting_grid) do
local slot_item_name = getItemName(search_slot)
if slot_item_name == recipe_item then
local missing_amount = craft_amount - turtle.getItemCount(slot)
-- Determine how many items can be taken from this slot
-- 1. If the item present in this slot is correct with the recipe
-- Only take as many items that are extra in that slot
-- 2. If the item present in this slot is not correct with the recipe
-- Take as much as you need
local transfer_amount
if recipe[j] ~= slot_item_name then
transfer_amount = missing_amount
else
local extra_amount = turtle.getItemCount(search_slot) - craft_amount
transfer_amount = math.min(missing_amount, extra_amount)
end
if transfer_amount > 0 then
turtle.select(search_slot)
turtle.transferTo(slot, transfer_amount)
-- If there are enough items, search can be stopped
if turtle.getItemCount(slot) == craft_amount then break end
end
end
end
end
end
end
-- Try crafting
-- return turtle.craft(craft_amount)
end
return craft

148
init.lua Normal file
View File

@ -0,0 +1,148 @@
assert(turtle, "The quickturtle library is for turtles only")
local qturtle = {}
local craftingGrid = {1, 2, 3, 5, 6, 7, 9, 10, 11}
-- Can pass a 'n' paramter, to tell that it to repeat that action
-- if 'n' is negative it will execute the opposite of that function
local function createRepeatableFunction(positiveFunc, negativeFunc)
return function(n)
local func = positiveFunc
n = n or 1
if n < 0 and negativeFunc then
func = negativeFunc
n = -n
end
for i=1, n do
if func() == false then
return false, i-1
end
end
return true
end
end
-- Mines in one place forever until there is not block there
local function createEnhancedDig(digFunc)
return function(force)
if force then
while digFunc() do end
else
return digFunc()
end
end
end
-- If an item name is given, it will find it and place it
local function createEnhancedPlace(placeFunc)
return function(itemName)
if itemName and not qturtle.findAndSelectItem(itemName) then
return false, "Item not found"
end
return placeFunc()
end
end
function qturtle.turnAround()
turtle.turnLeft()
turtle.turnLeft()
end
function qturtle.findItem(itemName)
for i=1, 16 do
local detail = turtle.getItemDetail(i)
if detail and detail.name == itemName then
return i
end
end
end
function qturtle.findAndSelectItem(itemName)
local selectedDetail = turtle.getItemDetail()
if selectedDetail and selectedDetail.name == itemName then
return true
end
local slot = qturtle.findItem(itemName)
if not slot then return false end
turtle.select(slot)
return true
end
function qturtle.findEmptySlot()
for i=1, 16 do
if turtle.getItemCount(i) == 0 then
return i
end
end
end
function qturtle.doItemsMatch(slot1, slot2)
local detail1 = turtle.getItemDetail(slot1)
local detail2 = turtle.getItemDetail(slot2)
return (not detail1 and not detail2) or (detail1 and detail2 and detail1.name == detail2.name)
end
function qturtle.stackItems()
for i=1, 15 do
local spaceLeft = turtle.getItemSpace(i)
if spaceLeft > 0 and turtle.getItemDetail(i) then
for j=i+1, 16 do
if qturtle.doItemsMatch(i, j) then
spaceLeft = spaceLeft - turtle.getItemCount()
turtle.select(j)
turtle.transferTo(i)
if spaceLeft <= 0 then break end
end
end
end
end
end
function qturtle.createRecipe()
local recipe = { }
for i, slot in ipairs(craftingGrid) do
local detail = turtle.getItemDetail(slot)
if detail then
recipe[i] = detail.name
end
end
return recipe
end
qturtle.turnLeft = createRepeatableFunction(turtle.turnLeft, turtle.turnRight)
qturtle.turnRight = createRepeatableFunction(turtle.turnRight, turtle.turnLeft)
qturtle.forward = createRepeatableFunction(turtle.forward, turtle.back)
qturtle.back = createRepeatableFunction(turtle.back, turtle.forward)
qturtle.dig = createEnhancedDig(turtle.dig)
qturtle.digUp = createEnhancedDig(turtle.digUp)
qturtle.digDown = createEnhancedDig(turtle.digDown)
qturtle.place = createEnhancedPlace(turtle.place)
qturtle.placeUp = createEnhancedPlace(turtle.placeUp)
qturtle.placeDown = createEnhancedPlace(turtle.placeDown)
qturtle.craftRecipe = require("craft")
function qturtle.goDig()
qturtle.dig(true)
turtle.forward()
end
function qturtle.goDigDown()
qturtle.dig(true)
turtle.down()
end
function qturtle.goDigUp()
qturtle.digUp(true)
turtle.up()
end
return qturtle