diff --git a/inventoryManager.lua b/inventoryManager.lua index a3234e9..7c4200a 100644 --- a/inventoryManager.lua +++ b/inventoryManager.lua @@ -829,6 +829,309 @@ local function drawDashboard() touchZones = pendingZones end +------------------------------------------------- +-- Smelter Dashboard +------------------------------------------------- + +local function drawSmelterDashboard() + if not smelterMon then return end + + local w, h = smelterMon.getSize() + smelterPendingZones = {} + + -- Offscreen buffer + draw = window.create(smelterMon, 1, 1, w, h, false) + draw.setBackgroundColor(colors.black) + draw.clear() + + -- ===== Title bar ===== + monFill(1, colors.purple) + monCenter(1, " ** SMELTER DASHBOARD ** ", colors.white, colors.purple) + + -- ===== Status bar ===== + monFill(2, colors.gray) + local activeCount = 0 + for _, fs in ipairs(cache.furnaceStatus or {}) do + if fs.active then activeCount = activeCount + 1 end + end + local statusStr = string.format(" Furnaces: %d Active: %d", + cache.furnaceCount or 0, activeCount) + monWrite(2, 2, statusStr, colors.white, colors.gray) + + -- Pause/Resume button + local pauseLabel = smeltingPaused and " PAUSED " or " ACTIVE " + local pauseBg = smeltingPaused and colors.red or colors.lime + local pauseFg = smeltingPaused and colors.white or colors.black + monWrite(w - #pauseLabel, 2, pauseLabel, pauseFg, pauseBg) + addSmelterZone(w - #pauseLabel, 2, w - 1, 2, "toggle_pause", nil) + + -- ===== Divider ===== + monFill(3, colors.magenta) + monCenter(3, string.rep("-", math.min(w - 4, 60)), colors.pink, colors.magenta) + + -- ===== 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 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") + + if smelterView == "status" then + -- ===== Furnace Status View ===== + -- Column headers + monFill(5, colors.gray) + local outCol = math.floor(w * 0.40) + local fuelCol = math.floor(w * 0.65) + local statCol = w - 6 + monWrite(2, 5, "#", colors.lightGray, colors.gray) + monWrite(4, 5, "T", colors.lightGray, colors.gray) + monWrite(6, 5, "Input", colors.lightGray, colors.gray) + monWrite(outCol, 5, "Output", colors.lightGray, colors.gray) + monWrite(fuelCol, 5, "Fuel", colors.lightGray, colors.gray) + monWrite(statCol, 5, "State", colors.lightGray, colors.gray) + + -- Furnace rows + local furnaceList = cache.furnaceStatus or {} + local maxRows = h - 8 + if maxRows < 1 then maxRows = 1 end + smelterTotalPages = math.max(1, math.ceil(#furnaceList / 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, #furnaceList) + + local row = 6 + if #furnaceList == 0 then + monFill(7, colors.black) + monCenter(7, "No furnaces found on network", colors.gray, colors.black) + row = 8 + else + for i = startIdx, endIdx do + local fs = furnaceList[i] + local y = row + local rowBg = ((i - startIdx) % 2 == 0) and colors.black or colors.gray + monFill(y, rowBg) + + -- Number + monWrite(2, y, string.format("%d", i), colors.lightBlue, rowBg) + + -- Type abbreviation + local typeAbbr = "F" + local typeColor = colors.orange + if fs.type == "minecraft:smoker" then + typeAbbr = "S" + typeColor = colors.green + elseif fs.type == "minecraft:blast_furnace" then + typeAbbr = "B" + typeColor = colors.cyan + end + monWrite(4, y, typeAbbr, typeColor, rowBg) + + -- Input + if fs.input then + local inName = fs.input.name:gsub("^minecraft:", ""):gsub("_", " ") + local maxIn = outCol - 8 + if #inName > maxIn then inName = inName:sub(1, maxIn - 2) .. ".." end + monWrite(6, y, inName, colors.white, rowBg) + monWrite(outCol - 4, y, "x" .. fs.input.count, colors.yellow, rowBg) + else + monWrite(6, y, "(empty)", colors.lightGray, rowBg) + end + + -- Output + if fs.output then + local outName = fs.output.name:gsub("^minecraft:", ""):gsub("_", " ") + local maxOut = fuelCol - outCol - 5 + if #outName > maxOut then outName = outName:sub(1, maxOut - 2) .. ".." end + monWrite(outCol, y, outName, colors.white, rowBg) + monWrite(fuelCol - 4, y, "x" .. fs.output.count, colors.yellow, rowBg) + else + monWrite(outCol, y, "-", colors.lightGray, rowBg) + end + + -- Fuel + if fs.fuel then + local fuelName = fs.fuel.name:gsub("^minecraft:", ""):gsub("_", " ") + local maxFuel = statCol - fuelCol - 4 + if #fuelName > maxFuel then fuelName = fuelName:sub(1, maxFuel - 2) .. ".." end + monWrite(fuelCol, y, fuelName, colors.white, rowBg) + monWrite(statCol - 4, y, "x" .. fs.fuel.count, colors.yellow, rowBg) + else + monWrite(fuelCol, y, "-", colors.lightGray, rowBg) + end + + -- Status indicator + if smeltingPaused then + monWrite(statCol, y, "PAUSE", colors.red, rowBg) + elseif fs.active then + monWrite(statCol, y, " COOK", colors.lime, rowBg) + elseif fs.input and not fs.fuel then + monWrite(statCol, y, "FUEL?", colors.orange, rowBg) + else + monWrite(statCol, y, " IDLE", colors.lightGray, rowBg) + end + + row = row + 1 + end + end + + -- Fill remaining rows + while row <= h - 2 do + monFill(row, colors.black) + row = row + 1 + end + + else + -- ===== Recipe Manager View ===== + + -- Build sorted recipe list + local recipeList = {} + for inputName, recipe in pairs(SMELTABLE) do + local short = inputName:gsub("^minecraft:", ""):gsub("_", " ") + short = short:sub(1,1):upper() .. short:sub(2) + local resultShort = recipe.result:gsub("^minecraft:", ""):gsub("_", " ") + resultShort = resultShort:sub(1,1):upper() .. resultShort:sub(2) + local types = "" + for _, ft in ipairs(recipe.furnaces) do + if ft == "minecraft:furnace" then types = types .. "F" + elseif ft == "minecraft:smoker" then types = types .. "S" + elseif ft == "minecraft:blast_furnace" then types = types .. "B" + end + end + local enabled = not disabledRecipes[inputName] + local inStorage = 0 + if cache.catalogue[inputName] then + for _, s in ipairs(cache.catalogue[inputName]) do + inStorage = inStorage + s.total + end + end + table.insert(recipeList, { + inputName = inputName, + inputShort = short, + resultShort = resultShort, + types = types, + enabled = enabled, + inStorage = inStorage, + }) + end + table.sort(recipeList, function(a, b) return a.inputShort < b.inputShort end) + + -- Column positions + local arrowCol = math.floor(w * 0.30) + local typeCol = math.floor(w * 0.60) + local stockCol = math.floor(w * 0.72) + local toggleCol = w - 5 + + -- Column headers + monFill(5, colors.gray) + monWrite(2, 5, "Input", colors.lightGray, colors.gray) + monWrite(arrowCol, 5, "Output", colors.lightGray, colors.gray) + monWrite(typeCol, 5, "Type", colors.lightGray, colors.gray) + monWrite(stockCol, 5, "Stock", colors.lightGray, colors.gray) + monWrite(toggleCol, 5, "On?", colors.lightGray, colors.gray) + + -- Bulk action buttons on tab row + local bulkX = w - 22 + bx1, by1, bx2, by2 = drawButton(bulkX, 4, "All On", colors.white, colors.green) + addSmelterZone(bx1, by1, bx2, by2, "enable_all", nil) + bx1, by1, bx2, by2 = drawButton(bx2 + 2, 4, "All Off", colors.white, colors.red) + addSmelterZone(bx1, by1, bx2, by2, "disable_all", nil) + + -- Recipe rows + local maxRows = h - 8 + if maxRows < 1 then maxRows = 1 end + smelterTotalPages = math.max(1, math.ceil(#recipeList / 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, #recipeList) + + local row = 6 + for i = startIdx, endIdx do + local r = recipeList[i] + local y = row + local rowBg = ((i - startIdx) % 2 == 0) and colors.black or colors.gray + monFill(y, rowBg) + + -- Input name + local maxInputLen = arrowCol - 3 + local inputDisplay = r.inputShort + if #inputDisplay > maxInputLen then + inputDisplay = inputDisplay:sub(1, maxInputLen - 2) .. ".." + end + monWrite(2, y, inputDisplay, colors.white, rowBg) + + -- Output + local maxOutLen = typeCol - arrowCol - 2 + local outDisplay = r.resultShort + if #outDisplay > maxOutLen then + outDisplay = outDisplay:sub(1, maxOutLen - 2) .. ".." + end + monWrite(arrowCol, y, outDisplay, colors.lightBlue, rowBg) + + -- Types + monWrite(typeCol, y, r.types, colors.orange, rowBg) + + -- Stock + monWrite(stockCol, y, tostring(r.inStorage), colors.yellow, rowBg) + + -- Toggle button + if r.enabled then + monWrite(toggleCol, y, " ON ", colors.white, colors.green) + else + monWrite(toggleCol, y, " OFF", colors.white, colors.red) + end + addSmelterZone(1, y, w, y, "toggle_recipe", r.inputName) + + row = row + 1 + end + + -- Fill remaining rows + while row <= h - 2 do + monFill(row, colors.black) + row = row + 1 + end + end + + -- ===== Pagination (h - 1) ===== + monFill(h - 1, colors.gray) + local pageStr = string.format("Pg %d/%d", smelterPage, smelterTotalPages) + monCenter(h - 1, pageStr, colors.white, colors.gray) + + if smelterPage > 1 then + monWrite(2, h - 1, " < ", colors.white, colors.lightGray) + addSmelterZone(2, h - 1, 4, h - 1, "page_prev", nil) + end + if smelterPage < smelterTotalPages then + monWrite(w - 3, h - 1, " > ", colors.white, colors.lightGray) + addSmelterZone(w - 3, h - 1, w - 1, h - 1, "page_next", nil) + end + + -- ===== 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 + 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) + + -- Flush to monitor + draw.setVisible(true) + + -- Swap zones + smelterTouchZones = smelterPendingZones +end + ------------------------------------------------- -- Barrel auto-sort -------------------------------------------------