diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 67246dc1953..25e3855bf84 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -25017,10 +25017,9 @@ /turf/open/floor/plating, /area/maintenance/starboard/aft) "fcB" = ( -/obj/structure/chair/office{ - dir = 1 +/obj/machinery/computer/accounting{ + dir = 4 }, -/obj/machinery/newscaster/directional/west, /turf/open/floor/wood, /area/command/heads_quarters/hop) "fcG" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index c89f063321c..6bdbedd16fe 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -25602,6 +25602,9 @@ /obj/effect/turf_decal/tile/blue{ dir = 8 }, +/obj/machinery/computer/accounting{ + dir = 4 + }, /turf/open/floor/iron, /area/command/heads_quarters/hop) "lwk" = ( diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 73ad0388c5e..8d15bb24c47 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -31744,16 +31744,11 @@ /turf/open/floor/iron/showroomfloor, /area/medical/medbay/central) "goc" = ( -/obj/structure/table/wood, -/obj/machinery/recharger, -/obj/item/toy/figure/hop{ - pixel_x = -8 - }, -/obj/item/toy/figure/ian{ - pixel_x = 8 - }, /obj/machinery/newscaster/directional/west, /obj/machinery/airalarm/directional/north, +/obj/machinery/computer/accounting{ + dir = 4 + }, /turf/open/floor/carpet/blue, /area/command/heads_quarters/hop) "goy" = ( @@ -59648,11 +59643,15 @@ /turf/open/floor/cult, /area/service/chapel/office) "puG" = ( -/obj/structure/table/wood, -/obj/item/stack/package_wrap, -/obj/item/storage/lockbox/loyalty, -/obj/item/hand_labeler, /obj/machinery/keycard_auth/directional/north, +/obj/item/toy/figure/ian{ + pixel_x = 8 + }, +/obj/item/toy/figure/hop{ + pixel_x = -8 + }, +/obj/machinery/recharger, +/obj/structure/table/wood, /turf/open/floor/carpet/blue, /area/command/heads_quarters/hop) "puH" = ( @@ -78817,6 +78816,7 @@ }, /obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/bot, +/obj/item/storage/lockbox/loyalty, /turf/open/floor/iron/dark, /area/command/heads_quarters/hop) "vME" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index d52d2372cdb..d572b7f728e 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -456,16 +456,12 @@ /turf/closed/wall/r_wall, /area/security/prison/safe) "aeN" = ( -/obj/item/flashlight/lamp/green{ - pixel_x = 1; - pixel_y = 5 - }, -/obj/structure/table/wood, /obj/machinery/button/door/directional/north{ id = "hop"; name = "Privacy Shutters Control"; req_access_txt = "28" }, +/obj/machinery/computer/accounting, /turf/open/floor/wood, /area/command/heads_quarters/hop) "aeO" = ( @@ -17503,9 +17499,16 @@ /turf/open/floor/iron, /area/hallway/primary/central) "fdu" = ( -/obj/machinery/recharger, +/obj/machinery/recharger{ + pixel_x = 2; + pixel_y = 3 + }, /obj/item/storage/secure/safe/directional/east, /obj/structure/table/wood, +/obj/item/flashlight/lamp/green{ + pixel_x = -12; + pixel_y = 5 + }, /turf/open/floor/wood, /area/command/heads_quarters/hop) "fdB" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 015f40474be..b462b0aa5a2 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -33190,8 +33190,13 @@ /turf/open/floor/iron, /area/cargo/drone_bay) "kBI" = ( -/obj/item/kirbyplants/random, /obj/machinery/status_display/evac/directional/north, +/obj/structure/table/wood, +/obj/item/paper_bin{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/pen, /turf/open/floor/wood, /area/command/heads_quarters/hop) "kBN" = ( @@ -33679,12 +33684,9 @@ /obj/structure/window/reinforced{ dir = 4 }, -/obj/structure/table/wood, -/obj/item/paper_bin{ - pixel_x = -2; - pixel_y = 4 +/obj/machinery/computer/accounting{ + dir = 8 }, -/obj/item/pen, /turf/open/floor/carpet, /area/command/heads_quarters/hop) "kJx" = ( @@ -37095,8 +37097,8 @@ dir = 4 }, /obj/structure/table/wood, -/obj/machinery/recharger, /obj/machinery/newscaster/directional/north, +/obj/machinery/recharger, /turf/open/floor/carpet, /area/command/heads_quarters/hop) "lQz" = ( @@ -53906,6 +53908,7 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, +/obj/item/kirbyplants/random, /turf/open/floor/iron, /area/hallway/secondary/command) "sco" = ( diff --git a/code/controllers/subsystem/economy.dm b/code/controllers/subsystem/economy.dm index 8ecfc723c4f..03ec542506e 100644 --- a/code/controllers/subsystem/economy.dm +++ b/code/controllers/subsystem/economy.dm @@ -49,6 +49,11 @@ SUBSYSTEM_DEF(economy) ///The modifier multiplied to the value of cargo pack prices. var/pack_price_modifier = 1 var/fire_counter_for_paycheck = 0 //SKYRAT EDIT ADDITION + /** + * A list of strings containing a basic transaction history of purchases on the station. + * Added to any time when player accounts purchase something. + */ + var/list/audit_log = list() /// Total value of exported materials. var/export_total = 0 @@ -148,3 +153,20 @@ SUBSYSTEM_DEF(economy) return 1 inflation_value = max(round(((station_total / bank_accounts_by_id.len) / station_target), 0.1), 1.0) return inflation_value + +/** + * Proc that adds a set of strings and ints to the audit log, tracked by the economy SS. + * + * * account: The bank account of the person purchasing the item. + * * price_to_use: The cost of the purchase made for this transaction. + * * vendor: The object or structure medium that is charging the user. For Vending machines that's the machine, for payment component that's the parent, cargo that's the crate, etc. + */ +/datum/controller/subsystem/economy/proc/track_purchase(datum/bank_account/account, price_to_use, vendor) + if(!account || !price_to_use || !vendor) + CRASH("Track purchases was missing an argument! (Account, Price, or Vendor.)") + + audit_log += list(list( + "account" = account.account_holder, + "cost" = price_to_use, + "vendor" = vendor, + )) diff --git a/code/datums/components/payment.dm b/code/datums/components/payment.dm index 49375c63079..c5c9c5b8542 100644 --- a/code/datums/components/payment.dm +++ b/code/datums/components/payment.dm @@ -69,10 +69,10 @@ target_acc.transfer_money(card.registered_account, cost + extra_fees) card.registered_account.bank_card_talk("[cost + extra_fees] credits deducted from your account.") playsound(src, 'sound/effects/cashregister.ogg', 20, TRUE) + SSeconomy.track_purchase(card.registered_account, cost + extra_fees, parent) /datum/component/payment/proc/change_cost(datum/source, new_cost) SIGNAL_HANDLER - if(!isnum(new_cost)) CRASH("change_cost called with variable new_cost as not a number.") cost = new_cost diff --git a/code/game/machinery/computer/accounting.dm b/code/game/machinery/computer/accounting.dm new file mode 100644 index 00000000000..64a26655540 --- /dev/null +++ b/code/game/machinery/computer/accounting.dm @@ -0,0 +1,34 @@ +/obj/machinery/computer/accounting + name = "account lookup console" + desc = "Used to view crewmember accounts and purchases." + icon_screen = "accounts" + icon_keyboard = "id_key" + circuit = /obj/item/circuitboard/computer/accounting + light_color = LIGHT_COLOR_GREEN + +/obj/machinery/computer/accounting/ui_interact(mob/user, datum/tgui/ui) + . = ..() + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + ui = new(user, src, "AccountingConsole", name) + ui.open() + +/obj/machinery/computer/accounting/ui_data(mob/user) + . = ..() + var/list/data = list() + var/list/player_accounts = list() + var/list/audit_list = SSeconomy.audit_log + + for(var/current_account as anything in SSeconomy.bank_accounts_by_id) + var/datum/bank_account/current_bank_account = SSeconomy.bank_accounts_by_id[current_account] + player_accounts += list(list( + "name" = current_bank_account.account_holder, + "job" = current_bank_account.account_job.title, + "balance" = current_bank_account.account_balance, + "modifier" = current_bank_account.payday_modifier, + )) + data["PlayerAccounts"] = player_accounts + data["AuditLog"] = audit_list + data["Crashing"] = HAS_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING) + return data + diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index dd22f011c53..cc3b1fb8e27 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -14,6 +14,11 @@ name = "Bluespace Artillery Controls (Computer Board)" build_path = /obj/machinery/computer/bsa_control +/obj/item/circuitboard/computer/accounting + name = "Account Lookup Console (Computer Board)" + greyscale_colors = CIRCUIT_COLOR_COMMAND + build_path = /obj/machinery/computer/accounting + //obj/item/circuitboard/computer/shield // name = "Shield Control (Computer Board)" // greyscale_colors = CIRCUIT_COLOR_COMMAND diff --git a/code/modules/research/designs/comp_board_designs.dm b/code/modules/research/designs/comp_board_designs.dm index 259655ae867..f48584a8ff7 100644 --- a/code/modules/research/designs/comp_board_designs.dm +++ b/code/modules/research/designs/comp_board_designs.dm @@ -306,3 +306,12 @@ build_type = IMPRINTER build_path = /obj/item/circuitboard/computer/exodrone_console category = list("Computer Boards") + +/datum/design/board/accounting_console + name = "Computer Design (Account Lookup Console)" + desc = "Allows for the construction of circuit boards used to assess the wealth of crewmates on station." + id = "account_console" + build_type = IMPRINTER + build_path = /obj/item/circuitboard/computer/accounting + category = list("Computer Boards") + departmental_flags = DEPARTMENTAL_FLAG_SECURITY diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index de82d739807..956f57ea211 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -1116,6 +1116,7 @@ description = "Organized record databases and how they're used." prereq_ids = list("comptech") design_ids = list( + "account_console", "automated_announcement", "med_data", "prisonmanage", diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index edf535d8d28..c9bf792865d 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -158,6 +158,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( if(istype(spawning_order, /datum/supply_order/armament)) LAZYADD(forced_briefcases[spawning_order.paying_account], spawning_order) paying_for_this.bank_card_talk("Cargo order #[spawning_order.id] has shipped. [price] credits have been charged to your bank account.") + SSeconomy.track_purchase(paying_for_this, price, spawning_order.pack.name) var/datum/bank_account/department/cargo = SSeconomy.get_dep_account(ACCOUNT_CAR) cargo.adjust_money(price - spawning_order.pack.get_cost()) //Cargo gets the handling fee value += spawning_order.pack.get_cost() diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index b1ccc4634e5..88e625c2725 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -962,7 +962,8 @@ GLOBAL_LIST_EMPTY(vending_products) if(D) D.adjust_money(price_to_use) SSblackbox.record_feedback("amount", "vending_spent", price_to_use) - log_econ("[price_to_use] credits were inserted into [src] by [D.account_holder] to buy [R].") + SSeconomy.track_purchase(account, price_to_use, name) + log_econ("[price_to_use] credits were inserted into [src] by [account.account_holder] to buy [R].") if(last_shopper != REF(usr) || purchase_message_cooldown < world.time) say("Thank you for shopping with [src]!") purchase_message_cooldown = world.time + 5 SECONDS diff --git a/icons/obj/computer.dmi b/icons/obj/computer.dmi index dfa3057b2e2..fb281724f0b 100644 Binary files a/icons/obj/computer.dmi and b/icons/obj/computer.dmi differ diff --git a/tgstation.dme b/tgstation.dme index b9a67d01703..35e873fc0f8 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1319,6 +1319,7 @@ #include "code\game\machinery\camera\presets.dm" #include "code\game\machinery\camera\tracking.dm" #include "code\game\machinery\computer\_computer.dm" +#include "code\game\machinery\computer\accounting.dm" #include "code\game\machinery\computer\aifixer.dm" #include "code\game\machinery\computer\apc_control.dm" #include "code\game\machinery\computer\arena.dm" diff --git a/tgui/global.d.ts b/tgui/global.d.ts index 348cb9c5165..73660d5b76e 100644 --- a/tgui/global.d.ts +++ b/tgui/global.d.ts @@ -21,6 +21,13 @@ declare module '*.svg' { export default content; } +namespace JSX { + interface IntrinsicElements { + marquee: any; + blink: any; + } +} + type TguiMessage = { type: string; payload?: any; diff --git a/tgui/packages/tgui/interfaces/AccountingConsole.js b/tgui/packages/tgui/interfaces/AccountingConsole.js new file mode 100644 index 00000000000..41c2fa1c35b --- /dev/null +++ b/tgui/packages/tgui/interfaces/AccountingConsole.js @@ -0,0 +1,93 @@ +import { BlockQuote, Collapsible, LabeledList, Modal, Section, Tabs } from '../components'; +import { useBackend } from '../backend'; +import { useLocalState } from '../backend'; +import { Window } from '../layouts'; + +export const AccountingConsole = (props, context) => { + const { act, data } = useBackend(context); + const { + PlayerAccounts, + AuditLog, + } = data; + const USER_SCREEN = 1; + const AUDIT_SCREEN = 2; + const [screenmode, setScreenmode] = useLocalState(context, 'tab_main', USER_SCREEN); + return ( + + + + + setScreenmode(USER_SCREEN)}> + Users + + setScreenmode(AUDIT_SCREEN)}> + Audit + + + {screenmode === USER_SCREEN && ( +
+ {PlayerAccounts.map(account => ( + + + + {account.job} + + + {account.balance} + + + {account.modifier*100}% + + + + ))} +
+ )} + {screenmode === AUDIT_SCREEN && ( +
+ {AuditLog.map(purchase => ( +
+ {purchase.account} spent {purchase.cost} + {' '}cr at {purchase.vendor}. +
+ ))} +
+ )} +
+
+ ); +}; + +/** The modal menu that contains the prompts to making new channels. */ +const MarketCrashing = (props, context) => { + const { act, data } = useBackend(context); + const [lockedmode, setLockedmode] = useLocalState(context, 'lockedmode', 1); + const { + Crashing, + } = data; + if (!Crashing) { + return null; + } + return ( + + OH GOD THE ECONOMY IS RUINED. + + ); +}; + + diff --git a/tgui/public/tgui.html b/tgui/public/tgui.html index 9a53f328ab6..ecb3e11b9cc 100644 --- a/tgui/public/tgui.html +++ b/tgui/public/tgui.html @@ -475,6 +475,17 @@ Byond.sendMessage('ready');