[MIRROR] Refactors mail, delivery and goodies code (#6432)

* Refactors mail and delivery code (#59730)

- Mail now uses weakreferences to minds, which means the presence of
  mail will not cause harddels, and persist between mindswaps or cloning
  or whatever horrible mob transfer things you've got going on.
- The code for creating a crate of mail has been refactored into a
  single proc, rather than having the same code twice.
- Instead of special casing reagents being delivered, instead
  reagent mail goodies are just regular bottle items like any other.

* Refactors mail, delivery and goodies code

Co-authored-by: coiax <yellowbounder@gmail.com>
This commit is contained in:
SkyratBot
2021-06-22 00:48:42 +01:00
committed by GitHub
co-authored by coiax
parent 1f53e5d6af
commit b37a7f134e
8 changed files with 98 additions and 71 deletions
+55 -34
View File
@@ -14,8 +14,8 @@
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
/// Destination tagging for the mail sorter.
var/sort_tag = 0
/// Who this mail is for and who can open it.
var/datum/weakref/recipient
/// Weak reference to who this mail is for and who can open it.
var/datum/weakref/recipient_ref
/// How many goodies this mail contains.
var/goodie_count = 1
/// Goodies which can be given to anyone. The base weight for cash is 56. For there to be a 50/50 chance of getting a department item, they need 56 weight as well.
@@ -109,9 +109,13 @@
playsound(loc, 'sound/machines/twobeep_high.ogg', 100, TRUE)
/obj/item/mail/attack_self(mob/user)
if(recipient && user != recipient)
to_chat(user, span_notice("You can't open somebody else's mail! That's <em>illegal</em>!"))
return
if(recipient_ref)
var/datum/mind/recipient = recipient_ref.resolve()
// If the recipient's mind has gone, then anyone can open their mail
// whether a mind can actually be qdel'd is an exercise for the reader
if(recipient && recipient != user?.mind)
to_chat(user, span_notice("You can't open somebody else's mail! That's <em>illegal</em>!"))
return
to_chat(user, span_notice("You start to unwrap the package..."))
if(!do_after(user, 1.5 SECONDS, target = user))
@@ -125,6 +129,7 @@
/obj/item/mail/examine_more(mob/user)
. = ..()
var/list/msg = list(span_notice("<i>You notice the postmarking on the front of the mail...</i>"))
var/datum/mind/recipient = recipient_ref.resolve()
if(recipient)
msg += "\t[span_info("Certified NT mail for [recipient].")]"
else
@@ -132,13 +137,15 @@
msg += "\t[span_info("Distribute by hand or via destination tagger using the certified NT disposal system.")]"
return msg
/// Accepts a mob to initialize goodies for a piece of mail.
/obj/item/mail/proc/initialize_for_recipient(mob/new_recipient)
recipient = new_recipient
name = "[initial(name)] for [new_recipient.real_name] ([new_recipient.job])"
/// Accepts a mind to initialize goodies for a piece of mail.
/obj/item/mail/proc/initialize_for_recipient(datum/mind/recipient)
name = "[initial(name)] for [recipient.name] ([recipient.assigned_role])"
recipient_ref = WEAKREF(recipient)
var/mob/living/body = recipient.current
var/list/goodies = generic_goodies
var/datum/job/this_job = SSjob.name_occupations[new_recipient.job]
var/datum/job/this_job = SSjob.name_occupations[recipient.assigned_role]
if(this_job)
if(this_job.paycheck_department && department_colors[this_job.paycheck_department])
color = department_colors[this_job.paycheck_department]
@@ -152,14 +159,8 @@
for(var/iterator = 0, iterator < goodie_count, iterator++)
var/target_good = pickweight(goodies)
if(ispath(target_good, /datum/reagent))
var/obj/item/reagent_containers/target_container = new /obj/item/reagent_containers/glass/bottle(src)
target_container.reagents.add_reagent(target_good, target_container.volume)
target_container.name = "[target_container.reagents.reagent_list[1].name] bottle"
new_recipient.log_message("[key_name(new_recipient)] received reagent container [target_container.name] in the mail ([target_good])", LOG_GAME)
else
var/atom/movable/target_atom = new target_good(src)
new_recipient.log_message("[key_name(new_recipient)] received [target_atom.name] in the mail ([target_good])", LOG_GAME)
var/atom/movable/target_atom = new target_good(src)
body.log_message("[key_name(body)] received [target_atom.name] in the mail ([target_good])", LOG_GAME)
return TRUE
@@ -202,11 +203,6 @@
desc = "A certified post crate from CentCom."
icon_state = "mail"
/// Crate for mail that automatically generates a lot of mail. Usually only normal mail, but on lowpop it may end up just being junk.
/obj/structure/closet/crate/mail/full
name = "brimming mail crate"
desc = "A certified post crate from CentCom. Looks stuffed to the gills."
/obj/structure/closet/crate/mail/update_icon_state()
. = ..()
if(opened)
@@ -216,26 +212,51 @@
else
icon_state = "[initial(icon_state)]sealed"
/obj/structure/closet/crate/mail/full/Initialize()
. = ..()
/// Fills this mail crate with N pieces of mail, where N is the lower of the amount var passed, and the maximum capacity of this crate. If N is larger than the number of alive human players, the excess will be junkmail.
/obj/structure/closet/crate/mail/proc/populate(amount)
var/mail_count = min(amount, storage_capacity)
// Fills the
var/list/mail_recipients = list()
for(var/mob/living/carbon/human/alive in GLOB.player_list)
if(alive.stat != DEAD)
mail_recipients += alive
for(var/iterator in 1 to storage_capacity)
for(var/mob/living/carbon/human/human in GLOB.player_list)
if(human.stat == DEAD || !human.mind)
continue
// Skip wizards, nuke ops, cyborgs; Centcom does not send them mail
if(!SSjob.GetJob(human.mind.assigned_role) || (human.mind.assigned_role in GLOB.nonhuman_positions))
continue
mail_recipients += human.mind
for(var/i in 1 to mail_count)
var/obj/item/mail/new_mail
if(prob(FULL_CRATE_LETTER_ODDS))
new_mail = new /obj/item/mail(src)
else
new_mail = new /obj/item/mail/envelope(src)
var/mob/living/carbon/human/mail_to
mail_to = pick(mail_recipients)
if(mail_to)
new_mail.initialize_for_recipient(mail_to)
mail_recipients -= mail_to //Once picked, the mail crate will need a new recipient.
var/datum/mind/recipient = pick_n_take(mail_recipients)
if(recipient)
new_mail.initialize_for_recipient(recipient)
else
new_mail.junk_mail()
update_icon()
/// Crate for mail that automatically depletes the economy subsystem's pending mail counter.
/obj/structure/closet/crate/mail/economy/Initialize()
. = ..()
populate(SSeconomy.mail_waiting)
SSeconomy.mail_waiting = 0
/// Crate for mail that automatically generates a lot of mail. Usually only normal mail, but on lowpop it may end up just being junk.
/obj/structure/closet/crate/mail/full
name = "brimming mail crate"
desc = "A certified post crate from CentCom. Looks stuffed to the gills."
/obj/structure/closet/crate/mail/full/Initialize()
. = ..()
populate(INFINITY)
/// Mailbag.
/obj/item/storage/bag/mail
+1 -1
View File
@@ -20,7 +20,7 @@
mail_goodies = list(
/obj/item/storage/box/rubbershot = 30,
/datum/reagent/consumable/clownstears = 10,
/obj/item/reagent_containers/glass/bottle/clownstears = 10,
/obj/item/stack/sheet/mineral/plasma = 10,
/obj/item/stack/sheet/mineral/uranium = 10,
)
+3 -3
View File
@@ -19,9 +19,9 @@
family_heirlooms = list(/obj/item/cultivator, /obj/item/reagent_containers/glass/bucket, /obj/item/toy/plush/beeplushie)
mail_goodies = list(
/datum/reagent/toxin/mutagen = 20,
/datum/reagent/saltpetre = 20,
/datum/reagent/diethylamine = 20,
/obj/item/reagent_containers/glass/bottle/mutagen = 20,
/obj/item/reagent_containers/glass/bottle/saltpetre = 20,
/obj/item/reagent_containers/glass/bottle/diethylamine = 20,
/obj/item/gun/energy/floragun = 10,
/obj/effect/spawner/lootdrop/space/rareseed = 5,// These are strong, rare seeds, so use sparingly.
/obj/item/food/monkeycube/bee = 2
+3 -3
View File
@@ -24,9 +24,9 @@
family_heirlooms = list(/obj/item/book/manual/wiki/chemistry, /obj/item/ph_booklet)
mail_goodies = list(
/datum/reagent/flash_powder = 15,
/datum/reagent/exotic_stabilizer = 5,
/datum/reagent/toxin/leadacetate = 5,
/obj/item/reagent_containers/glass/bottle/flash_powder = 15,
/obj/item/reagent_containers/glass/bottle/exotic_stabilizer = 5,
/obj/item/reagent_containers/glass/bottle/leadacetate = 5,
/obj/item/paper/secretrecipe = 1
)
+1 -1
View File
@@ -55,7 +55,7 @@
mail_goodies = list(
/obj/item/storage/box/ingredients/random = 80,
/datum/reagent/consumable/caramel = 20,
/obj/item/reagent_containers/glass/bottle/caramel = 20,
/obj/item/reagent_containers/food/condiment/flour = 20,
/obj/item/reagent_containers/food/condiment/rice = 20,
/obj/item/reagent_containers/food/condiment/enzyme = 15,
@@ -26,7 +26,7 @@
/obj/item/scalpel/advanced = 6,
/obj/item/retractor/advanced = 6,
/obj/item/cautery/advanced = 6,
/datum/reagent/toxin/formaldehyde = 6,
/obj/item/reagent_containers/glass/bottle/formaldehyde = 6,
/obj/effect/spawner/lootdrop/organ_spawner = 5,
/obj/effect/spawner/lootdrop/memeorgans = 1
)
@@ -420,3 +420,35 @@
/obj/item/reagent_containers/glass/bottle/thermite
name = "thermite bottle"
list_reagents = list(/datum/reagent/thermite = 30)
// Bottles for mail goodies.
/obj/item/reagent_containers/glass/bottle/clownstears
name = "bottle of distilled clown misery"
desc = "A small bottle. Contains a mythical liquid used by sublime bartenders; made from the unhappiness of clowns."
list_reagents = list(/datum/reagent/consumable/clownstears = 30)
/obj/item/reagent_containers/glass/bottle/saltpetre
name = "saltpetre bottle"
desc = "A small bottle. Contains saltpetre."
list_reagents = list(/datum/reagent/saltpetre = 30)
/obj/item/reagent_containers/glass/bottle/flash_powder
name = "flash powder bottle"
desc = "A small bottle. Contains flash powder."
list_reagents = list(/datum/reagent/flash_powder = 30)
/obj/item/reagent_containers/glass/bottle/exotic_stabilizer
name = "exotic stabilizer bottle"
desc = "A small bottle. Contains exotic stabilizer."
list_reagents = list(/datum/reagent/exotic_stabilizer = 30)
/obj/item/reagent_containers/glass/bottle/leadacetate
name = "lead acetate bottle"
desc = "A small bottle. Contains lead acetate."
list_reagents = list(/datum/reagent/toxin/leadacetate = 30)
/obj/item/reagent_containers/glass/bottle/caramel
name = "bottle of caramel"
desc = "A bottle containing caramalized sugar, also known as caramel. Do not lick."
list_reagents = list(/datum/reagent/consumable/caramel = 30)
+2 -28
View File
@@ -246,6 +246,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
//Early return if there's no mail waiting to prevent taking up a slot. We also don't send mails on sundays or holidays.
if(!SSeconomy.mail_waiting || SSeconomy.mail_blocked)
return
//spawn crate
var/list/empty_turfs = list()
for(var/place as anything in shuttle_areas)
@@ -254,35 +255,8 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
if(shuttle_floor.is_blocked_turf())
continue
empty_turfs += shuttle_floor
var/obj/structure/closet/crate/mail/mailcrate = new(pick(empty_turfs))
//collect recipients
var/list/mail_recipients = list()
for(var/mob/living/carbon/human/player_human in shuffle(GLOB.player_list))
if(player_human.stat == DEAD)
continue
if(!SSjob.GetJob(player_human.mind.assigned_role) || (player_human.mind.assigned_role in GLOB.nonhuman_positions))
continue //this check stops wizards and nuke ops from getting mail, which is hilarious but should definitely not happen
mail_recipients += player_human
//Creates mail for all the mail waiting to arrive, if there's nobody to recieve it it's just junkmail.
for(var/mail_iterator in 1 to SSeconomy.mail_waiting)
var/obj/item/mail/new_mail
if(prob(FULL_CRATE_LETTER_ODDS))
new_mail = new /obj/item/mail(mailcrate)
else
new_mail = new /obj/item/mail/envelope(mailcrate)
var/mob/living/carbon/human/mail_to
if(mail_recipients.len)
mail_to = pick(mail_recipients)
new_mail.initialize_for_recipient(mail_to)
mail_recipients -= mail_to
else
new_mail.junk_mail()
if(new_mail)
SSeconomy.mail_waiting -= 1
mailcrate.update_icon()
return mailcrate
new /obj/structure/closet/crate/mail/economy(pick(empty_turfs))
#undef GOODY_FREE_SHIPPING_MAX
#undef CRATE_TAX