Files
Bubberstation/code/modules/cargo/coupon.dm
Bloop 2bae025bfe Audits wash/cleaning signals + refactors wash() to ensure no needless mob updates occur (#91259)
## About The Pull Request

This has the potential to create a lot of needless mob updates which is
not great. Now should only update a mob's clothing if it was actually
washed.

This PR

1) ensures that all wash() procs return a bitflag.
2) ensures that `wash()` proccalls which result in expensive operations
like icon updates only do so when it is necessary

## Why It's Good For The Game

Updating mob sprites is expensive, and doing it when nothing has been
changed is bad.

## Changelog

Nothing really player facing
2025-06-02 18:54:53 +00:00

133 lines
4.7 KiB
Plaintext

///datum used by the Coupon Master PDA app to generate coupon items redeemed by a bank account.
/datum/coupon_code
///The pack that'll receive the discount
var/datum/supply_pack/discounted_pack
///The discount of the pack, on a 0 to 1 range.
var/discount
/**
* If set, copies of the coupon code will delete itself after a while if not printed.
* The ones SSmodular_computer.discount_coupons stay intact.
*/
var/expires_in
///Has the coupon been printed. Dictates in which section it's shown, and that it cannot be printed again.
var/printed = FALSE
///The timerid for deletion if expires_in is set.
var/timerid
///Reference to the associated bank account, since we need to clear refs on deletion.
var/datum/bank_account/associated_account
/datum/coupon_code/New(discount, discounted_pack, expires_in)
..()
src.discounted_pack = discounted_pack
src.discount = discount
if(expires_in)
src.expires_in = world.time + expires_in
/datum/coupon_code/Destroy()
if(associated_account)
associated_account.redeemed_coupons -= src
associated_account = null
return ..()
/datum/coupon_code/proc/copy(datum/bank_account/account)
var/datum/coupon_code/copy = new(discount, discounted_pack, expires_in)
copy.associated_account = account
if(account)
LAZYADD(account.redeemed_coupons, src)
if(expires_in)
copy.timerid = QDEL_IN_STOPPABLE(copy, expires_in - world.time)
/datum/coupon_code/proc/generate()
var/obj/item/coupon/coupon = new()
coupon.generate(discount, discounted_pack)
printed = TRUE
deltimer(timerid)
timerid = null
return coupon
/obj/item/coupon
name = "coupon"
desc = "It doesn't matter if you didn't want it before, what matters now is that you've got a coupon for it!"
icon_state = "data_1"
icon = 'icons/obj/card.dmi'
item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_TINY
var/datum/supply_pack/discounted_pack
var/discount_pct_off = 0.05
var/obj/machinery/computer/cargo/inserted_console
/obj/item/coupon/Initialize(mapload)
. = ..()
if(discounted_pack)
update_name()
/// Choose what our prize is :D
/obj/item/coupon/proc/generate(discount, datum/supply_pack/discounted_pack, mob/user)
src.discounted_pack = discounted_pack || pick(GLOB.discountable_packs[pick_weight(GLOB.pack_discount_odds)])
var/static/list/chances = list("0.10" = 4, "0.15" = 8, "0.20" = 10, "0.25" = 8, "0.50" = 4, COUPON_OMEN = 1)
discount_pct_off = discount || pick_weight(chances)
if(discount_pct_off != COUPON_OMEN)
if(!discount) // the discount arg should be a number already, while the keys in the chances list cannot be numbers
discount_pct_off = text2num(discount_pct_off)
update_name()
return
name = "coupon - fuck you"
desc = "The small text reads, 'You will be slaughtered'... That doesn't sound right, does it?"
var/mob/cursed = user || loc
if(!ismob(cursed))
return FALSE
to_chat(cursed, span_warning("The coupon reads '<b>fuck you</b>' in large, bold text... is- is that a prize, or?"))
if(!cursed.GetComponent(/datum/component/omen))
cursed.AddComponent(/datum/component/omen, src, 1)
return TRUE
if(HAS_TRAIT(cursed, TRAIT_CURSED))
to_chat(cursed, span_warning("What a horrible night... To have a curse!"))
addtimer(CALLBACK(src, PROC_REF(curse_heart), cursed), 5 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE)
/obj/item/coupon/update_name()
name = "coupon - [round(discount_pct_off * 100)]% off [initial(discounted_pack.name)]"
return ..()
/// Play stupid games, win stupid prizes
/obj/item/coupon/proc/curse_heart(mob/living/cursed)
if(!iscarbon(cursed))
cursed.gib(DROP_ALL_REMAINS)
burn_evilly()
return TRUE
var/mob/living/carbon/player = cursed
INVOKE_ASYNC(player, TYPE_PROC_REF(/mob, emote), "scream")
to_chat(player, span_mind_control("What could that coupon mean?"))
to_chat(player, span_userdanger("...The suspense is killing you!"))
player.set_heartattack(status = TRUE)
burn_evilly()
/obj/item/coupon/proc/burn_evilly()
visible_message(span_warning("[src] burns up in a sinister flash, taking an evil energy with it..."))
burn()
/obj/item/coupon/attack_atom(obj/attacked_obj, mob/living/user, list/modifiers, list/attack_modifiers)
if(!istype(attacked_obj, /obj/machinery/computer/cargo))
return ..()
if(discount_pct_off == COUPON_OMEN)
to_chat(user, span_warning("\The [attacked_obj] validates the coupon as authentic, but refuses to accept it..."))
attacked_obj.say("Coupon fulfillment already in progress...")
return
inserted_console = attacked_obj
LAZYADD(inserted_console.loaded_coupons, src)
inserted_console.say("Coupon for [initial(discounted_pack.name)] applied!")
forceMove(inserted_console)
/obj/item/coupon/Destroy()
if(inserted_console)
LAZYREMOVE(inserted_console.loaded_coupons, src)
inserted_console = null
return ..()