diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d163863 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/Howlfile.lua b/Howlfile.lua new file mode 100644 index 0000000..3c3cb8b --- /dev/null +++ b/Howlfile.lua @@ -0,0 +1,26 @@ +Options:Default "trace" + +Tasks:clean() + +Tasks:minify "minify" { + input = "build/radon.lua", + output = "build/radon.min.lua", +} + +Tasks:require "main" { + include = {"components/*.lua", "core/*.lua", "fonts/*.lua", "Krypton/*.lua", "modules/*.lua", "res/*.lua", "util/*.lua", "radon.lua", "profile.lua"}, + startup = "radon.lua", + output = "build/radon.lua", +} + +Tasks:Task "build" { "clean", "minify" } :Description "Main build task" + +--[[Tasks:gist "upload" (function(spec) + spec:summary "A build system for Lua (http://www.computercraft.info/forums2/index.php?/topic/21254- and https://github.com/SquidDev-CC/Howl)" + spec:gist "703e2f46ce68c2ca158673ff0ec4208c" + spec:from "build" { + include = { "Howl.lua", "Howl.min.lua" } + } +end) :Requires { "build/Howl.lua", "build/Howl.min.lua" }]] + +Tasks:Default "main" \ No newline at end of file diff --git a/core/ShopState.lua b/core/ShopState.lua index 2fd04dd..3b0ef05 100644 --- a/core/ShopState.lua +++ b/core/ShopState.lua @@ -167,33 +167,35 @@ parallel.waitForAny(function() while true do local event, transactionEvent = os.pullEvent("transaction") - local transactionCurrency = nil - for _, currency in ipairs(state.currencies) do - if currency.krypton.id == transactionEvent.source then - transactionCurrency = currency - break + if event == "transaction" then + local transactionCurrency = nil + for _, currency in ipairs(state.currencies) do + if currency.krypton.id == transactionEvent.source then + transactionCurrency = currency + break + end end - end - if transactionCurrency then - local transaction = transactionEvent.transaction - local sentName = transaction.sent_name - local sentMetaname = transaction.sent_metaname - local nameSuffix = transactionCurrency.krypton.currency.name_suffix - if sentName and transactionCurrency.name:find(".") then - sentName = sentName .. "." .. nameSuffix - end - if sentName and sentName:lower() == transactionCurrency.name:lower() then - local meta = parseMeta(transaction.metadata) - if sentMetaname then - success, err = pcall(handlePurchase, transaction, meta, sentMetaname, transactionCurrency, transactionCurrency, state) - if success then - -- Success :D + if transactionCurrency then + local transaction = transactionEvent.transaction + local sentName = transaction.sent_name + local sentMetaname = transaction.sent_metaname + local nameSuffix = transactionCurrency.krypton.currency.name_suffix + if sentName and transactionCurrency.name:find(".") then + sentName = sentName .. "." .. nameSuffix + end + if sentName and sentName:lower() == transactionCurrency.name:lower() then + local meta = parseMeta(transaction.metadata) + if sentMetaname then + success, err = pcall(handlePurchase, transaction, meta, sentMetaname, transactionCurrency, transactionCurrency, state) + if success then + -- Success :D + else + refund(transactionCurrency, transaction.from, meta, transaction.value, "An error occurred while processing your purchase!", true) + error(err) + end else - refund(transactionCurrency, transaction.from, meta, transaction.value, "An error occurred while processing your purchase!", true) - error(err) + refund(transactionCurrency, transaction.from, meta, transaction.value, "Must supply a product to purchase!", true) end - else - refund(transactionCurrency, transaction.from, meta, transaction.value, "Must supply a product to purchase!", true) end end end diff --git a/fonts/bigfont.lua b/fonts/bigfont.lua index e91014b..2aabc5b 100644 --- a/fonts/bigfont.lua +++ b/fonts/bigfont.lua @@ -1,7 +1,11 @@ +local base64 = require("modules.base64") local loadRIF = require("modules.rif") local createFont = require("modules.font") -local bigFontSheet = loadRIF("res/cfont.rif") +local cFont = require("res.cfont") +local bigFontData = base64.decode(cFont) + +local bigFontSheet = loadRIF(bigFontData) local bigFont = createFont(bigFontSheet, " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-,.\164!:\6@") return bigFont diff --git a/fonts/smolfont.lua b/fonts/smolfont.lua index 5b07892..4c54d99 100644 --- a/fonts/smolfont.lua +++ b/fonts/smolfont.lua @@ -1,7 +1,11 @@ +local base64 = require("modules.base64") local loadRIF = require("modules.rif") local createFont = require("modules.font") -local smolFontSheet = loadRIF("res/smolfont.rif") +local smolFontEncoded = require("res.smolfont") +local smolFontData = base64.decode(smolFontEncoded) + +local smolFontSheet = loadRIF(smolFontData) local smolFont = createFont(smolFontSheet, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:;<=>?[\\]^_{|}~\128` !\"#$%&'()*+,-./@\164") return smolFont diff --git a/gitget b/gitget deleted file mode 100644 index 7846b5c..0000000 --- a/gitget +++ /dev/null @@ -1,135 +0,0 @@ ---[[ /gitget -GitHub downloading utility for CC. -Developed by apemanzilla. - -This requires ElvishJerricco's JSON parsing API. -Direct link: http://pastebin.com/raw.php?i=4nRg9CHU -]]-- - --- Edit these variables to use preset mode. --- Whether to download the files asynchronously (huge speed benefits, will also retry failed files) --- If false will download the files one by one and use the old output (List each file name as it's downloaded) instead of the progress bar -local async = true - --- Whether to write to the terminal as files are downloaded --- Note that unless checked for this will not affect pre-set start/done code below -local silent = false - -local preset = { - -- The GitHub account name - user = nil, - -- The GitHub repository name - repo = nil, - - -- The branch or commit tree to download (defaults to 'master') - branch = nil, - - -- The local folder to save all the files to (defaults to '/') - path = nil, - - -- Function to run before starting the download - start = function() - if not silent then print("Downloading files from GitHub...") end - end, - - -- Function to run when the download completes - done = function() - if not silent then print("Done") end - end -} - --- Leave the rest of the program alone. -local args = {...} - -args[1] = preset.user or args[1] -args[2] = preset.repo or args[2] -args[3] = preset.branch or args[3] or "master" -args[4] = preset.path or args[4] or "" - -if #args < 2 then - print("Usage:\n"..((shell and shell.getRunningProgram()) or "gitget").." [branch/tree] [path]") error() -end - -local function save(data,file) - local file = shell.resolve(file:gsub("%%20"," ")) - if not (fs.exists(string.sub(file,1,#file - #fs.getName(file))) and fs.isDir(string.sub(file,1,#file - #fs.getName(file)))) then - if fs.exists(string.sub(file,1,#file - #fs.getName(file))) then fs.delete(string.sub(file,1,#file - #fs.getName(file))) end - fs.makeDir(string.sub(file,1,#file - #fs.getName(file))) - end - local f = fs.open(file,"w") - f.write(data) - f.close() -end - -local function download(url, file) - save(http.get(url).readAll(),file) -end - -if not json then - download("http://pastebin.com/raw.php?i=4nRg9CHU","json") - os.loadAPI("json") -end - -preset.start() -local data = json.decode(http.get("https://api.github.com/repos/"..args[1].."/"..args[2].."/git/trees/"..args[3].."?recursive=1").readAll()) -if data.message and data.message:find("API rate limit exceeded") then error("Out of API calls, try again later") end -if data.message and data.message == "Not found" then error("Invalid repository",2) else - for k,v in pairs(data.tree) do - -- Make directories - if v.type == "tree" then - fs.makeDir(fs.combine(args[4],v.path)) - if not hide_progress then - end - end - end - local drawProgress - if async and not silent then - local _, y = term.getCursorPos() - local wide, _ = term.getSize() - term.setCursorPos(1, y) - term.write("[") - term.setCursorPos(wide - 6, y) - term.write("]") - drawProgress = function(done, max) - local value = done / max - term.setCursorPos(2,y) - term.write(("="):rep(math.floor(value * (wide - 8)))) - local percent = math.floor(value * 100) .. "%" - term.setCursorPos(wide - percent:len(),y) - term.write(percent) - end - end - local filecount = 0 - local downloaded = 0 - local paths = {} - local failed = {} - for k,v in pairs(data.tree) do - -- Send all HTTP requests (async) - if v.type == "blob" then - v.path = v.path:gsub("%s","%%20") - local url = "https://raw.github.com/"..args[1].."/"..args[2].."/"..args[3].."/"..v.path,fs.combine(args[4],v.path) - if async then - http.request(url) - paths[url] = fs.combine(args[4],v.path) - filecount = filecount + 1 - else - download(url, fs.combine(args[4], v.path)) - if not silent then print(fs.combine(args[4], v.path)) end - end - end - end - while downloaded < filecount do - local e, a, b = os.pullEvent() - if e == "http_success" then - save(b.readAll(),paths[a]) - downloaded = downloaded + 1 - if not silent then drawProgress(downloaded,filecount) end - elseif e == "http_failure" then - -- Retry in 3 seconds - failed[os.startTimer(3)] = a - elseif e == "timer" and failed[a] then - http.request(failed[a]) - end - end -end -preset.done() \ No newline at end of file diff --git a/modules/base64.lua b/modules/base64.lua new file mode 100644 index 0000000..a8ea243 --- /dev/null +++ b/modules/base64.lua @@ -0,0 +1,197 @@ +--[[ + base64 -- v1.5.3 public domain Lua base64 encoder/decoder + no warranty implied; use at your own risk + Needs bit32.extract function. If not present it's implemented using BitOp + or Lua 5.3 native bit operators. For Lua 5.1 fallbacks to pure Lua + implementation inspired by Rici Lake's post: + http://ricilake.blogspot.co.uk/2007/10/iterating-bits-in-lua.html + author: Ilya Kolbin (iskolbin@gmail.com) + url: github.com/iskolbin/lbase64 + COMPATIBILITY + Lua 5.1+, LuaJIT + LICENSE + See end of file for license information. +--]] + + +local base64 = {} + +local extract = _G.bit32 and _G.bit32.extract -- Lua 5.2/Lua 5.3 in compatibility mode +if not extract then + if _G.bit then -- LuaJIT + local shl, shr, band = _G.bit.lshift, _G.bit.rshift, _G.bit.band + extract = function( v, from, width ) + return band( shr( v, from ), shl( 1, width ) - 1 ) + end + elseif _G._VERSION == "Lua 5.1" then + extract = function( v, from, width ) + local w = 0 + local flag = 2^from + for i = 0, width-1 do + local flag2 = flag + flag + if v % flag2 >= flag then + w = w + 2^i + end + flag = flag2 + end + return w + end + else -- Lua 5.3+ + extract = load[[return function( v, from, width ) + return ( v >> from ) & ((1 << width) - 1) + end]]() + end +end + + +function base64.makeencoder( s62, s63, spad ) + local encoder = {} + for b64code, char in pairs{[0]='A','B','C','D','E','F','G','H','I','J', + 'K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y', + 'Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n', + 'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2', + '3','4','5','6','7','8','9',s62 or '+',s63 or'/',spad or'='} do + encoder[b64code] = char:byte() + end + return encoder +end + +function base64.makedecoder( s62, s63, spad ) + local decoder = {} + for b64code, charcode in pairs( base64.makeencoder( s62, s63, spad )) do + decoder[charcode] = b64code + end + return decoder +end + +local DEFAULT_ENCODER = base64.makeencoder() +local DEFAULT_DECODER = base64.makedecoder() + +local char, concat = string.char, table.concat + +function base64.encode( str, encoder, usecaching ) + encoder = encoder or DEFAULT_ENCODER + local t, k, n = {}, 1, #str + local lastn = n % 3 + local cache = {} + for i = 1, n-lastn, 3 do + if i % 900 == 0 then + os.queueEvent("yieldb64") + os.pullEvent("yieldb64") + end + local a, b, c = str:byte( i, i+2 ) + local v = a*0x10000 + b*0x100 + c + local s + if usecaching then + s = cache[v] + if not s then + s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)]) + cache[v] = s + end + else + s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)]) + end + t[k] = s + k = k + 1 + end + if lastn == 2 then + local a, b = str:byte( n-1, n ) + local v = a*0x10000 + b*0x100 + t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[64]) + elseif lastn == 1 then + local v = str:byte( n )*0x10000 + t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[64], encoder[64]) + end + return concat( t ) +end + +function base64.decode( b64, decoder, usecaching ) + decoder = decoder or DEFAULT_DECODER + local pattern = '[^%w%+%/%=]' + if decoder then + local s62, s63 + for charcode, b64code in pairs( decoder ) do + if b64code == 62 then s62 = charcode + elseif b64code == 63 then s63 = charcode + end + end + pattern = ('[^%%w%%%s%%%s%%=]'):format( char(s62), char(s63) ) + end + b64 = b64:gsub( pattern, '' ) + local cache = usecaching and {} + local t, k = {}, 1 + local n = #b64 + local padding = b64:sub(-2) == '==' and 2 or b64:sub(-1) == '=' and 1 or 0 + for i = 1, padding > 0 and n-4 or n, 4 do + local a, b, c, d = b64:byte( i, i+3 ) + local s + if usecaching then + local v0 = a*0x1000000 + b*0x10000 + c*0x100 + d + s = cache[v0] + if not s then + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d] + s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8)) + cache[v0] = s + end + else + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d] + s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8)) + end + t[k] = s + k = k + 1 + end + if padding == 1 then + local a, b, c = b64:byte( n-3, n-1 ) + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + t[k] = char( extract(v,16,8), extract(v,8,8)) + elseif padding == 2 then + local a, b = b64:byte( n-3, n-2 ) + local v = decoder[a]*0x40000 + decoder[b]*0x1000 + t[k] = char( extract(v,16,8)) + end + return concat( t ) +end + +return base64 + +--[[ +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2018 Ilya Kolbin +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +--]] \ No newline at end of file diff --git a/modules/display.lua b/modules/display.lua index 041faee..eea7d1d 100644 --- a/modules/display.lua +++ b/modules/display.lua @@ -34,7 +34,9 @@ local TextCanvas = canvases.TextCanvas - self.mon = peripheral.wrap(props.peripherals.monitor) + if self.mon then + self.mon = peripheral.wrap(props.monitor) + end if not self.mon then self.mon = peripheral.find("monitor") end diff --git a/modules/rif.lua b/modules/rif.lua index d560b35..3fa9b7d 100644 --- a/modules/rif.lua +++ b/modules/rif.lua @@ -69,12 +69,9 @@ --colors[revPalMap[i]] = 2^(i - 1) end -return function(filename) +return function(data) -- Riko 4 image format - local file = fs.open(filename, "rb") - local data = file.readAll() - local width, height = data:byte(5) * 256 + data:byte(6), data:byte(7) * 256 + data:byte(8) local canv = PixelCanvas(width, height) local buffer = canv.canvas diff --git a/radon.lua b/radon.lua index 8846c93..d0b7c59 100644 --- a/radon.lua +++ b/radon.lua @@ -1,3 +1,6 @@ +local oldPullEvent = os.pullEvent +os.pullEvent = os.pullEventRaw + --- Imports local _ = require("util.score") @@ -34,7 +37,7 @@ error("Output chest is set to self, but no self peripheral name is set") end -local display = Display.new({theme=config.theme}) +local display = Display.new({theme=config.theme, monitor=config.peripherals.monitor}) local function getDisplayedProducts(allProducts, settings) local displayedProducts = {} @@ -340,7 +343,7 @@ local deltaTimer = os.startTimer(0) -ShopRunner.launchShop(shopState, function() +pcall(function() ShopRunner.launchShop(shopState, function() -- Profiler:activate() while true do tree = Solyd.render(tree, Main {t = t, config = config, shopState = shopState}) @@ -357,7 +360,7 @@ local t2 = os.epoch("utc") -- print("Render time: " .. (t2-t1) .. "ms") - local e = { os.pullEventRaw() } + local e = { os.pullEvent() } local name = e[1] if name == "timer" and e[2] == deltaTimer then local clock = os.epoch("utc") @@ -378,17 +381,20 @@ break end elseif name == "terminate" then - display.mon.clear() break end end -- Profiler:deactivate() -end) +end) end) -for i = 1, #config.currencies do - local currency = config.currencies[i] - currency.krypton.ws.disconnect() +display.mon.clear() +for i = 1, #shopState.config.currencies do + local currency = shopState.config.currencies[i] + if (currency.krypton and currency.krypton.ws) then + currency.krypton.ws:disconnect() + end end +os.pullEvent = oldPullEvent print("Radon terminated, goodbye!") -- Profiler:write_results(nil, "profile.txt") diff --git a/res/cfont.lua b/res/cfont.lua new file mode 100644 index 0000000..72b1768 --- /dev/null +++ b/res/cfont.lua @@ -0,0 +1,48 @@ +-- Base 64 encoded font data +return [[UklWAgGkAAoBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAABwAAAAAAAAAHAAAAAAdwAAAAcAAAcAAHBwAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAABw +AAAAAAAAAAAAAAAAAAAAAAAAAHdwB3dwAHdwB3dwB3d3B3d3AHd3BwAHB3cAAHBwAHBwAAcABwcA +BwB3cAd3AAd3AHd3AAd3cHd3cHAAcHAAcHAAcHAAcHAAcHd3cAd3AABwAAd3AAd3AAAHcHd3cAB3 +AHd3cAd3AAd3AAAAcAAAAAAAAAAHAHAHAAAAAAcAAAd3dwAAAAAAAAAAAAAABwAAAAAAAAAHAAAA +AHAAAAAAcAAAAAAABwAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAAA +BwAHBwAHBwAHBwAHBwAABwAABwAABwAHAHAAAHBwBwBwAAdwdwdwBwcABwcAcHAAcHAAcHAAAABw +AHAAcHAAcHAAcAcHAAcHAAAAcHAAcAdwAHAAcHAAcABwcHAAAAcAAHAAcHAAcHAAcAAHAAAAAAAA +AAAHBwAHAAcAAHdwAHcAB3AAAAAAAAAAAHdwBwdwAHdwAHcHAHdwB3dwB3dwcHcAcAAHBwBwcAdw +cAd3cAB3cAcHcAB3BwcHcAB3dwd3BwAHBwAHBwAHBwAHBwAHB3d3B3d3B3dwBwAABwAHB3cAB3cA +BwB3B3d3AHAAAHB3cABwAAcHBwcHBwcABwd3AHAAcHd3AAd3AABwAHAAcHAAcHAAcABwAABwAAAH +AHAHcABwAAAAcAAAcAcAcHd3AHAAAAAAcHAAcHAAcAAHAAAAAAAAAAB3d3AHAAAAB3d3AHAHcHAA +AAAAAAAAAAAHB3AHBwAHBwB3BwAHAHAAcABwdwBwcAAHBwcAcAcHBwcABwcABwdwBwcAdwdwBwcA +AABwBwAHBwAHBwAHAHBwBwAHAABwBwAHBwAHBwAABwAHBwAABwAABwAHBwAHAHAAAHBwBwBwAAcA +BwcAdwcABwcAAHAAcHAAcAAAcABwAHAAcHAAcHAAcAcHAABwAABwAHBwcABwAAB3AAB3AHAAcAAA +cHd3AAAHAAd3AAd3cABwAHd3cAAAAAAHcAAHAAAAd3d3cHBwcHAAAAAAAAAAAHd3BwAHBwAABwAH +B3d3AHAAcABwcABwcAAHB3AAcAcHBwcABwcABwcABwcABwcAAAB3cABwBwAHBwAHBwcHAAcABwAH +AAcABwAHBwAHBwAABwAHBwAABwAABwAHBwAHAHAAAHBwAHBwAAcABwcABwcABwcAAHAAcHAAcAAA +cABwAHAAcAcHAHBwcHAAcABwAAcAAHcAcABwAAcAAAAAcHd3cAAAcHAAcABwAHAAcAAAcAcAAAAA +AAAAAAB3d3AHAAAAdwcHcHB3d3AAAAAAAAAABwAHBwAHBwAHBwAHBwAAAHAAB3dwcABwcHAHBwcA +cAcABwcABwcABwd3cAB3dwcAAAAABwBwBwAHAHBwBwcHAHBwAHd3AHAABwAHBwAHBwAHBwAHBwAA +BwAABwAHBwAHAHAHAHBwAHBwAAcABwcABwcABwcAAHAHAHAAcHAAcABwAHAAcAcHAHcHcHAAcABw +AHAAAHAAcABwAHAAcHAAcAAAcHAAcHAAcABwAHAAcAAHAAcAAAAAAAAAAAAHBwAAAAcAAAcAAHcA +AAAAAAAAAAAAAHd3B3dwAHdwAHd3AHd3AHAAAABwcABwcHAHBwBwBwcABwcABwB3cAcAAAAABwcA +AAd3cAAHAHd3AAcAAHd3BwAHAAAHB3d3BwAHB3dwAHdwB3dwB3d3BwAAAHdwBwAHB3cAdwBwAHB3 +dwcABwcABwB3cAcAAAdwcHAAcAd3AABwAAd3AABwAHAAcHAAcABwAHd3cAd3AHd3cHd3cAd3AAAA +cAd3AAd3AABwAAd3AAdwAHAAAAAAAAcABwAHAHAHAAAAAHdwAAd3dwAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAd3cAAAAAAAdwAAAAAAAAAAAAAAAAAAcAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAA +B3dwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAQAAAQAAAQAAAQAAAQAAEAAAEAAAEBAAA +QAAEAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAQAAAQAAAQAAAQAAAQAAAQAAAQAAAQAAAQAAAQAAA +QAAAQAAAQAAAQAAAQABAAAQAAAQAAEAAAEAAAEAAAEAABAAABAAABAAABAAABAAABAAABAAABAAA +BAAABAAABAAABAAABAAABAAABAAABAAABAAABAAABAAABAAABAAABAAABAAEAAQAAAQABAAEAAAA +BAAAAAQAAAAAAP////////////////////////////////////////////////////////////// +////////f/9///n7Xu////////v/////YziGQTB08bredWMcwyHouq7rgvEexyc4g3H8/v9t/33w +///3//fvv//3/v////+//////991Xdf3fbev7UnWta7r767r1vXr5q67+r3ruvf/X3ePc/7/YzlO +YxjKXmsajuVUDtF1XdcFQdh3cdwE++JeVV3swvHuuu6+3+b+vi3sv657//9gf7Dp//9lXdPtLuvV +Vl2XNVm/Xdet3dt1fdf3Xbev7V3T9a777q7r1vuu7vPsvvAdhzv4n/cDqv7/Q9d3we66Xm7VdV3X +j9t11d3dXdd3fd91+7redV3vuu/u1qq79+zev+Dr7u7b//9gP6Xg/991XdfvoavVdl0XDv233Vqt +w951Xdf3Xbet613X9bbr7m5Nurvv7q77uu7u3v3/X3/f8///QzgOw/66WlvXjf3XhzfcQ/cFXTiG +QT92MbvQdWOfuvEe7667gzEIxm8c73Hu/91t/3jw////////8H/+///ff///////4f////////// +///////////////////////////f////////vu/7vvd9vbfv+77v++77vu/7vu/7vu/77n3v+773 +fd/3fd/3fd/3fd/3fd/3fXff3d/f/w==]] \ No newline at end of file diff --git a/res/smolfont.lua b/res/smolfont.lua new file mode 100644 index 0000000..dddbbe9 --- /dev/null +++ b/res/smolfont.lua @@ -0,0 +1,34 @@ +-- Base 64 encoded font data +return [[UklWAgGkAAcBAAAAAAAAAAAAAAAAcAAAAABwAAAAcAAAcAAHAABwcAB3AAAAAAAAAAAAAAAAAAAA +BwAAAAAAAAAAAAAAAAAHAHcAB3B3AHdwd3AHcHBwd3AAcHBwcABwcHBwBwB3AAcAdwAHcHdwcHBw +cHBwcHBwcHdwB3AHAHcAdwBwcHdwB3B3cHdwd3AAAAAABwAABwAHdwd3AAAHdwBwAAAAdwBwB3AA +dwd3BwAAAAcAcHBwcAdwcAB3AAcAAHBwAHBwAAAAAAAAAAAAcAd3AAcAcAAAAAAAAAAAAAAAAAAA +AHcAdwAHcAdwB3AHAAdwdwAAAAAAcHAHAHdwdwAHAHcAB3AHcAdwd3BwcHBwcHBwcHBwd3BwcHBw +cABwcHAAcABwAHBwBwAAcHBwcAB3cHdwcHBwcHBwcHBwAAcAcHBwcHBwcHBwcABwcHB3AABwAHBw +cHAAcAAAcHBwcHBwAHAAcAd3AHAABwcABwAABwcHAAAAcABwAHAHcAd3AHAAAAcAcHB3cHcAAHB3 +AAcABwAHAAcABwAAAAAAAAAAcHAAcHd3cAAAAAAAAAAAAAAAAAAAAAdwcHBwAHBwcHB3cHBwcHAH +AABwdwAHAHdwcHBwcHBwcHBwAHcABwBwcHBwd3AHAHBwB3B3cHcAcABwcHdwd3B3cHdwBwAAcHcA +cAB3cHdwcHB3AHBwd3AHAAcAcHBwcHdwBwAHAAcAcHAHAAcABwB3cHcAd3AHAHdwd3AAAAAHAAAA +AAcAcAcAAHAABwAAAAAHAAAAAAcAAAd3AAAAAAcAAABwcAdwBwB3cAAABwAHAHBwd3AAAHdwAAAH +AHBwcAdwAAAAAAAAAAAAAAAAAAAAAHBwcHBwAHBwdwAHAHdwcHAHAABwdwAHAHdwcHBwcHBwcHBw +AAdwBwBwcHdwd3AHAAdwdwBwcHBwcABwcHAAcABwcHBwBwBwcHBwcABwcHdwcHBwAHdwdwAAcAcA +cHAHAHdwcHAHAHAAcHAHAHAAAHAAcABwcHBwAHBwAHBwAHAAcAd3AHAAAAcAAAcABwAAAAAAcABw +AHAAAAd3AAAAAAAAAAB3cHcAcABwcAAABwAHAAAABwAHAAAAAABwAHB3cHd3cAAAAAAAAAAAAAAA +AAAAAHdwdwAHcAdwB3AHAABwcHAHAHBwcHB3cHBwcHAHAHcAB3BwAHcAB3AHcAcAd3BwcABwd3Bw +cHcAB3B3AHdwcAAHcHBwd3AHAHBwd3BwcHBwBwBwAAdwcHB3AAcAB3AHAHBwcHAHAHdwdwAHAHdw +dwAAcHcAd3BwAHdwdwAABwAABwAABwAAcAd3AAAHdwAAB3cAdwBwB3AAAAd3AAAAAAcAAABwcAcA +AHAHcAAAAHBwAAAAAABwAAAABwBwAHAAAAcHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcA +AAAAAAcAAAAAAAAAAAAAAHAAAHAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAd3cAcAcAAAAAAAAAAAAAAAAAAAAAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAE +AAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQA +BAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAQABAAEAAQABAAEAAQABAAEAAQABA +AEAAQABAAEAAQAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAABAAABAAAAAAAAAAA +AAAAAAAAAO+/v++9zv///9/////NyYipuOqqzc2JqqqK2cyKiYj/fUd87M/mRH+rpnOv6///xu3/ +///PnJmd/K+N3JyZqKqqqOrq7tqrjqiq6q2qqqu8q+6r6m7sdV/97mbstyIvd3f3/68L/v///6mu +iqq93Kiq6tyq2JrIroiIveyIyordqtjd2t3I2Ih//23v/fffx3+/ZuN3Kz5+q/n///+v6sqN2suN +qqqerYidrOrqrtqqrqiOvK2N2q7tu6uu627s993/7n78/yO7fvd3/7sI/v///8iZ2autiqrN6ZzZ +qIvKyeip2Iqq7anc2aqN3MjL6Mj3fW98fMzmx3+/9uav//u3+/X////////f//3//77////f//// +/////////////////////////////////////////3/Y/v///3d3d3d3d3d3d3d3d3d3d3d3d3d3 +d3d3d3d3d3d3d3e7u7u7u7u7u93d3d3d3d3dfd////8P]] \ No newline at end of file