123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- --{{GLOBAL}}--
- STORE_CREDIT = "default:grass_1"
- -- reports the contents of a list
- -- channel intended for LCDs
- local function showlist(channel, list, empty_msg)
- empty_msg = empty_msg or "Empty List."
- local size = table.maxn(list)
- if size <= 0 then
- digiline_send(channel, empty_msg)
- return
- end
- local longstr= ""
- for _, v in ipairs(list) do
- longstr = longstr .. v.name .. ", ".. v.count .."; \n"
- end
- digiline_send(channel, longstr)
- end
- local function is_in_list(string, list)
- for i, v in ipairs(list) do
- if v.name == string then
- return i;
- end
- end
- return -1
- end
- local function additem(list, stack)
- local index = is_in_list(stack.name, list)
- -- if the item is not in the list or the list is empty
- if (index < 0 or table.maxn(list) <= 0) and stack.count > 0 then
- table.insert(list, stack)
- return
- elseif index > 0 then
- -- if the item is in the list and it must be updated
- list[index].count = list[index].count + stack.count
- if list[index].count <= 0 then
- table.remove(list, index)
- end
- end
- end
- -- use for both payment chest and stock chest
- -- payment chest responds to uput or utake
- -- stock chest responds to tput or ttake
- local function detect(msg, list)
- if msg == nil then
- return
- end
- if msg.stack == nil then
- return
- end
- local n = msg.stack.name
- local c = msg.stack.count
- if msg.action == "uput" then
- -- player has put an item stack in the digichest
- additem(list, {name=n, count= c})
- elseif msg.action == "utake" then
- -- player has taken an item
- additem(list, {name=n, count= -c})
- elseif msg.action == "tput" then
- -- a tube has put an item
- additem(list, {name=n, count= c})
- -- showlist("lcd", mem.paid)
- elseif msg.action == "ttake" then
- -- a tube has taken an item
- additem(list, {name=n, count= -c})
- end
- end
- -- only take specified item as currency
- -- to either load funds or refund
- local function process_payment(dfi, list, currency)
- local size = table.maxn(list)
- if size <= 0 then
- return false
- end
- for i, v in ipairs(list) do
- if v.name == currency then
- digiline_send(dfi, v)
- return true
- end
- end
- end
- local function process_sale(dfi, order, itemname)
- if itemname == nil then
- return "Programming error: var 'itemname' is nil"
- end
- if tonumber(order[itemname]) == nil then
- return "Error: invalid input: not a number."
- end
- local quantity = math.floor(order[itemname])
- if quantity <= 0 then
- return "Error: invalid quantity (".. quantity ..")"
- end
- for i, v in ipairs(mem.stock) do
- if v.name == itemname and quantity > v.count then
- return "Order quantity exceeds stock!"
- end
- end
- local cost = 1 * quantity
- if table.maxn(mem.paid) <= 0 then
- -- note: tried to check mem.paid == {} - doesn't work
- return "Error: no funds loaded."
- end
- if mem.paid[1].count < cost then
- return "Error: Insufficient funds."
- end
- -- sale is good to go
- digiline_send(dfi, {name=itemname, count=quantity})
- additem(mem.paid, {name=mem.paid[1].name, count=-cost})
- return "Sale confirmed"
- end
- -- dfi_receive = customer payment
- -- dfi_send = send to customer (refunds, wares)
- local function touch_response(msg, dfi_receive, dfi_send)
- -- ignore the event when a player closes menu
- local lcd_status = "lcd3"
- local credit = STORE_CREDIT
- if msg["key_enter_field"] == nil and msg["quit"] ~= nil then
- return "Hello! Use the touchscreen to begin."
- end
- if msg["pay"] ~= nil then
- if process_payment(dfi_receive, mem.queue, credit) then
- return "Sent payment."
- else
- return "No payment items detected."
- end
- elseif msg["refund"] ~= nil then
- if process_payment(dfi_send, mem.paid, credit) then
- return "Sent refund."
- else
- return "No payment to return."
- end
- end
- for i, itemstack in ipairs(mem.stock) do
- if msg["key_enter_field"] == itemstack.name then
- return process_sale(dfi_send, msg, itemstack.name)
- end
- end
- end
- local function get_texture_from_itemname(itemname)
- -- no access to :gsub()
- local newChar = "_"
- local skip = 0
- -- mods with texture files that do not use prefixes
- if string.sub(itemname, 1,5) == "nssm:" then --can't access find() ?'
- skip = 5
- -- elseif string.sub(itemname,1,7) == "bucket:" then
- -- skip = 7
- elseif itemname == "bucket:bucket_empty" then
- return "bucket.png"
- end
- local charTable = {}
- for i=1, #itemname do
- if i > skip then
- local foo = string.sub(itemname, i, i)
- if foo ~= ":" then
- table.insert(charTable,foo)
- else
- table.insert(charTable,"_")
- end
- end
- end
- return table.concat(charTable) .. ".png"
- end
- local function spawnfield(channel, name, label, default, y)
- local filename = get_texture_from_itemname(name)
- local height = 1
- local width = 7
- local n = {}
- n.command = "addfield"
- n["X"] = 2
- n["Y"] = 1 + y
- n["W"] = width
- n["H"] = height
- n["name"] = name
- n["label"] = label
- n["default"] = default
- digiline_send(channel, n)
- local icon = {}
- icon.command = "addimage"
- icon["X"] = 0.5
- icon["Y"] = 0.5 + y
- icon["W"] = 1
- icon["H"] = 1
- icon.texture_name = filename
- digiline_send(channel,icon)
- end
- local function touch_init(channel, wares)
- local reset = {}
- reset.command = "clear"
- digiline_send(channel, reset)
- local y_offset = 0
- local btn_pay = {}
- btn_pay.command = "addbutton"
- btn_pay["X"] = 1
- btn_pay["Y"] = y_offset
- btn_pay["W"] = 4
- btn_pay["H"] = 1
- btn_pay["name"] = "pay"
- btn_pay["label"] = "Deposit"
- digiline_send(channel, btn_pay)
- local btn_refund = {}
- btn_refund.command = "addbutton"
- btn_refund["X"] = 5
- btn_refund["Y"] = y_offset
- btn_refund["W"] = 4
- btn_refund["H"] = 1
- btn_refund["name"] = "refund"
- btn_refund["label"] = "Refund"
- digiline_send(channel, btn_refund)
- y_offset = y_offset + 1
- local guide = {}
- guide.command = "addlabel"
- guide["X"] = 2.5
- guide["Y"] = y_offset
- guide.label = "Press ENTER (or RETURN) key to place order."
- digiline_send(channel, guide)
- y_offset = y_offset + 0.5
- local price = {}
- price.command = "addlabel"
- price["X"] = 2.5
- price["Y"] = y_offset
- price.label = "Items cost 1x Grass (default:grass_1) each."
- digiline_send(channel, price)
- -- let for loop increment y
- y_offset = y_offset - 0.5 -- (0.5 - 1 = -0.5)
- for i, v in ipairs(wares) do
- local label = v.name .. " (stock: " .. v.count .. ")"
- spawnfield(channel, v.name, label, "0", y_offset + i)
- end
- end
- local function main()
- local ts = "ts" -- touchscreen, order form
- local pay = "input" -- player pays w/ digichest
- local dfi1 = "accept" -- DFI sends payment from 'pay'
- local store = "store" -- digichest holds stock & payment
- local dfi2 = "deploy" -- DFI sends wares from stock
- local card = "swipe" -- experimental card reader
- local lcd_queue = "lcd"
- local lcd_paid = "lcd2"
- if event.type == "program" then
- mem.queue = {} -- items placed in chest
- mem.paid = {} -- items paid by customers
- mem.stock = {} -- items stocked by owner
- touch_init(ts, mem.stock)
- digiline_send("lcd", "Initialized!")
- digiline_send("lcd2", "Initialized!")
- digiline_send("lcd3", "Initialized!")
- end
- if event.type == "digiline" and event.channel == ts then
- local status = touch_response(event.msg, dfi1, dfi2)
- touch_init(ts, mem.stock)
- digiline_send("lcd3", status)
- showlist(lcd_paid, mem.paid, "No funds loaded.")
- end
- if event.type == "digiline" and event.channel == pay then
- detect(event.msg, mem.queue)
- showlist(lcd_queue, mem.queue, "Place payment in the chest below.")
- end
- if event.type == "digiline" and event.channel == store then
- if event.msg.action == "uput"
- or event.msg.action == "utake" then
- -- store stock directly accessed by player
- -- (as opposed to vending)
- detect(event.msg, mem.stock)
- elseif event.msg.action == "tput" then
- -- vending, payment confirmation
- -- update mem.paid to show current store credits
- detect(event.msg, mem.paid)
- showlist(lcd_paid, mem.paid, "No funds loaded.")
- elseif event.msg.action == "ttake" then
- -- vending, update stock after selling
- if event.msg.stack.name == STORE_CREDIT then
- detect(event.msg, mem.paid)
- else
- detect(event.msg, mem.stock)
- end
- showlist(lcd_paid, mem.paid, "No funds loaded.")
- -- process_sale already deducts store creditss
- -- note: upon refunds, the code will attempt to deduct
- -- currency from the stock list
- -- however additems() does allow negative quantities to be indexed.
- end
- touch_init(ts, mem.stock)
- end
- end
- return main()
|