Add crafting functionality to inventoryClient for display of available recipes and crafting status

This commit is contained in:
MayaTheShy
2026-03-16 00:12:39 -04:00
parent 10ec47611b
commit 50d38b86a2

View File

@@ -38,12 +38,15 @@ local activity = {
smelting = false,
defragging = false,
composting = false,
crafting = false,
}
local activeAlerts = {}
local smeltingPaused = false
local disabledRecipes = {}
local SMELTABLE = {} -- populated from master broadcast
local CRAFTABLE = {} -- populated from master broadcast
local craftTurtleOk = false
local connected = false -- true once first state received
-------------------------------------------------
@@ -175,6 +178,67 @@ local function hitTest(x, y)
return nil, nil
end
-------------------------------------------------
-- Crafting helpers (display-only, no peripheral calls)
-------------------------------------------------
local function getRecipeIngredients(recipe)
local ingredients = {}
for _, item in ipairs(recipe.grid) do
if item then
ingredients[item] = (ingredients[item] or 0) + 1
end
end
return ingredients
end
local function canCraftRecipe(recipe)
local ingredients = getRecipeIngredients(recipe)
local itemTotals = {}
for _, item in ipairs(cache.itemList) do
itemTotals[item.name] = item.total
end
for itemName, needed in pairs(ingredients) do
if (itemTotals[itemName] or 0) < needed then return false end
end
return true
end
local function maxCraftBatches(recipe)
local ingredients = getRecipeIngredients(recipe)
local itemTotals = {}
for _, item in ipairs(cache.itemList) do
itemTotals[item.name] = item.total
end
local minBatches = math.huge
for itemName, needed in pairs(ingredients) do
local batches = math.floor((itemTotals[itemName] or 0) / needed)
if batches < minBatches then minBatches = batches end
end
if minBatches == math.huge then return 0 end
return minBatches
end
local function getMissingIngredients(recipe)
local ingredients = getRecipeIngredients(recipe)
local itemTotals = {}
for _, item in ipairs(cache.itemList) do
itemTotals[item.name] = item.total
end
local missing = {}
for itemName, needed in pairs(ingredients) do
local have = itemTotals[itemName] or 0
if have < needed then
table.insert(missing, { name = itemName, have = have, need = needed })
end
end
return missing
end
-------------------------------------------------
-- Touch zone helpers
-------------------------------------------------
local function addSmelterZone(x1, y1, x2, y2, action, data)
table.insert(smelterPendingZones, {
x1 = x1, y1 = y1, x2 = x2, y2 = y2,
@@ -599,14 +663,22 @@ local function drawSmelterDashboard()
-- ===== Tab row =====
monFill(4, colors.black)
local tabStatusBg = smelterView == "status" and colors.purple or colors.gray
local tabRecipesBg = smelterView == "recipes" and colors.purple or colors.gray
local tabStatusBg = smelterView == "status" and colors.purple or colors.gray
local tabSmeltBg = smelterView == "smelt" and colors.purple or colors.gray
local tabCraftBg = smelterView == "craft" and colors.purple or colors.gray
local tabMissingBg = smelterView == "missing" and colors.purple or colors.gray
local bx1, by1, bx2, by2
bx1, by1, bx2, by2 = drawButton(2, 4, "Status", colors.white, tabStatusBg)
addSmelterZone(bx1, by1, bx2, by2, "tab", "status")
bx1, by1, bx2, by2 = drawButton(bx2 + 2, 4, "Recipes", colors.white, tabRecipesBg)
addSmelterZone(bx1, by1, bx2, by2, "tab", "recipes")
bx1, by1, bx2, by2 = drawButton(bx2 + 2, 4, "Smelt", colors.white, tabSmeltBg)
addSmelterZone(bx1, by1, bx2, by2, "tab", "smelt")
bx1, by1, bx2, by2 = drawButton(bx2 + 2, 4, "Craft", colors.white, tabCraftBg)
addSmelterZone(bx1, by1, bx2, by2, "tab", "craft")
bx1, by1, bx2, by2 = drawButton(bx2 + 2, 4, "Missing", colors.white, tabMissingBg)
addSmelterZone(bx1, by1, bx2, by2, "tab", "missing")
if smelterView == "status" then
-- ===== Furnace Status View =====
@@ -705,8 +777,8 @@ local function drawSmelterDashboard()
row = row + 1
end
else
-- ===== Recipe Manager View =====
elseif smelterView == "smelt" then
-- ===== Smelt Recipe Manager View =====
-- Build item totals lookup from itemList
local itemTotals = {}
for _, item in ipairs(cache.itemList) do
@@ -800,6 +872,163 @@ local function drawSmelterDashboard()
row = row + 1
end
while row <= h - 2 do
monFill(row, colors.black)
row = row + 1
end
elseif smelterView == "craft" then
-- ===== Available Crafting Recipes =====
-- Turtle status on tab row
local tLabel = craftTurtleOk and " Turtle OK " or " No Turtle "
local tBg = craftTurtleOk and colors.lime or colors.red
local tFg = craftTurtleOk and colors.black or colors.white
monWrite(w - #tLabel, 4, tLabel, tFg, tBg)
local availList = {}
for idx, recipe in ipairs(CRAFTABLE) do
if canCraftRecipe(recipe) then
local short = recipe.output:gsub("^minecraft:", ""):gsub("_", " ")
short = short:sub(1,1):upper() .. short:sub(2)
local batches = maxCraftBatches(recipe)
table.insert(availList, {
idx = idx,
short = short,
count = recipe.count,
batches = batches,
})
end
end
monFill(5, colors.gray)
local makeCol = w - 6
monWrite(2, 5, "#", colors.lightGray, colors.gray)
monWrite(4, 5, "Output", colors.lightGray, colors.gray)
monWrite(math.floor(w * 0.45), 5, "Yield", colors.lightGray, colors.gray)
monWrite(math.floor(w * 0.60), 5, "Can Make", colors.lightGray, colors.gray)
monWrite(makeCol, 5, "Go", colors.lightGray, colors.gray)
local maxRows = h - 8
if maxRows < 1 then maxRows = 1 end
smelterTotalPages = math.max(1, math.ceil(#availList / maxRows))
if smelterPage > smelterTotalPages then smelterPage = smelterTotalPages end
if smelterPage < 1 then smelterPage = 1 end
local startIdx = (smelterPage - 1) * maxRows + 1
local endIdx = math.min(startIdx + maxRows - 1, #availList)
local row = 6
if #availList == 0 then
monFill(7, colors.black)
monCenter(7, "No recipes available to craft", colors.gray, colors.black)
row = 8
else
for i = startIdx, endIdx do
local r = availList[i]
local y = row
local rowBg = ((i - startIdx) % 2 == 0) and colors.black or colors.gray
monFill(y, rowBg)
monWrite(2, y, string.format("%2d", i), colors.lightBlue, rowBg)
local maxNameLen = math.floor(w * 0.40)
local nameDisplay = r.short
if #nameDisplay > maxNameLen then
nameDisplay = nameDisplay:sub(1, maxNameLen - 2) .. ".."
end
monWrite(4, y, nameDisplay, colors.white, rowBg)
monWrite(math.floor(w * 0.45), y, "x" .. r.count, colors.yellow, rowBg)
monWrite(math.floor(w * 0.60), y,
string.format("x%d", r.batches), colors.lime, rowBg)
if craftTurtleOk then
monWrite(makeCol, y, " MAKE ", colors.white, colors.green)
addSmelterZone(makeCol, y, makeCol + 5, y, "craft", r.idx)
else
monWrite(makeCol, y, " ---- ", colors.gray, colors.black)
end
row = row + 1
end
end
while row <= h - 2 do
monFill(row, colors.black)
row = row + 1
end
elseif smelterView == "missing" then
-- ===== Unavailable Crafting Recipes =====
local missList = {}
for idx, recipe in ipairs(CRAFTABLE) do
if not canCraftRecipe(recipe) then
local short = recipe.output:gsub("^minecraft:", ""):gsub("_", " ")
short = short:sub(1,1):upper() .. short:sub(2)
local missing = getMissingIngredients(recipe)
local parts = {}
for _, m in ipairs(missing) do
local mShort = m.name:gsub("^minecraft:", ""):gsub("_", " ")
table.insert(parts, string.format("%s %d/%d", mShort, m.have, m.need))
end
table.insert(missList, {
idx = idx,
short = short,
count = recipe.count,
summary = table.concat(parts, ", "),
})
end
end
monFill(5, colors.gray)
monWrite(2, 5, "#", colors.lightGray, colors.gray)
monWrite(4, 5, "Output", colors.lightGray, colors.gray)
monWrite(math.floor(w * 0.35), 5, "Missing (have/need)", colors.lightGray, colors.gray)
local maxRows = h - 8
if maxRows < 1 then maxRows = 1 end
smelterTotalPages = math.max(1, math.ceil(#missList / maxRows))
if smelterPage > smelterTotalPages then smelterPage = smelterTotalPages end
if smelterPage < 1 then smelterPage = 1 end
local startIdx = (smelterPage - 1) * maxRows + 1
local endIdx = math.min(startIdx + maxRows - 1, #missList)
local row = 6
if #missList == 0 then
monFill(7, colors.black)
monCenter(7, "All recipes can be crafted!", colors.lime, colors.black)
row = 8
else
for i = startIdx, endIdx do
local r = missList[i]
local y = row
local rowBg = ((i - startIdx) % 2 == 0) and colors.black or colors.gray
monFill(y, rowBg)
monWrite(2, y, string.format("%2d", i), colors.lightBlue, rowBg)
local nameCol = math.floor(w * 0.35) - 5
local nameDisplay = r.short .. " x" .. r.count
if #nameDisplay > nameCol then
nameDisplay = nameDisplay:sub(1, nameCol - 2) .. ".."
end
monWrite(4, y, nameDisplay, colors.white, rowBg)
local missCol = math.floor(w * 0.35)
local missW = w - missCol - 1
local summaryDisplay = r.summary
if #summaryDisplay > missW then
summaryDisplay = summaryDisplay:sub(1, missW - 2) .. ".."
end
monWrite(missCol, y, summaryDisplay, colors.red, rowBg)
row = row + 1
end
end
while row <= h - 2 do
monFill(row, colors.black)
row = row + 1
@@ -822,14 +1051,27 @@ local function drawSmelterDashboard()
-- ===== Bottom accent =====
monFill(h, colors.purple)
local enabledCount = 0
local totalRecipes = 0
for _ in pairs(SMELTABLE) do totalRecipes = totalRecipes + 1 end
for inputName in pairs(SMELTABLE) do
if not disabledRecipes[inputName] then enabledCount = enabledCount + 1 end
local bottomMsg = ""
if smelterView == "status" or smelterView == "smelt" then
local enabledCount = 0
local totalRecipes = 0
for _ in pairs(SMELTABLE) do totalRecipes = totalRecipes + 1 end
for inputName in pairs(SMELTABLE) do
if not disabledRecipes[inputName] then enabledCount = enabledCount + 1 end
end
bottomMsg = string.format(" Smelt: %d/%d enabled ", enabledCount, totalRecipes)
if activity.smelting then bottomMsg = " SMELTING... " end
elseif smelterView == "craft" then
bottomMsg = " Tap MAKE to craft "
if activity.crafting then bottomMsg = " CRAFTING... " end
elseif smelterView == "missing" then
local totalC = #CRAFTABLE
local availC = 0
for _, r in ipairs(CRAFTABLE) do
if canCraftRecipe(r) then availC = availC + 1 end
end
bottomMsg = string.format(" Available: %d/%d recipes ", availC, totalC)
end
local bottomMsg = string.format(" Recipes: %d/%d enabled ", enabledCount, totalRecipes)
if activity.smelting then bottomMsg = " SMELTING... " end
monCenter(h, bottomMsg, colors.pink, colors.purple)
draw.setVisible(true)
@@ -966,6 +1208,15 @@ local function handleSmelterTouch(x, y)
smelterPage = smelterPage + 1
end
smelterNeedsRedraw = true
elseif action == "craft" then
sendToMaster({ type = "craft", recipeIdx = data })
local recipe = CRAFTABLE[data]
if recipe then
local short = recipe.output:gsub("^minecraft:", ""):gsub("_", " ")
print("[CRAFT-UI] Craft request sent: " .. short)
end
smelterNeedsRedraw = true
end
end
@@ -1051,6 +1302,12 @@ local function main()
if message.smeltable then
SMELTABLE = message.smeltable
end
if message.craftable then
CRAFTABLE = message.craftable
end
if message.craftTurtleOk ~= nil then
craftTurtleOk = message.craftTurtleOk
end
if not connected then
connected = true
@@ -1071,6 +1328,18 @@ local function main()
else
print("[WARN] " .. statusMessage)
end
elseif channel == CLIENT_CHANNEL and type(message) == "table" and message.type == "craft_result" then
-- Craft result from master
statusMessage = message.message or ""
statusColor = message.success and colors.lime or colors.red
statusTimer = 5
smelterNeedsRedraw = true
if message.success then
print("[OK] " .. statusMessage)
else
print("[WARN] " .. statusMessage)
end
end
end
end,