diff --git a/code/__DEFINES/economy.dm b/code/__DEFINES/economy.dm
index 1238d857047..ccb9a168e77 100644
--- a/code/__DEFINES/economy.dm
+++ b/code/__DEFINES/economy.dm
@@ -1,4 +1,9 @@
+/// Number of paychecks jobs start with at the creation of a new bank account for a player (So at shift-start or game join, but not a blank new account.)
#define STARTING_PAYCHECKS 7
+/// How much mail the Economy SS will create per minute, regardless of firing time.
+#define MAX_MAIL_PER_MINUTE 3
+/// Probability of using letters of envelope sprites on all letters.
+#define FULL_CRATE_LETTER_ODDS 70
//Experimental change: These are subject to tweaking based on the /tg/ economy overhaul.
//Current design direction: Higher paying jobs are vastly outnumbered by lower paying jobs, so anything above medium hurts inflation, common jobs help inflation
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index c4c9e6946f3..7def0b2ac20 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -263,3 +263,5 @@ GLOBAL_LIST_INIT(wisdoms, world.file2list("strings/wisdoms.txt"))
GLOBAL_LIST_INIT(station_numerals, greek_letters + phonetic_alphabet + numbers_as_words + generate_number_strings())
GLOBAL_LIST_INIT(admiral_messages, list("Do you know how expensive these stations are?","Stop wasting my time.","I was sleeping, thanks a lot.","Stand and fight you cowards!","You knew the risks coming in.","Stop being paranoid.","Whatever's broken just build a new one.","No.", "null","Error: No comment given.", "It's a good day to die!"))
+
+GLOBAL_LIST_INIT(junkmail_messages, world.file2list("strings/junkmail.txt"))
diff --git a/code/controllers/subsystem/economy.dm b/code/controllers/subsystem/economy.dm
index a8a0176a125..2ed9c9ed7d5 100644
--- a/code/controllers/subsystem/economy.dm
+++ b/code/controllers/subsystem/economy.dm
@@ -42,6 +42,13 @@ SUBSYSTEM_DEF(economy)
var/market_crashing = FALSE
var/fire_counter_for_paycheck = 0 //SKYRAT EDIT ADDITION
+ /// Total value of exported materials.
+ var/export_total = 0
+ /// Total value of imported goods.
+ var/import_total = 0
+ /// Number of mail items generated.
+ var/mail_waiting = 0
+
/datum/controller/subsystem/economy/Initialize(timeofday)
var/budget_to_hand_out = round(budget_pool / department_accounts.len)
for(var/A in department_accounts)
@@ -51,6 +58,7 @@ SUBSYSTEM_DEF(economy)
/datum/controller/subsystem/economy/fire(resumed = 0)
fire_counter_for_paycheck++ //SKYRAT EDIT ADDITION
var/temporary_total = 0
+ var/delta_time = wait * 0.2
departmental_payouts()
station_total = 0
station_target_buffer += STATION_TARGET_BUFFER
@@ -71,6 +79,8 @@ SUBSYSTEM_DEF(economy)
station_target = max(round(temporary_total / max(bank_accounts_by_id.len * 2, 1)) + station_target_buffer, 1)
if(!market_crashing)
price_update()
+ var/effective_mailcount = round(living_player_count()/(inflation_value - 0.5)) //More mail at low inflation, and vis versa.
+ mail_waiting += clamp(effective_mailcount, 1, MAX_MAIL_PER_MINUTE * delta_time)
/**
* Handy proc for obtaining a department's bank account, given the department ID, AKA the define assigned for what department they're under.
diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm
index 15d05b30183..55ce96d3e83 100644
--- a/code/game/objects/effects/spawners/lootdrop.dm
+++ b/code/game/objects/effects/spawners/lootdrop.dm
@@ -615,6 +615,34 @@
/obj/item/crowbar/red/caravan = 1
)
+/// Mail loot spawner. Some sort of random and rare building tool. No alien tech here.
+/obj/effect/spawner/lootdrop/space/fancytool/engineonly
+ loot = list(
+ /obj/item/wrench/caravan = 1,
+ /obj/item/wirecutters/caravan = 1,
+ /obj/item/screwdriver/caravan = 1,
+ /obj/item/crowbar/red/caravan = 1
+ )
+
+/// Mail loot spawner. Drop pool of advanced medical tools typically from research. Not endgame content.
+/obj/effect/spawner/lootdrop/space/fancytool/advmedicalonly
+ loot = list(
+ /obj/item/scalpel/advanced = 1,
+ /obj/item/retractor/advanced = 1,
+ /obj/item/cautery/advanced = 1
+ )
+
+/// Mail loot spawner. Some sort of random and rare surgical tool. Alien tech found here.
+/obj/effect/spawner/lootdrop/space/fancytool/raremedicalonly
+ loot = list(
+ /obj/item/scalpel/alien = 1,
+ /obj/item/hemostat/alien = 1,
+ /obj/item/retractor/alien = 1,
+ /obj/item/circular_saw/alien = 1,
+ /obj/item/surgicaldrill/alien = 1,
+ /obj/item/cautery/alien = 1
+ )
+
/// Space loot spawner. A bunch of rarer seeds. /obj/item/seeds/random is not a random seed, but an exotic seed.
/obj/effect/spawner/lootdrop/space/rareseed
lootcount = 5
diff --git a/code/game/objects/items/food/meat.dm b/code/game/objects/items/food/meat.dm
index 09aad826c46..0b5404a6022 100644
--- a/code/game/objects/items/food/meat.dm
+++ b/code/game/objects/items/food/meat.dm
@@ -388,6 +388,22 @@
tastes = list("the jungle" = 1, "bananas" = 1, "jimmies" = 1)
spawned_mob = /mob/living/simple_animal/hostile/gorilla
+/obj/item/food/monkeycube/chicken
+ name = "chicken cube"
+ desc = "A new Nanotrasen classic, the chicken cube. Tastes like everything!"
+ bite_consumption = 20
+ food_reagents = list(/datum/reagent/consumable/eggyolk = 30, /datum/reagent/medicine/strange_reagent = 1)
+ tastes = list("chicken" = 1, "the country" = 1, "chicken bouillon" = 1)
+ spawned_mob = /mob/living/simple_animal/chicken
+
+/obj/item/food/monkeycube/bee
+ name = "bee cube"
+ desc = "We were sure it was a good idea. Just add water."
+ bite_consumption = 20
+ food_reagents = list(/datum/reagent/consumable/honey = 10, /datum/reagent/toxin = 5, /datum/reagent/medicine/strange_reagent = 1)
+ tastes = list("buzzing" = 1, "honey" = 1, "regret" = 1)
+ spawned_mob = /mob/living/simple_animal/hostile/poison/bees
+
/obj/item/food/enchiladas
name = "enchiladas"
desc = "Viva La Mexico!"
diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm
new file mode 100644
index 00000000000..25740e2c50c
--- /dev/null
+++ b/code/game/objects/items/mail.dm
@@ -0,0 +1,277 @@
+/// 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
+ /// Who this mail is for and who can open it.
+ var/datum/weakref/recipient
+ /// 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()
+ . = ..()
+ RegisterSignal(src, COMSIG_MOVABLE_DISPOSING, .proc/disposal_handling)
+ AddElement(/datum/element/item_scaling, 0.5, 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 = 1, i <= stamp_count, i++)
+ 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, "*[tag]*")
+ sort_tag = destination_tag.currTag
+ playsound(loc, 'sound/machines/twobeep_high.ogg', 100, TRUE)
+
+/obj/item/mail/attack_self(mob/user)
+ if(recipient && user != recipient)
+ to_chat(user, "You can't open somebody else's mail! That's illegal!")
+ return
+
+ user.visible_message("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)
+
+/// 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])"
+ var/list/goodies = generic_goodies
+
+ var/datum/job/this_job = SSjob.name_occupations[new_recipient.job]
+ 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 = 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)
+
+ 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()
+ ..()
+ 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"
+
+/// 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)
+ 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"
+
+/obj/structure/closet/crate/mail/full/Initialize()
+ . = ..()
+ 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)
+ 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.
+ else
+ new_mail.junk_mail()
+
+
+/// 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()
+ . = ..()
+ 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()
+ . = ..()
+ info = pick(GLOB.junkmail_messages)
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 0478b490889..42233436350 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -141,6 +141,9 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
. = ..()
. += GLOB.uranium_recipes
+/obj/item/stack/sheet/mineral/uranium/five
+ amount = 5
+
/*
* Plasma
*/
@@ -185,6 +188,12 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
atmos_spawn_air("plasma=[amount*10];TEMP=[exposed_temperature]")
qdel(src)
+/obj/item/stack/sheet/mineral/plasma/five
+ amount = 5
+
+/obj/item/stack/sheet/mineral/plasma/thirty
+ amount = 30
+
/*
* Gold
*/
diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm
index 469d53b6503..508632699e0 100644
--- a/code/modules/cargo/exports/large_objects.dm
+++ b/code/modules/cargo/exports/large_objects.dm
@@ -3,7 +3,7 @@
k_elasticity = 0
unit_name = "crate"
export_types = list(/obj/structure/closet/crate)
- exclude_types = list(/obj/structure/closet/crate/large, /obj/structure/closet/crate/wooden)
+ exclude_types = list(/obj/structure/closet/crate/large, /obj/structure/closet/crate/wooden, /obj/structure/closet/crate/mail)
/datum/export/large/crate/total_printout(datum/export_report/ex, notes = TRUE) // That's why a goddamn metal crate costs that much.
. = ..()
diff --git a/code/modules/explorer_drone/exploration_events/resource.dm b/code/modules/explorer_drone/exploration_events/resource.dm
index 610109e94aa..8617fbd1238 100644
--- a/code/modules/explorer_drone/exploration_events/resource.dm
+++ b/code/modules/explorer_drone/exploration_events/resource.dm
@@ -262,9 +262,6 @@
delay_message = "Mining..."
loot_type = /obj/item/stack/sheet/mineral/plasma/thirty
-/obj/item/stack/sheet/mineral/plasma/thirty
- amount = 30
-
/datum/exploration_event/simple/resource/mineral_deposit
name = "MATERIAL Deposit"
required_site_traits = list(EXPLORATION_SITE_SURFACE)
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index f41662f6244..fe6a80bb746 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -67,6 +67,14 @@
var/bounty_types = CIV_JOB_BASIC
+ /// Goodies that can be received via the mail system.
+ // this is a weighted list.
+ /// Keep the _job definition for this empty and use /obj/item/mail to define general gifts.
+ var/list/mail_goodies = list()
+
+ /// If this job's mail goodies compete with generic goodies.
+ var/exclusive_mail_goodies = FALSE
+
///Bitfield of departments this job belongs wit
var/departments = NONE
@@ -301,3 +309,7 @@
types += satchel
types += duffelbag
return types
+
+/// An overridable getter for more dynamic goodies.
+/datum/job/proc/get_mail_goodies(mob/recipient)
+ return mail_goodies
diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm
index 157bf984d4e..19e5691bfda 100644
--- a/code/modules/jobs/job_types/assistant.dm
+++ b/code/modules/jobs/job_types/assistant.dm
@@ -21,6 +21,15 @@ Assistant
family_heirlooms = list(/obj/item/storage/toolbox/mechanical/old/heirloom, /obj/item/clothing/gloves/cut/heirloom)
+ mail_goodies = list(
+ /obj/effect/spawner/lootdrop/donkpockets = 10,
+ /obj/item/clothing/mask/gas = 10,
+ /obj/item/clothing/gloves/color/fyellow = 7,
+ /obj/item/choice_beacon/music = 5,
+ /obj/item/toy/sprayoncan = 3,
+ /obj/item/crowbar/large = 1
+ )
+
/datum/outfit/job/assistant
name = "Assistant"
jobtype = /datum/job/assistant
diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm
index 8988ff97950..71786b203ab 100644
--- a/code/modules/jobs/job_types/bartender.dm
+++ b/code/modules/jobs/job_types/bartender.dm
@@ -18,6 +18,13 @@
family_heirlooms = list(/obj/item/reagent_containers/glass/rag, /obj/item/clothing/head/that, /obj/item/reagent_containers/food/drinks/shaker)
+ mail_goodies = list(
+ /obj/item/storage/box/rubbershot = 30,
+ /datum/reagent/consumable/clownstears = 10,
+ /obj/item/stack/sheet/mineral/plasma = 10,
+ /obj/item/stack/sheet/mineral/uranium = 10,
+ )
+
/datum/outfit/job/bartender
name = "Bartender"
jobtype = /datum/job/bartender
diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm
index 0a22be34d94..128a2329515 100644
--- a/code/modules/jobs/job_types/botanist.dm
+++ b/code/modules/jobs/job_types/botanist.dm
@@ -18,6 +18,15 @@
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/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
+ )
+
/datum/outfit/job/botanist
name = "Botanist"
jobtype = /datum/job/botanist
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index 623c3c5e2ed..51afbaac104 100755
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -26,6 +26,12 @@
family_heirlooms = list(/obj/item/reagent_containers/food/drinks/flask/gold)
+ mail_goodies = list(
+ /obj/item/clothing/mask/cigarette/cigar/havana = 20,
+ /obj/item/storage/fancy/cigarettes/cigars/havana = 15,
+ /obj/item/reagent_containers/food/drinks/bottle/champagne = 10
+ )
+
/datum/job/captain/announce(mob/living/carbon/human/H, announce_captaincy = TRUE)
..()
if(announce_captaincy)
diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm
index 999e77055ed..365a685e3d4 100644
--- a/code/modules/jobs/job_types/cargo_technician.dm
+++ b/code/modules/jobs/job_types/cargo_technician.dm
@@ -20,6 +20,14 @@
family_heirlooms = list(/obj/item/clipboard)
+ mail_goodies = list(
+ /obj/item/pizzabox = 10,
+ /obj/item/stack/sheet/mineral/gold = 5,
+ /obj/item/stack/sheet/mineral/uranium = 4,
+ /obj/item/stack/sheet/mineral/diamond = 3,
+ /obj/item/gun/ballistic/rifle/boltaction = 1
+ )
+
/datum/outfit/job/cargo_tech
name = "Cargo Technician"
jobtype = /datum/job/cargo_technician
diff --git a/code/modules/jobs/job_types/chaplain.dm b/code/modules/jobs/job_types/chaplain.dm
index f4dacfecab7..97ccf3e81fd 100644
--- a/code/modules/jobs/job_types/chaplain.dm
+++ b/code/modules/jobs/job_types/chaplain.dm
@@ -18,6 +18,13 @@
family_heirlooms = list(/obj/item/toy/windup_toolbox, /obj/item/reagent_containers/food/drinks/bottle/holywater)
+ mail_goodies = list(
+ /obj/item/reagent_containers/food/drinks/bottle/holywater = 30,
+ /obj/item/toy/plush/awakenedplushie = 10,
+ /obj/item/grenade/chem_grenade/holy = 5,
+ /obj/item/toy/plush/narplush = 2,
+ /obj/item/toy/plush/ratplush = 1
+ )
/datum/job/chaplain/after_spawn(mob/living/H, mob/M)
. = ..()
diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm
index 8846c224c87..4c099fa77ce 100644
--- a/code/modules/jobs/job_types/chemist.dm
+++ b/code/modules/jobs/job_types/chemist.dm
@@ -23,6 +23,13 @@
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/paper/secretrecipe = 1
+ )
+
/datum/outfit/job/chemist
name = "Chemist"
jobtype = /datum/job/chemist
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
index 60e1194c19f..bd5d1a7e992 100644
--- a/code/modules/jobs/job_types/chief_engineer.dm
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -28,6 +28,15 @@
family_heirlooms = list(/obj/item/clothing/head/hardhat/white, /obj/item/screwdriver, /obj/item/wrench, /obj/item/weldingtool, /obj/item/crowbar, /obj/item/wirecutters)
+ mail_goodies = list(
+ /obj/item/food/cracker = 25, //you know. for poly
+ /obj/item/stack/sheet/mineral/diamond = 15,
+ /obj/item/stack/sheet/mineral/uranium/five = 15,
+ /obj/item/stack/sheet/mineral/plasma/five = 15,
+ /obj/item/stack/sheet/mineral/gold = 15,
+ /obj/effect/spawner/lootdrop/space/fancytool/engineonly = 3
+ )
+
/datum/job/chief_engineer/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
..()
if(announce_captaincy)
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
index 1443f43121a..3f0ccf5a2f7 100644
--- a/code/modules/jobs/job_types/chief_medical_officer.dm
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -26,6 +26,12 @@
display_order = JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER
bounty_types = CIV_JOB_MED
+ mail_goodies = list(
+ /obj/effect/spawner/lootdrop/organ_spawner = 10,
+ /obj/effect/spawner/lootdrop/memeorgans = 8,
+ /obj/effect/spawner/lootdrop/space/fancytool/advmedicalonly = 4,
+ /obj/effect/spawner/lootdrop/space/fancytool/raremedicalonly = 1
+ )
family_heirlooms = list(/obj/item/storage/firstaid/ancient/heirloom)
/datum/job/chief_medical_officer/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm
index 51120431280..ca17d874b58 100644
--- a/code/modules/jobs/job_types/clown.dm
+++ b/code/modules/jobs/job_types/clown.dm
@@ -18,6 +18,14 @@
display_order = JOB_DISPLAY_ORDER_CLOWN
departments = DEPARTMENT_SERVICE
+ mail_goodies = list(
+ /obj/item/food/grown/banana = 100,
+ /obj/item/food/pie/cream = 50,
+ /obj/item/clothing/shoes/clown_shoes/combat = 10,
+ /obj/item/reagent_containers/spray/waterflower/lube = 20, // lube
+ /obj/item/reagent_containers/spray/waterflower/superlube = 1 // Superlube, good lord.
+ )
+
family_heirlooms = list(/obj/item/bikehorn/golden)
/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M)
diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm
index 4d7c2cd585d..bdc849c5cbf 100644
--- a/code/modules/jobs/job_types/cook.dm
+++ b/code/modules/jobs/job_types/cook.dm
@@ -54,6 +54,17 @@
kitchen_areas |= path
+ mail_goodies = list(
+ /obj/item/storage/box/ingredients/random = 80,
+ /datum/reagent/consumable/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,
+ /obj/item/reagent_containers/food/condiment/soymilk = 15,
+ /obj/item/kitchen/knife = 4,
+ /obj/item/kitchen/knife/butcher = 2
+ )
+
/datum/outfit/job/cook
name = "Cook"
jobtype = /datum/job/cook
diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm
index bfc7b634c6d..dd6eb824d2d 100644
--- a/code/modules/jobs/job_types/detective.dm
+++ b/code/modules/jobs/job_types/detective.dm
@@ -23,6 +23,17 @@
display_order = JOB_DISPLAY_ORDER_DETECTIVE
+ mail_goodies = list(
+ /obj/item/storage/fancy/cigarettes = 25,
+ /obj/item/ammo_box/c38 = 25,
+ /obj/item/ammo_box/c38/dumdum = 5,
+ /obj/item/ammo_box/c38/hotshot = 5,
+ /obj/item/ammo_box/c38/iceblox = 5,
+ /obj/item/ammo_box/c38/match = 5,
+ /obj/item/ammo_box/c38/trac = 5,
+ /obj/item/storage/belt/holster/detective/full = 1
+ )
+
family_heirlooms = list(/obj/item/reagent_containers/food/drinks/bottle/whiskey)
/datum/outfit/job/detective
diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm
index 0f3cf95785d..d7ec5d92f95 100644
--- a/code/modules/jobs/job_types/geneticist.dm
+++ b/code/modules/jobs/job_types/geneticist.dm
@@ -19,6 +19,10 @@
display_order = JOB_DISPLAY_ORDER_GENETICIST
bounty_types = CIV_JOB_SCI
+ mail_goodies = list(
+ /obj/item/storage/box/monkeycubes = 10
+ )
+
family_heirlooms = list(/obj/item/clothing/under/shorts/purple)
/datum/outfit/job/geneticist
diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm
index dbeb2c54d93..44115564816 100644
--- a/code/modules/jobs/job_types/head_of_personnel.dm
+++ b/code/modules/jobs/job_types/head_of_personnel.dm
@@ -27,6 +27,11 @@
display_order = JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL
+ mail_goodies = list(
+ /obj/item/card/id/advanced/silver = 10,
+ /obj/item/stack/sheet/bone = 5
+ )
+
family_heirlooms = list(/obj/item/reagent_containers/food/drinks/trophy/silver_cup)
/datum/job/head_of_personnel/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
@@ -56,6 +61,14 @@
if(locate(/datum/holiday/ianbirthday) in SSevents.holidays)
undershirt = /datum/sprite_accessory/undershirt/ian
+//only pet worth reviving
+/datum/job/hop/get_mail_goodies(mob/recipient)
+ . = ..()
+ // Strange Reagent if the pet is dead.
+ for(var/mob/living/simple_animal/pet/dog/corgi/ian/staff_pet in GLOB.dead_mob_list)
+ . += list(/datum/reagent/medicine/strange_reagent = 20)
+ break
+
/obj/item/paper/fluff/ids_for_dummies
name = "Memo: New IDs and You"
desc = "It looks like this was left by the last Head of Personnel to man this station. It explains some information about new IDs."
diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm
index 99bb482a2de..759c73e3cef 100644
--- a/code/modules/jobs/job_types/janitor.dm
+++ b/code/modules/jobs/job_types/janitor.dm
@@ -18,6 +18,12 @@
family_heirlooms = list(/obj/item/mop, /obj/item/clothing/suit/caution, /obj/item/reagent_containers/glass/bucket, /obj/item/paper/fluff/stations/soap)
+ mail_goodies = list(
+ /obj/item/grenade/chem_grenade/cleaner = 30,
+ /obj/item/storage/box/lights/mixed = 20,
+ /obj/item/lightreplacer = 10
+ )
+
/datum/outfit/job/janitor
name = "Janitor"
jobtype = /datum/job/janitor
diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm
index a9f2098bdab..db593b9b2f6 100644
--- a/code/modules/jobs/job_types/medical_doctor.dm
+++ b/code/modules/jobs/job_types/medical_doctor.dm
@@ -21,6 +21,16 @@
family_heirlooms = list(/obj/item/storage/firstaid/ancient/heirloom)
+ mail_goodies = list(
+ /obj/item/healthanalyzer/advanced = 15,
+ /obj/item/scalpel/advanced = 6,
+ /obj/item/retractor/advanced = 6,
+ /obj/item/cautery/advanced = 6,
+ /datum/reagent/toxin/formaldehyde = 6,
+ /obj/effect/spawner/lootdrop/organ_spawner = 5,
+ /obj/effect/spawner/lootdrop/memeorgans = 1
+ )
+
/datum/outfit/job/doctor
name = "Medical Doctor"
jobtype = /datum/job/doctor
diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm
index 63bd512858a..fa54570a473 100644
--- a/code/modules/jobs/job_types/mime.dm
+++ b/code/modules/jobs/job_types/mime.dm
@@ -18,6 +18,13 @@
family_heirlooms = list(/obj/item/food/baguette)
+ mail_goodies = list(
+ /obj/item/food/baguette = 15,
+ /obj/item/food/cheese/wheel = 10,
+ /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing = 10,
+ /obj/item/book/mimery = 1,
+ )
+
/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M)
H.apply_pref_name("mime", M.client)
diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm
index e67b050175b..f5a97f30758 100644
--- a/code/modules/jobs/job_types/paramedic.dm
+++ b/code/modules/jobs/job_types/paramedic.dm
@@ -21,6 +21,15 @@
family_heirlooms = list(/obj/item/storage/firstaid/ancient/heirloom)
+ mail_goodies = list(
+ /obj/item/reagent_containers/hypospray/medipen = 20,
+ /obj/item/reagent_containers/hypospray/medipen/oxandrolone = 10,
+ /obj/item/reagent_containers/hypospray/medipen/salacid = 10,
+ /obj/item/reagent_containers/hypospray/medipen/salbutamol = 10,
+ /obj/item/reagent_containers/hypospray/medipen/penacid = 10,
+ /obj/item/reagent_containers/hypospray/medipen/survival/luxury = 5
+ )
+
/datum/outfit/job/paramedic
name = "Paramedic"
jobtype = /datum/job/paramedic
diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm
index 53d2cef0fea..c25f18921aa 100644
--- a/code/modules/jobs/job_types/prisoner.dm
+++ b/code/modules/jobs/job_types/prisoner.dm
@@ -13,6 +13,11 @@
display_order = JOB_DISPLAY_ORDER_PRISONER
+ exclusive_mail_goodies = TRUE
+ mail_goodies = list (
+ /obj/effect/spawner/lootdrop/prison_contraband = 1
+ )
+
family_heirlooms = list(/obj/item/pen/blue)
/datum/outfit/job/prisoner
diff --git a/code/modules/jobs/job_types/psychologist.dm b/code/modules/jobs/job_types/psychologist.dm
index 601e4aaf0b5..2effa1e4e10 100644
--- a/code/modules/jobs/job_types/psychologist.dm
+++ b/code/modules/jobs/job_types/psychologist.dm
@@ -20,6 +20,12 @@
family_heirlooms = list(/obj/item/storage/pill_bottle)
+ mail_goodies = list(
+ /obj/item/storage/pill_bottle/mannitol = 30,
+ /obj/item/storage/pill_bottle/happy = 5,
+ /obj/item/gun/syringe = 1
+ )
+
/datum/outfit/job/psychologist
name = "Psychologist"
jobtype = /datum/job/psychologist
diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm
index 88c9ae3e435..39cb2827783 100644
--- a/code/modules/jobs/job_types/quartermaster.dm
+++ b/code/modules/jobs/job_types/quartermaster.dm
@@ -21,14 +21,16 @@
display_order = JOB_DISPLAY_ORDER_QUARTERMASTER
bounty_types = CIV_JOB_RANDOM
departments = DEPARTMENT_CARGO
+ family_heirlooms = list(/obj/item/stamp, /obj/item/stamp/denied)
+ mail_goodies = list(
+ /obj/item/circuitboard/machine/emitter = 3
+ )
/datum/job/quartermaster/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
..()
if(announce_captaincy)
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to extreme staffing shortages, newly promoted Acting Captain [H.real_name] on deck!"))
- family_heirlooms = list(/obj/item/stamp, /obj/item/stamp/denied)
-
/datum/outfit/job/quartermaster
name = "Quartermaster"
jobtype = /datum/job/quartermaster
diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm
index 36f0ee282e2..99a737e2ca8 100644
--- a/code/modules/jobs/job_types/research_director.dm
+++ b/code/modules/jobs/job_types/research_director.dm
@@ -24,6 +24,12 @@
display_order = JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR
bounty_types = CIV_JOB_SCI
+ mail_goodies = list(
+ /obj/item/storage/box/monkeycubes = 30,
+ /obj/item/circuitboard/machine/sleeper/party = 3,
+ /obj/item/borg/upgrade/ai = 2
+ )
+
family_heirlooms = list(/obj/item/toy/plush/slimeplushie)
/datum/job/research_director/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm
index 940cb7b178c..97de5e21d04 100644
--- a/code/modules/jobs/job_types/roboticist.dm
+++ b/code/modules/jobs/job_types/roboticist.dm
@@ -19,6 +19,12 @@
display_order = JOB_DISPLAY_ORDER_ROBOTICIST
+ mail_goodies = list(
+ /obj/item/storage/box/flashes = 20,
+ /obj/item/stack/sheet/iron/twenty = 15,
+ /obj/item/modular_computer/tablet/preset/advanced = 5
+ )
+
family_heirlooms = list(/obj/item/toy/plush/pkplush)
/datum/job/roboticist/New()
diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm
index 1adca28c5c9..0bf0141092a 100644
--- a/code/modules/jobs/job_types/scientist.dm
+++ b/code/modules/jobs/job_types/scientist.dm
@@ -21,6 +21,12 @@
family_heirlooms = list(/obj/item/toy/plush/slimeplushie)
+ mail_goodies = list(
+ /obj/item/raw_anomaly_core/random = 10,
+ /obj/item/disk/tech_disk/spaceloot = 2,
+ /obj/item/camera_bug = 1
+ )
+
/datum/outfit/job/scientist
name = "Scientist"
jobtype = /datum/job/scientist
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index c800e2521b7..06505ff7e76 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -26,6 +26,14 @@
family_heirlooms = list(/obj/item/book/manual/wiki/security_space_law, /obj/item/clothing/head/beret/sec)
+ mail_goodies = list(
+ /obj/item/food/donut/caramel = 10,
+ /obj/item/food/donut/matcha = 10,
+ /obj/item/food/donut/blumpkin = 5,
+ /obj/item/clothing/mask/whistle = 5,
+ /obj/item/melee/baton/boomerang/loaded = 1
+ )
+
GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
/**
diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm
index 34a1b33a164..690090bdba3 100644
--- a/code/modules/jobs/job_types/station_engineer.dm
+++ b/code/modules/jobs/job_types/station_engineer.dm
@@ -23,6 +23,13 @@
family_heirlooms = list(/obj/item/clothing/head/hardhat, /obj/item/screwdriver, /obj/item/wrench, /obj/item/weldingtool, /obj/item/crowbar, /obj/item/wirecutters)
+ mail_goodies = list(
+ /obj/item/storage/box/lights/mixed = 20,
+ /obj/item/lightreplacer = 10,
+ /obj/item/holosign_creator/engineering = 8,
+ /obj/item/clothing/head/hardhat/red/upgraded = 1
+ )
+
/datum/outfit/job/engineer
name = "Station Engineer"
jobtype = /datum/job/station_engineer
diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm
index bf11dcc53c7..b5e6a5e64ce 100644
--- a/code/modules/jobs/job_types/virologist.dm
+++ b/code/modules/jobs/job_types/virologist.dm
@@ -23,6 +23,15 @@
family_heirlooms = list(/obj/item/reagent_containers/syringe)
+ mail_goodies = list(
+ /obj/item/reagent_containers/glass/bottle/random_virus = 15,
+ /obj/item/reagent_containers/glass/bottle/formaldehyde = 10,
+ /obj/item/reagent_containers/glass/bottle/synaptizine = 10,
+ /obj/item/stack/sheet/mineral/plasma = 10,
+ /obj/item/stack/sheet/mineral/uranium = 5
+ )
+
+
/datum/outfit/job/virologist
name = "Virologist"
jobtype = /datum/job/virologist
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index 9d82a1291f9..47c1e9dc198 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -26,6 +26,15 @@
family_heirlooms = list(/obj/item/book/manual/wiki/security_space_law)
+ mail_goodies = list(
+ /obj/item/storage/fancy/cigarettes = 15,
+ /obj/item/storage/box/handcuffs = 10,
+ /obj/item/storage/box/teargas = 10,
+ /obj/item/storage/box/flashbangs = 10,
+ /obj/item/storage/box/rubbershot = 10,
+ /obj/item/storage/box/lethalshot = 5
+ )
+
/datum/outfit/job/warden
name = "Warden"
jobtype = /datum/job/warden
diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm
index 1d80af38590..a7e9273a0e1 100644
--- a/code/modules/recycling/disposal/holder.dm
+++ b/code/modules/recycling/disposal/holder.dm
@@ -41,21 +41,15 @@
// now everything inside the disposal gets put into the holder
// note AM since can contain mobs or objs
for(var/A in D)
- var/atom/movable/AM = A
- if(AM == src)
+ var/atom/movable/atom_in_transit = A
+ if(atom_in_transit == src)
continue
- SEND_SIGNAL(AM, COMSIG_MOVABLE_DISPOSING, src, D)
- AM.forceMove(src)
- if(istype(AM, /obj/structure/big_delivery) && !hasmob)
- var/obj/structure/big_delivery/T = AM
- src.destinationTag = T.sortTag
- else if(istype(AM, /obj/item/small_delivery) && !hasmob)
- var/obj/item/small_delivery/T = AM
- src.destinationTag = T.sortTag
- else if(istype(AM, /mob/living/silicon/robot))
- var/obj/item/dest_tagger/borg/tagger = locate() in AM
- if (tagger)
- src.destinationTag = tagger.currTag
+ SEND_SIGNAL(atom_in_transit, COMSIG_MOVABLE_DISPOSING, src, D, hasmob)
+ atom_in_transit.forceMove(src)
+ if(iscyborg(atom_in_transit))
+ var/obj/item/dest_tagger/borg/tagger = locate() in atom_in_transit
+ if(tagger)
+ destinationTag = tagger.currTag
// start the movement process
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index 09e99cea0ce..5e1c899769c 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -6,10 +6,14 @@
density = TRUE
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
var/giftwrapped = FALSE
- var/sortTag = 0
+ var/sort_tag = 0
var/obj/item/paper/note
var/obj/item/barcode/sticker
+/obj/structure/big_delivery/Initialize()
+ . = ..()
+ RegisterSignal(src, COMSIG_MOVABLE_DISPOSING, .proc/disposal_handling)
+
/obj/structure/big_delivery/interact(mob/user)
to_chat(user, "You start to unwrap the package...")
if(!do_after(user, 15, target = user))
@@ -49,10 +53,10 @@
if(istype(W, /obj/item/dest_tagger))
var/obj/item/dest_tagger/O = W
- if(sortTag != O.currTag)
+ if(sort_tag != O.currTag)
var/tag = uppertext(GLOB.TAGGERLOCATIONS[O.currTag])
to_chat(user, "*[tag]*")
- sortTag = O.currTag
+ sort_tag = O.currTag
playsound(loc, 'sound/machines/twobeep_high.ogg', 100, TRUE)
else if(istype(W, /obj/item/pen))
@@ -164,6 +168,11 @@
for(var/obj/I in src.GetAllContents())
SEND_SIGNAL(I, COMSIG_STRUCTURE_UNWRAPPED)
+/obj/structure/big_delivery/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
+
/obj/item/small_delivery
name = "parcel"
desc = "A brown paper delivery parcel."
@@ -171,10 +180,14 @@
icon_state = "deliverypackage3"
inhand_icon_state = "deliverypackage"
var/giftwrapped = 0
- var/sortTag = 0
+ var/sort_tag = 0
var/obj/item/paper/note
var/obj/item/barcode/sticker
+/obj/item/small_delivery/Initialize()
+ . = ..()
+ RegisterSignal(src, COMSIG_MOVABLE_DISPOSING, .proc/disposal_handling)
+
/obj/item/small_delivery/contents_explosion(severity, target)
switch(severity)
if(EXPLODE_DEVASTATE)
@@ -231,10 +244,10 @@
if(istype(W, /obj/item/dest_tagger))
var/obj/item/dest_tagger/O = W
- if(sortTag != O.currTag)
+ if(sort_tag != O.currTag)
var/tag = uppertext(GLOB.TAGGERLOCATIONS[O.currTag])
to_chat(user, "*[tag]*")
- sortTag = O.currTag
+ sort_tag = O.currTag
playsound(loc, 'sound/machines/twobeep_high.ogg', 100, TRUE)
else if(istype(W, /obj/item/pen))
@@ -324,6 +337,11 @@
for(var/obj/I in src.GetAllContents())
SEND_SIGNAL(I, COMSIG_ITEM_UNWRAPPED)
+/obj/item/small_delivery/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
+
/obj/item/dest_tagger
name = "destination tagger"
desc = "Used to set the destination of properly wrapped packages."
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index f08da743024..aed11b76b71 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -28,6 +28,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
/obj/machinery/launchpad,
/obj/machinery/disposal,
/obj/structure/disposalpipe,
+ /obj/item/mail,
/obj/item/hilbertshotel,
/obj/machinery/camera,
/obj/item/gps,
@@ -82,6 +83,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
/obj/docking_port/mobile/supply/initiate_docking()
if(getDockedId() == "supply_away") // Buy when we leave home.
buy()
+ create_mail()
. = ..() // Fly/enter transit.
if(. != DOCKING_SUCCESS)
return
@@ -197,6 +199,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
SO.generateCombo(miscboxes[I], I, misc_contents[I])
qdel(SO)
+ SSeconomy.import_total += value
var/datum/bank_account/cargo_budget = SSeconomy.get_dep_account(ACCOUNT_CAR)
investigate_log("[purchases] orders in this shipment, worth [value] credits. [cargo_budget.account_balance] credits left.", INVESTIGATE_CARGO)
@@ -230,8 +233,53 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
msg += export_text + "\n"
D.adjust_money(ex.total_value[E])
+ SSeconomy.export_total += (D.account_balance - presale_points)
SSshuttle.centcom_message = msg
investigate_log("Shuttle contents sold for [D.account_balance - presale_points] credits. Contents: [ex.exported_atoms ? ex.exported_atoms.Join(",") + "." : "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO)
+/*
+ Generates a box of mail depending on our exports and imports.
+ Applied in the cargo shuttle sending/arriving, by building the crate if the round is ready to introduce mail based on the economy subsystem.
+ Then, fills the mail crate with mail, by picking applicable crew who can recieve mail at the time to sending.
+*/
+/obj/docking_port/mobile/supply/proc/create_mail()
+ //Early return if there's no mail waiting to prevent taking up a slot.
+ if(!SSeconomy.mail_waiting)
+ return
+ //spawn crate
+ var/list/empty_turfs = list()
+ for(var/place as anything in shuttle_areas)
+ var/area/shuttle/shuttle_area = place
+ for(var/turf/open/floor/shuttle_floor in shuttle_area)
+ 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 GLOB.player_list)
+ if(player_human.stat != DEAD)
+ 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
+
#undef GOODY_FREE_SHIPPING_MAX
#undef CRATE_TAX
diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm
index 84e5430aea7..66079daee29 100644
--- a/code/modules/vending/wardrobes.dm
+++ b/code/modules/vending/wardrobes.dm
@@ -147,22 +147,30 @@
icon_state = "cargodrobe"
product_ads = "Upgraded Assistant Style! Pick yours today!;These shorts are comfy and easy to wear, get yours now!"
vend_reply = "Thank you for using the CargoDrobe!"
- products = list(/obj/item/clothing/suit/hooded/wintercoat/cargo = 3,
- /obj/item/clothing/under/rank/cargo/tech = 3,
- /obj/item/clothing/under/rank/cargo/tech/skirt = 3,
- /obj/item/clothing/under/misc/cargo_long = 3, //SKYRAT EDIT ADDITION START
- /obj/item/clothing/under/utility/cargo/gorka = 3,
- /obj/item/clothing/under/utility/cargo/turtleneck = 3,
- /obj/item/clothing/under/utility/cargo = 3,
- /obj/item/clothing/suit/gorka/supply = 3,
- /obj/item/clothing/suit/toggle/jacket/supply = 3, //SKYRAT EDIT ADDITION END
- /obj/item/clothing/shoes/sneakers/black = 3,
- /obj/item/clothing/gloves/fingerless = 3,
- /obj/item/clothing/head/soft = 3,
- /obj/item/radio/headset/headset_cargo = 3)
- premium = list(/obj/item/clothing/under/rank/cargo/miner = 3)
+ products = list(
+ /obj/item/storage/bag/mail = 3,
+ /obj/item/clothing/suit/hooded/wintercoat/cargo = 3,
+ /obj/item/clothing/under/rank/cargo/tech = 3,
+ /obj/item/clothing/under/rank/cargo/tech/skirt = 3,
+ /obj/item/clothing/under/misc/cargo_long = 3, //SKYRAT EDIT ADDITION START
+ /obj/item/clothing/under/utility/cargo/gorka = 3,
+ /obj/item/clothing/under/utility/cargo/turtleneck = 3,
+ /obj/item/clothing/under/utility/cargo = 3,
+ /obj/item/clothing/suit/gorka/supply = 3,
+ /obj/item/clothing/suit/toggle/jacket/supply = 3, //SKYRAT EDIT ADDITION END
+ /obj/item/clothing/shoes/sneakers/black = 3,
+ /obj/item/clothing/gloves/fingerless = 3,
+ /obj/item/clothing/head/soft = 3,
+ /obj/item/radio/headset/headset_cargo = 3
+ )
+ premium = list(
+ /obj/item/clothing/under/rank/cargo/miner = 3,
+ /obj/item/clothing/head/mailman = 1,
+ /obj/item/clothing/under/misc/mailman = 1
+ )
refill_canister = /obj/item/vending_refill/wardrobe/cargo_wardrobe
payment_department = ACCOUNT_CAR
+
/obj/item/vending_refill/wardrobe/cargo_wardrobe
machine_name = "CargoDrobe"
diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi
index 4754c8375e9..6578e08fa0d 100644
Binary files a/icons/obj/bureaucracy.dmi and b/icons/obj/bureaucracy.dmi differ
diff --git a/icons/obj/crates.dmi b/icons/obj/crates.dmi
index 98ccc6b2ff1..3ae97bcc364 100644
Binary files a/icons/obj/crates.dmi and b/icons/obj/crates.dmi differ
diff --git a/strings/junkmail.txt b/strings/junkmail.txt
new file mode 100644
index 00000000000..db916907d8a
--- /dev/null
+++ b/strings/junkmail.txt
@@ -0,0 +1,14 @@
+Hello! I am executive at Nanotrasen Nigel Takall. Due to accounting error all of my salary is stored in an account unreachable. In order to withdraw I am required to utilize your account to make a deposit to confirm my reality situation. In exchange for a temporary deposit I will give you a payment 1000 credits. All I need is access to your account. Will you be assistant please?
+WE NEED YOUR BLOOD! WE ARE AN ANARCHO-COMMUNIST VAMPIRE COMMUNE. BLOOD ONLY LASTS 42 DAYS BEFORE IT GOES BAD! WE DO NOT HAVE NANOTRASEN STASIS! PLEASE, SEND BLOOD! THANK YOU! OR WE KILL YOU!
+Triple deposits are waiting for you at MaxBet Online when you register to play with us. You can qualify for a 200% Welcome Bonus at MaxBet Online when you sign up today. Once you are a player with MaxBet, you will also receive lucrative weekly and monthly promotions. You will be able to enjoy over 450 top-flight casino games at MaxBet.
+Hello !, I'm the former HoS of your deerest station accused by the Nanotrasen of being a traitor . I was the best we had to offer but it seems that nanotramsen has turned their back on me. I need 2000 credits to pay for my bail and then we can restore order on space station 14!
+Hello, I noticed you riding in a 2555 Ripley and wondered if you'd be interested in selling. Low mileage mechs sell very well in our current market. Please call 223-334-3245 if you're interested
+Resign Now. I’m on you now. You are fucking with me now Let’s see who you are. Watch your back , bitch. Call me. Don’t be afraid, you piece of shit. Stand up. If you don’t call, you’re just afraid. And later: I already know where you live, I’m on you. You might as well call me. You will see me. I promise. Bro.
+Clown Planet Is Going To Become Awesome Possum Again! If This Wasn't Sent To A Clown, Disregard. If This Was Sent To A Mime, Blow It Out Your Ass, Space Frenchie! Anyway! We Make Big Progress On Clown Planet After Stupid Mimes BLOW IT ALL TO SAM HELL!!!!! Sorry I Am Mad.. Anyway Come And Visit, Honkles! We Thought You Were Dead Long Time :^()
+MONTHPEOPLE ARE REAL, THE NANOTRASEN DEEP STATE DOESN'T WANT YOU TO SEE THIS! I'VE SEEN THEM IN REAL LIFE, THEY HAVE HUGE EYEBALLS AND NO HEAD. THEY'RE SENTIENT CALENDARS. I'M NOT CRAZY. SEARCH THE CALENDAR INCIDENT ON NTNET. USE A PROXY! #BIGTRUTHS #WAKEYWAKEYSPACEMEN #21STOFSEPTEMBER
+hello 👋👋 nanotrasens! fuck 👈👌 the syndicate! they 👵 got ☄ me 😍😰 questioning my 🤰 loyalty to nanotraben! so 👌💯 please 😫 lets ⛔👀 gather our 📸💩 energy 😎 and 💰🔣 QUICK. 😲 send this 🗑👈 to 💦💊 10 😂😂 other loyal 💯 nanotraysens to 💦🤔 show we 🐶 dont 🙅🚫 take 🛍 nothing from 😂 the ✝ syndicate!! bless your 👉🏼 heart 😍💔
+Hello, my name is Immigration officer Mimi Sashimi from the American-Felinid Homeworld consulate. It appears your current documents are either inaccurate if not entirely fraudulent. This action in it's current state is a federal offense as listed in the United Earth Commission charter section NY-4. Please pay a fine of 300,000 Space credits or $3000 United States Dollars or face deportation
+Hi %name%, We are unable to validate your billing information for the next billing cycle of your subscription to HONK Weekly therefore we'll suspend your membership if we do not receive a response from you within 48 hours. Obviously we'd love to have you back, simply mail %address% to update your details and continue to enjoy all the best pranks & gags without interruption.
+Loyal customer, DonkCo Customer Service. We appreciate your brand loyalty support. As such, it is our responsibility and pleasure to inform you of the status of your package. Your package for one "Moth-Fuzz Parka" has been delayed. Due to local political tensions, an animal rights group has seized and eaten your package. We appreciate the patience, DonkCo
+MESSAGE FROM CENTCOM HIGH COMMAND: DO NOT ACCEPT THE FRIEND REQUEST OF TICKLEBALLS THE CLOWN. HE IS NOT FUNNY AND ON TOP OF THAT HE WILL HACK YOUR NTNET ACCOUNT AND MAKE YOU UNFUNNY TOO. YOU WILL LOSE ALL YOUR SPACECREDITS!!!!! SPREAD THE WORD. ANYONE WHO BECOMES FRIENDS WITH TINKLEBALLS THE CLOWN IS GOING TO LOSE ALL OF THEIR SPACECREDITS AND LOOK LIKE A HUGE IDIOT.
+i WAS A NORMAL BOY AND I CAME HOME FROM SCHOOL AND I WANTED TO PLAY SOME ORION TRAIL WHICH IS A VERY FUN GAME BUT WHEN WENT TO ARCADE MACHINE SOMETHING WAS WEIRD TEH LOGO HASD BLOD IN IT AND I BECAME VERY SCARE AND I CHECK OPTIONS AND TEHRES ONLY 1 "GO BACK" I CKLICK IT AND I SEE CHAT SI EMPTY THERE'S ONLY ONE CHARACTER CALLED "CLOSE TEH GAME " AND I GO TO ANOTHER MACHINE AND PLAY THERE BUT WHEN I PLAY GAME IS FULL OF BLOOD AND DEAD BODIES FROM SPACEMAN LOOK CLOSER AND SEE CLOWN AND CLOWN COMES CLOSER AND LOOKS AT ME AND SAYS "DON'T SAY I DIKDNT' WWARN YOU" AND CLOWN CLOSEUP APPEARS WITH BLOOD-RED HYPERREALISTIC EYES AND HE TELLS ME "YOU WILL BE THE NEXT ONE" AND ARCADE MACHINE POWER SHUT OFF AND THAT NITE CLOWN APPEAR AT MY WINDOW AND KILL ME AT 3 AM AND NOW IM DEAD AND YOU WILL BE TRHNE NEXT OEN UNLESS YOU PASTE THIS STORY TO 10 NTNET FRIENDS
diff --git a/tgstation.dme b/tgstation.dme
index 17c15a5f52c..05f8db6a83b 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1185,6 +1185,7 @@
#include "code\game\objects\items\inducer.dm"
#include "code\game\objects\items\kitchen.dm"
#include "code\game\objects\items\latexballoon.dm"
+#include "code\game\objects\items\mail.dm"
#include "code\game\objects\items\manuals.dm"
#include "code\game\objects\items\miscellaneous.dm"
#include "code\game\objects\items\mop.dm"