Files
Bubberstation/code/game/objects/items/mail.dm
AnturK 4d6a8bc537 515 Compatibility (#71161)
Makes the code compatible with 515.1594+

Few simple changes and one very painful one.
Let's start with the easy:
* puts call behind `LIBCALL` define, so call_ext is properly used in 515
* Adds `NAMEOF_STATIC(_,X)` macro for nameof in static definitions since
src is now invalid there.
* Fixes tgui and devserver. From 515 onward the tmp3333{procid} cache
directory is not appened to base path in browser controls so we don't
check for it in base js and put the dev server dummy window file in
actual directory not the byond root.
* Renames the few things that had /final/ in typepath to ultimate since
final is a new keyword

And the very painful change:
`.proc/whatever` format is no longer valid, so we're replacing it with
new nameof() function. All this wrapped in three new macros.
`PROC_REF(X)`,`TYPE_PROC_REF(TYPE,X)`,`GLOBAL_PROC_REF(X)`. Global is
not actually necessary but if we get nameof that does not allow globals
it would be nice validation.
This is pretty unwieldy but there's no real alternative.
If you notice anything weird in the commits let me know because majority
was done with regex replace.

@tgstation/commit-access Since the .proc/stuff is pretty big change.

Co-authored-by: san7890 <the@san7890.com>
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
2022-11-15 03:50:11 +00:00

325 lines
12 KiB
Plaintext

/// 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 is 50. For there to be a 50/50 chance of getting a department item, they need 50 weight as well.
var/list/generic_goodies = list(
/obj/effect/spawner/random/entertainment/money_medium = 25,
/obj/effect/spawner/random/food_or_drink/refreshing_beverage = 10,
/obj/effect/spawner/random/food_or_drink/snack = 5,
/obj/effect/spawner/random/food_or_drink/donkpockets_single = 5,
/obj/effect/spawner/random/entertainment/toy = 3,
/obj/effect/spawner/random/entertainment/coin = 2,
)
// 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_REF(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,
)
// 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 <em>illegal</em>!"))
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("<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
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
var/is_mail_restricted = FALSE // certain roles and jobs (prisoner) do not receive generic gifts
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()
is_mail_restricted = this_job.exclusive_mail_goodies
if(LAZYLEN(job_goodies))
if(is_mail_restricted)
goodies = job_goodies
else
goodies += job_goodies
if(!is_mail_restricted)
// the weighted list is 50 (generic items) + 50 (job items)
// every quirk adds 5 to the final weighted list (regardless the number of items or weights in the quirk list)
// 5% is not too high or low so that stacking multiple quirks doesn't tilt the weighted list too much
for(var/datum/quirk/quirk as anything in body.quirks)
if(LAZYLEN(quirk.mail_goodies))
var/quirk_goodie = pick(quirk.mail_goodies)
goodies[quirk_goodie] = 5
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("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/bureaucracy.dmi'
icon_state = "mailbag"
worn_icon_state = "mailbag"
resistance_flags = FLAMMABLE
/obj/item/storage/bag/mail/Initialize(mapload)
. = ..()
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 42
atom_storage.max_slots = 21
atom_storage.numerical_stacking = FALSE
atom_storage.set_holdable(list(
/obj/item/mail,
/obj/item/delivery/small,
/obj/item/paper
))
/obj/item/paper/fluff/junkmail_redpill
name = "smudged paper"
icon_state = "scrap"
show_written_words = FALSE
var/nuclear_option_odds = 0.1
/obj/item/paper/fluff/junkmail_redpill/Initialize(mapload)
var/obj/machinery/nuclearbomb/selfdestruct/self_destruct = locate() in GLOB.nuke_list
if(!self_destruct || !prob(nuclear_option_odds)) // 1 in 1000 chance of getting 2 random nuke code characters.
add_raw_text("<i>You need to escape the simulation. Don't forget the numbers, they help you remember:</i> '[rand(0,9)][rand(0,9)][rand(0,9)]...'")
return ..()
if(self_destruct.r_code == NUKE_CODE_UNSET)
self_destruct.r_code = random_nukecode()
message_admins("Through junkmail, the self-destruct code was set to \"[self_destruct.r_code]\".")
add_raw_text("<i>You need to escape the simulation. Don't forget the numbers, they help you remember:</i> '[self_destruct.r_code[rand(1,5)]][self_destruct.r_code[rand(1,5)]]...'")
return ..()
/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"
show_written_words = FALSE
/obj/item/paper/fluff/junkmail_generic/Initialize(mapload)
default_raw_text = pick(GLOB.junkmail_messages)
return ..()