Advertisement
fatboychummy

Simplify Shop

May 29th, 2018
511
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 66.17 KB | None | 0 0
  1. --[[
  2. 17
  3. Fixed a bug that caused a crash, and the shop will now auto-reboot if it fails to update twice.
  4.  
  5.  
  6.     SIMPLIFY Shop
  7. made by fatmanchummy
  8. ----https://github.com/fatboychummy/Simplify-Shop/blob/master/LICENSE
  9. ]]
  10.  
  11. local version = 17
  12. local tArgs = {...}
  13.  
  14. local params = {
  15.   "setupText",
  16.   "setupVisuals",
  17. }
  18. shell.setCompletionFunction(shell.getRunningProgram(),
  19. function(shell,par,cur)
  20.   if par == 1 then
  21.     local res = {}
  22.     for i = 1,#params do
  23.       if params[i]:sub(1,#cur) == cur then
  24.         res[#res+1] = params[i]:sub(#cur+1)
  25.       end
  26.     end
  27.     return res
  28.   end
  29.   return {}
  30. end
  31. )
  32.  
  33.  
  34.  
  35.  
  36. if not fs.exists("w.lua") then
  37.   shell.run("wget","https://raw.githubusercontent.com/justync7/w.lua/master/w.lua")
  38. end
  39. if not fs.exists("r.lua") then
  40.   shell.run("wget","https://raw.githubusercontent.com/justync7/r.lua/master/r.lua")
  41. end
  42. if not fs.exists("k.lua") then
  43.   shell.run("wget","https://raw.githubusercontent.com/justync7/k.lua/master/k.lua")
  44. end
  45. if not fs.exists("json.lua") then
  46.   shell.run("pastebin","get","4nRg9CHU","json.lua")
  47. end
  48. if not fs.exists("jua.lua") then
  49.   shell.run("wget","https://raw.githubusercontent.com/justync7/Jua/master/jua.lua")
  50. end
  51. if not fs.exists("logger.lua") then
  52.   shell.run("wget https://raw.githubusercontent.com/fatboychummy/Simplify-Shop/master/Logger.lua logger.lua")
  53. end
  54.  
  55. ------CHECK FOR UPDATES
  56. os.unloadAPI("logger.lua")
  57. os.loadAPI("logger.lua")
  58.  
  59. if true then
  60.   local didUpdate = false
  61.   local handle = http.get("https://raw.githubusercontent.com/fatboychummy/Simplify-Shop/master/shop.lua")
  62.   handle.readLine()
  63.   local v = tonumber(handle.readLine())
  64.   local notes = handle.readLine()
  65.   if v < version then
  66.     print(v,"<",version)
  67.   elseif v == version then
  68.     print(v,"=",version)
  69.   else
  70.     print(v,">",version)
  71.   end
  72.   handle.close()
  73.   if v > version then
  74.     print("There is an update available.")
  75.     print("Update notes: ")
  76.     print("--------------------------------")
  77.     print(notes)
  78.     print("--------------------------------")
  79.     print("Would you like to do the update now? (Y/N)")
  80.     local utm = os.startTimer(30)
  81.     while true do
  82.       local a = {os.pullEvent()}
  83.       if a[1] == "char" then
  84.         if a[2] == "y" then
  85.           fs.delete(shell.getRunningProgram())
  86.           shell.run("wget https://raw.githubusercontent.com/fatboychummy/Simplify-Shop/master/shop.lua startup")
  87.           print("Update complete.")
  88.           didUpdate = true
  89.           break
  90.         elseif a[2] == "n" then
  91.           break
  92.         end
  93.       elseif a[1] == "timer" and a[2] == utm then
  94.         break
  95.       end
  96.     end
  97.     if not didUpdate then
  98.       print("Timed out or skipping update.")
  99.     end
  100.   else
  101.     print("Up to date.")
  102.   end
  103.  
  104.   if logger.isUpdate(version) then
  105.     if logger.update() then
  106.       didUpdate = true
  107.     end
  108.   else
  109.     logger.info("Logger is up to date.")
  110.   end
  111.  
  112.  
  113.   if didUpdate then
  114.     print("Rebooting.")
  115.     os.sleep(2)
  116.     os.reboot()
  117.   end
  118. end
  119. ------END
  120.  
  121. local w = require("w")
  122. local r = require("r")
  123. local k = require("k")
  124. os.loadAPI("json.lua")
  125. local json = _G.json
  126. _G.json = nil
  127. local jua = require("jua")
  128. w.init(jua)
  129. r.init(jua)
  130. k.init(jua,json,w,r)
  131.  
  132.  
  133.  
  134. ---------------------------------------------------
  135.  
  136. if logger.canLogBeOpened then
  137.   logger.openLog()
  138. end
  139. if logger.canPurchaseLogBeOpened then
  140.   logger.openPurchaseLog()
  141. end
  142.  
  143.  
  144. local function checkKristAddress(a)
  145.   return k.makev2address(k.toKristWalletFormat(a))
  146. end
  147.  
  148.  
  149. ----------
  150. local fatData = "fatItemData"
  151. local fatCustomization = "fatShopCustomization"
  152. local mon = nil
  153. local mName = nil
  154. local tName = nil
  155. local items = nil
  156. local privKey = nil
  157. local pubKey = nil
  158. local custom = {}
  159. local chests = {}
  160. local sIL = {}
  161. local selection = false
  162. local recentPressCount = 0
  163. local oldY = 0
  164. local page = 1
  165. local mxPages = 1
  166. local mX = 0
  167. local mY = 0
  168. local ws
  169. local buttons = {}
  170. local recentPress = false
  171. local purchaseTimer = "nothing to see yet"
  172. local cobCount = 0
  173. local refreshCheck = false
  174.  
  175.  
  176. local function fixCustomization(key)
  177.   logger.info("Attempting to fix customization file.")
  178.   local hand = "h"
  179.   local function ao(a)
  180.     hand.writeLine(a)
  181.     hand.flush()
  182.   end
  183.   local function chk(a)
  184.     return type(a) == "table"
  185.   end
  186.   local clr = {
  187.     [1] = "colors.white",
  188.     [2] = "colors.orange",
  189.     [4] = "colors.magenta",
  190.     [8] = "colors.lightBlue",
  191.     [16] = "colors.yellow",
  192.     [32] = "colors.lime",
  193.     [64] = "colors.pink",
  194.     [128] = "colors.gray",
  195.     [256] = "colors.lightGray",
  196.     [512] = "colors.cyan",
  197.     [1024] = "colors.purple",
  198.     [2048] = "colors.blue",
  199.     [4096] = "colors.brown",
  200.     [8192] = "colors.green",
  201.     [16384] = "colors.red",
  202.     [32768] = "colors.black",
  203.   }
  204.   hand = fs.open(fatCustomization,"w")
  205.  
  206.   if chk(custom) then
  207.     ao("data = {")
  208.     ao(custom.owner and "  owner = \""..custom.owner.."\"," or "  owner = \"Nobody\",")
  209.     ao(custom.shopName and "  shopName = \""..custom.shopName.."\"," or  "  shopName = \"Unnamed Shop\",")
  210.     ao(type(custom.drawBottomInfoBar) == "boolean" and "  drawBottomInfoBar = "..tostring(custom.drawBottomInfoBar).."," or "  drawBottomInfoBar = true,")
  211.     ao(type(custom.showCustomInfo) == "boolean" and "  showCustomInfo = "..tostring(custom.showCustomInfo).."," or "  showCustomInfo = true,")
  212.     ao("  customInfo = {")
  213.     if chk(custom.customInfo) then
  214.       ao((custom.customInfo and custom.customInfo[1]) and "    [ 1 ] = \"" .. custom.customInfo[1] .. "\"," or "    [ 1 ] = \"Edit customInfo variable to change me\",")
  215.       ao((custom.customInfo and custom.customInfo[2]) and "    [ 2 ] = \"" .. custom.customInfo[2] .. "\"," or "    [ 2 ] = \"Up to two lines are permitted\",")
  216.     else
  217.       ao("    [ 1 ] = \"Edit customInfo variable to change me\",")
  218.       ao("    [ 2 ] = \"Up to two lines are permitted\",")
  219.     end
  220.     ao("  },")
  221.     ao(type(custom.showCustomBigInfo) == "boolean" and "  showCustomBigInfo = "..tostring(custom.showCustomBigInfo).."," or "  showCustomBigInfo = false,")
  222.     ao("  customBigInfo = {")
  223.     if chk(custom.customBigInfo) then
  224.       ao((custom.customBigInfo and custom.customBigInfo[1]) and "    [ 1 ] = \""..custom.customBigInfo[1].."\"," or "    [ 1 ] = \"Edit customBigInfo variable to change me\",")
  225.       ao((custom.customBigInfo and custom.customBigInfo[2]) and "    [ 2 ] = \""..custom.customBigInfo[2].."\"," or "    [ 2 ] = \"the word PUBKEY will be translated\",")
  226.       ao((custom.customBigInfo and custom.customBigInfo[3]) and "    [ 3 ] = \""..custom.customBigInfo[3].."\"," or "    [ 3 ] = \"to your public krist address.\",")
  227.       ao((custom.customBigInfo and custom.customBigInfo[4]) and "    [ 4 ] = \""..custom.customBigInfo[4].."\"," or "    [ 4 ] = \"Up to four lines are permitted\",")
  228.     else
  229.       ao("    [ 1 ] = \"Edit customBigInfo variable to change me\",")
  230.       ao("    [ 2 ] = \"the word PUBKEY will be translated\",")
  231.       ao("    [ 3 ] = \"to your public krist address.\",")
  232.       ao("    [ 4 ] = \"Up to four lines are permitted\",")
  233.     end
  234.     ao("  },")
  235.     ao(type(custom.touchHereForCobbleButton) == "boolean" and "  touchHereForCobbleButton = "..tostring(custom.touchHereForCobbleButton).."," or "  touchHereForCobbleButton = true,")
  236.     ao(custom.dropSide and "  dropSide = \""..custom.dropSide.."\", -- the side the turtle will drop from, accepts 'top', 'bottom', and 'front'" or "  dropSide = \"unset\", -- the side the turtle will drop from, accepts 'top', 'bottom', and 'front'")
  237.     ao(custom.itemsDrawnAtOnce and "  itemsDrawnAtOnce = "..tostring(custom.itemsDrawnAtOnce).."," or "  itemsDrawnAtOnce = 7,")
  238.     ao(type(custom.useBothChestTypes) == "boolean" and "  useBothChestTypes = "..tostring(custom.useBothChestTypes).."," or "  useBothChestTypes = false,")
  239.     ao(type(custom.useSingleChest) == "boolean" and "  useSingleChest = "..tostring(custom.useSingleChest)..", --if useBothChestTypes is true, this value does not matter.  If useBothChestTypes is false, and there is a network attached, the turtle will ignore everything except the single chest." or "  useSingleChest = false, --if useBothChestTypes is true, this value does not matter.  If useBothChestTypes is false, and there is a network attached, the turtle will ignore everything except the single chest.")
  240.     ao(custom.chestSide and "  chestSide = \""..custom.chestSide.."\",--You can use a single chest attached to a network by typing it's network name here (eg: \"minecraft:chest_666\")" or "  chestSide = \"bottom\",--You can use a single chest attached to a network by typing it's network name here (eg: \"minecraft:chest_666\")")
  241.     ao(type(custom.doPurchaseForwarding) == "boolean" and "  doPurchaseForwarding = "..tostring(custom.doPurchaseForwarding).."," or "  doPurchaseForwarding = false," )
  242.     ao(custom.purchaseForwardingAddress and "  purchaseForwardingAddress = "..custom.purchaseForwardingAddress.."," or "  purchaseForwardingAddress = \"fakeAddress\"," )
  243.     ao(type(custom.compactMode) == "boolean" and "  compactMode = "..tostring(custom.compactMode).."," or "  compactMode = false,")
  244.     ao("  farthestBackground = {")
  245.     if chk(custom.farthestBackground) then
  246.       ao(custom.farthestBackground.bg and "    bg = "..clr[custom.farthestBackground.bg].."," or "    bg = colors.black,")
  247.     else
  248.       ao("    bg = colors.black,")
  249.     end
  250.     ao("  },")
  251.     ao("  background = {")
  252.     if chk(custom.background) then
  253.       ao(custom.background.bg and "    bg = "..clr[custom.background.bg].."," or "    bg = colors.gray,")
  254.       ao(custom.background.fg and "    fg = "..clr[custom.background.fg].."," or "    fg = colors.white,")
  255.     else
  256.       ao("    bg = colors.gray,")
  257.       ao("    fg = colors.white,")
  258.     end
  259.     ao("  },")
  260.     ao("  nameBar = {")
  261.     if chk(custom.nameBar) then
  262.       ao(custom.nameBar.bg  and "    bg = "..clr[custom.nameBar.bg].."," or "    bg = colors.purple,")
  263.       ao(custom.nameBar.fg  and "    fg = "..clr[custom.nameBar.fg].."," or "    fg = colors.white,")
  264.     else
  265.       ao("    bg = colors.purple,")
  266.       ao("    fg = colors.white,")
  267.     end
  268.     ao("  },")
  269.     ao("  itemInfoBar = {")
  270.     if chk(custom.itemInfoBar) then
  271.       ao(custom.itemInfoBar.bg  and "    bg = "..clr[custom.itemInfoBar.bg].."," or "    bg = colors.blue,")
  272.       ao(custom.itemInfoBar.fg  and "    fg = "..clr[custom.itemInfoBar.fg].."," or "    fg = colors.white,")
  273.     else
  274.       ao("    bg = colors.blue,")
  275.       ao("    fg = colors.white,")
  276.     end
  277.     ao("  },")
  278.     ao("  infoBar = {")
  279.     if chk(custom.infoBar) then
  280.       ao(custom.infoBar.bg  and "    bg = "..clr[custom.infoBar.bg].."," or "    bg = colors.purple,")
  281.       ao(custom.infoBar.fg  and "    fg = "..clr[custom.infoBar.fg].."," or "    fg = colors.white,")
  282.     else
  283.       ao("    bg = colors.purple,")
  284.       ao("    fg = colors.white,")
  285.     end
  286.     ao("  },")
  287.     ao("  buttons = {")
  288.     if chk(custom.buttons) then
  289.       ao(custom.buttons.bg  and "    bg = "..clr[custom.buttons.bg].."," or "    bg = colors.blue,")
  290.       ao(custom.buttons.fg  and "    fg = "..clr[custom.buttons.fg].."," or "    fg = colors.white,")
  291.     else
  292.       ao("    bg = colors.blue,")
  293.       ao("    fg = colors.white,")
  294.     end
  295.     ao("  },")
  296.     ao("  disabledButtons = {")
  297.     if chk(custom.disabledButtons) then
  298.       ao(custom.disabledButtons.bg  and "    bg = "..clr[custom.disabledButtons.bg].."," or "    bg = colors.lightGray,")
  299.       ao(custom.disabledButtons.fg  and "    fg = "..clr[custom.disabledButtons.fg].."," or "    fg = colors.white,")
  300.     else
  301.       ao("    bg = colors.lightGray,")
  302.       ao("    fg = colors.white,")
  303.     end
  304.     ao("  },")
  305.     ao("  selection = {")
  306.     if chk(custom.selection) then
  307.       ao(custom.selection.bg  and "    bg = "..clr[custom.selection.bg].."," or "    bg = colors.white,")
  308.       ao(custom.selection.fg  and "    fg = "..clr[custom.selection.fg].."," or "    fg = colors.black,")
  309.     else
  310.       ao("    bg = colors.white,")
  311.       ao("    fg = colors.black,")
  312.     end
  313.     ao("  },")
  314.     ao("  bigSelection = {")
  315.     if chk(custom.bigSelection) then
  316.       ao(custom.bigSelection.bg  and "    bg = "..clr[custom.bigSelection.bg].."," or "    bg = colors.black,")
  317.       ao(custom.bigSelection.bg  and "    fg = "..clr[custom.bigSelection.fg].."," or "    fg = colors.white,")
  318.     else
  319.       ao("    bg = colors.black,")
  320.       ao("    fg = colors.white,")
  321.     end
  322.     ao("  },")
  323.     ao("  selectedEmptyStock = {")
  324.     if chk(custom.selectedEmptyStock) then
  325.       ao(custom.selectedEmptyStock.bg and "   bg = "..clr[custom.selectedEmptyStock.bg].."," or "   bg = colors.red,")
  326.       ao(custom.selectedEmptyStock.fg and "   fg = "..clr[custom.selectedEmptyStock.fg].."," or "   fg = colors.white,")
  327.     else
  328.       ao("    bg = colors.red,")
  329.       ao("    fg = colors.white,")
  330.     end
  331.     ao("  },")
  332.     ao("  bigSelectionEmptyStock = {")
  333.     if chk(custom.bigSelectionEmptyStock) then
  334.       ao(custom.bigSelectionEmptyStock.bg and "   bg = "..clr[custom.bigSelectionEmptyStock.bg].."," or "   bg = colors.red,")
  335.       ao(custom.bigSelectionEmptyStock.fg and "   fg = "..clr[custom.bigSelectionEmptyStock.fg].."," or "   fg = colors.white,")
  336.     else
  337.       ao("    bg = colors.red,")
  338.       ao("    fg = colors.white,")
  339.     end
  340.     ao("  },")
  341.     ao("  bigInfo = {")
  342.     if chk(custom.bigInfo) then
  343.       ao(custom.bigInfo.bg  and "    bg = "..clr[custom.bigInfo.bg].."," or "    bg = colors.black,")
  344.       ao(custom.bigInfo.fg  and "    fg = "..clr[custom.bigInfo.fg].."," or "    fg = colors.white,")
  345.     else
  346.       ao("    bg = colors.black,")
  347.       ao("    fg = colors.white,")
  348.     end
  349.     ao("  },")
  350.     ao("  itemTableColor1 = {")
  351.     if chk(custom.itemTableColor1) then
  352.       ao(custom.itemTableColor1.bg  and "    bg = "..clr[custom.itemTableColor1.bg].."," or "    bg = colors.black,")
  353.       ao(custom.itemTableColor1.bg  and "    fg = "..clr[custom.itemTableColor1.fg].."," or "    fg = colors.white,")
  354.     else
  355.       ao("    bg = colors.black,")
  356.       ao("    fg = colors.white,")
  357.     end
  358.     ao("  },")
  359.     ao("  itemTableColor2 = {")
  360.     if chk(custom.itemTableColor2) then
  361.       ao(custom.itemTableColor2.bg  and "    bg = "..clr[custom.itemTableColor2.bg].."," or "    bg = colors.black,")
  362.       ao(custom.itemTableColor2.fg  and "    fg = "..clr[custom.itemTableColor2.fg].."," or "    fg = colors.white,")
  363.     else
  364.       ao("    bg = colors.black,")
  365.       ao("    fg = colors.white,")
  366.     end
  367.     ao("  },")
  368.     ao("  itemTableEmptyStock1 = {")
  369.     if chk(custom.itemTableEmptyStock1) then
  370.       ao(custom.itemTableEmptyStock1.bg and "    bg = "..clr[custom.itemTableEmptyStock1.bg].."," or "    bg = colors.black,")
  371.       ao(custom.itemTableEmptyStock1.fg and "    fg = "..clr[custom.itemTableEmptyStock1.fg].."," or "    fg = colors.red,")
  372.     else
  373.       ao("    bg = colors.black,")
  374.       ao("    fg = colors.red,")
  375.     end
  376.     ao("  },")
  377.     ao("  itemTableEmptyStock2 = {")
  378.     if chk(custom.itemTableEmptyStock2) then
  379.       ao(custom.itemTableEmptyStock2.bg and "    bg = "..clr[custom.itemTableEmptyStock2.bg].."," or "    bg = colors.black,")
  380.       ao(custom.itemTableEmptyStock2.fg and "    fg = "..clr[custom.itemTableEmptyStock2.fg].."," or "    fg = colors.red,")
  381.     else
  382.       ao("    bg = colors.black,")
  383.       ao("    fg = colors.red,")
  384.     end
  385.     ao("  },")
  386.     ao("  REFUNDS = {")
  387.     if chk(custom.REFUNDS) then
  388.       ao(custom.REFUNDS.noItemSelected and "    noItemSelected = \""..custom.REFUNDS.noItemSelected.."\"," or "    noItemSelected = \"There is no item selected!\",")
  389.       ao(custom.REFUNDS.underpay and "    underpay = \""..custom.REFUNDS.underpay .."\"," or "    underpay = \"You seem to have underpaid.\",")
  390.       ao(custom.REFUNDS.change and "    change = \""..custom.REFUNDS.change .."\"," or "    change = \"You overpaid by a small amount, here's your change!\",")
  391.       ao(custom.REFUNDS.outOfStock and "    outOfStock = \""..custom.REFUNDS.outOfStock .."\"," or "    outOfStock = \"We do not have any stock of that item!\",")
  392.       ao(custom.REFUNDS.UPDATE and "    UPDATE = \""..custom.REFUNDS.UPDATE.."\"," or "    UPDATE = \"The shop is updating it's stocks and an error occured!\",")
  393.     else
  394.       ao("    noItemSelected = \"There is no item selected!\",")
  395.       ao("    underpay = \"You seem to have underpaid.\",")
  396.       ao("    change = \"You overpaid by a small amount, here's your change.\",")
  397.       ao("    outOfStock = \"We do not have any stock of that item!\",")
  398.       ao("    UPDATE = \"The shop is updating it's stocks and an error occured!\",")
  399.     end
  400.     ao("  },")
  401.     ao("  LOGGER = {")
  402.     if chk(custom.LOGGER) then
  403.       ao(type(custom.LOGGER.doNormalLogging) == "boolean" and "    doNormalLogging = "..tostring(custom.LOGGER.doNormalLogging)..", --If you are getting errors, set this to true.  It tends to spam files." or "    doNormalLogging = false, --If you are getting errors, set this to true.  It tends to spam files.")
  404.       ao(type(custom.LOGGER.doPurchaseLogging) == "boolean" and "    doPurchaseLogging = "..tostring(custom.LOGGER.doPurchaseLogging).."," or "    doPurchaseLogging = true,")
  405.       ao(type(custom.LOGGER.doInfoLogging) == "boolean" and "    doInfoLogging = "..tostring(custom.LOGGER.doInfoLogging)..", --HIGHLY recommended to not enable this.  Every time the screen redraws an info event is created." or "    doInfoLogging = false, --HIGHLY recommended to not enable this.  Every time the screen redraws an info event is created.")
  406.       ao(type(custom.LOGGER.doWarnLogging) == "boolean" and "    doWarnLogging = "..tostring(custom.LOGGER.doWarnLogging).."," or "    doWarnLogging = true,")
  407.       ao(custom.LOGGER.LOG_LOCATION and "    LOG_LOCATION = \""..custom.LOGGER.LOG_LOCATION.."\"," or "\"logs/\",")
  408.       ao(custom.LOGGER.LOG_NAME and "    LOG_NAME = \""..custom.LOGGER.LOG_NAME.."\"," or "    LOG_NAME = \"Log\",")
  409.       ao(custom.LOGGER.PURCHASE_LOG_LOCATION and "    PURCHASE_LOG_LOCATION = \""..custom.LOGGER.PURCHASE_LOG_LOCATION.."\"," or "    PURCHASE_LOG_LOCATION = \"purchases/\",")
  410.       ao(custom.LOGGER.PURCHASE_LOG_NAME and "    PURCHASE_LOG_NAME = \""..custom.LOGGER.PURCHASE_LOG_NAME.."\"," or "    PURCHASE_LOG_NAME = \"PurchaseLog\",")
  411.     else
  412.       ao("    doNormalLogging = false, --If you are getting errors, set this to true.  It tends to spam files.")
  413.       ao("    doPurchaseLogging = true,")
  414.       ao("    doInfoLogging = false, --HIGHLY recommended to not enable this.  Every time the screen redraws an info event is created.")
  415.       ao("    doWarnLogging = true,")
  416.       ao("    LOG_LOCATION = \"logs/\",")
  417.       ao("    LOG_NAME = \"Log\",")
  418.       ao("    PURCHASE_LOG_LOCATION = \"purchases/\",")
  419.       ao("    PURCHASE_LOG_NAME = \"PurchaseLog\",")
  420.     end
  421.     ao("  },")
  422.     ao("}")
  423.     ao("return data")
  424.   else
  425.     fs.move(fatShopCustomization,"BadShopCustomization")
  426.     writeCustomization(fatShopCustomization)
  427.     logger.severe("The fatShopCustomization file should return a table.  The old file has been moved to BadShopCustomization, and a new one has been written in it's place.")
  428.     logger.info("Rebooting in 10 seconds.")
  429.     os.sleep(10)
  430.     os.reboot()
  431.   end
  432.   logger.info("Potential fix for customization file. Rebooting.")
  433.   os.sleep(4)
  434.   os.reboot()
  435. end
  436.  
  437.  
  438.  
  439.  
  440.  
  441. if tArgs[1] == "setupText" then
  442.   logger.info("Entering setup.")
  443.   sleep(3)
  444.   term.clear()
  445.   term.setCursorPos(1,1)
  446.   print("Before continuing, be sure you are alone and nobody else is on/able to access this computer.")
  447.   print("Nothing will be hidden, and everything written to the screen during the setup will be in plaintext.")
  448.   print()
  449.   print("Press any key to continue")
  450.   os.pullEvent("key")
  451.   sleep()
  452.  
  453.   local qa = {
  454.     kristAddress = {
  455.       t = "boolean",
  456.     },
  457.     kristPword = {
  458.       q = "Please enter the private-key for your krist address.",
  459.     },
  460.     confirmPword = {
  461.       q = "Please confirm the key by typing it again.",
  462.     },
  463.     customInfo1 = {
  464.       t = "string",
  465.       q = "Enter line 1, leave blank for nothing.",
  466.     },
  467.     customInfo2 = {
  468.       t = "string",
  469.       q = "Enter line 2, leave blank for nothing.",
  470.     },
  471.     useSingleChest = {
  472.       t = "boolean",
  473.       q = "Will you be using a chest directly beside the turtle?",
  474.     },
  475.     chestSide = {
  476.       q = "What side of the turtle is the chest on?",
  477.     },
  478.     useModemChest = {
  479.       t = "boolean",
  480.       q = "Will you be using a storage network attached to a modem?",
  481.     },
  482.   }
  483.   local q = {
  484.     owner = {
  485.       t = "string",
  486.       q = "Who owns this shop?",
  487.     },
  488.     shopName = {
  489.       t = "string",
  490.       q = "What would you like this shop to be called?",
  491.     },
  492.     showCustomInfo = {
  493.       t = "boolean",
  494.       q = "Would you like to use a custom information bar?",
  495.     },
  496.     touchHereForCobbleButton = {
  497.       t = "boolean",
  498.       q = "Would you like to display a \"Free Cobble\" button?",
  499.     },
  500.     itemsDrawnAtOnce = {
  501.       t = "number",
  502.       q = "How many items should be drawn per page?",
  503.     },
  504.     dropSide = {
  505.       t = "string",
  506.       q = "What side of the turtle would you like to drop items? (front, top, or bottom)",
  507.       list = {
  508.         "front",
  509.         "top",
  510.         "bottom",
  511.       },
  512.     },
  513.   }
  514.   local function resolveAnswer(q,a)
  515.     if q.list and (q.t == "string" or q.t == "number") then
  516.       local inList = false
  517.       for i = 1,#q.list do
  518.         if a == q.list[i] then
  519.           inList = true
  520.         end
  521.       end
  522.       return a,inList;
  523.     else
  524.       if q.t == "string" then
  525.         return a,true;
  526.       elseif q.t == "boolean" then
  527.         a = string.lower(a)
  528.         if a == "yes" or a == "true" or a == "1" or a == "y" then
  529.           return true,true;
  530.         elseif a == "no" or a == "false" or a == "0" or a == "n" then
  531.           return false,true;
  532.         else
  533.           return nil,false;
  534.         end
  535.       elseif q.t == "number" then
  536.         a = tonumber(a)
  537.         return a,type(a) == "number"
  538.       end
  539.     end
  540.     return "Something failed.",false;
  541.   end
  542.  
  543.  
  544.   local function c()
  545.     term.clear()
  546.     term.setCursorPos(1,1)
  547.   end
  548.   local function pq(q)
  549.     print(q.q,"(" .. q.t .. ")")
  550.     term.write("->")
  551.   end
  552.  
  553.   local tries = 0
  554.   repeat
  555.     local complete = false
  556.     tries = 0
  557.     repeat
  558.       c()
  559.       if tries > 0 then
  560.         print("Those are not the same!")
  561.       end
  562.       print(qa.kristPword.q)
  563.       term.write("->")
  564.       qa.kristPword.a = io.read()
  565.       print()
  566.       print(qa.confirmPword.q)
  567.       term.write("->")
  568.       qa.confirmPword.a = io.read()
  569.       print()
  570.       tries = 1
  571.       qa.kristAddress.a = checkKristAddress(qa.kristPword.a)
  572.     until qa.kristPword.a == qa.confirmPword.a
  573.     tries = 0
  574.     repeat
  575.       if tries > 0 then
  576.         print("That is not a valid answer!")
  577.       end
  578.       print("Is",checkKristAddress(qa.kristPword.a),"your krist address? (boolean)")
  579.       term.write("->")
  580.       local tmp = io.read()
  581.       local a,b = resolveAnswer(qa.kristAddress,tmp)
  582.       print(a,b)
  583.       if a and b then complete = true end
  584.       tries = 1
  585.     until b
  586.   until complete
  587.  
  588.   tries = 0
  589.   repeat
  590.     c()
  591.     if tries > 0 then
  592.       print("That is not a valid answer!")
  593.     end
  594.     print(qa.useSingleChest.q)
  595.     term.write("->")
  596.     local tmp = "empty"
  597.     local a,b = resolveAnswer(qa.useSingleChest,io.read())
  598.     if a and b then
  599.       print(qa.chestSide.q)
  600.       term.write("->")
  601.       tmp = io.read()
  602.     end
  603.     qa.chestSide.a = tmp
  604.     qa.useSingleChest.a = a
  605.     tries = 1
  606.   until b
  607.  
  608.   tries = 0
  609.   repeat
  610.     c()
  611.     if tries > 0 then
  612.       print("That is not a valid answer!")
  613.     end
  614.     print(qa.useModemChest.q)
  615.     term.write("->")
  616.     local a,b = resolveAnswer(qa.useModemChest,io.read())
  617.     qa.useModemChest.a = a
  618.     tries = 1
  619.   until b
  620.  
  621.   local function customInfoRead()
  622.     c()
  623.     pq(qa.customInfo1)
  624.     qa.customInfo1.a = io.read()
  625.     print()
  626.     c()
  627.     pq(qa.customInfo2)
  628.     qa.customInfo2.a = io.read()
  629.   end
  630.  
  631.  
  632.  
  633.   for k,v in pairs(q) do
  634.     tries = 0
  635.     repeat
  636.       local tmp = nil
  637.       c()
  638.       if tries > 0 then
  639.         print("That is not a valid answer!")
  640.       end
  641.       pq(v)
  642.       local a,b = resolveAnswer(v,io.read())
  643.       q[k].a = a
  644.       if k == "showCustomInfo" and a and b then
  645.         customInfoRead()
  646.       end
  647.       tries = tries + 1
  648.     until b
  649.   end
  650.  
  651.   custom = {}
  652.   for k,v in pairs(q) do
  653.     if v.a ~= nil then
  654.       custom[k] = v.a
  655.     end
  656.   end
  657.  
  658.   custom.customInfo = {
  659.     [ 1 ] = qa.customInfo1.a,
  660.     [ 2 ] = qa.customInfo2.a,
  661.   }
  662.   custom.useSingleChest = qa.useSingleChest.a
  663.   custom.chestSide = qa.chestSide.a
  664.   custom.useBothChestTypes = qa.useModemChest.a and qa.useSingleChest.a
  665.   local hand = fs.open(".privKey","w")
  666.   hand.writeLine("return \""..qa.kristPword.a.."\",\""..qa.kristAddress.a.."\"")
  667.   hand.close()
  668.  
  669.   fixCustomization()
  670. end
  671.  
  672.  
  673.  
  674.  
  675. if fs.exists(".turtle") then
  676.     local hd = fs.open(".turtle","r")
  677.     tName = hd.readLine()
  678.     hd.close()
  679. else
  680.     local juan = nil
  681.     for k,v in pairs(peripheral.getNames()) do
  682.         if v:find("chest") then juan = v break end
  683.     end
  684.     if not juan then
  685.         error("No chests connected to the network")
  686.     end
  687.     juan = peripheral.wrap(juan)
  688.     local tmp = juan.getTransferLocations()
  689.     for i = 1,#tmp do
  690.         if tmp[i]:find("turtle") then
  691.             tName = tmp[i]
  692.             logger.info("Connected to turtle "..tName)
  693.             break
  694.         end
  695.     end
  696. end
  697.  
  698. if fs.exists(".monitor") then
  699.     local hd = fs.open(".monitor","r")
  700.     mName = hd.readLine()
  701.     if peripheral.find(mName) then
  702.         mon = peripheral.wrap(mName)
  703.     end
  704.     hd.close()
  705. end
  706.  
  707. if not mon then
  708.     local pers = peripheral.getNames()
  709.     for i = 1,#pers do
  710.         if peripheral.getType(pers[i]) == "monitor" then
  711.             mName = pers[i]
  712.             mon = peripheral.wrap(pers[i])
  713.         end
  714.     end
  715.     if not mon then
  716.         error("Could not find monitor")
  717.     end
  718. end
  719.  
  720. logger.info("Connected to monitor "..mName)
  721. mon.setTextScale(0.5)
  722. mX,mY = mon.getSize()
  723.  
  724.  
  725. local function writeBlankPrivKey()
  726.     local hd = fs.open(".privKey","w")
  727.     hd.writeLine("--by default, so long as this returns your privateKey and public Krist Address, it will work.")
  728.     hd.writeLine("--  You may use whatever encryption methods.")
  729.     hd.writeLine("--It is recommended to use a different kristWallet than your main, as it may cause problems.")
  730.     hd.writeLine("return false,false")
  731.     hd.close()
  732.     logger.severe("Private key not valid.  Edit .privKey to change it.  Purchases will likely not work.")
  733. end
  734. if not fs.exists(".privKey") then
  735.     writeBlankPrivKey()
  736. else
  737.     privKey,pubKey = dofile(".privKey")
  738.     if type(privKey) ~= "string" or type(pubKey) ~= "string" then
  739.         fs.move(".privKey","badPrivateKey")
  740.         logger.severe("Your private key is messed up.  Your old private key has been moved to \"badPrivateKey\"")
  741.         logger.warn("Purchases will not work currently.  Without the private key the shop will crash!")
  742.         writeBlankPrivKey()
  743.     end
  744.     if privKey then
  745.       privKey = k.toKristWalletFormat(privKey)
  746.     end
  747. end
  748.  
  749.  
  750. local function writeData()
  751.   local hd = fs.open(fatData,"w")
  752.   local function ao(a)
  753.       hd.writeLine(a)
  754.   end
  755.   ao("local items = {")
  756.   ao("  {")
  757.   ao("    display = \"Iron Ingot\",")
  758.   ao("    price = 1,")
  759.   ao("    find = \"minecraft:iron_ingot\",")
  760.   ao("    damage = 0,")
  761.   ao("  },")
  762.   ao("  {")
  763.   ao("    display = \"Coal\",")
  764.   ao("    price = 0.2,")
  765.   ao("    find = \"minecraft:coal\",")
  766.   ao("    damage = 0,")
  767.   ao("  },")
  768.   ao("  {")
  769.   ao("    display = \"Charcoal\",")
  770.   ao("    price = 0.1,")
  771.   ao("    find = \"minecraft:coal\",")
  772.   ao("    damage = 1,")
  773.   ao("  },")
  774.   ao("}")
  775.   ao("return items")
  776.   hd.close()
  777. end
  778.  
  779. if not fs.exists(fatData) then
  780.   writeData()
  781.   logger.warn("file "..fatData.." does not exist, wrote default item data.")
  782.   items = dofile(fatData)
  783. else
  784.   items = dofile(fatData)
  785.   if type(items) ~= "table" then
  786.     logger.severe(fatData.." should return a table!")
  787.   else
  788.     logger.info("Items found in data: "..#items)
  789.   end
  790. end
  791.  
  792.  
  793.  
  794. local function refund(to,amt,rsn,gbad)
  795.     local success,err = await(k.makeTransaction,privKey,to,amt,( rsn and gbad and "message="..rsn ) or ( rsn and not gbad and "error="..rsn ) or ( "error=Unknown error occured, take your money back" ) )
  796.     if not success then
  797.         logger.severe("Failed to send refund")
  798.         print(textutils.serialise(err))
  799.         error("Failed to refund money due to "..err.error)
  800.     else
  801.         logger.info("Sent refund")
  802.     end
  803. end
  804.  
  805.  
  806. --get user preferences
  807. local function writeCustomization(name)
  808.     local hd = fs.open(name,"w")
  809.     local function ao(txt)
  810.         hd.writeLine(txt)
  811.     end
  812.     ao("data = {")
  813.     ao("  owner = \"nobody\",")
  814.     ao("  shopName = \"Unnamed Shop\",")
  815.     ao("  drawBottomInfoBar = true,")
  816.     ao("  showCustomInfo = true,")
  817.     ao("  customInfo = {")
  818.     ao("    [ 1 ] = \"Edit customInfo variable to change me\",")
  819.     ao("    [ 2 ] = \"Up to two lines are permitted\",")
  820.     ao("  },")
  821.     ao("  showCustomBigInfo = false,")
  822.     ao("  customBigInfo = {")
  823.     ao("    [ 1 ] = \"Edit customBigInfo variable to change me\",")
  824.     ao("    [ 2 ] = \"the word PUBKEY will be translated\",")
  825.     ao("    [ 3 ] = \"to your public krist address.\",")
  826.     ao("    [ 4 ] = \"Up to four lines are permitted\",")
  827.     ao("  },")
  828.     ao("  touchHereForCobbleButton = true,")
  829.     ao("  dropSide = \"top\", -- the side the turtle will drop from, accepts 'top', 'bottom', and 'front'")
  830.     ao("  itemsDrawnAtOnce = 7,")
  831.     ao("  useBothChestTypes = false,")
  832.     ao("  useSingleChest = false, --if useBothChestTypes is true, this value does not matter.  If useBothChestTypes is false, and there is a network attached, the turtle will ignore everything except the single chest.")
  833.     ao("  chestSide = \"bottom\",--You can use a single chest attached to a network by typing it's network name here (eg: \"minecraft:chest_666\")")
  834.     ao("  doPurchaseForwarding = false,")
  835.     ao("  purchaseForwardingAddress = \"fakeAddress\",")
  836.     ao("  compactMode = false,")
  837.     ao("  farthestBackground = {")
  838.     ao("    bg = colors.black,")
  839.     ao("  },")
  840.     ao("  background = {")
  841.     ao("    bg = colors.gray,")
  842.     ao("    fg = colors.white,")
  843.     ao("  },")
  844.     ao("  nameBar = {")
  845.     ao("    bg = colors.purple,")
  846.     ao("    fg = colors.white,")
  847.     ao("  },")
  848.     ao("  itemInfoBar = {")
  849.     ao("    bg = colors.blue,")
  850.     ao("    fg = colors.white,")
  851.     ao("  },")
  852.     ao("  infoBar = {")
  853.     ao("    bg = colors.purple,")
  854.     ao("    fg = colors.white,")
  855.     ao("  },")
  856.     ao("  buttons = {")
  857.     ao("    bg = colors.blue,")
  858.     ao("    fg = colors.white,")
  859.     ao("  },")
  860.     ao("  disabledButtons = {")
  861.     ao("    bg = colors.lightGray,")
  862.     ao("    fg = colors.white,")
  863.     ao("  },")
  864.     ao("  selection = {")
  865.     ao("    bg = colors.white,")
  866.     ao("    fg = colors.black,")
  867.     ao("  },")
  868.     ao("  bigSelection = {")
  869.     ao("    bg = colors.black,")
  870.     ao("    fg = colors.white,")
  871.     ao("  },")
  872.     ao("  selectedEmptyStock = {")
  873.     ao("    bg = colors.red,")
  874.     ao("    fg = colors.white,")
  875.     ao("  },")
  876.     ao("  bigSelectionEmptyStock = {")
  877.     ao("    bg = colors.red,")
  878.     ao("    fg = colors.white,")
  879.     ao("  },")
  880.     ao("  bigInfo = {")
  881.     ao("    bg = colors.black,")
  882.     ao("    fg = colors.white,")
  883.     ao("  },")
  884.     ao("  itemTableColor1 = {")
  885.     ao("    bg = colors.black,")
  886.     ao("    fg = colors.white,")
  887.     ao("  },")
  888.     ao("  itemTableColor2 = {")
  889.     ao("    bg = colors.black,")
  890.     ao("    fg = colors.white,")
  891.     ao("  },")
  892.     ao("  itemTableEmptyStock1 = {")
  893.     ao("    bg = colors.black,")
  894.     ao("    fg = colors.red,")
  895.     ao("  },")
  896.     ao("  itemTableEmptyStock2 = {")
  897.     ao("    bg = colors.black,")
  898.     ao("    fg = colors.red,")
  899.     ao("  },")
  900.  
  901.     ao("  REFUNDS = {")
  902.     ao("    noItemSelected = \"There is no item selected!\",")
  903.     ao("    underpay = \"You seem to have underpaid.\",")
  904.     ao("    change = \"You overpaid by a small amount, here's your change!\",")
  905.     ao("    outOfStock = \"We do not have any stock of that item!\",")
  906.     ao("    UPDATE = \"The shop is updating it's stocks and an error occured!\",")
  907.     ao("  },")
  908.     ao("  LOGGER = {")
  909.     ao("    doNormalLogging = false, --If you are getting errors, set this to true.  It tends to spam files.")
  910.     ao("    doPurchaseLogging = true,")
  911.     ao("    doInfoLogging = false, --HIGHLY recommended to not enable this.  Every time the screen redraws an info event is created.")
  912.     ao("    doWarnLogging = true,")
  913.     ao("    LOG_LOCATION = \"logs/\",")
  914.     ao("    LOG_NAME = \"Log\",")
  915.     ao("    PURCHASE_LOG_LOCATION = \"purchases/\",")
  916.     ao("    PURCHASE_LOG_NAME = \"PurchaseLog\",")
  917.     ao("  },")
  918.     ao("}")
  919.     ao("return data")
  920.     hd.close()
  921. end
  922.  
  923.  
  924.  
  925.  
  926. if not fs.exists(fatCustomization) then
  927.   writeCustomization(fatCustomization)
  928.   logger.warn("No customization file, wrote default customization file.")
  929.   custom = dofile(fatCustomization)
  930. else
  931.   custom = dofile(fatCustomization)
  932. end
  933.  
  934. local function checkCustomization()
  935.   logger.info("Checking Customization file")
  936.   writeCustomization(".temp")
  937.   local c2 = dofile(".temp")
  938.   fs.delete(".temp")
  939.   if type(custom) ~= "table" then
  940.     fixCustomization()
  941.   end
  942.   local function typeWarn(k,exp)
  943.     logger.severe(k..": expected "..exp..", got "..type(custom[k]))
  944.     fixCustomization()
  945.   end
  946.   local function typeInWarn(k,k2,v2)
  947.     logger.severe("Table "..k.."'s item '"..k2.."' should be of type "..type(v2)..", but is of type "..type(custom[k][k2]))
  948.     fixCustomization()
  949.   end
  950.   for k,v in pairs(c2) do
  951.     if type(v) ~= type(custom[k]) then
  952.       typeWarn(k,type(v))
  953.     end
  954.     if type(v) == "table" then
  955.       for k2,v2 in pairs(v) do
  956.         if type(custom[k]) == "table" then
  957.           if type(v2) ~= type(custom[k][k2]) then
  958.             typeInWarn(k,k2,v2)
  959.           end
  960.         end
  961.       end
  962.     end
  963.   end
  964.   return true
  965. end
  966.  
  967. local function checkData()
  968.   logger.info("Checking items, "..#items)
  969.   if type(items) ~= "table" then
  970.     logger.severe("Item file should return a table!")
  971.   end
  972.   for i = 1,#items do
  973.     if type(items[i]) ~= "table" then
  974.       logger.severe("Each item should be a table of four keys, #"..i..": got "..type(items[i])..", expected table")
  975.     else
  976.       local c = items[i]
  977.       local function typeWarn(k,exp)
  978.         logger.severe("Item #"..i.."'s "..k..": expected "..exp..", got "..type(c[k])..".")
  979.       end
  980.       if type(c.display) ~= "string" then
  981.         typeWarn("display","string")
  982.       end
  983.       if type(c.price) ~= "number" then
  984.         typeWarn("price","number")
  985.       end
  986.       if type(c.find) ~= "string" then
  987.         typeWarn("find","string")
  988.       end
  989.       if type(c.damage) ~= "number" then
  990.         typeWarn("damage","number")
  991.       end
  992.     end
  993.   end
  994.   return true
  995. end
  996.  
  997. local function checkKey()
  998.   if k.makev2address(privKey) ~= pubKey then
  999.     logger.severe("Your private-key and public-key are mismatched!")
  1000.     printError("Your private-key evaluates to...",k.makev2address(privKey))
  1001.     printError("Your public-key is written as...",pubKey)
  1002.     error("Private-key must evaluate to public-key.")
  1003.   else
  1004.     logger.info("Private-key and public-key match.")
  1005.   end
  1006. end
  1007.  
  1008. local function checkAllTheThings()
  1009.   checkCustomization()
  1010.   checkData()
  1011.   checkKey()
  1012. end
  1013.  
  1014.  
  1015.  
  1016. --------begin inventory and monitor manip
  1017.  
  1018. local function refreshChests()
  1019.   chests = {}
  1020.   if not custom.useSingleChest or custom.useBothChestTypes then
  1021.     local allPs = peripheral.getNames()
  1022.     for i = 1,#allPs do
  1023.       if allPs[i]:find("chest") or allPs[i]:find("shulker") then
  1024.         table.insert(chests,allPs[i])
  1025.       end
  1026.     end
  1027.   end
  1028.   if custom.useSingleChest or custom.useBothChestTypes then
  1029.     local yay = true
  1030.     for i = 1,#chests do
  1031.       if chests[i] == custom.chestSide then
  1032.         yay = false
  1033.       end
  1034.     end
  1035.     if yay then
  1036.       table.insert(chests,custom.chestSide)
  1037.     end
  1038.   end
  1039. end
  1040.  
  1041. local function recursiveCopy(from,to)
  1042.   if type(from) == "table" then
  1043.     for k,v in pairs(from) do
  1044.       if type(v) == "table" then
  1045.         to[k] = {}
  1046.         recursiveCopy(from[k],to[k])
  1047.       else
  1048.         to[k] = v
  1049.       end
  1050.     end
  1051.   end
  1052. end
  1053.  
  1054.  
  1055.  
  1056. local function refreshItems()
  1057.   refreshChests()
  1058.   local sIL2 = {}
  1059.   recursiveCopy(sIL,sIL2)
  1060.   for i = 1,#sIL2 do
  1061.     sIL2[i].count = 0
  1062.   end
  1063.   cobCount = 0
  1064.   for i = 1,#chests do
  1065.     local cChest = peripheral.wrap(chests[i])
  1066.     if type(cChest) ~= "table" then
  1067.       logger.warn("Chest \""..tostring(chests[i]).."\" (Index "..tostring(i)..") is seemingly missing from the network! Skipping it.")
  1068.     else
  1069.       local ok,cInv = pcall(cChest.list)
  1070.       if not ok then error(tostring(chests[i]).." is causing errors on the network and needs to be replaced.") end
  1071.       for o = 1,cChest.size() do
  1072.         if cInv[o] then
  1073.           for p = 1,#sIL2 do
  1074.             if cInv[o].name == sIL2[p].find and cInv[o].damage == sIL2[p].damage then
  1075.               sIL2[p].count = sIL2[p].count + cInv[o].count
  1076.             end
  1077.           end
  1078.           if custom.touchHereForCobbleButton and cInv[o].name == "minecraft:cobblestone" and cInv[o].damage == 0 then
  1079.             cobCount = cobCount + cInv[o].count
  1080.           end
  1081.         end
  1082.       end
  1083.     end
  1084.   end
  1085.   buttons.cobble.content = "Free Cobble ("..cobCount..")"
  1086.   local b = buttons.cobble.content
  1087.   buttons.cobble.x2 = buttons.cobble.x1+1+b:len()
  1088.   return sIL2
  1089. end
  1090.  
  1091. local function doRefresh()
  1092.   local ok = false
  1093.   ok,sIL = pcall(refreshItems)
  1094.   if not ok and type(sIL)  == "string" then
  1095.     logger.warn("Item refresh failed with code: "..sIL.."... retrying.")
  1096.   elseif not ok then
  1097.     logger.warn("Item refresh failed with unknown code... retrying.")
  1098.   end
  1099.   if not ok then
  1100.     if refreshCheck then
  1101.       error("Failed second refresh check.  Rebooting.")
  1102.     end
  1103.     refreshCheck = true
  1104.     doRefresh()
  1105.   else
  1106.     refreshCheck = false
  1107.   end
  1108. end
  1109.  
  1110. local function sortItems()
  1111.   sIL = {}
  1112.   local a = #items
  1113.   for i = 1,a do
  1114.     local smallestIndex = a --because why the fuck does this error if I dont
  1115.     while items[smallestIndex] == nil do
  1116.       smallestIndex = smallestIndex - 1
  1117.     end
  1118.     for o = a,1,-1 do
  1119.       if items[o] ~= nil and items[o].display < items[smallestIndex].display then
  1120.         smallestIndex = o
  1121.       end
  1122.     end
  1123.     if smallestIndex ~= -1 then
  1124.       sIL[i] = {}
  1125.       for k,v in pairs(items[smallestIndex]) do
  1126.         sIL[i][k] = v
  1127.       end
  1128.       items[smallestIndex] = nil
  1129.     end
  1130.   end
  1131. end
  1132.  
  1133.  
  1134.  
  1135. local function grabItems(name,dmg,count)
  1136.   refreshChests()
  1137.   local amountTransfered = 0
  1138.   if count ~= 0 then
  1139.     for i = 1,#chests do
  1140.       local cChest = peripheral.wrap(chests[i])
  1141.       local cur = cChest.list()
  1142.       local sz = cChest.size()
  1143.       for o = 1,sz do
  1144.         if cur[o] and cur[o].name == name and cur[o].damage == dmg then
  1145.           if count-amountTransfered > 0 then
  1146.             if ( custom.useBothChestTypes or custom.useSingleChest ) and chests[i] == custom.chestSide then
  1147.               if custom.chestSide == "front" or custom.chestSide == "bottom" or custom.chestSide == "top" or custom.chestSide == "left" or custom.chestSide == "right" or custom.chestSide == "back" then
  1148.                 amountTransfered = amountTransfered + cChest.drop(o,count-amountTransfered)
  1149.               else
  1150.                 amountTransfered = amountTransfered + cChest.pushItems(tName,o,count-amountTransfered)
  1151.               end
  1152.             else
  1153.               amountTransfered = amountTransfered + cChest.pushItems(tName,o,count-amountTransfered)
  1154.             end
  1155.           end
  1156.           if custom.dropSide == "top" then
  1157.             turtle.dropUp()
  1158.           elseif custom.dropSide == "bottom" then
  1159.             turtle.dropDown()
  1160.           elseif custom.dropSide == "front" then
  1161.             turtle.drop()
  1162.           else
  1163.             logger.warn("dropSide not configured correctly, dropping from the front.")
  1164.             turtle.drop()
  1165.           end
  1166.           if amountTransfered >= count then
  1167.             return amountTransfered
  1168.           end
  1169.         end
  1170.         if amountTransfered >= count then
  1171.           return amountTransfered
  1172.         end
  1173.       end
  1174.     end
  1175.   end
  1176.   return amountTransfered
  1177. end
  1178.  
  1179. local function getPages()
  1180.   if custom.itemsDrawnAtOnce == 0 or #sIL == 0 then
  1181.     mxPages = 1
  1182.   else
  1183.     mxPages = math.ceil(#sIL/custom.itemsDrawnAtOnce)
  1184.   end
  1185. end
  1186.  
  1187. --Monitor
  1188.  
  1189.  
  1190. buttons = {
  1191.   cobble = {
  1192.     x1 = 29,
  1193.     y1 = mY-7,
  1194.     x2 = 41,
  1195.     y2 = mY-5,
  1196.     content = "Free Cobble (UNKNOWN)",
  1197.     enabled = false,
  1198.   },
  1199.   pgUp = {
  1200.     x1 = 17,
  1201.     y1 = mY-7,
  1202.     x2 = 27,
  1203.     y2 = mY-5,
  1204.     content = "Next Page",
  1205.     enabled = false,
  1206.   },
  1207.   pgDwn = {
  1208.     x1 = 5,
  1209.     y1 = mY-7,
  1210.     x2 = 15,
  1211.     y2 = mY-5,
  1212.     content = "Prev Page",
  1213.     enabled = false,
  1214.   },
  1215. }
  1216.  
  1217. local function refreshButtons()
  1218.   buttons.cobble.enabled = custom.touchHereForCobbleButton
  1219.   if custom.compactMode then
  1220.     if custom.drawBottomInfoBar then
  1221.       if buttons.cobble.enabled then
  1222.         buttons.cobble.y1 = mY-2
  1223.         buttons.cobble.y2 = mY-2
  1224.         buttons.cobble.x1 = 16
  1225.         buttons.cobble.content = "Free Cobble ("..cobCount..")"
  1226.         local b = buttons.cobble.content
  1227.         buttons.cobble.x1 = buttons.cobble.x1-b:len()/2-1
  1228.         buttons.cobble.x2 = buttons.cobble.x1+1+b:len()
  1229.         buttons.pgUp.y1 = mY-4
  1230.         buttons.pgUp.y2 = mY-4
  1231.         buttons.pgDwn.y1 = mY-4
  1232.         buttons.pgDwn.y2 = mY-4
  1233.       else
  1234.         buttons.pgUp.y1 = mY-3
  1235.         buttons.pgUp.y2 = mY-3
  1236.         buttons.pgDwn.y1 = mY-3
  1237.         buttons.pgDwn.y2 = mY-3
  1238.       end
  1239.     else
  1240.       if buttons.cobble.enabled then
  1241.         buttons.cobble.y1 = mY
  1242.         buttons.cobble.y2 = mY
  1243.         buttons.cobble.x1 = 16
  1244.         buttons.cobble.content = "Free Cobble ("..cobCount..")"
  1245.         local b = buttons.cobble.content
  1246.         buttons.cobble.x1 = buttons.cobble.x1-b:len()/2-1
  1247.         buttons.cobble.x2 = buttons.cobble.x1+1+b:len()
  1248.         buttons.pgUp.y1 = mY-2
  1249.         buttons.pgUp.y2 = mY-2
  1250.         buttons.pgDwn.y1 = mY-2
  1251.         buttons.pgDwn.y2 = mY-2
  1252.       else
  1253.         buttons.pgUp.y1 = mY
  1254.         buttons.pgUp.y2 = mY
  1255.         buttons.pgDwn.y1 = mY
  1256.         buttons.pgDwn.y2 = mY
  1257.       end
  1258.     end
  1259.   else
  1260.     if buttons.cobble.enabled then
  1261.       if custom.drawBottomInfoBar then
  1262.         buttons.cobble.y1 = mY-7
  1263.         buttons.cobble.y2 = mY-5
  1264.         buttons.cobble.x1 = 29
  1265.         buttons.cobble.content = "Free Cobble ("..cobCount..")"
  1266.         local b = buttons.cobble.content
  1267.         buttons.cobble.x2 = buttons.cobble.x1+1+b:len()
  1268.         buttons.pgUp.y1 = mY-7
  1269.         buttons.pgUp.y2 = mY-5
  1270.         buttons.pgDwn.y1 = mY-7
  1271.         buttons.pgDwn.y2 = mY-5
  1272.       else
  1273.         buttons.cobble.y1 = mY-3
  1274.         buttons.cobble.y2 = mY-1
  1275.         buttons.cobble.x1 = 29
  1276.         buttons.cobble.content = "Free Cobble ("..cobCount..")"
  1277.         local b = buttons.cobble.content
  1278.         buttons.cobble.x2 = buttons.cobble.x1+1+b:len()
  1279.         buttons.pgUp.y1 = mY-3
  1280.         buttons.pgUp.y2 = mY-1
  1281.         buttons.pgDwn.y1 = mY-3
  1282.         buttons.pgDwn.y2 = mY-1
  1283.       end
  1284.     else
  1285.       if custom.drawBottomInfoBar then
  1286.         buttons.pgUp.y1 = mY-7
  1287.         buttons.pgUp.y2 = mY-5
  1288.         buttons.pgDwn.y1 = mY-7
  1289.         buttons.pgDwn.y2 = mY-5
  1290.       else
  1291.         buttons.pgUp.y1 = mY-3
  1292.         buttons.pgUp.y2 = mY-1
  1293.         buttons.pgDwn.y1 = mY-3
  1294.         buttons.pgDwn.y2 = mY-1
  1295.       end
  1296.     end
  1297.   end
  1298.  
  1299.  
  1300. end
  1301.  
  1302. local function drawButton(BUTT)
  1303.   if BUTT.enabled then
  1304.     mon.setBackgroundColor(custom.buttons.bg)
  1305.     mon.setTextColor(custom.buttons.fg)
  1306.   else
  1307.     mon.setBackgroundColor(custom.disabledButtons.bg)
  1308.     mon.setTextColor(custom.disabledButtons.fg)
  1309.   end
  1310.   local dist = BUTT.x2 - BUTT.x1+1
  1311.   dist = string.rep(" ",dist)
  1312.   for o = BUTT.y1,BUTT.y2 do
  1313.     mon.setCursorPos(BUTT.x1,o)
  1314.     mon.write(dist)
  1315.   end
  1316.   mon.setCursorPos(BUTT.x1+(BUTT.x2-BUTT.x1)/2-(BUTT.content:len()/2)+0.5,BUTT.y1+(BUTT.y2-BUTT.y1)/2)
  1317.   mon.write(BUTT.content)
  1318. end
  1319.  
  1320. local function inBetween(x1,y1,x2,y2,x,y)
  1321.   return x >= x1 and x <= x2 and y >= y1 and y <= y2
  1322. end
  1323.  
  1324. local function whichPress(x,y)
  1325.   for k,v in pairs(buttons) do
  1326.     if v.enabled and inBetween(v.x1,v.y1,v.x2,v.y2,x,y) then
  1327.       return k
  1328.     end
  1329.   end
  1330.   return "None"
  1331. end
  1332.  
  1333. local function square(x1,y1,x2,y2,c)
  1334.   if c then
  1335.     mon.setBackgroundColor(c)
  1336.   end
  1337.   local dist = x2-x1+1
  1338.   dist = string.rep(" ",dist)
  1339.   for i = y1,y2 do
  1340.     mon.setCursorPos(x1,i)
  1341.     mon.write(dist)
  1342.   end
  1343. end
  1344.  
  1345. local function drawBG()
  1346.   local topPad = 3
  1347.   local botPad = 3
  1348.   if custom.compactMode then
  1349.     topPad = 1
  1350.     botPad = 1
  1351.   end
  1352.   mon.setBackgroundColor(custom.farthestBackground.bg)
  1353.   mon.clear()
  1354.   square(2,topPad+1,mX-1,mY,custom.background.bg)
  1355.   square(2,1,mX-1,topPad,custom.nameBar.bg)
  1356.   mon.setCursorPos(mX/2-(custom.shopName:len()/2),topPad/2+0.5)
  1357.   mon.setTextColor(custom.nameBar.fg)
  1358.   mon.write(custom.shopName)
  1359.   if custom.drawBottomInfoBar then
  1360.     square(2,mY-botPad,mX-1,mY,custom.infoBar.bg)
  1361.     mon.setTextColor(custom.infoBar.fg)
  1362.     local ln1y = mY-2
  1363.     local ln2y = mY-1
  1364.     if custom.compactMode then
  1365.       ln1y = mY-1
  1366.       ln2y = mY
  1367.     end
  1368.     if not custom.showCustomInfo then
  1369.       local ln1 = "This shop was made by fatmanchummy"
  1370.       local ln2 = "This shop is owned by "..custom.owner
  1371.       mon.setCursorPos(mX/2-(ln1:len()/2),ln1y)
  1372.       mon.write(ln1)
  1373.       mon.setCursorPos(mX/2-(ln2:len()/2),ln2y)
  1374.       mon.write(ln2)
  1375.     else
  1376.       if type(custom.customInfo[1]) == "string" then
  1377.         mon.setCursorPos(mX/2-(custom.customInfo[1]:len()/2),ln1y)
  1378.         mon.write(custom.customInfo[1])
  1379.         if type(custom.customInfo[2]) == "string" then
  1380.           mon.setCursorPos(mX/2-(custom.customInfo[2]:len()/2),ln2y)
  1381.           mon.write(custom.customInfo[2])
  1382.         end
  1383.       end
  1384.     end
  1385.   end
  1386. end
  1387.  
  1388. local function draw(sel,override)
  1389.   oldY = sel
  1390.   refreshButtons()
  1391.   local toDraw = custom.itemsDrawnAtOnce
  1392.   getPages()
  1393.   local skip = 7
  1394.   local infoBarHeight = 7
  1395.   local infoBarBottom = 5
  1396.   local infoBarWords = 6
  1397.   if custom.compactMode then
  1398.     skip = 3
  1399.     infoBarHeight = 3
  1400.     infoBarBottom = 3
  1401.     infoBarWords = 3
  1402.   end
  1403.   square(3,infoBarBottom,mX/2+3,infoBarHeight,custom.itemInfoBar.bg)
  1404.   mon.setTextColor(custom.itemInfoBar.fg)
  1405.   mon.setCursorPos(4,infoBarWords)
  1406.   mon.write("Item")
  1407.   mon.setCursorPos(mX/3-5,infoBarWords)
  1408.   mon.write("Stock")
  1409.   mon.setCursorPos(mX/2-2,infoBarWords)
  1410.   mon.write("Price")
  1411.   square(3,infoBarHeight+1,mX/2+3,(infoBarHeight+1)+toDraw,custom.background.bg)
  1412.   for i = 1,toDraw do
  1413.     local cur = i+(toDraw)*(page-1)
  1414.     local cur1 = cur
  1415.     cur = sIL[cur]
  1416.     if cur then
  1417.       if cur.count == 0 then
  1418.         if i%2 == 1 then
  1419.           square(3,i+skip,mX/2+3,i+skip,custom.itemTableEmptyStock1.bg)
  1420.           mon.setTextColor(custom.itemTableEmptyStock1.fg)
  1421.         else
  1422.           square(3,i+skip,mX/2+3,i+skip,custom.itemTableEmptyStock2.bg)
  1423.           mon.setTextColor(custom.itemTableEmptyStock2.fg)
  1424.         end
  1425.       else
  1426.         if i%2 == 1 then
  1427.           square(3,i+skip,mX/2+3,i+skip,custom.itemTableColor1.bg)
  1428.           mon.setTextColor(custom.itemTableColor1.fg)
  1429.         else
  1430.           square(3,i+skip,mX/2+3,i+skip,custom.itemTableColor2.bg)
  1431.           mon.setTextColor(custom.itemTableColor2.fg)
  1432.         end
  1433.       end
  1434.       mon.setCursorPos(4,i+skip)
  1435.       mon.write(cur.display)
  1436.       mon.setCursorPos(mX/3-tostring(cur.count):len(),i+skip)
  1437.       mon.write(tostring(cur.count))
  1438.       local a = tostring(cur.price):find("%.")
  1439.       mon.setCursorPos(mX/2,i+skip)
  1440.       mon.write(".00")
  1441.       if a then
  1442.         mon.setCursorPos(mX/2+a-3,i+skip)
  1443.       else
  1444.         mon.setCursorPos(mX/2-tostring(cur.price):len(),i+skip)
  1445.       end
  1446.       mon.write(tostring(cur.price))
  1447.     end
  1448.   end
  1449.   if not override then
  1450.     if page == mxPages then
  1451.       buttons.pgUp.enabled = false
  1452.     else
  1453.       buttons.pgUp.enabled = true
  1454.     end
  1455.     if page == 1 then
  1456.       buttons.pgDwn.enabled = false
  1457.     else
  1458.       buttons.pgDwn.enabled = true
  1459.     end
  1460.   end
  1461.   drawButton(buttons.pgUp)
  1462.   drawButton(buttons.pgDwn)
  1463.   local bigSelStart = 18
  1464.   local bigSelEnd = 25
  1465.   local displStart = 19
  1466.   if custom.compactMode then
  1467.     bigSelStart = 9
  1468.     bigSelEnd = 14
  1469.     displStart = 9
  1470.   end
  1471.   if sel then
  1472.     local i = sel-skip
  1473.     selection = i+(page-1)*(toDraw)
  1474.     local cur = sIL[selection]
  1475.     if cur and i <= toDraw then
  1476.       if cur.count == 0 then
  1477.         square(3,sel,mX/2+3,sel,custom.selectedEmptyStock.bg)
  1478.         mon.setTextColor(custom.selectedEmptyStock.fg)
  1479.       else
  1480.         square(3,sel,mX/2+3,sel,custom.selection.bg)
  1481.         mon.setTextColor(custom.selection.fg)
  1482.       end
  1483.       mon.setCursorPos(4,i+skip)
  1484.       mon.write(cur.display)
  1485.       mon.setCursorPos(mX/3-tostring(cur.count):len(),i+skip)
  1486.       mon.write(tostring(cur.count))
  1487.       local a = tostring(cur.price):find("%.")
  1488.       mon.setCursorPos(mX/2,i+skip)
  1489.       mon.write(".00")
  1490.       if a then
  1491.         mon.setCursorPos(mX/2+a-3,i+skip)
  1492.       else
  1493.         mon.setCursorPos(mX/2-tostring(cur.price):len(),i+skip)
  1494.       end
  1495.       mon.write(tostring(cur.price))
  1496.  
  1497.       if cur.count == 0 then
  1498.         square(mX/2+5,bigSelStart,mX-5,bigSelEnd,custom.bigSelectionEmptyStock.bg)
  1499.         mon.setTextColor(custom.bigSelectionEmptyStock.fg)
  1500.       else
  1501.         square(mX/2+5,bigSelStart,mX-5,bigSelEnd,custom.bigSelection.bg)
  1502.         mon.setTextColor(custom.bigSelection.fg)
  1503.       end
  1504.       mon.setCursorPos(mX/2+6,displStart)
  1505.       mon.write(cur.display)
  1506.       mon.setCursorPos(mX/2+6,displStart+1)
  1507.       mon.write(tostring(cur.price).."KST each")
  1508.       mon.setCursorPos(mX/2+6,displStart+2)
  1509.       mon.write("x"..tostring(cur.count))
  1510.       mon.setCursorPos(mX/2+6,displStart+3)
  1511.       local tPrice = math.ceil(cur.count*cur.price)
  1512.       mon.write("Whole stock price: "..tostring(tPrice))
  1513.       if cur.price < 1 then
  1514.         mon.setCursorPos(mX/2+6,displStart+4)
  1515.         mon.write("Items for 1 KST: "..tostring(math.floor(1/cur.price+0.5)))
  1516.       end
  1517.       mon.setCursorPos(mX/2+6,displStart+5)
  1518.       mon.write("/pay "..pubKey.." "..tPrice)
  1519.     else
  1520.       square(mX/2+5,bigSelStart,mX-5,bigSelEnd,custom.background.bg)
  1521.     end
  1522.   else
  1523.     square(mX/2+5,bigSelStart,mX-5,bigSelEnd,custom.background.bg)
  1524.   end
  1525.  
  1526.   local bigInfoBegin = 8
  1527.   local bigInfoEnd = 16
  1528.   local inform = 9
  1529.   local bistart = 11
  1530.   if custom.compactMode then
  1531.     bigInfoBegin = 3
  1532.     bigInfoEnd = 7
  1533.     inform = 3
  1534.     bistart = 4
  1535.   end
  1536.  
  1537.   square(mX/2+5,bigInfoBegin,mX-5,bigInfoEnd,custom.bigInfo.bg)
  1538.   mon.setTextColor(custom.bigInfo.fg)
  1539.   mon.setCursorPos((3*mX)/4-6,inform)
  1540.   mon.write("Information")
  1541.   if custom.showCustomBigInfo then
  1542.     for i = 1,4 do
  1543.       custom.customBigInfo[i] = custom.customBigInfo[i]:gsub("PUBKEY",pubKey)
  1544.     end
  1545.     mon.setCursorPos((3*mX)/4-custom.customBigInfo[1]:len()/2,bistart)
  1546.     mon.write(custom.customBigInfo[1])
  1547.     mon.setCursorPos((3*mX)/4-custom.customBigInfo[2]:len()/2,bistart+1)
  1548.     mon.write(custom.customBigInfo[2])
  1549.     mon.setCursorPos((3*mX)/4-custom.customBigInfo[3]:len()/2,bistart+2)
  1550.     mon.write(custom.customBigInfo[3])
  1551.     mon.setCursorPos((3*mX)/4-custom.customBigInfo[4]:len()/2,bistart+3)
  1552.     mon.write(custom.customBigInfo[4])
  1553.   else
  1554.     local ln1 = "This shop's address is:"
  1555.     local ln2 = pubKey
  1556.     local ln3 = "Send Krist to this address after"
  1557.     local ln4 = "selecting an item to buy."
  1558.     mon.setCursorPos((3*mX)/4-ln1:len()/2,bistart)
  1559.     mon.write(ln1)
  1560.     mon.setCursorPos((3*mX)/4-ln2:len()/2,bistart+1)
  1561.     mon.write(ln2)
  1562.     mon.setCursorPos((3*mX)/4-ln3:len()/2,bistart+2)
  1563.     mon.write(ln3)
  1564.     mon.setCursorPos((3*mX)/4-ln4:len()/2,bistart+3)
  1565.     mon.write(ln4)
  1566.   end
  1567.   if custom.touchHereForCobbleButton then
  1568.     buttons.cobble.enabled = true
  1569.     drawButton(buttons.cobble)
  1570.   end
  1571. end
  1572.  
  1573.  
  1574. if true then
  1575.  
  1576.   local selection = false
  1577.   local s2 = false
  1578.  
  1579.   local oCT = {
  1580.     [1] = {color = colors.pink,x = mX/2-11,y = 4,y2 = 12,},
  1581.     [2] = {color = colors.magenta,x = mX/2-8,y = 4,y2 = 12,},
  1582.     [3] = {color = colors.purple,x = mX/2-5,y = 4,y2 = 12,},
  1583.     [4] = {color = colors.lightBlue,x = mX/2-2,y = 4,y2 = 12,},
  1584.     [5] = {color = colors.cyan,x = mX/2+1,y = 4,y2 = 12,},
  1585.     [6] = {color = colors.blue,x = mX/2+4,y = 4,y2 = 12,},
  1586.     [7] = {color = colors.green,x = mX/2+7,y = 4,y2 = 12,},
  1587.     [8] = {color = colors.lime,x = mX/2+10,y = 4,y2 = 12,},
  1588.     [9] = {color = colors.yellow,x = mX/2-11,y = 7,y2 = 15,},
  1589.     [10] = {color = colors.orange,x = mX/2-8,y = 7,y2 = 15,},
  1590.     [11] = {color = colors.red,x = mX/2-5,y = 7,y2 = 15,},
  1591.     [12] = {color = colors.brown,x = mX/2-2,y = 7,y2 = 15,},
  1592.     [13] = {color = colors.white,x = mX/2+1,y = 7,y2 = 15,},
  1593.     [14] = {color = colors.lightGray,x = mX/2+4,y = 7,y2 = 15,},
  1594.     [15] = {color = colors.gray,x = mX/2+7,y = 7,y2 = 15,},
  1595.     [16] = {color = colors.black,x = mX/2+10,y = 7,y2 = 15,},
  1596.     cancel = {color = colors.blue,y1=mY/2+4,y2=mY/2+6,contain = "cancel",},
  1597.   }
  1598.  
  1599.   local function getColorPress(x,y,selected)
  1600.     local y1 = oCT[1].y
  1601.     local y2 = oCT[9].y
  1602.     local yy1 = oCT[1].y2
  1603.     local yy2 = oCT[9].y2
  1604.     if type(selected) == "table" then
  1605.       if type(selected.bg) == "number" then
  1606.         for i = 1,8 do
  1607.           if inBetween(oCT[i].x,y1,oCT[i].x+1,y1+1,x,y) then
  1608.             return i,1
  1609.           end
  1610.         end
  1611.         for i = 9,16 do
  1612.           if inBetween(oCT[i].x,y2,oCT[i].x+1,y2+1,x,y) then
  1613.             return i,1
  1614.           end
  1615.         end
  1616.       end
  1617.       --------------------
  1618.       if type(selected.fg) == "number" then
  1619.         for i = 1,8 do
  1620.           if inBetween(oCT[i].x,yy1,oCT[i].x+1,yy1+1,x,y) then
  1621.             return i,2
  1622.           end
  1623.         end
  1624.         for i = 9,16 do
  1625.           if inBetween(oCT[i].x,yy2,oCT[i].x+1,yy2+1,x,y) then
  1626.             return i,2
  1627.           end
  1628.         end
  1629.       end
  1630.     end
  1631.     if inBetween(mX/2-oCT.cancel.contain:len()/2-2.5,mY/2+4,mX/2+oCT.cancel.contain:len()/2-0.5,mY/2+6,x,y) then
  1632.       selection = false
  1633.     end
  1634.   end
  1635.  
  1636.   local function drawColorBox(colorBox,iter)
  1637.     local iterD = "y"
  1638.     if iter ~= 1 then
  1639.       iterD = "y2"
  1640.     end
  1641.     mon.setBackgroundColor(colorBox.color)
  1642.     mon.setCursorPos(colorBox.x,colorBox[iterD])
  1643.     mon.write("  ")
  1644.     mon.setCursorPos(colorBox.x,colorBox[iterD]+1)
  1645.     mon.write("  ")
  1646.   end
  1647.  
  1648.   local function drawBoxColors2(writ,selected)
  1649.     square(mX/2-11.5,11,mX/2+12.5,17,colors.black)
  1650.     mon.setCursorPos(mX/2-writ:len()/2+0.5,11)
  1651.     mon.setTextColor(colors.white)
  1652.     mon.write(writ)
  1653.     for i = 1,16 do
  1654.       drawColorBox(oCT[i],2)
  1655.     end
  1656.   end
  1657.  
  1658.   local function drawBoxColors1(writ,selected)
  1659.     square(mX/2-11.5,3,mX/2+12.5,9,colors.black)
  1660.     mon.setCursorPos(mX/2-writ:len()/2+0.5,3)
  1661.  
  1662.     mon.setTextColor(colors.white)
  1663.     mon.write(writ)
  1664.  
  1665.     for i = 1,16 do
  1666.       drawColorBox(oCT[i],1)
  1667.     end
  1668.   end
  1669.  
  1670.  
  1671.   local function drawColors(selected)
  1672.     if type(selected) == "table" then
  1673.       drawBoxColors1("BACKGROUND",selected)
  1674.       if selected.fg then
  1675.         drawBoxColors2("TEXT",selected)
  1676.       end
  1677.     end
  1678.     mon.setBackgroundColor(colors.blue)
  1679.     if selected ~= nil and type(selected) ~= "boolean" then
  1680.       for i = 1,3 do
  1681.         mon.setCursorPos(mX/2-oCT.cancel.contain:len()/2-1.5,mY/2+3+i)
  1682.         mon.write(string.rep(" ",oCT.cancel.contain:len()+2))
  1683.       end
  1684.       mon.setCursorPos(mX/2-oCT.cancel.contain:len()/2-0.5,mY/2+5)
  1685.       mon.write(oCT.cancel.contain)
  1686.     end
  1687.   end
  1688.  
  1689.  
  1690.   local function select(x,y)
  1691.     if x == 1 or x == mX then
  1692.       selection = custom.farthestBackground
  1693.       s2 = "farthestBackground"
  1694.     elseif inBetween(2,1,mX-1,3,x,y) then
  1695.       selection = custom.nameBar
  1696.       s2 = "nameBar"
  1697.     elseif inBetween(2,mY-3,mX-1,mY,x,y) then
  1698.       selection = custom.infoBar
  1699.       s2 = "infoBar"
  1700.     elseif inBetween(3,5,mX/2+3,7,x,y) then
  1701.       selection = custom.itemInfoBar
  1702.       s2 = "itemInfoBar"
  1703.     elseif inBetween(3,8,mX/2+3,8,x,y) then
  1704.       selection = custom.itemTableColor1
  1705.       s2 = "itemTableColor1"
  1706.     elseif inBetween(3,9,mX/2+3,9,x,y) then
  1707.       selection = custom.itemTableColor2
  1708.       s2 = "itemTableColor2"
  1709.     elseif inBetween(3,10,mX/2+3,10,x,y) then
  1710.       selection = custom.selection
  1711.       s2 = "selection"
  1712.     elseif inBetween(3,11,mX/2+3,11,x,y) then
  1713.       selection = custom.itemTableEmptyStock2
  1714.       s2 = "itemTableEmptyStock2"
  1715.     elseif inBetween(3,12,mX/2+3,12,x,y) then
  1716.       selection = custom.itemTableEmptyStock1
  1717.       s2 = "itemTableEmptyStock1"
  1718.     elseif inBetween(mX/2+5,18,mX-5,25,x,y) then
  1719.       selection = custom.bigSelection
  1720.       s2 = "bigSelection"
  1721.     elseif inBetween(mX/2+5,8,mX-5,16,x,y) then
  1722.       selection = custom.bigInfo
  1723.       s2 = "bigInfo"
  1724.     elseif inBetween(5,mY-7,15,mY-5,x,y) then
  1725.       selection = custom.disabledButtons
  1726.       s2 = "disabledButtons"
  1727.     elseif inBetween(17,mY-7,27,mY-5,x,y)  then
  1728.       selection = custom.buttons
  1729.       s2 = "buttons"
  1730.     elseif inBetween(2,4,mX-1,mY-4,x,y) then--FINAL ELSEIF
  1731.       selection = custom.background
  1732.       s2 = "background"
  1733.     end
  1734.   end
  1735.  
  1736.  
  1737.   if tArgs[1] == "setupVisuals" then
  1738.     custom = dofile(fatCustomization)
  1739.     local oldCobble = custom.touchHereForCobbleButton
  1740.     local oldCompact = custom.compactMode
  1741.     local oldName = custom.shopName
  1742.     custom.touchHereForCobbleButton = false
  1743.     custom.compactMode = false
  1744.     custom.shopName = "Tap somewhere to change it's colors!"
  1745.     buttons.pgUp.content = "Enabled"
  1746.     buttons.pgUp.enabled = true
  1747.     buttons.pgDwn.content = "Disabled"
  1748.     buttons.pgDwn.enabled = false
  1749.     sIL = {
  1750.       {
  1751.         display = "Item List 1",
  1752.         find = "minecraft:cobblestone",
  1753.         damage = 0,
  1754.         price = 1.5,
  1755.         count = 100,
  1756.       },
  1757.       {
  1758.         display = "Item List 2",
  1759.         find = "minecraft:iron_ingot",
  1760.         damage = 0,
  1761.         price = 0.5,
  1762.         count = 5,
  1763.       },
  1764.       {
  1765.         display = "Selected Item",
  1766.         find = "minecraft:logs",
  1767.         damage = 0,
  1768.         price = 0.01,
  1769.         count = 9999,
  1770.       },
  1771.       {
  1772.         display = "Empty Stock Item 2",
  1773.         find = "minecraft:fuck",
  1774.         damage = 0,
  1775.         price = 100,
  1776.         count = 0,
  1777.       },
  1778.       {
  1779.         display = "Empty Stock Item 1",
  1780.         find = "minecraft:empty",
  1781.         damage = 0,
  1782.         price = 1000,
  1783.         count = 0,
  1784.       },
  1785.     }
  1786.     drawBG()
  1787.     draw(10,true)
  1788.     term.clear()
  1789.     term.setCursorPos(1,1)
  1790.     logger.info("Entering Visual Setup")
  1791.     print("Press the \"t\" key to exit.")
  1792.     print("This may not support smaller screens.")
  1793.     while true do
  1794.       drawBG()
  1795.       draw(10,true)
  1796.       drawColors(selection)
  1797.       local event = ({os.pullEvent()})
  1798.       if event[1] == "key" and event[2] == keys.t then
  1799.         mon.setBackgroundColor(custom.farthestBackground.bg)
  1800.         mon.clear()
  1801.         mon.setTextColor(custom.background.fg)
  1802.         mon.setTextScale(2)
  1803.         mon.setCursorPos(1,1)
  1804.         mon.write("Exiting customization.")
  1805.         break
  1806.       end
  1807.       if selection then
  1808.         if event[1] == "monitor_touch" then
  1809.           local index, bfg = getColorPress(event[3],event[4],selection)
  1810.           if index ~= nil then
  1811.             if bfg == 1 then
  1812.               custom[s2].bg = oCT[index].color
  1813.             elseif bfg == 2 then
  1814.               custom[s2].fg = oCT[index].color
  1815.             end
  1816.           end
  1817.         end
  1818.       else
  1819.         if event[1] == "monitor_touch" then
  1820.           select(event[3],event[4])
  1821.         end
  1822.       end
  1823.  
  1824.     end
  1825.     logger.info("Done, saving settings.")
  1826.     custom.touchHereForCobbleButton = oldCobble
  1827.     custom.shopName = oldName
  1828.     custom.compactMode = oldCompact
  1829.     fixCustomization()
  1830.     return 1
  1831.   end
  1832. end
  1833.  
  1834.  
  1835.  
  1836.  
  1837. -------------BEGIN-------------
  1838. checkAllTheThings()
  1839. sortItems()
  1840. local ten = pcall(doRefresh)
  1841.  
  1842. if not ten then
  1843.   logger.warn("Failed initial refresh check.  Auto reboot if next fails.")
  1844.   refreshCheck = true
  1845. end
  1846. drawBG()
  1847.  
  1848.  
  1849.  
  1850. local function writeLine(txt)
  1851.   local bX,bY = mon.getCursorPos()
  1852.   mon.write(txt)
  1853.   mon.setCursorPos(1,bY+1)
  1854. end
  1855. local function bsod(err)
  1856.   mon.setTextScale(0.5)
  1857.   mon.setBackgroundColor(colors.blue)
  1858.   mon.setTextColor(colors.white)
  1859.   mon.clear()
  1860.   local mxX,mxY = mon.getSize()
  1861.   mon.setCursorPos(1,mxY/2)
  1862.   writeLine("The shop encountered an error it could not recover from")
  1863.   writeLine(err)
  1864. end
  1865.  
  1866.  
  1867.  
  1868.  
  1869.  
  1870.  
  1871. local function doPurchase(data,updoot)
  1872.   local tx = data.transaction or json.decode(data)
  1873.   local meta = nil
  1874.   local tf = false
  1875.   if tx.metadata then
  1876.     meta = k.parseMeta(tx.metadata)
  1877.   else
  1878.     meta = {meta = {}}
  1879.   end
  1880.   if not meta or not meta.meta or not meta.meta["return"] then
  1881.     returnTo = tx.from
  1882.   else
  1883.     returnTo = meta.meta["return"]
  1884.   end
  1885.   if meta.meta.username then
  1886.     tf = true
  1887.   end
  1888.   if selection and tx.to == pubKey then
  1889.     logger.info("Payment being processed.")
  1890.     local item = sIL[selection]
  1891.     if item.count > 0 then
  1892.       local paid = tx.value
  1893.       local items_required = math.floor(paid/item.price)
  1894.       local items_grabbed = grabItems(item.find,item.damage,items_required)
  1895.       if items_grabbed > 0 then
  1896.         logger.purchaseLog(item.find..":"..item.damage,items_grabbed,paid,meta.meta.username or tx.from,tf)
  1897.       end
  1898.       local over = paid%item.price
  1899.       local refundAmt = math.floor((items_required - items_grabbed)*item.price+over)
  1900.  
  1901.       if item.price > paid then
  1902.         refund(returnTo,tx.value,custom.REFUNDS.underpay,false)
  1903.       else
  1904.         if refundAmt > 0 then
  1905.           refund(returnTo,refundAmt,custom.REFUNDS.change,true)
  1906.           logger.purchase("Sent refund of "..refundAmt.." due to overpay.")
  1907.         end
  1908.       end
  1909.       if custom.doPurchaseForwarding and items_grabbed*item.price > 0  then
  1910.         refund(custom.purchaseForwardingAddress,math.ceil(items_grabbed*item.price),(meta.meta.username and "player "..meta.meta.username.." bought "..tostring(items_grabbed).." of "..item.display.." at "..custom.shopName ) or ( tx.from and "address "..tx.from.." bought "..tostring(items_grabbed).." of "..item.display.." at "..custom.shopName ) or "Purchase-Forwarding ("..custom.shopName..")",true )
  1911.       end
  1912.     else
  1913.       if updoot then
  1914.         refund(returnTo,tx.value,custom.REFUNDS.UPDATE,false)
  1915.         logger.purchase("Sent refund of "..tx.value.."due to UPDATING_STOCKS")
  1916.       else
  1917.         refund(returnTo,tx.value,custom.REFUNDS.outOfStock,false)
  1918.         logger.purchase("Sent refund of "..tx.value.." due to not having the item selected.")
  1919.       end
  1920.     end
  1921.   else
  1922.     if tx.to == pubKey then
  1923.       logger.purchase("No item selected, but we were payed!  Returning...")
  1924.       if returnTo then
  1925.         refund(returnTo,tx.value,custom.REFUNDS.noItemSelected,false)
  1926.       end
  1927.     end
  1928.   end
  1929. end
  1930.  
  1931.  
  1932. local function redraw()
  1933.   logger.info("Redraw")
  1934.   mon.setCursorPos(1,1)
  1935.   mon.setBackgroundColor(custom.farthestBackground.bg ~= colors.red and colors.red or colors.blue)
  1936.   mon.write(" ")
  1937.   parallel.waitForAll(
  1938.   function()
  1939.     sIL = refreshItems()
  1940.     if recentPressCount == 0 then selection = false recentPress = false oldY = false end
  1941.     if recentPress then
  1942.       draw(oldY)
  1943.       recentPressCount = recentPressCount - 1
  1944.     else
  1945.       draw()
  1946.     end
  1947.   end)
  1948.   mon.setBackgroundColor(custom.farthestBackground.bg)
  1949.   mon.setCursorPos(1,1)
  1950.   mon.write(" ")
  1951. end
  1952.  
  1953.  
  1954.  
  1955.  
  1956. local function mainJua()
  1957.   jua.on("timer",function(evt,tmr)
  1958.     if tmr == purchaseTimer then
  1959.       mon.setCursorPos(1,2)
  1960.       mon.setBackgroundColor(custom.farthestBackground.bg)
  1961.       mon.write(" ")
  1962.     end
  1963.   end)
  1964.  
  1965.  
  1966.   jua.on("monitor_resize",function()
  1967.     mX,mY = mon.getSize()
  1968.     refreshButtons()
  1969.     drawBG()
  1970.     draw()
  1971.   end)
  1972.  
  1973.   jua.on("monitor_touch",function(nm,side,x,y)
  1974.     if side == mName then
  1975.       recentPress = true
  1976.       recentPressCount = 3
  1977.       local pressed = whichPress(x,y)
  1978.       local max = #sIL
  1979.       if inBetween(3,1,mX/2+3,mY,x,y) then
  1980.         draw(y)
  1981.       end
  1982.       if pressed == "pgUp" then
  1983.         page = page + 1
  1984.         draw()
  1985.       elseif pressed == "pgDwn" then
  1986.         page = page - 1
  1987.         draw()
  1988.       elseif pressed == "cobble" then
  1989.         grabItems("minecraft:cobblestone",0,64)
  1990.       end
  1991.     end
  1992.   end)
  1993.  
  1994.   jua.on("terminate",function()
  1995.     if ws then ws.close() end
  1996.     jua.stop()
  1997.     bsod("Terminated")
  1998.     logger.severe("Why would you terminate me like this?")
  1999.     if logger.canLogBeOpened then
  2000.       logger.closeLog()
  2001.     end
  2002.     if logger.canPurchaseLogBeOpened then
  2003.       logger.closePurchaseLog()
  2004.     end
  2005.     printError("I can't believe you've done this.")
  2006.   end)
  2007.  
  2008.  
  2009.   jua.go(function()
  2010.     local success,ws = await(k.connect,privKey)
  2011.     if success then
  2012.       logger.info("Connected to websocket")
  2013.       ws.on("hello",function(data)
  2014.         logger.info("MOTD: "..data.motd)
  2015.         local success = await(ws.subscribe,"transactions",function(data)
  2016.           doPurchase(data)
  2017.           mon.setCursorPos(1,2)
  2018.           mon.setBackgroundColor(custom.farthestBackground.bg ~= colors.blue and colors.blue or colors.red)
  2019.           mon.write(" ")
  2020.           purchaseTimer = os.startTimer(3)
  2021.         end)
  2022.         logger.ree()
  2023.         if success then
  2024.           logger.info("Subscribed to transactions")
  2025.         else
  2026.           jua.stop()
  2027.           logger.severe("Failed to subscribe")
  2028.           error()
  2029.         end
  2030.       end)
  2031.     else
  2032.       jua.stop()
  2033.       logger.severe("Failed to connect to kriststuff")
  2034.       error()
  2035.     end
  2036.   end)
  2037. end
  2038.  
  2039. --------------------------
  2040.  
  2041.  
  2042.  
  2043. local function para()
  2044.   parallel.waitForAny(mainJua,function()
  2045.   os.sleep(3)
  2046.     redraw()
  2047.     local tim = os.startTimer(10)
  2048.     while true do
  2049.       local event = {os.pullEvent("timer")}
  2050.       if event[2] == tim then
  2051.         redraw()
  2052.         tim = os.startTimer(10)
  2053.       end
  2054.     end
  2055.   end)
  2056. end
  2057.  
  2058. local suc,err = pcall(para)
  2059. if not suc then
  2060.   logger.severe(err)
  2061.   bsod(err)
  2062.   if logger.canLogBeOpened then
  2063.     logger.closeLog()
  2064.   end
  2065.   if logger.canPurchaseLogBeOpened then
  2066.     logger.closePurchaseLog()
  2067.   end
  2068.   if err ~= "Terminated" and not err:find("errors on the network") then
  2069.     writeLine("Reboot in 30 seconds.")
  2070.     os.sleep(30)
  2071.     os.reboot()
  2072.   end
  2073.   if err:find("errors on the network") then
  2074.     writeLine("This is caused when a chest is on the edge of a chunk")
  2075.     writeLine("Where the modem is in one chunk, and the chest is in another.")
  2076.     writeLine("The shop itself cannot fix this error; the chest must be moved.")
  2077.   end
  2078. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement