mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 09:42:29 +00:00
Prevents Debug ID Card from Polluting Cargo Budget By Doing It Right (#82214) ## About The Pull Request Fixes #81755 Alright instead of piggybacking off the departmental/non-departmental distinction and prevent ourselves from constantly abusing the cargo budget in order to achieve the very-specific effect of not wanting players to abuse this card in certain contexts let's just leverage the framework and expand it so that we can snowflake for admin/`holder` use cases in stuff like debugging code on a local server while preventing some player from stealing it off a newbie admin and immediately wrecking the economy (although it is funny). ## Why It's Good For The Game Probably a bad idea to continue to abuse the cargo budget like this since the only reason why it's structured that way is just for specific use-case exemptions in certain contexts - let's just do our own thing now :3 ## Changelog 🆑 admin: Advanced Debug Cards will still provide a whole lot of access, but the way the money on those cards work is now a bit different. Players shouldn't be able to use the money on those cards in any context though, don't fret about that. Just know that the money printer goes wrrrr /🆑 --------- Co-authored-by: san7890 <the@san7890.com> Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
182 lines
7.3 KiB
Plaintext
182 lines
7.3 KiB
Plaintext
|
|
/**
|
|
* 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
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE ///NO OVERRIDING TO CHEESE BOUNTIES
|
|
///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
|
|
///Does this payment component respect same-department-discount?
|
|
var/department_discount = FALSE
|
|
|
|
/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
|
|
|
|
/datum/component/payment/RegisterWithParent()
|
|
RegisterSignal(parent, COMSIG_OBJ_ATTEMPT_CHARGE, PROC_REF(attempt_charge))
|
|
RegisterSignal(parent, COMSIG_OBJ_ATTEMPT_CHARGE_CHANGE, PROC_REF(change_cost))
|
|
|
|
/datum/component/payment/UnregisterFromParent()
|
|
UnregisterSignal(parent, list(COMSIG_OBJ_ATTEMPT_CHARGE, COMSIG_OBJ_ATTEMPT_CHARGE_CHANGE))
|
|
|
|
/datum/component/payment/proc/attempt_charge(datum/source, atom/movable/target, extra_fees = 0)
|
|
SIGNAL_HANDLER
|
|
if(!cost && !extra_fees) //In case a free variant of anything is made it'll skip charging anyone.
|
|
return
|
|
var/total_cost = cost + extra_fees
|
|
if(!ismob(target))
|
|
return COMPONENT_OBJ_CANCEL_CHARGE
|
|
var/mob/living/user = target
|
|
if(HAS_SILICON_ACCESS(user) || isdrone(user)) //They have evolved beyond the need for mere credits
|
|
return
|
|
var/obj/item/card/id/card
|
|
if(istype(user))
|
|
card = user.get_idcard(TRUE)
|
|
if(!card && istype(user.pulling, /obj/item/card/id))
|
|
card = user.pulling
|
|
if(handle_card(user, card, total_cost))
|
|
return //Only breaks here if the card can handle the cost of purchasing with someone's ID.
|
|
if(handle_cardless(user, total_cost)) //Here we attempt to handle the purchase physically, with held money first. Otherwise we default to below.
|
|
return
|
|
return COMPONENT_OBJ_CANCEL_CHARGE
|
|
|
|
/**
|
|
* Proc that changes the base cost of the interaction.
|
|
*
|
|
* * source: Datum source of the thing changing the cost.
|
|
* * new_cost: the int value of the attempted new_cost to replace the cost value.
|
|
*/
|
|
/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
|
|
|
|
/**
|
|
* Attempts to charge the mob, user, an integer number of credits, total_cost, without the use of an ID card to directly draw upon.
|
|
*/
|
|
/datum/component/payment/proc/handle_cardless(mob/living/user, total_cost)
|
|
//Here is all the possible non-ID payment methods.
|
|
var/list/counted_money = list()
|
|
var/physical_cash_total = 0
|
|
for(var/obj/item/credit in typecache_filter_list(user.get_all_contents(), GLOB.allowed_money)) //Coins, cash, and credits.
|
|
if(physical_cash_total > total_cost)
|
|
break
|
|
physical_cash_total += credit.get_item_credit_value()
|
|
counted_money += credit
|
|
|
|
if(is_type_in_typecache(user.pulling, GLOB.allowed_money) && (physical_cash_total < total_cost)) //Coins(Pulled).
|
|
var/obj/item/counted_credit = user.pulling
|
|
physical_cash_total += counted_credit.get_item_credit_value()
|
|
counted_money += counted_credit
|
|
|
|
if(physical_cash_total < total_cost)
|
|
var/armless //Suggestions for those with no arms/simple animals.
|
|
if(!ishuman(user) && !isslime(user))
|
|
armless = TRUE
|
|
else
|
|
var/mob/living/carbon/human/harmless_armless = user
|
|
if(!harmless_armless.get_bodypart(BODY_ZONE_L_ARM) && !harmless_armless.get_bodypart(BODY_ZONE_R_ARM))
|
|
armless = TRUE
|
|
|
|
if(armless)
|
|
if(!user.pulling || !iscash(user.pulling) && !istype(user.pulling, /obj/item/card/id))
|
|
to_chat(user, span_notice("Try pulling a valid ID, space cash, holochip or coin while using \the [parent]!"))
|
|
return FALSE
|
|
return FALSE
|
|
|
|
if(physical_cash_total < total_cost)
|
|
to_chat(user, span_notice("Insufficient funds. Aborting."))
|
|
return FALSE
|
|
for(var/obj/cash_object in counted_money)
|
|
qdel(cash_object)
|
|
physical_cash_total -= total_cost
|
|
|
|
if(physical_cash_total > 0)
|
|
var/obj/item/holochip/holochange = new /obj/item/holochip(user.loc, physical_cash_total) //Change is made in holocredits exclusively.
|
|
holochange.name = "[holochange.credits] credit holochip"
|
|
if(ishuman(user))
|
|
var/mob/living/carbon/human/paying_customer = user
|
|
var/successfully_put_in_hands
|
|
ASYNC //Put_in_hands can sleep, we don't want that to block this proc.
|
|
successfully_put_in_hands = paying_customer.put_in_hands(holochange)
|
|
if(!successfully_put_in_hands)
|
|
user.pulling = holochange
|
|
else
|
|
user.pulling = holochange
|
|
log_econ("[total_cost] credits were spent on [parent] by [user].")
|
|
to_chat(user, span_notice("Purchase completed with held credits."))
|
|
playsound(user, 'sound/effects/cashregister.ogg', 20, TRUE)
|
|
return TRUE
|
|
|
|
/**
|
|
* Attempts to charge a mob, user, an integer number of credits, total_cost, directly from an ID card/bank account.
|
|
*/
|
|
/datum/component/payment/proc/handle_card(mob/living/user, obj/item/card/id/idcard, total_cost)
|
|
var/atom/movable/atom_parent = parent
|
|
|
|
if(!idcard)
|
|
if(transaction_style == PAYMENT_VENDING)
|
|
to_chat(user, span_warning("No card found."))
|
|
return FALSE
|
|
if(!idcard?.registered_account)
|
|
switch(transaction_style)
|
|
if(PAYMENT_FRIENDLY)
|
|
to_chat(user, span_warning("There's no account detected on your ID, how mysterious!"))
|
|
if(PAYMENT_ANGRY)
|
|
to_chat(user, span_warning("ARE YOU JOKING. YOU DON'T HAVE A BANK ACCOUNT ON YOUR ID YOU IDIOT."))
|
|
if(PAYMENT_CLINICAL)
|
|
to_chat(user, span_warning("ID Card lacks a bank account. Advancing."))
|
|
if(PAYMENT_VENDING)
|
|
to_chat(user, span_warning("No account found."))
|
|
|
|
return FALSE
|
|
|
|
if(!idcard.can_be_used_in_payment(user))
|
|
atom_parent.say("Departmental accounts have been blacklisted from personal expenses due to embezzlement.")
|
|
return FALSE
|
|
|
|
if(!(idcard.registered_account.has_money(total_cost)))
|
|
switch(transaction_style)
|
|
if(PAYMENT_FRIENDLY)
|
|
to_chat(user, span_warning("I'm so sorry... You don't seem to have enough money."))
|
|
if(PAYMENT_ANGRY)
|
|
to_chat(user, span_warning("YOU MORON. YOU ABSOLUTE BAFOON. YOU INSUFFERABLE TOOL. YOU ARE POOR."))
|
|
if(PAYMENT_CLINICAL)
|
|
to_chat(user, span_warning("ID Card lacks funds. Aborting."))
|
|
if(PAYMENT_VENDING)
|
|
to_chat(user, span_warning("You do not possess the funds to purchase that."))
|
|
atom_parent.balloon_alert(user, "needs [total_cost] credit\s!")
|
|
return FALSE
|
|
target_acc.transfer_money(idcard.registered_account, total_cost, "Nanotrasen: Usage of Corporate Machinery")
|
|
log_econ("[total_cost] credits were spent on [parent] by [user] via [idcard.registered_account.account_holder]'s card.")
|
|
idcard.registered_account.bank_card_talk("[total_cost] credits deducted from your account.")
|
|
playsound(src, 'sound/effects/cashregister.ogg', 20, TRUE)
|
|
SSeconomy.track_purchase(idcard.registered_account, total_cost, parent)
|
|
return TRUE
|
|
|
|
/**
|
|
* Attempts to remove the payment component, currently when the crew wins a revolution.
|
|
* * datum/source: source of the signal.
|
|
*/
|
|
/datum/component/payment/proc/clean_up(datum/source)
|
|
SIGNAL_HANDLER
|
|
target_acc = null
|
|
qdel(src)
|