diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm
index 9c542b505c..920886cc74 100644
--- a/code/datums/components/mood.dm
+++ b/code/datums/components/mood.dm
@@ -34,6 +34,7 @@
RegisterSignal(parent, COMSIG_MOB_HUD_CREATED, .proc/modify_hud)
RegisterSignal(parent, COMSIG_MOB_DEATH, .proc/stop_processing)
RegisterSignal(parent, COMSIG_VOID_MASK_ACT, .proc/direct_sanity_drain)
+ RegisterSignal(parent, COMSIG_ENTER_AREA, .proc/update_beauty)
if(owner.hud_used)
@@ -355,7 +356,7 @@
if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS)
add_event(null, "charge", /datum/mood_event/supercharged)
-/datum/component/mood/proc/update_beauty(area/A)
+/datum/component/mood/proc/update_beauty(datum/source, area/A)
if(A.outdoors) //if we're outside, we don't care.
clear_event(null, "area_beauty")
return FALSE
diff --git a/code/datums/elements/connect_loc.dm b/code/datums/elements/connect_loc.dm
new file mode 100644
index 0000000000..fee9072f75
--- /dev/null
+++ b/code/datums/elements/connect_loc.dm
@@ -0,0 +1,43 @@
+/// This element hooks a signal onto the loc the current object is on.
+/// When the object moves, it will unhook the signal and rehook it to the new object.
+/datum/element/connect_loc
+ element_flags = ELEMENT_BESPOKE
+ id_arg_index = 2
+
+ /// An assoc list of signal -> procpath to register to the loc this object is on.
+ var/list/connections
+
+/datum/element/connect_loc/Attach(atom/movable/listener, list/connections)
+ . = ..()
+ if (!istype(listener))
+ return ELEMENT_INCOMPATIBLE
+
+ src.connections = connections
+
+ RegisterSignal(listener, COMSIG_MOVABLE_MOVED, .proc/on_moved, override = TRUE)
+ update_signals(listener)
+
+/datum/element/connect_loc/Detach(atom/movable/listener)
+ . = ..()
+ unregister_signals(listener, listener.loc)
+ UnregisterSignal(listener, COMSIG_MOVABLE_MOVED)
+
+/datum/element/connect_loc/proc/update_signals(atom/movable/listener)
+ var/atom/listener_loc = listener.loc
+ if(isnull(listener_loc))
+ return
+
+ for (var/signal in connections)
+ //override=TRUE because more than one connect_loc element instance tracked object can be on the same loc
+ listener.RegisterSignal(listener_loc, signal, connections[signal], override=TRUE)
+
+/datum/element/connect_loc/proc/unregister_signals(datum/listener, atom/old_loc)
+ if(isnull(old_loc))
+ return
+
+ listener.UnregisterSignal(old_loc, connections)
+
+/datum/element/connect_loc/proc/on_moved(atom/movable/listener, atom/old_loc)
+ SIGNAL_HANDLER
+ unregister_signals(listener, old_loc)
+ update_signals(listener)
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 62b2a6da8d..e1d7737f5c 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -149,10 +149,11 @@ Class Procs:
circuit = new circuit(src)
circuit.apply_default_parts(src)
- if(!speed_process && init_process)
- START_PROCESSING(SSmachines, src)
- else
- START_PROCESSING(SSfastprocess, src)
+ if(init_process) // Required to prevent non-speed non-init machines from running
+ if(speed_process)
+ START_PROCESSING(SSfastprocess, src)
+ else
+ START_PROCESSING(SSmachines, src)
RegisterSignal(src, COMSIG_ENTER_AREA, .proc/power_change)
if (occupant_typecache)
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 1d7cbc7f53..966985c427 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -61,12 +61,17 @@
/obj/machinery/suit_storage_unit/engine
suit_type = /obj/item/clothing/suit/space/hardsuit/engine
mask_type = /obj/item/clothing/mask/breath
- shoes_type= /obj/item/clothing/shoes/magboots
+ shoes_type = /obj/item/clothing/shoes/magboots
+
+/obj/machinery/suit_storage_unit/atmos
+ suit_type = /obj/item/clothing/suit/space/hardsuit/engine/atmos
+ mask_type = /obj/item/clothing/mask/breath
+ storage_type = /obj/item/watertank/atmos
/obj/machinery/suit_storage_unit/ce
suit_type = /obj/item/clothing/suit/space/hardsuit/engine/elite
mask_type = /obj/item/clothing/mask/breath
- shoes_type= /obj/item/clothing/shoes/magboots/advance
+ shoes_type = /obj/item/clothing/shoes/magboots/advance
/obj/machinery/suit_storage_unit/security
suit_type = /obj/item/clothing/suit/space/hardsuit/security
@@ -165,7 +170,6 @@
/obj/machinery/suit_storage_unit/update_overlays()
. = ..()
-
if(uv)
if(uv_super)
. += "super"
@@ -182,7 +186,7 @@
. += "suit"
if(helmet)
. += "helm"
- if(storage)
+ if(shoes || storage)
. += "storage"
else if(occupant)
. += "human"
@@ -199,7 +203,6 @@
helmet = null
suit = null
mask = null
- shoes = null
storage = null
occupant = null
@@ -210,109 +213,8 @@
new /obj/item/stack/sheet/metal(loc, 2)
qdel(src)
-/obj/machinery/suit_storage_unit/interact(mob/living/user)
- var/static/list/items
-
- if (!items)
- items = list(
- "suit" = create_silhouette_of(/obj/item/clothing/suit/space/eva),
- "helmet" = create_silhouette_of(/obj/item/clothing/head/helmet/space/eva),
- "mask" = create_silhouette_of(/obj/item/clothing/mask/breath),
- "shoes" = create_silhouette_of(/obj/item/clothing/shoes/magboots),
- "storage" = create_silhouette_of(/obj/item/tank/internals/oxygen),
- )
-
- . = ..()
- if (.)
- return
-
- if (!check_interactable(user))
- return
-
- var/list/choices = list()
-
- if (locked)
- choices["unlock"] = icon('modular_sand/icons/hud/radial.dmi', "radial_unlock")
- else if (state_open)
- choices["close"] = icon('modular_sand/icons/hud/radial.dmi', "radial_close")
-
- for (var/item_key in items)
- var/item = vars[item_key]
- if (item)
- choices[item_key] = item
- else
- // If the item doesn't exist, put a silhouette in its place
- choices[item_key] = items[item_key]
- else
- choices["open"] = icon('modular_sand/icons/hud/radial.dmi', "radial_open")
- choices["disinfect"] = icon('modular_sand/icons/hud/radial.dmi', "radial_disinfect")
- choices["lock"] = icon('modular_sand/icons/hud/radial.dmi', "radial_lock")
-
- var/choice = show_radial_menu(
- user,
- src,
- choices,
- custom_check = CALLBACK(src, .proc/check_interactable, user),
- require_near = !issilicon(user),
- )
-
- if (!choice)
- return
-
- switch (choice)
- if ("open")
- if (!state_open)
- open_machine(drop = FALSE)
- if (occupant)
- dump_contents()
- if ("close")
- if (state_open)
- close_machine()
- if ("disinfect")
- if (occupant && safeties)
- return
- else if (!helmet && !mask && !suit && !shoes && !storage && !occupant)
- return
- else
- if (occupant)
- var/mob/living/mob_occupant = occupant
- to_chat(mob_occupant, "[src]'s confines grow warm, then hot, then scorching. You're being burned [!mob_occupant.stat ? "alive" : "away"]!")
- cook()
- if ("lock", "unlock")
- if (!state_open)
- locked = !locked
- else
- var/obj/item/item_to_dispense = vars[choice]
- if (item_to_dispense)
- vars[choice] = null
- user.put_in_hands(item_to_dispense)
- else
- var/obj/item/in_hands = user.get_active_held_item()
- if (in_hands)
- attackby(in_hands, user)
-
- interact(user)
-
-/obj/machinery/suit_storage_unit/proc/check_interactable(mob/user)
- if (!state_open && !can_interact(user))
- return FALSE
-
- if (panel_open)
- return FALSE
-
- if (uv)
- return FALSE
-
- return TRUE
-
-/obj/machinery/suit_storage_unit/proc/create_silhouette_of(atom/item)
- var/image/image = image(initial(item.icon), initial(item.icon_state))
- image.alpha = 128
- image.color = COLOR_RED
- return image
-
-/obj/machinery/suit_storage_unit/MouseDrop_T(atom/A, mob/living/user)
- if(!istype(user) || user.stat || !Adjacent(user) || !Adjacent(A) || !isliving(A))
+/obj/machinery/suit_storage_unit/MouseDrop_T(atom/A, mob/user)
+ if(user.stat || user.lying || !Adjacent(user) || !Adjacent(A) || !isliving(A))
return
var/mob/living/target = A
if(!state_open)
@@ -525,15 +427,93 @@
return ..()
-/* ref tg-git issue #45036
- screwdriving it open while it's running a decontamination sequence without closing the panel prior to finish
- causes the SSU to break due to state_open being set to TRUE at the end, and the panel becoming inaccessible.
-*/
-/obj/machinery/suit_storage_unit/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/I)
- if(!(flags_1 & NODECONSTRUCT_1) && I.tool_behaviour == TOOL_SCREWDRIVER && uv)
- to_chat(user, "It might not be wise to fiddle with [src] while it's running...")
- return TRUE
- return ..()
+/obj/machinery/suit_storage_unit/ui_state(mob/user)
+ return GLOB.notcontained_state
+
+/obj/machinery/suit_storage_unit/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "SuitStorageUnit", name)
+ ui.open()
+
+/obj/machinery/suit_storage_unit/ui_data()
+ var/list/data = list()
+ data["locked"] = locked
+ data["open"] = state_open
+ data["safeties"] = safeties
+ data["uv_active"] = uv
+ data["uv_super"] = uv_super
+ if(helmet)
+ data["helmet"] = helmet.name
+ else
+ data["helmet"] = null
+ if(suit)
+ data["suit"] = suit.name
+ else
+ data["suit"] = null
+ if(mask)
+ data["mask"] = mask.name
+ else
+ data["mask"] = null
+ if(shoes)
+ data["shoes"] = shoes.name
+ else
+ data["shoes"] = null
+ if(storage)
+ data["storage"] = storage.name
+ else
+ data["storage"] = null
+ if(occupant)
+ data["occupied"] = TRUE
+ else
+ data["occupied"] = FALSE
+ return data
+
+/obj/machinery/suit_storage_unit/ui_act(action, params)
+ if(..() || uv)
+ return
+ switch(action)
+ if("door")
+ if(state_open)
+ close_machine()
+ else
+ open_machine(0)
+ if(occupant)
+ dump_contents() // Dump out contents if someone is in there.
+ . = TRUE
+ if("lock")
+ if(state_open)
+ return
+ locked = !locked
+ . = TRUE
+ if("uv")
+ if(occupant && safeties)
+ return
+ else if(!helmet && !mask && !suit && !storage && !occupant)
+ return
+ else
+ if(occupant)
+ var/mob/living/mob_occupant = occupant
+ to_chat(mob_occupant, "[src]'s confines grow warm, then hot, then scorching. You're being burned [!mob_occupant.stat ? "alive" : "away"]!")
+ cook()
+ . = TRUE
+ if("dispense")
+ if(!state_open)
+ return
+
+ var/static/list/valid_items = list("helmet", "suit", "mask", "shoes", "storage")
+ var/item_name = params["item"]
+ if(item_name in valid_items)
+ var/obj/item/I = vars[item_name]
+ vars[item_name] = null
+ if(I)
+ var/mob/living/living_person = usr
+ if(!istype(living_person))
+ return
+ if(!istype(living_person) || !Adjacent(living_person) || !living_person.put_in_active_hand(I))
+ I.forceMove(loc)
+ . = TRUE
+ update_icon()
/obj/machinery/suit_storage_unit/default_pry_open(obj/item/I)//needs to check if the storage is locked.
. = !(state_open || panel_open || is_operational() || locked || (flags_1 & NODECONSTRUCT_1)) && I.tool_behaviour == TOOL_CROWBAR
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index eeef55941f..96a26e704c 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -399,7 +399,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
if(throwing)
throwing.finalize(FALSE)
if(loc == user)
- if(!user.temporarilyRemoveItemFromInventory(I = src))
+ if(!allow_attack_hand_drop(user) || !user.temporarilyRemoveItemFromInventory(src))
return
. = FALSE
@@ -428,7 +428,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
if(throwing)
throwing.finalize(FALSE)
if(loc == user)
- if(!user.temporarilyRemoveItemFromInventory(src))
+ if(!allow_attack_hand_drop(user) || !user.temporarilyRemoveItemFromInventory(I = src))
return
pickup(user)
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 7b2143cf86..f44860d769 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -42,7 +42,7 @@
var/static/list/runes = list("rune1","rune2","rune3","rune4","rune5","rune6")
var/static/list/randoms = list(RANDOM_ANY, RANDOM_RUNE, RANDOM_ORIENTED,
RANDOM_NUMBER, RANDOM_GRAFFITI, RANDOM_LETTER, RANDOM_SYMBOL, RANDOM_PUNCTUATION, RANDOM_DRAWING)
- var/static/list/graffiti_large_h = list("yiffhell", "secborg", "paint")
+ var/static/list/graffiti_large_h = list("yiffhell", "furrypride", "secborg", "paint")
var/static/list/all_drawables = graffiti + symbols + drawings + oriented + runes + graffiti_large_h
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index 97c61caffd..c5e92349c7 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -257,8 +257,17 @@
used = TRUE
if(istype(A, /obj/machinery/light))
if(!proximity && bluespace_toggle)
- U.Beam(A, icon_state = "rped_upgrade", time = 1 SECONDS)
- playsound(src, 'sound/items/pshoom.ogg', 40, 1)
+ // Set variable for target light
+ var/obj/machinery/light/target = A
+
+ // Check light status before playing effects
+ if(target.status != LIGHT_OK)
+ // Display RPED beam
+ U.Beam(A, icon_state = "rped_upgrade", time = 1 SECONDS)
+
+ // Play RPED sound
+ playsound(src, 'sound/items/pshoom.ogg', 40, 1)
+
ReplaceLight(A, U)
if(!used)
diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm
index 62a3530afe..9b0506855f 100644
--- a/code/game/objects/items/mop.dm
+++ b/code/game/objects/items/mop.dm
@@ -91,7 +91,7 @@
name = "advanced mop"
mopcap = 10
icon_state = "advmop"
- item_state = "mop"
+ item_state = "advmop"
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
force = 6
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index e55a092b32..b2a7f91e96 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -237,6 +237,12 @@
icon_state = "circle_glasses"
item_state = "circle_glasses"
+/obj/item/clothing/glasses/regular/modern
+ name = "modern glasses"
+ desc = "A Dork. Co. revamp and/or revision of Nerd. Co.'s classic prescription glasses, with less opaque lenses."
+ icon_state = "glasses_alt"
+ item_state = "glasses_alt"
+
//Here lies green glasses, so ugly they died. RIP
/obj/item/clothing/glasses/sunglasses
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm
index 3d89377952..0b7ca7adfd 100644
--- a/code/modules/mining/machine_processing.dm
+++ b/code/modules/mining/machine_processing.dm
@@ -121,6 +121,7 @@
icon_state = "furnace"
density = TRUE
needs_item_input = TRUE
+ init_process = TRUE
var/obj/machinery/mineral/CONSOLE = null
var/on = FALSE
var/datum/material/selected_material = null
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index eabab35c3b..32b79343e8 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -11,6 +11,7 @@
output_dir = SOUTH
req_access = list(ACCESS_MINERAL_STOREROOM)
speed_process = TRUE
+ init_process = TRUE
circuit = /obj/item/circuitboard/machine/ore_redemption
layer = BELOW_OBJ_LAYER
var/points = 0
diff --git a/code/modules/mining/machine_unloading.dm b/code/modules/mining/machine_unloading.dm
index b39b0df6ab..16b3b3967f 100644
--- a/code/modules/mining/machine_unloading.dm
+++ b/code/modules/mining/machine_unloading.dm
@@ -9,6 +9,7 @@
input_dir = WEST
output_dir = EAST
speed_process = TRUE
+ init_process = TRUE
/obj/machinery/mineral/unloading_machine/proc/horrible_quadratic_monster(var/turf/T)
set waitfor = FALSE
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 7fff5cb71a..7f40744eb0 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -585,18 +585,28 @@
for(var/job in category)
var/datum/job/job_datum = SSjob.name_occupations[job]
if(job_datum && IsJobUnavailable(job_datum.title, TRUE) == JOB_AVAILABLE)
+ // Get currently occupied slots
+ var/num_positions_current = job_datum.current_positions
+
+ // Get total slots that can be occupied
+ var/num_positions_total = job_datum.total_positions
+
+ // Change to lemniscate for infinite-slot jobs
+ // This variable should only used to display text!
+ num_positions_total = (num_positions_total == -1 ? "∞" : num_positions_total)
+
var/command_bold = ""
if(job in GLOB.command_positions)
command_bold = " command"
- //SKYRAT CHANGES
+ //Sandstorm changes
var/jobline = "[job_datum.title] ([job_datum.current_positions])"
if(job_datum in SSjob.prioritized_jobs)
jobline = "[jobline]"
if(client && client.prefs && client.prefs.alt_titles_preferences[job_datum.title])
jobline = "[jobline]
(as [client.prefs.alt_titles_preferences[job_datum.title]])"
- jobline = "[jobline]"
+ jobline = "[jobline] ([num_positions_current]/[num_positions_total])"
dept_dat += jobline
- //END OF SKYRAT CHANGES
+ //End of Sandstorm changes
if(!dept_dat.len)
dept_dat += "No positions open."
dat += jointext(dept_dat, "")
diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm
index a21b026080..b3ad29e637 100644
--- a/code/modules/recycling/conveyor2.dm
+++ b/code/modules/recycling/conveyor2.dm
@@ -308,13 +308,32 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
S.update_icon()
CHECK_TICK
-/obj/machinery/conveyor_switch/attackby(obj/item/I, mob/user, params)
- if(I.tool_behaviour == TOOL_CROWBAR)
- var/obj/item/conveyor_switch_construct/C = new/obj/item/conveyor_switch_construct(src.loc)
- C.id = id
- transfer_fingerprints_to(C)
- to_chat(user, "You detach the conveyor switch.")
- qdel(src)
+/obj/machinery/conveyor_switch/crowbar_act(mob/user, obj/item/tool)
+ tool.play_tool_sound(src, 50)
+ var/obj/item/conveyor_switch_construct/switch_construct = new/obj/item/conveyor_switch_construct(src.loc)
+ switch_construct.id = id
+ transfer_fingerprints_to(switch_construct)
+ to_chat(user, span_notice("You detach [src]."))
+ qdel(src)
+ return TRUE
+
+/obj/machinery/conveyor_switch/screwdriver_act(mob/user, obj/item/tool)
+ tool.play_tool_sound(src, 50)
+ oneway = !oneway
+ to_chat(user, span_notice("You set [src] to [oneway ? "one way" : "default"] configuration."))
+ return TRUE
+
+/obj/machinery/conveyor_switch/wrench_act(mob/user, obj/item/tool)
+ tool.play_tool_sound(src, 50)
+ invert_icon = !invert_icon
+ update_appearance()
+ to_chat(user, span_notice("You set [src] to [invert_icon ? "inverted": "normal"] position."))
+ return TRUE
+
+/obj/machinery/conveyor_switch/examine(mob/user)
+ . = ..()
+ . += span_notice("[src] is set to [oneway ? "one way" : "default"] configuration. It can be changed with a screwdriver.")
+ . += span_notice("[src] is set to [invert_icon ? "inverted": "normal"] position. It can be rotated with a wrench.")
/obj/machinery/conveyor_switch/oneway
icon_state = "conveyor_switch_oneway"
diff --git a/code/modules/recycling/conveyor_sorter.dm b/code/modules/recycling/conveyor_sorter.dm
new file mode 100644
index 0000000000..0e42c79067
--- /dev/null
+++ b/code/modules/recycling/conveyor_sorter.dm
@@ -0,0 +1,144 @@
+// credits to jjpark-kb, see Skyrat-SS13/Skyrat-tg#8790 and related files
+// - hatterhat
+
+/obj/item/conveyor_sorter
+ name = "conveyor sorter lister"
+ desc = "A tool that is used to create conveyor sorting marks, and give sorting lists to them."
+ icon = 'icons/obj/recycling.dmi'
+ icon_state = "lister"
+ ///the list of conveyor sorters spawned by
+ var/list/spawned_sorters = list()
+ ///the list of things that are currently within the sorting list
+ var/list/current_sort = list()
+
+/obj/item/conveyor_sorter/Destroy()
+ for(var/deleting_sorters in spawned_sorters)
+ qdel(deleting_sorters)
+ return ..()
+
+/obj/item/conveyor_sorter/examine(mob/user)
+ . = ..()
+ . += span_notice("Use it to place down a conveyor sorter, up to three.")
+ . += span_notice("Use Alt-Click to reset the sorting list.")
+ . += span_notice("Attack things to attempt to add to the sorting list.")
+
+/obj/item/conveyor_sorter/attack_self(mob/user, modifiers)
+ if(length(spawned_sorters) >= 3)
+ to_chat(user, span_warning("You may only have three spawned conveyor sorters!"))
+ return
+ var/obj/effect/decal/cleanable/conveyor_sorter/new_cs = new /obj/effect/decal/cleanable/conveyor_sorter(get_turf(src))
+ new_cs.parent_item = src
+ spawned_sorters += new_cs
+
+/obj/item/conveyor_sorter/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+ if(target == src)
+ return ..()
+ if(!proximity_flag)
+ return ..()
+ if(!ismovable(target))
+ return ..()
+ if(istype(target, /obj/effect/decal/cleanable/conveyor_sorter))
+ return
+ if(is_type_in_list(target, current_sort))
+ to_chat(user, span_warning("[target] is already in [src]'s sorting list!"))
+ return
+ if(length(current_sort) >= 5)
+ to_chat(user, span_warning("[src] already has five things within the sorting list!"))
+ return
+ current_sort += target.type
+ to_chat(user, span_notice("[target] has been added to [src]'s sorting list."))
+
+/obj/item/conveyor_sorter/AltClick(mob/user)
+ visible_message("[src] pings, resetting its sorting list!")
+ playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
+ current_sort = list()
+
+/obj/effect/decal/cleanable/conveyor_sorter
+ name = "conveyor sorter"
+ desc = "A mark that sorts items out based on what they are."
+ icon = 'icons/obj/recycling.dmi'
+ icon_state = "sorter"
+ layer = OBJ_LAYER
+ plane = GAME_PLANE
+ ///the list of items that will be sorted to the sorted direction
+ var/list/sorting_list = list()
+ //the direction that the items in the sorting list will be moved to
+ dir = NORTH
+ ///the parent conveyor sorter lister item, used for deletion
+ var/obj/item/conveyor_sorter/parent_item
+ /// To prevent spam
+ COOLDOWN_DECLARE(use_cooldown)
+
+ light_range = 3
+ light_color = COLOR_RED_LIGHT
+
+/obj/effect/decal/cleanable/conveyor_sorter/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = .proc/on_entered,
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
+
+/obj/effect/decal/cleanable/conveyor_sorter/Destroy()
+ if(parent_item)
+ parent_item.spawned_sorters -= src
+ parent_item = null
+ return ..()
+
+/obj/effect/decal/cleanable/conveyor_sorter/examine(mob/user)
+ . = ..()
+ . += span_notice("Attack with conveyor sorter lister to set the sorting list.")
+ . += span_notice("Slap with empty hands to change the sorting direction.")
+ . += span_notice("Alt-Click to reset the sorting list.")
+ . += span_notice("Ctrl-Click to remove.")
+
+/obj/effect/decal/cleanable/conveyor_sorter/attack_hand(mob/living/user, list/modifiers)
+ var/user_choice = tgui_input_list(user, "Choose which direction to sort to!", "Direction choice", list("North", "East", "South", "West"))
+ if(!user_choice)
+ return ..()
+ switch(user_choice)
+ if("North")
+ setDir(NORTH)
+ if("East")
+ setDir(EAST)
+ if("South")
+ setDir(SOUTH)
+ if("West")
+ setDir(WEST)
+ visible_message("[src] pings, updating its sorting direction!")
+ playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
+
+/obj/effect/decal/cleanable/conveyor_sorter/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/conveyor_sorter))
+ var/obj/item/conveyor_sorter/cs_item = W
+ sorting_list = cs_item.current_sort
+ visible_message("[src] pings, updating its sorting list!")
+ playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
+ return
+ else
+ return ..()
+
+/obj/effect/decal/cleanable/conveyor_sorter/AltClick(mob/user)
+ visible_message("[src] pings, resetting its sorting list!")
+ playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
+ sorting_list = list()
+
+/obj/effect/decal/cleanable/conveyor_sorter/CtrlClick(mob/user)
+ visible_message("[src] pings, before disappearing!")
+ playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
+ qdel(src)
+
+/obj/effect/decal/cleanable/conveyor_sorter/proc/on_entered(datum/source, atom/movable/AM)
+ if(is_type_in_list(AM, sorting_list) && !AM.anchored && COOLDOWN_FINISHED(src, use_cooldown))
+ COOLDOWN_START(src, use_cooldown, 1 SECONDS)
+ AM.Move(get_step(src, dir))
+
+/datum/design/conveyor_sorter
+ name = "Conveyor Sorter"
+ desc = "A wonderful item that can set markers and forcefully move stuff to a direction."
+ id = "conveyor_sorter"
+ build_type = PROTOLATHE
+ build_path = /obj/item/conveyor_sorter
+ materials = list(/datum/material/iron = 500, /datum/material/plastic = 500)
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_CARGO
diff --git a/code/modules/research/techweb/nodes/engineering_nodes.dm b/code/modules/research/techweb/nodes/engineering_nodes.dm
index 1deb97c3bd..51b9480c27 100644
--- a/code/modules/research/techweb/nodes/engineering_nodes.dm
+++ b/code/modules/research/techweb/nodes/engineering_nodes.dm
@@ -7,8 +7,8 @@
prereq_ids = list("base")
design_ids = list("solarcontrol", "recharger", "powermonitor", "rped", "pacman", "adv_capacitor", "adv_scanning", "emitter", "high_cell", "adv_matter_bin",
"atmosalerts", "atmos_control", "recycler", "autolathe", "autolathe_secure", "high_micro_laser", "nano_mani", "mesons", "thermomachine", "rad_collector", "tesla_coil", "grounding_rod",
- "apc_control", "power control", "airlock_board", "firelock_board", "airalarm_electronics", "firealarm_electronics", "cell_charger", "stack_console", "stack_machine", "rcd_ammo","oxygen_tank",
- "plasma_tank", "emergency_oxygen", "emergency_oxygen_engi", "plasmaman_tank_belt", "colormate")
+ "apc_control", "power control", "airlock_board", "firelock_board", "airalarm_electronics", "firealarm_electronics", "cell_charger", "stack_console", "stack_machine", "rcd_ammo", "oxygen_tank",
+ "plasma_tank", "emergency_oxygen", "emergency_oxygen_engi", "plasmaman_tank_belt", "colormate", "conveyor_sorter")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 6000)
/datum/techweb_node/adv_engi
diff --git a/code/modules/vehicles/cars/car.dm b/code/modules/vehicles/cars/car.dm
index 81b2db6cf8..e024718f4c 100644
--- a/code/modules/vehicles/cars/car.dm
+++ b/code/modules/vehicles/cars/car.dm
@@ -2,6 +2,7 @@
layer = ABOVE_MOB_LAYER
anchored = TRUE
default_driver_move = FALSE
+ var/explode_on_death = TRUE
var/car_traits = NONE //Bitflag for special behavior such as kidnapping
var/engine_sound = 'sound/vehicles/carrev.ogg'
var/last_enginesound_time
@@ -12,6 +13,11 @@
. = ..()
LoadComponent(/datum/component/riding)
+/obj/vehicle/sealed/car/Destroy()
+ . = ..()
+ if(explode_on_death)
+ explosion(loc, 0, 1, 2, 3, 0)
+
/obj/vehicle/sealed/car/generate_actions()
. = ..()
initialize_controller_action_type(/datum/action/vehicle/sealed/remove_key, VEHICLE_CONTROL_DRIVE)
diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm
index 1a1858522a..7bb4e878ec 100644
--- a/code/modules/vehicles/sealed.dm
+++ b/code/modules/vehicles/sealed.dm
@@ -1,7 +1,6 @@
/obj/vehicle/sealed
enclosed = TRUE // you're in a sealed vehicle dont get dinked idiot
var/enter_delay = 20
- var/explode_on_death = TRUE
flags_1 = BLOCK_FACE_ATOM_1
/obj/vehicle/sealed/generate_actions()
@@ -90,8 +89,6 @@
/obj/vehicle/sealed/Destroy()
DumpMobs()
- if(explode_on_death)
- explosion(loc, 0, 1, 2, 3, 0)
return ..()
/obj/vehicle/sealed/proc/DumpMobs(randomstep = TRUE)
diff --git a/html/changelogs/archive/2023-01.yml b/html/changelogs/archive/2023-01.yml
index ba170f1622..b69203272d 100644
--- a/html/changelogs/archive/2023-01.yml
+++ b/html/changelogs/archive/2023-01.yml
@@ -17,6 +17,12 @@
- rscadd: Improves Moth in Command to be an improved version of Commander and Chief
SpookyTheFox:
- tweak: moved blueshift themed sec gear out of premium pricing.
+2023-01-08:
+ LeDrascol:
+ - bugfix: Fixed techweb sequence break for Advanced Toolset Implant
+ - tweak: Cryptominer no longer functions in space
+ - tweak: Cryptominer no longer produces Co2
+ - code_imp: Refactored processing for cryptominer
2023-01-09:
LeDrascol:
- tweak: Fluid Infuser implant uses an improved activation button
diff --git a/icons/effects/96x32.dmi b/icons/effects/96x32.dmi
index 937b2e8d42..a78d11530b 100644
Binary files a/icons/effects/96x32.dmi and b/icons/effects/96x32.dmi differ
diff --git a/icons/mob/clothing/eyes.dmi b/icons/mob/clothing/eyes.dmi
index 49702bf920..1525ba9a93 100644
Binary files a/icons/mob/clothing/eyes.dmi and b/icons/mob/clothing/eyes.dmi differ
diff --git a/icons/mob/inhands/equipment/custodial_righthand.dmi b/icons/mob/inhands/equipment/custodial_righthand.dmi
index 26d8e61163..c986155b10 100644
Binary files a/icons/mob/inhands/equipment/custodial_righthand.dmi and b/icons/mob/inhands/equipment/custodial_righthand.dmi differ
diff --git a/icons/obj/abductor.dmi b/icons/obj/abductor.dmi
index 75f84347b6..83d71c1093 100644
Binary files a/icons/obj/abductor.dmi and b/icons/obj/abductor.dmi differ
diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi
index 1752892b60..c98c984c7d 100644
Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ
diff --git a/icons/obj/recycling.dmi b/icons/obj/recycling.dmi
index 9604d6b97e..621b9e4241 100644
Binary files a/icons/obj/recycling.dmi and b/icons/obj/recycling.dmi differ
diff --git a/modular_citadel/code/modules/client/loadout/glasses.dm b/modular_citadel/code/modules/client/loadout/glasses.dm
index fe44abc3de..0ca9aa0e05 100644
--- a/modular_citadel/code/modules/client/loadout/glasses.dm
+++ b/modular_citadel/code/modules/client/loadout/glasses.dm
@@ -45,3 +45,7 @@
/datum/gear/glasses/prescription
name = "Prescription glasses"
path = /obj/item/clothing/glasses/regular
+
+/datum/gear/glasses/modern
+ name = "Modern prescription glasses"
+ path = /obj/item/clothing/glasses/regular/modern
diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm
index 1d4a29ef3e..2685812232 100644
--- a/modular_citadel/code/modules/client/loadout/suit.dm
+++ b/modular_citadel/code/modules/client/loadout/suit.dm
@@ -18,7 +18,6 @@
/datum/gear/suit/redhood
name = "Red cloak"
path = /obj/item/clothing/suit/hooded/cloak/david
- cost = 3
/datum/gear/suit/jacketbomber
name = "Bomber jacket"
@@ -160,14 +159,14 @@
/datum/gear/suit/coat/polycoat
name = "Polychromic winter coat"
path = /obj/item/clothing/suit/hooded/wintercoat/polychromic
- cost = 4 //too many people with neon green coats is hard on the eyes
+ cost = 2 //too many people with neon green coats is hard on the eyes // it's probably fine now
loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
loadout_initial_colors = list("#6A6964", "#C4B8A6", "#0000FF")
/datum/gear/suit/coat/wbreakpoly
name = "Polychromic windbreaker"
path = /obj/item/clothing/suit/toggle/wbreakpoly/polychromic
- cost = 4
+ cost = 2
loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
loadout_initial_colors = list("#464F65", "#916035", "#474747")
diff --git a/modular_citadel/code/modules/client/loadout/uniform.dm b/modular_citadel/code/modules/client/loadout/uniform.dm
index 2a75f86ffc..5c22485c1f 100644
--- a/modular_citadel/code/modules/client/loadout/uniform.dm
+++ b/modular_citadel/code/modules/client/loadout/uniform.dm
@@ -280,36 +280,34 @@
/datum/gear/uniform/suit/poly
name = "Polychromic Button-up Shirt"
path = /obj/item/clothing/under/misc/poly_shirt
- cost = 3
+ cost = 2
loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
loadout_initial_colors = list("#FFFFFF", "#353535", "#353535")
/datum/gear/uniform/skirt/poly/pleated
name = "Polychromic Pleated Sweaterskirt"
path = /obj/item/clothing/under/dress/skirt/polychromic/pleated
- cost = 3
+ cost = 2
loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
loadout_initial_colors = list("#8CC6FF", "#808080", "#FF3535")
/datum/gear/uniform/polykilt
name = "Polychromic Kilt"
path = /obj/item/clothing/under/costume/kilt/polychromic
- cost = 3
+ cost = 2
loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
loadout_initial_colors = list("#FFFFFF", "#F08080")
/datum/gear/uniform/shorts/poly
name = "Polychromic Shorts"
path = /obj/item/clothing/under/misc/polyshorts
- cost = 3
+ cost = 2
loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
loadout_initial_colors = list("#353535", "#808080", "#808080")
/datum/gear/uniform/shorts/poly/athletic
name = "Polychromic Athletic Shorts"
path = /obj/item/clothing/under/shorts/polychromic
- cost = 2
- loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
loadout_initial_colors = list("#FFFFFF", "#F08080")
/datum/gear/uniform/hopcasual
diff --git a/modular_sand/code/game/machinery/cryptominers.dm b/modular_sand/code/game/machinery/cryptominers.dm
index df17cf0c25..a3c6eccac9 100644
--- a/modular_sand/code/game/machinery/cryptominers.dm
+++ b/modular_sand/code/game/machinery/cryptominers.dm
@@ -8,13 +8,15 @@
idle_power_usage = 20
active_power_usage = 200
circuit = /obj/item/circuitboard/machine/cryptominer
+ init_process = FALSE // Don't process upon creation
var/mining = FALSE
var/miningtime = 3000
var/miningpoints = 50
var/mintemp = TCRYO // 225K equals approximately -55F or -48C
var/midtemp = T0C // 273K equals 32F or 0C
var/maxtemp = 500 // 500K equals approximately 440F or 226C
- var/heatingPower = 40000
+ var/heatingPower = 100 // Heat added each processing
+ var/require_conductivity = TRUE // Prevent use in space
var/datum/bank_account/pay_me = null
/obj/machinery/cryptominer/Initialize(mapload)
@@ -76,43 +78,60 @@
. += "Alt-Click to reset to the Cargo budget."
/obj/machinery/cryptominer/process()
+ // Get turf
var/turf/T = get_turf(src)
if(!T)
return
+
+ // Check for tiles with no conductivity (space)
+ if(T.thermal_conductivity == 0)
+ // Normal mode: Warn the user and stop processing
+ if(require_conductivity)
+ say("Invalid atmospheric conditions detected! Shutting off!")
+ playsound(loc, 'sound/machines/beep.ogg', 50, TRUE, -1)
+ set_mining(FALSE)
+ return
+
+ // Cheat mode: Skip all atmos code and give points
+ else
+ produce_points(3)
+ return
+
+ // Get air
var/datum/gas_mixture/env = T.return_air()
if(!env)
return
- if(!mining)
- return
- if(env.return_temperature() >= maxtemp)
- if(mining)
- playsound(loc, 'sound/machines/beep.ogg', 50, TRUE, -1)
+
+ // Get temp
+ var/env_temp = env.return_temperature()
+
+ // Check for temperature effects
+ // Minimum (most likely)
+ if(env_temp <= mintemp)
+ produce_points(3)
+ // Mid
+ else if((env_temp <= midtemp) && (env_temp >= mintemp))
+ produce_points(1)
+ // Maximum
+ else if((env_temp <= maxtemp) && (env_temp >= midtemp))
+ produce_points(0.20)
+ // Overheat
+ else if(env_temp >= maxtemp)
+ say("Critical overheating detected! Shutting off!")
+ playsound(loc, 'sound/machines/beep.ogg', 50, TRUE, -1)
set_mining(FALSE)
- return
- if(env.return_temperature() <= maxtemp && env.return_temperature() >= midtemp)
- if(mining)
- produce_points(0.20)
- produce_heat()
- return
- if(env.return_temperature() <= midtemp && env.return_temperature() >= mintemp)
- if(mining)
- produce_points(1)
- produce_heat()
- return
- if(env.return_temperature() <= mintemp)
- if(mining)
- produce_points(3)
- produce_heat()
- return
+
+ // Increase heat by heatingPower
+ env.set_temperature(env_temp + heatingPower)
+
+ // Update air
+ air_update_turf()
/obj/machinery/cryptominer/proc/produce_points(number)
playsound(loc, 'sound/machines/ping.ogg', 50, TRUE, -1)
if(pay_me)
pay_me.adjust_money(FLOOR(miningpoints * number,1))
-/obj/machinery/cryptominer/proc/produce_heat()
- atmos_spawn_air("co2=10;TEMP=2000")
-
/obj/machinery/cryptominer/attack_hand(mob/living/user)
. = ..()
if(!is_operational())
diff --git a/modular_sand/code/modules/mining/machine_bluespaceminer.dm b/modular_sand/code/modules/mining/machine_bluespaceminer.dm
index 0d62ee9267..513a22e4cc 100644
--- a/modular_sand/code/modules/mining/machine_bluespaceminer.dm
+++ b/modular_sand/code/modules/mining/machine_bluespaceminer.dm
@@ -7,6 +7,7 @@
can_be_unanchored = TRUE
circuit = /obj/item/circuitboard/machine/bluespace_miner
layer = BELOW_OBJ_LAYER
+ init_process = TRUE
var/list/ore_rates = list(/datum/material/iron = 0.3, /datum/material/glass = 0.3, /datum/material/plasma = 0.1, /datum/material/silver = 0.1, /datum/material/gold = 0.05, /datum/material/titanium = 0.05, /datum/material/uranium = 0.05, /datum/material/diamond = 0.02)
var/datum/component/remote_materials/materials
var/multiplier = 0 //Multiplier by tier, has been made fair and everything
diff --git a/modular_sand/code/modules/research/techweb/nodes/all_nodes.dm b/modular_sand/code/modules/research/techweb/nodes/all_nodes.dm
index 09aa866394..303af10462 100644
--- a/modular_sand/code/modules/research/techweb/nodes/all_nodes.dm
+++ b/modular_sand/code/modules/research/techweb/nodes/all_nodes.dm
@@ -27,7 +27,7 @@
id = "adv_toolset_implant"
display_name = "Advanced Toolset Implant"
description = "Allows the creation of alien powerful implants for your arms."
- prereq_ids = list("alien_bio")
+ prereq_ids = list("alien_bio", "alien_engi", "adv_cyber_implants")
design_ids = list("ci-toolset-adv","ci-surgery-adv")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
diff --git a/tgstation.dme b/tgstation.dme
index 39a492dd4e..47e18c3c82 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -728,6 +728,7 @@
#include "code\datums\elements\bed_tucking.dm"
#include "code\datums\elements\bsa_blocker.dm"
#include "code\datums\elements\cleaning.dm"
+#include "code\datums\elements\connect_loc.dm"
#include "code\datums\elements\decal.dm"
#include "code\datums\elements\dusts_on_catatonia.dm"
#include "code\datums\elements\dusts_on_leaving_area.dm"
@@ -3368,6 +3369,7 @@
#include "code\modules\reagents\reagent_containers\spray.dm"
#include "code\modules\reagents\reagent_containers\syringes.dm"
#include "code\modules\recycling\conveyor2.dm"
+#include "code\modules\recycling\conveyor_sorter.dm"
#include "code\modules\recycling\sortingmachinery.dm"
#include "code\modules\recycling\disposal\bin.dm"
#include "code\modules\recycling\disposal\construction.dm"
diff --git a/tgui/packages/tgui/interfaces/SuitStorageUnit.js b/tgui/packages/tgui/interfaces/SuitStorageUnit.js
index c6f66a79d2..0ac3c61932 100644
--- a/tgui/packages/tgui/interfaces/SuitStorageUnit.js
+++ b/tgui/packages/tgui/interfaces/SuitStorageUnit.js
@@ -14,6 +14,7 @@ export const SuitStorageUnit = (props, context) => {
suit,
helmet,
mask,
+ shoes,
storage,
} = data;
return (
@@ -89,6 +90,15 @@ export const SuitStorageUnit = (props, context) => {
item: 'mask',
})} />
+
+