diff --git a/apis/shatter.lua b/apis/shatter.lua new file mode 100644 index 0000000..ed741dc --- /dev/null +++ b/apis/shatter.lua @@ -0,0 +1,482 @@ +local os = _G.os +local parallel = _G.parallel +local peripheral = _G.peripheral + +local mods = peripheral.wrap("back") +--ensure glasses are present +if not mods.canvas then + error("Shatter requires Overlay Glasses", 2) +end + +--###TERMINAL API CODE###-- +--colors, for reference use +local colors = { + white = 0xf0f0f000, + orange = 0xf2b23300, + magenta = 0xe57fd800, + lightBlue = 0x99b2f200, + yellow = 0xdede6c00, + lime = 0x7fcc1900, + pink = 0xf2b2cc00, + gray = 0x4c4c4c00, + lightGray = 0x99999900, + cyan = 0x4c99b200, + purple = 0xb266e500, + blue = 0x3366cc00, + brown = 0x7f664c00, + green = 0x57a64e00, + red = 0xcc4c4c00, + black = 0x19191900 +} +--colors by number + --colors by number +local cbn = { + colors.white, + colors.orange, + colors.magenta, + colors.lightBlue, + colors.yellow, + colors.lime, + colors.pink, + colors.gray, + colors.lightGray, + colors.cyan, + colors.purple, + colors.blue, + colors.brown, + colors.green, + colors.red, + colors.black +} +--scaled character factor +local ox, oy = 6, 9 +-- character size +local sx, sy = 6, 9 +--term bg and fg colors and alpha values +local bg, fg, bgbn, fgbn, fga, bga, fgabn, bgabn = colors.black, colors.white, 2^(#cbn-1), 2^0, 255, 255, 1, 1 +--cursor, pos, and blink +local csr, cx, cy, cb = nil, 1, 1, true +local textScale = 1 +local can = mods.canvas() + +--term size +local tx, ty = can.getSize() +tx, ty = math.floor(tx/ox), math.floor(ty/oy) +--screen rendering in a table +local screen = {} +--populate that table +local function tPop() + local x, y = can.getSize() + for i = 1, math.floor(x/ox) do + screen[i] = {} + for j = 1, math.floor(y/oy) do + screen[i][j] = {bg = {}, fg = {}} + end + end +end +tPop() +--write text in grid fashion and add to table +local function write(x, y, char, color) + x, y = math.floor(x), math.floor(y) + if x > 0 and y > 0 and x <= tx and y <= ty then + if not screen[x][y].fg.getColor then + screen[x][y].fg = can.addText({((x-1)*ox)+1, ((y-1)*oy)+1}, char, color, ox/sx) + else + screen[x][y].fg.setColor(color) + screen[x][y].fg.setText(char) + end + end +end +--draw pixel in grid fashion and add to table +local function draw(x, y, color) + x, y = math.floor(x), math.floor(y) + if x > 0 and y > 0 and x <= tx and y <= ty then + if not screen[x][y].bg.getColor then + screen[x][y].bg = can.addRectangle((x-1)*ox, (y-1)*oy, ox, oy, color) + else + screen[x][y].bg.setColor(color) + end + end +end +--get the data of a particular pixel +local function getData(pixel) + if pixel then + return {bgc = bit32.band(pixel.bg.getColor(), 2^32-1), -- Credit to MC:Anavrins for bit32 ingenuity + fgc = bit32.band(pixel.fg.getColor(), 2^32-1), + txt = pixel.fg.getText()} + end +end +--set the data of a particular pixel +local function setData(pixel, data) + if pixel and data then + if pixel.bg.getPosition then + local x, y = pixel.bg.getPosition() + draw(math.floor(x/ox)+1, math.floor(y/oy)+1, data.bgc) + write(math.floor(x/ox)+1, math.floor(y/oy)+1, data.txt, data.fgc) + end + end +end +--move a row to an entirely different line +local function move(line, to) + if line > 0 and line <= ty and to > 0 and to <= ty then + for i = 1, tx do + setData(screen[i][to], getData(screen[i][line])) + end + end +end +--populate term with default bg and fg colors. +local function repopulate() + local x, y = can.getSize() + for i = 1, math.floor(x/ox) do + for j = 1, math.floor(y/oy) do + draw(i, j, bg) + end + end + for i = 1, math.floor(x/ox) do + for j = 1, math.floor(y/oy) do + write(i, j, "", fg) + end + end +end + +local function resize(x, y) + ox, oy = math.ceil(textScale*sx), math.ceil(textScale*sy) + tx, ty = x, y + csr.remove() + local oldscr = screen -- replicate the screen + screen = {} -- remove it for repopulation of table w/ new scale + tPop() -- repopulate table + repopulate() -- add objects + csr = can.addText({cx*ox, (cy*oy)+1}, "", 0xffffffff, textScale) --recreate cursor + for i = 1, #oldscr do --rerender screen in new scale + for j = 1, #oldscr[i] do + if oldscr[i][j].bg.getColor ~= nil then + --if screen[i] and screen[i][j] then + -- setData(screen[i][j], getData(oldscr[i][j])) + --end + oldscr[i][j].bg.remove() + oldscr[i][j].fg.remove() + end + end + os.sleep(0) + end + os.queueEvent("monitor_resize", "glasses") +end + +local out = {} +out.write = function(str) +--term.write + str = tostring(str) + for i = 1, #str do + write(cx+i-1, cy, str:sub(i, i), fg+fga) + draw(cx+i-1, cy, bg+bga) + end + cx = cx+#str +end +out.blit = function(str, tfg, tbg) +--term.blit + if type(str) ~= "string" then + error("bad argument #1 (expected string, got "..type(str)..")", 2) + elseif type(tfg) ~= "string" then + error("bad argument #2 (expected string, got "..type(tfg)..")", 2) + elseif type(tbg) ~= "string" then + error("bad argument #3 (expected string, got "..type(tbg)..")", 2) + end + for i = 1, #str do + local nfg = cbn[tonumber(tfg:sub(i,i), 16)+1] + local nbg = cbn[tonumber(tbg:sub(i,i), 16)+1] + draw(cx+i-1, cy, nbg+bga) + write(cx+i-1, cy, str:sub(i,i), nfg+fga) + end + cx = cx+#str +end +out.clear = function() +--term.clear + for i = 1, tx do + for j = 1, ty do + write(i, j, "", fg+fga) + draw(i, j, bg+bga) + end + end +end +out.clearLine = function() +--term.clearLine + if cy > 0 and cy <= ty then + for i = 1, tx do + draw(i, cy, bg+bga) + write(i, cy, "", fg+fga) + end + end +end +out.getCursorPos = function() +--term.getCursorPos + return cx, cy +end +out.setCursorPos = function(x, y) +--term.setCursorPos + if type(x) ~= "number" then + error("bad argument #1 (expected number, got "..type(x)..")", 2) + elseif type(y) ~= "number" then + error("bad argument #2 (expected number, got "..type(y)..")", 2) + end + csr.setPosition((x-1)*ox, ((y-1)*oy)+1) + cx, cy = x, y +end + +out.setCursorBlink = function(b) + if type(b) ~= "boolean" then + error("bad argument #1 (expected boolean, got "..type(b)..")", 2) + end + cb = b +end + +out.isColor = function() + return true, "now with more alpha!" +end + +out.isColour = out.isColor + +out.getSize = function() + return tx, ty +end + +out.setSize = function(x, y) + resize(x, y) +end + +out.scroll = function(amount) + local _, tcy = out.getCursorPos() + if type(amount) ~= "number" then + error("bad argument #1 (expected number, got "..type(amount)..")", 2) + end + if amount > 0 then + for i = 1, tx do + move(i, i-amount) + end + elseif amount < 0 then + for i = tx, 1, -1 do + move(i, i-amount) + end + end + out.setCursorPos(1, tcy-amount-1) +end +local function invCol(col) +--A simple error message I am too lazy to type twice +--used in the following few functions + error("invalid color (got "..col..")", 2) +end +local function lb2(num) +--very basic implementation of base 2 logarithm + return math.log(num)/math.log(2) +end +out.setTextColor = function(col) +--term.setTextColor + if type(col) ~= "number" then + error("bad argument #1 (number expected, got "..type(col)..")", 2) + end + if lb2(col) > #cbn or lb2(col) ~= math.ceil(lb2(col)) then + invCol(col) + else + fg = cbn[lb2(col)+1] + fgbn = col + end +end +out.setBackgroundColor = function(col) +--term.setBackgroundColor + if type(col) ~= "number" then + error("bad argument #1 (expected number, got "..type(col)..")", 2) + end + if lb2(col) > #cbn or lb2(col) ~= math.ceil(lb2(col)) then + invCol(col) + else + bg = cbn[lb2(col)+1] + bgbn = col + end +end +-- Text & BG Alpha innovated by MC:Ale32bit +out.setTextAlpha = function(val) +-- set the alpha value of the text + if type(val) ~= "number" then + error("bad argument #1 (expected number, got "..type(val)..")", 2) + end + if val > 1 then val = 1 elseif val < 0 then val = 0 end + fga = math.floor(val*255) + fgabn = val +end +out.setBackgroundAlpha = function(val) +-- set the alpha value of the background + if type(val) ~= "number" then + error("bad argument #1 (expected number, got "..type(val)..")", 2) + end + if val > 1 then val = 1 elseif val < 0 then val = 0 end + bga = math.floor(val*255) + bgabn = val +end +out.setTextHex = function(hex) +-- set the hex color value of the text + if type(tonumber(hex, 16)) ~= "number" then + error("bad argument #1 (expected number, got "..type(hex)..")", 2) + end + fg = hex + fgbn = 1 +end +out.setBackgroundHex = function(hex) +-- set the hex color value of the background + if type(tonumber(hex, 16)) ~= "number" then + error("bad argument #1 (expected number, got "..type(hex)..")", 2) + end + bg = hex + bgbn = 1 +end +out.getTextColor = function() +--term.getTextColor + return fgbn +end +out.getBackgroundColor = function() +--term.getBackgroundColor + return bgbn +end +out.getTextAlpha = function() +-- get the alpha value of the text + return fgabn +end +out.getBackgroundAlpha = function() +--get the alpha value of the background + return bgabn +end +out.getTextHex = function() +-- get the hex color value of the text + return fg +end +out.getBackgroundHex = function() +-- get the hex color value of the background + return bg +end +local function torgba(hex) +-- Converts a hex value into 3 seperate r, g, and b values +-- Technically also gets a value, but it thrown out due to what this is needed for +-- Credit to MC:valithor2 for this algorithm + local vals = {} + for i = 1, 4 do + vals[i] = hex%256 + hex = (hex-vals[i])/256 + end + return vals[4]/255, vals[3]/255, vals[2]/255 +end +local function refreshColor(oc, nc) +-- refreshes terminal when palette values are manipulated + for i = 1, #screen do + for j = 1, #screen[i] do + local op, changed = getData(screen[i][j]), false + if op.bgc == oc then + op.bgc = nc + changed = true + end + if op.fgc == oc then + op.fgc = nc + changed = true + end + if changed then + setData(screen[i][j], op) + end + end + end +end +out.getPaletteColor = function(col) +--term.getPaletteColor + if type(col) ~= "number" then + error("bad argument #1 (number expected, got "..type(col)..")", 2) + end + if lb2(col) > #cbn or lb2(col) ~= math.ceil(lb2(col)) then + invCol(col) + end + return torgba(cbn[lb2(col)+1]) +end +out.setPaletteColor = function(cnum, r, g, b) +--term.setPaletteColor + local oc = cbn[lb2(cnum)+1] + if type(cnum) ~= "number" then + error("bad argument #1 (number expected, got "..type(cnum)..")", 2) + end + if type(r) ~= "number" then + error("bad argument #2 (number expected, got "..type(r)..")", 2) + end + if g then + if type(g) ~= "number" then + error("bad argument #3 (number expected, got "..type(g)..")", 2) + elseif type(b) ~= "number" then + error("bad argument #4 (number expected, got "..type(b)..")", 2) + end + if r > 1 then r = 1 elseif r < 0 then r = 0 end + if g > 1 then g = 1 elseif g < 0 then g = 0 end + if b > 1 then b = 1 elseif b < 0 then b = 0 end + cbn[lb2(cnum)+1] = (((r*255)*(16^6))+((g*255)*(16^4))+((b*255)*(16^2))) + else + cbn[lb2(cnum)+1] = (r*256) + end + if bgbn == cnum then + out.setBackgroundColor(bgbn) + end + if fgbn == cnum then + out.setTextColor(fgbn) + end + --refreshColor(oc, cbn[lb2(cnum)+1]) -- errors +end +--compat for all those UK'ers +out.setTextColour = out.setTextColor +out.setBackgroundColour = out.setBackgroundColor +out.setPaletteColour = out.setPaletteColor +out.getTextColour = out.getTextColor +out.getBackgroundColour = out.getBackgroundColor +out.getPaletteColour = out.getPaletteColor + +out.getTextScale = function() return textScale end +out.setTextScale = function(scale) + if type(scale) ~= "number" then + error("bad argument #1 (number expected, got "..type(scale)..")", 2) + end + if 0.4 >= scale or scale > 10 then + error("Expected number in range 0.5-10", 2) + end + if textScale ~= scale then + local factor = textScale/scale +debug({ scale, textScale, factor, tx*factor, ty*factor }) + textScale = scale + resize(tx*factor, ty*factor) + end +end + +--###TERMINAL CREATION CODE###-- +csr = can.addText({cx*ox, (cy*oy)+1}, "", 0xffffffff, ox/sx) +repopulate() +out.cursorRoutine = function() + parallel.waitForAll(function() + --cursor flicker + while true do + if not cb then + csr.setText(" ") + os.sleep() + else + csr.setText("_") + os.sleep(.4) + csr.setText(" ") + os.sleep(.4) + end + end + end, + function() + --glasses event handler conversion + while true do + local e = {os.pullEvent()} + if e[1]:find("glasses") then + local _, b = e[1]:find("glasses") + e[1] = "mouse"..e[1]:sub(b+1, -1) + if e[1] ~= "mouse_scroll" then + e[3], e[4] = math.ceil(e[3]/ox), math.ceil(e[4]/oy) + end + os.queueEvent(unpack(e)) + end + end + end) +end +return out diff --git a/apps/cows.lua b/apps/cows.lua index 784e595..2196c92 100644 --- a/apps/cows.lua +++ b/apps/cows.lua @@ -2,6 +2,7 @@ _G.requireInjector(_ENV) local Config = require('config') local Util = require('util') +local InventoryAdapter = require('chestAdapter18') local device = _G.device local os = _G.os @@ -16,23 +17,51 @@ local sensor = device['plethora:sensor'] or turtle.equip('right', 'plethora:module:3') and device['plethora:sensor'] or error('Plethora sensor required') +local dispenser = device['minecraft:dispenser_89'] or + error('Dispenser not found') +local integrator = device['redstone_integrator_131'] or + error('Integrator not found') + +local function pulse() + integrator.setOutput('north', true) + os.sleep(.25) + integrator.setOutput('north', false) +end + +local function turnOffWater() + local list = dispenser.list() + if list[1].name == 'minecraft:bucket' then + pulse() + os.sleep(2) + end +end + +local function turnOnWater() + if dispenser.list()[1].name == 'minecraft:water_bucket' then + pulse() + end +end + local function getCowCount() local blocks = sensor.sense() local grown = 0 local babies = 0 + local xpCount = 0 Util.filterInplace(blocks, function(v) if v.name == 'Cow' then if v.y > -.5 then grown = grown + 1 end if v.y < -.5 then babies = babies + 1 end return v.y > -.5 + elseif v.name == 'XPOrb' then + xpCount = xpCount + 1 end end) - Util.print('%d grown, %d babies', grown, babies) + Util.print('%d grown, %d babies, %d xp', grown, babies, xpCount) - return #blocks + return #blocks, xpCount end local function butcher() @@ -60,17 +89,30 @@ local function breed() end end +local chest = InventoryAdapter({ side = 'top', direction = 'down' }) or + error('missing chest above') + turtle.run(function() + turnOffWater() + repeat - if getCowCount() > config.max_cows then + local cowCount, xpCount = getCowCount() + if cowCount > config.max_cows then turtle.setStatus('Butchering') butcher() elseif turtle.getItemCount('minecraft:wheat') == 0 then - turtle.setStatus('Out of wheat') + if chest:provide({ name = 'minecraft:wheat' }, 64) == 0 then + turtle.setStatus('Out of wheat') + end else turtle.setStatus('Breeding') breed() end + if xpCount > 2 then + turnOnWater() + os.sleep(8) + turnOffWater() + end os.sleep(5) until turtle.isAborted() end) diff --git a/apps/glassesDriver.lua b/apps/glassesDriver.lua new file mode 100644 index 0000000..9b17688 --- /dev/null +++ b/apps/glassesDriver.lua @@ -0,0 +1,31 @@ +_G.requireInjector(_ENV) + +local device = _G.device +local kernel = _G.kernel +local os = _G.os + +local glasses = require('shatter') +glasses.name = 'glasses' +glasses.type = 'rayban' +glasses.size = 'face' +device.glasses = glasses + +glasses.setTextScale(.5) +glasses.setSize(100, 40) + +kernel.hook({ 'glasses_click', 'glasses_up', 'glasses_drag' }, function(event, eventData) + local sx, sy = 6, 9 + local scale = glasses.getTextScale() + local ox, oy = math.ceil(scale*sx), math.ceil(scale*sy) + + local lookup = { + glasses_click = 'monitor_touch', + glasses_up = 'monitor_up', + glasses_drag = 'monitor_drag', + } + local x, y = math.floor(eventData[2]/ox) + 1, math.floor(eventData[3]/oy) + 1 + os.queueEvent(lookup[event], 'glasses', x, y) + + glasses.setCursorPos(x, y) + glasses.write('X ' .. eventData[3]) +end) diff --git a/apps/mwm.lua b/apps/mwm.lua index 590879e..2858942 100644 --- a/apps/mwm.lua +++ b/apps/mwm.lua @@ -28,8 +28,9 @@ local monitor local defaultEnv = Util.shallowCopy(_ENV) defaultEnv.multishell = multishell - -if args[2] then +if args[3] then + monitor = _G.device[args[3]] +elseif args[2] then monitor = peripheral.wrap(args[2]) or syntax() else monitor = peripheral.find('monitor') or syntax() diff --git a/apps/pickup.lua b/apps/pickup.lua index f0aa9bb..140c326 100644 --- a/apps/pickup.lua +++ b/apps/pickup.lua @@ -12,10 +12,6 @@ local peripheral = _G.peripheral local printError = _G.printError local turtle = _G.turtle -if not device.wireless_modem then - error('Modem is required') -end - if not turtle then error('Can only be run on a turtle') end @@ -236,16 +232,18 @@ local function pickupHost(socket) end end -Event.addRoutine(function() - while true do - print('waiting for connection on port 5222') - local socket = Socket.server(5222) +if device.wireless_modem then + Event.addRoutine(function() + while true do + print('waiting for connection on port 5222') + local socket = Socket.server(5222) - print('pickup: connection from ' .. socket.dhost) + print('pickup: connection from ' .. socket.dhost) - Event.addRoutine(function() pickupHost(socket) end) - end -end) + Event.addRoutine(function() pickupHost(socket) end) + end + end) +end local function eachEntry(t, fn) diff --git a/apps/pickupRemote.lua b/apps/pickupRemote.lua index 3e99ec5..a8162bd 100644 --- a/apps/pickupRemote.lua +++ b/apps/pickupRemote.lua @@ -94,6 +94,7 @@ local function getPoint() if not gpt then mainPage.statusBar:timedStatus('Unable to get location', 3) end + gpt.y = gpt.y - 1 return gpt end