sc3-rom-dump/rom/programs/poster.lua

288 lines
7.3 KiB
Lua
Raw Permalink Normal View History

2024-01-15 10:36:50 +01:00
local startTColor = term.getTextColor()
local highlightColor = colors.lightGray
local errColor = colors.gray
local greenColor = colors.white
if term.isColor() then
highlightColor = colors.yellow
errColor = colors.red
greenColor = colors.green
end
local function printUsage()
local programName = arg[0] or fs.getName(shell.getRunningProgram())
term.setTextColor(colors.lightGray)
term.write("Usage: ")
term.setTextColor(colors.white)
print(("%s <file or url> [count] [options?]"):format(programName))
term.setTextColor(colors.gray)
print("Options for .2dja: [ <index> | <from> <to> ]")
term.setTextColor(colors.white)
print(("Type '%s stop' to cancel the print task"):format(programName))
end
-- Find a printer
local printer = peripheral.find("poster_printer")
if not printer then
error("No printer found", 0)
end
-- Validate arguments
local args = { ... }
if #args < 1 or #args > 4
or args[1]:lower() == "help" then
printUsage()
return
end
-- Stop the printer by running `poster stop`
if args[1] == "stop" then
print("Stopping printer...")
printer.stop()
return
end
local status = printer.status()
if status == "busy" then
error("Printer is busy", 0)
end
-- Convert string to number and validate it
local function getNum(str)
local num = tonumber(str)
if not num or math.floor(num) < 1 then
return
end
return math.floor(num)
end
-- Get count
local count = 1
if #args > 1 then
count = getNum(args[2])
if not count then
printUsage()
return
end
end
-- Get index, if given
local index = { all = true, from = nil, to = nil }
if #args >= 3 then
local num1, num2 = getNum(args[3]), getNum(args[4])
if num1 and num2 then
-- Interval
index.from = math.min(num1, num2)
index.to = math.max(num1, num2)
elseif #args > 3 then
-- Second argument is not acceptable
printUsage()
return
elseif num1 then
-- Index, not interval
index.from = num1
index.to = num1
else
-- First argument is not acceptable
printUsage()
return
end
-- Index or interval is given, therefore we do not want to print all pages
index.all = false
end
local filename = args[1]
-- Loads from local file or Url
local function loadPoster(name)
local stream
if http and name:match("^https?://") then
print("Downloading...")
stream = http.get{ url = name, binary = true }
else
print("Loading...")
name = shell.resolve(name)
if not fs.exists(name) then
-- Try to find a .2dj or .2dja file if the extension did not got specified
if not filename:match(".2dj$") or not filename:match(".2dja$") then
local hits = 0
local newName
for _, sEnd in ipairs({".2dj", ".2dja"}) do
local otherName = name..sEnd
if fs.exists(otherName) then
newName = otherName
hits = hits+1
end
end
if hits == 1 then
return loadPoster(newName)
elseif hits > 1 then
error(("File extension for \'%s\' is not specified."):format(name), 0)
end
end
error(("File \'%s\' not found."):format(name), 0)
end
stream = fs.open(name, "r")
end
if not stream then
error(("Could not open \'%s\'"):format(name), 0)
end
local data = stream.readAll()
stream.close()
local data, err = textutils.unserialiseJSON(data)
if type(data) ~= "table" then
error(("\n\nCould not parse \'%s\': %s"):format(name, err), 0)
end
return data
end
-- Check if given poster is valid
local function isValidPoster(data)
if type(data.pixels) ~= "table" then
return true, "Table \'pixels\' does not exist"
elseif type(data.palette) ~= "table" then
return true, "Table \'palette\' does not exist"
end
return false
end
local posters = {}
local data = loadPoster(filename)
-- Add all needed pages to stack (.2dja)
if type(data.pages) == "table" then
if index.all then
index.from = 1
index.to = #data.pages
elseif index.to > #data.pages then
error(("Index out of bounds (got %d, limit: %d)"):format(index.to, #data.pages), 0)
end
for i=index.from, index.to do
local poster = data.pages[i]
local hasError, msg = isValidPoster(poster)
if hasError then
error(("Could not load page %d: \'%s\'"):format(i, msg), 0)
end
table.insert(posters, poster)
end
else
-- Must be a single poster (.2dj)
local hasError, msg = isValidPoster(data)
if hasError then
error(("Could not load .2dj file: \'%s\'"):format(msg), 0)
end
table.insert(posters, data)
end
-- Print a given poster
local function commitPrint(data)
printer.reset()
if data.label then printer.setLabel(data.label) end
if data.tooltip then printer.setTooltip(data.tooltip) end
printer.blitPalette(data.palette)
printer.blitPixels(1, 1, data.pixels)
printer.commit(count)
end
-- Start printing (Finally...)
term.setTextColor(highlightColor)
print("\nHold Ctrl+T to stop\n")
term.setTextColor(colors.lightGray)
print("Now printing:")
local _, ypos = term.getCursorPos()
local width, height = term.getSize()
-- Move everything up for enough space
if ypos > height-3 then
term.scroll(4)
ypos = 15
end
local function printRow(name, value, optional)
term.setTextColor(highlightColor)
term.write(name)
term.setTextColor(colors.white)
term.write(value)
if optional then
term.setTextColor(colors.lightGray)
term.write(optional)
end
end
-- Loop to print all selected posters
local printed = 0
local maxPages = #posters*count
local numDigits = math.floor(math.log10(maxPages))+1
local terminated = false
for i, data in ipairs(posters) do
local currentPage = 0
if terminated then break end
commitPrint(data)
term.setCursorPos(1, ypos)
printRow("Name: ", (data.label or "Untitled"):sub(1, width-6))
term.setCursorPos(1, ypos+1)
printRow("Status: ", (" 0%% : %"..numDigits.."d / %"..numDigits.."d"):format(printed, maxPages), (" (x%d) "):format(count))
local cur, max = printer.getInkLevel()
term.setCursorPos(1, ypos+2)
printRow("Ink: ", ("%3d%% "):format(math.floor(100/max*cur)))
-- Status and Ink level
while true do
local e, p1 = os.pullEventRaw()
if e == "poster_printer_complete" or e == "poster_printer_state" then
local progress = 100-(tonumber(p1) or 0)
if progress >= 100 then
printed = printed+1
currentPage = currentPage+1
end
term.setCursorPos(1, ypos+1)
printRow("Status: ", ("%3d%% : %"..numDigits.."d / %"..numDigits.."d "):format(progress, printed, maxPages), ("(x%d) "):format(count))
if currentPage >= count then
break
end
elseif e == "terminate" then
printer.stop()
terminated = true
break
end
end
end
-- Print results
term.setCursorPos(1, ypos+3)
local plural = (printed ~= 1) and "posters" or "poster"
if terminated then
plural = (printed+1 ~= 1) and "posters" or "poster"
term.setTextColor(errColor)
print(("Printed %d %s out of %d."):format(printed+1, plural, maxPages))
else
term.setTextColor(greenColor)
print(("Printed %d %s!"):format(printed, plural))
end
term.setTextColor(startTColor)