diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index 9f3dbc39c251..2409fd65a5d0 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -12624,7 +12624,7 @@
/obj/effect/portal/permanent/one_way/multi/entry{
alpha = 55;
color = "7D7D7D";
- desc = "for when the clock hits one thirty and keeps ticking...";
+ desc = "For when the clock hits one thirty and keeps ticking...";
id = "testchamber";
name = "Test Chamber Portal";
teleport_channel = "quantum"
@@ -21648,7 +21648,7 @@
/obj/effect/portal/permanent/one_way/multi/entry{
alpha = 55;
color = "7D7D7D";
- desc = "for when the clock hits one thirty and keeps ticking...";
+ desc = "For when the clock hits one thirty and keeps ticking...";
id = "testchamber";
name = "Test Chamber Portal";
teleport_channel = "quantum"
@@ -23483,7 +23483,7 @@
/obj/effect/portal/permanent/one_way/multi/entry{
alpha = 55;
color = "7D7D7D";
- desc = "for when the clock hits one thirty and keeps ticking...";
+ desc = "For when the clock hits one thirty and keeps ticking...";
id = "testchamber";
name = "Test Chamber Portal";
teleport_channel = "quantum"
diff --git a/code/__DEFINES/construction/material.dm b/code/__DEFINES/construction/material.dm
index 294fe6364cd5..10eeaf9ea6cf 100644
--- a/code/__DEFINES/construction/material.dm
+++ b/code/__DEFINES/construction/material.dm
@@ -12,7 +12,7 @@
/// The maximum size of a stack object.
#define MAX_STACK_SIZE 50
/// Maximum amount of cable in a coil
-#define MAXCOIL 30
+#define MAXCOIL 40
//Category of materials
/// Is the material from an ore? currently unused but exists atm for categorizations sake
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
index 4f56824b5e4a..188297594d37 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
@@ -100,6 +100,9 @@
/// from cosmetic items to restyle certain mobs, objects or organs: (atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
#define COMSIG_ATOM_RESTYLE "atom_restyle"
+/// Called on [/atom/SpinAnimation()] : (speed, loops, segments, angle)
+#define COMSIG_ATOM_SPIN_ANIMATION "atom_spin_animation"
+
///! from proc/get_rad_contents(): ()
#define COMSIG_ATOM_RAD_PROBE "atom_rad_probe"
#define COMPONENT_BLOCK_RADIATION 1
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
index 45be2ed4f984..44278be89e13 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
@@ -94,6 +94,7 @@
/// from base of atom/movable/Process_Spacemove(): (movement_dir, continuous_move)
#define COMSIG_MOVABLE_SPACEMOVE "spacemove"
#define COMSIG_MOVABLE_STOP_SPACEMOVE (1<<0)
+ #define COMSIG_MOVABLE_ALLOW_SPACEMOVE (1<<1)
/// Sent from /obj/item/radio/talk_into(): (obj/item/radio/used_radio)
#define COMSIG_MOVABLE_USING_RADIO "movable_radio"
diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index 1ba6879005b8..211dc52c42d3 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -180,9 +180,9 @@
//#define OBJ_LAYER 3 //For easy recordkeeping; this is a byond define
#define CLOSED_DOOR_LAYER 3.1
#define CLOSED_FIREDOOR_LAYER 3.11
+#define SHUTTER_LAYER 3.12 // HERE BE DRAGONS
+#define CLOSED_BLASTDOOR_LAYER 3.13 // ABOVE DOORS
#define ABOVE_OBJ_LAYER 3.2
-#define CLOSED_BLASTDOOR_LAYER 3.3 // ABOVE WINDOWS AND DOORS
-#define SHUTTER_LAYER 3.3 // HERE BE DRAGONS
#define ABOVE_WINDOW_LAYER 3.3
#define SIGN_LAYER 3.4
#define CORGI_ASS_PIN_LAYER 3.41
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 5817688c2ae3..e7f7f15cc4e2 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -314,6 +314,13 @@
#define REAGENTS_METABOLISM 0.4 //How many units of reagent are consumed per tick, by default.
#define REAGENTS_EFFECT_MULTIPLIER (REAGENTS_METABOLISM / 0.4) // By defining the effect multiplier this way, it'll exactly adjust all effects according to how they originally were with the 0.4 metabolism
+// Eye protection
+#define FLASH_PROTECTION_HYPER_SENSITIVE -2
+#define FLASH_PROTECTION_SENSITIVE -1
+#define FLASH_PROTECTION_NONE 0
+#define FLASH_PROTECTION_FLASH 1
+#define FLASH_PROTECTION_WELDER 2
+
// Roundstart trait system
#define MAX_QUIRKS 6 //The maximum amount of quirks one character can have at roundstart
@@ -392,3 +399,25 @@
/// Possible value of [/atom/movable/buckle_lying]. If set to a different (positive-or-zero) value than this, the buckling thing will force a lying angle on the buckled.
#define NO_BUCKLE_LYING -1
+
+/// Squashing will not occur if the mob is not lying down (bodyposition is LYING_DOWN)
+#define SQUASHED_SHOULD_BE_DOWN (1<<0)
+/// If present, outright gibs the squashed mob instead of just dealing damage
+#define SQUASHED_SHOULD_BE_GIBBED (1<<1)
+/// If squashing always passes if the mob is dead
+#define SQUASHED_ALWAYS_IF_DEAD (1<<2)
+/// Don't squash our mob if its not located in a turf
+#define SQUASHED_DONT_SQUASH_IN_CONTENTS (1<<3)
+
+// Bitflags for mob dismemberment and gibbing
+/// Mobs will drop a brain
+#define DROP_BRAIN (1<<0)
+/// Mobs will drop organs
+#define DROP_ORGANS (1<<1)
+/// Mobs will drop bodyparts (arms, legs, etc.)
+#define DROP_BODYPARTS (1<<2)
+/// Mobs will drop items
+#define DROP_ITEMS (1<<3)
+
+/// Mobs will drop everything
+#define DROP_ALL_REMAINS (DROP_BRAIN | DROP_ORGANS | DROP_BODYPARTS | DROP_ITEMS)
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index ab49290820fb..359711f46144 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -116,6 +116,8 @@
#define STATUS_EFFECT_EXPOSED /datum/status_effect/exposed //increases incoming damage
+#define STATUS_EFFECT_EXPOSED_HARPOONED /datum/status_effect/exposed/harpooned //increases incoming damage when hit by a gasharpoon
+
#define STATUS_EFFECT_TAMING /datum/status_effect/taming //tames the target after enough tame stacks
#define STATUS_EFFECT_NECROPOLIS_CURSE /datum/status_effect/necropolis_curse
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index e5357fbe10b0..696563feadb6 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -173,7 +173,8 @@
#define INIT_ORDER_PATH -50
#define INIT_ORDER_DISCORD -60
#define INIT_ORDER_EXPLOSIONS -69
-#define INIT_ORDER_STATPANELS -98
+#define INIT_ORDER_STATPANELS -97
+#define INIT_ORDER_INIT_PROFILER -98 //Near the end, logs the costs of initialize
#define INIT_ORDER_DEMO -99 // To avoid a bunch of changes related to initialization being written, do this last
#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
diff --git a/code/__HELPERS/animations.dm b/code/__HELPERS/animations.dm
index cae8d3a8f52b..e80bfe319c0c 100644
--- a/code/__HELPERS/animations.dm
+++ b/code/__HELPERS/animations.dm
@@ -65,3 +65,53 @@
animate(transform = transforms[2], time = 0.1)
animate(transform = transforms[3], time = 0.2)
animate(transform = transforms[4], time = 0.3)
+
+
+/**
+ * Proc called when you want the atom to spin around the center of its icon (or where it would be if its transform var is translated)
+ * By default, it makes the atom spin forever and ever at a speed of 60 rpm.
+ *
+ * Arguments:
+ * * speed: how much it takes for the atom to complete one 360° rotation
+ * * loops: how many times do we want the atom to rotate
+ * * clockwise: whether the atom ought to spin clockwise or counter-clockwise
+ * * segments: in how many animate calls the rotation is split. Probably unnecessary, but you shouldn't set it lower than 3 anyway.
+ * * parallel: whether the animation calls have the ANIMATION_PARALLEL flag, necessary for it to run alongside concurrent animations.
+ */
+/atom/proc/SpinAnimation(speed = 1 SECONDS, loops = -1, clockwise = TRUE, segments = 3, parallel = TRUE)
+ if(!segments)
+ return
+ var/segment = 360/segments
+ if(!clockwise)
+ segment = -segment
+ SEND_SIGNAL(src, COMSIG_ATOM_SPIN_ANIMATION, speed, loops, segments, segment)
+ do_spin_animation(speed, loops, segments, segment, parallel)
+
+/atom/proc/DabAnimation(speed = 1, loops = 1, direction = 1 , hold_seconds = 0 , angle = 1 , stay = FALSE) // Hopek 2019
+ // By making this in atom/proc everything in the game can potentially dab. You have been warned.
+ if(hold_seconds > 9999) // if you need to hold a dab for more than 2 hours intentionally let me know.
+ return
+ if(hold_seconds > 0)
+ hold_seconds = hold_seconds * 10 // Converts seconds to deciseconds
+ if(angle == 1) //if angle is 1: random angle. Else take angle
+ angle = rand(25,50)
+ if(direction == 1) // direciton:: 1 for random pick, 2 for clockwise , 3 for anti-clockwise
+ direction = pick(2,3)
+ if(direction == 3) // if 3 then counter clockwise
+ angle = angle * -1
+ if(speed == 1) // if speed is 1 choose random speed from list
+ speed = rand(3,5)
+
+ // dab matrix here
+ var/matrix/DAB_COMMENCE = matrix(transform)
+ var/matrix/DAB_RETURN = matrix(transform)
+ DAB_COMMENCE.Turn(angle) // dab angle to matrix
+
+ // Dab animation
+ animate(src, transform = DAB_COMMENCE, time = speed, loops ) // dab to hold angle
+ if(hold_seconds > 0)
+ sleep(hold_seconds) // time to hold the dab before going back
+ if(!stay) // if stay param is true dab doesn't return
+ animate(transform = DAB_RETURN, time = speed * 1.5, loops ) // reverse dab to starting position , slower
+ //doesn't have an object argument because this is "Stacking" with the animate call above
+ //3 billion% intentional
diff --git a/code/__HELPERS/colors.dm b/code/__HELPERS/colors.dm
index 134091a88f88..6c6f8064d9a2 100644
--- a/code/__HELPERS/colors.dm
+++ b/code/__HELPERS/colors.dm
@@ -40,6 +40,10 @@
/// But paired down and modified to work for our color range
/// Accepts the color cutoffs as two 3 length list(0-100,...) arguments
/proc/blend_cutoff_colors(list/first_color, list/second_color)
+ // These runtimes usually mean that either the eye or the glasses have an incorrect color_cutoffs
+ ASSERT(first_color?.len == 3, "First color must be a 3 length list, received [json_encode(first_color)]")
+ ASSERT(second_color?.len == 3, "Second color must be a 3 length list, received [json_encode(second_color)]")
+
var/list/output = new /list(3)
// Invert the colors, multiply to "darken" (actually lights), then uninvert to get back to what we want
diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm
index 636e4735bc02..2fca8792abe5 100644
--- a/code/__HELPERS/matrices.dm
+++ b/code/__HELPERS/matrices.dm
@@ -2,60 +2,6 @@
. = new_angle - old_angle
Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT
-/atom/proc/SpinAnimation(speed = 1 SECONDS, loops = -1, clockwise = 1, segments = 3, parallel = TRUE)
- if(!segments)
- return
- var/segment = 360/segments
- if(!clockwise)
- segment = -segment
- var/list/matrices = list()
- for(var/i in 1 to segments-1)
- var/matrix/M = matrix(transform)
- M.Turn(segment*i)
- matrices += M
- var/matrix/last = matrix(transform)
- matrices += last
-
- speed /= segments
-
- if(parallel)
- animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
- else
- animate(src, transform = matrices[1], time = speed, loops)
- for(var/i in 2 to segments) //2 because 1 is covered above
- animate(transform = matrices[i], time = speed)
- //doesn't have an object argument because this is "Stacking" with the animate call above
- //3 billion% intentional
-
-/atom/proc/DabAnimation(speed = 1, loops = 1, direction = 1 , hold_seconds = 0 , angle = 1 , stay = FALSE) // Hopek 2019
- // By making this in atom/proc everything in the game can potentially dab. You have been warned.
- if(hold_seconds > 9999) // if you need to hold a dab for more than 2 hours intentionally let me know.
- return
- if(hold_seconds > 0)
- hold_seconds = hold_seconds * 10 // Converts seconds to deciseconds
- if(angle == 1) //if angle is 1: random angle. Else take angle
- angle = rand(25,50)
- if(direction == 1) // direciton:: 1 for random pick, 2 for clockwise , 3 for anti-clockwise
- direction = pick(2,3)
- if(direction == 3) // if 3 then counter clockwise
- angle = angle * -1
- if(speed == 1) // if speed is 1 choose random speed from list
- speed = rand(3,5)
-
- // dab matrix here
- var/matrix/DAB_COMMENCE = matrix(transform)
- var/matrix/DAB_RETURN = matrix(transform)
- DAB_COMMENCE.Turn(angle) // dab angle to matrix
-
- // Dab animation
- animate(src, transform = DAB_COMMENCE, time = speed, loops ) // dab to hold angle
- if(hold_seconds > 0)
- sleep(hold_seconds) // time to hold the dab before going back
- if(!stay) // if stay param is true dab doesn't return
- animate(transform = DAB_RETURN, time = speed * 1.5, loops ) // reverse dab to starting position , slower
- //doesn't have an object argument because this is "Stacking" with the animate call above
- //3 billion% intentional
-
//Dumps the matrix data in format a-f
/matrix/proc/tolist()
. = list()
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 93b36ddf2b4d..2ad8972edec6 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -474,8 +474,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/newdrift = ((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, newdrift))
var/starting_tick_usage = TICK_USAGE
-
- if(newdrift - olddrift >= CONFIG_GET(number/drift_dump_threshold))
+ //Yog: profile dumping was throttling lower performance computers, so we're going to have it disabled by default but you can enable it via config flags
+ if(newdrift - olddrift >= CONFIG_GET(number/drift_dump_threshold) && CONFIG_GET(flag/auto_profile))
AttemptProfileDump(CONFIG_GET(number/drift_profile_delay))
olddrift = newdrift
diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm
index f2ce0c3522f2..8a3ca56432fa 100644
--- a/code/controllers/subsystem/atoms.dm
+++ b/code/controllers/subsystem/atoms.dm
@@ -1,4 +1,3 @@
-#define SUBSYSTEM_INIT_SOURCE "subsystem init"
SUBSYSTEM_DEF(atoms)
name = "Atoms"
init_order = INIT_ORDER_ATOMS
@@ -43,11 +42,16 @@ SUBSYSTEM_DEF(atoms)
if(initialized == INITIALIZATION_INSSATOMS)
return
- set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, SUBSYSTEM_INIT_SOURCE)
+ // Generate a unique mapload source for this run of InitializeAtoms
+ var/static/uid = 0
+ uid = (uid + 1) % (SHORT_REAL_LIMIT - 1)
+ var/source = "subsystem init [uid]"
+ set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, source)
// This may look a bit odd, but if the actual atom creation runtimes for some reason, we absolutely need to set initialized BACK
- CreateAtoms(atoms, atoms_to_return)
- clear_tracked_initalize(SUBSYSTEM_INIT_SOURCE)
+ CreateAtoms(atoms, atoms_to_return, source)
+ clear_tracked_initalize(source)
+ SSicon_smooth.free_deferred(source)
if(late_loaders.len)
for(var/I in 1 to late_loaders.len)
@@ -68,12 +72,13 @@ SUBSYSTEM_DEF(atoms)
testing("[queued_deletions.len] atoms were queued for deletion.")
queued_deletions.Cut()
+
// #ifdef PROFILE_MAPLOAD_INIT_ATOM
// rustg_file_write(json_encode(mapload_init_times), "[GLOB.log_directory]/init_times.json")
// #endif
/// Actually creates the list of atoms. Exists soley so a runtime in the creation logic doesn't cause initalized to totally break
-/datum/controller/subsystem/atoms/proc/CreateAtoms(list/atoms, list/atoms_to_return = null)
+/datum/controller/subsystem/atoms/proc/CreateAtoms(list/atoms, list/atoms_to_return = null, mapload_source = null)
if (atoms_to_return)
LAZYINITLIST(created_atoms)
@@ -91,7 +96,12 @@ SUBSYSTEM_DEF(atoms)
for(var/I in 1 to atoms.len)
var/atom/A = atoms[I]
if(!(A.flags_1 & INITIALIZED_1))
- CHECK_TICK
+ // Unrolled CHECK_TICK setup to let us enable/disable mapload based off source
+ if(TICK_CHECK)
+ clear_tracked_initalize(mapload_source)
+ stoplag()
+ if(mapload_source)
+ set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, mapload_source)
PROFILE_INIT_ATOM_BEGIN()
InitAtom(A, TRUE, mapload_arg)
PROFILE_INIT_ATOM_END(A)
@@ -108,7 +118,11 @@ SUBSYSTEM_DEF(atoms)
#ifdef TESTING
++count
#endif
- CHECK_TICK
+ if(TICK_CHECK)
+ clear_tracked_initalize(mapload_source)
+ stoplag()
+ if(mapload_source)
+ set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, mapload_source)
testing("Initialized [count] atoms")
@@ -118,12 +132,18 @@ SUBSYSTEM_DEF(atoms)
/datum/controller/subsystem/atoms/proc/map_loader_stop(source)
clear_tracked_initalize(source)
+/// Returns the source currently modifying SSatom's init behavior
+/datum/controller/subsystem/atoms/proc/get_initialized_source()
+ var/state_length = length(initialized_state)
+ if(!state_length)
+ return null
+ return initialized_state[state_length][1]
+
/// Use this to set initialized to prevent error states where the old initialized is overriden, and we end up losing all context
/// Accepts a state and a source, the most recent state is used, sources exist to prevent overriding old values accidentially
/datum/controller/subsystem/atoms/proc/set_tracked_initalized(state, source)
if(!length(initialized_state))
base_initialized = initialized
-
initialized_state += list(list(source, state))
initialized = state
@@ -141,9 +161,9 @@ SUBSYSTEM_DEF(atoms)
return
initialized = initialized_state[length(initialized_state)][2]
-/// Returns TRUE if anything is currently being initialized or needing to be deleted
+/// Returns TRUE if anything is currently being initialized
/datum/controller/subsystem/atoms/proc/initializing_something()
- return length(initialized_state)
+ return length(initialized_state) > 1
/datum/controller/subsystem/atoms/Recover()
initialized = SSatoms.initialized
@@ -201,5 +221,3 @@ SUBSYSTEM_DEF(atoms)
var/initlog = InitLog()
if(initlog)
text2file(initlog, "[GLOB.log_directory]/initialize.log")
-
-#undef SUBSYSTEM_INIT_SOURCE
diff --git a/code/controllers/subsystem/icon_smooth.dm b/code/controllers/subsystem/icon_smooth.dm
index a0a33f0e17ac..9e5e9ffa99de 100644
--- a/code/controllers/subsystem/icon_smooth.dm
+++ b/code/controllers/subsystem/icon_smooth.dm
@@ -9,8 +9,7 @@ SUBSYSTEM_DEF(icon_smooth)
var/list/blueprint_queue = list()
var/list/smooth_queue = list()
var/list/deferred = list()
-
- var/map_loading = FALSE
+ var/list/deferred_by_source = list()
/datum/controller/subsystem/icon_smooth/fire()
// We do not want to smooth icons of atoms whose neighbors are not initialized yet,
@@ -63,16 +62,30 @@ SUBSYSTEM_DEF(icon_smooth)
return SS_INIT_SUCCESS
+/// Releases a pool of delayed smooth attempts from a particular source
+/datum/controller/subsystem/icon_smooth/proc/free_deferred(source_to_free)
+ smooth_queue += deferred_by_source[source_to_free]
+ deferred_by_source -= source_to_free
+ if(!can_fire)
+ can_fire = TRUE
/datum/controller/subsystem/icon_smooth/proc/add_to_queue(atom/thing)
if(thing.smoothing_flags & SMOOTH_QUEUED)
return
thing.smoothing_flags |= SMOOTH_QUEUED
+ // If we're currently locked into mapload BY something
+ // Then put us in a deferred list that we release when this mapload run is finished
+ if(initialized && length(SSatoms.initialized_state) && SSatoms.initialized == INITIALIZATION_INNEW_MAPLOAD)
+ var/source = SSatoms.get_initialized_source()
+ LAZYADD(deferred_by_source[source], thing)
+ return
smooth_queue += thing
if(!can_fire)
can_fire = TRUE
/datum/controller/subsystem/icon_smooth/proc/remove_from_queues(atom/thing)
+ // Lack of removal from deferred_by_source is safe because the lack of SMOOTH_QUEUED will just free it anyway
+ // Hopefully this'll never cause a harddel (dies)
thing.smoothing_flags &= ~SMOOTH_QUEUED
smooth_queue -= thing
if(blueprint_queue)
diff --git a/code/controllers/subsystem/init_profiler.dm b/code/controllers/subsystem/init_profiler.dm
new file mode 100644
index 000000000000..063898b6a098
--- /dev/null
+++ b/code/controllers/subsystem/init_profiler.dm
@@ -0,0 +1,28 @@
+#define INIT_PROFILE_NAME "init_profiler.json"
+
+///Subsystem exists so we can separately log init time costs from the costs of general operation
+///Hopefully this makes sorting out what causes problems when easier
+SUBSYSTEM_DEF(init_profiler)
+ name = "Init Profiler"
+ init_order = INIT_ORDER_INIT_PROFILER
+ init_stage = INITSTAGE_MAX
+ flags = SS_NO_FIRE
+
+/datum/controller/subsystem/init_profiler/Initialize()
+ if(CONFIG_GET(flag/auto_profile))
+ write_init_profile()
+ return SS_INIT_SUCCESS
+
+/datum/controller/subsystem/init_profiler/proc/write_init_profile()
+ var/current_profile_data = world.Profile(PROFILE_REFRESH, format = "json")
+ CHECK_TICK
+
+ if(!length(current_profile_data)) //Would be nice to have explicit proc to check this
+ stack_trace("Warning, profiling stopped manually before dump.")
+ var/prof_file = file("[GLOB.log_directory]/[INIT_PROFILE_NAME]")
+ if(fexists(prof_file))
+ fdel(prof_file)
+ WRITE_FILE(prof_file, current_profile_data)
+ world.Profile(PROFILE_CLEAR) //Now that we're written this data out, dump it. We don't want it getting mixed up with our current round data
+
+#undef INIT_PROFILE_NAME
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 8709e70f96eb..4fbc20fc21ae 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -617,9 +617,9 @@ SUBSYSTEM_DEF(job)
/datum/controller/subsystem/job/proc/irish_override()
var/datum/map_template/template = SSmapping.station_room_templates["Bar Irish"]
- for(var/obj/effect/landmark/stationroom/box/bar/B in GLOB.bar_landmarks)
+ for(var/obj/effect/landmark/stationroom/box/bar/B in GLOB.landmarks_list)
template.load(B.loc, centered = FALSE)
-
+ qdel(B)
/datum/controller/subsystem/job/proc/random_chapel_init()
try
@@ -664,9 +664,9 @@ SUBSYSTEM_DEF(job)
log_game("WARNING: CHAPEL RECOVERY FAILED! THERE WILL BE NO CHAPEL FOR THIS ROUND!")
return
- for(var/obj/effect/landmark/stationroom/box/chapel/B in GLOB.chapel_landmarks)
+ for(var/obj/effect/landmark/stationroom/box/chapel/B in GLOB.landmarks_list)
template.load(B.loc, centered = FALSE)
-
+ qdel(B)
catch(var/exception/e)
message_admins("RUNTIME IN RANDOM_CHAPEL_INIT")
spawn_chapel()
@@ -681,9 +681,9 @@ SUBSYSTEM_DEF(job)
if(isnull(template))
message_admins("UNABLE TO SPAWN CHAPEL")
- for(var/obj/effect/landmark/stationroom/box/chapel/B in GLOB.chapel_landmarks)
+ for(var/obj/effect/landmark/stationroom/box/chapel/B in GLOB.landmarks_list)
template.load(B.loc, centered = FALSE)
-
+ qdel(B)
/datum/controller/subsystem/job/proc/random_clerk_init()
try
@@ -728,9 +728,9 @@ SUBSYSTEM_DEF(job)
log_game("WARNING: CLERK RECOVERY FAILED! THERE WILL BE NO CLERK SHOP FOR THIS ROUND!")
return
- for(var/obj/effect/landmark/stationroom/box/clerk/B in GLOB.clerk_office_landmarks)
+ for(var/obj/effect/landmark/stationroom/box/clerk/B in GLOB.landmarks_list)
template.load(B.loc, centered = FALSE)
-
+ qdel(B)
catch(var/exception/e)
message_admins("RUNTIME IN RANDOM_CLERK_INIT")
spawn_clerk()
@@ -745,8 +745,9 @@ SUBSYSTEM_DEF(job)
if(isnull(template))
message_admins("UNABLE TO SPAWN CLERK")
- for(var/obj/effect/landmark/stationroom/box/clerk/B in GLOB.clerk_office_landmarks)
+ for(var/obj/effect/landmark/stationroom/box/clerk/B in GLOB.landmarks_list)
template.load(B.loc, centered = FALSE)
+ qdel(B)
/datum/controller/subsystem/job/proc/handle_auto_deadmin_roles(client/C, rank)
if(!C?.holder)
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index 667491c24048..156b929bae0b 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -1052,7 +1052,7 @@ SUBSYSTEM_DEF(shuttle)
else if(S)
. = TRUE
// If successful, returns the mobile docking port
- var/obj/docking_port/mobile/mdp = action_load(S)
+ var/obj/docking_port/mobile/mdp = action_load(S, replace = TRUE)
if(mdp)
user.forceMove(get_turf(mdp))
message_admins("[key_name_admin(usr)] loaded [mdp] with the shuttle manipulator.")
diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm
index 95d590a0fded..d615bc28798b 100644
--- a/code/controllers/subsystem/timer.dm
+++ b/code/controllers/subsystem/timer.dm
@@ -4,8 +4,6 @@
#define BUCKET_POS(timer) (((ROUND_UP((timer.timeToRun - timer.timer_subsystem.head_offset) / world.tick_lag)+1) % BUCKET_LEN) || BUCKET_LEN)
/// Gets the maximum time at which timers will be invoked from buckets, used for deferring to secondary queue
#define TIMER_MAX(timer_ss) (timer_ss.head_offset + TICKS2DS(BUCKET_LEN + timer_ss.practical_offset - 1))
-/// Max float with integer precision
-#define TIMER_ID_MAX (2**24)
/**
* # Timer Subsystem
@@ -740,4 +738,3 @@ SUBSYSTEM_DEF(timer)
#undef BUCKET_LEN
#undef BUCKET_POS
#undef TIMER_MAX
-#undef TIMER_ID_MAX
diff --git a/code/datums/components/bloodysoles.dm b/code/datums/components/bloodysoles.dm
index 03afc96182dc..d05043312d7f 100644
--- a/code/datums/components/bloodysoles.dm
+++ b/code/datums/components/bloodysoles.dm
@@ -234,7 +234,7 @@ Like its parent but can be applied to carbon mobs instead of clothing items
. = list()
if(ishuman(wielder))// Monkeys get no bloody feet :(
if(HAS_BLOOD_DNA(wielder))
- bloody_feet.color = bloody_feet.color = get_blood_dna_color(wielder.return_blood_DNA())
+ bloody_feet.color = get_blood_dna_color(wielder.return_blood_DNA())
. += bloody_feet
if(bloody_shoes[BLOOD_STATE_HUMAN] > 0 && !is_obscured())
wielder.remove_overlay(SHOES_LAYER)
diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm
index 03f1e4f2d452..b996ab73d182 100644
--- a/code/datums/components/squeak.dm
+++ b/code/datums/components/squeak.dm
@@ -13,13 +13,18 @@
var/last_use = 0
var/use_delay = 20
+ ///what we set connect_loc to if parent is an item
+ var/static/list/item_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(play_squeak_crossed),
+ )
+
/datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignals(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY), PROC_REF(play_squeak))
if(ismovable(parent))
RegisterSignals(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT, COMSIG_PROJECTILE_BEFORE_FIRE), PROC_REF(play_squeak))
- RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, PROC_REF(play_squeak_crossed))
+ AddComponent(/datum/component/connect_loc_behalf, parent, item_connections)
RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, PROC_REF(disposing_react))
if(isitem(parent))
RegisterSignals(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_HIT_REACT), PROC_REF(play_squeak))
@@ -41,6 +46,10 @@
if(isnum(use_delay_override))
use_delay = use_delay_override
+/datum/component/squeak/UnregisterFromParent()
+ . = ..()
+ qdel(GetComponent(/datum/component/connect_loc_behalf))
+
/datum/component/squeak/proc/play_squeak()
if(prob(squeak_chance))
if(!override_squeak_sounds)
diff --git a/code/datums/components/squishable.dm b/code/datums/components/squishable.dm
new file mode 100644
index 000000000000..b3aba6d076ce
--- /dev/null
+++ b/code/datums/components/squishable.dm
@@ -0,0 +1,81 @@
+///This component allows something to be when crossed, for example for cockroaches.
+/datum/component/squashable
+ ///Chance on crossed to be squashed
+ var/squash_chance = 50
+ ///How much brute is applied when mob is squashed
+ var/squash_damage = 1
+ ///Squash flags, for extra checks etcetera.
+ var/squash_flags = NONE
+ ///Special callback to call on squash instead, for things like hauberoach
+ var/datum/callback/on_squash_callback
+ ///signal list given to connect_loc
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
+ )
+
+
+/datum/component/squashable/Initialize(squash_chance, squash_damage, squash_flags, squash_callback)
+ . = ..()
+ if(!isliving(parent))
+ return COMPONENT_INCOMPATIBLE
+ if(squash_chance)
+ src.squash_chance = squash_chance
+ if(squash_damage)
+ src.squash_damage = squash_damage
+ if(squash_flags)
+ src.squash_flags = squash_flags
+ if(!src.on_squash_callback && squash_callback)
+ on_squash_callback = CALLBACK(parent, squash_callback)
+
+ AddComponent(/datum/component/connect_loc_behalf, parent, loc_connections)
+
+/datum/component/squashable/Destroy(force)
+ on_squash_callback = null
+ return ..()
+
+///Handles the squashing of the mob
+/datum/component/squashable/proc/on_entered(turf/source_turf, atom/movable/crossing_movable)
+ // SIGNAL_HANDLER -- dont uncomment this
+
+ if(parent == crossing_movable)
+ return
+
+ var/mob/living/parent_as_living = parent
+ if((squash_flags & SQUASHED_DONT_SQUASH_IN_CONTENTS) && !isturf(parent_as_living.loc))
+ return
+
+ if((squash_flags & SQUASHED_SHOULD_BE_DOWN) && parent_as_living.body_position != LYING_DOWN)
+ return
+
+ var/should_squash = ((squash_flags & SQUASHED_ALWAYS_IF_DEAD) && parent_as_living.stat == DEAD) || prob(squash_chance)
+
+ if(should_squash && on_squash_callback)
+ if(on_squash_callback.Invoke(parent_as_living, crossing_movable))
+ return //Everything worked, we're done!
+ if(isliving(crossing_movable))
+ var/mob/living/crossing_mob = crossing_movable
+ if(crossing_mob.mob_size > MOB_SIZE_SMALL && !(crossing_mob.movement_type & MOVETYPES_NOT_TOUCHING_GROUND))
+ if(HAS_TRAIT(crossing_mob, TRAIT_PACIFISM))
+ crossing_mob.visible_message(span_notice("[crossing_mob] carefully steps over [parent_as_living]."), span_notice("You carefully step over [parent_as_living] to avoid hurting it."))
+ return
+ if(should_squash)
+ crossing_mob.visible_message(span_notice("[crossing_mob] squashed [parent_as_living]."), span_notice("You squashed [parent_as_living]."))
+ Squish(parent_as_living)
+ else
+ parent_as_living.visible_message(span_notice("[parent_as_living] avoids getting crushed."))
+ else if(isstructure(crossing_movable))
+ if(should_squash)
+ crossing_movable.visible_message(span_notice("[parent_as_living] is crushed under [crossing_movable]."))
+ Squish(parent_as_living)
+ else
+ parent_as_living.visible_message(span_notice("[parent_as_living] avoids getting crushed."))
+
+/datum/component/squashable/proc/Squish(mob/living/target)
+ if(squash_flags & SQUASHED_SHOULD_BE_GIBBED)
+ target.gib(DROP_ALL_REMAINS)
+ else
+ target.adjustBruteLoss(squash_damage)
+
+/datum/component/squashable/UnregisterFromParent()
+ . = ..()
+ qdel(GetComponent(/datum/component/connect_loc_behalf))
diff --git a/code/datums/elements/decals/blood.dm b/code/datums/elements/decals/blood.dm
index cdaec2c089da..f496f76adf1e 100644
--- a/code/datums/elements/decals/blood.dm
+++ b/code/datums/elements/decals/blood.dm
@@ -13,10 +13,6 @@
/datum/element/decal/blood/generate_appearance(_icon, _icon_state, _dir, _plane, _layer, _color, _alpha, _smoothing, source)
var/obj/item/I = source
- if(!_icon)
- _icon = 'icons/effects/blood.dmi'
- if(!_icon_state)
- _icon_state = "itemblood"
if(!_color)
_color = COLOR_BLOOD
var/icon = I.icon
@@ -25,19 +21,14 @@
// It's something which takes on the look of other items, probably
icon = I.icon
icon_state = I.icon_state
- var/static/list/blood_splatter_appearances = list()
- //try to find a pre-processed blood-splatter. otherwise, make a new one
- var/index = "[REF(icon)]-[icon_state]"
- pic = blood_splatter_appearances[index]
-
- if(!pic)
- var/icon/blood_splatter_icon = icon(I.icon, I.icon_state, , 1) //icon of the item that will become splattered
- var/icon/blood_icon = icon(_icon, _icon_state) //icon of the blood that we apply
- blood_icon.Scale(blood_splatter_icon.Width(), blood_splatter_icon.Height())
- blood_splatter_icon.Blend(_color, ICON_ADD) //fills the icon_state with white (except where it's transparent)
- blood_splatter_icon.Blend(blood_icon, ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
- pic = mutable_appearance(blood_splatter_icon, I.icon_state)
- blood_splatter_appearances[index] = pic
+ var/icon/icon_for_size = icon(icon, icon_state)
+ var/scale_factor_x = icon_for_size.Width()/world.icon_size
+ var/scale_factor_y = icon_for_size.Height()/world.icon_size
+ var/mutable_appearance/blood_splatter = mutable_appearance('icons/effects/blood.dmi', "itemblood", appearance_flags = RESET_COLOR) //MA of the blood that we apply
+ blood_splatter.transform = blood_splatter.transform.Scale(scale_factor_x, scale_factor_y)
+ blood_splatter.blend_mode = BLEND_INSET_OVERLAY
+ blood_splatter.color = _color
+ pic = blood_splatter
return TRUE
/datum/element/decal/blood/proc/get_examine_name(datum/source, mob/user, list/override)
diff --git a/code/datums/martial/reverbpalm.dm b/code/datums/martial/reverbpalm.dm
index d92317aa06bf..36234dda2be8 100644
--- a/code/datums/martial/reverbpalm.dm
+++ b/code/datums/martial/reverbpalm.dm
@@ -48,9 +48,7 @@
//animation procs
//knocking them down
-/datum/martial_art/reverberating_palm/proc/footsies(mob/living/target, var/suplex = FALSE)
- if(suplex)
- animate(target, transform = matrix(180, MATRIX_ROTATE), time = 0 SECONDS, loop = 0)
+/datum/martial_art/reverberating_palm/proc/footsies(mob/living/target)
if(target.mobility_flags & MOBILITY_STAND)
animate(target, transform = matrix(90, MATRIX_ROTATE), time = 0 SECONDS, loop = 0)
return
@@ -103,14 +101,14 @@
return
COOLDOWN_START(src, next_palm, COOLDOWN_RPALM)
var/obj/item/melee/overcharged_emitter/B = new()
- user.visible_message(span_userdanger("[user]'s left arm begins crackling loudly!"))
+ user.visible_message(span_userdanger("[user]'s right arm begins crackling loudly!"))
playsound(user,'sound/effects/beepskyspinsabre.ogg', 60, 1)
if(do_after(user, 2 SECONDS, user, timed_action_flags = IGNORE_USER_LOC_CHANGE))
- if(!user.put_in_l_hand(B))
- to_chat(user, span_warning("You can't do this with your left hand full!"))
+ if(!user.put_in_r_hand(B))
+ to_chat(user, span_warning("You can't do this with your right hand full!"))
else
user.visible_message(span_danger("[user]'s arm begins shaking violently!"))
- if(user.active_hand_index % 2 == 0)
+ if(user.active_hand_index % 2 == 1)
user.swap_hand(0)
//do cooldown
@@ -137,7 +135,7 @@
to_chat(user, span_warning("You can't do that yet!"))
return
COOLDOWN_START(src, next_suplex, COOLDOWN_SUPLEX)
- footsies(target, TRUE)
+ footsies(target)
var/turf/Q = get_step(get_turf(user), turn(user.dir,180))
user.visible_message(span_warning("[user] outstretches [user.p_their()] arm and goes for a grab!"))
wakeup(target)
@@ -150,7 +148,6 @@
if(target.stat == DEAD)
target.visible_message(span_warning("[target] crashes and explodes!"))
target.gib()
- wakeup(target)
to_chat(user, span_warning("[user] suplexes [target] against [Q]!"))
to_chat(target, span_userdanger("[user] crushes you against [Q]!"))
playsound(target, 'sound/effects/meteorimpact.ogg', 60, 1)
diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm
index 906c17af66f9..29e700df8eb5 100644
--- a/code/datums/materials/_material.dm
+++ b/code/datums/materials/_material.dm
@@ -7,7 +7,7 @@ Simple datum which is instanced once per type and is used for every object of sa
/datum/material
var/name = "material"
- var/desc = "its..stuff."
+ var/desc = "It's...stuff." // I'm stuff :stuff:
///Var that's mostly used by science machines to identify specific materials, should most likely be phased out at some point
var/id = "mat"
///Base color of the material, is used for greyscale. Item isn't changed in color if this is null.
diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm
index 3012fc6d533a..1cc3eb6763f8 100644
--- a/code/datums/materials/basemats.dm
+++ b/code/datums/materials/basemats.dm
@@ -2,7 +2,7 @@
/datum/material/iron
name = "iron"
id = "iron"
- desc = "Common iron ore often found in sedimentary and igneous layers of the crust."
+ desc = "A common iron ore often found in sedimentary and igneous layers of the crust."
color = "#878687"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
sheet_type = /obj/item/stack/sheet/metal
@@ -24,7 +24,7 @@
/datum/material/silver
name = "silver"
id = "silver"
- desc = "Silver"
+ desc = "Silver."
color = "#bdbebf"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/silver
@@ -34,7 +34,7 @@
/datum/material/gold
name = "gold"
id = "gold"
- desc = "Gold"
+ desc = "Gold. You're rich."
color = "#f0972b"
strength_modifier = 1.2
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
@@ -45,7 +45,7 @@
/datum/material/diamond
name = "diamond"
id = "diamond"
- desc = "Highly pressurized carbon"
+ desc = "Highly pressurized carbon."
color = "#22c2d4"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/diamond
@@ -55,7 +55,7 @@
/datum/material/uranium
name = "uranium"
id = "uranium"
- desc = "Uranium"
+ desc = "Uranium, known for its radioactive properties."
color = "#1fb83b"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/uranium
@@ -95,7 +95,7 @@
/datum/material/bluespace
name = "bluespace crystal"
id = "bluespace_crystal"
- desc = "Crystals with bluespace properties"
+ desc = "Rare crystals with bluespace properties."
color = "#506bc7"
categories = list(MAT_CATEGORY_ORE = TRUE)
sheet_type = /obj/item/stack/sheet/bluespace_crystal
@@ -104,7 +104,7 @@
/datum/material/bananium
name = "bananium"
id = "bananium"
- desc = "Material with hilarious properties"
+ desc = "A very rare material with hilarious properties."
color = "#fff263"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/bananium
@@ -125,7 +125,7 @@
/datum/material/titanium
name = "titanium"
id = "titanium"
- desc = "Titanium"
+ desc = "Titanium."
color = "#b3c0c7"
strength_modifier = 1.3
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
@@ -135,7 +135,7 @@
/datum/material/plastic
name = "plastic"
id = "plastic"
- desc = "plastic"
+ desc = "Plastic."
color = "#caccd9"
strength_modifier = 0.85
sheet_type = /obj/item/stack/sheet/plastic
@@ -151,7 +151,7 @@
//formed when freon react with o2, emits a lot of plasma when heated
/datum/material/hot_ice
name = "hot ice"
- desc = "A weird kind of ice, feels warm to the touch"
+ desc = "A weird kind of ice, feels warm to the touch."
color = "#88cdf1"
alpha = 150
categories = list(MAT_CATEGORY_RIGID = TRUE)
@@ -176,7 +176,7 @@
/datum/material/metalhydrogen
name = "Metal Hydrogen"
- desc = "Solid metallic hydrogen. Some say it should be impossible"
+ desc = "Solid metallic hydrogen. Some say it should be impossible."
color = "#f2d5d7"
alpha = 240
categories = list(MAT_CATEGORY_RIGID = TRUE)
@@ -185,7 +185,7 @@
/datum/material/zaukerite
name = "zaukerite"
- desc = "A light absorbing crystal"
+ desc = "A light-absorbing crystal."
color = COLOR_ALMOST_BLACK
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/zaukerite
@@ -201,7 +201,7 @@
/datum/material/dilithium
name = "dilithium crystal"
id = "dilithium_crystal"
- desc = "Crystals with dilithium properties"
+ desc = "Crystals with dilithium properties."
color = "#506bc7"
categories = list(MAT_CATEGORY_ORE = TRUE)
sheet_type = /obj/item/stack/sheet/dilithium_crystal
diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm
index d19b16310078..5c23c96e2fd1 100644
--- a/code/datums/ruins/space.dm
+++ b/code/datums/ruins/space.dm
@@ -103,7 +103,7 @@
id = "empty-shell"
suffix = "emptyshell.dmm"
name = "Empty Shell"
- description = "Cosy, rural property available for young professional couple. Only twelve parsecs from the nearest hyperspace lane!"
+ description = "Cosy, rural property available for young professional couple. Only twelve parsecs from the nearest gigabeacon!"
/datum/map_template/ruin/space/gas_the_lizards
id = "gas-the-lizards"
diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm
index ffeb5067fe8b..6089eb84b98a 100644
--- a/code/datums/status_effects/debuffs/debuffs.dm
+++ b/code/datums/status_effects/debuffs/debuffs.dm
@@ -1301,6 +1301,45 @@
for(var/i in S.damage_coeff)
S.damage_coeff[i] /= power
+/datum/status_effect/exposed/harpooned
+ id = "harpooned"
+ duration = 2 SECONDS
+ ///damage multiplier
+ power = 1.3
+
+/datum/status_effect/exposed/harpooned/on_apply()
+ . = ..()
+ if(.)
+ owner.add_filter("exposed", 2, list("type" = "outline", "color" = COLOR_RED, "size" = 1))
+
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.brute_mod *= power
+ H.physiology.burn_mod *= power
+ H.physiology.tox_mod *= power
+ H.physiology.oxy_mod *= power
+ H.physiology.clone_mod *= power
+ H.physiology.stamina_mod *= power
+ else if(isanimal(owner))
+ var/mob/living/simple_animal/S = owner
+ for(var/i in S.damage_coeff)
+ S.damage_coeff[i] *= power
+
+/datum/status_effect/exposed/harpooned/on_remove()
+ owner.remove_filter("exposed")
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.brute_mod /= power
+ H.physiology.burn_mod /= power
+ H.physiology.tox_mod /= power
+ H.physiology.oxy_mod /= power
+ H.physiology.clone_mod /= power
+ H.physiology.stamina_mod /= power
+ else if(isanimal(owner))
+ var/mob/living/simple_animal/S = owner
+ for(var/i in S.damage_coeff)
+ S.damage_coeff[i] /= power
+
/datum/status_effect/knuckled
id = "knuckle_wound"
duration = 10 SECONDS
diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm
index 494468db88ba..37c511734e47 100644
--- a/code/game/area/areas/shuttles.dm
+++ b/code/game/area/areas/shuttles.dm
@@ -99,7 +99,7 @@
////////////////////////////Single-area shuttles////////////////////////////
/area/shuttle/transit
- name = "Hyperspace"
+ name = "Bluespace"
desc = "Weeeeee"
static_lighting = FALSE
base_lighting_alpha = 255
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index cba4d4a5a013..56f4083ced98 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -927,6 +927,9 @@
if(throwing)
return TRUE
+ if(SEND_SIGNAL(src, COMSIG_MOVABLE_SPACEMOVE, movement_dir) & COMSIG_MOVABLE_ALLOW_SPACEMOVE)
+ return TRUE
+
if(!isturf(loc))
return TRUE
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index f3d3ba070582..3589e558963f 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -165,14 +165,17 @@ Medical HUD! Basic mode needs suit sensors on.
holder.pixel_y = I.Height() - world.icon_size
if(HAS_TRAIT(src, TRAIT_XENO_HOST))
holder.icon_state = "hudxeno"
+ if(undergoing_cardiac_arrest() && stat != DEAD) //dripstation edit
+ holder.icon_state = "huddefib" //dripstation edit
+ return //dripstation edit
else if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
if(HAS_TRAIT(src, TRAIT_FAKEDEATH))
- holder.icon_state = "huddefib"
+ holder.icon_state = "hudflatline" //dripstation edit
return
if(tod)
var/tdelta = round(world.time - timeofdeath)
if(tdelta < (DEFIB_TIME_LIMIT))
- holder.icon_state = "huddefib"
+ holder.icon_state = "hudflatline" //dripstation edit
return
holder.icon_state = "huddead"
else
diff --git a/code/game/gamemodes/brother/traitor_bro.dm b/code/game/gamemodes/brother/traitor_bro.dm
index fc7417dd8e6a..beaacb372fe5 100644
--- a/code/game/gamemodes/brother/traitor_bro.dm
+++ b/code/game/gamemodes/brother/traitor_bro.dm
@@ -6,9 +6,10 @@
name = "traitor+brothers"
config_tag = "traitorbro"
restricted_jobs = list("AI", "Cyborg")
- required_players = 8 //yogs - just a minor change
+ required_players = 20 //yogs - just a minor change
title_icon = "ss13"
+
announce_span = "danger"
announce_text = "There are Syndicate agents and Blood Brothers on the station!\n\
Traitors: Accomplish your objectives.\n\
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index 38d9de8ed8dd..32ad3e2bb3a0 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -81,7 +81,7 @@ GLOBAL_VAR(changeling_team_objective_type)
false_report_weight = 10
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Brig Physician") //YOGS - added hop and brig physician
- required_players = 25
+ required_players = 20
required_enemies = 2
recommended_enemies = 4
reroll_friendly = 1
diff --git a/code/game/gamemodes/changeling/traitor_chan.dm b/code/game/gamemodes/changeling/traitor_chan.dm
index cb1c5b13c84f..f3e16fe471c6 100644
--- a/code/game/gamemodes/changeling/traitor_chan.dm
+++ b/code/game/gamemodes/changeling/traitor_chan.dm
@@ -5,7 +5,7 @@
false_report_weight = 10
traitors_possible = 3 //hard limit on traitors if scaling is turned off
restricted_jobs = list("AI", "Cyborg")
- required_players = 25
+ required_players = 20
required_enemies = 1 // how many of each type are required
recommended_enemies = 3
reroll_friendly = 1
diff --git a/code/game/gamemodes/clown_ops/clown_weapons.dm b/code/game/gamemodes/clown_ops/clown_weapons.dm
index 3c1c015922eb..a7dfa85ac74e 100644
--- a/code/game/gamemodes/clown_ops/clown_weapons.dm
+++ b/code/game/gamemodes/clown_ops/clown_weapons.dm
@@ -14,7 +14,7 @@
//Clown shoes with combat stats and noslip. Of course they still squeak.
/obj/item/clothing/shoes/clown_shoes/combat
name = "combat clown shoes"
- desc = "advanced clown shoes that protect the wearer and render them nearly immune to slipping on their own peels. They also squeak at 100% capacity."
+ desc = "A pair of advanced clown shoes that protect the wearer and render them nearly immune to slipping on their own peels. They also squeak at 100% capacity."
clothing_flags = NOSLIP
slowdown = SHOES_SLOWDOWN
armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 60, RAD = 0, FIRE = 70, ACID = 50)
@@ -286,16 +286,7 @@
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/honker/dark
- max_equip = 3
-
-/obj/mecha/combat/honker/dark/GrantActions(mob/living/user, human_occupant = 0)
- ..()
- thrusters_action.Grant(user, src)
-
-
-/obj/mecha/combat/honker/dark/RemoveActions(mob/living/user, human_occupant = 0)
- ..()
- thrusters_action.Remove(user)
+ max_equip = 4
/obj/mecha/combat/honker/dark/add_cell(obj/item/stock_parts/cell/C)
if(C)
@@ -312,6 +303,8 @@
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/tearstache()//The mousetrap mortar was not up-to-snuff.
ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion()
+ ME.attach(src)
/obj/mecha/combat/honker/dark/crew
operation_req_access = list()
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index 00530fe4d1e5..645d1708fd3d 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -41,7 +41,7 @@
false_report_weight = 10
restricted_jobs = list("Chaplain","AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Brig Physician") //Yogs: Added Brig Physician
protected_jobs = list()
- required_players = 29
+ required_players = 24
required_enemies = 4
recommended_enemies = 4
enemy_minimum_age = 14
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index 7c9fa59fd698..e83d8dbd2f50 100644
--- a/code/game/gamemodes/meteor/meteors.dm
+++ b/code/game/gamemodes/meteor/meteors.dm
@@ -88,19 +88,33 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
icon_state = "small"
density = TRUE
anchored = TRUE
- var/hits = 4
- var/hitpwr = 2 //Level of ex_act to be called on hit.
- var/dest
pass_flags = PASSTABLE
- var/heavy = 0
+
+ ///The resilience of our meteor
+ var/hits = 4
+ ///Level of ex_act to be called on hit.
+ var/hitpwr = EXPLODE_HEAVY
+ //Should we shake people's screens on impact
+ var/heavy = FALSE
+ ///Sound to play when you hit something
var/meteorsound = 'sound/effects/meteorimpact.ogg'
+ ///Our starting z level, prevents infinite meteors
var/z_original
- var/threat = 0 // used for determining which meteors are most interesting
- var/lifetime = DEFAULT_METEOR_LIFETIME
- var/timerid = null
+ ///Used for determining which meteors are most interesting
+ var/threat = 0
+
+ //Potential items to spawn when you die
var/list/meteordrop = list(/obj/item/stack/ore/iron)
+ ///How much stuff to spawn when you die
var/dropamt = 2
+ ///The thing we're moving towards, usually a turf
+ var/atom/dest
+ ///Lifetime in seconds
+ var/lifetime = DEFAULT_METEOR_LIFETIME
+
+ var/timerid = null
+
/obj/effect/meteor/Move()
if(z != z_original || loc == dest)
qdel(src)
@@ -134,6 +148,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
SpinAnimation()
timerid = QDEL_IN(src, lifetime)
chase_target(target)
+ update_appearance()
/obj/effect/meteor/Bump(atom/A)
if(A)
diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm
index bff987ecc363..fa74510a48aa 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -19,7 +19,7 @@
false_report_weight = 10
restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg", "Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer", "Shaft Miner", "Mining Medic", "Brig Physician") //Yogs: Added Brig Physician
required_jobs = list(list("Captain"=1),list("Head of Personnel"=1),list("Head of Security"=1),list("Chief Engineer"=1),list("Research Director"=1),list("Chief Medical Officer"=1)) //Any head present
- required_players = 30
+ required_players = 25
required_enemies = 2
recommended_enemies = 3
enemy_minimum_age = 14
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 1cf5d4dc2ab6..6086a909e646 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -57,7 +57,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list(
/obj/machinery/computer/arcade
name = "random arcade"
- desc = "random arcade machine"
+ desc = "A random arcade machine."
icon_state = "arcade"
icon_keyboard = null
icon_screen = "invaders"
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 4b17d6bd8892..a0248f48490b 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -1306,10 +1306,9 @@
return
INVOKE_ASYNC(src, (density ? PROC_REF(open) : PROC_REF(close)), 2)
- if(istype(I, /obj/item/jawsoflife) || istype(I, /obj/item/mantis/blade))
- if(isElectrified())
- if(shock(user,100))//it's like sticking a fork in a power socket
- return
+ if(istype(I, /obj/item/jawsoflife) || istype(I, /obj/item/mantis/blade) || istype(I, /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp))
+ if(isElectrified() && shock(user,100))//it's like sticking a fork in a power socket
+ return
if(istype(I, /obj/item/mantis/blade))
var/obj/item/mantis/blade/secondsword = user.get_inactive_held_item()
@@ -1662,7 +1661,7 @@
qdel(src)
/obj/machinery/door/airlock/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_DECONSTRUCT)
if(security_level != AIRLOCK_SECURITY_NONE)
to_chat(user, span_notice("[src]'s reinforcement needs to be removed first."))
diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm
index 7bf3fefe4449..679557a011e8 100644
--- a/code/game/machinery/doors/airlock_electronics.dm
+++ b/code/game/machinery/doors/airlock_electronics.dm
@@ -3,9 +3,14 @@
req_access = list(ACCESS_MAINT_TUNNELS)
custom_price = 5
+ /// A list of all granded accesses
var/list/accesses = list()
+ /// If the airlock should require ALL or only ONE of the listed accesses
var/one_access = 0
- var/unres_sides = 0 //unrestricted sides, or sides of the airlock that will open regardless of access
+ /// Unrestricted sides, or sides of the airlock that will open regardless of access
+ var/unres_sides = 0
+ /// A holder of the electronics, in case of them working as an integrated part
+ var/holder
/obj/item/electronics/airlock/examine(mob/user)
. = ..()
@@ -49,40 +54,45 @@
return data
-/obj/item/electronics/airlock/ui_act(action, params)
- if(..())
- return
+/// Shared by RCD and airlock electronics
+/obj/item/electronics/airlock/proc/do_action(action, params)
switch(action)
if("clear_all")
accesses = list()
one_access = 0
- . = TRUE
if("grant_all")
accesses = get_all_accesses()
- . = TRUE
if("one_access")
one_access = !one_access
- . = TRUE
if("set")
var/access = text2num(params["access"])
if (!(access in accesses))
accesses += access
else
accesses -= access
- . = TRUE
if("direc_set")
var/unres_direction = text2num(params["unres_direction"])
unres_sides ^= unres_direction //XOR, toggles only the bit that was clicked
- . = TRUE
if("grant_region")
var/region = text2num(params["region"])
if(isnull(region))
return
accesses |= get_region_accesses(region)
- . = TRUE
if("deny_region")
var/region = text2num(params["region"])
if(isnull(region))
return
accesses -= get_region_accesses(region)
- . = TRUE
+
+/obj/item/electronics/airlock/ui_act(action, params)
+ . = ..()
+ if(.)
+ return
+
+ do_action(action, params)
+ return TRUE
+
+/obj/item/electronics/airlock/ui_host()
+ if(holder)
+ return holder
+ return src
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 19df2d845817..c21f917ef52e 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -506,7 +506,7 @@
icon_state = "frame[constructionStep]"
/obj/structure/firelock_frame/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- if(the_rcd.mode == RCD_DECONSTRUCT)
+ if(the_rcd.construction_mode == RCD_DECONSTRUCT)
return list("mode" = RCD_DECONSTRUCT, "delay" = 50, "cost" = 16)
return FALSE
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 0b3471c5fe86..78d3195f7284 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -393,7 +393,7 @@
INVOKE_ASYNC(src, PROC_REF(open_and_close))
/obj/machinery/door/window/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_DECONSTRUCT)
return list("mode" = RCD_DECONSTRUCT, "delay" = 50, "cost" = 32)
return FALSE
diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm
index 6c11dc1e5e3b..13dbfdbb3c20 100644
--- a/code/game/mecha/combat/gygax.dm
+++ b/code/game/mecha/combat/gygax.dm
@@ -25,7 +25,7 @@
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/gygax/dark
- max_equip = 6
+ max_equip = 7
destruction_sleep_duration = 20
/obj/mecha/combat/gygax/dark/loaded/Initialize(mapload)
@@ -42,6 +42,8 @@
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/emergency_eject
ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion
+ ME.attach(src)
max_ammo()
/obj/mecha/combat/gygax/dark/add_cell(obj/item/stock_parts/cell/C=null)
@@ -56,16 +58,6 @@
..()
overload_action.Grant(user, src)
-/obj/mecha/combat/gygax/dark/GrantActions(mob/living/user, human_occupant = 0)
- ..()
- thrusters_action.Grant(user, src)
-
-
/obj/mecha/combat/gygax/RemoveActions(mob/living/user, human_occupant = 0)
..()
overload_action.Remove(user)
-
-/obj/mecha/combat/gygax/dark/RemoveActions(mob/living/user, human_occupant = 0)
- ..()
- thrusters_action.Remove(user)
-
diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm
index cedcdc143603..5ce4c06b372e 100644
--- a/code/game/mecha/combat/marauder.dm
+++ b/code/game/mecha/combat/marauder.dm
@@ -15,19 +15,17 @@
add_req_access = 0
internal_damage_threshold = 25
force = 40
- max_equip = 4
+ max_equip = 5
bumpsmash = 1
/obj/mecha/combat/marauder/GrantActions(mob/living/user, human_occupant = 0)
..()
smoke_action.Grant(user, src)
- thrusters_action.Grant(user, src)
zoom_action.Grant(user, src)
/obj/mecha/combat/marauder/RemoveActions(mob/living/user, human_occupant = 0)
..()
smoke_action.Remove(user)
- thrusters_action.Remove(user)
zoom_action.Remove(user)
/obj/mecha/combat/marauder/loaded/Initialize(mapload)
@@ -40,6 +38,8 @@
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src)
ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
+ ME.attach(src)
max_ammo()
/obj/mecha/combat/marauder/seraph
@@ -53,7 +53,7 @@
wreckage = /obj/structure/mecha_wreckage/seraph
internal_damage_threshold = 20
force = 50
- max_equip = 5
+ max_equip = 6
/obj/mecha/combat/marauder/seraph/unloaded
@@ -71,6 +71,8 @@
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src)
ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
+ ME.attach(src)
max_ammo()
/obj/mecha/combat/marauder/mauler
@@ -80,7 +82,7 @@
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/mauler
- max_equip = 7
+ max_equip = 8
destruction_sleep_duration = 20
ejection_distance = 8
@@ -100,6 +102,8 @@
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/emergency_eject(src) // YEET
ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/thrusters/ion(src)
+ ME.attach(src)
max_ammo()
diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm
index 8bbdd4ce7015..72d643b50805 100644
--- a/code/game/mecha/equipment/mecha_equipment.dm
+++ b/code/game/mecha/equipment/mecha_equipment.dm
@@ -7,6 +7,8 @@
icon_state = "mecha_equip"
force = 5
max_integrity = 300
+ /// Prevents hitting stuff when trying to use certain equipment as tools
+ item_flags = NOBLUDGEON
/// Cooldown after use
var/equip_cooldown = 0
/// is the module ready for use
@@ -27,8 +29,21 @@
var/destroy_sound = 'sound/mecha/critdestr.ogg'
/// Bitflag. Used by exosuit fabricator to assign sub-categories based on which exosuits can equip this.
var/mech_flags = NONE
- //Special melee override for melee weapons
+ /// Special melee override for melee weapons
var/melee_override = FALSE
+ /// Actions granted by this equipment
+ var/list/equip_actions = list()
+
+/obj/item/mecha_parts/mecha_equipment/Initialize(mapload)
+ . = ..()
+ var/list/action_type_list = equip_actions.Copy()
+ equip_actions = list()
+ for(var/path in action_type_list)
+ var/datum/action/innate/mecha/equipment/action = new path
+ action.equipment = src
+ equip_actions.Add(action)
+ qdel(action_type_list)
+
/obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page()
if(chassis)
send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list())
@@ -55,6 +70,8 @@
chassis.occupant_message(span_danger("[src] is destroyed!"))
chassis.occupant.playsound_local(chassis, destroy_sound, 50)
chassis = null
+ for(var/datum/action/innate/mecha/equipment/E in equip_actions)
+ E.Destroy()
return ..()
/obj/item/mecha_parts/mecha_equipment/try_attach_part(mob/user, obj/mecha/M)
@@ -103,7 +120,7 @@
return 0
return 1
-/obj/item/mecha_parts/mecha_equipment/proc/action(atom/target)
+/obj/item/mecha_parts/mecha_equipment/proc/action(atom/target, mob/living/user, params)
return 0
/obj/item/mecha_parts/mecha_equipment/proc/start_cooldown()
@@ -140,9 +157,21 @@
forceMove(M)
log_message("[src] initialized.", LOG_MECHA)
update_chassis_page()
+ ADD_TRAIT(src, TRAIT_NODROP, "mecha")
+ item_flags |= NO_MAT_REDEMPTION // terrible
+ for(var/datum/action/innate/mecha/equipment/action as anything in equip_actions)
+ action.chassis = M
+ if(chassis.occupant)
+ grant_actions(chassis.occupant)
return
/obj/item/mecha_parts/mecha_equipment/proc/detach(atom/moveto=null)
+ if(chassis.occupant)
+ remove_actions(chassis.occupant)
+ for(var/datum/action/innate/mecha/equipment/action as anything in equip_actions)
+ action.chassis = null
+ item_flags &= ~NO_MAT_REDEMPTION
+ REMOVE_TRAIT(src, TRAIT_NODROP, "mecha")
if(chassis.selected == src)
src.on_deselect()
moveto = moveto || get_turf(chassis)
@@ -198,3 +227,16 @@
/obj/item/mecha_parts/mecha_equipment/proc/check_eva()
return chassis?.check_eva()
+// Some equipment can be used as tools
+/obj/item/mecha_parts/mecha_equipment/tool_use_check(mob/living/user, amount)
+ return (chassis ? (chassis.cell.charge >= energy_drain) : FALSE) // but not if they aren't attached to a mech
+
+// Grant any actions to the pilot
+/obj/item/mecha_parts/mecha_equipment/proc/grant_actions(mob/pilot)
+ for(var/datum/action/innate/mecha/equipment/action as anything in equip_actions)
+ action.Grant(pilot)
+
+// Remove the actions!!!!
+/obj/item/mecha_parts/mecha_equipment/proc/remove_actions(mob/pilot)
+ for(var/datum/action/innate/mecha/equipment/action as anything in equip_actions)
+ action.Remove(pilot)
diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index ecf3a724bcc0..345401e86c38 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -471,7 +471,105 @@
if(..())
radiation_pulse(get_turf(src), rad_per_cycle)
+/////////////////////////////////////////// THRUSTERS /////////////////////////////////////////////
+
+/obj/item/mecha_parts/mecha_equipment/thrusters
+ name = "generic exosuit thrusters" //parent object, in-game sources will be a child object
+ desc = "A generic set of thrusters, from an unknown source. Uses not-understood methods to propel exosuits seemingly for free."
+ icon_state = "thrusters"
+ equip_actions = list(/datum/action/innate/mecha/equipment/toggle_thrusters)
+ selectable = FALSE
+ var/thrusters_active = FALSE
+ var/datum/effect_system/trail_follow/thrust_trail = /datum/effect_system/trail_follow/sparks
+
+/obj/item/mecha_parts/mecha_equipment/thrusters/Initialize(mapload)
+ . = ..()
+ thrust_trail = new thrust_trail
+ thrust_trail.set_up(src)
+
+/obj/item/mecha_parts/mecha_equipment/thrusters/try_attach_part(mob/user, obj/mecha/M)
+ for(var/obj/item/mecha_parts/mecha_equipment/equip as anything in M.equipment)
+ if(istype(equip, type))
+ to_chat(user, span_warning("[src] already has thrusters!"))
+ return FALSE
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/thrusters/attach(obj/mecha/M)
+ . = ..()
+ if(thrusters_active)
+ thrust_trail.start()
+ RegisterSignal(M, COMSIG_MOVABLE_SPACEMOVE, PROC_REF(thrust))
+
+/obj/item/mecha_parts/mecha_equipment/thrusters/detach(atom/moveto)
+ UnregisterSignal(chassis, COMSIG_MOVABLE_SPACEMOVE)
+ if(thrusters_active)
+ thrust_trail.stop()
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/thrusters/proc/thrust(obj/mecha/exo, movement_dir)
+ if(!thrusters_active)
+ return
+ if(!chassis)
+ return
+ return COMSIG_MOVABLE_ALLOW_SPACEMOVE //This parent should never exist in-game outside admeme use, so why not let it be a creative thruster?
+
+/obj/item/mecha_parts/mecha_equipment/thrusters/get_equip_info()
+ return "[..()] \[Thrusters: [thrusters_active ? "Enabled" : "Disabled"]\]"
+
+/obj/item/mecha_parts/mecha_equipment/thrusters/gas
+ name = "RCS thruster package"
+ desc = "A set of thrusters that allow for exosuit movement in zero-gravity environments, by expelling gas from the internal life support tank."
+ thrust_trail = /datum/effect_system/trail_follow/smoke
+ var/move_cost = 0.05 // moles per step (5 times more than human jetpacks)
+/obj/item/mecha_parts/mecha_equipment/thrusters/gas/thrust(obj/mecha/exo, movement_dir)
+ if(!thrusters_active)
+ return
+ if(!movement_dir)
+ return
+ var/obj/machinery/portable_atmospherics/canister/internal_tank = chassis.internal_tank
+ if(!internal_tank)
+ return
+ var/datum/gas_mixture/our_mix = internal_tank.return_air()
+ var/moles = our_mix.total_moles()
+ if(moles < move_cost)
+ thrusters_active = FALSE
+ thrust_trail.stop()
+ our_mix.remove(moles)
+ return
+ our_mix.remove(move_cost)
+ return COMSIG_MOVABLE_ALLOW_SPACEMOVE
+
+/obj/item/mecha_parts/mecha_equipment/thrusters/ion //for mechs with built-in thrusters, should never really exist un-attached to a mech
+ name = "ion thruster package"
+ desc = "A set of thrusters that allow for exosuit movement in zero-gravity environments."
+ thrust_trail = /datum/effect_system/trail_follow/ion
+ salvageable = FALSE
+
+/obj/item/mecha_parts/mecha_equipment/thrusters/ion/thrust(obj/mecha/exo, movement_dir)
+ if(!thrusters_active)
+ return
+ if(!chassis.use_power(chassis.step_energy_drain))
+ thrusters_active = FALSE
+ thrust_trail.stop()
+ return
+ return COMSIG_MOVABLE_ALLOW_SPACEMOVE
+
+/datum/action/innate/mecha/equipment/toggle_thrusters
+ name = "Toggle Thrusters"
+ button_icon_state = "mech_thrusters_off"
+
+/datum/action/innate/mecha/equipment/toggle_thrusters/Activate()
+ var/obj/item/mecha_parts/mecha_equipment/thrusters/thruster = equipment
+ thruster.thrusters_active = !thruster.thrusters_active
+ if(thruster.thrusters_active)
+ thruster.thrust_trail.start()
+ else
+ thruster.thrust_trail.stop()
+ chassis.log_message("Toggled thrusters.", LOG_MECHA)
+ chassis.occupant_message("Thrusters [thruster.thrusters_active ?"en":"dis"]abled.")
+ button_icon_state = "mech_thrusters_[thruster.thrusters_active ? "on" : "off"]"
+ build_all_button_icons()
/////////////////////////////////////////// EJECTION /////////////////////////////////////////////
diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm
index 56a7af725331..d24c6e86cbae 100644
--- a/code/game/mecha/equipment/tools/work_tools.dm
+++ b/code/game/mecha/equipment/tools/work_tools.dm
@@ -1,8 +1,6 @@
-#define DECONSTRUCT 0
-#define WALL 1
-#define AIRLOCK 2
-//Hydraulic clamp, Kill clamp, Extinguisher, RCD, Cable layer.
+
+//Hydraulic clamp, Kill clamp, Extinguisher, RCD, RPD, Cable layer.
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp
@@ -11,11 +9,29 @@
icon_state = "mecha_clamp"
equip_cooldown = 15
energy_drain = 10
+ toolspeed = 0.5
+ usesound = 'sound/mecha/hydraulic.ogg'
+ tool_behaviour = TOOL_CROWBAR
+ equip_actions = list(/datum/action/innate/mecha/equipment/clamp_mode)
/// How much damage does it apply when used
var/dam_force = 20
var/obj/mecha/working/ripley/cargo_holder
harmful = FALSE
+/datum/action/innate/mecha/equipment/clamp_mode
+ name = "Toggle Clamp Mode"
+ button_icon_state = "clamp_crowbar"
+
+/datum/action/innate/mecha/equipment/clamp_mode/Activate()
+ if(equipment.tool_behaviour == TOOL_CROWBAR)
+ equipment.tool_behaviour = TOOL_WRENCH
+ else
+ equipment.tool_behaviour = TOOL_CROWBAR
+ button_icon_state = "clamp_[equipment.tool_behaviour]"
+ chassis.balloon_alert(owner, "clamp set to [(equipment.tool_behaviour==TOOL_CROWBAR) ? "pry" : "wrench"]")
+ playsound(chassis, 'sound/items/change_jaws.ogg', 50, 1)
+ build_all_button_icons()
+
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/mecha/working/ripley/M as obj)
if(..())
if(istype(M))
@@ -31,11 +47,18 @@
..()
cargo_holder = null
-/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/action(atom/target)
+/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/action(atom/target, mob/living/user, params)
if(!action_checks(target))
return
if(!cargo_holder)
return
+
+ // There are two ways things handle being pried, and I'm too lazy to make every single thing use the same one
+ if(target.tool_act(user, src, tool_behaviour) & TOOL_ACT_MELEE_CHAIN_BLOCKING)
+ return TRUE
+ if(target.attackby(src, user, params))
+ return TRUE
+
if(ismecha(target))
var/obj/mecha/M = target
var/have_ammo
@@ -49,20 +72,14 @@
else
to_chat(chassis.occupant, "No providable supplies found in cargo hold")
return
+
if(isobj(target))
var/obj/O = target
- if(istype(O, /obj/machinery/door/firedoor))
- var/obj/machinery/door/firedoor/D = O
- D.try_to_crowbar(src,chassis.occupant)
- return
- if(istype(O, /obj/machinery/door/airlock/))
- var/obj/machinery/door/airlock/D = O
- D.try_to_crowbar(src,chassis.occupant)
- return
if(!O.anchored)
if(cargo_holder.cargo.len < cargo_holder.cargo_capacity)
chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.")
O.anchored = TRUE
+ play_tool_sound(chassis)
if(do_after_cooldown(target))
cargo_holder.cargo += O
O.forceMove(chassis)
@@ -242,133 +259,182 @@
name = "mounted RCD"
desc = "An exosuit-mounted Rapid Construction Device."
icon_state = "mecha_rcd"
- equip_cooldown = 10
- energy_drain = 50
+ equip_cooldown = 0 // internal RCD will handle it
+ energy_drain = 0 // uses matter instead of energy
range = MECHA_MELEE|MECHA_RANGED
item_flags = NO_MAT_REDEMPTION
- var/mode = DECONSTRUCT
- var/play_sound = TRUE //so fancy mime RCD can be silent
+ equip_actions = list(/datum/action/innate/mecha/equipment/rcd)
+ var/rcd_type = /obj/item/construction/rcd/exosuit
+ var/obj/item/construction/rcd/internal_rcd
/obj/item/mecha_parts/mecha_equipment/rcd/Initialize(mapload)
. = ..()
GLOB.rcd_list += src
+ internal_rcd = new rcd_type(src)
/obj/item/mecha_parts/mecha_equipment/rcd/Destroy()
GLOB.rcd_list -= src
+ if(internal_rcd && !QDELETED(internal_rcd))
+ qdel(internal_rcd)
return ..()
-/obj/item/mecha_parts/mecha_equipment/rcd/action(atom/target)
- if(istype(target, /turf/open/space/transit))//>implying these are ever made -Sieve
- return
-
- if(!isturf(target) && !istype(target, /obj/machinery/door/airlock))
- target = get_turf(target)
- if(!action_checks(target) || get_dist(chassis, target)>3)
- return
- if(play_sound)
- playsound(chassis, 'sound/machines/click.ogg', 50, 1)
-
- switch(mode)
- if(DECONSTRUCT)
- if(iswallturf(target))
- if(istype(target, /turf/closed/wall/r_wall))
- occupant_message("Wall reinforcements are too complex for deconstruction, must be deconstructed manually.")
- return
- energy_drain = 500
- var/turf/closed/wall/W = target
- occupant_message("Deconstructing [W]...")
- if(do_after_cooldown(W))
- chassis.spark_system.start()
- W.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
- if(play_sound)
- playsound(W, 'sound/items/deconstruct.ogg', 50, 1)
- if(target == /turf/closed/wall/r_wall)
- energy_drain = 2000
- else if(isfloorturf(target))
- if(istype(target, /turf/open/floor/engine))
- occupant_message("Floor reinforcements prevent deconstruction, remove before continuing.")
- return
- energy_drain = 100
- var/turf/open/floor/F = target
- occupant_message("Deconstructing [F]...")
- if(do_after_cooldown(target))
- chassis.spark_system.start()
- F.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
- if(play_sound)
- playsound(F, 'sound/items/deconstruct.ogg', 50, 1)
- else if (istype(target, /obj/machinery/door/airlock))
- var/obj/machinery/door/airlock/A = target
- if(A.damage_deflection > 21)
- occupant_message("Airlock too reinforced for deconstruction, remove reinforcements before continuing.")
- return
- energy_drain = 500
- occupant_message("Deconstructing [target]...")
- if(do_after_cooldown(target))
- chassis.spark_system.start()
- qdel(target)
- if(play_sound)
- playsound(target, 'sound/items/deconstruct.ogg', 50, 1)
- if(WALL)
- if(isspaceturf(target))
- var/turf/open/space/S = target
- occupant_message("Building Floor...")
- if(do_after_cooldown(S))
- S.place_on_top(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
- if(play_sound)
- playsound(S, 'sound/items/deconstruct.ogg', 50, 1)
- chassis.spark_system.start()
- else if(isfloorturf(target))
- var/turf/open/floor/F = target
- energy_drain = 750
- occupant_message("Building Wall...")
- if(do_after_cooldown(F))
- F.place_on_top(/turf/closed/wall)
- if(play_sound)
- playsound(F, 'sound/items/deconstruct.ogg', 50, 1)
- chassis.spark_system.start()
- if(AIRLOCK)
- if(isfloorturf(target))
- energy_drain = 750
- occupant_message("Building Airlock...")
- if(do_after_cooldown(target))
- chassis.spark_system.start()
- var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target)
- T.autoclose = TRUE
- if(play_sound)
- playsound(target, 'sound/items/deconstruct.ogg', 50, 1)
- playsound(target, 'sound/effects/sparks2.ogg', 50, 1)
-
-
-
-/obj/item/mecha_parts/mecha_equipment/rcd/do_after_cooldown(atom/target)
+/obj/item/mecha_parts/mecha_equipment/rcd/attach(obj/mecha/M)
. = ..()
+ internal_rcd.owner = M
-/obj/item/mecha_parts/mecha_equipment/rcd/Topic(href,href_list)
- ..()
- if(href_list["mode"])
- mode = text2num(href_list["mode"])
- switch(mode)
- if(0)
- occupant_message("Switched RCD to Deconstruct.")
- energy_drain = initial(energy_drain)
- if(1)
- occupant_message("Switched RCD to Construct.")
- energy_drain = 2*initial(energy_drain)
- if(2)
- occupant_message("Switched RCD to Construct Airlock.")
- energy_drain = 2*initial(energy_drain)
- return
+/obj/item/mecha_parts/mecha_equipment/rcd/detach(atom/moveto)
+ internal_rcd.owner = null
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/rcd/action(atom/target, mob/living/user, params)
+ var/prox_flag = chassis.Adjacent(target)
+ if(prox_flag && (istype(target, /obj/item/stack) || istype(target, /obj/item/rcd_ammo) || istype(target, /obj/item/rcd_upgrade)))
+ chassis.matter_resupply(target, user)
+ return TRUE
+ if(!isliving(target))
+ internal_rcd.afterattack(target, user, prox_flag, params) // RCD itself will handle it
+ return TRUE
/obj/item/mecha_parts/mecha_equipment/rcd/get_equip_info()
- return "[..()] \[D|C|A\]"
+ return "[..()] \[Matter: [internal_rcd ? internal_rcd.matter : 0]/[internal_rcd ? internal_rcd.max_matter : 0]\]"
+/datum/action/innate/mecha/equipment/rcd
+ name = "Change RCD Mode"
+ button_icon_state = "rcd"
+
+/datum/action/innate/mecha/equipment/rcd/Activate()
+ var/obj/item/mecha_parts/mecha_equipment/rcd/E = equipment
+ E.internal_rcd.ui_interact(owner)
/obj/item/mecha_parts/mecha_equipment/rcd/mime //special silent RCD
name = "silenced mounted RCD"
desc = "An expertly mimed exosuit-mounted Rapid Construction Device. Not a sound is made."
- play_sound = FALSE
+ rcd_type = /obj/item/construction/rcd/exosuit/mime
+/obj/item/mecha_parts/mecha_equipment/pipe_dispenser
+ name = "mounted RPD"
+ desc = "An exosuit-mounted Rapid Pipe Dispenser"
+ icon_state = "mecha_pipe_dispenser"
+ equip_cooldown = 0 // internal RPD will handle it
+ energy_drain = 0 // uses matter instead of energy
+ range = MECHA_MELEE|MECHA_RANGED
+ item_flags = NO_MAT_REDEMPTION
+ equip_actions = list(/datum/action/innate/mecha/equipment/pipe_dispenser)
+ var/rpd_type = /obj/item/pipe_dispenser/exosuit // in case there's ever any other type of RPD for mechs for some reason
+ var/obj/item/pipe_dispenser/internal_rpd
+
+/obj/item/mecha_parts/mecha_equipment/pipe_dispenser/Initialize(mapload)
+ . = ..()
+ internal_rpd = new rpd_type(src)
+
+/obj/item/mecha_parts/mecha_equipment/pipe_dispenser/Destroy()
+ if(internal_rpd && !QDELETED(internal_rpd))
+ qdel(internal_rpd)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/pipe_dispenser/attach(obj/mecha/M)
+ . = ..()
+ internal_rpd.owner = M
+
+/obj/item/mecha_parts/mecha_equipment/pipe_dispenser/detach(atom/moveto)
+ internal_rpd.owner = null
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/pipe_dispenser/action(atom/target, mob/living/user, params)
+ if(internal_rpd.pre_attack(target, user))
+ return FALSE
+ chassis.Beam(target, icon_state="rped_upgrade",time=2)
+ return TRUE
+
+/datum/action/innate/mecha/equipment/pipe_dispenser
+ name = "Change RPD Mode"
+ button_icon_state = "rpd"
+
+/datum/action/innate/mecha/equipment/pipe_dispenser/Activate()
+ var/obj/item/mecha_parts/mecha_equipment/pipe_dispenser/E = equipment
+ E.internal_rpd.ui_interact(owner)
+
+
+/obj/item/mecha_parts/mecha_equipment/t_scanner
+ name = "exosuit T-ray scanner"
+ desc = "An exosuit-mounted terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes. Has much higher range than the handheld version."
+ icon_state = "mecha_t_scanner"
+ equip_actions = list(/datum/action/innate/mecha/equipment/t_scanner)
+ selectable = FALSE
+ /// Scanning distance
+ var/distance = 6
+ /// Whether the scanning is enabled
+ var/scanning = FALSE
+ /// Stored t-ray scan images
+ var/list/t_ray_images
+
+/obj/item/mecha_parts/mecha_equipment/t_scanner/attach(obj/mecha/M)
+ . = ..()
+ RegisterSignal(M, COMSIG_MOVABLE_MOVED, PROC_REF(on_mech_move))
+
+/obj/item/mecha_parts/mecha_equipment/t_scanner/detach(atom/moveto)
+ UnregisterSignal(chassis, COMSIG_MOVABLE_MOVED)
+ if(scanning)
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/t_scanner/process(delta_time)
+ if(!update_scan(chassis.occupant))
+ return PROCESS_KILL
+
+/obj/item/mecha_parts/mecha_equipment/t_scanner/proc/on_mech_move()
+ if(chassis.occupant?.client)
+ update_scan(chassis.occupant)
+
+/obj/item/mecha_parts/mecha_equipment/t_scanner/proc/update_scan(mob/pilot, force_remove=FALSE) // twice the range, no downtime
+ if(!pilot?.client)
+ return FALSE
+ if(t_ray_images?.len)
+ pilot.client.images.Remove(t_ray_images)
+ QDEL_NULL(t_ray_images)
+ if(!scanning || force_remove)
+ return FALSE
+
+ t_ray_images = list()
+ for(var/obj/O in orange(distance, chassis))
+ if(HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE))
+ var/image/I = new(loc = get_turf(O))
+ var/mutable_appearance/MA = new(O)
+ MA.alpha = 128
+ MA.dir = O.dir
+ I.appearance = MA
+ t_ray_images += I
+
+ if(t_ray_images.len)
+ pilot.client.images += t_ray_images
+
+ return TRUE
+
+/obj/item/mecha_parts/mecha_equipment/t_scanner/grant_actions(mob/pilot)
+ . = ..()
+ update_scan(pilot)
+
+/obj/item/mecha_parts/mecha_equipment/t_scanner/remove_actions(mob/pilot)
+ update_scan(pilot, TRUE)
+ return ..()
+
+/datum/action/innate/mecha/equipment/t_scanner
+ name = "Toggle T-ray Scanner"
+ button_icon_state = "t_scanner_off"
+
+/datum/action/innate/mecha/equipment/t_scanner/Activate()
+ var/obj/item/mecha_parts/mecha_equipment/t_scanner/t_scan = equipment
+ t_scan.scanning = !t_scan.scanning
+ t_scan.update_scan(t_scan.chassis.occupant)
+ t_scan.chassis.occupant_message("You [t_scan.scanning ? "activate" : "deactivate"] [t_scan].")
+ button_icon_state = "t_scanner_[t_scan.scanning ? "on" : "off"]"
+ build_all_button_icons()
+ if(t_scan.scanning)
+ START_PROCESSING(SSobj, t_scan)
+ else
+ STOP_PROCESSING(SSobj, t_scan)
+
/obj/item/mecha_parts/mecha_equipment/cable_layer
name = "cable layer"
desc = "Equipment for engineering exosuits. Lays cable along the exosuit's path."
@@ -561,7 +627,3 @@
qdel(M)
playsound(get_turf(N),'sound/items/ratchet.ogg',50,1)
return
-
-#undef DECONSTRUCT
-#undef WALL
-#undef AIRLOCK
diff --git a/code/game/mecha/equipment/weapons/melee_weapons.dm b/code/game/mecha/equipment/weapons/melee_weapons.dm
index dc1c60733b6f..06c42b2d4642 100644
--- a/code/game/mecha/equipment/weapons/melee_weapons.dm
+++ b/code/game/mecha/equipment/weapons/melee_weapons.dm
@@ -62,7 +62,7 @@
addtimer(CALLBACK(src, PROC_REF(set_ready_state), 1), chassis.melee_cooldown * attack_speed_modifier * check_eva()) //Guns only shoot so fast, but weapons can be used as fast as the chassis can swing it!
//Melee weapon attacks are a little different in that they'll override the standard melee attack
-/obj/item/mecha_parts/mecha_equipment/melee_weapon/action(atom/target, params)
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/action(atom/target, mob/living/user, params)
if(!action_checks(target))
return 0
@@ -125,7 +125,7 @@
/obj/item/mecha_parts/mecha_equipment/melee_weapon/proc/cleave_attack()
return 0
-/obj/item/mecha_parts/mecha_equipment/melee_weapon/proc/special_hit() //For special effects, slightly simplifies cleave/precise attack procs
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/proc/special_hit(atom/target) //For special effects, slightly simplifies cleave/precise attack procs
return 1
/obj/item/mecha_parts/mecha_equipment/melee_weapon/on_select()
@@ -199,7 +199,7 @@
if((isstructure(A) || ismachinery(A) || istype(A, /obj/mecha)) && can_stab_at(chassis, A)) //if it's a big thing we hit anyways. Structures ALWAYS are hit, machines and mechs can be protected
var/obj/O = A
- if(!O.density) //Make sure it's not an open door or something
+ if(!O.density && !istype(O, /obj/structure/spacevine)) //Make sure it's not an open door or something
continue
var/object_damage = max(chassis.force + weapon_damage, minimum_damage) * structure_damage_mult * (istype(A, /obj/mecha) ? mech_damage_multiplier : 1) //Half damage on mechs
O.take_damage(object_damage, dam_type, "melee", 0)
@@ -536,3 +536,126 @@
span_userdanger("[chassis.name] penetrates your suits armor with [src]!"))
chassis.log_message("Hit [H] with [src.name] (precise attack).", LOG_MECHA)
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/mop
+ name = "heavy mop"
+ desc = "A very big mop, designed to be attached to mechanical exosuits."
+ icon_state = "mecha_mop"
+ energy_drain = 5
+ attack_sound = 'sound/effects/slosh.ogg'
+
+ cleave = TRUE
+ precise_attacks = FALSE // cleave only
+ attack_sharpness = SHARP_NONE
+ harmful = FALSE
+ weapon_damage = 0 // no damage
+ structure_damage_mult = 0 // don't break stuff while trying to clean
+ equip_actions = list(/datum/action/innate/mecha/equipment/sweeping)
+ var/auto_sweep = TRUE
+
+/datum/action/innate/mecha/equipment/sweeping
+ name = "Toggle Auto-Mop"
+ button_icon_state = "sweep_on"
+
+/datum/action/innate/mecha/equipment/sweeping/Activate()
+ var/obj/item/mecha_parts/mecha_equipment/melee_weapon/mop/mop = equipment
+ mop.auto_sweep = !mop.auto_sweep
+ button_icon_state = "sweep_[mop.auto_sweep ? "on" : "off"]"
+ build_all_button_icons()
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/mop/attach(obj/mecha/M)
+ . = ..()
+ RegisterSignal(M, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_pre_move))
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/mop/detach(atom/moveto)
+ UnregisterSignal(chassis, COMSIG_MOVABLE_PRE_MOVE)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/mop/can_attach(obj/mecha/M)
+ if(istype(M, /obj/mecha/working) && M.equipment.len < M.max_equip)
+ return TRUE
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/mop/proc/on_pre_move(obj/mecha/mech, atom/newloc)
+ if(!auto_sweep)
+ return
+ var/mop_dir = get_dir(mech, newloc)
+ if(mop_dir != mech.dir) // only sweep things in front of the mech
+ return
+ do_mop(mech, newloc)
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/mop/proc/do_mop(obj/mecha/mech, atom/newloc, throw_power=1)
+ var/turf/mop_turf = newloc
+ var/turf/thrown_at = get_edge_target_turf(mop_turf, chassis.dir)
+ var/cleaned = FALSE
+
+ if(mop_turf.wash(CLEAN_SCRUB))
+ cleaned = TRUE
+ for(var/atom/movable/moved_atom in newloc)
+ if(istype(moved_atom, /obj/effect/decal/nuclear_waste)) // sweep that nuclear waste under the rug
+ cleaned = TRUE
+ playsound(moved_atom, 'sound/effects/gib_step.ogg', 50, 1)
+ qdel(moved_atom)
+ continue
+ if(moved_atom.wash(CLEAN_SCRUB))
+ cleaned = TRUE
+ if(moved_atom.anchored)
+ continue
+ if(moved_atom == chassis) // it can clean itself, but not move itself
+ continue
+ moved_atom.throw_at(thrown_at, throw_power, 1, mech.occupant, (throw_power > 1))
+ if(isliving(moved_atom) && throw_power > 1)
+ moved_atom.visible_message(span_danger("[mech] mops the floor with [moved_atom]!"), span_userdanger("[mech] mops the floor with you!"))
+
+ if(cleaned)
+ playsound(newloc, 'sound/effects/slosh.ogg', 25, 1)
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/mop/cleave_attack()
+ playsound(chassis, attack_sound, 50, 1)
+ for(var/turf/T in list(get_turf(chassis), get_step(chassis, chassis.dir), get_step(chassis, turn(chassis.dir, -45)), get_step(chassis, turn(chassis.dir, 45))))
+ do_mop(chassis, T, 3) // mop the floor with them!
+ var/turf/cleave_effect_loc = get_step(get_turf(src), SOUTHWEST)
+ new cleave_effect(cleave_effect_loc, chassis.dir)
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/flyswatter
+ name = "comically large flyswatter"
+ desc = "A comically large flyswatter, presumably for killing comically large bugs."
+ attack_sound = 'sound/effects/snap.ogg'
+ icon_state = "mecha_flyswatter"
+ cleave = FALSE
+ precise_attacks = TRUE
+ hit_effect = ATTACK_EFFECT_SMASH
+ ///Things in this list will be instantly splatted.
+ var/list/strong_against
+ ///Damage to mobs with the MOB_BUG biotype, quadrupled for simple mobs
+ var/bug_damage = 30
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/flyswatter/Initialize(mapload)
+ . = ..()
+ strong_against = typecacheof(list(
+ /mob/living/simple_animal/hostile/poison/bees,
+ /mob/living/simple_animal/butterfly,
+ /mob/living/simple_animal/cockroach,
+ /obj/item/queen_bee
+ ))
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/flyswatter/precise_attack(atom/target)
+ var/mob/living/mob_target = target
+ if(is_type_in_typecache(target, strong_against))
+ new /obj/effect/decal/cleanable/insectguts(target.drop_location())
+ to_chat(chassis.occupant, span_warning("You easily splat the [target]."))
+ if(isliving(target))
+ var/mob/living/bug = target
+ bug.death(TRUE)
+ else
+ qdel(target)
+ else if(isliving(target) && (mob_target.mob_biotypes & MOB_BUG))
+ mob_target.apply_damage(bug_damage * (ishuman(mob_target) ? 1 : 4), BRUTE, wound_bonus=CANT_WOUND) // bonus damage to simple mobs
+ target.visible_message(span_warning("[chassis] splats [target] with [src]!"), span_userdanger("[chassis] splats you with [src]!"))
+ chassis.do_attack_animation(target, hit_effect)
+ playsound(chassis, attack_sound, 50, 1)
+
+/obj/item/mecha_parts/mecha_equipment/melee_weapon/flyswatter/can_attach(obj/mecha/M)
+ if(istype(M, /obj/mecha/working) && M.equipment.len < M.max_equip)
+ return TRUE
+ return ..()
diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm
index 6069a2acf89b..05c7b50a1cdc 100644
--- a/code/game/mecha/equipment/weapons/weapons.dm
+++ b/code/game/mecha/equipment/weapons/weapons.dm
@@ -32,7 +32,7 @@
/obj/item/mecha_parts/mecha_equipment/weapon/proc/get_shot_amount()
return projectiles_per_shot
-/obj/item/mecha_parts/mecha_equipment/weapon/action(atom/target, params)
+/obj/item/mecha_parts/mecha_equipment/weapon/action(atom/target, mob/living/user, params)
if(!action_checks(target))
return 0
@@ -151,6 +151,7 @@
/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma
equip_cooldown = 10
+ range = MECHA_MELEE|MECHA_RANGED
name = "217-D Heavy Plasma Cutter"
desc = "A device that shoots resonant plasma bursts at extreme velocity. The blasts are capable of crushing rock and demolishing solid obstacles."
icon_state = "mecha_plasmacutter"
@@ -160,6 +161,9 @@
energy_drain = 30
projectile = /obj/projectile/plasma/adv/mech
fire_sound = 'sound/weapons/plasma_cutter.ogg'
+ usesound = list('sound/items/welder.ogg', 'sound/items/welder2.ogg')
+ toolspeed = 0.25 // high-power cutting
+ tool_behaviour = TOOL_WELDER
harmful = FALSE
/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/mecha/M)
@@ -171,6 +175,18 @@
return 1
return 0
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/action(atom/target, mob/living/user, params)
+ if(!chassis.Adjacent(target))
+ return ..()
+ // Again, two ways using tools can be handled, so check both
+ if(target.tool_act(chassis.occupant, src, TOOL_WELDER) & TOOL_ACT_MELEE_CHAIN_BLOCKING)
+ return TRUE
+ if(target.attackby(src, chassis.occupant, params))
+ return TRUE
+ if(user.a_intent == INTENT_HARM) // hurt things
+ chassis.default_melee_attack(target)
+ return TRUE
+
/obj/item/mecha_parts/mecha_equipment/weapon/energy/mecha_kineticgun
equip_cooldown = 10
name = "Exosuit Proto-kinetic Accelerator"
@@ -309,7 +325,7 @@
src.rearm()
return
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action(atom/target)
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action(atom/target, mob/living/user, params)
if(..())
projectiles -= get_shot_amount()
send_byjax(chassis.occupant,"exosuit.browser","[REF(src)]",src.get_equip_info())
@@ -548,3 +564,42 @@
var/atom/movable/AM = hit_atom
AM.safe_throw_at(get_edge_target_turf(AM,get_dir(src, AM)), 7, 2)
qdel(src)
+
+// pressure washer, technically a gun
+/obj/item/mecha_parts/mecha_equipment/weapon/pressure_washer
+ name = "exosuit-mounted pressure washer"
+ desc = "A high-power pressure washer."
+ icon_state = "mecha_washer"
+ range = MECHA_MELEE|MECHA_RANGED
+ projectile = /obj/projectile/reagent/pressure_washer
+ firing_effect_type = null
+ fire_sound = 'sound/effects/extinguish.ogg'
+ var/chem_amount = 5
+
+/obj/item/mecha_parts/mecha_equipment/weapon/pressure_washer/Initialize(mapload)
+ . = ..()
+ create_reagents(1000)
+ reagents.add_reagent(/datum/reagent/water, 1000)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/pressure_washer/action(atom/target, mob/living/user, params)
+ if(istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1)
+ var/obj/structure/reagent_dispensers/WT = target
+ WT.reagents.trans_to(src, 1000)
+ occupant_message(span_notice("Pressure washer refilled."))
+ playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6)
+ return TRUE
+ else if(reagents.total_volume < 1)
+ occupant_message(span_notice("Not enough water!"))
+ return TRUE
+ if(..())
+ reagents.remove_reagent(/datum/reagent/water, chem_amount)
+ return TRUE
+ return FALSE
+
+/obj/item/mecha_parts/mecha_equipment/weapon/pressure_washer/can_attach(obj/mecha/M)
+ if(istype(M, /obj/mecha/working) && M.equipment.len < M.max_equip)
+ return TRUE
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/weapon/pressure_washer/get_equip_info()
+ return "[..()] \[[src.reagents.total_volume]\]"
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index f92f786b6d81..aae3755c65fb 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -4,8 +4,8 @@
#define MECHA_INT_TANK_BREACH (1<<3)
#define MECHA_INT_CONTROL_LOST (1<<4)
-#define MECHA_MELEE 1
-#define MECHA_RANGED 2
+#define MECHA_MELEE (1<<0)
+#define MECHA_RANGED (1<<1)
#define FRONT_ARMOUR 1
#define SIDE_ARMOUR 2
@@ -111,7 +111,6 @@
var/datum/action/innate/mecha/mech_cycle_equip/cycle_action = new
var/datum/action/innate/mecha/mech_toggle_lights/lights_action = new
var/datum/action/innate/mecha/mech_view_stats/stats_action = new
- var/datum/action/innate/mecha/mech_toggle_thrusters/thrusters_action = new
var/datum/action/innate/mecha/mech_defence_mode/defence_action = new
var/datum/action/innate/mecha/mech_overload_mode/overload_action = new
var/datum/effect_system/fluid_spread/smoke/smoke_system = new //not an action, but trigged by one
@@ -122,7 +121,6 @@
var/datum/action/innate/mecha/strafe/strafing_action = new
//Action vars
- var/thrusters_active = FALSE
var/defence_mode = FALSE
var/defence_mode_deflect_chance = 15
var/leg_overload_mode = FALSE
@@ -135,7 +133,7 @@
var/phasing_energy_drain = 200
var/phase_state = "" //icon_state when phasing
var/strafe = FALSE //If we are strafing
- var/canstrafe = TRUE
+ var/pivot_step = FALSE
var/nextsmash = 0
var/smashcooldown = 3 //deciseconds
var/ejection_distance = 0 //violently ejects the pilot when destroyed
@@ -481,7 +479,7 @@
////////////////////////////
-/obj/mecha/proc/click_action(atom/target,mob/user,params)
+/obj/mecha/proc/click_action(atom/target, mob/user, params)
if(!occupant || occupant != user )
return
if(!locate(/turf) in list(target,target.loc)) // Prevents inventory from being drilled
@@ -524,7 +522,7 @@
if(HAS_TRAIT(L, TRAIT_NO_STUN_WEAPONS) && !selected.harmful)
to_chat(user, span_warning("You cannot use non-lethal weapons!"))
return
- if(selected.action(target,params))
+ if(selected.action(target, user, params))
selected.start_cooldown()
else if(selected && selected.is_melee())
if(isliving(target) && selected.harmful && HAS_TRAIT(L, TRAIT_PACIFISM))
@@ -538,19 +536,22 @@
if(HAS_TRAIT(L, TRAIT_PACIFISM) && W.cleave)
to_chat(user, span_warning("You don't want to harm other living beings!"))
return
- if(selected.action(target,params))
+ if(selected.action(target, user, params))
selected.start_cooldown()
else
- if(internal_damage & MECHA_INT_CONTROL_LOST)
- target = pick(oview(1,src))
- if(!melee_can_hit || !istype(target, /atom))
- return
- if(equipment_disabled)
- return
- target.mech_melee_attack(src, TRUE)
- melee_can_hit = FALSE
- spawn(melee_cooldown)
- melee_can_hit = TRUE
+ default_melee_attack(target)
+
+/obj/mecha/proc/default_melee_attack(atom/target)
+ if(internal_damage & MECHA_INT_CONTROL_LOST)
+ target = pick(oview(1,src))
+ if(!melee_can_hit || !istype(target, /atom))
+ return
+ if(equipment_disabled)
+ return
+ target.mech_melee_attack(src, TRUE)
+ melee_can_hit = FALSE
+ spawn(melee_cooldown)
+ melee_can_hit = TRUE
/obj/mecha/proc/range_action(atom/target)
@@ -573,8 +574,6 @@
. = ..()
if(.)
return TRUE
- if(thrusters_active && movement_dir && use_power(step_energy_drain))
- return TRUE
var/atom/movable/backup = get_spacemove_backup()
if(backup)
@@ -608,8 +607,10 @@
/obj/mecha/proc/domove(direction)
if(can_move >= world.time)
return FALSE
- if(direction == DOWN || direction == UP)
- return FALSE //nuh uh
+ if((direction & (DOWN|UP)) && !get_step_multiz(get_turf(src), direction))
+ direction &= ~(DOWN|UP) // remove vertical component
+ if(!direction) // don't bother moving without a direction
+ return FALSE
if(!Process_Spacemove(direction))
return FALSE
if(!has_charge(step_energy_drain))
@@ -656,25 +657,30 @@
/obj/mecha/proc/mechturn(direction)
setDir(direction)
- if(turnsound)
+ if(turnsound && has_gravity())
playsound(src,turnsound,40,1)
return TRUE
/obj/mecha/proc/mechstep(direction)
var/current_dir = dir
var/result = step(src,direction)
- if(strafe)
+ if(strafe && !pivot_step)
setDir(current_dir)
- if(result && stepsound)
+ if(result && stepsound && has_gravity())
playsound(src,stepsound,40,1)
return result
/obj/mecha/proc/mechsteprand()
var/result = step_rand(src)
- if(result && stepsound)
+ if(result && stepsound && has_gravity())
playsound(src,stepsound,40,1)
return result
+/obj/mecha/setDir()
+ . = ..()
+ if(occupant)
+ occupant.setDir(dir) // keep the pilot facing the direction of the mech or bad things happen
+
/obj/mecha/Bump(atom/obstacle)
var/turf/newloc = get_step(src,dir)
var/area/newarea = newloc.loc
@@ -1274,6 +1280,13 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013???
to_chat(user, span_notice("None of the equipment on this exosuit can use this ammo!"))
return FALSE
+// Matter resupply and upgrades for mounted RCDs
+/obj/mecha/proc/matter_resupply(obj/item/I, mob/user)
+ for(var/obj/item/mecha_parts/mecha_equipment/rcd/R in equipment)
+ R.internal_rcd.attackby(I, user)
+ if(QDELETED(I))
+ return
+
// Checks the pilot and their clothing for mech speed buffs
/obj/mecha/proc/check_eva()
var/evaNum = 1
diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm
index bebbc829af15..fc850f051ffb 100644
--- a/code/game/mecha/mecha_actions.dm
+++ b/code/game/mecha/mecha_actions.dm
@@ -8,8 +8,9 @@
cycle_action.Grant(user, src)
lights_action.Grant(user, src)
stats_action.Grant(user, src)
- if(canstrafe)
- strafing_action.Grant(user, src)
+ strafing_action.Grant(user, src)
+ for(var/obj/item/mecha_parts/mecha_equipment/E as anything in equipment)
+ E.grant_actions(user)
/obj/mecha/proc/RemoveActions(mob/living/user, human_occupant = 0)
@@ -19,8 +20,9 @@
cycle_action.Remove(user)
lights_action.Remove(user)
stats_action.Remove(user)
- if(canstrafe)
- strafing_action.Remove(user)
+ strafing_action.Remove(user)
+ for(var/obj/item/mecha_parts/mecha_equipment/E as anything in equipment)
+ E.remove_actions(user)
/datum/action/innate/mecha
check_flags = AB_CHECK_HANDS_BLOCKED | AB_CHECK_IMMOBILE | AB_CHECK_CONSCIOUS
@@ -134,7 +136,7 @@
/datum/action/innate/mecha/strafe
name = "Toggle Strafing. Disabled when Alt is held."
- button_icon_state = "strafe"
+ button_icon_state = "strafe_off"
/datum/action/innate/mecha/strafe/Activate()
if(!owner || !chassis || chassis.occupant != owner)
@@ -151,25 +153,12 @@
occupant_message("Toggled strafing mode [strafe?"on":"off"].")
log_message("Toggled strafing mode [strafe?"on":"off"].", LOG_MECHA)
+ strafing_action.button_icon_state = "strafe_[strafe?"on":"off"]"
strafing_action.build_all_button_icons()
//////////////////////////////////////// Specific Ability Actions ///////////////////////////////////////////////
//Need to be granted by the mech type, Not default abilities.
-/datum/action/innate/mecha/mech_toggle_thrusters
- name = "Toggle Thrusters"
- button_icon_state = "mech_thrusters_off"
-
-/datum/action/innate/mecha/mech_toggle_thrusters/Activate()
- if(!owner || !chassis || chassis.occupant != owner)
- return
- if(chassis.get_charge() > 0)
- chassis.thrusters_active = !chassis.thrusters_active
- button_icon_state = "mech_thrusters_[chassis.thrusters_active ? "on" : "off"]"
- chassis.log_message("Toggled thrusters.", LOG_MECHA)
- chassis.occupant_message("Thrusters [chassis.thrusters_active ?"en":"dis"]abled.")
-
-
/datum/action/innate/mecha/mech_defence_mode
name = "Toggle Defence Mode"
button_icon_state = "mech_defence_mode_off"
@@ -288,3 +277,18 @@
button_icon_state = "mech_phasing_[chassis.phasing ? "on" : "off"]"
chassis.occupant_message("En":"#f00\">Dis"]abled phasing.")
build_all_button_icons()
+
+//////////////////////////////////////// Equipment Actions ///////////////////////////////////////////////
+//Equipment-based actions like RCD mode selection
+
+/datum/action/innate/mecha/equipment
+ var/obj/item/mecha_parts/mecha_equipment/equipment
+
+/datum/action/innate/mecha/equipment/Grant(mob/living/L, obj/mecha/M, obj/item/mecha_parts/mecha_equipment/E)
+ if(E)
+ equipment = E
+ return ..()
+
+/datum/action/innate/mecha/equipment/Destroy()
+ equipment = null
+ return ..()
diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm
index ba6c833a217e..4b9591afbc3d 100644
--- a/code/game/mecha/mecha_defense.dm
+++ b/code/game/mecha/mecha_defense.dm
@@ -211,6 +211,15 @@
if(istype(W, /obj/item/mecha_ammo))
ammo_resupply(W, user)
return
+
+ if(istype(W, /obj/item/stack) || istype(W, /obj/item/rcd_ammo) || istype(W, /obj/item/rcd_upgrade))
+ matter_resupply(W, user)
+ return
+
+ if(istype(W, /obj/item/mecha_parts))
+ var/obj/item/mecha_parts/P = W
+ P.try_attach_part(user, src)
+ return
if(W.GetID())
if(add_req_access || maint_access)
@@ -304,11 +313,6 @@
to_chat(user, span_warning("The [name] is at full integrity!"))
return 1
- else if(istype(W, /obj/item/mecha_parts))
- var/obj/item/mecha_parts/P = W
- P.try_attach_part(user, src)
- return
-
else if(istype(W, /obj/item/airlock_scanner)) //yogs start
var/obj/item/airlock_scanner/S = W
S.show_access(src, user) //yogs end
diff --git a/code/game/mecha/mecha_parts.dm b/code/game/mecha/mecha_parts.dm
index 81f83e1c5f1f..45c9149eab5b 100644
--- a/code/game/mecha/mecha_parts.dm
+++ b/code/game/mecha/mecha_parts.dm
@@ -7,7 +7,7 @@
icon = 'icons/mecha/mech_construct.dmi'
icon_state = "blank"
w_class = WEIGHT_CLASS_GIGANTIC
- flags_1 = CONDUCT_1
+ flags_1 = CONDUCT_1 | RAD_NO_CONTAMINATE_1
/obj/item/mecha_parts/proc/try_attach_part(mob/user, obj/mecha/M) //For attaching parts to a finished mech
if(!user.transferItemToLoc(src, M))
diff --git a/code/game/mecha/mecha_topic.dm b/code/game/mecha/mecha_topic.dm
index 1dff7668054b..9c31593b3523 100644
--- a/code/game/mecha/mecha_topic.dm
+++ b/code/game/mecha/mecha_topic.dm
@@ -100,7 +100,6 @@
Environment pressure: [environment_pressure>WARNING_HIGH_PRESSURE ? span_danger("[environment_pressure]"): environment_pressure]kPa
Environment temperature: [environment_temperature]°K|[environment_temperature - T0C]°C
[dna_lock?"DNA-locked:
[dna_lock] \[Reset\]
":""]
- [thrusters_action.owner ? "Thrusters: [thrusters_active ? "Enabled" : "Disabled"]
" : ""]
[defence_action.owner ? "Defence Mode: [defence_mode ? "Enabled" : "Disabled"]
" : ""]
[overload_action.owner ? "Leg Actuators Overload: [leg_overload_mode ? "Enabled" : "Disabled"]
" : ""]
[smoke_action.owner ? "Smoke: [smoke]
" : ""]
diff --git a/code/game/mecha/medical/medical.dm b/code/game/mecha/medical/medical.dm
index d605c64a839b..c379795ff78a 100644
--- a/code/game/mecha/medical/medical.dm
+++ b/code/game/mecha/medical/medical.dm
@@ -1,19 +1,5 @@
/obj/mecha/medical
internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_MEDICAL)
-
-/obj/mecha/medical/mechturn(direction)
- setDir(direction)
- playsound(src,'sound/mecha/mechmove01.ogg',40,1)
- return 1
-
-/obj/mecha/medical/mechstep(direction)
- var/result = step(src,direction)
- if(result)
- playsound(src,'sound/mecha/mechstep.ogg',25,1)
- return result
-
-/obj/mecha/medical/mechsteprand()
- var/result = step_rand(src)
- if(result)
- playsound(src,'sound/mecha/mechstep.ogg',25,1)
- return result
\ No newline at end of file
+ stepsound = 'sound/mecha/mechstep.ogg'
+ turnsound = 'sound/mecha/mechmove01.ogg'
+ pivot_step = TRUE
diff --git a/code/game/mecha/working/clarke.dm b/code/game/mecha/working/clarke.dm
index 21219c90f8aa..69dc1e31b3af 100644
--- a/code/game/mecha/working/clarke.dm
+++ b/code/game/mecha/working/clarke.dm
@@ -6,16 +6,17 @@
max_temperature = 65000
max_integrity = 200
step_in = 1.25
- fast_pressure_step_in = 1.25
- slow_pressure_step_in = 1.8
+ fast_pressure_step_in = 1.5
+ slow_pressure_step_in = 2
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
light_power = 7
deflect_chance = 10
- armor = list(MELEE = 20, BULLET = 10, LASER = 20, ENERGY = 0, BOMB = 60, BIO = 0, RAD = 70, FIRE = 100, ACID = 100)
+ flags_1 = HEAR_1 | RAD_PROTECT_CONTENTS_1 | RAD_NO_CONTAMINATE_1
+ armor = list(MELEE = 20, BULLET = 10, LASER = 20, ENERGY = 0, BOMB = 60, BIO = 0, RAD = 100, FIRE = 100, ACID = 100)
max_equip = 7
wreckage = /obj/structure/mecha_wreckage/clarke
enter_delay = 40
- canstrafe = FALSE
+ pivot_step = TRUE
/// Handles an internal ore box for Clarke
var/obj/structure/ore_box/box
omnidirectional_attacks = TRUE
@@ -50,6 +51,14 @@
var/mob/living/brain/B = M.brainmob
hud.show_to(B)
+/obj/mecha/working/clarke/domove(direction)
+ if(ISDIAGONALDIR(direction) && strafe)
+ if(EWCOMPONENT(dir))
+ direction &= ~(NORTH|SOUTH)
+ else if(NSCOMPONENT(dir))
+ direction &= ~(EAST|WEST)
+ return ..(direction)
+
//Ore Box Controls
///Special equipment for the Clarke mech, handles moving ore without giving the mech a hydraulic clamp and cargo compartment.
diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index 046ce62ff769..f9eb136da172 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -18,6 +18,9 @@
enclosed = FALSE //Normal ripley has an open cockpit design
enter_delay = 10 //can enter in a quarter of the time of other mechs
exit_delay = 10
+ /// Custom Ripley step and turning sounds (from TGMC)
+ stepsound = 'sound/mecha/powerloader_step.ogg'
+ turnsound = 'sound/mecha/powerloader_turn2.ogg'
opacity = FALSE //Ripley has a window
/obj/mecha/working/ripley/Move()
@@ -67,7 +70,8 @@
fast_pressure_step_in = 1.75 //step_in while in low pressure conditions
slow_pressure_step_in = 3 //step_in while in normal pressure conditions
step_in = 3
- armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 0, BOMB = 40, BIO = 100, RAD = 55, FIRE = 100, ACID = 100)
+ flags_1 = HEAR_1 | RAD_PROTECT_CONTENTS_1 | RAD_NO_CONTAMINATE_1
+ armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 0, BOMB = 40, BIO = 100, RAD = 100, FIRE = 100, ACID = 100)
wreckage = /obj/structure/mecha_wreckage/ripley/mkii
enclosed = TRUE
enter_delay = 40
@@ -80,12 +84,13 @@
icon_state = "firefighter"
max_temperature = 65000
max_integrity = 250
- fast_pressure_step_in = 2 //step_in while in low pressure conditions
- slow_pressure_step_in = 4 //step_in while in normal pressure conditions
- step_in = 4
+ fast_pressure_step_in = 1.75 //step_in while in low pressure conditions
+ slow_pressure_step_in = 3 //step_in while in normal pressure conditions
+ step_in = 3
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
light_power = 7
- armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 0, BOMB = 60, BIO = 100, RAD = 70, FIRE = 100, ACID = 100)
+ flags_1 = HEAR_1 | RAD_PROTECT_CONTENTS_1 | RAD_NO_CONTAMINATE_1
+ armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 0, BOMB = 60, BIO = 100, RAD = 100, FIRE = 100, ACID = 100)
max_equip = 5 // More armor, less tools
wreckage = /obj/structure/mecha_wreckage/ripley/firefighter
enclosed = TRUE
@@ -93,6 +98,15 @@
silicon_icon_state = null
opacity = TRUE
+// maybe janitor ERTs could get this or something?
+/obj/mecha/working/ripley/janitorial/Initialize(mapload)
+ . = ..()
+ var/obj/item/mecha_parts/mecha_equipment/washer = new /obj/item/mecha_parts/mecha_equipment/weapon/pressure_washer
+ washer.attach(src)
+ var/obj/item/mecha_parts/mecha_equipment/big_mop = new /obj/item/mecha_parts/mecha_equipment/melee_weapon/mop
+ big_mop.attach(src)
+ var/obj/item/mecha_parts/mecha_equipment/swatter = new /obj/item/mecha_parts/mecha_equipment/melee_weapon/flyswatter
+ swatter.attach(src)
/obj/mecha/working/ripley/deathripley
desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE"
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index 6d408ecaed6d..15b5bfe7d593 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -34,6 +34,10 @@
diseases_to_add += D
if(LAZYLEN(diseases_to_add))
AddComponent(/datum/component/infective, diseases_to_add)
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C) // Returns true if we should give up in favor of the pre-existing decal
if(mergeable_decal)
diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm
index e686f9b57948..f700c847f6ee 100644
--- a/code/game/objects/effects/decals/cleanable/humans.dm
+++ b/code/game/objects/effects/decals/cleanable/humans.dm
@@ -130,7 +130,7 @@
/obj/effect/decal/cleanable/blood/gibs/ex_act(severity, target)
return
-/obj/effect/decal/cleanable/blood/gibs/Crossed(atom/movable/L)
+/obj/effect/decal/cleanable/blood/gibs/on_entered(datum/source, atom/movable/L)
if(isliving(L) && has_gravity(loc))
playsound(loc, 'sound/effects/gib_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 20 : 50, TRUE)
. = ..()
diff --git a/code/game/objects/effects/effect_system/effects_other.dm b/code/game/objects/effects/effect_system/effects_other.dm
index 81f3330f53cf..83583f844b3f 100644
--- a/code/game/objects/effects/effect_system/effects_other.dm
+++ b/code/game/objects/effects/effect_system/effects_other.dm
@@ -11,7 +11,7 @@
var/active = FALSE
var/allow_overlap = FALSE
var/auto_process = TRUE
- var/qdel_in_time = 10
+ var/qdel_in_time = 1 SECONDS
var/fadetype = "ion_fade"
var/fade = TRUE
var/nograv_required = FALSE
@@ -65,6 +65,16 @@
/datum/effect_system/trail_follow/steam
effect_type = /obj/effect/particle_effect/steam
+/datum/effect_system/trail_follow/sparks
+ effect_type = /obj/effect/particle_effect/sparks
+ nograv_required = TRUE
+ fade = FALSE
+
+/datum/effect_system/trail_follow/smoke
+ effect_type = /obj/effect/particle_effect/fluid/smoke/trail
+ nograv_required = TRUE
+ fade = FALSE
+
/obj/effect/particle_effect/ion_trails
name = "ion trails"
icon_state = "ion_trails"
@@ -76,7 +86,7 @@
/datum/effect_system/trail_follow/ion
effect_type = /obj/effect/particle_effect/ion_trails
nograv_required = TRUE
- qdel_in_time = 20
+ qdel_in_time = 2 SECONDS
/datum/effect_system/trail_follow/proc/set_dir(obj/effect/particle_effect/ion_trails/I)
I.setDir(holder.dir)
diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm
index 585fe1433621..f02dfc5396a7 100644
--- a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm
+++ b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm
@@ -156,6 +156,19 @@
/obj/effect/particle_effect/fluid/smoke/transparent
opacity = FALSE
+/// Special smoke used for the RCS thruster
+/obj/effect/particle_effect/fluid/smoke/trail
+ lifetime = 1 SECONDS
+ opacity = FALSE
+ alpha = 100
+
+/obj/effect/particle_effect/fluid/smoke/trail/Initialize(mapload, datum/fluid_group/group, ...)
+ . = ..()
+ var/matrix/start_transform = matrix(transform)/2
+ var/matrix/end_transform = matrix(transform)
+ transform = start_transform
+ animate(src, alpha = 0, transform = end_transform, time = lifetime)
+
/**
* A helper proc used to spawn small puffs of smoke.
*
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index 930959270c27..691226b7836b 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -86,13 +86,23 @@
icon_state = "uglymine"
alpha = 30
var/triggered = 0
+ /// Can be set to FALSE if we want a short 'coming online' delay, then set to TRUE. Can still be set off by damage
+ var/armed = TRUE
var/smartmine = FALSE
var/disarm_time = 12 SECONDS
var/disarm_product = /obj/item/deployablemine // ie what drops when the mine is disarmed
+ /// Who's got their foot on the mine's pressure plate
+ /// Stepping on the mine will set this to the first mob who stepped over it
+ /// The mine will not detonate via movement unless the first mob steps off of it
+ var/datum/weakref/foot_on_mine
/obj/effect/mine/Initialize(mapload)
. = ..()
- layer = ABOVE_MOB_LAYER
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
+ COMSIG_ATOM_EXITED = PROC_REF(on_exited),
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
/obj/effect/mine/attackby(obj/I, mob/user, params)
if(istype(I, /obj/item/multitool))
@@ -107,18 +117,6 @@
/obj/effect/mine/proc/mineEffect(mob/victim)
to_chat(victim, span_danger("*click*"))
-/obj/effect/mine/Crossed(AM as mob|obj)
- . = ..()
- if(isturf(loc))
- if(ismob(AM))
- var/mob/MM = AM
- if(!(MM.movement_type & FLYING))
- checksmartmine(AM)
- else
- if(istype(AM, /obj/projectile))
- return
- triggermine(AM)
-
/obj/effect/mine/proc/checksmartmine(mob/target)
if(smartmine && target && !HAS_TRAIT(target, TRAIT_MINDSHIELD))
triggermine(target)
@@ -132,7 +130,7 @@
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(1, 0, src)
s.start()
- mineEffect(victim)
+ INVOKE_ASYNC(src, PROC_REF(mineEffect), victim)
triggered = 1
qdel(src)
@@ -257,7 +255,7 @@
/obj/effect/mine/pickup
name = "pickup"
- desc = "pick me up"
+ desc = "Pick me up."
icon = 'icons/effects/effects.dmi'
icon_state = "electricity2"
density = FALSE
@@ -360,3 +358,45 @@
/obj/effect/mine/creampie/mineEffect(mob/victim)
var/obj/item/reagent_containers/food/snacks/pie/cream/P = new /obj/item/reagent_containers/food/snacks/pie/cream(src)
P.splat(victim)
+
+/// Can this mine trigger on the passed movable?
+/obj/effect/mine/proc/can_trigger(atom/movable/on_who)
+ if(triggered || !isturf(loc) || iseffect(on_who))
+ return FALSE
+
+ var/mob/living/living_mob
+ if(ismob(on_who))
+ if(!isliving(on_who)) //no ghosties.
+ return FALSE
+ living_mob = on_who
+
+ if(living_mob?.incorporeal_move || (on_who.movement_type & MOVETYPES_NOT_TOUCHING_GROUND))
+ return foot_on_mine ? IS_WEAKREF_OF(on_who, foot_on_mine) : FALSE //Only go boom if their foot was on the mine PRIOR to flying/phasing. You fucked up, you live with the consequences.
+
+ return TRUE
+
+
+/obj/effect/mine/proc/on_entered(datum/source, atom/movable/arrived)
+ SIGNAL_HANDLER
+
+ if(!can_trigger(arrived))
+ return
+ // Someone already on it
+ if(foot_on_mine?.resolve())
+ return
+
+ foot_on_mine = WEAKREF(arrived)
+ visible_message(span_danger("[icon2html(src, viewers(src))] *click*"))
+ playsound(src, 'sound/machines/click.ogg', 60, TRUE)
+
+/obj/effect/mine/proc/on_exited(datum/source, atom/movable/gone)
+ // SIGNAL_HANDLER we're not ready for this
+
+ if(!can_trigger(gone))
+ return
+ // Check that the guy who's on it is stepping off
+ if(foot_on_mine && !IS_WEAKREF_OF(gone, foot_on_mine))
+ return
+
+ triggermine(gone)
+ foot_on_mine = null
diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm
index f32892331598..f0ab2f890b99 100644
--- a/code/game/objects/items/RCD.dm
+++ b/code/game/objects/items/RCD.dm
@@ -1,6 +1,3 @@
-#define GLOW_MODE 3
-#define LIGHT_MODE 2
-#define REMOVE_MODE 1
/*
CONTAINS:
@@ -41,6 +38,7 @@ RLD
var/linked_switch_id = null //integer variable, the id for the assigned conveyor switch
var/obj/machinery/conveyor/last_placed
var/color_choice = null
+ var/silent = FALSE // does it make sound? (used for mime mech RCD)
/obj/item/construction/Initialize(mapload)
. = ..()
@@ -50,13 +48,20 @@ RLD
if(upgrade & RCD_UPGRADE_SILO_LINK)
silo_mats = AddComponent(/datum/component/remote_materials, "RCD", mapload, FALSE)
+/// Used for examining the RCD and for its UI
+/obj/item/construction/proc/get_silo_iron()
+ if(silo_link && silo_mats.mat_container && !silo_mats.on_hold())
+ return silo_mats.mat_container.get_material_amount(/datum/material/iron)/500
+ return FALSE
+
/obj/item/construction/examine(mob/user)
. = ..()
. += "It currently holds [matter]/[max_matter] matter-units."
if(upgrade & RCD_UPGRADE_SILO_LINK)
. += "Remote storage link state: [silo_link ? "[silo_mats.on_hold() ? "ON HOLD" : "ON"]" : "OFF"]."
- if(silo_link && silo_mats.mat_container && !silo_mats.on_hold())
- . += "Remote connection has iron in equivalent to [silo_mats.mat_container.get_material_amount(/datum/material/iron)/500] RCD unit\s." //1 matter for 1 floor tile, as 4 tiles are produced from 1 metal
+ var/iron = get_silo_iron()
+ if(iron)
+ . += "Remote connection has iron in equivalent to [iron] RCD unit\s." //1 matter for 1 floor tile, as 4 tiles are produced from 1 metal
/obj/item/construction/Destroy()
QDEL_NULL(spark_system)
@@ -90,13 +95,15 @@ RLD
upgrade |= rcd_up.upgrade
if((rcd_up.upgrade & RCD_UPGRADE_SILO_LINK) && !silo_mats)
silo_mats = AddComponent(/datum/component/remote_materials, "RCD", FALSE, FALSE)
- playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
+ if(!silent)
+ playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
qdel(rcd_up)
/// Inserts matter into the RCD allowing it to build
/obj/item/construction/proc/insert_matter(obj/O, mob/user)
if(iscyborg(user))
return FALSE
+
var/loaded = FALSE
if(istype(O, /obj/item/rcd_ammo))
var/obj/item/rcd_ammo/R = O
@@ -108,7 +115,8 @@ RLD
if(R.ammoamt <= 0)
qdel(R)
matter += load
- playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
+ if(!silent)
+ playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
loaded = TRUE
else if(istype(O, /obj/item/stack))
loaded = loadwithsheets(O, user)
@@ -127,17 +135,20 @@ RLD
var/amount_to_use = min(S.amount, maxsheets)
S.use(amount_to_use)
matter += value*amount_to_use
- playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
+ if(!silent)
+ playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
to_chat(user, span_notice("You insert [amount_to_use] [S.name] sheets into [src]. "))
return TRUE
to_chat(user, span_warning("You can't insert any more [S.name] sheets into [src]!"))
return FALSE
/obj/item/construction/proc/activate()
- playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE)
+ if(!silent)
+ playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE)
/obj/item/construction/attack_self(mob/user)
- playsound(src.loc, 'sound/effects/pop.ogg', 50, FALSE)
+ if(!silent)
+ playsound(src.loc, 'sound/effects/pop.ogg', 50, FALSE)
if(prob(20))
spark_system.start()
@@ -169,6 +180,39 @@ RLD
silo_mats.silo_log(src, "consume", -amount, "build", materials)
return TRUE
+/obj/item/construction/ui_data(mob/user)
+ var/list/data = list()
+
+ //matter in the rcd
+ var/total_matter = ((upgrade & RCD_UPGRADE_SILO_LINK) && silo_link) ? get_silo_iron() : matter
+ if(!total_matter)
+ total_matter = 0
+ data["matterLeft"] = total_matter
+
+ //silo details
+ data["silo_upgraded"] = !!(upgrade & RCD_UPGRADE_SILO_LINK)
+ data["silo_enabled"] = silo_link
+
+ return data
+
+///shared action for toggling silo link rcd,rld & plumbing
+/obj/item/construction/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return
+
+ if(action == "toggle_silo")
+ if(silo_mats)
+ if(!silo_mats.mat_container && !silo_link) // Allow them to turn off an invalid link
+ to_chat(usr, span_alert("No silo link detected. Connect to silo via multitool."))
+ return FALSE
+ silo_link = !silo_link
+ to_chat(usr, span_notice("You change [src]'s storage link state: [silo_link ? "ON" : "OFF"]."))
+ else
+ to_chat(usr, span_warning("[src] doesn't have remote storage connection."))
+ return TRUE
+ return FALSE
+
/obj/item/construction/proc/checkResource(amount, mob/user)
if(!silo_link || !silo_mats || !silo_mats.mat_container)
. = matter >= amount
@@ -213,6 +257,27 @@ RLD
return FALSE
return TRUE
+///each define maps to a variable used for construction in the RCD
+#define CONSTRUCTION_MODE "construction_mode"
+#define WINDOW_TYPE "window_type"
+#define WINDOW_GLASS "window_glass"
+#define WINDOW_SIZE "window_size"
+#define COMPUTER_DIR "computer_dir"
+#define FURNISH_TYPE "furnish_type"
+#define FURNISH_COST "furnish_cost"
+#define FURNISH_DELAY "furnish_delay"
+#define AIRLOCK_TYPE "airlock_type"
+#define CONVEYOR_TYPE "conveyor_type"
+
+///flags to be sent to UI
+#define TITLE "title"
+#define ICON "icon"
+
+///flags for creating icons shared by an entire category
+#define CATEGORY_ICON_STATE "category_icon_state"
+#define CATEGORY_ICON_SUFFIX "category_icon_suffix"
+#define TITLE_ICON "ICON=TITLE"
+
/obj/item/construction/rcd
name = "rapid-construction-device (RCD)"
icon = 'icons/obj/tools.dmi'
@@ -224,7 +289,104 @@ RLD
slot_flags = ITEM_SLOT_BELT
item_flags = NO_MAT_REDEMPTION | NOBLUDGEON
has_ammobar = TRUE
- var/mode = RCD_FLOORWALL
+
+ ///all stuff used by RCD for construction
+ var/static/list/root_categories = list(
+ //1ST ROOT CATEGORY
+ "Construction" = list( //Stuff you use to make & decorate areas
+ //Walls & Windows
+ "Structures" = list(
+ list(CONSTRUCTION_MODE = RCD_FLOORWALL, ICON = "wallfloor", TITLE = "Wall/Floor"),
+ list(CONSTRUCTION_MODE = RCD_DECONSTRUCT, ICON = "delete", TITLE = "Deconstruct"),
+ list(CONSTRUCTION_MODE = RCD_WINDOWGRILLE, WINDOW_TYPE = /obj/structure/window, WINDOW_GLASS = RCD_WINDOW_NORMAL, WINDOW_SIZE = RCD_WINDOW_DIRECTIONAL, ICON = "dirwindow", TITLE = "Directional Window"),
+ list(CONSTRUCTION_MODE = RCD_WINDOWGRILLE, WINDOW_TYPE = /obj/structure/window/fulltile, WINDOW_GLASS = RCD_WINDOW_NORMAL, WINDOW_SIZE = RCD_WINDOW_FULLTILE, ICON = "fullwindow", TITLE = "Full Tile Window"),
+ list(CONSTRUCTION_MODE = RCD_WINDOWGRILLE, WINDOW_TYPE = /obj/structure/window/reinforced, WINDOW_GLASS = RCD_WINDOW_REINFORCED, WINDOW_SIZE = RCD_WINDOW_DIRECTIONAL, ICON = "dirwindow_r", TITLE = "Directional Reinforced Window"),
+ list(CONSTRUCTION_MODE = RCD_WINDOWGRILLE, WINDOW_TYPE = /obj/structure/window/reinforced/fulltile, WINDOW_GLASS = RCD_WINDOW_REINFORCED, WINDOW_SIZE = RCD_WINDOW_FULLTILE, ICON = "fullwindow_r", TITLE = "Full Tile Reinforced Window"),
+ ),
+
+ //Computers & Machine Frames
+ "Machines" = list(
+ list(CONSTRUCTION_MODE = RCD_MACHINE, ICON = "box_1", TITLE = "Machine Frame"),
+ list(CONSTRUCTION_MODE = RCD_COMPUTER, COMPUTER_DIR = 1, ICON = "cnorth", TITLE = "Computer North"),
+ list(CONSTRUCTION_MODE = RCD_COMPUTER, COMPUTER_DIR = 2, ICON = "csouth", TITLE = "Computer South"),
+ list(CONSTRUCTION_MODE = RCD_COMPUTER, COMPUTER_DIR = 4, ICON = "ceast", TITLE = "Computer East"),
+ list(CONSTRUCTION_MODE = RCD_COMPUTER, COMPUTER_DIR = 8, ICON = "cwest", TITLE = "Computer West"),
+ ),
+
+ //Interior Design[construction_mode = RCD_FURNISHING is implied]
+ "Furniture" = list(
+ list(FURNISH_TYPE = /obj/structure/chair, FURNISH_COST = 8, FURNISH_DELAY = 10, ICON = "chair", TITLE = "Chair"),
+ list(FURNISH_TYPE = /obj/structure/chair/stool, FURNISH_COST = 8, FURNISH_DELAY = 10, ICON = "stool", TITLE = "Stool"),
+ list(FURNISH_TYPE = /obj/structure/table, FURNISH_COST = 16, FURNISH_DELAY = 20, ICON = "table",TITLE = "Table"),
+ list(FURNISH_TYPE = /obj/structure/table/glass, FURNISH_COST = 16, FURNISH_DELAY = 20, ICON = "glass_table", TITLE = "Glass Table"),
+ ),
+
+ //Conveyors & Switches
+ "Conveyors" = list(
+ list(CONSTRUCTION_MODE = RCD_CONVEYOR, ICON = "conveyor_construct", TITLE = "Conveyor Belt"),
+ list(CONSTRUCTION_MODE = RCD_SWITCH, ICON = "switch-off", TITLE = "Conveyor Switch"),
+ )
+ ),
+
+ //2ND ROOT CATEGORY[construction_mode = RCD_AIRLOCK is implied,"icon=closed"]
+ "Airlocks" = list( //used to seal/close areas
+ //Solid Airlocks[airlock_glass = FALSE is implied,no fill_closed overlay]
+ "Solid Airlocks" = list(
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock, TITLE = "Standard", CATEGORY_ICON_STATE = TITLE_ICON),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/public, TITLE = "Public"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/engineering, TITLE = "Engineering"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/atmos, TITLE = "Atmospherics"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/security, TITLE = "Security"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/command, TITLE = "Command"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/medical, TITLE = "Medical"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/research, TITLE = "Research"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/freezer, TITLE = "Freezer"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/virology, TITLE = "Virology"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/mining, TITLE = "Mining"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/maintenance, TITLE = "Maintenance"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/external, TITLE = "External"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/maintenance/external, TITLE = "External Maintenance"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/hatch, TITLE = "Airtight Hatch"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/maintenance_hatch, TITLE = "Maintenance Hatch"),
+ ),
+
+ //Glass Airlocks[airlock_glass = TRUE is implied,do fill_closed overlay]
+ "Glass Airlocks" = list(
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/glass, TITLE = "Standard", CATEGORY_ICON_STATE = TITLE_ICON, CATEGORY_ICON_SUFFIX = "Glass"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/public/glass, TITLE = "Public"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/engineering/glass, TITLE = "Engineering"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/atmos/glass, TITLE = "Atmospherics"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/security/glass, TITLE = "Security"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/command/glass, TITLE = "Command"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/medical/glass, TITLE = "Medical"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/research/glass, TITLE = "Research"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/virology/glass, TITLE = "Virology"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/mining/glass, TITLE = "Mining"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/maintenance/glass, TITLE = "Maintenance"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/external/glass, TITLE = "External"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/airlock/maintenance/external/glass, TITLE = "External Maintenance"),
+ ),
+
+ //Window Doors[airlock_glass = TRUE is implied]
+ "Windoors" = list(
+ list(AIRLOCK_TYPE = /obj/machinery/door/window, ICON = "windoor", TITLE = "Windoor"),
+ list(AIRLOCK_TYPE = /obj/machinery/door/window/brigdoor, ICON = "secure_windoor", TITLE = "Secure Windoor"),
+ ),
+ ),
+
+ //3RD CATEGORY Airlock access,empty list cause airlock_electronics UI will be displayed when this tab is selected
+ "Airlock Access" = list()
+ )
+
+ ///english name for the design to check if it was selected or not
+ var/design_title = "Wall/Floor"
+ var/design_category = "Structures"
+ var/root_category = "Construction"
+ var/closed = FALSE
+ ///owner of this rcd. It can either be an construction console or an player
+ var/owner
+
+ var/construction_mode = RCD_FLOORWALL
var/ranged = FALSE
var/computer_dir = 1
var/airlock_type = /obj/machinery/door/airlock
@@ -244,7 +406,7 @@ RLD
var/obj/item/electronics/airlock/airlock_electronics
/obj/item/construction/rcd/suicide_act(mob/user)
- mode = RCD_FLOORWALL
+ construction_mode = RCD_FLOORWALL
if(!rcd_create(get_turf(user), user))
return SHAME
if(isfloorturf(get_turf(user)))
@@ -252,350 +414,39 @@ RLD
user.visible_message(span_suicide("[user] sets the RCD to 'Wall' and points it down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide.."))
return (BRUTELOSS)
-/obj/item/construction/rcd/verb/toggle_window_glass_verb()
- set name = "RCD : Toggle Window Glass"
- set category = "Object"
- set src in view(1)
-
- if(!usr.canUseTopic(src, BE_CLOSE))
- return
-
- toggle_window_glass(usr)
-
-/obj/item/construction/rcd/verb/toggle_window_size_verb()
- set name = "RCD : Toggle Window Size"
- set category = "Object"
- set src in view(1)
-
- if(!usr.canUseTopic(src, BE_CLOSE))
- return
-
- toggle_window_size(usr)
-
-/obj/item/construction/rcd/proc/toggle_access(acc)
- if (acc == "all")
- conf_access = null
- else if(acc == "one")
- use_one_access = !use_one_access
- else
- var/req = text2num(acc)
-
- if (conf_access == null)
- conf_access = list()
-
- if (!(req in conf_access))
- conf_access += req
- else
- conf_access -= req
- if (!conf_access.len)
- conf_access = null
-
-/// Toggles the usage of reinforced or normal glass
-/obj/item/construction/rcd/proc/toggle_window_glass(mob/user)
- if (window_glass != RCD_WINDOW_REINFORCED)
- set_window_type(user, RCD_WINDOW_REINFORCED, window_size)
- return
- set_window_type(user, RCD_WINDOW_NORMAL, window_size)
-
-/// Toggles the usage of directional or full tile windows
-/obj/item/construction/rcd/proc/toggle_window_size(mob/user)
- if (window_size != RCD_WINDOW_DIRECTIONAL)
- set_window_type(user, window_glass, RCD_WINDOW_DIRECTIONAL)
- return
- set_window_type(user, window_glass, RCD_WINDOW_FULLTILE)
-
-/// Sets the window type to be created based on parameters
-/obj/item/construction/rcd/proc/set_window_type(mob/user, glass, size)
- window_glass = glass
- window_size = size
- if(window_glass == RCD_WINDOW_REINFORCED)
- if(window_size == RCD_WINDOW_DIRECTIONAL)
- window_type = /obj/structure/window/reinforced
- else
- window_type = /obj/structure/window/reinforced/fulltile
- else
- if(window_size == RCD_WINDOW_DIRECTIONAL)
- window_type = /obj/structure/window
- else
- window_type = /obj/structure/window/fulltile
-
- to_chat(user, span_notice("You change \the [src]'s window mode to [window_size] [window_glass] window."))
-
-/obj/item/construction/rcd/proc/toggle_silo_link(mob/user)
- if(silo_mats)
- if(!silo_mats.mat_container)
- to_chat(user, span_alert("No silo link detected. Connect to silo via multitool."))
- return FALSE
- silo_link = !silo_link
- to_chat(user, span_notice("You change \the [src]'s storage link state: [silo_link ? "ON" : "OFF"]."))
- else
- to_chat(user, span_warning("\the [src] doesn't have remote storage connection."))
-
-/obj/item/construction/rcd/proc/get_airlock_image(airlock_type)
- var/obj/machinery/door/airlock/proto = airlock_type
- var/ic = initial(proto.icon)
- var/mutable_appearance/MA = mutable_appearance(ic, "closed")
- if(!initial(proto.glass))
- MA.overlays += "fill_closed"
- //Not scaling these down to button size because they look horrible then, instead just bumping up radius.
- return MA
-
-/obj/item/construction/rcd/proc/change_computer_dir(mob/user)
- if(!user)
- return
- var/list/computer_dirs = list(
- "NORTH" = image(icon = 'icons/mob/radial.dmi', icon_state = "cnorth"),
- "EAST" = image(icon = 'icons/mob/radial.dmi', icon_state = "ceast"),
- "SOUTH" = image(icon = 'icons/mob/radial.dmi', icon_state = "csouth"),
- "WEST" = image(icon = 'icons/mob/radial.dmi', icon_state = "cwest")
- )
- var/computerdirs = show_radial_menu(user, src, computer_dirs, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE)
- if(!check_menu(user))
- return
- switch(computerdirs)
- if("NORTH")
- computer_dir = 1
- if("EAST")
- computer_dir = 4
- if("SOUTH")
- computer_dir = 2
- if("WEST")
- computer_dir = 8
-
-/**
- * Customizes RCD's airlock settings based on user's choices
- *
- * Arguments:
- * * user The mob that is choosing airlock settings
- * * remote_anchor The remote anchor for radial menus. If set, it will also remove proximity restrictions from the menus
- */
-/obj/item/construction/rcd/proc/change_airlock_setting(mob/user, remote_anchor)
- if(!user)
- return
-
- var/list/solid_or_glass_choices = list(
- "Solid" = get_airlock_image(/obj/machinery/door/airlock),
- "Glass" = get_airlock_image(/obj/machinery/door/airlock/glass),
- "Windoor" = image(icon = 'icons/mob/radial.dmi', icon_state = "windoor"),
- "Secure Windoor" = image(icon = 'icons/mob/radial.dmi', icon_state = "secure_windoor")
- )
-
- var/list/solid_choices = list(
- "Standard" = get_airlock_image(/obj/machinery/door/airlock),
- "Public" = get_airlock_image(/obj/machinery/door/airlock/public),
- "Engineering" = get_airlock_image(/obj/machinery/door/airlock/engineering),
- "Atmospherics" = get_airlock_image(/obj/machinery/door/airlock/atmos),
- "Security" = get_airlock_image(/obj/machinery/door/airlock/security),
- "Command" = get_airlock_image(/obj/machinery/door/airlock/command),
- "Medical" = get_airlock_image(/obj/machinery/door/airlock/medical),
- "Research" = get_airlock_image(/obj/machinery/door/airlock/research),
- "Freezer" = get_airlock_image(/obj/machinery/door/airlock/freezer),
- "Science" = get_airlock_image(/obj/machinery/door/airlock/science),
- "Virology" = get_airlock_image(/obj/machinery/door/airlock/virology),
- "Mining" = get_airlock_image(/obj/machinery/door/airlock/mining),
- "Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance),
- "External" = get_airlock_image(/obj/machinery/door/airlock/external),
- "External Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/external),
- "Airtight Hatch" = get_airlock_image(/obj/machinery/door/airlock/hatch),
- "Maintenance Hatch" = get_airlock_image(/obj/machinery/door/airlock/maintenance_hatch)
- )
-
- var/list/glass_choices = list(
- "Standard" = get_airlock_image(/obj/machinery/door/airlock/glass),
- "Public" = get_airlock_image(/obj/machinery/door/airlock/public/glass),
- "Engineering" = get_airlock_image(/obj/machinery/door/airlock/engineering/glass),
- "Atmospherics" = get_airlock_image(/obj/machinery/door/airlock/atmos/glass),
- "Security" = get_airlock_image(/obj/machinery/door/airlock/security/glass),
- "Command" = get_airlock_image(/obj/machinery/door/airlock/command/glass),
- "Medical" = get_airlock_image(/obj/machinery/door/airlock/medical/glass),
- "Research" = get_airlock_image(/obj/machinery/door/airlock/research/glass),
- "Science" = get_airlock_image(/obj/machinery/door/airlock/science/glass),
- "Virology" = get_airlock_image(/obj/machinery/door/airlock/virology/glass),
- "Mining" = get_airlock_image(/obj/machinery/door/airlock/mining/glass),
- "Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/glass),
- "External" = get_airlock_image(/obj/machinery/door/airlock/external/glass),
- "External Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/external/glass)
- )
-
- var/airlockcat = show_radial_menu(user, remote_anchor || src, solid_or_glass_choices, custom_check = CALLBACK(src, PROC_REF(check_menu), user, remote_anchor), require_near = remote_anchor ? FALSE : TRUE, tooltips = TRUE)
- switch(airlockcat)
- if("Solid")
- if(advanced_airlock_setting == 1)
- var/airlockpaint = show_radial_menu(user, remote_anchor || src, solid_choices, radius = 42, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = remote_anchor ? FALSE : TRUE, tooltips = TRUE)
- switch(airlockpaint)
- if("Standard")
- airlock_type = /obj/machinery/door/airlock
- if("Public")
- airlock_type = /obj/machinery/door/airlock/public
- if("Engineering")
- airlock_type = /obj/machinery/door/airlock/engineering
- if("Atmospherics")
- airlock_type = /obj/machinery/door/airlock/atmos
- if("Security")
- airlock_type = /obj/machinery/door/airlock/security
- if("Command")
- airlock_type = /obj/machinery/door/airlock/command
- if("Medical")
- airlock_type = /obj/machinery/door/airlock/medical
- if("Research")
- airlock_type = /obj/machinery/door/airlock/research
- if("Freezer")
- airlock_type = /obj/machinery/door/airlock/freezer
- if("Science")
- airlock_type = /obj/machinery/door/airlock/science
- if("Virology")
- airlock_type = /obj/machinery/door/airlock/virology
- if("Mining")
- airlock_type = /obj/machinery/door/airlock/mining
- if("Maintenance")
- airlock_type = /obj/machinery/door/airlock/maintenance
- if("External")
- airlock_type = /obj/machinery/door/airlock/external
- if("External Maintenance")
- airlock_type = /obj/machinery/door/airlock/maintenance/external
- if("Airtight Hatch")
- airlock_type = /obj/machinery/door/airlock/hatch
- if("Maintenance Hatch")
- airlock_type = /obj/machinery/door/airlock/maintenance_hatch
- airlock_glass = FALSE
- else
- airlock_type = /obj/machinery/door/airlock
- airlock_glass = FALSE
-
- if("Glass")
- if(advanced_airlock_setting == 1)
- var/airlockpaint = show_radial_menu(user, remote_anchor || src, glass_choices, radius = 42, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = remote_anchor ? FALSE : TRUE, tooltips = TRUE)
- if(!check_menu(user))
- return
- switch(airlockpaint)
- if("Standard")
- airlock_type = /obj/machinery/door/airlock/glass
- if("Public")
- airlock_type = /obj/machinery/door/airlock/public/glass
- if("Engineering")
- airlock_type = /obj/machinery/door/airlock/engineering/glass
- if("Atmospherics")
- airlock_type = /obj/machinery/door/airlock/atmos/glass
- if("Security")
- airlock_type = /obj/machinery/door/airlock/security/glass
- if("Command")
- airlock_type = /obj/machinery/door/airlock/command/glass
- if("Medical")
- airlock_type = /obj/machinery/door/airlock/medical/glass
- if("Research")
- airlock_type = /obj/machinery/door/airlock/research/glass
- if("Science")
- airlock_type = /obj/machinery/door/airlock/science/glass
- if("Virology")
- airlock_type = /obj/machinery/door/airlock/virology/glass
- if("Mining")
- airlock_type = /obj/machinery/door/airlock/mining/glass
- if("Maintenance")
- airlock_type = /obj/machinery/door/airlock/maintenance/glass
- if("External")
- airlock_type = /obj/machinery/door/airlock/external/glass
- if("External Maintenance")
- airlock_type = /obj/machinery/door/airlock/maintenance/external/glass
- airlock_glass = TRUE
- else
- airlock_type = /obj/machinery/door/airlock/glass
- airlock_glass = TRUE
- if("Windoor")
- airlock_type = /obj/machinery/door/window
- airlock_glass = TRUE
- if("Secure Windoor")
- airlock_type = /obj/machinery/door/window/brigdoor
- airlock_glass = TRUE
- else
- airlock_type = /obj/machinery/door/airlock
- airlock_glass = FALSE
-
-/// Radial menu for choosing the object you want to be created with the furnishing mode
-/obj/item/construction/rcd/proc/change_furnishing_type(mob/user)
- if(!user)
- return
- var/static/list/choices = list(
- "Chair" = image(icon = 'icons/mob/radial.dmi', icon_state = "chair"),
- "Stool" = image(icon = 'icons/mob/radial.dmi', icon_state = "stool"),
- "Table" = image(icon = 'icons/mob/radial.dmi', icon_state = "table"),
- "Glass Table" = image(icon = 'icons/mob/radial.dmi', icon_state = "glass_table")
- )
- var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE)
- if(!check_menu(user))
- return
- switch(choice)
- if("Chair")
- furnish_type = /obj/structure/chair
- furnish_cost = 8
- furnish_delay = 10
- if("Stool")
- furnish_type = /obj/structure/chair/stool
- furnish_cost = 8
- furnish_delay = 10
- if("Table")
- furnish_type = /obj/structure/table
- furnish_cost = 16
- furnish_delay = 20
- if("Glass Table")
- furnish_type = /obj/structure/table/glass
- furnish_cost = 16
- furnish_delay = 20
-
/obj/item/construction/rcd/proc/rcd_create(atom/A, mob/user)
var/list/rcd_results = A.rcd_vals(user, src)
if(!rcd_results)
return FALSE
var/delay = rcd_results["delay"] * delay_mod
- var/obj/effect/constructing_effect/rcd_effect = new(get_turf(A), delay, src.mode)
+ var/obj/effect/constructing_effect/rcd_effect = new(get_turf(A), delay, src.construction_mode)
+ var/datum/beam/rcd_beam
if(checkResource(rcd_results["cost"], user))
- if(do_after(user, delay, A))
+ if(!A.Adjacent(owner ? owner : user)) // ranged RCDs create beams
+ if(isatom(owner))
+ var/atom/owner_atom = owner
+ rcd_beam = owner_atom.Beam(A,icon_state="rped_upgrade",time=delay)
+ else
+ rcd_beam = Beam(A,icon_state="rped_upgrade",time=delay)
+ if(do_after(user, delay, (owner ? owner : A)))
if(checkResource(rcd_results["cost"], user))
if(A.rcd_act(user, src, rcd_results["mode"]))
rcd_effect.end_animation()
useResource(rcd_results["cost"], user)
activate()
- playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
+ if(!silent)
+ playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
return TRUE
+ if(rcd_beam)
+ qdel(rcd_beam)
qdel(rcd_effect)
return FALSE
-/obj/item/construction/rcd/proc/rcd_switch(atom/A, mob/user)
- var/cost = 1
- var/delay = 1
- var/obj/effect/constructing_effect/rcd_effect = new(get_turf(A), delay, src.mode)
- if(checkResource(cost, user))
- if(do_after(user, delay, A))
- if(checkResource(cost, user))
- rcd_effect.end_animation()
- useResource(cost, user)
- activate()
- playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
- new /obj/item/conveyor_switch_construct(A)
- qdel(rcd_effect)
-
-/obj/item/construction/rcd/proc/rcd_conveyor(atom/A, mob/user)
- var/delay = 5
- var/cost = 5
- var/obj/effect/constructing_effect/rcd_effect = new(get_turf(A), delay, src.mode)
- if(checkResource(cost, user))
- if(do_after(user, delay, target = A))
- if(checkResource(cost, user))
- rcd_effect.end_animation()
- useResource(cost, user)
- activate()
- playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
- var/cdir = get_dir(A, user)
- if (last_placed)
- cdir = get_dir(A, last_placed)
- if(cdir in GLOB.cardinals)
- last_placed.setDir(get_dir(last_placed, A))
- last_placed = new/obj/machinery/conveyor(A, cdir, linked_switch_id)
- qdel(rcd_effect)
-
/obj/item/construction/rcd/Initialize(mapload)
. = ..()
airlock_electronics = new(src)
airlock_electronics.name = "Access Control"
+ airlock_electronics.holder = src
GLOB.rcd_list += src
/obj/item/construction/rcd/Destroy()
@@ -603,127 +454,174 @@ RLD
GLOB.rcd_list -= src
. = ..()
-/obj/item/construction/rcd/attack_self(mob/user)
- ..()
- var/list/choices = list(
- "Airlock" = image(icon = 'icons/mob/radial.dmi', icon_state = "airlock"),
- "Deconstruct" = image(icon= 'icons/mob/radial.dmi', icon_state = "delete"),
- "Grilles & Windows" = image(icon = 'icons/mob/radial.dmi', icon_state = "grillewindow"),
- "Floors & Walls" = image(icon = 'icons/mob/radial.dmi', icon_state = "wallfloor")
+/obj/item/construction/rcd/ui_host(mob/user)
+ return owner || ..()
+
+/obj/item/construction/rcd/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/rcd)
+ assets.send(user)
+ ui = new(user, src, "RapidConstructionDevice", name)
+ ui.open()
+
+/obj/item/construction/rcd/ui_static_data(mob/user)
+ return airlock_electronics.ui_static_data(user)
+
+/obj/item/construction/rcd/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/rcd),
)
- if(upgrade & RCD_UPGRADE_FRAMES)
- choices += list(
- "Machine Frames" = image(icon = 'icons/mob/radial.dmi', icon_state = "machine"),
- "Computer Frames" = image(icon = 'icons/mob/radial.dmi', icon_state = "computer_dir"),
- )
- if(upgrade & RCD_UPGRADE_SILO_LINK)
- choices += list(
- "Silo Link" = image(icon = 'icons/obj/mining.dmi', icon_state = "silo"),
- )
- if(upgrade & RCD_UPGRADE_FURNISHING)
- choices += list(
- "Furnishing" = image(icon = 'icons/mob/radial.dmi', icon_state = "chair")
- )
- if(mode == RCD_AIRLOCK)
- choices += list(
- "Change Access" = image(icon = 'icons/mob/radial.dmi', icon_state = "access"),
- "Change Airlock Type" = image(icon = 'icons/mob/radial.dmi', icon_state = "airlocktype")
- )
- else if(mode == RCD_WINDOWGRILLE)
- choices += list(
- "Change Window Glass" = image(icon = 'icons/mob/radial.dmi', icon_state = "windowtype"),
- "Change Window Size" = image(icon = 'icons/mob/radial.dmi', icon_state = "windowsize")
- )
- else if(mode == RCD_FURNISHING)
- choices += list(
- "Change Furnishing Type" = image(icon = 'icons/mob/radial.dmi', icon_state = "chair")
- )
- if(upgrade & RCD_UPGRADE_CONVEYORS)
- choices += list(
- "Conveyor" = image(icon = 'icons/obj/recycling.dmi', icon_state = "conveyor_construct"),
- "Switch" = image(icon = 'icons/obj/recycling.dmi', icon_state = "switch-off")
- )
- var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE)
- if(!check_menu(user))
+
+/obj/item/construction/rcd/ui_data(mob/user)
+ var/list/data = ..()
+
+ //main categories
+ data["selected_root"] = root_category
+ data["root_categories"] = list()
+ for(var/category in root_categories)
+ data["root_categories"] += category
+
+ //create the category list
+ data["selected_category"] = design_category
+ data["selected_design"] = design_title
+ data["categories"] = list()
+
+ var/category_icon_state
+ var/category_icon_suffix
+ for(var/list/sub_category as anything in root_categories[root_category])
+ var/list/target_category = root_categories[root_category][sub_category]
+ if(target_category.len == 0)
+ continue
+
+ //skip category if upgrades were not installed for these
+ if(sub_category == "Machines" && !(upgrade & RCD_UPGRADE_FRAMES))
+ continue
+ if(sub_category == "Furniture" && !(upgrade & RCD_UPGRADE_FURNISHING))
+ continue
+ if(sub_category == "Conveyors" && !(upgrade & RCD_UPGRADE_CONVEYORS))
+ continue
+ category_icon_state = ""
+ category_icon_suffix = ""
+
+ var/list/designs = list() //initialize all designs under this category
+ for(var/i in 1 to target_category.len)
+ var/list/design = target_category[i]
+
+ //check for special icon flags
+ if(design[CATEGORY_ICON_STATE] != null)
+ category_icon_state = design[CATEGORY_ICON_STATE]
+ if(design[CATEGORY_ICON_SUFFIX] != null)
+ category_icon_suffix = design[CATEGORY_ICON_SUFFIX]
+
+ //get icon or create it from pre defined flags
+ var/icon_state
+ if(design[ICON] != null)
+ icon_state = design[ICON]
+ else
+ icon_state = category_icon_state
+ if(icon_state == TITLE_ICON)
+ icon_state = design[TITLE]
+ icon_state = "[icon_state][category_icon_suffix]"
+
+ //sanitize them so you dont go insane when icon names contain spaces in them
+ icon_state = sanitize_css_class_name(icon_state)
+
+ designs += list(list("design_id" = i, TITLE = design[TITLE], ICON = icon_state))
+ data["categories"] += list(list("cat_name" = sub_category, "designs" = designs))
+
+ //merge airlock_electronics ui data with this
+ var/list/airlock_data = airlock_electronics.ui_data(user)
+ for(var/key in airlock_data)
+ data[key] = airlock_data[key]
+
+ return data
+
+
+/obj/item/construction/rcd/ui_act(action, params)
+ . = ..()
+ if(.)
return
- switch(choice)
- if("Floors & Walls")
- mode = RCD_FLOORWALL
- if("Airlock")
- mode = RCD_AIRLOCK
- if("Deconstruct")
- mode = RCD_DECONSTRUCT
- if("Grilles & Windows")
- mode = RCD_WINDOWGRILLE
- if("Machine Frames")
- mode = RCD_MACHINE
- if("Furnishing")
- mode = RCD_FURNISHING
- if("Computer Frames")
- mode = RCD_COMPUTER
- change_computer_dir(user)
- return
- if("Change Access")
- airlock_electronics.ui_interact(user)
- return
- if("Change Airlock Type")
- change_airlock_setting(user)
- return
- if("Change Window Glass")
- toggle_window_glass(user)
- return
- if("Change Window Size")
- toggle_window_size(user)
- return
- if("Change Furnishing Type")
- change_furnishing_type(user)
- return
- if("Silo Link")
- toggle_silo_link(user)
- return
- if("Conveyor")
- mode = RCD_CONVEYOR
- linked_switch_id = null
- last_placed = null
- if("Switch")
- mode = RCD_SWITCH
- else
- return
- playsound(src, 'sound/effects/pop.ogg', 50, FALSE)
- to_chat(user, span_notice("You change RCD's mode to '[choice]'."))
+
+ switch(action)
+ if("root_category")
+ var/new_root = params["root_category"]
+ if(root_categories[new_root] != null) //is a valid category
+ root_category = new_root
+
+ if("design")
+ var/category_name = params["category"]
+ var/index = params["index"]
+
+ var/list/root = root_categories[root_category]
+ if(root == null) //not a valid root
+ return TRUE
+ var/list/category = root[category_name]
+ if(category == null) //not a valid category
+ return TRUE
+ var/list/design = category[index]
+ if(design == null) //not a valid design
+ return TRUE
+
+ design_category = category_name
+ design_title = design["title"]
+
+ if(category_name == "Structures")
+ construction_mode = design[CONSTRUCTION_MODE]
+ if(design[WINDOW_TYPE] != null)
+ window_type = design[WINDOW_TYPE]
+ if(design[WINDOW_GLASS] != null)
+ window_glass = design[WINDOW_GLASS]
+ if(design[WINDOW_SIZE] != null)
+ window_size = design[WINDOW_SIZE]
+ else if(category_name == "Machines")
+ construction_mode = design[CONSTRUCTION_MODE]
+ if(design[COMPUTER_DIR] != null)
+ computer_dir = design[COMPUTER_DIR]
+ else if(category_name == "Furniture")
+ construction_mode = RCD_FURNISHING
+ furnish_type = design[FURNISH_TYPE]
+ furnish_cost = design[FURNISH_COST]
+ furnish_delay = design[FURNISH_DELAY]
+ else if(category_name == "Conveyors")
+ construction_mode = design[CONSTRUCTION_MODE]
+
+ if(root_category == "Airlocks")
+ construction_mode = RCD_AIRLOCK
+ airlock_glass = (category_name != "Solid AirLocks")
+ airlock_type = design[AIRLOCK_TYPE]
+ else
+ airlock_electronics.do_action(action, params)
+
+ return TRUE
+
+/obj/item/construction/rcd/attack_self(mob/user)
+ . = ..()
+ ui_interact(user)
/obj/item/construction/rcd/proc/target_check(atom/A, mob/user) // only returns true for stuff the device can actually work with
- if((isturf(A) && A.density && mode==RCD_DECONSTRUCT) || (isturf(A) && !A.density) || (istype(A, /obj/machinery/door/airlock) && mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/grille) || (istype(A, /obj/structure/window) && mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/girder))
+ if((isturf(A) && A.density && construction_mode==RCD_DECONSTRUCT) || (isturf(A) && !A.density) || (istype(A, /obj/machinery/door/airlock) && construction_mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/grille) || (istype(A, /obj/structure/window) && construction_mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/girder))
return TRUE
else
return FALSE
/obj/item/construction/rcd/afterattack(atom/A, mob/user, proximity)
. = ..()
- if (mode == RCD_CONVEYOR)
- if(!range_check(A, user) || !target_check(A,user) || istype(A, /obj/machinery/conveyor) || !isopenturf(A) || istype(A, /area/shuttle))
- to_chat(user, "Error! Invalid tile!")
- return
- if (!linked_switch_id)
- to_chat(user, "Error! [src] is not linked!")
- return
- if (get_turf(A) == get_turf(user))
- to_chat(user, "Cannot place conveyor below your feet!")
- return
- if(!proximity)
- return
- rcd_conveyor(A, user)
- if (mode == RCD_SWITCH)
- if(!range_check(A, user) || !target_check(A,user) || istype(A, /obj/item/conveyor_switch_construct) || !isopenturf(A) || istype(A, /area/shuttle))
- to_chat(user, "Error! Invalid tile!")
- return
- if(!proximity)
- return
- rcd_switch(A, user)
- else
- if(!prox_check(proximity))
- return
- rcd_create(A, user)
+ if(!prox_check(proximity) && !(ranged && range_check(A, user)))
+ return
+ if((upgrade & RCD_UPGRADE_CONVEYORS) && istype(A, /obj/machinery/conveyor_switch))
+ var/obj/machinery/conveyor_switch/C = A
+ linked_switch_id = C.id
+ balloon_alert(user, "linked")
+ return
+ rcd_create(A, user)
+
+/obj/item/construction/rcd/attackby(obj/item/I, mob/user, params)
+ . = ..()
+ if((upgrade & RCD_UPGRADE_CONVEYORS) && istype(I, /obj/item/conveyor_switch_construct))
+ var/obj/item/conveyor_switch_construct/C = I
+ linked_switch_id = C.id
+ balloon_alert(user, "linked")
/obj/item/construction/rcd/proc/detonate_pulse()
audible_message("[src] begins to vibrate and \
@@ -796,6 +694,23 @@ RLD
matter = 500
canRturf = TRUE
+#undef CONSTRUCTION_MODE
+#undef WINDOW_TYPE
+#undef WINDOW_GLASS
+#undef WINDOW_SIZE
+#undef COMPUTER_DIR
+#undef FURNISH_TYPE
+#undef FURNISH_COST
+#undef FURNISH_DELAY
+#undef AIRLOCK_TYPE
+
+#undef TITLE
+#undef ICON
+
+#undef CATEGORY_ICON_STATE
+#undef CATEGORY_ICON_SUFFIX
+#undef TITLE_ICON
+
/obj/item/rcd_ammo
name = "compressed matter cartridge"
desc = "Highly compressed matter for the RCD."
@@ -832,18 +747,43 @@ RLD
has_ammobar = FALSE
/obj/item/construction/rcd/arcd/afterattack(atom/A, mob/user)
- ..()
if(!range_check(A,user))
return
- if(target_check(A,user))
- user.Beam(A,icon_state="rped_upgrade",time=30)
- rcd_create(A,user)
-
+ return ..()
+/obj/item/construction/rcd/exosuit
+ name = "mounted RCD"
+ desc = "You're not supposed to see this!"
+ max_matter = 1000
+ matter = 0 // starts off empty, load materials into the mech itself
+ delay_mod = 0.5
+ ranged = TRUE
+ has_ammobar = FALSE // don't bother, you can't see it
+ item_flags = NO_MAT_REDEMPTION | DROPDEL | NOBLUDGEON
+ resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | UNACIDABLE // would be weird if it could somehow be destroyed inside the equipment item
+
+/obj/item/construction/rcd/exosuit/ui_state(mob/user)
+ return GLOB.pilot_state
+
+/obj/item/construction/rcd/exosuit/ui_status(mob/user)
+ if(!(owner && ismecha(owner)))
+ return UI_CLOSE
+ var/obj/mecha/gundam = owner
+ if(user != gundam.occupant)
+ return UI_CLOSE
+ if(!gundam.equipment_disabled && gundam.selected == loc)
+ return UI_INTERACTIVE
+ return UI_UPDATE
+
+/obj/item/construction/rcd/exosuit/mime
+ name = "silenced mounted RCD"
+ silent = TRUE
// RAPID LIGHTING DEVICE
-
+#define GLOW_MODE 3
+#define LIGHT_MODE 2
+#define REMOVE_MODE 1
/obj/item/construction/rld
name = "Rapid Lighting Device (RLD)"
@@ -854,10 +794,12 @@ RLD
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
matter = 200
max_matter = 200
+ slot_flags = ITEM_SLOT_BELT
+ ///it does not make sense why any of these should be installed
+ banned_upgrades = RCD_UPGRADE_FRAMES | RCD_UPGRADE_SIMPLE_CIRCUITS | RCD_UPGRADE_FURNISHING
+
var/matter_divisor = 35
var/mode = LIGHT_MODE
- slot_flags = ITEM_SLOT_BELT
- actions_types = list(/datum/action/item_action/pick_color)
var/wallcost = 10
var/floorcost = 15
@@ -868,35 +810,62 @@ RLD
var/floordelay = 10
var/decondelay = 15
-/obj/item/construction/rld/ui_action_click(mob/user, datum/action/A)
- if(istype(A, /datum/action/item_action/pick_color))
- color_choice = input(user,"","Choose Color",color_choice) as color
- else
- ..()
+ ///reference to thr original icons
+ var/list/original_options = list(
+ "Color Pick" = icon(icon = 'icons/mob/radial.dmi', icon_state = "omni"),
+ "Glow Stick" = icon(icon = 'icons/obj/lighting.dmi', icon_state = "glowstick"),
+ "Deconstruct" = icon(icon = 'icons/obj/tools.dmi', icon_state = "wrench"),
+ "Light Fixture" = icon(icon = 'icons/obj/lighting.dmi', icon_state = "ltube"),
+ )
+ ///will contain the original icons modified with the color choice
+ var/list/display_options = list()
+
+/obj/item/construction/rld/Initialize(mapload)
+ . = ..()
+ for(var/option in original_options)
+ display_options[option] = icon(original_options[option])
/obj/item/construction/rld/update_icon_state()
. = ..()
icon_state = "rld-[round(matter/35)]"
/obj/item/construction/rld/attack_self(mob/user)
- ..()
- switch(mode)
- if(REMOVE_MODE)
+ . = ..()
+
+ if((upgrade & RCD_UPGRADE_SILO_LINK) && display_options["Silo Link"] == null) //silo upgrade instaled but option was not updated then update it just one
+ display_options["Silo Link"] = icon(icon = 'icons/obj/mining.dmi', icon_state = "silo")
+ var/choice = show_radial_menu(user, src, display_options, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE)
+ if(!check_menu(user))
+ return
+ if(!choice)
+ return
+
+ switch(choice)
+ if("Light Fixture")
mode = LIGHT_MODE
to_chat(user, span_notice("You change RLD's mode to 'Permanent Light Construction'."))
- if(LIGHT_MODE)
+ if("Glow Stick")
mode = GLOW_MODE
to_chat(user, span_notice("You change RLD's mode to 'Light Launcher'."))
- if(GLOW_MODE)
+ if("Color Pick")
+ var/new_choice = input(user,"","Choose Color",color_choice) as color
+ if(new_choice == null)
+ return
+
+ var/list/new_rgb = ReadRGB(new_choice)
+ for(var/option in original_options)
+ if(option == "Color Pick" || option == "Deconstruct" || option == "Silo Link")
+ continue
+ var/icon/icon = icon(original_options[option])
+ icon.SetIntensity(new_rgb[1]/255, new_rgb[2]/255, new_rgb[3]/255) //apply new scale
+ display_options[option] = icon
+
+ color_choice = new_choice
+ if("Deconstruct")
mode = REMOVE_MODE
to_chat(user, span_notice("You change RLD's mode to 'Deconstruct'."))
-
-/obj/item/construction/rcd/attackby(obj/item/I, mob/user, params)
- ..()
- if(upgrade & RCD_UPGRADE_CONVEYORS && istype(I, /obj/item/conveyor_switch_construct))
- to_chat(user, "You link the switch to the [src].")
- var/obj/item/conveyor_switch_construct/C = I
- linked_switch_id = C.id
+ else
+ ui_act("toggle_silo", list())
/obj/item/construction/rld/proc/checkdupes(target)
. = list()
@@ -917,7 +886,8 @@ RLD
if(checkResource(deconcost, user))
to_chat(user, span_notice("You start deconstructing [A]..."))
user.Beam(A,icon_state="nzcrentrs_power",time=15)
- playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
+ if(!silent)
+ playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
if(do_after(user, decondelay, A))
if(!useResource(deconcost, user))
return FALSE
@@ -931,8 +901,9 @@ RLD
if(checkResource(floorcost, user))
to_chat(user, span_notice("You start building a wall light..."))
user.Beam(A,icon_state="nzcrentrs_power",time=15)
- playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
- playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, FALSE)
+ if(!silent)
+ playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
+ playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, FALSE)
if(do_after(user, floordelay, A))
if(!istype(W))
return FALSE
@@ -946,7 +917,8 @@ RLD
candidates += C
if(!candidates.len)
to_chat(user, span_warning("Valid target not found..."))
- playsound(src.loc, 'sound/misc/compiler-failure.ogg', 30, TRUE)
+ if(!silent)
+ playsound(src.loc, 'sound/misc/compiler-failure.ogg', 30, TRUE)
return FALSE
for(var/turf/open/O in candidates)
if(istype(O))
@@ -977,8 +949,9 @@ RLD
if(checkResource(floorcost, user))
to_chat(user, span_notice("You start building a floor light..."))
user.Beam(A,icon_state="light_beam",time=15)
- playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
- playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, TRUE)
+ if(!silent)
+ playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
+ playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, TRUE)
if(do_after(user, floordelay, A))
if(!istype(F))
return 0
diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm
index a58fe204b090..12d3e9973540 100644
--- a/code/game/objects/items/RPD.dm
+++ b/code/game/objects/items/RPD.dm
@@ -241,6 +241,8 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
var/static/datum/pipe_info/first_plumbing
var/mode = BUILD_MODE | PAINT_MODE | DESTROY_MODE | WRENCH_MODE
var/locked = FALSE //wheter we can change categories. Useful for the plumber
+ /// The owner of this RCD. It can be a mech or a player.
+ var/owner
/obj/item/pipe_dispenser/Initialize(mapload)
. = ..()
@@ -287,6 +289,9 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
get_asset_datum(/datum/asset/spritesheet/pipes),
)
+/obj/item/pipe_dispenser/ui_host(mob/user)
+ return owner || ..()
+
/obj/item/pipe_dispenser/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
@@ -306,7 +311,7 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
"selected_color" = paint_color,
"paint_colors" = GLOB.pipe_paint_colors,
"mode" = mode,
- "locked" = locked
+ "locked" = locked,
)
var/list/recipes
@@ -330,10 +335,10 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
return data
/obj/item/pipe_dispenser/ui_act(action, params)
- if(..())
- return
- if(!usr.canUseTopic(src, BE_CLOSE))
+ . = ..()
+ if(.)
return
+
var/playeffect = TRUE
switch(action)
if("color")
@@ -568,6 +573,24 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
return
to_chat(source, span_notice("You set the layer to [piping_layer]."))
+/obj/item/pipe_dispenser/exosuit
+ name = "mounted pipe dispenser"
+ desc = "You shouldn't be seeing this!"
+ item_flags = NO_MAT_REDEMPTION | DROPDEL | NOBLUDGEON
+ resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | UNACIDABLE // would be weird if it could somehow be destroyed inside the equipment item
+
+/obj/item/pipe_dispenser/exosuit/ui_state(mob/user)
+ return GLOB.pilot_state
+
+// don't allow using this thing unless you're piloting the mech it's attached to
+/obj/item/pipe_dispenser/exosuit/can_interact(mob/user)
+ if(!(owner && ismecha(owner)))
+ return FALSE
+ var/obj/mecha/gundam = owner
+ if(user == gundam.occupant && !gundam.equipment_disabled && gundam.selected == loc)
+ return TRUE
+ return FALSE
+
/obj/item/pipe_dispenser/plumbing
name = "Plumberinator"
desc = "A crude device to rapidly plumb things."
diff --git a/code/game/objects/items/bell.dm b/code/game/objects/items/bell.dm
index 7bb200f82249..f3b1b1d30467 100644
--- a/code/game/objects/items/bell.dm
+++ b/code/game/objects/items/bell.dm
@@ -1,6 +1,6 @@
/obj/item/deskbell
name = "desk bell"
- desc = "ding. ding."
+ desc = "Ding! Ding! Ding!"
icon = 'icons/obj/bell.dmi'
icon_state = "bell"
force = 5
diff --git a/code/game/objects/items/devices/busterarm/busterharpoon.dm b/code/game/objects/items/devices/busterarm/busterharpoon.dm
new file mode 100644
index 000000000000..31a2a43f6ba6
--- /dev/null
+++ b/code/game/objects/items/devices/busterarm/busterharpoon.dm
@@ -0,0 +1,108 @@
+/datum/action/cooldown/buster/megabuster/megaharpoon
+ name = "gasharpoon"
+ desc = "Charge up your harpoon and ready it to be fired, if it makes contact with a person it will drag them to you and immobilize them."
+ cooldown_time = 10 SECONDS
+ button_icon_state = "harpoonhead"
+
+
+/obj/item/gun/magic/wire/harpoon
+ name = "Harpoon Head"
+ desc = "A harpoon head made of pure plasteel, hits like a freighter."
+ ammo_type = /obj/item/ammo_casing/magic/wire/harpoon
+ icon_state = "gasharpoon"
+ item_state = "chain"
+ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
+ fire_sound = 'sound/weapons/batonextend.ogg'
+ max_charges = 1
+ item_flags = NEEDS_PERMIT | DROPDEL
+ force = 0
+ can_charge = FALSE
+
+/obj/item/ammo_casing/magic/wire/harpoon
+ name = "harpoon"
+ desc = "A harpoon."
+ projectile_type = /obj/projectile/wire/harpoon
+ caliber = CALIBER_HOOK
+ icon_state = "harpoonhead"
+
+/obj/projectile/wire/harpoon/fire(setAngle)
+ if(firer)
+ wire = firer.Beam(src, icon_state = "harpoonrope", time = INFINITY, maxdistance = INFINITY)
+ ..()
+
+/obj/projectile/wire/harpoon
+ name = "harpoon"
+ icon_state = "harpoonhead"
+ icon = 'icons/obj/lavaland/artefacts.dmi'
+ pass_flags = PASSTABLE
+ damage = 10
+ armour_penetration = 100
+ damage_type = BRUTE
+ nodamage = TRUE
+ range = 8
+ hitsound = 'sound/effects/splat.ogg'
+ immobilize = 1 SECONDS
+
+/obj/projectile/wire/harpoon/on_hit(atom/target)
+ var/mob/living/L = target
+ var/mob/living/carbon/human/H = firer
+ if(!L)
+ return
+ L.apply_status_effect(STATUS_EFFECT_EXPOSED_HARPOONED)
+ if(isobj(target)) // If it's an object
+ var/obj/item/I = target
+ if(!I?.anchored) // Give it to us if it's not anchored
+ I.throw_at(get_step_towards(H,I), 8, 2)
+ H.visible_message(span_danger("[I] is pulled by [H]'s harpoon!"))
+ if(istype(I, /obj/item/clothing/head))
+ H.equip_to_slot_if_possible(I, ITEM_SLOT_HEAD)
+ H.visible_message(span_danger("[H] pulls [I] onto [H.p_their()] head!"))
+ else
+ H.put_in_hands(I)
+ return
+ zip(H, target) // Pull us towards it if it's anchored
+ if(isliving(target)) // If it's somebody
+ H.swap_hand(0) //for the sake of throttling people you catch
+ var/turf/T = get_step(get_turf(H), H.dir)
+ var/turf/Q = get_turf(H)
+ var/obj/item/bodypart/limb_to_hit = L.get_bodypart(H.zone_selected)
+ var/armor = L.run_armor_check(limb_to_hit, MELEE, armour_penetration = 35)
+ if(!L.anchored) // Only pull them if they're unanchored
+ if(istype(H))
+ L.visible_message(span_danger("[L] is pulled by [H]'s harpoon!"),span_userdanger("A harpoon pierces you and pulls you towards [H]!"))
+ L.Immobilize(1.0 SECONDS)
+ if(T.density) // If we happen to be facing a wall after the wire snatches them
+ to_chat(H, span_warning("[H] catches [L] and throws [L.p_them()] against [T]!"))
+ to_chat(L, span_userdanger("[H] crushes you against [T]!"))
+ playsound(L,'sound/effects/pop_expl.ogg', 130, 1)
+ L.apply_damage(15, BRUTE, limb_to_hit, armor, wound_bonus=CANT_WOUND)
+ L.forceMove(Q)
+ return
+ // If we happen to be facing a dense object after the wire snatches them, like a table or window
+ for(var/obj/D in T.contents)
+ if(D.density == TRUE)
+ D.take_damage(50)
+ L.apply_damage(15, BRUTE, limb_to_hit, armor, wound_bonus=CANT_WOUND)
+ L.forceMove(Q)
+ to_chat(H, span_warning("[H] catches [L] throws [L.p_them()] against [D]!"))
+ playsound(L,'sound/effects/pop_expl.ogg', 20, 1)
+ return
+ L.forceMove(T)
+ if(iswallturf(target)) // If we hit a wall, pull us to it
+ var/turf/W = target
+ zip(H, W)
+
+/// Left buster-arm means megabuster goes in left hand -- I stole this from megabuster! -- cowbot93
+/datum/action/cooldown/buster/megabuster/megaharpoon/l/Activate()
+ var/obj/item/gun/magic/wire/harpoon/B = new()
+ owner.visible_message(span_userdanger("[owner]'s arm lets out a harrowing sound!"))
+ playsound(owner,'sound/weapons/bladeslice.ogg', 60, 1)
+ if(do_after(owner, 2 SECONDS, owner, timed_action_flags = IGNORE_USER_LOC_CHANGE))
+ if(!owner.put_in_l_hand(B))
+ to_chat(owner, span_warning("You can't do this with your left hand full!"))
+ else
+ owner.visible_message(span_danger("[owner]'s readies the harpoon to fire!"))
+ if(owner.active_hand_index % 2 == 0)
+ owner.swap_hand(0)
+ StartCooldown()
diff --git a/code/game/objects/items/devices/busterarm/gasharpoon.dm b/code/game/objects/items/devices/busterarm/gasharpoon.dm
new file mode 100644
index 000000000000..2889422101a0
--- /dev/null
+++ b/code/game/objects/items/devices/busterarm/gasharpoon.dm
@@ -0,0 +1,59 @@
+/obj/item/clothing/gloves/gasharpoon
+ name = "gasharpoon"
+ desc = "A metal gauntlet with a harpoon attatched, powered by gasoline and traditionally used by space-whalers."
+ ///reminder to channge all this -- I changed it :)
+ icon = 'icons/obj/traitor.dmi'
+ icon_state = "gasharpoon"
+ item_state = "gasharpoon"
+ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
+ attack_verb = list("harpooned", "gouged", "pierced")
+ force = 10
+ throwforce = 10
+ throw_range = 7
+ strip_delay = 15 SECONDS
+ cold_protection = HANDS
+ heat_protection = HANDS
+ w_class = WEIGHT_CLASS_NORMAL
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, ELECTRIC = 100)
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ var/click_delay = 1.5
+
+
+/obj/item/clothing/gloves/gasharpoon/equipped(mob/user, slot)
+ . = ..()
+ if(slot & ITEM_SLOT_GLOVES)
+ RegisterSignal(user, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(power_harpoon))
+ var/datum/action/cooldown/buster/megabuster/megaharpoon/l/harpoon = new(user)
+ harpoon.Grant(user)
+
+/obj/item/clothing/gloves/gasharpoon/dropped(mob/user)
+ . = ..()
+ if(user.get_item_by_slot(ITEM_SLOT_GLOVES)==src)
+ UnregisterSignal(user, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)
+ var/datum/action/cooldown/buster/megabuster/megaharpoon/l/harpoon = locate(/datum/action/cooldown/buster/megabuster/megaharpoon/l) in user.actions
+ if(harpoon)
+ harpoon.Remove(user)
+ return ..()
+
+
+/obj/item/clothing/gloves/gasharpoon/proc/power_harpoon(mob/living/user, atom/movable/target)
+ if(!user || user.a_intent!=INTENT_HARM || (!isliving(target) && !isobj(target)) || isitem(target))
+ return
+ do_attack(user, target, force * 2)
+ playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1)
+ target.visible_message(span_danger("[user]'s gasharpoon pierces through [target.name]!"))
+ return COMPONENT_NO_ATTACK_HAND
+
+/obj/item/clothing/gloves/gasharpoon/attack(mob/living/target, mob/living/user)
+ power_harpoon(user, target)
+
+/obj/item/clothing/gloves/gasharpoon/proc/do_attack(mob/living/user, atom/target, punch_force)
+ if(isliving(target))
+ var/mob/living/target_mob = target
+ target_mob.apply_damage(punch_force, BRUTE, wound_bonus = 30)
+ else if(isobj(target))
+ var/obj/target_obj = target
+ target_obj.take_damage(punch_force, BRUTE, MELEE, FALSE)
+ user.do_attack_animation(target, ATTACK_EFFECT_SLASH)
+ user.changeNext_move(CLICK_CD_MELEE * click_delay)
diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm
index d7d7cf9ef2fc..0792c4085680 100644
--- a/code/game/objects/items/flamethrower.dm
+++ b/code/game/objects/items/flamethrower.dm
@@ -1,3 +1,6 @@
+/// How many joules of energy from reactions required to cause 1 damage
+#define JOULES_PER_DAMAGE 100000
+
/obj/item/flamethrower
name = "flamethrower"
desc = "You are a firestarter!"
@@ -54,7 +57,7 @@
if(M.is_holding(src))
location = M.loc
if(isturf(location)) //start a fire if possible
- igniter.flamethrower_process(location)
+ open_flame(igniter.heat)
/obj/item/flamethrower/update_overlays()
@@ -199,33 +202,21 @@
if(!istype(target))
return FALSE
- var/ratio_removed = 1
- if(!release_all)
- ratio_removed = min(ptank.distribute_pressure, ptank.air_contents.return_pressure()) / ptank.air_contents.return_pressure()
+ var/ratio_removed = min(ptank.distribute_pressure, ptank.air_contents.return_pressure()) / ptank.air_contents.return_pressure()
+
var/datum/gas_mixture/fuel_mix = ptank.air_contents.remove_ratio(ratio_removed)
+ var/datum/gas_mixture/turf_mix = target.return_air()
+
+ fuel_mix.merge(turf_mix.copy()) // copy air from the turf to do reactions with
+ fuel_mix.set_temperature(igniter.heat) // heat the contents
+
+ var/old_thermal_energy = fuel_mix.thermal_energy()
+ for(var/i in 1 to 10) // react a bunch of times on the target turf
+ if(!fuel_mix.react(target))
+ break // break the loop if it stops reacting
- // Return of the stimball flamethrower, wear radiation protection when using this or you're just as likely to die as your target
- if(fuel_mix.get_moles(GAS_PLASMA) >= NITRO_BALL_MOLES_REQUIRED && fuel_mix.get_moles(GAS_NITRIUM) >= NITRO_BALL_MOLES_REQUIRED && fuel_mix.get_moles(GAS_PLUOXIUM) >= NITRO_BALL_MOLES_REQUIRED)
- var/balls_shot = round(min(fuel_mix.get_moles(GAS_NITRIUM), fuel_mix.get_moles(GAS_PLUOXIUM), NITRO_BALL_MAX_REACT_RATE / NITRO_BALL_MOLES_REQUIRED))
- var/angular_increment = 360/balls_shot
- var/random_starting_angle = rand(0,360)
- for(var/i in 1 to balls_shot)
- target.fire_nuclear_particle((i*angular_increment+random_starting_angle))
- fuel_mix.adjust_moles(GAS_PLASMA, -balls_shot * NITRO_BALL_MOLES_REQUIRED) // No free extra damage for you, conservation of mass go brrrrr
-
- // Funny rad flamethrower go brrr
- if(fuel_mix.get_moles(GAS_TRITIUM)) // Tritium fires cause a bit of radiation
- radiation_pulse(target, min(fuel_mix.get_moles(GAS_TRITIUM), fuel_mix.get_moles(GAS_O2)/2) * FIRE_HYDROGEN_ENERGY_RELEASED / TRITIUM_BURN_RADIOACTIVITY_FACTOR)
-
- // 8 damage at 0.5 mole transfer or ~17 kPa release pressure
- // 16 damage at 1 mole transfer or ~35 kPa release pressure
- var/damage = fuel_mix.get_moles(GAS_PLASMA) * 16
- // harder to achieve than plasma
- damage += fuel_mix.get_moles(GAS_TRITIUM) * 24 // Lower damage than hydrogen, causes minor radiation
- damage += fuel_mix.get_moles(GAS_H2) * 32
- // Maximum damage restricted by the available oxygen, with a hard cap at 16
- var/datum/gas_mixture/turf_air = target.return_air()
- damage = min(damage, turf_air.get_moles(GAS_O2) + fuel_mix.get_moles(GAS_O2), max_damage) // capped by combined oxygen in the fuel mix and enviroment
+ // damage is based on the positive or negative energy of the reaction, with a cap
+ var/damage = min(abs(fuel_mix.thermal_energy() - old_thermal_energy) / JOULES_PER_DAMAGE, max_damage)
// If there's not enough fuel and/or oxygen to do more than 1 damage, shut itself off
if(damage < 1)
@@ -251,22 +242,40 @@
for(var/turf/T in turflist)
if(T == previousturf)
continue //so we don't burn the tile we be standin on
- for(var/obj/structure/blob/B in T)
+ var/cached_damage = 0
+
+ for(var/obj/structure/blob/blob in T)
// This is run before atmos checks because blob can be atmos blocking but we still want to hit them
// See /proc/default_ignite
- var/damage = process_fuel(T)
- if(!damage)
- break // Out of gas, stop running pointlessly
- B.take_damage(damage * 2, BURN, FIRE) // strong against blobs
+ if(!cached_damage)
+ cached_damage = process_fuel(T)
+ if(!lit)
+ break // stopped running, don't continue
+ if(QDELETED(blob))
+ continue
+ blob.take_damage(cached_damage * 2, BURN, FIRE) // strong against blobs
+
+ for(var/obj/structure/spacevine/vine in T)
+ // This is run before atmos checks because vines can be on top of a window or some other atmos-blocking structure
+ if(!cached_damage)
+ cached_damage = process_fuel(T)
+ if(!lit)
+ break // stopped running, don't continue
+ if(QDELETED(vine))
+ continue
+ vine.take_damage(cached_damage * 3, BURN, FIRE, TRUE) // very strong against vines
+
var/list/turfs_sharing_with_prev = previousturf.GetAtmosAdjacentTurfs(alldir=1)
if(!(T in turfs_sharing_with_prev))
break // Hit something that blocks atmos
- if(igniter)
- if(!igniter.ignite_turf(src,T))
- break // Out of gas, stop running pointlessly
- else
- if(!default_ignite(T))
- break // Out of gas, stop running pointlessly
+
+ if(!cached_damage)
+ cached_damage = process_fuel(T)
+ if(!lit)
+ break // stopped running, don't continue
+ if(!burn_atoms_on_turf(T, cached_damage))
+ break // Out of gas, stop running pointlessly
+
if(!sound_played) // play the sound once if we successfully ignite at least one thing
sound_played = TRUE
playsound(loc, pick(flame_sounds), 50, TRUE)
@@ -281,10 +290,9 @@
// /obj/structure/blob/normal
// Return value tells the parent whether to continue calculating the line
-/obj/item/flamethrower/proc/default_ignite(turf/target, release_all = FALSE)
- // do the fuel stuff
- var/damage = process_fuel(target, release_all)
- if(!damage)
+/obj/item/flamethrower/proc/burn_atoms_on_turf(turf/target, damage)
+ // no damage? don't continue
+ if(damage <= 0)
return FALSE
//Burn it
@@ -333,24 +341,17 @@
var/obj/projectile/P = hitby
if(damage && attack_type == PROJECTILE_ATTACK && P.damage_type != STAMINA && prob(5))
owner.visible_message(span_danger("\The [attack_text] hits the fueltank on [owner]'s [name], rupturing it! What a shot!"))
- var/target_turf = get_turf(owner)
- igniter.ignite_turf(src,target_turf, release_all = TRUE)
- qdel(ptank)
- return 1 //It hit the flamethrower, not them
-
-
-/obj/item/assembly/igniter/proc/flamethrower_process(turf/open/location)
- location.hotspot_expose(700,2)
-
-/obj/item/assembly/igniter/proc/ignite_turf(obj/item/flamethrower/F, turf/open/location, release_all = FALSE)
- return F.default_ignite(location, release_all)
+ var/turf/target_turf = get_turf(owner)
+ burn_atoms_on_turf(target_turf, process_fuel(target_turf))
+ return TRUE //It hit the flamethrower, not them
+ return ..()
///////////////////// Flamethrower as an energy weapon /////////////////////
// Currently used exclusively in /obj/item/gun/energy/printer/flamethrower
/obj/item/ammo_casing/energy/flamethrower
projectile_type = /obj/projectile/bullet/incendiary/flamethrower
select_name = "fire"
- fire_sound = null
+ fire_sound = 'sound/weapons/flamethrower1.ogg'
firing_effect_type = null
e_cost = 50
@@ -361,3 +362,5 @@
sharpness = SHARP_NONE
range = 6
penetration_flags = PENETRATE_OBJECTS | PENETRATE_MOBS
+
+#undef JOULES_PER_DAMAGE
diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm
index 2423c687ef52..477af55a02f6 100644
--- a/code/game/objects/items/grenades/chem_grenade.dm
+++ b/code/game/objects/items/grenades/chem_grenade.dm
@@ -342,7 +342,7 @@
/obj/item/grenade/chem_grenade/radiation
name = "Rad Bomb"
- desc = "the best grenade to irridiate the fuck out of someone"
+ desc = "The best grenade to irradiate the fuck out of someone."
stage = GRENADE_READY
/obj/item/grenade/chem_grenade/radiation/Initialize(mapload)
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index c14723dd7e6c..18824aa5da65 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -268,7 +268,11 @@
/obj/item/restraints/legcuffs/beartrap/Initialize(mapload)
. = ..()
- update_appearance(UPDATE_ICON)
+ update_appearance()
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(trap_stepped_on),
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
/obj/item/restraints/legcuffs/beartrap/update_icon_state()
. = ..()
@@ -310,6 +314,55 @@
update_appearance(UPDATE_ICON)
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
+/obj/item/restraints/legcuffs/beartrap/proc/trap_stepped_on(datum/source, atom/movable/entering, ...)
+ SIGNAL_HANDLER
+
+ spring_trap(entering)
+
+/**
+ * Tries to spring the trap on the target movable.
+ *
+ * This proc is safe to call without knowing if the target is valid or if the trap is armed.
+ *
+ * Does not trigger on tiny mobs.
+ * If ignore_movetypes is FALSE, does not trigger on floating / flying / etc. mobs.
+ */
+/obj/item/restraints/legcuffs/beartrap/proc/spring_trap(atom/movable/target, ignore_movetypes = FALSE)
+ if(!armed || !isturf(loc) || !isliving(target))
+ return
+
+ var/mob/living/victim = target
+ if(istype(victim.buckled, /obj/vehicle))
+ var/obj/vehicle/ridden_vehicle = victim.buckled
+ if(!ridden_vehicle.are_legs_exposed) //close the trap without injuring/trapping the rider if their legs are inside the vehicle at all times.
+ close_trap()
+ ridden_vehicle.visible_message(span_danger("[ridden_vehicle] triggers \the [src]."))
+ return
+
+ //don't close the trap if they're as small as a mouse
+ if(victim.mob_size <= MOB_SIZE_TINY)
+ return
+ if(!ignore_movetypes && (victim.movement_type & MOVETYPES_NOT_TOUCHING_GROUND))
+ return
+
+ close_trap()
+ if(ignore_movetypes)
+ victim.visible_message(span_danger("\The [src] ensnares [victim]!"), \
+ span_userdanger("\The [src] ensnares you!"))
+ else
+ victim.visible_message(span_danger("[victim] triggers \the [src]."), \
+ span_userdanger("You trigger \the [src]!"))
+ var/def_zone = BODY_ZONE_CHEST
+ if(iscarbon(victim) && victim.body_position == STANDING_UP)
+ var/mob/living/carbon/carbon_victim = victim
+ def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ if(!carbon_victim.legcuffed && carbon_victim.num_legs >= 2) //beartrap can't cuff your leg if there's already a beartrap or legcuffs, or you don't have two legs.
+ INVOKE_ASYNC(carbon_victim, TYPE_PROC_REF(/mob/living/carbon, equip_to_slot), src, ITEM_SLOT_LEGCUFFED)
+ SSblackbox.record_feedback("tally", "handcuffs", 1, type)
+
+ victim.apply_damage(trap_damage, BRUTE, def_zone)
+
+
/obj/item/restraints/legcuffs/beartrap/Crossed(AM as mob|obj)
if(armed && isturf(loc))
if(isliving(AM))
diff --git a/code/game/objects/items/manuals.dm b/code/game/objects/items/manuals.dm
index 0b41e021e48e..b5f37de5e195 100644
--- a/code/game/objects/items/manuals.dm
+++ b/code/game/objects/items/manuals.dm
@@ -10,7 +10,7 @@
/obj/item/book/manual/ripley_build_and_repair
name = "APLU \"Ripley\" Construction and Operation Manual"
icon_state ="book"
- author = "Weyland-Yutani Corp"
+ author = "Sano-Waltfield Industries"
title = "APLU \"Ripley\" Construction and Operation Manual"
dat = {"
@@ -24,7 +24,7 @@
- Weyland-Yutani - Building Better Worlds
+ Sano-Waltfield - Forging Better Futures
Autonomous Power Loader Unit \"Ripley\"
Specifications:
diff --git a/code/game/objects/items/stacks/license_plates.dm b/code/game/objects/items/stacks/license_plates.dm
index ece53770f9fa..92f7edc922ee 100644
--- a/code/game/objects/items/stacks/license_plates.dm
+++ b/code/game/objects/items/stacks/license_plates.dm
@@ -1,6 +1,6 @@
/obj/item/stack/license_plates
name = "invalid plate"
- desc = "someone fucked up"
+ desc = "Someone fucked up."
icon = 'icons/obj/machines/prison.dmi'
icon_state = "empty_plate"
novariants = FALSE
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index d7b7421bf7b5..a02293e02c5a 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -33,6 +33,17 @@
var/preload_cell_type
///used for passive discharge
var/cell_last_used = 0
+ light_range = 1.5
+ light_system = MOVABLE_LIGHT
+ light_on = FALSE
+ light_color = LIGHT_COLOR_ORANGE
+ light_power = 0.5
+
+/// Toggles the stun baton's light
+/obj/item/melee/baton/proc/toggle_light(mob/user)
+ set_light_on(!light_on)
+ return
+
/obj/item/melee/baton/get_cell()
return cell
@@ -76,6 +87,7 @@
if(status && cell.charge < hitcost)
//we're below minimum, turn off
status = FALSE
+ set_light_on(FALSE)
update_appearance(UPDATE_ICON)
playsound(loc, "sparks", 75, 1, -1)
STOP_PROCESSING(SSobj, src) // no more charge? stop checking for discharge
@@ -135,6 +147,8 @@
status = !status
to_chat(user, span_notice("[src] is now [status ? "on" : "off"]."))
playsound(loc, "sparks", 75, 1, -1)
+ toggle_light(user)
+ do_sparks(1, TRUE, src)
cell_last_used = 0
if(status)
START_PROCESSING(SSobj, src)
@@ -306,3 +320,5 @@
desc = "A new power management circuit which enables stun batons to instantly stun, at the cost of double power usage."
icon = 'icons/obj/module.dmi'
icon_state = "cyborg_upgrade3"
+
+
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 3a3da7c3be55..9cfe1022c7ac 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -456,6 +456,14 @@
w_class = WEIGHT_CLASS_TINY
var/ash_type = /obj/effect/decal/cleanable/ash
+/obj/item/toy/snappop/Initialize(mapload)
+ . = ..()
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
+
+
/obj/item/toy/snappop/proc/pop_burst(n=3, c=1)
var/datum/effect_system/spark_spread/s = new()
s.set_up(n, c, src)
@@ -473,8 +481,7 @@
if(!..())
pop_burst()
-/obj/item/toy/snappop/Crossed(H as mob|obj)
- . = ..()
+/obj/item/toy/snappop/proc/on_entered(datum/source, atom/movable/H, ...)
if(ishuman(H) || issilicon(H)) //i guess carp and shit shouldn't set them off
var/mob/living/carbon/M = H
if(issilicon(H) || M.m_intent == MOVE_INTENT_RUN)
diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm
index 48f8af00a690..ddcdb6ba0bf0 100644
--- a/code/game/objects/items/trash.dm
+++ b/code/game/objects/items/trash.dm
@@ -46,7 +46,7 @@
/obj/item/trash/plate
name = "plate"
- desc = "a relic from a forgotten time... I miss eating off of plates..."
+ desc = "A relic from a forgotten time... I miss eating off of plates..."
icon_state = "plate"
resistance_flags = NONE
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 9fd276f6ef92..cefc64e51f50 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -261,7 +261,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
/obj/item/katana/basalt
name = "basalt katana"
- desc = "a katana made out of hardened basalt. Particularly damaging to lavaland fauna. (Activate this item in hand to dodge roll in the direction you're facing)"
+ desc = "A katana made of hardened basalt. Particularly damaging to lavaland fauna.
(Activate this item in hand to dodge roll in the direction you're facing)"
icon_state = "basalt_katana"
item_state = "basalt_katana"
force = 18
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index 26ffaa271b51..30b8a116b360 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -319,7 +319,7 @@
qdel(src)
/obj/structure/door_assembly/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- if(the_rcd.mode == RCD_DECONSTRUCT)
+ if(the_rcd.construction_mode == RCD_DECONSTRUCT)
return list("mode" = RCD_DECONSTRUCT, "delay" = 50, "cost" = 16)
return FALSE
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 8abaa8a5f237..f0438d4b89e2 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -377,7 +377,7 @@
qdel(src)
/obj/structure/girder/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_FLOORWALL)
return list("mode" = RCD_FLOORWALL, "delay" = 20, "cost" = 8)
if(RCD_DECONSTRUCT)
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 0313894e0e60..999054d19ef1 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -68,7 +68,7 @@
. += span_notice("The anchoring screws are unscrewed. The rods look like they could be cut through.")
/obj/structure/grille/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_DECONSTRUCT)
return list("mode" = RCD_DECONSTRUCT, "delay" = 20, "cost" = 5)
if(RCD_WINDOWGRILLE)
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index c270c1d47913..ca111ff4fecf 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -52,7 +52,7 @@
qdel(src)
/obj/structure/lattice/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- if(the_rcd.mode == RCD_FLOORWALL)
+ if(the_rcd.construction_mode == RCD_FLOORWALL)
return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 2)
/obj/structure/lattice/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index 7d22e05d02f5..b143d3e1d2ce 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -144,7 +144,7 @@
/obj/item/wallframe/mirror
name = "mirror"
- desc = "a mirror on your hand, what are you gonna do?"
+ desc = "A mirror on your hand, what are you gonna do?"
icon = 'icons/obj/watercloset.dmi'
icon_state = "mirror"
result_path = /obj/structure/mirror
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 67c1c825f1c6..eb0e6ef59c8c 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -239,7 +239,7 @@
qdel(src)
/obj/structure/table/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_DECONSTRUCT)
return list("mode" = RCD_DECONSTRUCT, "delay" = 24, "cost" = 16)
return FALSE
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 205d357bee58..9327f9175fed 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -74,7 +74,7 @@
AddElement(/datum/element/connect_loc, loc_connections)
/obj/structure/window/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_DECONSTRUCT)
return list("mode" = RCD_DECONSTRUCT, "delay" = 20, "cost" = 5)
return FALSE
@@ -83,7 +83,7 @@
if (resistance_flags & INDESTRUCTIBLE)
return FALSE
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_DECONSTRUCT)
to_chat(user, span_notice("You deconstruct the window."))
qdel(src)
diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm
index d5460156c700..2127dc3bac60 100644
--- a/code/game/turfs/closed/walls.dm
+++ b/code/game/turfs/closed/walls.dm
@@ -196,7 +196,7 @@
return
//get the user's location
- if(!isturf(user.loc))
+ if(!isturf(user.loc) && !ismecha(user.loc))
return //can't do this stuff whilst inside objects and such
add_fingerprint(user)
@@ -297,7 +297,7 @@
dismantle_wall(1)
/turf/closed/wall/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_DECONSTRUCT)
return list("mode" = RCD_DECONSTRUCT, "delay" = 40, "cost" = 26)
return FALSE
diff --git a/code/game/turfs/open/chasm.dm b/code/game/turfs/open/chasm.dm
index 532a3e5b3e9a..7871b313ea9e 100644
--- a/code/game/turfs/open/chasm.dm
+++ b/code/game/turfs/open/chasm.dm
@@ -36,7 +36,7 @@
return
/turf/open/chasm/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_FLOORWALL)
return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 3)
return FALSE
diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm
index 80706649c786..67990c43ee7b 100644
--- a/code/game/turfs/open/floor.dm
+++ b/code/game/turfs/open/floor.dm
@@ -164,8 +164,8 @@
return FALSE
/turf/open/floor/crowbar_act(mob/living/user, obj/item/I)
- if(istype(I,/obj/item/jawsoflife/jimmy))
- to_chat(user,"The [I] cannot pry tiles.")
+ if(istype(I, /obj/item/jawsoflife/jimmy) || istype(I, /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp))
+ to_chat(user,"[I] cannot pry tiles.")
return
if(overfloor_placed && pry_tile(I, user))
return TRUE
@@ -235,7 +235,7 @@
ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
/turf/open/floor/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_FLOORWALL)
return list("mode" = RCD_FLOORWALL, "delay" = 20, "cost" = 16)
if(RCD_AIRLOCK)
@@ -253,6 +253,10 @@
return list("mode" = RCD_COMPUTER, "delay" = 20, "cost" = 25)
if(RCD_FURNISHING)
return list("mode" = RCD_FURNISHING, "delay" = the_rcd.furnish_delay, "cost" = the_rcd.furnish_cost)
+ if(RCD_CONVEYOR)
+ return list("mode" = RCD_CONVEYOR, "delay" = 5, "cost" = 5)
+ if(RCD_SWITCH)
+ return list("mode" = RCD_SWITCH, "delay" = 1, "cost" = 1)
return FALSE
/turf/open/floor/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
@@ -329,4 +333,19 @@
var/atom/new_furnish = new the_rcd.furnish_type(src)
new_furnish.setDir(user.dir)
return TRUE
+ if(RCD_CONVEYOR)
+ if(locate(/obj/machinery/conveyor) in src)
+ return FALSE
+ if(get_turf(user) == src)
+ return FALSE
+ var/obj/machinery/conveyor/new_conveyor = new /obj/machinery/conveyor(src)
+ new_conveyor.setDir(user.dir)
+ if(the_rcd.linked_switch_id)
+ new_conveyor.id = the_rcd.linked_switch_id // link the conveyor if possible
+ return TRUE
+ if(RCD_SWITCH)
+ if(locate(/obj/machinery/conveyor_switch) in src)
+ return FALSE
+ new /obj/machinery/conveyor_switch(src)
+ return TRUE
return FALSE
diff --git a/code/game/turfs/open/floor/plating.dm b/code/game/turfs/open/floor/plating.dm
index 2c6a8bbd0005..115a9e89c71d 100644
--- a/code/game/turfs/open/floor/plating.dm
+++ b/code/game/turfs/open/floor/plating.dm
@@ -163,7 +163,7 @@
to_chat(user, span_danger("You hit [src], to no effect!"))
/turf/open/floor/plating/foam/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- if(the_rcd.mode == RCD_FLOORWALL)
+ if(the_rcd.construction_mode == RCD_FLOORWALL)
return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 1)
/turf/open/floor/plating/foam/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm
index f58f77d03e1f..eb63fc7dd6c8 100644
--- a/code/game/turfs/open/lava.dm
+++ b/code/game/turfs/open/lava.dm
@@ -127,7 +127,7 @@
STOP_PROCESSING(SSobj, src)
/turf/open/lava/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_FLOORWALL)
return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 3)
return FALSE
diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm
index 5216f2280d96..2bf2f2c87af0 100644
--- a/code/game/turfs/open/openspace.dm
+++ b/code/game/turfs/open/openspace.dm
@@ -108,7 +108,7 @@
return can_build_on
/turf/open/openspace/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_FLOORWALL)
return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 3)
return FALSE
diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm
index de3c5383a498..f370afc3123d 100644
--- a/code/game/turfs/open/space/space.dm
+++ b/code/game/turfs/open/space/space.dm
@@ -149,7 +149,7 @@ GLOBAL_LIST_EMPTY(starlight)
return TRUE
/turf/open/space/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
+ switch(the_rcd.construction_mode)
if(RCD_FLOORWALL)
return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 3)
return FALSE
diff --git a/code/game/turfs/open/space/transit.dm b/code/game/turfs/open/space/transit.dm
index 61087e674021..fa5ce4bf686d 100644
--- a/code/game/turfs/open/space/transit.dm
+++ b/code/game/turfs/open/space/transit.dm
@@ -1,5 +1,5 @@
/turf/open/space/transit
- name = "\proper hyperspace"
+ name = "\proper bluespace"
desc = "What is this, light-speed? We need to go to plaid speed!" // spaceballs was a great movie
icon_state = "black"
dir = SOUTH
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index f7922e820a45..48ea42c20dd1 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -138,6 +138,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
if (smoothing_flags & (SMOOTH_CORNERS|SMOOTH_BITMASK))
QUEUE_SMOOTH(src)
+ QUEUE_SMOOTH_NEIGHBORS(src) //Yog code because there are some templates we load right into the map
visibilityChanged()
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index 604ef5a2b179..ed357bb9d91a 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -17,7 +17,7 @@ GLOBAL_LIST_EMPTY(antagonists)
var/antag_moodlet //typepath of moodlet that the mob will gain with their status
var/can_hijack = HIJACK_NEUTRAL //If these antags are alone on shuttle hijack happens.
///The antag hud's icon file
- var/hud_icon = 'yogstation/icons/mob/antag_hud.dmi'
+ var/hud_icon = 'modular_dripstation/icons/mob/hud.dmi' //dripstation edit
///Name of the antag hud we provide to this mob.
var/antag_hud_name
var/awake_stage = ANTAG_AWAKE //What stage we are of "waking up"
diff --git a/code/modules/antagonists/bloodsuckers/vassal/vassal.dm b/code/modules/antagonists/bloodsuckers/vassal/vassal.dm
index bf88783d06c6..9d21f401a298 100644
--- a/code/modules/antagonists/bloodsuckers/vassal/vassal.dm
+++ b/code/modules/antagonists/bloodsuckers/vassal/vassal.dm
@@ -276,7 +276,7 @@
show_in_antagpanel = FALSE
silent = TRUE
ui_name = FALSE
- hud_icon = 'yogstation/icons/mob/hud.dmi'
+ hud_icon = 'modular_dripstation/icons/mob/hud.dmi' //dripstation edit
///The revenge vassal that brought us into the fold.
var/datum/antagonist/vassal/revenge/revenge_vassal
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index a9dfd38d2af9..4d5fefa3d622 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -487,7 +487,7 @@
user.dropItemToGround(src, TRUE)
/obj/item/clothing/glasses/hud/health/night/cultblind
- desc = "may Nar'sie guide you through the darkness and shield you from the light."
+ desc = "May Nar'sie guide you through the darkness and shield you from the light."
name = "zealot's blindfold"
icon_state = "blindfold"
item_state = "blindfold"
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 9fede71f0ad6..0b72aa0f9a2d 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -17,7 +17,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
name = "rune"
var/cultist_name = "basic rune"
desc = "A rune vandalizing the station."
- var/cultist_desc = "a basic rune with no function." //This is shown to cultists who examine the rune in order to determine its true purpose.
+ var/cultist_desc = "A basic rune with no function." //This is shown to cultists who examine the rune in order to determine its true purpose.
anchored = TRUE
icon = 'icons/obj/rune.dmi'
icon_state = "1"
@@ -193,7 +193,7 @@ structure_check() searches for nearby cultist structures required for the invoca
//Malformed Rune: This forms if a rune is not drawn correctly. Invoking it does nothing but hurt the user.
/obj/effect/rune/malformed
cultist_name = "malformed rune"
- cultist_desc = "a senseless rune written in gibberish. No good can come from invoking this."
+ cultist_desc = "A senseless rune written in gibberish. No good can come from invoking this."
invocation = "Ra'sha yoka!"
invoke_damage = 30
@@ -209,7 +209,7 @@ structure_check() searches for nearby cultist structures required for the invoca
//Rite of Offering: Converts or sacrifices a target.
/obj/effect/rune/convert
cultist_name = "Offer"
- cultist_desc = "offers a noncultist above it to Nar'sie, either converting them or sacrificing them."
+ cultist_desc = "Offers a non-cultist above it to Nar'sie, either converting them or sacrificing them."
req_cultists_text = "2 for conversion, 3 for living sacrifices and sacrifice targets."
invocation = "Mah'weyh pleggh at e'ntrath!"
icon_state = "3"
@@ -363,7 +363,7 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/empower
cultist_name = "Empower"
- cultist_desc = "allows cultists to prepare greater amounts of blood magic at far less of a cost."
+ cultist_desc = "Allows cultists to prepare greater amounts of blood magic at far less of a cost."
invocation = "H'drak v'loso, mir'kanas verbot!"
icon_state = "3"
color = RUNE_COLOR_TALISMAN
@@ -377,7 +377,7 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/teleport
cultist_name = "Teleport"
- cultist_desc = "warps everything above it to another chosen teleport rune."
+ cultist_desc = "Warps everything above it to another chosen teleport rune."
invocation = "Sas'so c'arta forbici!"
icon_state = "2"
color = RUNE_COLOR_TELEPORT
@@ -500,7 +500,7 @@ structure_check() searches for nearby cultist structures required for the invoca
//Ritual of Dimensional Rending: Calls forth the avatar of Nar'sie upon the station.
/obj/effect/rune/narsie
cultist_name = "Nar'sie"
- cultist_desc = "tears apart dimensional barriers, beginning the Red Harvest. You will need to protect 4 Bloodstones around the station, then the Anchor Bloodstone after invoking this rune or the summoning will backfire and need to be restarted. Requires 9 invokers, with the cult leader counting as half of this if they invoke the rune."
+ cultist_desc = "Tears apart dimensional barriers, beginning the Red Harvest. You will need to protect 4 Bloodstones around the station, then the Anchor Bloodstone after invoking this rune or the summoning will backfire and need to be restarted. Requires 9 invokers, with the cult leader counting as half of this if they invoke the rune."
invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!"
req_cultists = 9
req_cultists_text = "9 cultists, with the cult leader counting as 5 if they are the invoker"
@@ -591,7 +591,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
//Rite of Resurrection: Requires a dead or inactive cultist. When reviving the dead, you can only perform one revival for every three sacrifices your cult has carried out.
/obj/effect/rune/raise_dead
cultist_name = "Revive"
- cultist_desc = "requires a dead, mindless, or inactive cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be given a new life. This will cause large amounts of damage to the invoker and the revived corpse."
+ cultist_desc = "Requires a dead, mindless, or inactive cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be given a new life. This will cause large amounts of damage to the invoker and the revived corpse."
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
icon_state = "1"
color = RUNE_COLOR_MEDIUMRED
@@ -685,7 +685,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
//Rite of the Corporeal Shield: When invoked, becomes solid and cannot be passed. Invoke again to undo.
/obj/effect/rune/wall
cultist_name = "Barrier"
- cultist_desc = "when invoked, makes a temporary invisible wall to block passage. Can be invoked again to reverse this."
+ cultist_desc = "When invoked, makes a temporary invisible wall to block passage. Can be invoked again to reverse this."
invocation = "Khari'd! Eske'te tannin!"
icon_state = "4"
color = RUNE_COLOR_DARKRED
@@ -766,7 +766,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
//Rite of Joined Souls: Summons a single cultist.
/obj/effect/rune/summon
cultist_name = "Summon Cultist"
- cultist_desc = "summons a single cultist to the rune. Requires 2 invokers."
+ cultist_desc = "Summons a single cultist to the rune. Requires 2 invokers."
invocation = "N'ath reth sh'yro eth d'rekkathnor!"
req_cultists = 2
invoke_damage = 10
@@ -824,7 +824,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
//Rite of Boiling Blood: Deals extremely high amounts of damage to non-cultists nearby
/obj/effect/rune/blood_boil
cultist_name = "Boil Blood"
- cultist_desc = "boils the blood of non-believers who can see the rune, rapidly dealing extreme amounts of damage. Requires 3 invokers."
+ cultist_desc = "Boils the blood of non-believers who can see the rune, rapidly dealing extreme amounts of damage. Requires 3 invokers."
invocation = "Dedo ol'btoh!"
icon_state = "4"
color = RUNE_COLOR_BURNTORANGE
@@ -889,7 +889,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
//Rite of Spectral Manifestation: Summons a ghost on top of the rune as a cultist human with no items. User must stand on the rune at all times, and takes damage for each summoned ghost.
/obj/effect/rune/manifest
cultist_name = "Spirit Realm"
- cultist_desc = "manifests a spirit servant of the Geometer and allows you to ascend as a spirit yourself. The invoker must not move from atop the rune, and will take damage for each summoned spirit."
+ cultist_desc = "Manifests a spirit servant of the Geometer and allows you to ascend as a spirit yourself. The invoker must not move from atop the rune, and will take damage for each summoned spirit."
invocation = "Gal'h'rfikk harfrandid mud'gib!" //how the fuck do you pronounce this
icon_state = "7"
invoke_damage = 10
@@ -1016,7 +1016,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
/obj/effect/rune/apocalypse
cultist_name = "Apocalypse"
- cultist_desc = "a harbinger of the end times. Grows in strength with the cult's desperation - but at the risk of... side effects."
+ cultist_desc = "A harbinger of the end times. Grows in strength with the cult's desperation - but at the risk of... side effects."
invocation = "Ta'gh fara'qha fel d'amar det!"
icon = 'icons/effects/96x96.dmi'
icon_state = "apoc"
diff --git a/code/modules/antagonists/disease/disease_datum.dm b/code/modules/antagonists/disease/disease_datum.dm
index fb18acc65d00..74c35d9d177c 100644
--- a/code/modules/antagonists/disease/disease_datum.dm
+++ b/code/modules/antagonists/disease/disease_datum.dm
@@ -76,7 +76,7 @@
return result.Join("
")
/datum/antagonist/disease/get_preview_icon()
- var/icon/icon = icon('icons/mob/hud.dmi', "virus_infected")
+ var/icon/icon = icon('modular_dripstation/icons/mob/hud.dmi', "virus_infected") //dripstation edit
icon.Blend(COLOR_GREEN_GRAY, ICON_MULTIPLY)
icon.Scale(ANTAGONIST_PREVIEW_ICON_SIZE, ANTAGONIST_PREVIEW_ICON_SIZE)
return icon
@@ -109,7 +109,7 @@
return FALSE
/datum/antagonist/disease/get_preview_icon()
- var/icon/disease_icon = icon('icons/mob/hud.dmi', "infected")
+ var/icon/disease_icon = icon('modular_dripstation/icons/mob/hud.dmi', "infected") //dripstation edit
disease_icon.Blend(COLOR_GREEN_GRAY, ICON_MULTIPLY)
disease_icon.Scale(ANTAGONIST_PREVIEW_ICON_SIZE, ANTAGONIST_PREVIEW_ICON_SIZE)
return disease_icon
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm
index e3ae58f0497d..40c530c1efed 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_effects.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_effects.dm
@@ -419,7 +419,7 @@
/obj/effect/penance_giver
name = "code ing"
- desc = "it takes your soul, and other stuff"
+ desc = "It takes your soul, and other stuff."
icon = 'icons/mob/triangle.dmi'
icon_state = "triangle"
light_power = 2
diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm
index 51de65512872..77db2ed669ba 100644
--- a/code/modules/antagonists/revolution/revolution.dm
+++ b/code/modules/antagonists/revolution/revolution.dm
@@ -175,7 +175,7 @@
// Otherwise, the R gets cut off.
final_icon.Scale(64, 64)
- var/icon/rev_head_icon = icon('yogstation/icons/mob/antag_hud.dmi', "rev_head")
+ var/icon/rev_head_icon = icon('modular_dripstation/icons/mob/hud.dmi', "rev_head") //dripstation edit
rev_head_icon.Scale(48, 48)
rev_head_icon.Crop(1, 1, 64, 64)
rev_head_icon.Shift(EAST, 10)
diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm
index cd2eb6972683..75f8fd51ee9c 100644
--- a/code/modules/assembly/mousetrap.dm
+++ b/code/modules/assembly/mousetrap.dm
@@ -9,6 +9,13 @@
var/armed = FALSE
+/obj/item/assembly/mousetrap/Initialize(mapload)
+ . = ..()
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(trap_stepped_on),
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
+
/obj/item/assembly/mousetrap/examine(mob/user)
. = ..()
. += span_notice("The pressure plate is [armed?"primed":"safe"].")
@@ -109,7 +116,7 @@
return ..()
-/obj/item/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj)
+/obj/item/assembly/mousetrap/proc/trap_stepped_on(datum/source, atom/movable/AM, ...)
if(armed)
if(ismob(AM))
var/mob/MM = AM
@@ -124,7 +131,7 @@
triggered(MM)
else if(AM.density) // For mousetrap grenades, set off by anything heavy
triggered(AM)
- ..()
+ return
/obj/item/assembly/mousetrap/on_found(mob/finder)
diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm
index fd72dc814a4d..0ac3e148490a 100644
--- a/code/modules/asset_cache/asset_list_items.dm
+++ b/code/modules/asset_cache/asset_list_items.dm
@@ -654,3 +654,59 @@
glow = "pod_glow_[glow]"
podIcon.Blend(icon(icon_file, glow), ICON_OVERLAY)
Insert("pod_asset[style]", podIcon)
+
+/datum/asset/spritesheet/rcd
+ name = "rcd-tgui"
+
+/datum/asset/spritesheet/rcd/create_spritesheets()
+ //We load airlock icons seperatly from other icons cause they need overlays
+
+ //load all category essential icon_states. format is icon_file = list of icon states we need from that file
+ var/list/essentials = list(
+ 'icons/mob/radial.dmi' = list("wallfloor", "delete", "dirwindow", "fullwindow", "dirwindow_r", "fullwindow_r", "cnorth", "csouth", "ceast", "cwest", "chair", "stool", "windoor", "secure_windoor"),
+ 'icons/obj/recycling.dmi' = list("conveyor_construct", "switch-off"),
+ 'icons/obj/structures.dmi' = list("window0", "rwindow0", "table", "glass_table"),
+ 'icons/obj/stock_parts.dmi' = list("box_1"),
+ )
+
+ var/icon/icon
+ for(var/icon_file as anything in essentials)
+ for(var/icon_state as anything in essentials[icon_file])
+ icon = icon(icon = icon_file, icon_state = icon_state)
+ Insert(sanitize_css_class_name(icon_state), icon)
+
+ //for each airlock type we create its overlayed version with the suffix Glass in the sprite name
+ var/list/airlocks = list(
+ "Standard" = 'icons/obj/doors/airlocks/station/public.dmi',
+ "Public" = 'icons/obj/doors/airlocks/station2/glass.dmi',
+ "Engineering" = 'icons/obj/doors/airlocks/station/engineering.dmi',
+ "Atmospherics" = 'icons/obj/doors/airlocks/station/atmos.dmi',
+ "Security" = 'icons/obj/doors/airlocks/station/security.dmi',
+ "Command" = 'icons/obj/doors/airlocks/station/command.dmi',
+ "Medical" = 'icons/obj/doors/airlocks/station/medical.dmi',
+ "Research" = 'icons/obj/doors/airlocks/station/research.dmi',
+ "Freezer" = 'icons/obj/doors/airlocks/station/freezer.dmi',
+ "Virology" = 'icons/obj/doors/airlocks/station/virology.dmi',
+ "Mining" = 'icons/obj/doors/airlocks/station/mining.dmi',
+ "Maintenance" = 'icons/obj/doors/airlocks/station/maintenance.dmi',
+ "External" = 'icons/obj/doors/airlocks/external/external.dmi',
+ "External Maintenance" = 'icons/obj/doors/airlocks/station/maintenanceexternal.dmi',
+ "Airtight Hatch" = 'icons/obj/doors/airlocks/hatch/centcom.dmi',
+ "Maintenance Hatch" = 'icons/obj/doors/airlocks/hatch/maintenance.dmi'
+ )
+ //these 3 types dont have glass doors
+ var/list/exclusion = list("Freezer", "Airtight Hatch", "Maintenance Hatch")
+
+ for(var/airlock_name in airlocks)
+ //solid door with overlay
+ icon = icon(icon = airlocks[airlock_name] , icon_state = "closed" , dir = SOUTH)
+ icon.Blend(icon(icon = airlocks[airlock_name], icon_state = "fill_closed", dir = SOUTH), ICON_OVERLAY)
+ Insert(sanitize_css_class_name(airlock_name), icon)
+
+ //exclude these glass types
+ if(airlock_name in exclusion)
+ continue
+
+ //glass door no overlay
+ icon = icon(airlocks[airlock_name] , "closed" , SOUTH)
+ Insert(sanitize_css_class_name("[airlock_name]Glass"), icon)
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index f0e24ee776a6..2b1ae7d7d4a3 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -429,7 +429,7 @@
GAS_PLASMA = 10,
)
-/datum/gas_reaction/bzformation/react(datum/gas_mixture/air)
+/datum/gas_reaction/bzformation/react(datum/gas_mixture/air, datum/holder)
var/pressure = air.return_pressure()
var/old_thermal_energy = air.thermal_energy()
@@ -448,7 +448,9 @@
air.adjust_moles(GAS_PLASMA, -2*reaction_efficency)
//clamps by a minimum amount in the event of an underflow.
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, clamp((reaction_efficency**2)*BZ_RESEARCH_AMOUNT,0.01,BZ_RESEARCH_MAX_AMOUNT))
+ var/turf/holder_turf = get_holder_turf(holder)
+ if(holder_turf && SSmapping.level_trait(holder_turf.z, ZTRAIT_STATION))
+ SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, clamp((reaction_efficency**2)*BZ_RESEARCH_AMOUNT,0.01,BZ_RESEARCH_MAX_AMOUNT))
if(energy_released > 0)
var/new_heat_capacity = air.heat_capacity()
@@ -467,7 +469,7 @@
GAS_TRITIUM = 10,
"TEMP" = 5000000)
-/datum/gas_reaction/nobliumformation/react(datum/gas_mixture/air)
+/datum/gas_reaction/nobliumformation/react(datum/gas_mixture/air, datum/holder)
var/initial_trit = air.get_moles(GAS_TRITIUM)
var/initial_n2 = air.get_moles(GAS_N2)
var/initial_bz = air.get_moles(GAS_BZ)
@@ -480,7 +482,11 @@
air.adjust_moles(GAS_TRITIUM, -10*nob_formed)
air.adjust_moles(GAS_N2, -20*nob_formed)
air.adjust_moles(GAS_HYPERNOB, nob_formed)
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, clamp(nob_formed*NOBLIUM_RESEARCH_AMOUNT, 0.01, NOBLIUM_RESEARCH_MAX_AMOUNT))
+
+ var/turf/holder_turf = get_holder_turf(holder)
+ if(holder_turf && SSmapping.level_trait(holder_turf.z, ZTRAIT_STATION))
+ SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, clamp(nob_formed*NOBLIUM_RESEARCH_AMOUNT, 0.01, NOBLIUM_RESEARCH_MAX_AMOUNT))
+
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
air.set_temperature(max(((old_thermal_energy - energy_taken)/new_heat_capacity),TCMB))
@@ -510,7 +516,10 @@
//Possibly burning a bit of organic matter through maillard reaction, so a *tiny* bit more heat would be understandable
air.set_temperature(air.return_temperature() + cleaned_air * 0.002)
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, clamp(cleaned_air*MIASMA_RESEARCH_AMOUNT,0.01, MIASMA_RESEARCH_MAX_AMOUNT))//Turns out the burning of miasma is kinda interesting to scientists
+
+ var/turf/holder_turf = get_holder_turf(holder)
+ if(holder_turf && SSmapping.level_trait(holder_turf.z, ZTRAIT_STATION))
+ SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, clamp(cleaned_air*MIASMA_RESEARCH_AMOUNT,0.01, MIASMA_RESEARCH_MAX_AMOUNT))//Turns out the burning of miasma is kinda interesting to scientists
return REACTING
/datum/gas_reaction/nitro_ball
@@ -730,7 +739,9 @@
if (prob(25 * increase_factor))
air.adjust_moles(GAS_H2, -(heat_efficency * 10))
new /obj/item/stack/sheet/mineral/metal_hydrogen(location)
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min((heat_efficency * increase_factor * 0.5), METAL_HYDROGEN_RESEARCH_MAX_AMOUNT))
+ var/turf/holder_turf = get_holder_turf(holder)
+ if(holder_turf && SSmapping.level_trait(holder_turf.z, ZTRAIT_STATION))
+ SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min((heat_efficency * increase_factor * 0.5), METAL_HYDROGEN_RESEARCH_MAX_AMOUNT))
if(energy_used > 0)
var/new_heat_capacity = air.heat_capacity()
diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm
index 700b970fb1d6..209408558b01 100644
--- a/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm
+++ b/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm
@@ -251,10 +251,11 @@
var/remove_amount = round(min(fuel_list[gas_id], fuel_consumption), 0.01)
internal_fusion.adjust_moles(gas_id, -remove_amount)
delta_fuel_list[gas_id] -= remove_amount
+
+ var/add_remove_amount = round(scaled_production, 0.01) // gases on the same tier are produced at normal rate
for(var/gas_id in fuel.primary_products)
- var/add_amount = round(fuel_consumption * 0.5, 0.01)
- internal_fusion.adjust_moles(gas_id, add_amount)
- delta_fuel_list[gas_id] += add_amount
+ internal_fusion.adjust_moles(gas_id, add_remove_amount)
+ delta_fuel_list[gas_id] += add_remove_amount
if(power_level < 1)
return // can't produce any gases, don't need to continue
@@ -262,8 +263,8 @@
// Each recipe provides a tier list of six output gases.
// Which gases are produced depend on what the fusion level is.
var/list/tier = fuel.secondary_products
- moderator_internal.adjust_moles(tier[power_level], round(scaled_production, 0.01)) // gases on the same tier are produced at normal rate
- delta_mod_list[tier[power_level]] += round(scaled_production, 0.01)
+ moderator_internal.adjust_moles(tier[power_level], add_remove_amount)
+ delta_mod_list[tier[power_level]] += add_remove_amount
if(power_level < 6)
moderator_internal.adjust_moles(tier[power_level + 1], round(scaled_production * 0.5, 0.01)) // gases on the above tier are produced at reduced rate
delta_mod_list[tier[power_level + 1]] += round(scaled_production * 0.5, 0.01)
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index 42abcc19fd6f..d6de11c10b18 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -40,7 +40,7 @@
"generic striped" = /obj/machinery/portable_atmospherics/canister/generic/stripe,
"generic hazard" = /obj/machinery/portable_atmospherics/canister/generic/hazard,
"caution" = /obj/machinery/portable_atmospherics/canister,
- "danger" = /obj/machinery/portable_atmospherics/canister/fusion_test,
+ "danger" = /obj/machinery/portable_atmospherics/canister/fusion,
"n2" = /obj/machinery/portable_atmospherics/canister/nitrogen,
"o2" = /obj/machinery/portable_atmospherics/canister/oxygen,
"co2" = /obj/machinery/portable_atmospherics/canister/carbon_dioxide,
@@ -168,56 +168,56 @@
/obj/machinery/portable_atmospherics/canister/freon
name = "Freon canister"
- desc = "Freon. Can absorb heat"
+ desc = "Freon. Can absorb heat."
icon_state = "freon"
gas_type = GAS_FREON
filled = 1
/obj/machinery/portable_atmospherics/canister/hydrogen
name = "Hydrogen canister"
- desc = "Hydrogen, highly flammable"
+ desc = "Hydrogen, highly flammable."
icon_state = "h2"
gas_type = GAS_H2
filled = 1
/obj/machinery/portable_atmospherics/canister/healium
name = "Healium canister"
- desc = "Healium, causes deep sleep"
+ desc = "Healium, causes deep sleep."
icon_state = "healium"
gas_type = GAS_HEALIUM
filled = 1
/obj/machinery/portable_atmospherics/canister/pluonium
name = "Pluonium canister"
- desc = "Pluonium, reacts differently with various gases"
+ desc = "Pluonium, reacts differently with various gases."
icon_state = "pluonium"
gas_type = GAS_PLUONIUM
filled = 1
/obj/machinery/portable_atmospherics/canister/halon
name = "Halon canister"
- desc = "Halon, remove oxygen from high temperature fires and cool down the area"
+ desc = "Halon, remove oxygen from high temperature fires and cool down the area."
icon_state = "halon"
gas_type = GAS_HALON
filled = 1
/obj/machinery/portable_atmospherics/canister/hexane
name = "Hexane canister"
- desc = "hexane, highly flammable."
+ desc = "Hexane, highly flammable."
icon_state = "hexane"
gas_type = GAS_HEXANE
filled = 1
/obj/machinery/portable_atmospherics/canister/zauker
name = "Zauker canister"
- desc = "Zauker, highly toxic"
+ desc = "Zauker, highly toxic."
icon_state = "zauker"
gas_type = GAS_ZAUKER
filled = 1
/obj/machinery/portable_atmospherics/canister/antinoblium
name = "Antinoblium canister"
- desc = "Antinoblium, we still don't know what it does, but it sells for a lot"
+ desc = "Antinoblium, we still don't know what it does, but it sells for a lot."
icon_state = "antino"
gas_type = GAS_ANTINOB
filled = 1
@@ -566,6 +566,12 @@
analyzer_act(user, src)
return ..()
+/obj/machinery/portable_atmospherics/canister/fusion
+ name = "Fusion Canister"
+ desc = "A violent mix of gases resulting in a fusion reaction inside the canister.
\
+ A note on the side reads: \"DANGER: DO NOT OPEN\""
+ icon_state = "danger"
+
/* yog- ADMEME CANISTERS */
/// Canister 1 Kelvin below the fusion point. Is highly unoptimal, do not spawn to start fusion, only good for testing low instability mixes.
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index dd07e425d30a..21396361cc4b 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -183,7 +183,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot))
player_alt_titles = SANITIZE_LIST(player_alt_titles)
- toggles = sanitize_integer(toggles, 0, ~0, initial(toggles)) // Yogs -- Fixes toggles not having >16 bits of flagspace
+ toggles = sanitize_integer(toggles, 0, SHORT_REAL_LIMIT-1, initial(toggles))
key_bindings = sanitize_keybindings(key_bindings)
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index 64c244fa5b72..cd98d5465b88 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -11,22 +11,21 @@
materials = list(/datum/material/glass = 250)
var/vision_flags = 0
var/invis_view = SEE_INVISIBLE_LIVING //admin only for now
- var/invis_override = 0 //Override to allow glasses to set higher than normal see_invis
- var/list/icon/current = list() //the current hud icons
- var/vision_correction = 0 //does wearing these glasses correct some of our vision defects?
- var/glass_colour_type //colors your vision when worn
-
+ /// Override to allow glasses to set higher than normal see_invis
+ var/invis_override = 0
/// A percentage of how much rgb to "max" on the lighting plane
/// This lets us brighten darkness without washing out bright color
var/lighting_cutoff = null
/// Similar to lighting_cutoff, except it has individual r g and b components in the same 0-100 scale
var/list/color_cutoffs = null
-// Potentially replace glass_color_type with a setup that colors lighting by dropping segments of different componets
-// Like the current idea, but applied without the mass cutoff (maybe? somehow?)
-// That or just a light color to the lighting plane, that'd work too
-// Enough to make it visible but not so much that it's a pain
-
-// That, or just make stuff that uses lighting_cutoff have colored offsets and all, like you were planning
+ /// The current hud icons
+ var/list/icon/current = list()
+ /// Colors your vision when worn
+ var/glass_colour_type
+ /// Whether or not vision coloring is forcing
+ var/forced_glass_color = FALSE
+ //does wearing these glasses correct some of our vision defects?
+ var/vision_correction = 0
/obj/item/clothing/glasses/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] is stabbing \the [src] into [user.p_their()] eyes! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -533,14 +532,13 @@
return ..() && isliving(owner)
/datum/action/cooldown/expose/Activate(atom/exposed)
- StartCooldown(15 SECONDS)
-
if(owner.stat != CONSCIOUS)
return FALSE
if(!isliving(exposed) || exposed == owner)
owner.balloon_alert(owner, "invalid exposed!")
return FALSE
-
+ StartCooldown(15 SECONDS)
+
var/mob/living/living_exposed = exposed
living_exposed.apply_status_effect(STATUS_EFFECT_EXPOSED)
living_exposed.adjust_jitter(5 SECONDS)
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 5579278a21a3..70084ff9db3f 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -375,7 +375,7 @@ GLOBAL_LIST_INIT(cursed_animal_masks, list(
/obj/item/clothing/mask/rmask
name = "dusty mask"
- desc = "A face is nothing, it’s what’s inside that matters."
+ desc = "A face is nothing, it's what's inside that matters."
icon_state = "rmask"
item_state = "rmaks"
flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
@@ -384,7 +384,7 @@ GLOBAL_LIST_INIT(cursed_animal_masks, list(
/obj/item/clothing/mask/pocketcatmask
name = "peculiar cat mask"
- desc = "this mask makes you a little uneasy"
+ desc = "This mask makes you a little uneasy."
icon_state = "pocketmask"
item_state = "pocketmask"
flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
diff --git a/code/modules/clothing/neck/skillcapes/skillcapes.dm b/code/modules/clothing/neck/skillcapes/skillcapes.dm
index 56972e5a33bc..6d67e97bed06 100644
--- a/code/modules/clothing/neck/skillcapes/skillcapes.dm
+++ b/code/modules/clothing/neck/skillcapes/skillcapes.dm
@@ -11,7 +11,7 @@
/obj/item/clothing/neck/skillcape/trimmed
name = "trimmed cape of skill"
- desc = "a golden trimmed cape, marks proof of excellence."
+ desc = "A golden-trimmed cape, marks proof of excellence."
/obj/item/clothing/neck/skillcape/admin
name = "cape of mighty judgement"
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 78fbc7bae03f..64ab89735680 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -202,7 +202,7 @@
/obj/item/clothing/under/cloud
name = "cloud"
- desc = "cloud"
+ desc = "Cloud."
icon_state = "cloud"
can_adjust = FALSE
diff --git a/code/modules/economy/pay_stand.dm b/code/modules/economy/pay_stand.dm
index 1e32fe3adb1e..565956699d4e 100644
--- a/code/modules/economy/pay_stand.dm
+++ b/code/modules/economy/pay_stand.dm
@@ -1,6 +1,6 @@
/obj/machinery/paystand
name = "unregistered pay stand"
- desc = "an unregistered pay stand"
+ desc = "An unregistered pay stand, ready to be linked to an account."
icon = 'icons/obj/economy.dmi'
icon_state = "card_scanner"
anchored = TRUE
diff --git a/code/modules/events/shuttle_catastrophe.dm b/code/modules/events/shuttle_catastrophe.dm
index 7fa850c78943..4ed74ae0b931 100644
--- a/code/modules/events/shuttle_catastrophe.dm
+++ b/code/modules/events/shuttle_catastrophe.dm
@@ -37,5 +37,5 @@
SSshuttle.load_template(new_shuttle)
SSshuttle.existing_shuttle = SSshuttle.emergency
SSshuttle.emergency.name = new_shuttle.name
- SSshuttle.action_load(new_shuttle)
+ SSshuttle.action_load(new_shuttle, replace = TRUE)
log_game("Shuttle Catastrophe set a new shuttle, [new_shuttle.name].")
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 9880855e6d27..bbb28b85863c 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -3,7 +3,7 @@
////////////////////////////////////////////////////////////////////////////////
/obj/item/reagent_containers/food/drinks
name = "drink"
- desc = "yummy"
+ desc = "Yummy."
icon = 'icons/obj/drinks.dmi'
icon_state = "pineapplejuice" // Shouldn't see this anyways.
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
diff --git a/code/modules/food_and_drinks/food/snacks_seafood.dm b/code/modules/food_and_drinks/food/snacks_seafood.dm
index d0574f6af193..46b3e93ee46f 100644
--- a/code/modules/food_and_drinks/food/snacks_seafood.dm
+++ b/code/modules/food_and_drinks/food/snacks_seafood.dm
@@ -178,7 +178,7 @@
/obj/item/reagent_containers/food/snacks/fishdumpling
name = "fish dumpling"
- desc = "a powerful little pocket of flavor."
+ desc = "A powerful little pocket of flavor."
icon_state = "fishdumpling"
bonus_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 10)
list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 15) //delicious onion and garlic and fish
diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm
index dbcdde5169c5..c0b8bd142596 100644
--- a/code/modules/holodeck/turfs.dm
+++ b/code/modules/holodeck/turfs.dm
@@ -89,18 +89,18 @@
icon_state = SPACE_ICON_STATE // so realistic
. = ..()
-/turf/open/floor/holofloor/hyperspace
- name = "\proper hyperspace"
+/turf/open/floor/holofloor/bluespace
+ name = "\proper bluespace"
icon = 'icons/turf/space.dmi'
icon_state = "speedspace_ns_1"
bullet_bounce_sound = null
tiled_dirt = FALSE
-/turf/open/floor/holofloor/hyperspace/Initialize(mapload)
+/turf/open/floor/holofloor/bluespace/Initialize(mapload)
icon_state = "speedspace_ns_[(x + 5*y + (y%2+1)*7)%15+1]"
. = ..()
-/turf/open/floor/holofloor/hyperspace/ns/Initialize(mapload)
+/turf/open/floor/holofloor/bluespace/ns/Initialize(mapload)
. = ..()
icon_state = "speedspace_ns_[(x + 5*y + (y%2+1)*7)%15+1]"
diff --git a/code/modules/jobs/departments/departments.dm b/code/modules/jobs/departments/departments.dm
index a629c2eaab62..81b44473b7fa 100644
--- a/code/modules/jobs/departments/departments.dm
+++ b/code/modules/jobs/departments/departments.dm
@@ -43,7 +43,7 @@
department_experience_type = EXP_TYPE_COMMAND
display_order = 1
label_class = "command"
- ui_color = "#ccccff"
+ ui_color = "#6681a5"
/datum/job_department/security
@@ -53,7 +53,7 @@
department_experience_type = EXP_TYPE_SECURITY
display_order = 2
label_class = "security"
- ui_color = "#ffbbbb"
+ ui_color = "#d46a78"
/datum/job_department/engineering
@@ -63,7 +63,7 @@
department_experience_type = EXP_TYPE_ENGINEERING
display_order = 3
label_class = "engineering"
- ui_color = "#ffeeaa"
+ ui_color = "#dfb567"
/datum/job_department/medical
@@ -73,7 +73,7 @@
department_experience_type = EXP_TYPE_MEDICAL
display_order = 4
label_class = "medical"
- ui_color = "#c1e1ec"
+ ui_color = "#65b2bd"
/datum/job_department/science
@@ -83,7 +83,7 @@
department_experience_type = EXP_TYPE_SCIENCE
display_order = 5
label_class = "science"
- ui_color = "#ffddff"
+ ui_color = "#c973c9"
/datum/job_department/cargo
@@ -93,7 +93,7 @@
department_experience_type = EXP_TYPE_SUPPLY
display_order = 6
label_class = "supply"
- ui_color = "#d7b088"
+ ui_color = "#cf9c6c"
/datum/job_department/service
@@ -103,7 +103,7 @@
department_experience_type = EXP_TYPE_SERVICE
display_order = 7
label_class = "service"
- ui_color = "#ddddff"
+ ui_color = "#7cc46a"
/datum/job_department/silicon
@@ -113,7 +113,7 @@
department_experience_type = EXP_TYPE_SILICON
display_order = 8
label_class = "silicon"
- ui_color = "#ccffcc"
+ ui_color = "#5dbda0"
/// Catch-all department for undefined jobs.
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 0a7c80874597..f9ec46ba90f7 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -47,8 +47,6 @@
/// What kind of mob type joining players with this job as their assigned role are spawned as.
var/spawn_type = /mob/living/carbon/human
- /// Selection Color for job preferences
- var/selection_color = "#ffffff"
/// Alternate titles for the job
var/list/alt_titles
/// If this is set to TRUE, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect.
@@ -134,7 +132,6 @@
Here is another example of using this:
/datum/job/doctor/proc/OmegaStationChanges()
- selection_color = "#ffffff"
total_positions = 3
spawn_positions = 3
added_access = list()
diff --git a/code/modules/jobs/job_types/ai.dm b/code/modules/jobs/job_types/ai.dm
index 62a8798e8b7c..c2f33e9b666b 100644
--- a/code/modules/jobs/job_types/ai.dm
+++ b/code/modules/jobs/job_types/ai.dm
@@ -6,7 +6,6 @@
faction = "Station"
total_positions = 1
spawn_positions = 1
- selection_color = "#ccffcc"
supervisors = "your laws"
req_admin_notify = TRUE
minimal_player_age = 30
diff --git a/code/modules/jobs/job_types/artist.dm b/code/modules/jobs/job_types/artist.dm
index 55784466133e..28dfe08cc02e 100644
--- a/code/modules/jobs/job_types/artist.dm
+++ b/code/modules/jobs/job_types/artist.dm
@@ -7,7 +7,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#dddddd"
outfit = /datum/outfit/job/artist
alt_titles = list("Painter", "Composer", "Artisan")
diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm
index 666a68b0f168..b2427dfdefde 100644
--- a/code/modules/jobs/job_types/assistant.dm
+++ b/code/modules/jobs/job_types/assistant.dm
@@ -9,7 +9,6 @@ Assistant
total_positions = 5
spawn_positions = 5
supervisors = "absolutely everyone"
- selection_color = "#dddddd"
added_access = list() //See /datum/job/assistant/get_access()
base_access = list() //See /datum/job/assistant/get_access()
outfit = /datum/outfit/job/assistant
diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm
index 2d4b57815cd2..dc0d460ed354 100644
--- a/code/modules/jobs/job_types/atmospheric_technician.dm
+++ b/code/modules/jobs/job_types/atmospheric_technician.dm
@@ -7,7 +7,6 @@
total_positions = 3
spawn_positions = 2
supervisors = "the chief engineer"
- selection_color = "#fff5cc"
exp_requirements = 180
exp_type = EXP_TYPE_CREW
alt_titles = list("Life-support Technician", "Fire Suppression Specialist", "Atmospherics Trainee", "Environmental Maintainer", "Fusion Specialist")
diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm
index 66fce46dc27a..eca2c26c67e6 100644
--- a/code/modules/jobs/job_types/bartender.dm
+++ b/code/modules/jobs/job_types/bartender.dm
@@ -7,7 +7,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#bbe291"
exp_type_department = EXP_TYPE_SERVICE // This is so the jobs menu can work properly
alt_titles = list("Barkeep", "Tapster", "Barista", "Mixologist")
diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm
index 3e366db34668..b63b4e969c52 100644
--- a/code/modules/jobs/job_types/botanist.dm
+++ b/code/modules/jobs/job_types/botanist.dm
@@ -7,7 +7,6 @@
total_positions = 3
spawn_positions = 2
supervisors = "the head of personnel"
- selection_color = "#bbe291"
outfit = /datum/outfit/job/botanist
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index 6365594bd8dc..75d55d8b4aed 100644
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -10,7 +10,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "Nanotrasen officers and Space law" //Changed to officer to separate from CentCom officials being their superior.
- selection_color = "#ccccff"
req_admin_notify = 1
space_law_notify = 1 //Yogs
minimal_player_age = 14
diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm
index 14ea8105f32b..ab2a5973a9bd 100644
--- a/code/modules/jobs/job_types/cargo_technician.dm
+++ b/code/modules/jobs/job_types/cargo_technician.dm
@@ -9,7 +9,6 @@
total_positions = 2
spawn_positions = 1
supervisors = "the quartermaster and the head of personnel"
- selection_color = "#dcba97"
outfit = /datum/outfit/job/cargo_tech
diff --git a/code/modules/jobs/job_types/chaplain.dm b/code/modules/jobs/job_types/chaplain.dm
index 3cd1ee881bd2..42a2cb83d797 100644
--- a/code/modules/jobs/job_types/chaplain.dm
+++ b/code/modules/jobs/job_types/chaplain.dm
@@ -8,7 +8,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#dddddd"
outfit = /datum/outfit/job/chaplain
diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm
index 140bd0337c28..72b93fbb9ddc 100644
--- a/code/modules/jobs/job_types/chemist.dm
+++ b/code/modules/jobs/job_types/chemist.dm
@@ -8,7 +8,6 @@
total_positions = 2
spawn_positions = 2
supervisors = "the chief medical officer"
- selection_color = "#d4ebf2"
exp_type = EXP_TYPE_CREW
exp_requirements = 120
exp_type_department = EXP_TYPE_MEDICAL
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
index 9c0b7297f63d..c7004ee741a3 100644
--- a/code/modules/jobs/job_types/chief_engineer.dm
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -10,7 +10,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the captain"
- selection_color = "#ffeeaa"
req_admin_notify = 1
minimal_player_age = 7
exp_requirements = 1500 //25 hours
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
index 2bc428901cc5..2dec1ebd5fe6 100644
--- a/code/modules/jobs/job_types/chief_medical_officer.dm
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -10,7 +10,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the captain"
- selection_color = "#c1e1ec"
req_admin_notify = 1
minimal_player_age = 7
exp_requirements = 1500 //25 hours
diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm
index 7fc1b36a9f38..4c38c09cb965 100644
--- a/code/modules/jobs/job_types/clown.dm
+++ b/code/modules/jobs/job_types/clown.dm
@@ -7,7 +7,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#dddddd"
outfit = /datum/outfit/job/clown
diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm
index b0efc565e7a6..3100197198af 100644
--- a/code/modules/jobs/job_types/cook.dm
+++ b/code/modules/jobs/job_types/cook.dm
@@ -7,7 +7,6 @@
total_positions = 2
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#bbe291"
var/cooks = 0 //Counts cooks amount
outfit = /datum/outfit/job/cook
diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm
index eb7aae9266a3..5d8e15bc38ec 100644
--- a/code/modules/jobs/job_types/curator.dm
+++ b/code/modules/jobs/job_types/curator.dm
@@ -8,7 +8,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#dddddd"
outfit = /datum/outfit/job/curator
diff --git a/code/modules/jobs/job_types/cyborg.dm b/code/modules/jobs/job_types/cyborg.dm
index c1b202ae57f1..b2b714a9d6c1 100644
--- a/code/modules/jobs/job_types/cyborg.dm
+++ b/code/modules/jobs/job_types/cyborg.dm
@@ -7,7 +7,6 @@
total_positions = 0
spawn_positions = 2
supervisors = "your laws and the AI" //Nodrak
- selection_color = "#ddffdd"
minimal_player_age = 21
exp_requirements = 120
exp_type = EXP_TYPE_CREW
diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm
index ddc4fd758b16..328700db625e 100644
--- a/code/modules/jobs/job_types/detective.dm
+++ b/code/modules/jobs/job_types/detective.dm
@@ -9,7 +9,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of security"
- selection_color = "#ffeeee"
minimal_player_age = 7
exp_requirements = 180
exp_type = EXP_TYPE_SECURITY
diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm
index 2b92768b71bd..27db89c87a40 100644
--- a/code/modules/jobs/job_types/geneticist.dm
+++ b/code/modules/jobs/job_types/geneticist.dm
@@ -7,7 +7,6 @@
total_positions = 2
spawn_positions = 2
supervisors = "the chief medical officer and research director"
- selection_color = "#d4ebf2"
exp_type = EXP_TYPE_CREW
exp_requirements = 60
alt_titles = list("DNA Mechanic", "Bioengineer", "Junior Geneticist", "Gene Splicer", "Mutation Specialist")
diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm
index 4d684d9a14ca..681574e1cfaf 100644
--- a/code/modules/jobs/job_types/head_of_personnel.dm
+++ b/code/modules/jobs/job_types/head_of_personnel.dm
@@ -10,7 +10,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the captain"
- selection_color = "#ddddff"
req_admin_notify = 1
minimal_player_age = 10
exp_requirements = 720 //fairly low skill job
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
index b3449b86cc8e..434c3627504c 100644
--- a/code/modules/jobs/job_types/head_of_security.dm
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -10,7 +10,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the captain"
- selection_color = "#ffdddd"
req_admin_notify = 1
minimal_player_age = 14
exp_requirements = 1500 //25 hours
diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm
index 55e6708188cd..a14f9ee38454 100644
--- a/code/modules/jobs/job_types/janitor.dm
+++ b/code/modules/jobs/job_types/janitor.dm
@@ -7,7 +7,6 @@
total_positions = 2
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#bbe291"
outfit = /datum/outfit/job/janitor
diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm
index 2e4c1aaa7850..edcce8838c85 100644
--- a/code/modules/jobs/job_types/lawyer.dm
+++ b/code/modules/jobs/job_types/lawyer.dm
@@ -8,7 +8,6 @@
total_positions = 2
spawn_positions = 2
supervisors = "the head of personnel"
- selection_color = "#dddddd"
var/lawyers = 0 //Counts lawyer amount
alt_titles = list("Prosecutor", "Defense Attorney", "Paralegal", "Ace Attorney")
diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm
index dd83f89c8d16..b44a4dcf9e6a 100644
--- a/code/modules/jobs/job_types/medical_doctor.dm
+++ b/code/modules/jobs/job_types/medical_doctor.dm
@@ -8,7 +8,6 @@
total_positions = 5
spawn_positions = 3
supervisors = "the chief medical officer"
- selection_color = "#d4ebf2"
exp_requirements = 180
exp_type = EXP_TYPE_CREW
alt_titles = list("Physician", "Surgeon", "Nurse", "Medical Resident", "Attending Physician", "General Practitioner")
diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm
index c64526aeb6bb..3826212f52f1 100644
--- a/code/modules/jobs/job_types/mime.dm
+++ b/code/modules/jobs/job_types/mime.dm
@@ -7,7 +7,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#dddddd"
outfit = /datum/outfit/job/mime
diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm
index e30304d00b2c..4442590fe746 100644
--- a/code/modules/jobs/job_types/quartermaster.dm
+++ b/code/modules/jobs/job_types/quartermaster.dm
@@ -8,7 +8,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#d7b088"
outfit = /datum/outfit/job/quartermaster
alt_titles = list("Stock Controller", "Cargo Coordinator", "Shipping Overseer", "Postmaster General")
added_access = list()
diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm
index e381a867427a..b6a91ef5c87d 100644
--- a/code/modules/jobs/job_types/research_director.dm
+++ b/code/modules/jobs/job_types/research_director.dm
@@ -11,7 +11,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the captain"
- selection_color = "#ffddff"
req_admin_notify = 1
minimal_player_age = 7
exp_type_department = EXP_TYPE_SCIENCE
diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm
index b798d1c85e75..b90ccf3d6aec 100644
--- a/code/modules/jobs/job_types/roboticist.dm
+++ b/code/modules/jobs/job_types/roboticist.dm
@@ -7,7 +7,6 @@
total_positions = 2
spawn_positions = 2
supervisors = "the research director"
- selection_color = "#ffeeff"
exp_requirements = 60
exp_type = EXP_TYPE_CREW
alt_titles = list("Augmentation Theorist", "Cyborg Maintainer", "Robotics Intern", "Biomechanical Engineer", "Mechatronic Engineer", "Machinist", "Chrome Shaman", "Ripperdoc")
diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm
index b69a337ab166..725a217f3155 100644
--- a/code/modules/jobs/job_types/scientist.dm
+++ b/code/modules/jobs/job_types/scientist.dm
@@ -7,7 +7,6 @@
total_positions = 5
spawn_positions = 3
supervisors = "the research director"
- selection_color = "#ffeeff"
exp_requirements = 180
exp_type = EXP_TYPE_CREW
alt_titles = list("Researcher", "Toxins Specialist", "Physicist", "Test Associate", "Anomalist", "Quantum Physicist", "Theoretical Physicist", "Xenobiologist", "Explosives Technician", "Hypothetical Physicist")
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 30564c5c89cf..1b231992929c 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -9,7 +9,6 @@
total_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions()
spawn_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions()
supervisors = "the head of security, and the head of your assigned department (if applicable)"
- selection_color = "#ffeeee"
minimal_player_age = 7
exp_requirements = 300
exp_type = EXP_TYPE_CREW
diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm
index 1163f300518e..5776843d03b4 100644
--- a/code/modules/jobs/job_types/shaft_miner.dm
+++ b/code/modules/jobs/job_types/shaft_miner.dm
@@ -8,7 +8,6 @@
total_positions = 3
spawn_positions = 3
supervisors = "the quartermaster and the head of personnel"
- selection_color = "#dcba97"
alt_titles = list("Lavaland Scout", "Prospector", "Junior Miner", "Major Miner", "Surveyor")
outfit = /datum/outfit/job/miner
diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm
index 1caf26068293..e96c1dee2768 100644
--- a/code/modules/jobs/job_types/station_engineer.dm
+++ b/code/modules/jobs/job_types/station_engineer.dm
@@ -8,7 +8,6 @@
total_positions = 5
spawn_positions = 5
supervisors = "the chief engineer"
- selection_color = "#fff5cc"
exp_requirements = 180
exp_type = EXP_TYPE_CREW
alt_titles = list("Engine Technician", "Solar Engineer", "Project Engineer", "Junior Engineer", "Construction Specialist")
diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm
index 837e74c86c6a..1e31e5e5330f 100644
--- a/code/modules/jobs/job_types/virologist.dm
+++ b/code/modules/jobs/job_types/virologist.dm
@@ -8,7 +8,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the chief medical officer"
- selection_color = "#d4ebf2"
exp_type = EXP_TYPE_CREW
exp_requirements = 120
minimal_player_age = 7
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index ccb68f5c0e1c..84f8838d2b08 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -10,7 +10,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of security"
- selection_color = "#ffeeee"
minimal_player_age = 7
exp_requirements = 600
exp_type = EXP_TYPE_CREW
diff --git a/code/modules/mining/aux_base_camera.dm b/code/modules/mining/aux_base_camera.dm
index 284b9641ff30..46f4850e0a7a 100644
--- a/code/modules/mining/aux_base_camera.dm
+++ b/code/modules/mining/aux_base_camera.dm
@@ -22,7 +22,7 @@
dir = direct //This camera eye is visible as a drone, and needs to keep the dir updated
..()
-/obj/item/construction/rcd/internal //Base console's internal RCD. Roundstart consoles are filled, rebuilt cosoles start empty.
+/obj/item/construction/rcd/internal //Base console's internal RCD. Roundstart consoles are filled, rebuilt consoles start empty.
name = "internal RCD"
max_matter = 600 //Bigger container and faster speeds due to being specialized and stationary.
no_ammo_message = span_warning("Internal matter exhausted. Please add additional materials.")
@@ -43,10 +43,8 @@
var/obj/item/construction/rcd/internal/RCD //Internal RCD. The computer passes user commands to this in order to avoid massive copypaste.
var/obj/machinery/computer/auxiliary_base/found_aux_console //Tracker for the Aux base console, so the eye can always find it.
- var/datum/action/innate/aux_base/switch_mode/switch_mode_action = new //Action for switching the RCD's build modes
+ var/datum/action/innate/aux_base/configure_mode/configure_mode_action = new //Action for switching the RCD's build modes
var/datum/action/innate/aux_base/build/build_action = new //Action for using the RCD
- var/datum/action/innate/aux_base/airlock_type/airlock_mode_action = new //Action for setting the airlock type
- var/datum/action/innate/aux_base/window_type/window_action = new //Action for setting the window type
var/fans_remaining = 0 //Number of fans in stock.
var/datum/action/innate/aux_base/place_fan/fan_action = new //Action for spawning fans
var/turret_stock = 0 //Turrets in stock
@@ -96,26 +94,16 @@
/obj/machinery/computer/camera_advanced/base_construction/GrantActions(mob/living/user)
..()
- if(switch_mode_action)
- switch_mode_action.target = src
- switch_mode_action.Grant(user)
- actions += switch_mode_action
+ if(configure_mode_action)
+ configure_mode_action.target = src
+ configure_mode_action.Grant(user)
+ actions += configure_mode_action
if(build_action)
build_action.target = src
build_action.Grant(user)
actions += build_action
- if(airlock_mode_action)
- airlock_mode_action.target = src
- airlock_mode_action.Grant(user)
- actions += airlock_mode_action
-
- if(window_action)
- window_action.target = src
- window_action.Grant(user)
- actions += window_action
-
if(fan_action)
fan_action.target = src
fan_action.Grant(user)
@@ -190,38 +178,17 @@
B.RCD.afterattack(rcd_target, owner, TRUE) //Activate the RCD and force it to work remotely!
playsound(target_turf, 'sound/items/deconstruct.ogg', 60, 1)
-/datum/action/innate/aux_base/switch_mode
- name = "Switch Mode"
- button_icon_state = "builder_mode"
-
-/datum/action/innate/aux_base/switch_mode/Activate()
- if(..())
- return
-
- var/list/buildlist = list("Walls and Floors" = RCD_FLOORWALL,"Airlocks" = RCD_AIRLOCK,"Deconstruction" = RCD_DECONSTRUCT,"Windows and Grilles" = RCD_WINDOWGRILLE)
- var/buildmode = input(owner, "Set construction mode.", "Base Console", null) in buildlist
- B.RCD.mode = buildlist[buildmode]
- to_chat(owner, "Build mode is now [buildmode].")
+/datum/action/innate/aux_base/configure_mode
+ name = "Configure RCD"
+ button_icon = 'icons/obj/tools.dmi'
+ button_icon_state = "rcd"
-/datum/action/innate/aux_base/airlock_type
- name = "Select Airlock Type"
- button_icon_state = "airlock_select"
-
-datum/action/innate/aux_base/airlock_type/Activate()
+/datum/action/innate/aux_base/configure_mode/Activate()
if(..())
return
- B.RCD.change_airlock_setting(owner, remote_eye)
-
-
-datum/action/innate/aux_base/window_type
- name = "Select Window Glass"
- button_icon_state = "window_select"
-
-datum/action/innate/aux_base/window_type/Activate()
- if(..())
- return
- B.RCD.toggle_window_glass(owner)
+ B.RCD.owner = B
+ B.RCD.ui_interact(owner)
datum/action/innate/aux_base/place_fan
name = "Place Tiny Fan"
diff --git a/code/modules/mining/fulton.dm b/code/modules/mining/fulton.dm
index 7e085227c744..19eea5ae191a 100644
--- a/code/modules/mining/fulton.dm
+++ b/code/modules/mining/fulton.dm
@@ -200,7 +200,7 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
/obj/effect/extraction_holder
name = "extraction holder"
- desc = "you shouldnt see this"
+ desc = "You shouldn't see this."
var/atom/movable/stored_obj
/obj/item/extraction_pack/proc/check_for_living_mobs(atom/A)
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 8eb74ad1ddfe..859732d9b6d3 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -317,7 +317,7 @@ GLOBAL_LIST_EMPTY(aide_list)
/obj/effect/wisp/proc/update_user_sight(mob/user)
SIGNAL_HANDLER
- user.sight |= sight_flags
+ user.add_sight(sight_flags)
if(!isnull(color_cutoffs))
user.lighting_color_cutoffs = blend_cutoff_colors(user.lighting_color_cutoffs, color_cutoffs)
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index d6597e8a269f..41065300c24f 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -19,15 +19,19 @@
var/icon_deny = "mining-deny"
var/list/prize_list = list( //if you add something to this, please, for the love of god, sort it by price/type. use tabs and not spaces.
new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750, VENDING_WEAPON),
- new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/kinetic_crusher, 750, VENDING_WEAPON),
+ new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/kinetic_crusher, 750, VENDING_WEAPON),
new /datum/data/mining_equipment("Resonator", /obj/item/resonator, 800, VENDING_WEAPON),
new /datum/data/mining_equipment("Super Resonator", /obj/item/resonator/upgraded, 2500, VENDING_WEAPON),
new /datum/data/mining_equipment("Kinetic Javelin", /obj/item/kinetic_javelin/blue, 1000, VENDING_WEAPON), //YOGS EDIT
new /datum/data/mining_equipment("Silver Pickaxe", /obj/item/pickaxe/silver, 1000, VENDING_WEAPON),
new /datum/data/mining_equipment("Diamond Pickaxe", /obj/item/pickaxe/diamond, 2000, VENDING_WEAPON),
new /datum/data/mining_equipment("Mini Plasma Cutter", /obj/item/gun/energy/plasmacutter/mini, 2500, VENDING_WEAPON),
- new /datum/data/mining_equipment("Plasma Cutter Shotgun", /obj/item/gun/energy/plasmacutter/scatter, 6000, VENDING_WEAPON),
- new /datum/data/mining_equipment("Plasma Shotgun Upgrade", /obj/item/upgrade/plasmacutter/defuser, 1000, VENDING_WEAPON),
+ new /datum/data/mining_equipment("Plasma Cutter Shotgun", /obj/item/gun/energy/plasmacutter/scatter, 5000, VENDING_WEAPON),
+ new /datum/data/mining_equipment("PC Defuser Upgrade", /obj/item/upgrade/plasmacutter/defuser, 1000, VENDING_UPGRADE),
+ new /datum/data/mining_equipment("PC Capacity Upgrade", /obj/item/upgrade/plasmacutter/capacity, 4500, VENDING_UPGRADE),
+ new /datum/data/mining_equipment("PC Cooldown Upgrade", /obj/item/upgrade/plasmacutter/cooldown, 5000, VENDING_UPGRADE),
+ new /datum/data/mining_equipment("PC Range Upgrade", /obj/item/upgrade/plasmacutter/range, 5000, VENDING_UPGRADE),
+ new /datum/data/mining_equipment("PC Ore Upgrade", /obj/item/upgrade/plasmacutter/ore, 10000, VENDING_UPGRADE),
new /datum/data/mining_equipment("KA Minebot Passthrough", /obj/item/borg/upgrade/modkit/minebot_passthrough, 100, VENDING_UPGRADE),
new /datum/data/mining_equipment("KA White Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer, 100, VENDING_UPGRADE),
new /datum/data/mining_equipment("KA Adjustable Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer/adjustable, 150, VENDING_UPGRADE),
@@ -303,9 +307,12 @@
new /datum/data/mining_equipment("Diamond Pickaxe", /obj/item/pickaxe/diamond, 1500, VENDING_WEAPON),
new /datum/data/mining_equipment("Mini Plasma Cutter", /obj/item/gun/energy/plasmacutter/mini, 500, VENDING_WEAPON),
new /datum/data/mining_equipment("Plasma Cutter" , /obj/item/gun/energy/plasmacutter, 2500, VENDING_WEAPON),
- new /datum/data/mining_equipment("Plasma Cutter Shotgun", /obj/item/gun/energy/plasmacutter/scatter, 6000, VENDING_WEAPON),
- new /datum/data/mining_equipment("PS Defuser Upgrade", /obj/item/upgrade/plasmacutter/defuser, 1000, VENDING_UPGRADE),
- new /datum/data/mining_equipment("PS Capacity Upgrade", /obj/item/upgrade/plasmacutter/capacity, 4500, VENDING_UPGRADE),
+ new /datum/data/mining_equipment("Plasma Cutter Shotgun", /obj/item/gun/energy/plasmacutter/scatter, 5000, VENDING_WEAPON),
+ new /datum/data/mining_equipment("PC Defuser Upgrade", /obj/item/upgrade/plasmacutter/defuser, 1000, VENDING_UPGRADE),
+ new /datum/data/mining_equipment("PC Capacity Upgrade", /obj/item/upgrade/plasmacutter/capacity, 4500, VENDING_UPGRADE),
+ new /datum/data/mining_equipment("PC Cooldown Upgrade", /obj/item/upgrade/plasmacutter/cooldown, 5000, VENDING_UPGRADE),
+ new /datum/data/mining_equipment("PC Range Upgrade", /obj/item/upgrade/plasmacutter/range, 5000, VENDING_UPGRADE),
+ new /datum/data/mining_equipment("PC Ore Upgrade", /obj/item/upgrade/plasmacutter/ore, 10000, VENDING_UPGRADE),
new /datum/data/mining_equipment("KA Minebot Passthrough", /obj/item/borg/upgrade/modkit/minebot_passthrough, 100, VENDING_UPGRADE),
new /datum/data/mining_equipment("KA White Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer, 100, VENDING_UPGRADE),
new /datum/data/mining_equipment("KA Adjustable Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer/adjustable, 150, VENDING_UPGRADE),
diff --git a/code/modules/mob/dead/new_player/latejoin_menu.dm b/code/modules/mob/dead/new_player/latejoin_menu.dm
index 80dd13b9359a..6a46a49dc1cc 100644
--- a/code/modules/mob/dead/new_player/latejoin_menu.dm
+++ b/code/modules/mob/dead/new_player/latejoin_menu.dm
@@ -43,15 +43,10 @@ GLOBAL_DATUM_INIT(latejoin_menu, /datum/latejoin_menu, new)
// FIXME: this can cause a runtime since user can be a living mob
if(istype(user))
user.jobs_menu_mounted = FALSE
- addtimer(CALLBACK(src, PROC_REF(scream_at_player), user), 5 SECONDS)
ui = new(user, src, "JobSelection", "Latejoin Menu")
ui.open()
-/datum/latejoin_menu/proc/scream_at_player(mob/dead/new_player/player)
- if(!player.jobs_menu_mounted)
- to_chat(player, span_notice("If the late join menu isn't showing, you can open the fallback menu using the verb in the Preferences tab!"))
-
/datum/latejoin_menu/ui_data(mob/user)
var/mob/dead/new_player/owner = user
var/list/departments = list()
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 54235f77176e..6fe67f54b776 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -596,7 +596,7 @@
set_invis_see(min(glasses.invis_view, see_invisible))
if(!isnull(glasses.lighting_cutoff))
lighting_cutoff = max(lighting_cutoff, glasses.lighting_cutoff)
- if(!isnull(glasses.color_cutoffs))
+ if(length(glasses.color_cutoffs))
lighting_color_cutoffs = blend_cutoff_colors(lighting_color_cutoffs, glasses.color_cutoffs)
diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm
index 21becca2178d..8e58ff3cf1a6 100644
--- a/code/modules/mob/living/carbon/inventory.dm
+++ b/code/modules/mob/living/carbon/inventory.dm
@@ -70,7 +70,7 @@
if(observe.client)
observe.client.screen -= I
I.forceMove(src)
- I.plane = ABOVE_HUD_PLANE
+ SET_PLANE_EXPLICIT(I, ABOVE_HUD_PLANE, src)
I.appearance_flags |= NO_CLIENT_COLOR
var/not_handled = FALSE
switch(slot)
diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
index b3ba2a8d27d0..de0c0ec01e7e 100644
--- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
@@ -28,6 +28,16 @@
var/squish_chance = 50
del_on_death = 1
+
+/mob/living/simple_animal/cockroach/Initialize(mapload)
+ . = ..()
+ AddComponent( \
+ /datum/component/squashable, \
+ squash_chance = 50, \
+ squash_damage = 1, \
+ squash_flags = SQUASHED_SHOULD_BE_GIBBED|SQUASHED_ALWAYS_IF_DEAD|SQUASHED_DONT_SQUASH_IN_CONTENTS, \
+ )
+
/mob/living/simple_animal/cockroach/death(gibbed)
if(SSticker.mode && SSticker.mode.station_was_nuked) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes.
return
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/drakeling.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/drakeling.dm
index 954cbf4cb10d..549cfc784d40 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/drakeling.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/drakeling.dm
@@ -113,7 +113,7 @@
/datum/action/cooldown/spell/pointed/drakeling
name = "ULTRA DRAGON ATTACK"
- desc = "if you can see this something has probably gone very wrong and you should make a bug report."
+ desc = "If you can see this something has probably gone very wrong and you should make a bug report."
background_icon_state = "bg_demon"
panel = "Dragon"
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
index 7ac2c9a5a278..681949c38483 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
@@ -36,9 +36,13 @@
icon_living = "rare_frog"
icon_dead = "rare_frog_dead"
butcher_results = list(/obj/item/reagent_containers/food/snacks/nugget = 5)
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
-/mob/living/simple_animal/hostile/retaliate/frog/Crossed(AM as mob|obj)
- . = ..()
+
+/mob/living/simple_animal/hostile/retaliate/frog/proc/on_entered(datum/source, atom/movable/AM, ...)
if(!stat && isliving(AM))
var/mob/living/L = AM
if(L.mob_size > MOB_SIZE_TINY)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 749f3a4387b1..d250293ede6c 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -161,7 +161,7 @@
hud_list[hud] = list()
else
- var/image/I = image('yogstation/icons/mob/hud.dmi', src, "")
+ var/image/I = image('modular_dripstation/icons/mob/hud.dmi', src, "") //dripstation edit
I.appearance_flags = RESET_COLOR|RESET_TRANSFORM
hud_list[hud] = I
set_hud_image_active(hud, update_huds = FALSE) //by default everything is active. but dont add it to huds to keep control.
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 6747f04952d6..c604ea038554 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -27,6 +27,7 @@ By design, d1 is the smallest direction and d2 is the highest
desc = "A flexible, superconducting insulated cable for heavy-duty power transfer."
icon = 'icons/obj/power_cond/cables.dmi'
icon_state = "0-1"
+ plane = FLOOR_PLANE
layer = WIRE_LAYER //Above hidden pipes, GAS_PIPE_HIDDEN_LAYER
anchored = TRUE
obj_flags = CAN_BE_HIT | ON_BLUEPRINTS
@@ -89,7 +90,11 @@ By design, d1 is the smallest direction and d2 is the highest
cable_color = param_color || cable_color || pick(cable_colors)
if(cable_colors[cable_color])
cable_color = cable_colors[cable_color]
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/structure/cable/LateInitialize()
update_appearance(UPDATE_ICON)
+ //is_fully_initialized = TRUE
/obj/structure/cable/Destroy() // called when a cable is deleted
if(powernet)
diff --git a/code/modules/power/reactor/reactor.dm b/code/modules/power/reactor/reactor.dm
index 3819a4d72a5e..7de1e268229f 100644
--- a/code/modules/power/reactor/reactor.dm
+++ b/code/modules/power/reactor/reactor.dm
@@ -175,12 +175,15 @@
to_chat(user, span_notice("The reactor has no fuel rods!"))
return TRUE
var/obj/item/fuel_rod/rod = tgui_input_list(usr, "Select a fuel rod to remove", "Fuel Rods", fuel_rods)
- if(rod && istype(rod) && I.use_tool(src, user, removal_time))
+ if(rod && istype(rod) && I.use_tool(src, user, removal_time, volume=50))
if(temperature > REACTOR_TEMPERATURE_MINIMUM)
var/turf/T = get_turf(src)
T.atmos_spawn_air("water_vapor=[pressure/100];TEMP=[temperature]")
user.rad_act(rod.fuel_power * 1000)
fuel_rods.Remove(rod)
+ if(ismecha(user.loc))
+ rod.forceMove(get_step(get_turf(user.loc), user.loc.dir))
+ return TRUE
if(!user.put_in_hands(rod))
rod.forceMove(user.loc)
return TRUE
diff --git a/code/modules/projectiles/ammunition/caseless/rocket.dm b/code/modules/projectiles/ammunition/caseless/rocket.dm
index e82508d2c67d..558471acd3a7 100644
--- a/code/modules/projectiles/ammunition/caseless/rocket.dm
+++ b/code/modules/projectiles/ammunition/caseless/rocket.dm
@@ -30,7 +30,7 @@
/obj/item/ammo_casing/caseless/bolts
name = "bolts"
- desc = "rods, cut in half and ready to be shot"
+ desc = "Rods, cut in half and ready to be shot."
caliber = null
icon = 'icons/obj/ammo.dmi'
icon_state = "bolt"
diff --git a/code/modules/projectiles/ammunition/energy/plasma.dm b/code/modules/projectiles/ammunition/energy/plasma.dm
index 922b950b9333..a74528a65381 100644
--- a/code/modules/projectiles/ammunition/energy/plasma.dm
+++ b/code/modules/projectiles/ammunition/energy/plasma.dm
@@ -5,6 +5,12 @@
delay = 15
e_cost = 25
+/obj/item/ammo_casing/energy/plasma/ready_proj(atom/target, mob/living/user, quiet, zone_override = "")
+ ..()
+ if(loc && istype(loc, /obj/item/gun/energy/plasmacutter))
+ var/obj/item/gun/energy/plasmacutter/PC = loc
+ PC.modify_projectile(BB)
+
/obj/item/ammo_casing/energy/plasma/weak
projectile_type = /obj/projectile/plasma/weak
select_name = "weak plasma burst"
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 03d6582fac10..467831b21e3f 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -1,3 +1,5 @@
+#define PLASMA_BASE_RECHARGE 500
+
/obj/item/gun/energy/ionrifle
name = "ion rifle"
desc = "Invented in 2506 to quell attacks from SELF aligned IPCs, the NT-I1 is a bulky rifle designed to disable mechanical and electronic threats at range."
@@ -129,26 +131,40 @@
var/progress_flash_divisor = 10 //copypasta is best pasta
var/light_intensity = 1
var/charge_weld = 25 //amount of charge used up to start action (multiplied by amount) and per progress_flash_divisor ticks of welding
- /// Contains the type paths for installed upgrades
- var/installed_upgrades = list()
-
-/obj/item/gun/energy/plasmacutter/mini
- name = "mini plasma cutter"
- desc = "A weak plasma based mining tool."
- icon_state = "plasmacutter_mini"
- item_state = "plasmacutter_mini"
- ammo_type = list(/obj/item/ammo_casing/energy/plasma/weak)
- toolspeed = 2
+ /// Contains the instances of installed upgrades
+ var/list/installed_upgrades = list()
+ /// Mod capacity of this item
+ var/mod_capacity = 80
+
+/obj/item/gun/energy/plasmacutter/proc/modify_projectile(obj/projectile/plasma/K)
+ K.gun = src //do something special on-hit, easy!
+ for(var/obj/item/upgrade/plasmacutter/A in installed_upgrades)
+ A.modify_projectile(K)
+
+/obj/item/gun/energy/plasmacutter/proc/get_remaining_mod_capacity()
+ . = mod_capacity
+ for(var/obj/item/upgrade/plasmacutter/a in installed_upgrades)
+ . -= a.cost
+ return .
/obj/item/gun/energy/plasmacutter/Initialize(mapload)
AddElement(/datum/element/update_icon_blocker)
. = ..()
AddComponent(/datum/component/butchering, 25, 105, 0, 'sound/weapons/plasma_cutter.ogg')
+/obj/item/gun/energy/plasmacutter/Destroy()
+ . = ..()
+ for(var/obj/item/upgrade/plasmacutter/a in installed_upgrades)
+ qdel(a)
+ QDEL_NULL(installed_upgrades)
+
/obj/item/gun/energy/plasmacutter/examine(mob/user)
. = ..()
if(cell)
. += span_notice("[src] is [round(cell.percent())]% charged.")
+ . += span_boldnotice("[get_remaining_mod_capacity()]% mod capacity remaining.")
+ for(var/obj/item/upgrade/plasmacutter/a in installed_upgrades)
+ . += span_notice("There is \a [a] installed, using [span_bold("[a.cost]%")] capacity.")
/obj/item/gun/energy/plasmacutter/attackby(obj/item/I, mob/user)
var/charge_multiplier = 0 //2 = Refined stack, 1 = Ore
@@ -156,16 +172,20 @@
charge_multiplier = 2
if(istype(I, /obj/item/stack/ore/plasma))
charge_multiplier = 1
- if(charge_multiplier)
- if(cell.charge == cell.maxcharge)
- to_chat(user, span_notice("You try to insert [I] into [src], but it's fully charged.")) //my cell is round and full
- return
- I.use(1)
- cell.give(500*charge_multiplier)
- to_chat(user, span_notice("You insert [I] in [src], recharging it."))
- else
- ..()
+ if(!charge_multiplier)
+ return ..()
+
+ var/obj/item/stack/S = I
+ var/charge_amount = PLASMA_BASE_RECHARGE * charge_multiplier // Get the amount of charge per item
+ // Get remaining capacity and get the ideal amount to recharge or all of the stack whichever is smaller
+ var/amount_to_eat = ceil(min(((cell.maxcharge - cell.charge) / charge_amount), S.get_amount()))
+ if(amount_to_eat == 0)
+ to_chat(user, span_notice("You try to insert [I] into [src], but it's fully charged.")) //my cell is round and full
+ return
+ I.use(amount_to_eat)
+ cell.give(charge_amount * amount_to_eat)
+ to_chat(user, span_notice("You insert [I] in [src], recharging it."))
// Tool procs, in case plasma cutter is used as welder
// Can we start welding?
/obj/item/gun/energy/plasmacutter/tool_start_check(mob/living/user, amount)
@@ -211,12 +231,54 @@
else
. = ..(amount=1)
+/obj/item/gun/energy/plasmacutter/attackby(obj/item/I, mob/user)
+ . = ..()
+ if(istype(I, /obj/item/upgrade/plasmacutter))
+ var/obj/item/upgrade/plasmacutter/PC = I
+ if(get_remaining_mod_capacity() < PC.cost)
+ to_chat(user, span_warning("There is no more room for this upgrade."))
+ return
+ if(!PC.stackable && is_type_in_list(PC, installed_upgrades))
+ to_chat(user, span_notice("[I] has already been installed in [src]"))
+ return
+ to_chat(user, span_notice("You install [I] into [src]"))
+ playsound(loc, 'sound/items/screwdriver.ogg', 100, 1)
+ installed_upgrades += I
+ PC.install(src)
+ I.forceMove(src)
+
+/obj/item/gun/energy/plasmacutter/crowbar_act(mob/living/user, obj/item/I)
+ . = TRUE
+ if(installed_upgrades.len)
+ to_chat(user, span_notice("You pry the modifications out."))
+ I.play_tool_sound(src, 100)
+ for(var/obj/item/upgrade/plasmacutter/M in installed_upgrades)
+ M.forceMove(drop_location()) // Uninstallation handled in Exited().
+ else
+ to_chat(user, span_notice("There are no modifications currently installed."))
+
+/obj/item/gun/energy/plasmacutter/Exited(atom/movable/gone, direction)
+ ..()
+ if(gone in installed_upgrades)
+ var/obj/item/upgrade/plasmacutter/MK = gone
+ MK.uninstall(src)
+
+/obj/item/gun/energy/plasmacutter/mini
+ name = "mini plasma cutter"
+ desc = "A weak plasma based mining tool."
+ icon_state = "plasmacutter_mini"
+ item_state = "plasmacutter_mini"
+ ammo_type = list(/obj/item/ammo_casing/energy/plasma/weak)
+ toolspeed = 2
+ mod_capacity = 50
+
/obj/item/gun/energy/plasmacutter/adv
name = "advanced plasma cutter"
icon_state = "adv_plasmacutter"
item_state = "adv_plasmacutter"
force = 15
ammo_type = list(/obj/item/ammo_casing/energy/plasma/adv)
+ mod_capacity = 100
/obj/item/gun/energy/plasmacutter/adv/mega
name = "mega plasma cutter"
@@ -224,6 +286,7 @@
item_state = "plasmacutter_mega"
desc = "A mining tool capable of expelling concentrated plasma bursts. You could use it to cut limbs off xenos! Or, you know, mine stuff. This one has been enhanced with plasma magmite."
ammo_type = list(/obj/item/ammo_casing/energy/plasma/adv/mega)
+ mod_capacity = 120
/obj/item/gun/energy/plasmacutter/scatter
name = "plasma cutter shotgun"
@@ -232,15 +295,7 @@
desc = "An industrial-grade, heavy-duty mining shotgun."
force = 10
ammo_type = list(/obj/item/ammo_casing/energy/plasma/scatter)
-
-
-
-/obj/item/gun/energy/plasmacutter/attackby(obj/item/I, mob/user)
- . = ..()
- if(try_upgrade(I, user))
- to_chat(user, span_notice("You install [I] into [src]"))
- playsound(loc, 'sound/items/screwdriver.ogg', 100, 1)
- qdel(I)
+ mod_capacity = 100
/obj/item/gun/energy/plasmacutter/scatter/mega
name = "mega plasma cutter shotgun"
@@ -248,6 +303,7 @@
item_state = "miningshotgun_mega"
desc = "An industrial-grade, heavy-duty mining shotgun. This one seems... mega!"
ammo_type = list(/obj/item/ammo_casing/energy/plasma/scatter/adv/mega)
+ mod_capacity = 120
/obj/item/gun/energy/plasmacutter/adv/cyborg
name = "cyborg advanced plasma cutter"
@@ -255,6 +311,7 @@
force = 15
selfcharge = 1
ammo_type = list(/obj/item/ammo_casing/energy/plasma/adv/cyborg)
+ mod_capacity = 70
/obj/item/gun/energy/plasmacutter/adv/malf // Can't be subtype of cyborg or it will interfere with upgrades
name = "cyborg malfunctioning plasma cutter"
@@ -263,47 +320,71 @@
force = 15
selfcharge = 1
ammo_type = list(/obj/item/ammo_casing/energy/plasma/adv/cyborg/malf)
+ mod_capacity = 100
// Upgrades for plasma cutters
/obj/item/upgrade/plasmacutter
name = "generic upgrade kit"
- desc = "An upgrade for plasma shotguns."
+ desc = "An upgrade for plasma cutters."
icon = 'icons/obj/objects.dmi'
icon_state = "modkit"
w_class = WEIGHT_CLASS_SMALL
+ var/cost = 10
+ var/stackable = FALSE
+
+/obj/item/upgrade/plasmacutter/proc/modify_projectile(obj/projectile/plasma/K)
+
+/obj/item/upgrade/plasmacutter/proc/install(obj/item/gun/energy/plasmacutter/P)
+
+/obj/item/upgrade/plasmacutter/proc/uninstall(obj/item/gun/energy/plasmacutter/P)
+
/obj/item/upgrade/plasmacutter/defuser
name = "plasma cutter defusal kit"
- desc = "An upgrade for plasma shotguns that allows it to automatically defuse gibtonite."
+ desc = "An upgrade for plasma cutters that allows it to automatically defuse gibtonite."
+
+/obj/item/upgrade/plasmacutter/defuser/modify_projectile(obj/projectile/plasma/K)
+ K.defuse = TRUE
/obj/item/upgrade/plasmacutter/capacity
name = "plasma cutter capacity kit"
- desc = "An upgrade for plasma shotguns that doubles the tank capacity."
+ desc = "An upgrade for plasma cutters that doubles the tank capacity."
+ cost = 20
-/obj/item/gun/energy/plasmacutter/proc/try_upgrade(obj/item/I, mob/user)
- if(I.type in installed_upgrades)
- to_chat(user, span_notice("[I] has already been installed in [src]"))
- return FALSE
- return FALSE
+/obj/item/upgrade/plasmacutter/capacity/install(obj/item/gun/energy/plasmacutter/P)
+ P.cell.maxcharge = initial(P.cell.maxcharge)*2
-/obj/item/gun/energy/plasmacutter/scatter/try_upgrade(obj/item/I, mob/user)
- . = ..()
- if(.)
- return TRUE
- if(istype(I, /obj/item/upgrade/plasmacutter/defuser))
- var/kaboom = new/obj/item/ammo_casing/energy/plasma/scatter/adv
- ammo_type = list(kaboom)
- installed_upgrades += I.type
- return TRUE
- if(istype(I, /obj/item/upgrade/plasmacutter/capacity))
- cell.maxcharge = initial(cell.maxcharge)*2
- installed_upgrades += I.type
- return TRUE
- return FALSE
+/obj/item/upgrade/plasmacutter/capacity/uninstall(obj/item/gun/energy/plasmacutter/P)
+ P.cell.maxcharge = initial(P.cell.maxcharge)
+ P.cell.charge = min(P.cell.charge, P.cell.maxcharge)
-//no upgrading this one either (for now)
-/obj/item/gun/energy/plasmacutter/scatter/mega/try_upgrade(obj/item/I, mob/user)
- return
+/obj/item/upgrade/plasmacutter/cooldown
+ name = "plasma cutter cooldown kit"
+ desc = "An upgrade for plasma cutters that reduces the cooldown."
+ cost = 40
+ stackable = TRUE
+
+/obj/item/upgrade/plasmacutter/cooldown/install(obj/item/gun/energy/plasmacutter/P)
+ P.fire_delay *= 0.5
+
+/obj/item/upgrade/plasmacutter/cooldown/uninstall(obj/item/gun/energy/plasmacutter/P)
+ P.fire_delay *= 2
+
+/obj/item/upgrade/plasmacutter/range
+ name = "plasma cutter range kit"
+ desc = "An upgrade for plasma cutters that increases the range."
+ cost = 30
+
+/obj/item/upgrade/plasmacutter/range/modify_projectile(obj/projectile/plasma/K)
+ K.range += 4
+
+/obj/item/upgrade/plasmacutter/ore
+ name = "plasma cutter ore kit"
+ desc = "An upgrade for plasma cutters that doubles ore output."
+ cost = 30
+
+/obj/item/upgrade/plasmacutter/ore/modify_projectile(obj/projectile/plasma/K)
+ K.explosive = TRUE
/obj/item/gun/energy/wormhole_projector
name = "bluespace wormhole projector"
@@ -512,3 +593,5 @@
icon_state = "prifle"
item_state = "prifle"
ammo_type = list(/obj/item/ammo_casing/energy/grimdark)
+
+#undef PLASMA_BASE_RECHARGE
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index cb890ec8514b..97428e8e26e9 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -244,8 +244,11 @@
splatter_dir = get_dir(starting, target_loca)
if(isalien(L) || ispolysmorph(L))
new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir)
- else if (iscarbon(L) && !(NOBLOOD in C.dna.species.species_traits))
- new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir)
+ else if(iscarbon(L) && !(NOBLOOD in C.dna.species.species_traits))
+ var/splatter_color
+ var/mob/living/carbon/carbon_bleeder = L
+ splatter_color = carbon_bleeder.dna.blood_type.color
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, splatter_color)
else
new /obj/effect/temp_visual/dir_setting/bloodsplatter/genericsplatter(target_loca, splatter_dir)
var/obj/item/bodypart/B = L.get_bodypart(def_zone)
diff --git a/code/modules/projectiles/projectile/special/plasma.dm b/code/modules/projectiles/projectile/special/plasma.dm
index ce7137a504ab..85f746a4e30b 100644
--- a/code/modules/projectiles/projectile/special/plasma.dm
+++ b/code/modules/projectiles/projectile/special/plasma.dm
@@ -16,6 +16,10 @@
light_color = LIGHT_COLOR_PURPLE
light_range = 2
+ var/obj/item/gun/energy/plasmacutter/gun
+ var/defuse = FALSE
+ var/explosive = FALSE
+
/obj/projectile/plasma/weak
name = "weak plasma blast"
icon_state = "plasmacutter_weak"
@@ -24,6 +28,7 @@
impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser
light_color = LIGHT_COLOR_RED
mine_range = 0
+
//yogs begin
/obj/projectile/plasma/Move(atom/newloc, dir)
. = ..()
@@ -34,9 +39,12 @@
//yogs end
/obj/projectile/plasma/on_hit(atom/target)
. = ..()
+ if(defuse && istype(target, /turf/closed/mineral/gibtonite))
+ var/turf/closed/mineral/gibtonite/gib = target
+ gib.defuse()
if(ismineralturf(target))
var/turf/closed/mineral/M = target
- M.attempt_drill(firer)
+ M.attempt_drill(firer, explosive)
if(mine_range)
mine_range--
range++
@@ -52,12 +60,6 @@
return BULLET_ACT_FORCE_PIERCE
// yogs end
-/obj/projectile/plasma/scatter/adv/on_hit(atom/target)
- if(istype(target, /turf/closed/mineral/gibtonite))
- var/turf/closed/mineral/gibtonite/gib = target
- gib.defuse()
- . = ..()
-
/obj/projectile/plasma/adv
damage = 7
range = 5
@@ -78,6 +80,7 @@
// Same as the scatter but with automatic defusing
/obj/projectile/plasma/scatter/adv
+ defuse = TRUE
// Megafauna loot, possibly best cutter?
/obj/projectile/plasma/scatter/adv/stalwart
diff --git a/code/modules/projectiles/projectile/special/reagent.dm b/code/modules/projectiles/projectile/special/reagent.dm
index 524180486c7b..e19024470544 100644
--- a/code/modules/projectiles/projectile/special/reagent.dm
+++ b/code/modules/projectiles/projectile/special/reagent.dm
@@ -47,6 +47,25 @@
last_volume = R.volume
name = "\proper [lowertext(R.name)]"
+// PRESSURE WASHER
+/obj/projectile/reagent/pressure_washer
+ name = "\proper high-pressure water"
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "extinguish"
+ range = 7
+ reagents_list = list(/datum/reagent/water = 10)
+ speed = 0.6 // very high power
+
+/obj/projectile/reagent/pressure_washer/on_hit(atom/movable/target, blocked)
+ . = ..()
+ if(istype(target) && !target.anchored && prob(20))
+ target.throw_at(get_step(target, dir), 1, 1, firer)
+
+/obj/projectile/reagent/pressure_washer/Move(atom/newloc, dir)
+ . = ..()
+ if(newloc)
+ newloc.wash(CLEAN_SCRUB) // wash everything in its path
+
/// Xeno neurotoxin
/obj/projectile/reagent/neurotoxin
name = "neurotoxin spit"
diff --git a/code/modules/projectiles/projectile/special/rocket.dm b/code/modules/projectiles/projectile/special/rocket.dm
index 3d220e4842a3..0a39cfd58b33 100644
--- a/code/modules/projectiles/projectile/special/rocket.dm
+++ b/code/modules/projectiles/projectile/special/rocket.dm
@@ -10,7 +10,7 @@
/obj/projectile/bullet/a84mm
name ="\improper HEDP rocket"
- desc = "USE A WEEL GUN"
+ desc = "USE A WEEL GUN."
icon_state= "84mm-hedp"
armor_flag = BOMB
damage = 80
@@ -73,7 +73,7 @@
/obj/projectile/bullet/cball
name = "cannonball"
icon_state = "cannonball"
- desc = "Not for bowling purposes"
+ desc = "Not for bowling purposes."
damage = 30
demolition_mod = 20 // YARRR
@@ -91,5 +91,5 @@
/obj/projectile/bullet/bolt
name = "bolt"
icon_state = "bolt"
- desc = "smaller and faster rod"
+ desc = "A smaller and faster rod."
damage = 25
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index ce0225b4e1ea..ec3bea63fddd 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -97,7 +97,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
color = "#221915" // rgb: 34, 25, 21
taste_description = "malt and chocolate"
glass_name = "glass of stout"
- glass_desc = "a cold pint of 'genius' brand stout."
+ glass_desc = "A cold pint of 'genius' brand stout."
/datum/reagent/consumable/ethanol/beer/stout/irishflip
name = "Irish Flip"
@@ -106,7 +106,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = "chocolate cream and egg"
glass_icon_state = "irish_flip"
glass_name = "glass of irish flip"
- glass_desc = "a fancy glass of creamy cocktail."
+ glass_desc = "A fancy glass of creamy cocktail."
/datum/reagent/consumable/ethanol/beer/stout/blackvelvet
name = "Black Velvet"
@@ -115,7 +115,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = "Champagne with a hint of chocolate."
glass_icon_state = "black_velvet"
glass_name = "glass of black velvet"
- glass_desc = "a fancy drink with a melancholic past."
+ glass_desc = "A fancy drink with a melancholic past."
/datum/reagent/consumable/ethanol/beer/stout/espressomartini
name = "Espresso Martini"
@@ -124,7 +124,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = "bitterness, chocolate, and cream."
glass_icon_state = "espresso_martini"
glass_name = "glass of espresso martini"
- glass_desc = "a cocktail guaranteed to keep you awake."
+ glass_desc = "A cocktail guaranteed to keep you awake."
///////////////////////////////////////////
/datum/reagent/consumable/ethanol/beer/light
name = "Light Beer"
@@ -2281,7 +2281,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = "dried plums and malt"
glass_icon_state = "trappistglass"
glass_name = "Trappist Beer"
- glass_desc = "boozy Catholicism in a glass."
+ glass_desc = "Boozy Catholicism in a glass."
/datum/reagent/consumable/ethanol/trappist/on_mob_life(mob/living/carbon/M)
if(M.mind.holy_role)
@@ -2440,7 +2440,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = "tequila, creme de menthe, and a hint of medicine?"
glass_icon_state = "flaming_moe2"
glass_name = "Flaming Moe"
- glass_desc = "an amazing concoction of various different bar drinks and a secret ingredient"
+ glass_desc = "An amazing concoction of various different bar drinks and a secret ingredient"
/datum/reagent/consumable/ethanol/flaming_moe/on_mob_life(mob/living/carbon/M)
M.adjust_drowsiness(-5 SECONDS)
diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm
index 9b5a012ee9cd..14f89cc5dde3 100644
--- a/code/modules/research/designs/mecha_designs.dm
+++ b/code/modules/research/designs/mecha_designs.dm
@@ -411,6 +411,66 @@
construction_time = 1200
category = list("Exosuit Equipment")
+/datum/design/mech_thrusters
+ name = "Exosuit Module (RCS Thruster Package)"
+ desc = "A thruster package for exosuits. Expels gas from the internal life-support air tank to generate thrust."
+ id = "mech_thrusters"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/mecha_equipment/thrusters/gas
+ materials = list(/datum/material/iron=25000,/datum/material/titanium=5000,/datum/material/silver=3000)
+ construction_time = 100
+ category = list("Exosuit Equipment")
+
+/datum/design/mech_pipe_dispenser
+ name = "Exosuit Module (Pipe Dispenser Module)"
+ desc = "An exosuit-mounted Rapid Pipe Dispenser."
+ id = "mech_pipe_dispenser"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/mecha_equipment/pipe_dispenser
+ materials = list(/datum/material/iron=10000,/datum/material/glass=2000)
+ construction_time = 100
+ category = list("Exosuit Equipment")
+
+/datum/design/mech_t_scanner
+ name = "Exosuit Module (T-ray Scanner Module)"
+ desc = "An exosuit-mounted Terahertz-Ray Scanner."
+ id = "mech_t_scanner"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/mecha_equipment/t_scanner
+ materials = list(/datum/material/iron=2000)
+ construction_time = 50
+ category = list("Exosuit Equipment")
+
+/datum/design/mech_washer
+ name = "Exosuit Module (Pressure Washer)"
+ desc = "An exosuit-mounted pressure washer."
+ id = "mech_washer"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/mecha_equipment/weapon/pressure_washer
+ materials = list(/datum/material/iron=2000)
+ construction_time = 50
+ category = list("Exosuit Equipment")
+
+/datum/design/mech_mop
+ name = "Exosuit Module (Mop)"
+ desc = "An exosuit-mounted mop."
+ id = "mech_mop"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/mecha_equipment/melee_weapon/mop
+ materials = list(/datum/material/iron=2000)
+ construction_time = 50
+ category = list("Exosuit Equipment")
+
+/datum/design/mech_flyswatter
+ name = "Exosuit Module (Flyswatter)"
+ desc = "An exosuit-mounted flyswatter."
+ id = "mech_flyswatter"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/mecha_equipment/melee_weapon/flyswatter
+ materials = list(/datum/material/iron=2000)
+ construction_time = 50
+ category = list("Exosuit Equipment")
+
/datum/design/mech_gravcatapult
name = "Exosuit Module (Gravitational Catapult Module)"
desc = "An exosuit mounted Gravitational Catapult."
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index eb8ec7b9a1af..ff01af524c1f 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -11,7 +11,7 @@
construction_time = 75
build_path = /obj/item/mmi
category = list("Control Interfaces", "Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/posibrain
name = "Positronic Brain"
@@ -22,7 +22,7 @@
construction_time = 75
build_path = /obj/item/mmi/posibrain
category = list("Control Interfaces", "Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/bluespacebeaker
name = "Bluespace Beaker"
@@ -708,7 +708,7 @@
/////////////////////
/datum/design/surgery
name = "Surgery Design"
- desc = "what"
+ desc = "What."
id = "surgery_parent"
research_icon = 'icons/misc/surgery_icons.dmi'
research_icon_state = "surgery_any"
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index a0cc937c928b..2cb62f1d9d7b 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -39,7 +39,7 @@
starting_node = TRUE
display_name = "Basic Exosuit Equipment"
description = "Various tools fit for basic mech units"
- design_ids = list("mech_drill", "mech_mscanner", "mech_extinguisher", "mech_cable_layer")
+ design_ids = list("mech_drill", "mech_mscanner", "mech_extinguisher", "mech_cable_layer", "mech_t_scanner", "mech_pipe_dispenser")
/datum/techweb_node/clarke
id = "mecha_clarke"
@@ -620,7 +620,7 @@
display_name = "Advanced Sanitation Technology"
description = "Clean things better, faster, stronger, and harder!"
prereq_ids = list("adv_engi")
- design_ids = list("advmop", "buffer", "blutrash", "light_replacer", "spraybottle", "beartrap")
+ design_ids = list("advmop", "buffer", "blutrash", "light_replacer", "spraybottle", "beartrap", "mech_washer", "mech_mop", "mech_flyswatter")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/botany
@@ -857,7 +857,7 @@
display_name = "Advanced Exosuit Equipment"
description = "Tools for high level mech suits"
prereq_ids = list("adv_mecha")
- design_ids = list("mech_rcd")
+ design_ids = list("mech_rcd", "mech_thrusters")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/med_mech_tools
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index 5f5bb52270e7..5a510273911f 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -50,10 +50,10 @@ All ShuttleMove procs go here
//Destination turf changes
//Baseturfs is definitely a list or this proc wouldnt be called
var/shuttle_depth = depth_to_find_baseturf(/turf/baseturf_skipover/shuttle)
-
+
if(!shuttle_depth)
CRASH("A turf queued to move via shuttle somehow had no skipover in baseturfs. [src]([type]):[loc]")
- newT.CopyOnTop(src, 1, shuttle_depth, TRUE, CHANGETURF_DEFER_CHANGE)
+ newT.CopyOnTop(src, 1, shuttle_depth, TRUE)
SEND_SIGNAL(src, COMSIG_TURF_ON_SHUTTLE_MOVE, newT)
return TRUE
@@ -67,7 +67,7 @@ All ShuttleMove procs go here
var/shuttle_depth = depth_to_find_baseturf(/turf/baseturf_skipover/shuttle)
if(shuttle_depth)
- oldT.ScrapeAway(shuttle_depth)
+ oldT.ScrapeAway(shuttle_depth, CHANGETURF_DEFER_CHANGE)
if(rotation)
shuttleRotate(rotation) //see shuttle_rotate.dm
diff --git a/code/modules/shuttle/ripple.dm b/code/modules/shuttle/ripple.dm
index 912d95488862..19269c6a83ba 100644
--- a/code/modules/shuttle/ripple.dm
+++ b/code/modules/shuttle/ripple.dm
@@ -1,6 +1,6 @@
/obj/effect/abstract/ripple
- name = "hyperspace ripple"
- desc = "Something is coming through hyperspace, you can see the \
+ name = "bluespace ripple"
+ desc = "Something is coming through bluespace, you can see the \
visual disturbances. It's probably best not to be on top of these \
when whatever is tunneling comes through."
icon = 'icons/effects/effects.dmi'
diff --git a/code/modules/spells/spell_types/self/spacetime_distortion.dm b/code/modules/spells/spell_types/self/spacetime_distortion.dm
index b41560aa1629..62e4edcc3d73 100644
--- a/code/modules/spells/spell_types/self/spacetime_distortion.dm
+++ b/code/modules/spells/spell_types/self/spacetime_distortion.dm
@@ -98,7 +98,7 @@
/obj/effect/cross_action
name = "cross me"
- desc = "for crossing"
+ desc = "For crossing."
anchored = TRUE
/obj/effect/cross_action/spacetime_dist
diff --git a/code/modules/surgery/organs/augments_eyes.dm b/code/modules/surgery/organs/augments_eyes.dm
index 067261c67490..67d77435c416 100644
--- a/code/modules/surgery/organs/augments_eyes.dm
+++ b/code/modules/surgery/organs/augments_eyes.dm
@@ -1,6 +1,6 @@
/obj/item/organ/cyberimp/eyes/hud
name = "cybernetic hud"
- desc = "artificial photoreceptors with specialized functionality"
+ desc = "A couple of artificial photoreceptors with specialized functionality."
icon_state = "eye_implant"
implant_overlay = "eye_implant_overlay"
slot = ORGAN_SLOT_EYES
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index 7be34b681780..6bd6c3d7eb46 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -172,6 +172,12 @@
medium_light_cutoff = list(0, 20, 35)
high_light_cutoff = list(0, 40, 50)
+/obj/item/organ/eyes/zombie
+ name = "undead eyes"
+ desc = "Somewhat counterintuitively, these half-rotten eyes actually have superior vision to those of a living human."
+ color_cutoffs = list(25, 35, 5)
+ lighting_cutoff = LIGHTING_CUTOFF_HIGH
+
//innate nightvision eyes
/obj/item/organ/eyes/alien
name = "alien eyes"
@@ -180,12 +186,6 @@
color_cutoffs = list(25, 5, 42)
lighting_cutoff = LIGHTING_CUTOFF_HIGH
-/obj/item/organ/eyes/zombie
- name = "undead eyes"
- desc = "Somewhat counterintuitively, these half-rotten eyes actually have superior vision to those of a living human."
- color_cutoffs = list(25, 35, 5)
- lighting_cutoff = LIGHTING_CUTOFF_HIGH
-
/obj/item/organ/eyes/shadow
name = "burning red eyes"
desc = "Even without their shadowy owner, looking at these eyes gives you a sense of dread."
@@ -243,7 +243,7 @@
sight_flags = SEE_MOBS
// We're gonna downshift green and blue a bit so darkness looks yellow
color_cutoffs = list(25, 8, 5)
- flash_protect = -1
+ flash_protect = FLASH_PROTECTION_SENSITIVE
/obj/item/organ/eyes/robotic/flashlight
name = "flashlight eyes"
@@ -279,7 +279,7 @@
/obj/item/organ/eyes/robotic/shield
name = "shielded robotic eyes"
desc = "These reactive micro-shields will protect you from welders and flashes without obscuring your vision."
- flash_protect = 2
+ flash_protect = FLASH_PROTECTION_WELDER
/obj/item/organ/eyes/robotic/shield/emp_act(severity)
return
diff --git a/code/modules/tgui/states/pilot.dm b/code/modules/tgui/states/pilot.dm
new file mode 100644
index 000000000000..c5b63b5ad1d8
--- /dev/null
+++ b/code/modules/tgui/states/pilot.dm
@@ -0,0 +1,9 @@
+GLOBAL_DATUM_INIT(pilot_state, /datum/ui_state/pilot_state, new)
+
+/datum/ui_state/pilot_state/can_use_topic(src_object, mob/user)
+ if(!ismecha(src_object))
+ return UI_CLOSE
+ var/obj/mecha/gundam = src_object
+ if(user == gundam.occupant)
+ return UI_INTERACTIVE
+ return UI_CLOSE
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 96460e519239..7699c09a3e46 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -339,6 +339,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
manufacturer = /datum/corporation/traitor/cybersun
surplus = 0
+/datum/uplink_item/dangerous/gasharpoon
+ name = "Gasharpoon"
+ desc = "A repurposed space-whaling tool attatched to a glove, can be used as a sturdy weapon in both hands, or worn as a glove to allow access to it's harpoon."
+ item = /obj/item/clothing/gloves/gasharpoon
+ cost = 10
+ surplus = 0
+
/datum/uplink_item/dangerous/rawketlawnchair
name = "84mm Rocket Propelled Grenade Launcher"
desc = "A reusable rocket propelled grenade launcher preloaded with a low-yield 84mm HE round. \
diff --git a/config/config.txt b/config/config.txt
index e077fe2da1f1..e3e17849b3e1 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -422,6 +422,16 @@ DEFAULT_VIEW 19x15
## You probably shouldn't ever be changing this, but it's here if you want to.
DEFAULT_VIEW_SQUARE 15x15
+
+## Enable automatic profiling - Byond 513.1506 and newer only.
+#AUTO_PROFILE
+
+## Threshold (in deciseconds) for real time between ticks before we start dumping profiles
+DRIFT_DUMP_THRESHOLD 40
+
+## How long to wait (in deciseconds) after a profile dump before logging another tickdrift sourced one
+DRIFT_PROFILE_DELAY 150
+
## Comment this out if you want to use the SQL based mentor system, the legacy system uses mentors.txt.
## You need to set up your database to use the SQL based system.
## This flag is automatically enabled if SQL_ENABLED isn't
diff --git a/config/private_default.txt b/config/private_default.txt
index 88850ee7cada..832186c7c650 100644
--- a/config/private_default.txt
+++ b/config/private_default.txt
@@ -86,9 +86,8 @@ VOICE_ANNOUNCE_DIR ../Yogstation.net/voice_announce_tmp
## Enable the demo subsystem
#DEMOS_ENABLED
-## Starlight for exterior walls and breaches. Uncomment for starlight!
-## This is disabled by default to make testing quicker, should be enabled on production servers or testing servers messing with lighting
-#STARLIGHT
+## Enable automatic profiling - Byond 513.1506 and newer only.
+#AUTO_PROFILE
## Assets can opt-in to caching their results into `tmp`.
diff --git a/config/private_server.txt b/config/private_server.txt
index 8b2019e124ee..f8d2ee73d29d 100644
--- a/config/private_server.txt
+++ b/config/private_server.txt
@@ -97,6 +97,9 @@ VOICE_ANNOUNCE_DIR data/voice_announcements
## Enable the demo subsystem
DEMOS_ENABLED
+## Enable automatic profiling - Byond 513.1506 and newer only.
+AUTO_PROFILE
+
## Starlight for exterior walls and breaches. Uncomment for starlight!
## This is disabled by default to make testing quicker, should be enabled on production servers or testing servers messing with lighting
STARLIGHT
diff --git a/html/changelog.html b/html/changelog.html
index 4a251bd03991..edfa835aec8e 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -57,6 +57,102 @@
-->
+
23 February 2024
+
Cowbot92 & Chubbygummibear updated:
+
+ - Fixes a bunch of stuff you step on
+ - Added new traitor item, the gasharpoon
+
+
Chubbygummibear updated:
+
+ - auto_profile config flag added to the private default and private server config files
+ - private servers aren't dumpy unless you specifically request them to be
+ - main yog server will be extra dumpy because we can handle it
+ - no more double clerk and chaplain workplace spawns
+
+
Moltijoe updated:
+
+ - New ethereal bodyparts
+ - Old ethereal bodyparts
+
+
+
21 February 2024
+
Identification updated:
+
+ - Restores walls to true top-down.
+
+
sapphicoverload, syncit21, zxaber updated:
+
+ - added a bunch more equipment for utility mechs
+ - adds new sound effects for hydraulic clamp and APLU mech movement
+ - hydraulic clamp works as a wrench or crowbar and can pry powered doors
+ - mech plasma cutter can be used as a welder like the handheld version
+ - mech RCD works like an actual RCD now
+ - adds tgui RCD menu
+ - strafe button icon shows whether or not you're strafing
+ - APLU and Clarke mechs now have radiation shielding
+ - fixed clarke movement not working correctly
+ - fixes and re-adds multi-Z mech movement (no phasing through floors or teleporting to other z-levels this time)
+
+
13spacemen updated:
+
+ - The latejoin menu no longer has anemia.
+
+
AMyriad updated:
+
+ - Fixed the eye of god expose cooldown going off when an invalid target is selected
+ - Fixed mention of Weyland-Yutani appearing in the ripley mech repair manual
+ - "Hyperspace" no longer exists and never did, FTL travel is achieved by tunneling through bluespace
+ - Players can no longer relabel gas canisters to a variant that's intended for admins and breaks the 4th wall
+
+
Chubbygummibear updated:
+
+ - index_out_of_bounds fixed on blend_cutoff_colors
+ - turfs that smooth will spur their neighboring turfs to check their smoothing again when late loaded in
+ - cables on the correct plane so they don't have weird lattice lighting filters
+ - meteors with space lighting overlays rotate with the meteors instead of being disjointed and unmoving
+ - shuttle atmos shouldn't get left behind on takeoff
+
+
LazennG updated:
+
+ - fixed seismic suplex animation and some text
+
+
adamsong updated:
+
+ - fixed shuttle catastrophe
+ - fixed admin shuttle manipulator
+
+
cowbot92 updated:
+
+ - adjust some pop requirements for several antags
+
+
redmoogle updated:
+
+ - PC Range Upgrade
+ - PC Cooldown Upgrade
+ - Vending machines not containing upgrades
+ - All plasma cutters can be upgraded
+ - Plasmacutters can be recharged with one click now
+
+
warface1234455 updated:
+
+ - Partially revert undocumented change to shutter/blastdoor layer covering window but still keep the blast door covering the door
+
+
+
20 February 2024
+
Chubbygummibear updated:
+
+ - fix adminwho by skipping null clients in the admin list
+
+
cowbot92 updated:
+
+ - fixed beartraps not trapping
+
+
warface1234455 updated:
+
+ - cable coil maxstacks is now 40
+
+
19 February 2024
SapphicOverload updated:
@@ -1284,61 +1380,6 @@ cowbot92 updated:
- Adds auxmos to the minor filter
-
- 23 November 2023
- SapphicOverload updated:
-
- - power-fist works like a glove now
-
- SomeguyManperson updated:
-
- - gangrel gorilla transformation is now 15 armor down from 40
-
- Yarinoi updated:
-
- - Medical can print chemical analyzer implants again.
-
- warface1234455 updated:
-
- - Remove the portable pump cargo pack
-
- ynot01 updated:
-
- - The door between the armory and the auxiliary armory are now default security access
-
-
- 22 November 2023
- PositiveEntropy, Cark, Blutsu updated:
-
- - new wood sprites from TG, and resprites on stairs by Blutsu
- - replaces old wood tile sprites
-
- cark updated:
-
- - bridge on donut now has an APC and blast doors, apc in chapel is moved and some other minor fixes
-
- 00ze-cyclone updated:
-
- - Removed helmet, bulletproof helmet and riot helmet crates
- - armor, bulletproof armor and riot armor crates now contain helmets as well, price adjusted to cost the same as before
-
- JohnFulpWillard updated:
-
- - Pancake overlays now work
-
- SapphicOverload updated:
-
- - fixed people with the bald trait not being bald when cloned
-
- Therandomhoboo updated:
-
- - Glycerol making results in 3 units instead of 1
- - Reinforced Window Damage deflection is now 11 instead of 10
-
- wonderinghost updated:
-
- - Adds new programs and hardware to pdas
-
GoonStation 13 Development Team
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 52a6b2804d08..73ff413e40ed 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -43177,3 +43177,74 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
SapphicOverload:
- bugfix: RCDs work on space tiles again
- bugfix: Fixed space lighting not working in space
+2024-02-20:
+ Chubbygummibear:
+ - bugfix: fix adminwho by skipping null clients in the admin list
+ cowbot92:
+ - bugfix: fixed beartraps not trapping
+ warface1234455:
+ - bugfix: cable coil maxstacks is now 40
+2024-02-21:
+ ' Identification':
+ - imageadd: Restores walls to true top-down.
+ ' sapphicoverload, syncit21, zxaber':
+ - rscadd: added a bunch more equipment for utility mechs
+ - soundadd: adds new sound effects for hydraulic clamp and APLU mech movement
+ - tweak: hydraulic clamp works as a wrench or crowbar and can pry powered doors
+ - tweak: mech plasma cutter can be used as a welder like the handheld version
+ - tweak: mech RCD works like an actual RCD now
+ - tweak: adds tgui RCD menu
+ - tweak: strafe button icon shows whether or not you're strafing
+ - tweak: APLU and Clarke mechs now have radiation shielding
+ - bugfix: fixed clarke movement not working correctly
+ - bugfix: fixes and re-adds multi-Z mech movement (no phasing through floors or
+ teleporting to other z-levels this time)
+ 13spacemen:
+ - tweak: The latejoin menu no longer has anemia.
+ AMyriad:
+ - bugfix: Fixed the eye of god expose cooldown going off when an invalid target
+ is selected
+ - spellcheck: Fixed mention of Weyland-Yutani appearing in the ripley mech repair
+ manual
+ - tweak: '"Hyperspace" no longer exists and never did, FTL travel is achieved by
+ tunneling through bluespace'
+ - bugfix: Players can no longer relabel gas canisters to a variant that's intended
+ for admins and breaks the 4th wall
+ Chubbygummibear:
+ - bugfix: index_out_of_bounds fixed on blend_cutoff_colors
+ - bugfix: turfs that smooth will spur their neighboring turfs to check their smoothing
+ again when late loaded in
+ - bugfix: cables on the correct plane so they don't have weird lattice lighting
+ filters
+ - bugfix: meteors with space lighting overlays rotate with the meteors instead of
+ being disjointed and unmoving
+ - bugfix: shuttle atmos shouldn't get left behind on takeoff
+ LazennG:
+ - bugfix: fixed seismic suplex animation and some text
+ adamsong:
+ - bugfix: fixed shuttle catastrophe
+ - bugfix: fixed admin shuttle manipulator
+ cowbot92:
+ - tweak: adjust some pop requirements for several antags
+ redmoogle:
+ - rscadd: PC Range Upgrade
+ - rscadd: PC Cooldown Upgrade
+ - bugfix: Vending machines not containing upgrades
+ - tweak: All plasma cutters can be upgraded
+ - tweak: Plasmacutters can be recharged with one click now
+ warface1234455:
+ - tweak: Partially revert undocumented change to shutter/blastdoor layer covering
+ window but still keep the blast door covering the door
+2024-02-23:
+ ' Cowbot92 & Chubbygummibear':
+ - bugfix: Fixes a bunch of stuff you step on
+ - rscadd: Added new traitor item, the gasharpoon
+ Chubbygummibear:
+ - rscadd: auto_profile config flag added to the private default and private server
+ config files
+ - tweak: private servers aren't dumpy unless you specifically request them to be
+ - tweak: main yog server will be extra dumpy because we can handle it
+ - bugfix: no more double clerk and chaplain workplace spawns
+ Moltijoe:
+ - imageadd: New ethereal bodyparts
+ - imagedel: Old ethereal bodyparts
diff --git a/html/changelogs/AutoChangelog-pr-21390.yml b/html/changelogs/AutoChangelog-pr-21390.yml
new file mode 100644
index 000000000000..33de417ea20c
--- /dev/null
+++ b/html/changelogs/AutoChangelog-pr-21390.yml
@@ -0,0 +1,4 @@
+author: " ktlwjec"
+delete-after: true
+changes:
+ - imageadd: "Lightens the outline for the bag of holding in-hand sprites."
diff --git a/html/changelogs/AutoChangelog-pr-21415.yml b/html/changelogs/AutoChangelog-pr-21415.yml
new file mode 100644
index 000000000000..56fdcabb14b4
--- /dev/null
+++ b/html/changelogs/AutoChangelog-pr-21415.yml
@@ -0,0 +1,4 @@
+author: "AMyriad"
+delete-after: true
+changes:
+ - spellcheck: "Fixed every description that didn't begin with a capital letter, make a bug report if you find something I missed"
diff --git a/html/changelogs/AutoChangelog-pr-21430.yml b/html/changelogs/AutoChangelog-pr-21430.yml
new file mode 100644
index 000000000000..c97868fc83b2
--- /dev/null
+++ b/html/changelogs/AutoChangelog-pr-21430.yml
@@ -0,0 +1,4 @@
+author: "Mqiib"
+delete-after: true
+changes:
+ - tweak: "Mech melee weapons now also hit vines properly when using cleave attacks"
diff --git a/html/changelogs/AutoChangelog-pr-21437.yml b/html/changelogs/AutoChangelog-pr-21437.yml
new file mode 100644
index 000000000000..b0e6631e8de6
--- /dev/null
+++ b/html/changelogs/AutoChangelog-pr-21437.yml
@@ -0,0 +1,7 @@
+author: "SapphicOverload"
+delete-after: true
+changes:
+ - tweak: "flamethrowers now react their fuel for damage and effects instead of using pre-determined values"
+ - tweak: "flamethrower tanks release some of their contents when shot instead of just deleting themselves"
+ - tweak: "flamethrowers can hit vines on windows"
+ - bugfix: "fixed flamethrowers sometimes using more fuel than intended"
diff --git a/html/changelogs/AutoChangelog-pr-21474.yml b/html/changelogs/AutoChangelog-pr-21474.yml
new file mode 100644
index 000000000000..210b6c682b74
--- /dev/null
+++ b/html/changelogs/AutoChangelog-pr-21474.yml
@@ -0,0 +1,4 @@
+author: "AMyriad"
+delete-after: true
+changes:
+ - tweak: "MMIs and positronic brains can no longer be printed from the medical techfab"
diff --git a/html/changelogs/AutoChangelog-pr-21483.yml b/html/changelogs/AutoChangelog-pr-21483.yml
new file mode 100644
index 000000000000..f02b7a33d652
--- /dev/null
+++ b/html/changelogs/AutoChangelog-pr-21483.yml
@@ -0,0 +1,4 @@
+author: "cowbot92"
+delete-after: true
+changes:
+ - rscadd: " Ports baton light up from TG"
diff --git a/html/changelogs/AutoChangelog-pr-21493.yml b/html/changelogs/AutoChangelog-pr-21493.yml
new file mode 100644
index 000000000000..b7eb51bc0cdf
--- /dev/null
+++ b/html/changelogs/AutoChangelog-pr-21493.yml
@@ -0,0 +1,4 @@
+author: "warface1234455"
+delete-after: true
+changes:
+ - tweak: "HFR gas byproducts now uses scaled_production instead of fuel_consumption, and now scaled alongside with gas produced from moderator, code refactor"
diff --git a/html/changelogs/AutoChangelog-pr-21496.yml b/html/changelogs/AutoChangelog-pr-21496.yml
new file mode 100644
index 000000000000..1d9544e59ed1
--- /dev/null
+++ b/html/changelogs/AutoChangelog-pr-21496.yml
@@ -0,0 +1,4 @@
+author: "Mqiib"
+delete-after: true
+changes:
+ - tweak: "The clarke is now tied for fastest mech in the game with the ripley mk-I"
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi
index fbe6182716b7..9f06f421b549 100644
Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ
diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi
index 432ef8861cfb..483ab0444233 100644
Binary files a/icons/effects/blood.dmi and b/icons/effects/blood.dmi differ
diff --git a/icons/effects/footprints.dmi b/icons/effects/footprints.dmi
index a98344abe41e..dc8ddb4e7341 100644
Binary files a/icons/effects/footprints.dmi and b/icons/effects/footprints.dmi differ
diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi
index e64729a33764..abfa721d57d9 100644
Binary files a/icons/mecha/mecha_equipment.dmi and b/icons/mecha/mecha_equipment.dmi differ
diff --git a/icons/mob/actions/actions_arm.dmi b/icons/mob/actions/actions_arm.dmi
index 71bb415e8ad9..2154e742819e 100644
Binary files a/icons/mob/actions/actions_arm.dmi and b/icons/mob/actions/actions_arm.dmi differ
diff --git a/icons/mob/actions/actions_mecha.dmi b/icons/mob/actions/actions_mecha.dmi
index 81c706b22c8a..78a2ba5ec89a 100644
Binary files a/icons/mob/actions/actions_mecha.dmi and b/icons/mob/actions/actions_mecha.dmi differ
diff --git a/icons/mob/clothing/hands/hands.dmi b/icons/mob/clothing/hands/hands.dmi
index 57bef8c67fff..e07cfff4b117 100644
Binary files a/icons/mob/clothing/hands/hands.dmi and b/icons/mob/clothing/hands/hands.dmi differ
diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi
index 004bf8ad9902..a7e311e3a225 100644
Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ
diff --git a/icons/mob/inhands/equipment/backpack_lefthand.dmi b/icons/mob/inhands/equipment/backpack_lefthand.dmi
index 15425dabca14..0183ae173468 100644
Binary files a/icons/mob/inhands/equipment/backpack_lefthand.dmi and b/icons/mob/inhands/equipment/backpack_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/backpack_righthand.dmi b/icons/mob/inhands/equipment/backpack_righthand.dmi
index c51285f0867f..94b50fbb8d63 100644
Binary files a/icons/mob/inhands/equipment/backpack_righthand.dmi and b/icons/mob/inhands/equipment/backpack_righthand.dmi differ
diff --git a/icons/mob/inhands/weapons/melee_lefthand.dmi b/icons/mob/inhands/weapons/melee_lefthand.dmi
index 63624745e62c..dd0e7cfc86b0 100644
Binary files a/icons/mob/inhands/weapons/melee_lefthand.dmi and b/icons/mob/inhands/weapons/melee_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/melee_righthand.dmi b/icons/mob/inhands/weapons/melee_righthand.dmi
index d50eb8ccea9d..6b66977d77a0 100644
Binary files a/icons/mob/inhands/weapons/melee_righthand.dmi and b/icons/mob/inhands/weapons/melee_righthand.dmi differ
diff --git a/icons/mob/radial.dmi b/icons/mob/radial.dmi
index 533e11521d65..9006b42b0700 100644
Binary files a/icons/mob/radial.dmi and b/icons/mob/radial.dmi differ
diff --git a/icons/obj/guns/magic.dmi b/icons/obj/guns/magic.dmi
index 94bb606cbfc5..7ae2646ec3b8 100644
Binary files a/icons/obj/guns/magic.dmi and b/icons/obj/guns/magic.dmi differ
diff --git a/icons/obj/lavaland/artefacts.dmi b/icons/obj/lavaland/artefacts.dmi
index 494c964d48f2..00d590b2ac43 100644
Binary files a/icons/obj/lavaland/artefacts.dmi and b/icons/obj/lavaland/artefacts.dmi differ
diff --git a/icons/obj/traitor.dmi b/icons/obj/traitor.dmi
index 92851f3708cd..4d7a4931bcaf 100644
Binary files a/icons/obj/traitor.dmi and b/icons/obj/traitor.dmi differ
diff --git a/icons/turf/walls/false_walls.dmi b/icons/turf/walls/false_walls.dmi
index 1b02b4bdbe6d..a64fbe06fa5b 100644
Binary files a/icons/turf/walls/false_walls.dmi and b/icons/turf/walls/false_walls.dmi differ
diff --git a/icons/turf/walls/material_wall.dmi b/icons/turf/walls/material_wall.dmi
index 2bd844c0b135..d4c48e66f6ea 100644
Binary files a/icons/turf/walls/material_wall.dmi and b/icons/turf/walls/material_wall.dmi differ
diff --git a/icons/turf/walls/material_wall.png b/icons/turf/walls/material_wall.png
index 1f636cb6db09..0c2533dec6f9 100644
Binary files a/icons/turf/walls/material_wall.png and b/icons/turf/walls/material_wall.png differ
diff --git a/icons/turf/walls/reinforced_states.dmi b/icons/turf/walls/reinforced_states.dmi
index 89c0114a8d6e..4fc5c06e05a9 100644
Binary files a/icons/turf/walls/reinforced_states.dmi and b/icons/turf/walls/reinforced_states.dmi differ
diff --git a/icons/turf/walls/reinforced_wall.dmi b/icons/turf/walls/reinforced_wall.dmi
index 65267a93b2d2..210268b4625a 100644
Binary files a/icons/turf/walls/reinforced_wall.dmi and b/icons/turf/walls/reinforced_wall.dmi differ
diff --git a/icons/turf/walls/reinforced_wall.png b/icons/turf/walls/reinforced_wall.png
index f8d07602c574..37093774fbdc 100644
Binary files a/icons/turf/walls/reinforced_wall.png and b/icons/turf/walls/reinforced_wall.png differ
diff --git a/icons/turf/walls/wall.dmi b/icons/turf/walls/wall.dmi
index 6cdd342fd9ed..043da38c0346 100644
Binary files a/icons/turf/walls/wall.dmi and b/icons/turf/walls/wall.dmi differ
diff --git a/icons/turf/walls/wall.png b/icons/turf/walls/wall.png
index 8f95ca652cdf..6e603751a6e0 100644
Binary files a/icons/turf/walls/wall.png and b/icons/turf/walls/wall.png differ
diff --git a/modular_dripstation/code/modules/antagonists/nukeop/nukeop.dm b/modular_dripstation/code/modules/antagonists/nukeop/nukeop.dm
index 888960577048..852269504c02 100644
--- a/modular_dripstation/code/modules/antagonists/nukeop/nukeop.dm
+++ b/modular_dripstation/code/modules/antagonists/nukeop/nukeop.dm
@@ -80,6 +80,9 @@
op_mob.real_name = "[newname]"
+//////Nuke leader//////
+/datum/antagonist/nukeop/leader
+ antag_hud_name = "syndleader"
/datum/antagonist/nukeop/leader/give_alias()
title = pick("Boss", "Commander", "Chief", "Director", "Overlord")
@@ -203,4 +206,7 @@
var/obj/item/computer_hardware/card_slot/CS = ID.loc
CS.holder?.update_label()
balloon_alert(op, "name replaced")
- search_id = 0
\ No newline at end of file
+ search_id = 0
+
+/datum/antagonist/nukeop/lone
+ antag_hud_name = "loneop"
\ No newline at end of file
diff --git a/modular_dripstation/icons/mob/hud.dmi b/modular_dripstation/icons/mob/hud.dmi
new file mode 100644
index 000000000000..cea3996fa7a5
Binary files /dev/null and b/modular_dripstation/icons/mob/hud.dmi differ
diff --git a/sound/mecha/hydraulic.ogg b/sound/mecha/hydraulic.ogg
new file mode 100644
index 000000000000..3281ed2dc0f0
Binary files /dev/null and b/sound/mecha/hydraulic.ogg differ
diff --git a/sound/mecha/powerloader_step.ogg b/sound/mecha/powerloader_step.ogg
new file mode 100644
index 000000000000..538ba1efed31
Binary files /dev/null and b/sound/mecha/powerloader_step.ogg differ
diff --git a/sound/mecha/powerloader_turn2.ogg b/sound/mecha/powerloader_turn2.ogg
new file mode 100644
index 000000000000..c3816df9d9e2
Binary files /dev/null and b/sound/mecha/powerloader_turn2.ogg differ
diff --git a/tgui/packages/common/string.js b/tgui/packages/common/string.js
index 16a0921a2559..5b4e5d6d7f2b 100644
--- a/tgui/packages/common/string.js
+++ b/tgui/packages/common/string.js
@@ -87,6 +87,19 @@ export const capitalize = str => {
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
};
+/**
+ * Similar to capitalize, this takes a string and replaces all first letters
+ * of any words.
+ *
+ * @param {string} str
+ * @return {string} The string with the first letters capitalized.
+ *
+ * @example capitalizeAll('heLLo woRLd') === 'HeLLo WoRLd'
+ */
+export const capitalizeAll = (str) => {
+ return str.replace(/(^\w{1})|(\s+\w{1})/g, (letter) => letter.toUpperCase());
+};
+
export const toTitleCase = str => {
// Handle array
if (Array.isArray(str)) {
diff --git a/tgui/packages/tgui/interfaces/AirlockElectronics.js b/tgui/packages/tgui/interfaces/AirlockElectronics.js
deleted file mode 100644
index a448f55e9b2e..000000000000
--- a/tgui/packages/tgui/interfaces/AirlockElectronics.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import { useBackend } from '../backend';
-import { Button, LabeledList, Section } from '../components';
-import { Window } from '../layouts';
-import { AccessList } from './common/AccessList';
-
-export const AirlockElectronics = (props, context) => {
- const { act, data } = useBackend(context);
- const {
- oneAccess,
- unres_direction,
- } = data;
- const regions = data.regions || [];
- const accesses = data.accesses || [];
- return (
-
-
-
-
-
-
-
-
-
-
- act('set', {
- access: ref,
- })}
- grantAll={() => act('grant_all')}
- denyAll={() => act('clear_all')}
- grantDep={ref => act('grant_region', {
- region: ref,
- })}
- denyDep={ref => act('deny_region', {
- region: ref,
- })} />
-
-
- );
-};
diff --git a/tgui/packages/tgui/interfaces/AirlockElectronics.tsx b/tgui/packages/tgui/interfaces/AirlockElectronics.tsx
new file mode 100644
index 000000000000..9166106cc02b
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/AirlockElectronics.tsx
@@ -0,0 +1,109 @@
+import { BooleanLike } from 'common/react';
+import { useBackend } from '../backend';
+import { Button, Input, LabeledList, Section } from '../components';
+import { Window } from '../layouts';
+import { AccessConfig } from './common/AccessConfig';
+
+type Data = {
+ oneAccess: BooleanLike;
+ unres_direction: number;
+ regions: string[];
+ accesses: string[];
+};
+
+export const AirLockMainSection = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ accesses = [],
+ oneAccess,
+ regions = [],
+ unres_direction,
+ } = data;
+
+ return (
+
+
+
+ act('one_access')}
+ />
+
+
+
+ act('direc_set', {
+ unres_direction: '1',
+ })
+ }
+ />
+
+ act('direc_set', {
+ unres_direction: '2',
+ })
+ }
+ />
+
+ act('direc_set', {
+ unres_direction: '4',
+ })
+ }
+ />
+
+ act('direc_set', {
+ unres_direction: '8',
+ })
+ }
+ />
+
+
+
+ act('set', {
+ access: ref,
+ })
+ }
+ grantAll={() => act('grant_all')}
+ denyAll={() => act('clear_all')}
+ grantDep={(ref) =>
+ act('grant_region', {
+ region: ref,
+ })
+ }
+ denyDep={(ref) =>
+ act('deny_region', {
+ region: ref,
+ })
+ }
+ />
+
+ );
+};
+
+export const AirlockElectronics = (props, context) => {
+ return (
+
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/RapidConstructionDevice.tsx b/tgui/packages/tgui/interfaces/RapidConstructionDevice.tsx
new file mode 100644
index 000000000000..937c4b256029
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/RapidConstructionDevice.tsx
@@ -0,0 +1,181 @@
+import { Window } from '../layouts';
+import { BooleanLike, classes } from 'common/react';
+import { capitalizeAll } from 'common/string';
+import { useBackend, useLocalState } from '../backend';
+import { LabeledList, Section, Button, Tabs, Stack, Box } from '../components';
+import { AirLockMainSection } from './AirlockElectronics';
+
+type Data = {
+ matterLeft: number;
+ silo_upgraded: BooleanLike;
+ silo_enabled: BooleanLike;
+ root_categories: string[];
+ selected_root: string;
+ categories: Category[];
+ selected_category: string;
+ selected_design: string;
+ display_tabs: BooleanLike;
+};
+
+type Category = {
+ cat_name: string;
+ designs: Design[];
+};
+
+type Design = {
+ title: string;
+ design_id: Number;
+ icon: string;
+};
+
+export const MatterItem = (props, context) => {
+ const { data } = useBackend(context);
+ const { matterLeft } = data;
+ return (
+
+ {matterLeft} Units
+
+ );
+};
+
+export const SiloItem = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { silo_enabled } = data;
+ return (
+
+ act('toggle_silo')}
+ />
+
+ );
+};
+
+const CategoryItem = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { root_categories = [], selected_root } = data;
+ return (
+
+ {root_categories.map((root) => (
+ act('root_category', { root_category: root })}
+ />
+ ))}
+
+ );
+};
+
+const InfoSection = (props, context) => {
+ const { data } = useBackend(context);
+ const { silo_upgraded } = data;
+
+ return (
+
+
+
+ {silo_upgraded ? : ''}
+
+
+
+ );
+};
+
+const DesignSection = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { categories = [], selected_category, selected_design } = data;
+ const [categoryName, setCategoryName] = useLocalState(
+ context,
+ 'categoryName',
+ selected_category
+ );
+ const shownCategory =
+ categories.find((category) => category.cat_name === categoryName) ||
+ categories[0];
+ return (
+
+
+ {categories.map((category) => (
+ setCategoryName(category.cat_name)}>
+ {category.cat_name}
+
+ ))}
+
+ {shownCategory?.designs.map((design) => (
+
+ act('design', {
+ category: shownCategory.cat_name,
+ index: design.design_id,
+ })
+ }>
+
+ {capitalizeAll(design.title)}
+
+ ))}
+
+ );
+};
+
+const ConfigureSection = (props, context) => {
+ const { data } = useBackend(context);
+ const { selected_root } = data;
+
+ return (
+
+ {selected_root === 'Airlock Access' ? (
+
+ ) : (
+
+ )}
+
+ );
+};
+
+export const RapidConstructionDevice = (props, context) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/common/AccessConfig.js b/tgui/packages/tgui/interfaces/common/AccessConfig.js
new file mode 100644
index 000000000000..32828faca24c
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/common/AccessConfig.js
@@ -0,0 +1,135 @@
+import { sortBy } from 'common/collections';
+import { Section, Button, Flex, Tabs, Grid } from '../../components';
+import { useLocalState } from '../../backend';
+
+export const AccessConfig = (props, context) => {
+ const {
+ accesses = [],
+ selectedList = [],
+ accessMod,
+ grantAll,
+ denyAll,
+ grantDep,
+ denyDep,
+ } = props;
+ const [selectedAccessName, setSelectedAccessName] = useLocalState(
+ context,
+ 'accessName',
+ accesses[0]?.name
+ );
+ const selectedAccess = accesses.find(
+ (access) => access.name === selectedAccessName
+ );
+ const selectedAccessEntries = sortBy((entry) => entry.desc)(
+ selectedAccess?.accesses || []
+ );
+
+ const checkAccessIcon = (accesses) => {
+ let oneAccess = false;
+ let oneInaccess = false;
+ for (let element of accesses) {
+ if (selectedList.includes(element.ref)) {
+ oneAccess = true;
+ } else {
+ oneInaccess = true;
+ }
+ }
+ if (!oneAccess && oneInaccess) {
+ return 0;
+ } else if (oneAccess && oneInaccess) {
+ return 1;
+ } else {
+ return 2;
+ }
+ };
+
+ return (
+
+ grantAll()}
+ />
+ denyAll()}
+ />
+ >
+ }>
+
+
+
+ {accesses.map((access) => {
+ const entries = access.accesses || [];
+ const icon = diffMap[checkAccessIcon(entries)].icon;
+ const color = diffMap[checkAccessIcon(entries)].color;
+ return (
+ setSelectedAccessName(access.name)}>
+ {access.name}
+
+ );
+ })}
+
+
+
+
+
+ grantDep(selectedAccess.regid)}
+ />
+
+
+ denyDep(selectedAccess.regid)}
+ />
+
+
+ {selectedAccessEntries.map((entry) => (
+ accessMod(entry.ref)}
+ />
+ ))}
+
+
+
+ );
+};
+
+const diffMap = {
+ 0: {
+ icon: 'times-circle',
+ color: 'bad',
+ },
+ 1: {
+ icon: 'stop-circle',
+ color: null,
+ },
+ 2: {
+ icon: 'check-circle',
+ color: 'good',
+ },
+};
diff --git a/yogstation.dme b/yogstation.dme
index 054c32eb17ba..399cfdbb7c3c 100644
--- a/yogstation.dme
+++ b/yogstation.dme
@@ -427,6 +427,7 @@
#include "code\controllers\subsystem\garbage.dm"
#include "code\controllers\subsystem\icon_smooth.dm"
#include "code\controllers\subsystem\idlenpcpool.dm"
+#include "code\controllers\subsystem\init_profiler.dm"
#include "code\controllers\subsystem\input.dm"
#include "code\controllers\subsystem\ipintel.dm"
#include "code\controllers\subsystem\job.dm"
@@ -634,6 +635,7 @@
#include "code\datums\components\spill.dm"
#include "code\datums\components\spooky.dm"
#include "code\datums\components\squeak.dm"
+#include "code\datums\components\squishable.dm"
#include "code\datums\components\stationloving.dm"
#include "code\datums\components\summoning.dm"
#include "code\datums\components\surgery_bed.dm"
@@ -1344,6 +1346,8 @@
#include "code\game\objects\items\devices\transfer_valve.dm"
#include "code\game\objects\items\devices\busterarm\_buster.dm"
#include "code\game\objects\items\devices\busterarm\buster_limb.dm"
+#include "code\game\objects\items\devices\busterarm\busterharpoon.dm"
+#include "code\game\objects\items\devices\busterarm\gasharpoon.dm"
#include "code\game\objects\items\devices\busterarm\megabuster.dm"
#include "code\game\objects\items\devices\busterarm\wire_snatch.dm"
#include "code\game\objects\items\devices\PDA\cart.dm"
@@ -3847,6 +3851,7 @@
#include "code\modules\tgui\states\observer.dm"
#include "code\modules\tgui\states\permissions.dm"
#include "code\modules\tgui\states\physical.dm"
+#include "code\modules\tgui\states\pilot.dm"
#include "code\modules\tgui\states\self.dm"
#include "code\modules\tgui\states\zlevel.dm"
#include "code\modules\tgui_input\alert.dm"
diff --git a/yogstation/code/datums/world_topic.dm b/yogstation/code/datums/world_topic.dm
index 8fc07efea64f..97e34eb09d5e 100644
--- a/yogstation/code/datums/world_topic.dm
+++ b/yogstation/code/datums/world_topic.dm
@@ -31,6 +31,8 @@ GLOBAL_VAR_INIT(mentornoot, FALSE)
var/list/admin_keys = list()
for(var/adm in GLOB.permissions.admins)
var/client/C = adm
+ if(isnull(C)) //Yog we're having issues with null holders breaking adminwho, so let's skip nulls
+ continue
if(input["adminchannel"])
admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]"
else if(!C.holder.fakekey)
diff --git a/yogstation/code/game/objects/effects/landmarks.dm b/yogstation/code/game/objects/effects/landmarks.dm
index afb45340a277..61140dd2e873 100644
--- a/yogstation/code/game/objects/effects/landmarks.dm
+++ b/yogstation/code/game/objects/effects/landmarks.dm
@@ -60,6 +60,7 @@ GLOBAL_LIST_EMPTY(chosen_station_templates)
stack_trace("Station room spawner [src] at ([T.x], [T.y], [T.z]) has a null template.")
if(!template_name || template_name == EMPTY_SPAWN)
GLOB.stationroom_landmarks -= src
+ qdel(src)
return FALSE
GLOB.chosen_station_templates += template_name
var/datum/map_template/template = SSmapping.station_room_templates[template_name]
@@ -69,7 +70,7 @@ GLOBAL_LIST_EMPTY(chosen_station_templates)
template.load(T, centered = FALSE)
template.loaded++
GLOB.stationroom_landmarks -= src
- //qdel(src)
+ qdel(src)
return TRUE
// Proc to allow you to add conditions for choosing templates, instead of just randomly picking from the template list.
@@ -91,40 +92,22 @@ GLOBAL_LIST_EMPTY(chosen_station_templates)
template_names = current_templates
return chosen_template
-/obj/effect/landmark/stationroom/box
- ///Should this landmark load a template during setup? You might not want to in the case of the chapel or clerk office that uses
- ///player preferences to determine which template loads on roundstart
- var/load_on_init = TRUE
-
-/obj/effect/landmark/stationroom/box/load(template_name)
- GLOB.stationroom_landmarks -= src
- if(!load_on_init)
- //don't actually load anything, we're going to do that ourselves
- return TRUE
- . = ..()
-
/obj/effect/landmark/stationroom/box/bar
- load_on_init = FALSE
template_names = list(
"Bar Trek", "Bar Spacious", "Bar Box", "Bar Casino", "Bar Citadel",
"Bar Conveyor", "Bar Diner", "Bar Disco", "Bar Purple", "Bar Cheese",
"Bar Clock", "Bar Arcade")
-/obj/effect/landmark/stationroom/box/bar/Initialize(mapload)
- . = ..()
- GLOB.bar_landmarks += src
+/obj/effect/landmark/stationroom/box/bar/load(template_name)
+ GLOB.stationroom_landmarks -= src
+ return TRUE
/obj/effect/landmark/stationroom/box/clerk
- load_on_init = FALSE
template_names = list("Clerk Box", "Clerk Pod", "Clerk Meta", "Clerk Gambling Hall")
-/obj/effect/landmark/stationroom/box/clerk/Initialize(mapload)
- . = ..()
- GLOB.clerk_office_landmarks += src
-
-// /obj/effect/landmark/stationroom/box/clerk/load(template_name)
-// GLOB.stationroom_landmarks -= src
-// return TRUE
+/obj/effect/landmark/stationroom/box/clerk/load(template_name)
+ GLOB.stationroom_landmarks -= src
+ return TRUE
/obj/effect/landmark/stationroom/box/engine
template_names = list("Engine SM" = 40, "Engine Singulo And Tesla" = 20, "Engine Nuclear Reactor" = 20,"Engine TEG" = 20)
@@ -161,16 +144,11 @@ GLOBAL_LIST_EMPTY(chosen_station_templates)
template_names = list("Transfer 1", "Transfer 2", "Transfer 3", "Transfer 4", "Transfer 5", "Transfer 6", "Transfer 7", "Transfer 8", "Transfer 9", "Transfer 10")
/obj/effect/landmark/stationroom/box/chapel
- load_on_init = FALSE
template_names = list("Chapel 1", "Chapel 2")
-/obj/effect/landmark/stationroom/box/chapel/Initialize(mapload)
- . = ..()
- GLOB.chapel_landmarks += src
-
-// /obj/effect/landmark/stationroom/box/chapel/load(template_name)
-// GLOB.stationroom_landmarks -= src
-// return TRUE
+/obj/effect/landmark/stationroom/box/chapel/load(template_name)
+ GLOB.stationroom_landmarks -= src
+ return TRUE
/obj/effect/landmark/stationroom/meta/engine
template_names = list("Meta SM" = 25, "Meta Nuclear Reactor" = 45, "Meta TEG" = 25) // tesla is loud as fuck and singulo doesn't make sense, so SM/reactor only
diff --git a/yogstation/code/game/objects/items/fishing/bait.dm b/yogstation/code/game/objects/items/fishing/bait.dm
index 54e4abf3d3f8..d0c64df32657 100644
--- a/yogstation/code/game/objects/items/fishing/bait.dm
+++ b/yogstation/code/game/objects/items/fishing/bait.dm
@@ -1,6 +1,6 @@
/obj/item/reagent_containers/food/snacks/bait
name = "development bait"
- desc = "if you see this, get help"
+ desc = "If you see this, get help."
icon = 'yogstation/icons/obj/fishing/fishing.dmi'
icon_state = "bait_worm"
tastes = list("sour, rotten water" = 1)
diff --git a/yogstation/code/modules/clothing/gloves/miscellaneous.dm b/yogstation/code/modules/clothing/gloves/miscellaneous.dm
index 076f56947d07..f30b0e6b7063 100644
--- a/yogstation/code/modules/clothing/gloves/miscellaneous.dm
+++ b/yogstation/code/modules/clothing/gloves/miscellaneous.dm
@@ -9,8 +9,8 @@
armor = list(melee = 35, bullet = 50, laser = 45, energy = 30, bomb = 50, bio = 50, rad = 40)
/obj/item/clothing/gloves/yogs/army
- desc = "Gloves often seen used by military folk. These gloves are fire-resistant."
name = "military gloves"
+ desc = "Gloves often seen used by military folk. These gloves are fire-resistant."
icon_state = "armygloves"
item_state = "armygloves"
cold_protection = HANDS
@@ -20,12 +20,12 @@
resistance_flags = NONE
/obj/item/clothing/gloves/yogs/namgloves
- desc = "nam gloves to help show people just exactly what war is good for."
name = "nam gloves"
+ desc = "Nam gloves to help show people just exactly what war is good for."
icon_state = "namgloves"
item_state = "namgloves"
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
- resistance_flags = NONE
\ No newline at end of file
+ resistance_flags = NONE
diff --git a/yogstation/code/modules/clothing/suits/armor.dm b/yogstation/code/modules/clothing/suits/armor.dm
index 6877bd5e8e12..ba67ea89f6eb 100644
--- a/yogstation/code/modules/clothing/suits/armor.dm
+++ b/yogstation/code/modules/clothing/suits/armor.dm
@@ -55,7 +55,7 @@
/obj/item/clothing/suit/armor/vest/hosjacket
name = "head of security jacket"
- desc = "all the style of a jacket with all the protection of a armor vest!"
+ desc = "All the style of a jacket with all the protection of a armor vest!"
mob_overlay_icon = 'yogstation/icons/mob/clothing/suit/suit.dmi'
icon = 'yogstation/icons/obj/clothing/suits.dmi'
icon_state = "hos_jacket"
@@ -63,7 +63,7 @@
/obj/item/clothing/suit/armor/vest/wardenjacket
name = "warden's black jacket"
- desc = "all the style of a jacket with all the protection of a armor vest!"
+ desc = "All the style of a jacket with all the protection of a armor vest!"
mob_overlay_icon = 'yogstation/icons/mob/clothing/suit/suit.dmi'
icon = 'yogstation/icons/obj/clothing/suits.dmi'
icon_state = "warden_jacket"
@@ -71,7 +71,7 @@
/obj/item/clothing/suit/armor/hos/germancoat
name = "padded german coat"
- desc = "for those cold german winters or for those head of securitys that want to show their true colors."
+ desc = "For those cold german winters or those heads of security that want to show their true colors."
mob_overlay_icon = 'yogstation/icons/mob/clothing/suit/suit.dmi'
icon = 'yogstation/icons/obj/clothing/suits.dmi'
icon_state = "german_coat"
diff --git a/yogstation/code/modules/clothing/suits/miscellaneous.dm b/yogstation/code/modules/clothing/suits/miscellaneous.dm
index 5bf739e57c9f..ce8501efe69c 100644
--- a/yogstation/code/modules/clothing/suits/miscellaneous.dm
+++ b/yogstation/code/modules/clothing/suits/miscellaneous.dm
@@ -365,7 +365,7 @@
/obj/item/clothing/head/hooded/winterhood/northern
name = "northern hat"
- desc = "only this, and nothing more."
+ desc = "Only this, and nothing more."
icon_state = "northern"
item_state = "northern"
diff --git a/yogstation/code/modules/jobs/job_types/brig_physician.dm b/yogstation/code/modules/jobs/job_types/brig_physician.dm
index e3d0bdf1eef4..6bdbcc5b305c 100644
--- a/yogstation/code/modules/jobs/job_types/brig_physician.dm
+++ b/yogstation/code/modules/jobs/job_types/brig_physician.dm
@@ -7,7 +7,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the chief medical officer"
- selection_color = "#d4ebf2"
minimal_player_age = 5 //seriously stop griefing
exp_requirements = 100
exp_type = EXP_TYPE_CREW
diff --git a/yogstation/code/modules/jobs/job_types/clerk.dm b/yogstation/code/modules/jobs/job_types/clerk.dm
index d7d9a2d4a114..230ee6c051ef 100644
--- a/yogstation/code/modules/jobs/job_types/clerk.dm
+++ b/yogstation/code/modules/jobs/job_types/clerk.dm
@@ -7,7 +7,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the head of personnel"
- selection_color = "#dddddd"
added_access = list()
base_access = list(ACCESS_MANUFACTURING)
alt_titles = list("Salesman", "Gift Shop Attendent", "Retail Worker")
diff --git a/yogstation/code/modules/jobs/job_types/mining_medic.dm b/yogstation/code/modules/jobs/job_types/mining_medic.dm
index 326c26a014f5..f02ce13fbc2f 100644
--- a/yogstation/code/modules/jobs/job_types/mining_medic.dm
+++ b/yogstation/code/modules/jobs/job_types/mining_medic.dm
@@ -7,7 +7,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the chief medical officer and the quartermaster"
- selection_color = "#d4ebf2"
minimal_player_age = 4
exp_requirements = 120
exp_type = EXP_TYPE_CREW
diff --git a/yogstation/code/modules/jobs/job_types/network_admin.dm b/yogstation/code/modules/jobs/job_types/network_admin.dm
index b84aac807a57..cd7a72bdc67a 100644
--- a/yogstation/code/modules/jobs/job_types/network_admin.dm
+++ b/yogstation/code/modules/jobs/job_types/network_admin.dm
@@ -7,7 +7,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the chief engineer and research director"
- selection_color = "#fff5cc"
exp_requirements = 180
exp_type = EXP_TYPE_CREW
alt_titles = list("AI Tech Support", "SysOp")
diff --git a/yogstation/code/modules/jobs/job_types/paramedic.dm b/yogstation/code/modules/jobs/job_types/paramedic.dm
index 9f8d3fbd6cfb..45581225f83c 100644
--- a/yogstation/code/modules/jobs/job_types/paramedic.dm
+++ b/yogstation/code/modules/jobs/job_types/paramedic.dm
@@ -7,7 +7,6 @@
total_positions = 3
spawn_positions = 2
supervisors = "the chief medical officer"
- selection_color = "#d4ebf2"
alt_titles = list("EMT", "Paramedic Trainee", "Rapid Response Medic", "Space Search & Rescue")
outfit = /datum/outfit/job/paramedic
diff --git a/yogstation/code/modules/jobs/job_types/psychiatrist.dm b/yogstation/code/modules/jobs/job_types/psychiatrist.dm
index 0fac1c0868ab..b7487fc5ea68 100644
--- a/yogstation/code/modules/jobs/job_types/psychiatrist.dm
+++ b/yogstation/code/modules/jobs/job_types/psychiatrist.dm
@@ -7,7 +7,6 @@
total_positions = 1
spawn_positions = 1
supervisors = "the chief medical officer"
- selection_color = "#d4ebf2"
alt_titles = list("Counsellor", "Therapist", "Mentalist")
minimal_player_age = 5 //stop griefing
diff --git a/yogstation/code/modules/jobs/job_types/tourist.dm b/yogstation/code/modules/jobs/job_types/tourist.dm
index d5ebb5c1e177..ba5aab4c8fd1 100644
--- a/yogstation/code/modules/jobs/job_types/tourist.dm
+++ b/yogstation/code/modules/jobs/job_types/tourist.dm
@@ -6,7 +6,6 @@
total_positions = -1
spawn_positions = 0
supervisors = "the head of personnel"
- selection_color = "#dddddd"
added_access = list()
base_access = list()
alt_titles = list("Visitor", "Traveler", "Siteseer", "Fisher")
diff --git a/yogstation/code/modules/jungleland/kinetic_javelin.dm b/yogstation/code/modules/jungleland/kinetic_javelin.dm
index 1c48c6d4305d..d20f0be812a2 100644
--- a/yogstation/code/modules/jungleland/kinetic_javelin.dm
+++ b/yogstation/code/modules/jungleland/kinetic_javelin.dm
@@ -23,7 +23,7 @@
/obj/item/kinetic_javelin
name = "kinetic javelin"
- desc = "powerful thrown weapon best suited to exotic environments. It has a small piece of bluespace lodged inside of it's shaft, hitting a living being while in an exotic environment teleports it straight back to you."
+ desc = "Powerful thrown weapon best suited to exotic environments. It has a small piece of bluespace lodged inside of it's shaft, hitting a living being while in an exotic environment teleports it straight back to you."
icon = 'yogstation/icons/obj/kinetic_javelin.dmi'
lefthand_file = 'yogstation/icons/mob/inhands/lefthand.dmi'
righthand_file = 'yogstation/icons/mob/inhands/righthand.dmi'