diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index eebe775d479..d2705a33259 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -482,13 +482,20 @@ ///from [/obj/structure/closet/supplypod/proc/endlaunch]: #define COMSIG_SUPPLYPOD_LANDED "supplypodgoboom" +// /obj signals for economy +///called when the payment component tries to charge an account. +#define COMSIG_OBJ_ATTEMPT_CHARGE "obj_attempt_simple_charge" + #define COMPONENT_OBJ_CANCEL_CHARGE (1<<0) +///Called when a payment component changes value +#define COMSIG_OBJ_ATTEMPT_CHARGE_CHANGE "obj_attempt_simple_charge_change" + // /obj/item signals for economy ///called when an item is sold by the exports subsystem #define COMSIG_ITEM_SOLD "item_sold" ///called when a wrapped up structure is opened by hand #define COMSIG_STRUCTURE_UNWRAPPED "structure_unwrapped" -#define COMSIG_ITEM_UNWRAPPED "item_unwrapped" ///called when a wrapped up item is opened by hand +#define COMSIG_ITEM_UNWRAPPED "item_unwrapped" #define COMSIG_ITEM_SPLIT_VALUE (1<<0) ///called when getting the item's exact ratio for cargo's profit. #define COMSIG_ITEM_SPLIT_PROFIT "item_split_profits" diff --git a/code/__DEFINES/economy.dm b/code/__DEFINES/economy.dm index 28d68ec6df3..11d724d93be 100644 --- a/code/__DEFINES/economy.dm +++ b/code/__DEFINES/economy.dm @@ -46,3 +46,8 @@ #define CIV_JOB_MINE 10 #define CIV_JOB_MED 11 #define CIV_JOB_GROW 12 + +//These defines are to be used to with the payment component, determines which lines will be used during a transaction. If in doubt, go with clinical. +#define PAYMENT_CLINICAL "clinical" +#define PAYMENT_FRIENDLY "friendly" +#define PAYMENT_ANGRY "angry" diff --git a/code/datums/components/payment.dm b/code/datums/components/payment.dm new file mode 100644 index 00000000000..d2238fffd12 --- /dev/null +++ b/code/datums/components/payment.dm @@ -0,0 +1,71 @@ + +/** + * Handles simple payment operations where the cost of the object in question doesn't change. + * + * What this is useful for: + * Basic forms of vending. + * Objects that can drain the owner's money linearly. + * What this is not useful for: + * Things where the seller may want to fluxuate the price of the object. + * Improving standardizing every form of payment handing, as some custom handling is specific to that object. + **/ +/datum/component/payment + ///Standardized of operation. + var/cost = 10 + ///Flavor style for handling cash (Friendly? Hostile? etc.) + var/transaction_style = "Clinical" + ///Who's getting paid? + var/datum/bank_account/target_acc + +/datum/component/payment/Initialize(_cost, _target, _style) + target_acc = _target + if(!target_acc) + target_acc = SSeconomy.get_dep_account(ACCOUNT_CIV) + + cost = _cost + transaction_style = _style + RegisterSignal(parent, COMSIG_OBJ_ATTEMPT_CHARGE, .proc/attempt_charge) + RegisterSignal(parent, COMSIG_OBJ_ATTEMPT_CHARGE_CHANGE, .proc/change_cost) + +/datum/component/payment/proc/attempt_charge(datum/source, atom/movable/target, var/extra_fees = 0) + if(!cost) //In case a free variant of anything is made it'll skip charging anyone. + return + if(!ismob(target)) + return COMPONENT_OBJ_CANCEL_CHARGE + var/mob/user = target + var/obj/item/card/id/card = user.get_idcard(TRUE) + if(!card) + switch(transaction_style) + if(PAYMENT_FRIENDLY) + to_chat(user, "ID not detected, sorry [user]!") + if(PAYMENT_ANGRY) + to_chat(user, "WHERE IS YOUR GOD DAMN CARD! GOD DAMNIT!") + if(PAYMENT_CLINICAL) + to_chat(user, "ID card not present. Aborting.") + return COMPONENT_OBJ_CANCEL_CHARGE + if(!card.registered_account) + switch(transaction_style) + if(PAYMENT_FRIENDLY) + to_chat(user, "There's no account detected on your ID, how mysterious!") + if(PAYMENT_ANGRY) + to_chat(user, "ARE YOU JOKING. YOU DON'T HAVE A BANK ACCOUNT ON YOUR ID YOU IDIOT.") + if(PAYMENT_CLINICAL) + to_chat(user, "ID Card lacks a bank account. Aborting.") + return COMPONENT_OBJ_CANCEL_CHARGE + if(!(card.registered_account.has_money(cost + extra_fees))) + switch(transaction_style) + if(PAYMENT_FRIENDLY) + to_chat(user, "I'm so sorry... You don't seem to have enough money.") + if(PAYMENT_ANGRY) + to_chat(user, "YOU MORON. YOU ABSOLUTE BAFOON. YOU INSUFFERABLE TOOL. YOU ARE POOR.") + if(PAYMENT_CLINICAL) + to_chat(user, "ID Card lacks funds. Aborting.") + return COMPONENT_OBJ_CANCEL_CHARGE + target_acc.transfer_money(card.registered_account, cost) + card.registered_account.bank_card_talk("[cost] credits deducted from your account.") + playsound(src, 'sound/effects/cashregister.ogg', 20, TRUE) + +/datum/component/payment/proc/change_cost(datum/source, var/new_cost) + if(!isnum(new_cost)) + CRASH("change_cost called with variable new_cost as not a number.") + cost = new_cost diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 03486f0e995..32a0368c2c7 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1431,3 +1431,11 @@ */ /atom/proc/setClosed() return + +/** + * Used to attempt to charge an object with a payment component. + * + * Use this if an atom needs to attempt to charge another atom. + */ +/atom/proc/attempt_charge(var/atom/sender, var/atom/target, var/extra_fees = 0) + return SEND_SIGNAL(sender, COMSIG_OBJ_ATTEMPT_CHARGE, target, extra_fees) diff --git a/code/game/machinery/medical_kiosk.dm b/code/game/machinery/medical_kiosk.dm index b474a80d7fe..77f35944433 100644 --- a/code/game/machinery/medical_kiosk.dm +++ b/code/game/machinery/medical_kiosk.dm @@ -29,35 +29,23 @@ /obj/machinery/medical_kiosk/Initialize() //loaded subtype for mapping use . = ..() + AddComponent(/datum/component/payment, active_price, SSeconomy.get_dep_account(ACCOUNT_MED), PAYMENT_FRIENDLY) scanner_wand = new/obj/item/scanner_wand(src) /obj/machinery/medical_kiosk/proc/inuse() //Verifies that the user can use the interface, followed by showing medical information. - if (pandemonium == TRUE) - active_price += (rand(10,30)) //The wheel of capitalism says health care ain't cheap. - if(!istype(C)) - say("No ID card detected.") // No unidentified crew. - return - if(C.registered_account) + if(C?.registered_account) account = C.registered_account - else - say("No account detected.") //No homeless crew. - return if(account?.account_job?.paycheck_department == payment_department) use_power(20) paying_customer = TRUE say("Hello, esteemed medical staff!") RefreshParts() return - if(!account.has_money(active_price)) - say("You do not possess the funds to purchase this.") //No jobless crew, either. + var/bonus_fee = pandemonium ? rand(10,30) : 0 + if(attempt_charge(src, H, bonus_fee) & COMPONENT_OBJ_CANCEL_CHARGE ) return - else - account.adjust_money(-active_price) - var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_MED) - if(D) - D.adjust_money(active_price) - use_power(20) - paying_customer = TRUE + use_power(20) + paying_customer = TRUE icon_state = "kiosk_active" say("Thank you for your patronage!") RefreshParts() @@ -332,22 +320,26 @@ return switch(action) if("beginScan_1") - inuse() + if(!scan_active_1) + inuse() if(paying_customer == TRUE) scan_active_1 = TRUE paying_customer = FALSE if("beginScan_2") - inuse() + if(!scan_active_2) + inuse() if(paying_customer == TRUE) scan_active_2 = TRUE paying_customer = FALSE if("beginScan_3") - inuse() + if(!scan_active_3) + inuse() if(paying_customer == TRUE) scan_active_3 = TRUE paying_customer = FALSE if("beginScan_4") - inuse() + if(!scan_active_4) + inuse() if(paying_customer == TRUE) scan_active_4 = TRUE paying_customer = FALSE diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 9a375f09724..2ca575b5d7a 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -29,6 +29,10 @@ var/mob/living/ass //i can't believe i didn't write a stupid-ass comment about this var when i first coded asscopy. var/busy = FALSE +/obj/machinery/photocopier/Initialize() + . = ..() + AddComponent(/datum/component/payment, 5, SSeconomy.get_dep_account(ACCOUNT_CIV), PAYMENT_CLINICAL) + /obj/machinery/photocopier/ui_interact(mob/user) . = ..() var/list/dat = list("Photocopier

