From ecfaa26cc2a24323fef001c454e8f8d43e7ba424 Mon Sep 17 00:00:00 2001
From: Marm <85680653+ItsMarmite@users.noreply.github.com>
Date: Wed, 20 Sep 2023 00:30:03 +0100
Subject: [PATCH] You've Got Mail! Adds Mail system (#22269)
* heres the mail it never fails
Adds envelopes and its functions.
* It makes me want to wag my tail
Adds new envelope sprites courtesy of McRamon, makes mail bags and envelopess able to be carried by cargo clothing.
* when it comes i want to whail
Makes Wizard and Nukie equip change to off station role. Adds mail crates and functionality/logging for randomly choosing recipients of mail.
* MAAAAAAAAAAAAAAIIIL!!!!
Adds functionality for the mail scanner alongside sounds. Begins the process of making mail arrive on the shuttle.
* MAIL
* THE MAILMAN IS HERE
* MAIL IS REAL
* Give me an M, give me an A, give me an I, give me an L. What does that spell? MAIL.
Finalises pre-review mail features, adding the mail scanner to cargo tech loadout/autolathe.
* Update code/game/gamemodes/nuclear/nuclear.dm
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
* Update code/modules/shuttle/supply.dm
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
* Update code/game/jobs/job/support.dm
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
* Update code/game/objects/items/weapons/storage/bags.dm
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
* Update code/game/objects/items/weapons/storage/bags.dm
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
* Update code/game/objects/structures/crates_lockers/crates.dm
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
* Update code/controllers/subsystem/SSeconomy.dm
Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com>
* check out what you got now
Removes unused sprite bloat.
* Update code/game/objects/mail.dm
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
* Update code/game/objects/mail.dm
* Update code/game/objects/mail.dm
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
* Update code/game/objects/mail.dm
Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com>
* Update code/game/objects/mail.dm
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
* Update code/game/objects/mail.dm
Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com>
* First few Contra reviews
* Second batch
* Cl doesn't fail anymore
* Even more fucking reviews
* Doesn't quite work yet but we're almost there
* WHEN DOES IT EEEEEND
* I have no energy to make a blues clues reference
More commits to respond to reviews
* God I miss Steve
Adds hand sprites to mail scanners
* Woooo Mail works again
* Science envelopes
* Update code/game/objects/mail.dm
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
* my god it worked
II hate it
* Bread and Circuses
splits up service envelopes into two categories, addresses other reviews.
* Lewc review - needs testing
* Almost there
Changing lists and more.
* Last fix
* IT IS ALL WORKING NOW
* Mail. Is. Done.
Final pass.
* Update code/controllers/subsystem/SSeconomy.dm
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
* Update code/game/objects/mail.dm
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
* The fix
* Just this one too
* Lewc review
* mail?
yeah
* Begone, ye powersink
* Sirryan review
* Update code/__DEFINES/economy_defines.dm
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
* Update code/game/objects/mail.dm
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
* Update code/game/objects/mail.dm
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
* Update code/controllers/subsystem/SSeconomy.dm
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
* Update code/game/objects/mail.dm
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
* Update code/game/objects/mail.dm
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
* Wjpp[s
* Removes useless comment
* We ball
---------
Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com>
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
---
code/__DEFINES/economy_defines.dm | 5 +-
code/__DEFINES/misc_defines.dm | 6 +
code/controllers/subsystem/SSeconomy.dm | 8 +
code/controllers/subsystem/SSshuttles.dm | 21 ++
code/datums/outfits/outfit_debug.dm | 1 -
code/game/gamemodes/nuclear/nuclear.dm | 1 +
code/game/gamemodes/wizard/wizard.dm | 1 +
code/game/jobs/job/support.dm | 2 +
code/game/machinery/requests_console.dm | 11 -
.../objects/items/stacks/sheets/mineral.dm | 6 +
.../objects/items/weapons/storage/bags.dm | 16 ++
code/game/objects/mail.dm | 272 ++++++++++++++++++
.../structures/crates_lockers/crates.dm | 25 ++
code/modules/clothing/suits/misc_suits.dm | 4 +-
code/modules/mining/machine_redemption.dm | 2 +-
.../research/designs/autolathe_designs.dm | 8 +
code/modules/shuttle/supply.dm | 8 +-
code/modules/supply/supply_console.dm | 2 +-
icons/mob/inhands/items/devices_lefthand.dmi | Bin 2715 -> 2972 bytes
icons/mob/inhands/items/devices_righthand.dmi | Bin 2806 -> 2960 bytes
icons/obj/bureaucracy.dmi | Bin 24822 -> 27230 bytes
icons/obj/device.dmi | Bin 51365 -> 55036 bytes
paradise.dme | 1 +
sound/mail/mailapproved.ogg | Bin 0 -> 6747 bytes
sound/mail/maildenied.ogg | Bin 0 -> 6845 bytes
sound/mail/mailscanned.ogg | Bin 0 -> 5303 bytes
26 files changed, 380 insertions(+), 20 deletions(-)
create mode 100644 code/game/objects/mail.dm
create mode 100644 sound/mail/mailapproved.ogg
create mode 100644 sound/mail/maildenied.ogg
create mode 100644 sound/mail/mailscanned.ogg
diff --git a/code/__DEFINES/economy_defines.dm b/code/__DEFINES/economy_defines.dm
index bb08ac5c54e..dc4a53f50de 100644
--- a/code/__DEFINES/economy_defines.dm
+++ b/code/__DEFINES/economy_defines.dm
@@ -22,7 +22,7 @@
#define DEPARTMENT_BALANCE_HIGH 1500
/////BASE PAY AMOUNTS///
-#define CREW_BASE_PAY_LOW 125
+#define CREW_BASE_PAY_LOW 100
#define CREW_PAY_MEDIUM 250
#define CREW_PAY_HIGH 300
@@ -62,3 +62,6 @@
#define SUPPLY_VEND 9
#define DEFAULT_CRATE_VALUE 15
+
+/// mail deliveries
+#define MAIL_DELIVERY_BONUS 100
diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm
index 81850bfc16a..544e499beea 100644
--- a/code/__DEFINES/misc_defines.dm
+++ b/code/__DEFINES/misc_defines.dm
@@ -552,3 +552,9 @@
#define BLOCKED_BURROWS "Blocked Burrows"
#define CLASSIC_CAVES "Classic Caves"
#define DEADLY_DEEPROCK "Deadly Deeprock"
+
+// Request console message priority defines
+
+#define RQ_NONEW_MESSAGES 0 // RQ_NONEWMESSAGES = no new message
+#define RQ_NORMALPRIORITY 1 // RQ_NORMALPRIORITY = normal priority
+#define RQ_HIGHPRIORITY 2 // RQ_HIGHPRIORITY = high priority
diff --git a/code/controllers/subsystem/SSeconomy.dm b/code/controllers/subsystem/SSeconomy.dm
index ab3f1dd6e67..8f316ecc674 100644
--- a/code/controllers/subsystem/SSeconomy.dm
+++ b/code/controllers/subsystem/SSeconomy.dm
@@ -92,6 +92,8 @@ SUBSYSTEM_DEF(economy)
var/next_paycheck_delay = 0
/// total paydays this round
var/payday_count = 0
+ /// Time until the next mail shipment
+ var/next_mail_delay = 0
var/global_paycheck_bonus = 0
var/global_paycheck_deduction = 0
@@ -132,6 +134,7 @@ SUBSYSTEM_DEF(economy)
centcom_message = "
---[station_time_timestamp()]---
Remember to stamp and send back the supply manifests.
"
next_paycheck_delay = 30 MINUTES + world.time
+ next_mail_delay = 15 MINUTES + world.time
/datum/controller/subsystem/economy/fire()
if(next_paycheck_delay <= world.time)
@@ -141,6 +144,11 @@ SUBSYSTEM_DEF(economy)
next_data_check = 10 MINUTES + world.time
record_economy_data()
process_job_tasks()
+ if(next_mail_delay <= world.time)
+ if(!is_admin_level(SSshuttle.supply.z) || SSshuttle.supply.areaInstance.moving)
+ return
+ next_mail_delay = 15 MINUTES + world.time
+ SSshuttle.mail_delivery()
/datum/controller/subsystem/economy/proc/record_economy_data()
economy_data["totalcash"] += total_space_cash
diff --git a/code/controllers/subsystem/SSshuttles.dm b/code/controllers/subsystem/SSshuttles.dm
index 35de41472a8..a229a3ab80c 100644
--- a/code/controllers/subsystem/SSshuttles.dm
+++ b/code/controllers/subsystem/SSshuttles.dm
@@ -24,6 +24,8 @@ SUBSYSTEM_DEF(shuttle)
//supply shuttle stuff
var/obj/docking_port/mobile/supply/supply
+ /// Supply shuttle turfs to make mail be put down faster
+ var/static/list/supply_shuttle_turfs = list()
var/list/hidden_shuttle_turfs = list() //all turfs hidden from navigation computers associated with a list containing the image hiding them and the type of the turf they are pretending to be
var/list/hidden_shuttle_turf_images = list() //only the images from the above list
@@ -284,4 +286,23 @@ SUBSYSTEM_DEF(shuttle)
QDEL_LIST_CONTENTS(remove_images)
+/datum/controller/subsystem/shuttle/proc/mail_delivery()
+ for(var/obj/machinery/requests_console/console in GLOB.allRequestConsoles)
+ if(console.department != "Cargo Bay")
+ continue
+ console.createMessage("Messaging and Intergalactic Letters", "New Mail Crates ready to be ordered!", "A new mail crate is able to be shipped alongside your next orders!", RQ_NORMALPRIORITY)
+
+ if(!length(supply_shuttle_turfs))
+ for(var/turf/simulated/T in supply.areaInstance)
+ if(T.density)
+ continue
+ for(var/obj/structure/structure in T.contents)
+ if(structure.density)
+ continue
+ supply_shuttle_turfs += T
+ if(!length(supply_shuttle_turfs)) // In case some nutjob walled the supply shuttle 10 minutes into the round
+ return
+ var/turf/spawn_location = pick(supply_shuttle_turfs)
+ new /obj/structure/closet/crate/mail(spawn_location)
+
#undef CALL_SHUTTLE_REASON_LENGTH
diff --git a/code/datums/outfits/outfit_debug.dm b/code/datums/outfits/outfit_debug.dm
index a646f082bb6..dd7c0e4cd87 100644
--- a/code/datums/outfits/outfit_debug.dm
+++ b/code/datums/outfits/outfit_debug.dm
@@ -16,7 +16,6 @@
mask = /obj/item/clothing/mask/gas/welding/advanced
shoes = /obj/item/clothing/shoes/combat/swat
- // shit down here is mine
box = /obj/item/storage/box/debug/debugtools
suit_store = /obj/item/tank/internals/oxygen
gloves = /obj/item/clothing/gloves/combat
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 1f380ef73d4..914ae3b18f7 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -292,6 +292,7 @@
U.hidden_uplink.uplink_owner="[synd_mob.key]"
U.hidden_uplink.uses = uplink_uses
synd_mob.equip_to_slot_or_del(U, slot_in_backpack)
+ synd_mob.mind.offstation_role = TRUE
if(synd_mob.dna.species)
var/race = synd_mob.dna.species.name
diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm
index 4783089c03b..015f595f634 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -147,6 +147,7 @@
wizard_mob.equip_to_slot_or_del(spellbook, slot_l_hand)
wizard_mob.faction = list("wizard")
+ wizard_mob.mind.offstation_role = TRUE
diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm
index eaef20e4fa9..d77defb864c 100644
--- a/code/game/jobs/job/support.dm
+++ b/code/game/jobs/job/support.dm
@@ -47,6 +47,7 @@
selection_color = "#eeddbe"
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINT, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
+ alt_titles = list("Mail Carrier", "Courier")
outfit = /datum/outfit/job/cargo_tech
/datum/outfit/job/cargo_tech
@@ -55,6 +56,7 @@
uniform = /obj/item/clothing/under/rank/cargo/tech
shoes = /obj/item/clothing/shoes/black
+ l_pocket = /obj/item/mail_scanner
l_ear = /obj/item/radio/headset/headset_cargo
id = /obj/item/card/id/supply
pda = /obj/item/pda/cargo
diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm
index db575db584a..b6a634ce373 100644
--- a/code/game/machinery/requests_console.dm
+++ b/code/game/machinery/requests_console.dm
@@ -27,10 +27,6 @@
#define COM_ROLES list("Blueshield", "NT Representative", "Head of Personnel's Desk", "Captain's Desk", "Bridge")
#define SCI_ROLES list("Robotics", "Science", "Research Director's Desk")
-#define RQ_NONEW_MESSAGES 0
-#define RQ_NORMALPRIORITY 1
-#define RQ_HIGHPRIORITY 2
-
GLOBAL_LIST_EMPTY(req_console_assistance)
GLOBAL_LIST_EMPTY(req_console_supplies)
GLOBAL_LIST_EMPTY(req_console_information)
@@ -48,9 +44,6 @@ GLOBAL_LIST_EMPTY(allRequestConsoles)
var/list/message_log = list() //List of all messages
var/departmentType = 0 //Bitflag. Zero is reply-only. Map currently uses raw numbers instead of defines.
var/newmessagepriority = RQ_NONEW_MESSAGES
- // RQ_NONEWMESSAGES = no new message
- // RQ_NORMALPRIORITY = normal priority
- // RQ_HIGHPRIORITY = high priority
var/screen = RCS_MAINMENU
var/silent = FALSE // set to TRUE for it not to beep all the time
var/announcementConsole = FALSE
@@ -371,7 +364,3 @@ GLOBAL_LIST_EMPTY(allRequestConsoles)
sp.sortTag = tag_index
sp.update_desc()
print_cooldown = world.time + 600 //1 minute cooldown before you can print another label, but you can still configure the next one during this time
-
-#undef RQ_NONEW_MESSAGES
-#undef RQ_NORMALPRIORITY
-#undef RQ_HIGHPRIORITY
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 85359257e12..ee5c879d8f6 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -329,6 +329,9 @@ GLOBAL_LIST_INIT(sandbag_recipes, list (
materials = list(MAT_BANANIUM = MINERAL_MATERIAL_AMOUNT)
point_value = 50
+/obj/item/stack/sheet/mineral/bananium/ten
+ amount = 10
+
/obj/item/stack/sheet/mineral/bananium/fifty
amount = 50
@@ -348,6 +351,9 @@ GLOBAL_LIST_INIT(sandbag_recipes, list (
wall_allowed = FALSE //no tranquilite walls in code
point_value = 50
+/obj/item/stack/sheet/mineral/tranquillite/ten
+ amount = 10
+
/obj/item/stack/sheet/mineral/tranquillite/fifty
amount = 50
diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm
index 5ace765ad39..a5a19c88d45 100644
--- a/code/game/objects/items/weapons/storage/bags.dm
+++ b/code/game/objects/items/weapons/storage/bags.dm
@@ -536,3 +536,19 @@
/obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/iv_bag,
/obj/item/reagent_containers/hypospray/autoinjector/epinephrine)
resistance_flags = FLAMMABLE
+
+/*
+ * Mail bag
+ */
+
+/obj/item/storage/bag/mail
+ name = "mail bag"
+ desc = "A bag for envelopes, stamps, pens, and papers."
+ icon = 'icons/obj/bureaucracy.dmi'
+ icon_state = "mailbag"
+ item_state = "mailbag"
+ storage_slots = 14
+ max_combined_w_class = 28
+ w_class = WEIGHT_CLASS_TINY
+ can_hold = list(/obj/item/envelope, /obj/item/stamp, /obj/item/pen, /obj/item/paper)
+ resistance_flags = FLAMMABLE
diff --git a/code/game/objects/mail.dm b/code/game/objects/mail.dm
new file mode 100644
index 00000000000..6e6a2af8590
--- /dev/null
+++ b/code/game/objects/mail.dm
@@ -0,0 +1,272 @@
+/obj/item/envelope
+ name = "broken letter"
+ desc = "We just got a letter, we just got a letter, we just got a letter -- I wonder who it's from?"
+ force = 0
+ throwforce = 0
+ w_class = WEIGHT_CLASS_SMALL
+ icon = 'icons/obj/bureaucracy.dmi'
+ icon_state = "mail_misc"
+ item_state = "paper"
+ drop_sound = 'sound/items/handling/paper_drop.ogg'
+ pickup_sound = 'sound/items/handling/paper_pickup.ogg'
+
+ var/list/possible_contents = list()
+ /// A list that contains the names of the jobs that can receive this type of letter. Only the base job has to be put in it, alternative titles have the same definition on the mind. Name of the job can be found in `mind.assigned_role`
+ var/list/job_list = list()
+ var/mob/living/recipient
+ var/has_been_scanned = FALSE
+
+/obj/item/envelope/suicide_act(mob/user)
+ user.visible_message("[user] is licking a sharp corner of the envelope. It looks like [user.p_theyre()] trying to commit suicide!")
+ playsound(loc, 'sound/effects/-adminhelp.ogg', 50, TRUE, -1)
+ return BRUTELOSS
+
+/obj/item/envelope/attack_self(mob/user)
+ if(!user?.mind)
+ return
+ if(user.real_name != recipient.real_name)
+ to_chat(user, "You don't want to open up another person's mail, that's an invasion of their privacy!")
+ return
+ if(do_after(user, 1 SECONDS, target = user) && !QDELETED(src))
+ to_chat(user, "You begin to open the envelope.")
+ playsound(loc, 'sound/items/poster_ripped.ogg', 50, TRUE)
+ user.unEquip(src)
+ for(var/obj/item/I in contents)
+ user.put_in_hands(I)
+ qdel(src)
+
+/obj/item/envelope/Initialize(mapload)
+ . = ..()
+ var/item = pick(possible_contents)
+ new item(src)
+ new /obj/item/stack/spacecash(src, rand(1, 50) * 5)
+ var/list/mind_copy = shuffle(SSticker.minds)
+ for(var/datum/mind/mail_attracted_people in mind_copy)
+ var/turf/T = get_turf(mail_attracted_people.current)
+ if(mail_attracted_people.offstation_role || !ishuman(mail_attracted_people.current) || is_admin_level(T.z))
+ continue
+ if(mail_attracted_people.assigned_role in job_list)
+ recipient = mail_attracted_people.current
+ name = "letter to [recipient.real_name]"
+ return
+ if(!admin_spawned)
+ log_debug("Failed to find a new name to assign to [src]!")
+ qdel(src)
+
+/obj/item/envelope/security
+ icon_state = "mail_sec"
+ possible_contents = list(/obj/item/reagent_containers/food/snacks/donut/sprinkles,
+ /obj/item/megaphone,
+ /obj/item/poster/random_official,
+ /obj/item/restraints/handcuffs/pinkcuffs,
+ /obj/item/restraints/legcuffs/bola/energy,
+ /obj/item/reagent_containers/food/drinks/coffee,
+ /obj/item/stock_parts/cell/super,
+ /obj/item/grenade/barrier/dropwall,
+ /obj/item/toy/figure/crew/detective,
+ /obj/item/toy/figure/crew/hos,
+ /obj/item/toy/figure/crew/secofficer)
+ job_list = list("Head of Security", "Security Officer", "Detective", "Warden")
+
+/obj/item/envelope/science
+ icon_state = "mail_sci"
+ possible_contents = list(/obj/item/analyzer,
+ /obj/item/assembly/signaler,
+ /obj/item/slime_extract/grey,
+ /obj/item/clothing/mask/gas,
+ /obj/item/reagent_containers/spray/cleaner,
+ /obj/item/clothing/glasses/regular,
+ /obj/item/stack/ore/diamond, // Jackpot
+ /obj/item/paicard,
+ /obj/item/toy/figure/crew/borg,
+ /obj/item/toy/figure/crew/geneticist,
+ /obj/item/toy/figure/crew/rd,
+ /obj/item/toy/figure/crew/roboticist,
+ /obj/item/toy/figure/crew/scientist)
+ job_list = list("Research Director", "Roboticist", "Geneticist", "Scientist")
+
+/obj/item/envelope/supply
+ icon_state = "mail_sup"
+ possible_contents = list(/obj/item/reagent_containers/hypospray/autoinjector/survival,
+ /obj/item/reagent_containers/food/drinks/bottle/absinthe/premium,
+ /obj/item/clothing/glasses/meson/gar,
+ /obj/item/stack/marker_beacon/ten,
+ /obj/item/stack/medical/splint,
+ /obj/item/pen/multi/fountain,
+ /obj/item/clothing/mask/cigarette/cigar,
+ /obj/item/stack/wrapping_paper,
+ /obj/item/toy/figure/crew/cargotech,
+ /obj/item/toy/figure/crew/qm,
+ /obj/item/toy/figure/crew/miner)
+ job_list = list("Quartermaster", "Cargo Technician", "Shaft Miner")
+
+/obj/item/envelope/medical
+ icon_state = "mail_med"
+ possible_contents = list(/obj/item/soap,
+ /obj/item/reagent_containers/glass/bottle/morphine,
+ /obj/item/reagent_containers/hypospray/safety,
+ /obj/item/reagent_containers/applicator/brute,
+ /obj/item/reagent_containers/applicator/burn,
+ /obj/item/clothing/glasses/sunglasses,
+ /obj/item/reagent_containers/food/snacks/fortunecookie,
+ /obj/item/scalpel/laser/laser1,
+ /obj/item/toy/figure/crew/cmo,
+ /obj/item/toy/figure/crew/chemist,
+ /obj/item/toy/figure/crew/geneticist,
+ /obj/item/toy/figure/crew/md,
+ /obj/item/toy/figure/crew/virologist)
+ job_list = list("Chief Medical Officer", "Medical Doctor", "Coroner", "Chemist", "Virologist", "Psychiatrist", "Paramedic")
+
+/obj/item/envelope/engineering
+ icon_state = "mail_eng"
+ possible_contents = list(/obj/item/airlock_electronics,
+ /obj/item/reagent_containers/food/drinks/cans/beer,
+ /obj/item/reagent_containers/food/snacks/candy/confectionery/nougat,
+ /obj/item/mod/module/storage/large_capacity,
+ /obj/item/weldingtool/hugetank,
+ /obj/item/geiger_counter,
+ /obj/item/rcd_ammo,
+ /obj/item/grenade/gas/oxygen,
+ /obj/item/toy/figure/crew/atmos,
+ /obj/item/toy/figure/crew/ce,
+ /obj/item/toy/figure/crew/engineer)
+ job_list = list("Chief Engineer", "Station Engineer", "Life Support Specialist")
+
+/obj/item/envelope/bread
+ icon_state = "mail_serv"
+ possible_contents = list(/obj/item/painter,
+ /obj/item/gun/energy/floragun,
+ /obj/item/reagent_containers/food/drinks/bottle/fernet,
+ /obj/item/whetstone,
+ /obj/item/soap/deluxe,
+ /obj/item/stack/tile/disco_light/thirty,
+ /obj/item/paicard,
+ /obj/item/gun/projectile/automatic/toy/pistol,
+ /obj/item/toy/figure/crew/bartender,
+ /obj/item/toy/figure/crew/botanist,
+ /obj/item/toy/figure/crew/chef,
+ /obj/item/toy/figure/crew/janitor,
+ /obj/item/toy/figure/crew/librarian)
+ job_list = list("Bartender", "Chef", "Botanist", "Janitor", "Barber", "Librarian", "Barber")
+
+/obj/item/envelope/circuses
+ icon_state = "mail_serv"
+ possible_contents = list(/obj/item/painter,
+ /obj/item/stack/sheet/mineral/tranquillite/ten,
+ /obj/item/stack/sheet/mineral/bananium/ten,
+ /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing,
+ /obj/item/gun/throw/piecannon,
+ /obj/item/ammo_box/shotgun/confetti,
+ /obj/item/book/manual/wiki/sop_security, // They'll need this.
+ /obj/item/soulstone/anybody/purified/chaplain,
+ /obj/item/toy/figure/crew/clown,
+ /obj/item/toy/figure/crew/hop,
+ /obj/item/toy/figure/crew/chaplain,
+ /obj/item/toy/figure/crew/mime)
+ job_list = list("Clown", "Mime", "Head of Personnel", "Chaplain")
+
+
+/obj/item/envelope/command
+ icon_state = "mail_com"
+ possible_contents = list(/obj/item/flash,
+ /obj/item/storage/fancy/cigarettes/cigpack_robustgold,
+ /obj/item/poster/random_official,
+ /obj/item/book/manual/wiki/sop_command,
+ /obj/item/reagent_containers/food/pill/patch/synthflesh,
+ /obj/item/paper_bin/nanotrasen,
+ /obj/item/reagent_containers/food/snacks/spesslaw,
+ /obj/item/clothing/head/collectable/petehat,
+ /obj/item/toy/figure/crew/captain,
+ /obj/item/toy/figure/crew/lawyer,
+ /obj/item/toy/figure/crew/dsquad)
+ job_list = list("Captain", "Magistrate", "Nanotrasen Representative", "Blueshield", "Internal Affairs Agent")
+
+/obj/item/envelope/misc
+ possible_contents = list(/obj/item/clothing/under/misc/assistantformal,
+ /obj/item/clothing/under/syndicate/tacticool,
+ /obj/item/clothing/shoes/ducky,
+ /obj/item/toy/plushie/orange_fox/grump, // A grumpy plushie for a grumpy tider
+ /obj/item/multitool,
+ /obj/item/instrument/piano_synth,
+ /obj/item/toy/crayon/spraycan,
+ /obj/item/clothing/head/cakehat,
+ /obj/item/toy/figure/crew/assistant,
+ /obj/item/toy/figure/owl,
+ /obj/item/toy/figure/griffin)
+ job_list = list("Assistant", "Explorer")
+
+
+ /*//////////////////////\/
+ \/ \\ // \/
+ \/ \\ // \/
+ \/ \\ // \/
+ \/ \\ // \/
+ \/ \\// \/
+ \/ \/
+ \/ You've got: \/
+ \/ Mail \/
+ \/ \/
+ \/\\\\\\\\\\\\\\\\\\\\\\*/
+
+/obj/item/mail_scanner
+ name = "mail scanner"
+ desc = "Sponsored by Messaging and Intergalactic Letters, this device allows you to log mail deliveries in exchange for financial compensation."
+ force = 0
+ throwforce = 0
+ icon = 'icons/obj/device.dmi'
+ icon_state = "mail_scanner"
+ item_state = "mail_scanner"
+ lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
+ flags = CONDUCT
+ slot_flags = SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ origin_tech = "magnets=1"
+ /// The reference to the envelope that is currently stored in the mail scanner. It will be cleared upon confirming a correct delivery
+ var/obj/item/envelope/saved
+
+/obj/item/mail_scanner/examine(mob/user)
+ . = ..()
+ . += "Scan a letter to log it into the active database, then scan the person you wish to hand the letter to. Correctly scanning the recipient of the letter logged into the active database will add credits to the Supply budget."
+
+/obj/item/mail_scanner/attack()
+ return
+
+/obj/item/mail_scanner/afterattack(atom/A, mob/user)
+ if(istype(A, /obj/item/envelope))
+ var/obj/item/envelope/envelope = A
+ if(envelope.has_been_scanned)
+ to_chat(user, "This letter has already been logged to the active database!")
+ playsound(loc, 'sound/mail/maildenied.ogg', 50, TRUE)
+ return
+ to_chat(user, "You add [envelope] to the active database.")
+ playsound(loc, 'sound/mail/mailscanned.ogg', 50, TRUE)
+ saved = A
+ return
+ if(isliving(A))
+ var/mob/living/M = A
+ if(!saved)
+ to_chat(user, "Error: You have not logged mail to the mail scanner!")
+ playsound(loc, 'sound/mail/maildenied.ogg', 50, TRUE)
+ return
+
+ if(M.stat == DEAD)
+ to_chat(user, "Consent Verification failed: You can't deliver mail to a corpse!")
+ playsound(loc, 'sound/mail/maildenied.ogg', 50, TRUE)
+ return
+
+ if(M.real_name != saved.recipient.real_name)
+ to_chat(user, "'Identity Verification failed: Target is not an authorized recipient of this package!")
+ playsound(loc, 'sound/mail/maildenied.ogg', 50, TRUE)
+ return
+
+ if(!M.client)
+ to_chat(user, "Consent Verification failed: The scanner will not accept confirmation of orders from SSD people!")
+ playsound(loc, 'sound/mail/maildenied.ogg', 50, TRUE)
+ return
+
+ saved.has_been_scanned = TRUE
+ saved = null
+ to_chat(user, "Successful delivery acknowledged! [MAIL_DELIVERY_BONUS] credits added to Supply account!")
+ playsound(loc, 'sound/mail/mailapproved.ogg', 50, TRUE)
+ GLOB.station_money_database.credit_account(SSeconomy.cargo_account, MAIL_DELIVERY_BONUS, "Mail Delivery Compensation", "Messaging and Intergalactic Letters", supress_log = FALSE)
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 035de168476..6b6f51f1e17 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -504,6 +504,31 @@
icon_opened = "electricalcrate_open"
icon_closed = "electricalcrate"
+/obj/structure/closet/crate/mail
+ name = "mail crate"
+ desc = "A plastic crate for mail delivery."
+ icon = 'icons/obj/bureaucracy.dmi'
+ icon_state = "mailsealed"
+ icon_opened = "mailopen"
+ icon_closed = "mailsealed"
+ material_drop = /obj/item/stack/sheet/plastic
+ material_drop_amount = 4
+ var/list/possible_contents = list(/obj/item/envelope/security,
+ /obj/item/envelope/science,
+ /obj/item/envelope/supply,
+ /obj/item/envelope/medical,
+ /obj/item/envelope/engineering,
+ /obj/item/envelope/bread,
+ /obj/item/envelope/circuses,
+ /obj/item/envelope/command,
+ /obj/item/envelope/misc)
+
+/obj/structure/closet/crate/mail/populate_contents()
+ . = ..()
+ for(var/i in 1 to rand(5, 10))
+ var/item = pick(possible_contents)
+ new item(src)
+
/obj/structure/closet/crate/tape/populate_contents()
if(prob(10))
new /obj/item/bikehorn/rubberducky(src)
diff --git a/code/modules/clothing/suits/misc_suits.dm b/code/modules/clothing/suits/misc_suits.dm
index cbc5490d86c..a97ad4d73c8 100644
--- a/code/modules/clothing/suits/misc_suits.dm
+++ b/code/modules/clothing/suits/misc_suits.dm
@@ -501,7 +501,7 @@
name = "cargo winter coat"
icon_state = "wintercoat_cargo"
item_state = "coatcargo"
- allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/rcs, /obj/item/clipboard)
+ allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/rcs, /obj/item/clipboard, /obj/item/envelope, /obj/item/storage/bag/mail)
hoodtype = /obj/item/clothing/head/hooded/winterhood/cargo
/obj/item/clothing/head/hooded/winterhood/cargo
@@ -891,7 +891,7 @@
icon_state = "bombercargo"
item_state = "bombercargo"
ignore_suitadjust = 0
- allowed = list(/obj/item/rcs, /obj/item/clipboard, /obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/toy, /obj/item/lighter, /obj/item/storage/fancy/cigarettes)
+ allowed = list(/obj/item/rcs, /obj/item/clipboard, /obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/toy, /obj/item/lighter, /obj/item/storage/fancy/cigarettes, /obj/item/storage/bag/mail, /obj/item/envelope)
body_parts_covered = UPPER_TORSO | LOWER_TORSO | ARMS
cold_protection = UPPER_TORSO | LOWER_TORSO | ARMS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index df41f7948b0..41d77a681bb 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -468,7 +468,7 @@
if(!(C.department in supply_consoles))
continue
if(!supply_consoles[C.department] || length(supply_consoles[C.department] - mats_in_stock))
- C.createMessage("Ore Redemption Machine", "New Minerals Available!", msg, 1) // RQ_NORMALPRIORITY
+ C.createMessage("Ore Redemption Machine", "New Minerals Available!", msg, RQ_NORMALPRIORITY)
/**
* Tries to insert the ID card held by the given user into the machine.
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index 49ccab63937..eedcc0c05cd 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -933,3 +933,11 @@
materials = list(MAT_METAL = 4000)
build_path = /obj/item/desk_bell
category = list("initial", "Miscellaneous")
+
+/datum/design/mailscanner
+ name = "Mail Scanner"
+ id = "mailscanner"
+ build_type = AUTOLATHE
+ materials = list(MAT_METAL = 1500, MAT_GLASS = 500)
+ build_path = /obj/item/mail_scanner
+ category = list("initial", "Miscellaneous")
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index f2dcf4d109b..9e2f6c23a8f 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -34,8 +34,8 @@
/obj/effect/hierophant,
/obj/item/warp_cube,
/obj/machinery/quantumpad,
- /obj/structure/extraction_point
- )
+ /obj/structure/extraction_point,
+ /obj/item/envelope)
if(A)
if(is_type_in_list(A, blacklist))
return TRUE
@@ -126,10 +126,12 @@
continue
if(istype(MA, /mob/dead))
continue
+ if(istype(MA, /obj/structure/closet/crate/mail))
+ continue
SSeconomy.sold_atoms += " [MA.name]"
// Must be in a crate (or a critter crate)!
- if(istype(MA,/obj/structure/closet/crate) || istype(MA,/obj/structure/closet/critter))
+ if(istype(MA, /obj/structure/closet/crate) || istype(MA, /obj/structure/closet/critter))
SSeconomy.sold_atoms += ":"
if(!length(MA.contents))
SSeconomy.sold_atoms += " (empty)"
diff --git a/code/modules/supply/supply_console.dm b/code/modules/supply/supply_console.dm
index 8d323258b5b..863be663631 100644
--- a/code/modules/supply/supply_console.dm
+++ b/code/modules/supply/supply_console.dm
@@ -410,7 +410,7 @@
if(is_public) // Public consoles cant move the shuttle. Dont allow exploiters.
return
if(SSshuttle.supply.canMove())
- to_chat(user, "For safety reasons the automated supply shuttle cannot transport live organisms, classified nuclear weaponry or homing beacons.")
+ to_chat(user, "For safety reasons the automated supply shuttle cannot transport live organisms, undelivered mail, classified nuclear weaponry or homing beacons.")
else if(SSshuttle.supply.getDockedId() == "supply_home")
SSshuttle.toggleShuttle("supply", "supply_home", "supply_away", 1)
investigate_log("| [key_name(user)] has sent the supply shuttle away. Shuttle contents: [SSeconomy.sold_atoms]", "cargo")
diff --git a/icons/mob/inhands/items/devices_lefthand.dmi b/icons/mob/inhands/items/devices_lefthand.dmi
index bf9c3154c62b18562e9f681f31fc845b543c3938..73f963c0eaa4a0a3c069fc51a0f376e43b2eabf3 100644
GIT binary patch
delta 2933
zcmXw33p~@^8(%j?F7KO5Y=v^EA_;LLV*#|!NJtj6p2LotzpDxXQRWzK|+x32`yt|Zs29F!ptzu*pg7!VBFgkuz?fx$BwJnO@PJ6)=eE`=m_iMrJa`WG5+n{`fh
zXU^b03lmQ07;@)sW1VUW`R0q0zC7e99i@wbhona<@t5AdwlFUH?GmV~GRBe7+p*^d%~9T^W29d-xqn9=T3REX^UVkI7=@}7A1O0jZ
zooNfhk@~Ccaihx3urBWP0z}N7sY!LbVF`AcEa%8Hj!^dBS3m7uN6sblBwn2s&xm*)
zc@_i`Rkt=jjlu&N-^QY_j3L>^KtGij0_-3t|sp{5agqoB8
zp>HOO2|+KFY0Q1*VrwlbVAYVWLPo_cmY74n)xvY2-yVi+JaW9+V1{%Wna6x0OLo)@
zJ>ErhfgxL%2tXr#)8I_+}yz5C-&4(XsQ#Jkwc0p{_r-FghAq?Go=e}14$04t7
z<|>xbgxc^({B9#=ua*rlgZW^-MM3me!lQRju~m}+yz`oa0eQGmjtB`GWWjAjkP&;co2yew!Za+L_PvHM~e`OjcRxduk+Z~vKJ
zu}v9t2G3t)4P6a<4L2u0j+>O6*70qg6QN=sJ~O{a|Ci1dnLD}Agqjn3AP>U8jz)Pr
zdxxWG7s50yR#FcB@(Kpa^<7Tr53*;#@Aii81(I_v69|NOSt+WiFJhzLbPt17Twl&x4TlM~q6X5dsTvbzIme-}KDDS-+6PRZO;
zuP7jF1V5Y?g$LO`I2pd6iDobyO6%%!9<;!EBnBskTsXHwZ%-XIF<}Iu!lY6cdg*M%R;9RmP5cpNm2|4Ae^c_uBRq)jT;@B9
zUKvHtHOf77+}yp7IPo#>ZNCWM>G%C;QWk~TbNuz($B81I?5CtRnu`%ZH~tb8U1eb2
zzZ|2Mz;Yiv`jYQQ_|tV*1^7#X@G^GN1suGW$y`r!BjKv9D}w#
zV-)hYAJBN2`D!%ogDFyFWv8C^tOm*$Vd8IBV0p8pXn?&OUY%1P)Ag)}RzB5cf+jAN
zXbs@=RQh7;>X;bvKswhd&WL+1CFkV6RJC*(3Oo-(`1lmV`Wh^+$TMK(m&LV~?NQIq
zPkUm4qwO|v!wTpb!W$yym(NttgW-?a1*BqHu*%8_24%lcd+o3G!!hJaj>EOVT
zx+y#6g&Js^Rq^0|#6XQrdZU+$I1