From 8bbde6c44b408624c905c6d482f9871b2f8f9f7a Mon Sep 17 00:00:00 2001
From: ubq323 <ubq323@ubq323.website>
Date: Mon, 2 Jan 2023 17:35:01 +0000
Subject: shop2

---
 shop2.lua | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 196 insertions(+)
 create mode 100644 shop2.lua

diff --git a/shop2.lua b/shop2.lua
new file mode 100644
index 0000000..cb1b453
--- /dev/null
+++ b/shop2.lua
@@ -0,0 +1,196 @@
+local key=assert(settings.get"krist.pkey","please set private key")
+
+-- ac.kst
+local OURNAME = "ac"
+local ITEMS = {}
+local function i(adr,itname,hname,price)
+	ITEMS[adr]={itname=itname,hname=hname,price=price,adr=adr}
+end
+i("dmn","minecraft:diamond","Diamond",5)
+i("blz","minecraft:blaze_rod","Blaze Rod",10)
+i("ely","minecraft:elytra","Elytra",200)
+i=nil
+
+
+local chest = peripheral.wrap"back"
+local function take_stock()
+	-- if you do this in parallel, you avoid having to wait 1 tick for each
+	-- slot of the chest. which is probably good.
+	local out = {}
+	local fns = {}
+	for i=1,chest.size() do
+		fns[i] = function() out[i] = chest.getItemDetail(i) end
+	end
+	parallel.waitForAll(unpack(fns))
+	return out
+end
+
+
+local sres =textutils.unserializeJSON( http.post("https://krist.dev/ws/start","privatekey="..key).readAll())
+assert(sres.ok,"not ok")
+
+local ws = assert(http.websocket(sres.url))
+local nextid = 0
+local our_addr = "???"
+
+local function sendws(t)
+	t.id = nextid
+	nextid = nextid + 1
+	return ws.send(textutils.serializeJSON(t))
+end
+
+sendws{type="me"}
+
+local function parsemeta(m)
+	local out = {}
+	for s in string.gmatch(m..";","(.-);") do
+		local k,v = s:match"^(.-)=(.-)$"
+		if k==nil then
+			out.recipient = s
+		else
+			out[k]=v
+		end
+	end
+	return out
+end
+
+-- XXX
+local function stock_amt(item)
+	local out = 0
+	for i=1,16 do
+		local x = turtle.getItemDetail(i)
+		if x and x.name == ITEM then out = out + x.count end
+	end
+	return out
+end
+
+-- XXX
+local function give(amt)
+	amt = amt or 1
+	-- assumes that we have at least amt in stock already
+	for i=1,16 do
+		local x = turtle.getItemDetail(i)
+		if x and x.name == ITEM then
+			local a = math.min(amt,x.count)
+			turtle.select(i)
+			turtle.drop(a)
+			amt = amt - a
+			if amt <= 0 then break end
+		end
+	end
+end
+
+local function proctrans(tr)
+	if tr.to ~= our_addr then return end
+	if tr.type ~= "transfer" then return end
+	if tr.sent_name ~= OURNAME then return end
+	local meta = parsemeta(tr.metadata)
+	local function tell(msg) if meta.username then chatbox.tell(meta.username,msg) end end
+	local function refund() if meta['return'] then sendws { type="make_transaction", to=meta['return'], amount=tr.value } end end
+
+	local mtn = tr.sent_metaname
+	
+
+	local remainder = tr.value % PRICE
+	if remainder ~= 0 then
+		tell("i can only give you a whole number of items. make sure the amount you gave me is a multiple of "..PRICE)
+		refund()
+	else
+		local in_stock = stock_amt()
+		if in_stock == 0 then
+			tell("we are out of stock! please yell at ubq323 about this")
+			refund()
+		else
+			local to_give = math.floor(tr.value / PRICE)
+			if to_give > in_stock then
+				tell("i don't have that many items in stock, sorry")
+				refund()
+			else
+				give(to_give)
+				tell("thank you!!! :3")
+			end
+		end
+	end
+end
+
+local function run_shop()
+	while true do
+		msgtxt = assert(ws.receive(),"ws error")
+		msg = textutils.unserializeJSON(msgtxt)
+		if msg.type == "response" and msg.responding_to_type == "me" then
+			our_addr = msg.address.address
+		end
+		if msg.type == "event" and msg.event == "transaction" then
+			proctrans(msg.transaction)
+		end
+	end
+end
+
+local function run_topdisp()
+
+	local mtop = peripheral.wrap"top"
+	mtop.setPaletteColor(colors.cyan,0x00FFFF)
+	while true do
+		mtop.setTextScale(5)
+		mtop.setTextColor(colors.cyan)
+		mtop.setCursorPos(1,1)
+		mtop.write"DIAMONDS"
+
+		os.sleep(0.75)
+		mtop.clear()
+		os.sleep(0.25)
+
+		mtop.setTextScale(4)
+		mtop.setTextColor(colors.white)
+		mtop.setCursorPos(1,1)
+		mtop.write("5KST EACH")
+
+		os.sleep(0.75)
+		mtop.clear()
+		os.sleep(0.25)
+	end
+end
+
+local function run_sidedisp()
+	local m = peripheral.wrap("left")
+	local function printseq(q)
+		for _,v in ipairs(q) do
+			if type(v) == "number" then
+				m.setTextColor(v)
+			elseif type(v) == "table" then
+				m.setCursorPos(v[1],v[2])
+			else -- str
+				m.write(v)
+			end
+		end
+	end
+	while true do
+		local sa = stock_amt()
+		m.clear()
+		printseq {
+			{7,1}, colors.orange, "UBQ323", {3,2}, "DIAMOND STORE",
+			{9,3}, "!!!",
+			{1,5}, colors.white, "stock: ", colors.yellow, ""..sa,
+			{1,6}, colors.white, "price: ", colors.yellow, ""..PRICE, colors.white, "kst/item"
+		}
+		if sa > 0 then
+			printseq {
+				{2,8}, colors.blue, "/pay d@ac.kst "..PRICE,
+				{2,9}, colors.gray, "(or a multiple",{6,10}," of "..PRICE..")",
+			}
+		else
+			printseq {
+				{3,8}, colors.red, "out of stock!",
+				{2,9}, "please come back",{7,10},"soon."
+			}
+			
+		end
+		os.sleep(2)
+		
+	end
+end
+
+print(pcall(parallel.waitForAny,run_shop, run_topdisp, run_sidedisp))
+print("hi")
+peripheral.call("top","clear")
+peripheral.call("left","clear")
-- 
cgit v1.2.3