From 3c63532ada3893779dbce80ec1591492026ab889 Mon Sep 17 00:00:00 2001
From: Casper3667 <8396443+Casper3667@users.noreply.github.com>
Date: Sun, 1 Mar 2026 07:46:28 +0100
Subject: [PATCH] Make the commissary register able to be filled out with paper
forms (#21905)
The commissary register can now be filled out by unlocking it and using
a filled out piece of paper on it. This adds the listed items to the
things listed in it, making it quick to set up for operations crew
instead of manually typing it in every round.
---------
Signed-off-by: Casper3667 <8396443+Casper3667@users.noreply.github.com>
Co-authored-by: Cody Brittain <1779662+Generalcamo@users.noreply.github.com>
---
aurorastation.dme | 1 +
code/__HELPERS/price.dm | 61 ++++++++++++++++++++
code/modules/cooking/machinery/commissary.dm | 41 ++++++++++---
code/modules/economy/quikpay.dm | 36 +++++++++---
html/changelogs/PaperList.yml | 6 ++
tgui/packages/tgui/interfaces/QuikPay.tsx | 20 +++++--
6 files changed, 143 insertions(+), 22 deletions(-)
create mode 100644 code/__HELPERS/price.dm
create mode 100644 html/changelogs/PaperList.yml
diff --git a/aurorastation.dme b/aurorastation.dme
index 18f07b737fb..86b12c9934e 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -221,6 +221,7 @@
#include "code\__HELPERS\nameof.dm"
#include "code\__HELPERS\names.dm"
#include "code\__HELPERS\overmap.dm"
+#include "code\__HELPERS\price.dm"
#include "code\__HELPERS\qdel.dm"
#include "code\__HELPERS\ref.dm"
#include "code\__HELPERS\sanitize_values.dm"
diff --git a/code/__HELPERS/price.dm b/code/__HELPERS/price.dm
new file mode 100644
index 00000000000..3a5331f3bed
--- /dev/null
+++ b/code/__HELPERS/price.dm
@@ -0,0 +1,61 @@
+/// Registers name and prices for the commissary from a paper.
+/// First line is ignored, acting as header for name/pricing, mainly for readability.
+/// The second line and after are read as the name of the thing and the price of the thing.
+/// Example below
+/// name,price
+/// Candy,2.50
+/// Snack,3.10
+/// Meal,10.00
+/// The above would add 3 items, the candy, snack and meal, with their respective prices.
+/// It returns a list containing name and prices
+/proc/read_paper_price_list(var/obj/item/paper/R)
+ var/text = R.info
+
+ // Split on new line
+ var/list/lines = splittext(text, "
")
+ var/list/result = list()
+
+ // Skip a header line
+ for(var/i = 2; i <= lines.len; i++)
+ var/line = lines[i]
+ if(!length(line))
+ continue
+
+ // Split the name and price
+ var/list/split_input = splittext(line, ";")
+
+ if(split_input.len < 2)
+ continue
+
+ var/name = split_input[1]
+ var/price_text = split_input[2]
+
+ var/price = text2num(price_text)
+
+ // In case of invalid prices for some reason
+ if(price == 0 && price_text != "0" && price_text != "0.0")
+ continue
+
+ result += list(list("name" = name, "price" = price))
+
+ return result
+
+// Prints the prices from a register/quikpay into a list that can be used for read_paper_price_list()
+/proc/print_price_to_paper(var/shop_name, var/list/items, var/paper_loc, mob/user)
+ if(!items || !items.len)
+ return FALSE
+
+ var/obj/item/paper/notepad/receipt/R = new(paper_loc)
+ var/title = "Price List: [shop_name]"
+ var/text = "name;price
"
+
+ for(var/list/L in items)
+ var/item_name = L["name"]
+ var/item_price = L["price"]
+ text += "[item_name];[round(item_price, 0.01)]
"
+
+ R.set_content(title, text)
+
+ user.put_in_any_hand_if_possible(R)
+ R.ripped = TRUE
+ return TRUE
diff --git a/code/modules/cooking/machinery/commissary.dm b/code/modules/cooking/machinery/commissary.dm
index 237a5cb07d3..5e9e2bccac2 100644
--- a/code/modules/cooking/machinery/commissary.dm
+++ b/code/modules/cooking/machinery/commissary.dm
@@ -157,6 +157,7 @@
. += "Alt click with credits in hand, to deposit them."
. += "Alt click while having operations access, to withdraw credits from it."
. += "Items can be paid for with id cards, charge cards or physical credits, and a receipt will be printed."
+ . += "The register can print a paper which can be used to quickly fill it out in the future by using it on the register."
/obj/structure/cash_register/commissary/Initialize()
. = ..()
@@ -207,6 +208,9 @@
R.ripped = TRUE
/obj/structure/cash_register/commissary/attackby(obj/item/attacking_item, mob/user)
+ if(istype(attacking_item, /obj/item/paper))
+ read_paper_list(attacking_item, user)
+ return
if(sum == 0)
return
if (istype(attacking_item, /obj/item/spacecash/ewallet))
@@ -258,9 +262,9 @@
if(transaction)
to_chat(user, SPAN_NOTICE("[icon2html(src, user)][transaction]."))
else
- playsound(src, 'sound/machines/chime.ogg', 50, 1)
- visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes."))
visible_message("\The [user] swipes a card on \the [src]." )
+ audible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes."))
+ playsound(src, 'sound/machines/chime.ogg', 50, 1)
print_receipt()
sum = 0
receipt = ""
@@ -278,8 +282,8 @@
E.worth -= transaction_amount
visible_message("\The [user] swipes a card on \the [src]." )
+ audible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes."))
playsound(src, 'sound/machines/chime.ogg', 50, 1)
- src.audible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes."))
print_receipt()
sum = 0
receipt = ""
@@ -289,6 +293,18 @@
to_chat(user, SPAN_WARNING("[icon2html(src, user)]\The [E] doesn't have that much money!"))
return
+/obj/structure/cash_register/commissary/proc/read_paper_list(obj/item/paper/R, mob/user)
+ if(!editmode)
+ balloon_alert(user, "device locked!")
+ return FALSE
+ var/result = read_paper_price_list(R)
+ for(var/item in result)
+ items += list(list("name" = item["name"], "price" = item["price"]))
+ items_to_price[item["name"]] += item["price"]
+
+/obj/structure/cash_register/commissary/proc/print_price(mob/user)
+ return print_price_to_paper(shop_name, items, loc, user)
+
/obj/structure/cash_register/commissary/attack_hand(mob/living/user)
. = ..()
ui_interact(user)
@@ -319,7 +335,7 @@
switch(action)
if("add")
if(!editmode)
- to_chat(usr, SPAN_WARNING("Device locked."))
+ balloon_alert(usr, "device locked!")
return FALSE
items += list(list("name" = new_item, "price" = new_price))
@@ -328,7 +344,7 @@
if("remove")
if(!editmode)
- to_chat(usr, SPAN_NOTICE("Device locked."))
+ balloon_alert(usr, "device locked!")
return FALSE
var/index = 0
for(var/list/L in items)
@@ -390,7 +406,7 @@
if("locking")
if(editmode)
editmode = FALSE
- to_chat(usr, SPAN_NOTICE("Device locked."))
+ balloon_alert(usr, "device locked!")
else
if(!editmode)
var/obj/item/card/id/I = usr.GetIdCard()
@@ -398,19 +414,26 @@
return
if(check_access(I))
editmode = !editmode
- to_chat(usr, SPAN_NOTICE("Device [editmode ? "un" : ""]locked."))
+ balloon_alert(usr, "device [editmode ? "un" : ""]locked")
. = TRUE
if("accountselect")
if(!editmode)
- to_chat(usr, SPAN_WARNING("Device locked."))
+ balloon_alert(usr, "device locked!")
return FALSE
var/dest = tgui_input_list(usr, "What account would you like to select?", "Destination Account", assoc_to_keys(SSeconomy.department_accounts))
if(!dest)
return FALSE
destinationact = dest
- return TRUE
+ . = TRUE
+
+ if("print_dsv")
+ if(!editmode)
+ balloon_alert(usr, "device locked!")
+ return FALSE
+ print_price(usr)
+ . = TRUE
/obj/structure/cash_register/commissary/proc/clear_order()
buying.Cut()
diff --git a/code/modules/economy/quikpay.dm b/code/modules/economy/quikpay.dm
index 0ecb32e2e05..a3c3c01c667 100644
--- a/code/modules/economy/quikpay.dm
+++ b/code/modules/economy/quikpay.dm
@@ -74,6 +74,9 @@
usr.put_in_any_hand_if_possible(R)
/obj/item/quikpay/attackby(obj/item/attacking_item, mob/user)
+ if(istype(attacking_item, /obj/item/paper))
+ read_paper_list(attacking_item, user)
+ return
if (istype(attacking_item, /obj/item/spacecash/ewallet))
var/obj/item/spacecash/ewallet/E = attacking_item
var/transaction_amount = sum
@@ -81,8 +84,8 @@
var/transaction_terminal = machine_id
if(transaction_amount <= E.worth)
+ audible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes."))
playsound(src, 'sound/machines/chime.ogg', 50, 1)
- src.visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes."))
SSeconomy.charge_to_account(SSeconomy.get_department_account(destinationact)?.account_number, E.owner_name, transaction_purpose, transaction_terminal, transaction_amount)
E.worth -= transaction_amount
@@ -107,13 +110,25 @@
if(transaction)
to_chat(user, SPAN_NOTICE("[icon2html(src, user)][transaction]."))
else
+ audible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes."))
playsound(src, 'sound/machines/chime.ogg', 50, 1)
- visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] chimes."))
print_receipt()
sum = 0
receipt = ""
to_chat(user, SPAN_NOTICE("Transaction completed, please return to the home screen."))
+/obj/item/quikpay/proc/read_paper_list(obj/item/paper/R, mob/user)
+ if(!editmode)
+ balloon_alert(user, "device locked!")
+ return FALSE
+ var/result = read_paper_price_list(R)
+ for(var/item in result)
+ items += list(list("name" = item["name"], "price" = item["price"]))
+ items_to_price[item["name"]] += item["price"]
+
+/obj/item/quikpay/proc/print_price(mob/user)
+ return print_price_to_paper(shop_name, items, loc, user)
+
/obj/item/quikpay/attack_self(var/mob/user)
ui_interact(user)
@@ -144,7 +159,7 @@
switch(action)
if("add")
if(!editmode)
- to_chat(usr, SPAN_WARNING("Device locked."))
+ balloon_alert(usr, "device locked!")
return FALSE
items += list(list("name" = new_item, "price" = new_price))
@@ -153,7 +168,7 @@
if("remove")
if(!editmode)
- to_chat(usr, SPAN_NOTICE("Device locked."))
+ balloon_alert(usr, "device locked!")
return FALSE
var/index = 0
for(var/list/L in items)
@@ -215,7 +230,7 @@
if("locking")
if(editmode)
editmode = FALSE
- to_chat(usr, SPAN_NOTICE("Device locked."))
+ balloon_alert(usr, "device locked!")
else
if(!editmode)
var/obj/item/card/id/I = usr.GetIdCard()
@@ -228,14 +243,21 @@
if("accountselect")
if(!editmode)
- to_chat(usr, SPAN_WARNING("Device locked."))
+ balloon_alert(usr, "device locked!")
return FALSE
var/dest = tgui_input_list(usr, "What account would you like to select?", "Destination Account", assoc_to_keys(SSeconomy.department_accounts))
if(!dest)
return FALSE
destinationact = dest
- return TRUE
+ . = TRUE
+
+ if("print_dsv")
+ if(!editmode)
+ balloon_alert(usr, "device locked!")
+ return FALSE
+ print_price(usr)
+ . = TRUE
/obj/item/quikpay/proc/clear_order()
buying.Cut()
diff --git a/html/changelogs/PaperList.yml b/html/changelogs/PaperList.yml
new file mode 100644
index 00000000000..dc79f0a9d65
--- /dev/null
+++ b/html/changelogs/PaperList.yml
@@ -0,0 +1,6 @@
+author: TheGreyWolf
+
+delete-after: True
+
+changes:
+ - rscadd: "The commissary cash register can now be filled out with a paper form."
diff --git a/tgui/packages/tgui/interfaces/QuikPay.tsx b/tgui/packages/tgui/interfaces/QuikPay.tsx
index fc42068c4fb..b9ec897ecd8 100644
--- a/tgui/packages/tgui/interfaces/QuikPay.tsx
+++ b/tgui/packages/tgui/interfaces/QuikPay.tsx
@@ -44,12 +44,20 @@ export const QuikPay = (props, context) => {
buttons={
<>
{data.editmode ? (
-