summaryrefslogtreecommitdiff
path: root/shop2
diff options
context:
space:
mode:
Diffstat (limited to 'shop2')
-rw-r--r--shop2/disp.lua80
-rw-r--r--shop2/main.lua163
-rw-r--r--shop2/stock.lua39
3 files changed, 282 insertions, 0 deletions
diff --git a/shop2/disp.lua b/shop2/disp.lua
new file mode 100644
index 0000000..5260cdc
--- /dev/null
+++ b/shop2/disp.lua
@@ -0,0 +1,80 @@
+local ourname = "ac.kst"
+
+local function printseq(m) return function(q)
+ for _,v in ipairs(q) do
+ print(type(v),v)
+ if type(v) == "number" then
+ m.setTextColor(v)
+ elseif type(v) == "string" then
+ m.write(v)
+ elseif type(v) == "table" then
+ if #v == 2 then
+ -- position
+ m.setCursorPos(v[1],v[2])
+ else
+ error("unknown format")
+ end
+ end
+ end
+end end
+
+local function pad(s,n)
+ s=tostring(s)
+ local l = #s
+ local p = string.rep(" ",math.max(0,n-l))
+ return p..s
+end
+local function centre(s,w)
+ s=tostring(s)
+ local l = #s
+ local p = math.floor(math.max(0,w-l)/2)
+ return string.rep(" ",p)..s
+end
+
+local function disp_shopscreen(items)
+ -- i don't like how hardcoded all the spacing is in this
+ -- but i also don't feel like rewriting it yet.
+ local m = peripheral.wrap"left"
+ m.clear()
+ m.setTextScale(0.5)
+ -- Stock Price Adr. Name
+ -- xxxx xxxkst dmn Diamond
+ -- 123456789012345678901234567890123456789012345678901234567
+ -- 0 1 2 3 4 5
+
+ -- local function fmt_row(m,y, stock,price,adr,name, colour)
+ local function fmt_row(m,y, idesc,
+ colour = colour or colors.cyan
+ printseq(m) {
+ {1,y}, colors.white, pad(stock,5),
+ {8,y}, colors.yellow, pad(price,3), colors.lightGray, "kst",
+ {16,y}, colour, adr,
+ {22,y}, colour, name,
+ }
+ end
+
+
+ printseq(m) {
+ {1,1}, colors.orange, "Apiaristics Consortium Store",
+ {1,2}, colors.lightGray, "Stock Price Adr. Name",
+ }
+
+ -- sort alphabetically
+ -- todo: more intuitive sort, once more things are for sale
+ --
+ for ix,i in ipairs() do
+ fmt_row(m,ix+2,i[6],i[2],i[1],i[4],i[5])
+ end
+
+ local w,h = m.getSize()
+
+ printseq(m) {
+ {1,h-1}, colors.blue, centre("/pay <adr>@ac.kst <amount>",w)
+ }
+
+
+
+
+end
+
+disp_shopscreen()
diff --git a/shop2/main.lua b/shop2/main.lua
new file mode 100644
index 0000000..e79872c
--- /dev/null
+++ b/shop2/main.lua
@@ -0,0 +1,163 @@
+local key=assert(settings.get"krist.pkey","please set private key")
+local pp = require"cc.pretty".pretty_print
+
+-- 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 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
+
+local chest
+for _,name in ipairs(peripheral.getNames()) do
+ if name:match("chest") then chest = peripheral.wrap(name) break end
+end
+assert(chest,"couldn't find chest")
+-- might not work if there are multiple modems but why would you do that
+local localname = peripheral.find("modem").getNameLocal()
+
+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 function item_desc_matches(idesc,itemdetail)
+ -- idesc is an entry from ITEMS
+ -- itemdetail is something returned from getItemDetail on the chest
+ -- if you were wondering
+ return idesc.itname == itemdetail.name
+end
+
+local function stock_amt(stockinfo,idesc)
+ local total = 0
+ for ix,itm in pairs(stockinfo) do
+ if item_desc_matches(idesc,itm) then
+ total = total + itm.count
+ end
+ end
+ return total
+end
+
+local function give(stockinfo,idesc,amt)
+ amt = amt or 1
+ -- assumes that we have at least amt in stock already
+ -- actually no, might as well double check this anyway
+ assert(stock_amt(stockinfo,idesc) >= amt)
+ assert(amt>0)
+ -- make sure current turtle inv slot is empty
+ assert(turtle.getItemCount() == 0)
+
+ for slotidx,idtl in pairs(stockinfo) do
+ if item_desc_matches(idesc,idtl) then
+ local a = math.min(amt,idtl.count)
+ chest.pushItems(localname, slotidx, a, 1)
+ 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 idesc = ITEMS[mtn]
+ if not idesc then
+ -- some other metaname that has nothing to do with us
+ -- presumably some other service @ac.kst. so just ignore it
+ tell("(debug) i didn't recognise that metaname so no transaction occurs")
+ return
+ end
+
+ local remainder = tr.value % idesc.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 "..idesc.price)
+ refund()
+ else
+ local si = take_stock()
+ local in_stock = stock_amt(si,idesc)
+ 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 / idesc.price)
+ if to_give > in_stock then
+ tell("i don't have that many items in stock, sorry")
+ refund()
+ else
+ give(si,idesc,to_give)
+ tell("thank you!!! :3")
+ end
+ end
+ end
+end
+
+local function run_shop()
+ print("RUNSHOP")
+ while true do
+ msgtxt = assert(ws.receive(),"ws error")
+ print(msgtxt)
+ 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
+ print("proctransing...")
+ proctrans(msg.transaction)
+ end
+ end
+end
+
+local function run_sidedisp()
+end
+
+print(pcall(parallel.waitForAny,run_shop))
+-- print("hi")
+-- peripheral.call("top","clear")
+-- peripheral.call("left","clear")
diff --git a/shop2/stock.lua b/shop2/stock.lua
new file mode 100644
index 0000000..ce76bf0
--- /dev/null
+++ b/shop2/stock.lua
@@ -0,0 +1,39 @@
+
+
+local chest
+for _,name in ipairs(peripheral.getNames()) do
+ if name:match("chest") then chest = peripheral.wrap(name) break end
+end
+assert(chest,"couldn't find chest")
+-- might not work if there are multiple modems but why would you do that
+local localname = peripheral.find("modem").getNameLocal()
+
+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 function item_desc_matches(idesc,itemdetail)
+ -- idesc is an entry from ITEMS
+ -- itemdetail is something returned from getItemDetail on the chest
+ -- if you were wondering
+ return idesc.itname == itemdetail.name
+end
+
+local function stock_amt(stockinfo,idesc)
+ local total = 0
+ for ix,itm in pairs(stockinfo) do
+ if item_desc_matches(idesc,itm) then
+ total = total + itm.count
+ end
+ end
+ return total
+end
+