mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-09 16:05:07 +00:00
Mail Sorting Unit (#2742)
## About The Pull Request Adds the Mail Sorting Unit for cargo. https://github.com/tgstation/tgstation/pull/88288 https://github.com/tgstation/tgstation/pull/88562 --------- Co-authored-by: mcbalaam <104003807+mcbalaam@users.noreply.github.com> Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -476,3 +476,9 @@
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
#undef MAX_FLAT_PACKS
|
||||
|
||||
/obj/item/flatpack/flatpacker // a roundstart flatpacker is NICE you can gahdamn tell the time and everythin'
|
||||
board = /obj/item/circuitboard/machine/flatpacker
|
||||
|
||||
/obj/item/flatpack/mailsorter // to have a roundstart mail sorter at cargo
|
||||
board = /obj/item/circuitboard/machine/mailsorter
|
||||
|
||||
@@ -1475,6 +1475,16 @@
|
||||
/datum/stock_part/scanning_module = 1,
|
||||
/datum/stock_part/card_reader = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/mailsorter
|
||||
name = "Mail Sorter"
|
||||
greyscale_colors = CIRCUIT_COLOR_SUPPLY
|
||||
build_path = /obj/machinery/mailsorter
|
||||
req_components = list(
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/datum/stock_part/matter_bin = 2,
|
||||
/datum/stock_part/scanning_module = 1)
|
||||
needs_anchored = TRUE
|
||||
|
||||
//Tram
|
||||
/obj/item/circuitboard/machine/crossing_signal
|
||||
name = "Crossing Signal"
|
||||
|
||||
@@ -1347,3 +1347,13 @@
|
||||
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_CARGO
|
||||
|
||||
/datum/design/board/mailsorter
|
||||
name = "Mail Sorter"
|
||||
desc = "The circuit board for a mail sorting unit."
|
||||
id = "mailsorter"
|
||||
build_path = /obj/item/circuitboard/machine/mailsorter
|
||||
category = list(
|
||||
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_CARGO
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_ENGINEERING
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"manulathe",
|
||||
"manusorter",
|
||||
"manurouter",
|
||||
"mailsorter",
|
||||
)
|
||||
|
||||
/datum/techweb_node/energy_manipulation
|
||||
|
||||
314
code/modules/vending/mail.dm
Normal file
314
code/modules/vending/mail.dm
Normal file
@@ -0,0 +1,314 @@
|
||||
#define STATE_SORTING "sorting"
|
||||
#define STATE_IDLE "idle"
|
||||
#define STATE_YES "yes"
|
||||
#define STATE_NO "no"
|
||||
#define MAIL_CAPACITY 100
|
||||
|
||||
/obj/machinery/mailsorter
|
||||
name = "mail sorter"
|
||||
desc = "A large mail sorting unit. Sorting mail since 1987!"
|
||||
icon = 'icons/obj/machines/mailsorter.dmi'
|
||||
icon_state = "mailsorter"
|
||||
base_icon_state = "mailsorter"
|
||||
layer = BELOW_OBJ_LAYER
|
||||
density = TRUE
|
||||
max_integrity = 300
|
||||
integrity_failure = 0.33
|
||||
req_access = list(ACCESS_CARGO)
|
||||
circuit = /obj/item/circuitboard/machine/mailsorter
|
||||
|
||||
var/light_mask = "mailsorter-light-mask"
|
||||
var/panel_type = "panel"
|
||||
|
||||
/// What the machine is currently doing. Can be "sorting", "idle", "yes", "no".
|
||||
var/currentstate = STATE_IDLE
|
||||
/// List of all mail that's inside the mailbox.
|
||||
var/list/mail_list = list()
|
||||
/// The direction in which the mail will be unloaded.
|
||||
var/output_dir = SOUTH
|
||||
/// List of the departments to sort the mail for.
|
||||
var/static/list/sorting_departments = list(
|
||||
DEPARTMENT_ENGINEERING,
|
||||
DEPARTMENT_SECURITY,
|
||||
DEPARTMENT_MEDICAL,
|
||||
DEPARTMENT_SCIENCE,
|
||||
DEPARTMENT_CARGO,
|
||||
DEPARTMENT_SERVICE,
|
||||
DEPARTMENT_COMMAND,
|
||||
)
|
||||
var/static/list/choices = list(
|
||||
"Eject" = icon('icons/hud/radial.dmi', "radial_eject"),
|
||||
"Dump" = icon('icons/hud/radial.dmi', "mail_dump"),
|
||||
"Sort" = icon('icons/hud/radial.dmi', "mail_sort"),
|
||||
)
|
||||
|
||||
/// Steps one tile in the `output_dir`. Returns `turf`.
|
||||
/obj/machinery/mailsorter/proc/get_unload_turf()
|
||||
return get_step(src, output_dir)
|
||||
|
||||
/// Opening the maintenance panel.
|
||||
/obj/machinery/mailsorter/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
default_deconstruction_screwdriver(user, "[base_icon_state]-off", base_icon_state, tool)
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/// Deconstructing the mail sorter.
|
||||
/obj/machinery/mailsorter/crowbar_act(mob/living/user, obj/item/tool)
|
||||
default_deconstruction_crowbar(tool)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/machinery/mailsorter/examine(mob/user)
|
||||
. = ..()
|
||||
. += span_notice("There is[length(mail_list) < 100 ? " " : " no more "]space for <b>[length(mail_list) < 100 ? "[100 - length(mail_list)] " : ""]</b>envelope\s inside.")
|
||||
. += span_notice("There [length(mail_list) >= 2 ? "are" : "is"] <b>[length(mail_list) ? length(mail_list) : "no"]</b> envelope\s inside.")
|
||||
if(panel_open)
|
||||
. += span_notice("Alt-click to rotate the output direction.")
|
||||
|
||||
/obj/machinery/mailsorter/Destroy()
|
||||
QDEL_LIST(mail_list)
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/mailsorter/on_deconstruction(disassembled)
|
||||
drop_all_mail()
|
||||
. = ..()
|
||||
|
||||
/// Drops all enevlopes on the machine turf.
|
||||
/obj/machinery/mailsorter/proc/drop_all_mail()
|
||||
if(!isturf(get_turf(src)))
|
||||
QDEL_LIST(mail_list)
|
||||
return
|
||||
for(var/obj/item/mail in mail_list)
|
||||
mail.forceMove(src)
|
||||
mail_list -= mail
|
||||
|
||||
/// Dumps all envelopes on the `unload_turf`.
|
||||
/obj/machinery/mailsorter/proc/dump_all_mail()
|
||||
if(!isturf(get_turf(src)))
|
||||
QDEL_LIST(mail_list)
|
||||
return
|
||||
var/turf/unload_turf = get_unload_turf()
|
||||
for(var/obj/item/mail in mail_list)
|
||||
mail.forceMove(unload_turf)
|
||||
mail.throw_at(unload_turf, 2, 3)
|
||||
mail_list -= mail
|
||||
|
||||
/// Validates whether the inserted item is acceptable.
|
||||
/obj/machinery/mailsorter/proc/accept_check(obj/item/weapon)
|
||||
var/static/list/accepted_items = list(
|
||||
/obj/item/mail,
|
||||
/obj/item/paper,
|
||||
)
|
||||
return is_type_in_list(weapon, accepted_items)
|
||||
|
||||
/obj/machinery/mailsorter/interact(mob/user)
|
||||
if (!allowed(user))
|
||||
to_chat(user, span_warning("Access denied."))
|
||||
return
|
||||
if (currentstate != STATE_IDLE)
|
||||
return
|
||||
if (length(mail_list) == 0)
|
||||
to_chat(user, span_warning("There's no mail inside!"))
|
||||
return
|
||||
var/choice = show_radial_menu(
|
||||
user,
|
||||
src,
|
||||
choices,
|
||||
require_near = !HAS_SILICON_ACCESS(user),
|
||||
autopick_single_option = FALSE,
|
||||
)
|
||||
if (!choice)
|
||||
return
|
||||
switch (choice)
|
||||
if ("Eject")
|
||||
pick_mail(user)
|
||||
if ("Dump")
|
||||
playsound(src, 'sound/machines/buzz/buzz-sigh.ogg', 20, TRUE)
|
||||
to_chat(user, span_notice("[src] dumps [length(mail_list)] envelope\s on the floor."))
|
||||
dump_all_mail()
|
||||
if ("Sort")
|
||||
sort_mail(user)
|
||||
|
||||
/// Prompts the player to select a department to sort the mail for. Returns if `null`.
|
||||
/obj/machinery/mailsorter/proc/sort_mail(mob/user)
|
||||
var/sorting_dept = tgui_input_list(user, "Choose the department to sort mail for","Mail Sorting", sorting_departments)
|
||||
if (!sorting_dept)
|
||||
return
|
||||
currentstate = STATE_SORTING
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
playsound(src, 'sound/machines/mail_sort.ogg', 20, TRUE)
|
||||
addtimer(CALLBACK(src, PROC_REF(continue_sort), user, sorting_dept), 5 SECONDS)
|
||||
|
||||
/// Sorts the mail based on the picked department. Ejects the sorted envelopes onto the `unload_turf`.
|
||||
/obj/machinery/mailsorter/proc/continue_sort(mob/user, sorting_dept)
|
||||
var/list/sorted_mail = list()
|
||||
var/total_to_sort = length(mail_list)
|
||||
var/sorted = 0
|
||||
var/unable_to_sort = 0
|
||||
|
||||
for (var/obj/item/mail/some_mail in mail_list)
|
||||
if (!some_mail.recipient_ref)
|
||||
unable_to_sort ++
|
||||
continue
|
||||
var/datum/mind/some_recipient = some_mail.recipient_ref.resolve()
|
||||
if (some_recipient)
|
||||
var/datum/job/recipient_job = some_recipient.assigned_role
|
||||
var/datum/job_department/primary_department = recipient_job.departments_list?[1]
|
||||
if (primary_department == null) // permabrig is temporary, tide is forever
|
||||
unable_to_sort ++
|
||||
else
|
||||
var/datum/job_department/main_department = primary_department.department_name
|
||||
if (main_department == sorting_dept)
|
||||
sorted_mail.Add(some_mail)
|
||||
sorted ++
|
||||
else
|
||||
unable_to_sort ++
|
||||
if (length(sorted_mail) == 0)
|
||||
currentstate = STATE_NO
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
playsound(src, 'sound/machines/buzz/buzz-sigh.ogg', 20, TRUE)
|
||||
say("No mail for the following department: [sorting_dept].")
|
||||
else
|
||||
currentstate = STATE_YES
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
say("[sorted] envelope\s sorted successfully.")
|
||||
playsound(src, 'sound/machines/ping.ogg', 20, TRUE)
|
||||
to_chat(user, span_notice("[src] ejects [length(sorted_mail)] envelope\s."))
|
||||
var/turf/unload_turf = get_unload_turf()
|
||||
for (var/obj/item/mail/mail_in_list in sorted_mail)
|
||||
mail_in_list.forceMove(unload_turf)
|
||||
sorted_mail -= mail_in_list
|
||||
mail_list -= mail_in_list
|
||||
addtimer(CALLBACK(src, PROC_REF(check_sorted), unable_to_sort, total_to_sort), 1 SECONDS)
|
||||
|
||||
/// Informs the player of the amount of processed envelopes.
|
||||
/obj/machinery/mailsorter/proc/check_sorted(mob/user, unable_to_sort, total_to_sort)
|
||||
if (unable_to_sort > 0)
|
||||
playsound(src, 'sound/machines/buzz/buzz-sigh.ogg', 20, TRUE)
|
||||
say("Couldn't sort [unable_to_sort] envelope\s.")
|
||||
else
|
||||
playsound(src, 'sound/machines/ping.ogg', 20, TRUE)
|
||||
say("[total_to_sort] envelope\s processed.")
|
||||
addtimer(CALLBACK(src, PROC_REF(update_state_after_sorting)), 1 SECONDS)
|
||||
|
||||
/obj/machinery/mailsorter/proc/update_state_after_sorting()
|
||||
currentstate = STATE_IDLE
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
|
||||
/obj/machinery/mailsorter/item_interaction(mob/user, obj/item/thingy, params)
|
||||
if (istype(thingy, /obj/item/storage/bag/mail))
|
||||
if (length(thingy.contents) < 1)
|
||||
to_chat(user, span_warning("The [thingy] is empty!"))
|
||||
return
|
||||
var/loaded = 0
|
||||
for (var/obj/item/mail in thingy.contents)
|
||||
if (!(mail.item_flags & ABSTRACT) && \
|
||||
!(mail.flags_1 & HOLOGRAM_1) && \
|
||||
accept_check(mail) \
|
||||
)
|
||||
if (length(mail_list) + 1 > MAIL_CAPACITY )
|
||||
to_chat(user, span_warning("There is no space for more mail in [src]!"))
|
||||
return FALSE
|
||||
else if (load(mail, user))
|
||||
loaded++
|
||||
mail_list += mail
|
||||
if(loaded)
|
||||
user.visible_message(span_notice("[user] loads \the [src] with \the [thingy]."), \
|
||||
span_notice("You load \the [src] with \the [thingy]."))
|
||||
if(length(thingy.contents))
|
||||
to_chat(user, span_warning("Some items are refused."))
|
||||
return TRUE
|
||||
else
|
||||
to_chat(user, span_warning("There is nothing in \the [thingy] to put in the [src]!"))
|
||||
return FALSE
|
||||
else if (istype(thingy, /obj/item/mail))
|
||||
if (length(mail_list) + 1 > MAIL_CAPACITY )
|
||||
to_chat(user, span_warning("There is no space for more mail in [src]!"))
|
||||
else
|
||||
thingy.forceMove(src)
|
||||
mail_list += thingy
|
||||
to_chat(user, span_notice("The [src] whizzles as it accepts the [thingy]."))
|
||||
|
||||
/// Prompts the user to select an anvelope from the list of all the envelopes inside.
|
||||
/obj/machinery/mailsorter/proc/pick_mail(mob/user)
|
||||
if(!length(mail_list))
|
||||
return
|
||||
var/obj/item/mail/mail_throw = tgui_input_list(user, "Choose the envelope to eject","Mail Sorting", mail_list)
|
||||
if(!mail_throw)
|
||||
return
|
||||
currentstate = STATE_SORTING
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
playsound(src, 'sound/machines/mail_sort.ogg', 20, TRUE)
|
||||
addtimer(CALLBACK(src, PROC_REF(pick_envelope), user, mail_throw), 50)
|
||||
|
||||
/// Ejects a single envelope the player has picked onto the `unload_turf`.
|
||||
/obj/machinery/mailsorter/proc/pick_envelope(mob/user, obj/item/mail/mail_throw)
|
||||
to_chat(user, span_notice("[src] reluctantly spits out [mail_throw]."))
|
||||
var/turf/unload_turf = get_unload_turf()
|
||||
mail_throw.forceMove(unload_turf)
|
||||
mail_throw.throw_at(unload_turf, 2, 3)
|
||||
mail_list -= mail_throw
|
||||
currentstate = STATE_IDLE
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
|
||||
/// Tries to load something into the machine.
|
||||
/obj/machinery/mailsorter/proc/load(obj/item/thingy, mob/user)
|
||||
if(ismob(thingy.loc))
|
||||
var/mob/owner = thingy.loc
|
||||
if(!owner.transferItemToLoc(thingy, src))
|
||||
to_chat(owner, span_warning("\the [thingy] is stuck to your hand, you cannot put it in \the [src]!"))
|
||||
return FALSE
|
||||
return TRUE
|
||||
else
|
||||
if(thingy.loc.atom_storage)
|
||||
return thingy.loc.atom_storage.attempt_remove(thingy, src, silent = TRUE)
|
||||
else
|
||||
thingy.forceMove(src)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/mailsorter/click_alt(mob/living/user)
|
||||
if(!panel_open)
|
||||
return CLICK_ACTION_BLOCKING
|
||||
output_dir = turn(output_dir, -90)
|
||||
to_chat(user, span_notice("You change [src]'s I/O settings, setting the output to [dir2text(output_dir)]."))
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
return CLICK_ACTION_SUCCESS
|
||||
|
||||
|
||||
/obj/machinery/mailsorter/update_overlays()
|
||||
. = ..()
|
||||
if(!powered())
|
||||
return
|
||||
if(!(machine_stat & BROKEN))
|
||||
var/image/mail_output = image(icon='icons/obj/doors/airlocks/station/overlays.dmi', icon_state="unres_[output_dir]")
|
||||
switch(output_dir)
|
||||
if(NORTH)
|
||||
mail_output.pixel_y = 32
|
||||
if(SOUTH)
|
||||
mail_output.pixel_y = -32
|
||||
if(EAST)
|
||||
mail_output.pixel_x = 32
|
||||
if(WEST)
|
||||
mail_output.pixel_x = -32
|
||||
mail_output.color = COLOR_CRAYON_ORANGE
|
||||
var/mutable_appearance/light_out = emissive_appearance(mail_output.icon, mail_output.icon_state, offset_spokesman = src, alpha = mail_output.alpha)
|
||||
light_out.pixel_y = mail_output.pixel_y
|
||||
light_out.pixel_x = mail_output.pixel_x
|
||||
. += mail_output
|
||||
. += light_out
|
||||
. += mutable_appearance(base_icon_state, currentstate)
|
||||
if(panel_open)
|
||||
. += panel_type
|
||||
if(light_mask && !(machine_stat & BROKEN))
|
||||
. += emissive_appearance(icon, light_mask, src)
|
||||
|
||||
/obj/machinery/mailsorter/update_icon_state()
|
||||
icon_state = "[base_icon_state][powered() ? null : "-off"]"
|
||||
if(machine_stat & BROKEN)
|
||||
icon_state = "[base_icon_state]-broken"
|
||||
return ..()
|
||||
|
||||
#undef STATE_SORTING
|
||||
#undef STATE_IDLE
|
||||
#undef STATE_YES
|
||||
#undef STATE_NO
|
||||
#undef MAIL_CAPACITY
|
||||
@@ -204,6 +204,7 @@ GLOBAL_VAR_INIT(roaches_deployed, FALSE)
|
||||
/obj/item/storage/bag/mail = 3,
|
||||
/obj/item/radio/headset/headset_cargo = 3,
|
||||
/obj/item/clothing/accessory/pocketprotector = 3,
|
||||
/obj/item/flatpack/mailsorter = 1,
|
||||
)
|
||||
premium = list(
|
||||
/obj/item/clothing/head/costume/mailman = 1,
|
||||
|
||||
5
html/changelogs/AutoChangeLog-pr-88288.yml
Normal file
5
html/changelogs/AutoChangeLog-pr-88288.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
author: "mcbalaam"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Added the mail sorting unit - working with mail has never been simpler!"
|
||||
- rscadd: "Added two flatpack pre-defined subtypes for the flatpacker and the mail sorter."
|
||||
4
html/changelogs/AutoChangeLog-pr-88562.yml
Normal file
4
html/changelogs/AutoChangeLog-pr-88562.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
author: "mcbalaam"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "The mail sorter no longer runtimes processing assistant mail"
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 28 KiB |
BIN
icons/obj/machines/mailsorter.dmi
Normal file
BIN
icons/obj/machines/mailsorter.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 114 KiB |
@@ -4,3 +4,5 @@ This is licensed under CC-BY 4.0, found at https://creativecommons.org/licenses/
|
||||
|
||||
shutter.ogg adapted from Joseph Sardin on BigSoundBank
|
||||
https://bigsoundbank.com/detail-2475-manual-roller-shutter-closing-out-2.html
|
||||
|
||||
mail_sort.ogg adapted from csigusz_foxoup ob Freesound https://freesound.org/people/csigusz_foxoup/sounds/711428/
|
||||
BIN
sound/machines/mail_sort.ogg
Normal file
BIN
sound/machines/mail_sort.ogg
Normal file
Binary file not shown.
@@ -6400,6 +6400,7 @@
|
||||
#include "code\modules\vending\liberation.dm"
|
||||
#include "code\modules\vending\liberation_toy.dm"
|
||||
#include "code\modules\vending\magivend.dm"
|
||||
#include "code\modules\vending\mail.dm"
|
||||
#include "code\modules\vending\medical.dm"
|
||||
#include "code\modules\vending\medical_wall.dm"
|
||||
#include "code\modules\vending\megaseed.dm"
|
||||
|
||||
Reference in New Issue
Block a user