/// Mail is tamper-evident and unresealable, postmarked by CentCom for an individual recepient. /obj/item/mail name = "mail" gender = NEUTER desc = "An officially postmarked, tamper-evident parcel regulated by CentCom and made of high-quality materials." icon = 'icons/obj/bureaucracy.dmi' icon_state = "mail_small" inhand_icon_state = "paper" worn_icon_state = "paper" item_flags = NOBLUDGEON w_class = WEIGHT_CLASS_SMALL drop_sound = 'sound/items/handling/paper_drop.ogg' pickup_sound = 'sound/items/handling/paper_pickup.ogg' mouse_drag_pointer = MOUSE_ACTIVE_POINTER /// Destination tagging for the mail sorter. var/sort_tag = 0 /// 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. var/list/generic_goodies = list( /obj/item/stack/spacecash/c50 = 10, /obj/item/stack/spacecash/c100 = 25, /obj/item/stack/spacecash/c200 = 15, /obj/item/stack/spacecash/c500 = 5, /obj/item/stack/spacecash/c1000 = 1, ) // Overlays (pure fluff) /// Does the letter have the postmark overlay? var/postmarked = TRUE /// Does the letter have a stamp overlay? var/stamped = TRUE /// List of all stamp overlays on the letter. var/list/stamps = list() /// Maximum number of stamps on the letter. var/stamp_max = 1 /// Physical offset of stamps on the object. X direction. var/stamp_offset_x = 0 /// Physical offset of stamps on the object. Y direction. var/stamp_offset_y = 2 ///mail will have the color of the department the recipient is in. var/static/list/department_colors /obj/item/mail/envelope name = "envelope" icon_state = "mail_large" goodie_count = 2 stamp_max = 2 stamp_offset_y = 5 /obj/item/mail/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_MOVABLE_DISPOSING, .proc/disposal_handling) AddElement(/datum/element/item_scaling, 0.75, 1) if(isnull(department_colors)) department_colors = list( ACCOUNT_CIV = COLOR_WHITE, ACCOUNT_ENG = COLOR_PALE_ORANGE, ACCOUNT_SCI = COLOR_PALE_PURPLE_GRAY, ACCOUNT_MED = COLOR_PALE_BLUE_GRAY, ACCOUNT_SRV = COLOR_PALE_GREEN_GRAY, ACCOUNT_CAR = COLOR_BEIGE, ACCOUNT_SEC = COLOR_PALE_RED_GRAY, ACCOUNT_CMD = COLOR_BLUE_GRAY, // SKYRAT EDIT ADDITION ACCOUNT_CCM = COLOR_DARK_MODERATE_LIME_GREEN, // SKYRAT EDIT ADDITION ) // Icons // Add some random stamps. if(stamped == TRUE) var/stamp_count = rand(1, stamp_max) for(var/i in 1 to stamp_count) stamps += list("stamp_[rand(2, 6)]") update_icon() /obj/item/mail/update_overlays() . = ..() var/bonus_stamp_offset = 0 for(var/stamp in stamps) var/image/stamp_image = image( icon = icon, icon_state = stamp, pixel_x = stamp_offset_x, pixel_y = stamp_offset_y + bonus_stamp_offset ) stamp_image.appearance_flags |= RESET_COLOR add_overlay(stamp_image) bonus_stamp_offset -= 5 if(postmarked == TRUE) var/image/postmark_image = image( icon = icon, icon_state = "postmark", pixel_x = stamp_offset_x + rand(-3, 1), pixel_y = stamp_offset_y + rand(bonus_stamp_offset + 3, 1) ) postmark_image.appearance_flags |= RESET_COLOR add_overlay(postmark_image) /obj/item/mail/attackby(obj/item/W, mob/user, params) // Destination tagging if(istype(W, /obj/item/dest_tagger)) var/obj/item/dest_tagger/destination_tag = W if(sort_tag != destination_tag.currTag) var/tag = uppertext(GLOB.TAGGERLOCATIONS[destination_tag.currTag]) to_chat(user, span_notice("*[tag]*")) sort_tag = destination_tag.currTag playsound(loc, 'sound/machines/twobeep_high.ogg', 100, TRUE) /obj/item/mail/attack_self(mob/user) 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)) return user.temporarilyRemoveItemFromInventory(src, TRUE) if(contents.len) user.put_in_hands(contents[1]) playsound(loc, 'sound/items/poster_ripped.ogg', 50, TRUE) qdel(src) /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 msg += "\t[span_info("Certified mail for [GLOB.station_name].")]" msg += "\t[span_info("Distribute by hand or via destination tagger using the certified NT disposal system.")]" return msg /// 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.title])" recipient_ref = WEAKREF(recipient) var/mob/living/body = recipient.current var/list/goodies = generic_goodies var/datum/job/this_job = recipient.assigned_role if(this_job) if(this_job.paycheck_department && department_colors[this_job.paycheck_department]) color = department_colors[this_job.paycheck_department] var/list/job_goodies = this_job.get_mail_goodies() if(LAZYLEN(job_goodies)) // certain roles and jobs (prisoner) do not receive generic gifts. if(this_job.exclusive_mail_goodies) goodies = job_goodies else goodies += job_goodies for(var/iterator in 1 to goodie_count) var/target_good = pick_weight(goodies) 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 /// Alternate setup, just complete garbage inside and anyone can open /obj/item/mail/proc/junk_mail() var/obj/junk = /obj/item/paper/fluff/junkmail_generic var/special_name = FALSE if(prob(25)) special_name = TRUE junk = pick(list(/obj/item/paper/pamphlet/gateway, /obj/item/paper/pamphlet/violent_video_games, /obj/item/paper/fluff/junkmail_redpill, /obj/effect/decal/cleanable/ash)) var/list/junk_names = list( /obj/item/paper/pamphlet/gateway = "[initial(name)] for [pick(GLOB.adjectives)] adventurers", /obj/item/paper/pamphlet/violent_video_games = "[initial(name)] for the truth about the arcade centcom doesn't want to hear", /obj/item/paper/fluff/junkmail_redpill = "[initial(name)] for those feeling [pick(GLOB.adjectives)] working at Nanotrasen", /obj/effect/decal/cleanable/ash = "[initial(name)] with INCREDIBLY IMPORTANT ARTIFACT- DELIVER TO SCIENCE DIVISION. HANDLE WITH CARE.", ) color = pick(department_colors) //eh, who gives a shit. name = special_name ? junk_names[junk] : "important [initial(name)]" junk = new junk(src) return TRUE /obj/item/mail/proc/disposal_handling(disposal_source, obj/structure/disposalholder/disposal_holder, obj/machinery/disposal/disposal_machine, hasmob) SIGNAL_HANDLER if(!hasmob) disposal_holder.destinationTag = sort_tag /// Subtype that's always junkmail /obj/item/mail/junkmail/Initialize(mapload) . = ..() junk_mail() /// Crate for mail from CentCom. /obj/structure/closet/crate/mail name = "mail crate" desc = "A certified post crate from CentCom." icon_state = "mail" can_install_electronics = FALSE /obj/structure/closet/crate/mail/update_icon_state() . = ..() if(opened) icon_state = "[initial(icon_state)]open" if(locate(/obj/item/mail) in src) icon_state = initial(icon_state) else icon_state = "[initial(icon_state)]sealed" /// 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/human in GLOB.player_list) if(human.stat == DEAD || !human.mind) continue // Skip wizards, nuke ops, cyborgs; Centcom does not send them mail if(!(human.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) 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/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(mapload) . = ..() 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(mapload) . = ..() populate(INFINITY) /// Mailbag. /obj/item/storage/bag/mail name = "mail bag" desc = "A bag for letters, envelopes, and other postage." icon = 'icons/obj/library.dmi' icon_state = "bookbag" worn_icon_state = "bookbag" resistance_flags = FLAMMABLE /obj/item/storage/bag/mail/ComponentInitialize() . = ..() var/datum/component/storage/storage = GetComponent(/datum/component/storage) storage.max_w_class = WEIGHT_CLASS_NORMAL storage.max_combined_w_class = 42 storage.max_items = 21 storage.display_numerical_stacking = FALSE storage.set_holdable(list( /obj/item/mail, /obj/item/small_delivery, /obj/item/paper )) /obj/item/paper/fluff/junkmail_redpill name = "smudged paper" icon_state = "scrap" var/nuclear_option_odds = 0.1 /obj/item/paper/fluff/junkmail_redpill/Initialize(mapload) . = ..() if(!prob(nuclear_option_odds)) // 1 in 1000 chance of getting 2 random nuke code characters. info = "You need to escape the simulation. Don't forget the numbers, they help you remember: '[rand(0,9)][rand(0,9)][rand(0,9)]...'" return var/code = random_nukecode() for(var/obj/machinery/nuclearbomb/selfdestruct/self_destruct in GLOB.nuke_list) self_destruct.r_code = code message_admins("Through junkmail, the self-destruct code was set to \"[code]\".") info = "You need to escape the simulation. Don't forget the numbers, they help you remember: '[code[rand(1,5)]][code[rand(1,5)]]...'" /obj/item/paper/fluff/junkmail_redpill/true //admin letter enabling players to brute force their way through the nuke code if they're so inclined. nuclear_option_odds = 100 /obj/item/paper/fluff/junkmail_generic name = "important document" icon_state = "paper_words" /obj/item/paper/fluff/junkmail_generic/Initialize(mapload) . = ..() info = pick(GLOB.junkmail_messages)