From b37a7f134e1e030fef83188bdfd59e1e82dd0c76 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 22 Jun 2021 01:48:42 +0200 Subject: [PATCH] [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 --- code/game/objects/items/mail.dm | 89 ++++++++++++------- code/modules/jobs/job_types/bartender.dm | 2 +- code/modules/jobs/job_types/botanist.dm | 6 +- code/modules/jobs/job_types/chemist.dm | 6 +- code/modules/jobs/job_types/cook.dm | 2 +- code/modules/jobs/job_types/medical_doctor.dm | 2 +- .../reagents/reagent_containers/bottle.dm | 32 +++++++ code/modules/shuttle/supply.dm | 30 +------ 8 files changed, 98 insertions(+), 71 deletions(-) diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm index f4663ff4fd1..63e972468f6 100644 --- a/code/game/objects/items/mail.dm +++ b/code/game/objects/items/mail.dm @@ -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 illegal!")) - 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 illegal!")) + 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("You notice the postmarking on the front of the mail...")) + 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 diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm index 8f82f57a338..fd06f8c7ccc 100644 --- a/code/modules/jobs/job_types/bartender.dm +++ b/code/modules/jobs/job_types/bartender.dm @@ -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, ) diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm index 128a2329515..ea6de611f4a 100644 --- a/code/modules/jobs/job_types/botanist.dm +++ b/code/modules/jobs/job_types/botanist.dm @@ -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 diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm index 4c099fa77ce..257f4591ad6 100644 --- a/code/modules/jobs/job_types/chemist.dm +++ b/code/modules/jobs/job_types/chemist.dm @@ -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 ) diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm index 2fd055572a2..f1cb63a7ab7 100644 --- a/code/modules/jobs/job_types/cook.dm +++ b/code/modules/jobs/job_types/cook.dm @@ -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, diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index db593b9b2f6..257f8c280cc 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -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 ) diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm index 6b656f345d7..4432211b560 100644 --- a/code/modules/reagents/reagent_containers/bottle.dm +++ b/code/modules/reagents/reagent_containers/bottle.dm @@ -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) diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index bfcc60c8f3a..7835b8cc2f8 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -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