") @@ -56,8 +60,12 @@ return if(href_list["copy"]) if(copy) + if(busy) + return for(var/i = 0, i < copies, i++) - if(toner > 0 && !busy && copy) + if(toner > 0 && copy) + if(attempt_charge(src, usr) & COMPONENT_OBJ_CANCEL_CHARGE) + return var/copy_as_paper = 1 if(istype(copy, /obj/item/paper/contract/employment)) var/obj/item/paper/contract/employment/E = copy @@ -89,16 +97,24 @@ break updateUsrDialog() else if(photocopy) + if(busy) + return for(var/i = 0, i < copies, i++) - if(toner >= 5 && !busy && photocopy) //Was set to = 0, but if there was say 3 toner left and this ran, you would get -2 which would be weird for ink + if(attempt_charge(src, usr) & COMPONENT_OBJ_CANCEL_CHARGE) + return + if(toner >= 5 && photocopy) //Was set to = 0, but if there was say 3 toner left and this ran, you would get -2 which would be weird for ink new /obj/item/photo (loc, photocopy.picture.Copy(greytoggle == "Greyscale"? TRUE : FALSE)) busy = TRUE addtimer(CALLBACK(src, .proc/reset_busy), 1.5 SECONDS) else break else if(doccopy) + if(busy) + return for(var/i = 0, i < copies, i++) - if(toner > 5 && !busy && doccopy) + if(attempt_charge(src, usr) & COMPONENT_OBJ_CANCEL_CHARGE) + return + if(toner > 5 && doccopy) new /obj/item/documents/photocopy(loc, doccopy) toner-= 6 // the sprite shows 6 papers, yes I checked busy = TRUE @@ -107,7 +123,11 @@ break updateUsrDialog() else if(ass) //ASS COPY. By Miauw + if(busy) + return for(var/i = 0, i < copies, i++) + if(attempt_charge(src, usr) & COMPONENT_OBJ_CANCEL_CHARGE) + return var/icon/temp_img if(ishuman(ass) && (ass.get_item_by_slot(ITEM_SLOT_ICLOTHING) || ass.get_item_by_slot(ITEM_SLOT_OCLOTHING))) to_chat(usr, "You feel kind of silly, copying [ass == usr ? "your" : ass][ass == usr ? "" : "\'s"] ass with [ass == usr ? "your" : "[ass.p_their()]"] clothes on." ) diff --git a/tgstation.dme b/tgstation.dme index 87181078c6e..f416b29f1cf 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -426,6 +426,7 @@ #include "code\datums\components\omen.dm" #include "code\datums\components\orbiter.dm" #include "code\datums\components\paintable.dm" +#include "code\datums\components\payment.dm" #include "code\datums\components\pellet_cloud.dm" #include "code\datums\components\pricetag.dm" #include "code\datums\components\punchcooldown.dm"