diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
index 26556306fd53c..c91658d62ab07 100644
--- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm
+++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
@@ -74302,8 +74302,8 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/cable,
-/obj/structure/disposalpipe/junction/flip{
- dir = 4
+/obj/structure/disposalpipe/junction{
+ dir = 8
},
/turf/open/floor/iron,
/area/station/hallway/primary/starboard)
diff --git a/code/__DEFINES/diseases.dm b/code/__DEFINES/diseases.dm
index 047bb79582de4..fe05a30e0fd83 100644
--- a/code/__DEFINES/diseases.dm
+++ b/code/__DEFINES/diseases.dm
@@ -81,28 +81,28 @@ DEFINE_BITFIELD(spread_flags, list(
//// Adjust to make it faster or slower to cure once the virus has reached its peak.
#define DISEASE_PEAKED_RECOVERY_MULTIPLIER 1.2
/// Slowdown Recovery Bonus - set this to the maximum extra chance per tick you want people to get to recover from spaceacillin or other slowdown/virus resistance effects
-#define DISEASE_SLOWDOWN_RECOVERY_BONUS 1
-/// Slowdown Recovery Bonus Duration - set this to the maximum # of cycles you want things that cause slowdown/virus resistance to be able to add a bonus up to DISEASE_SLOWDOWN_RECOVERY_BONUS.______qdel_list_wrapper(list/L)
+#define DISEASE_SLOWDOWN_RECOVERY_BONUS 3
+/// Slowdown Recovery Bonus Duration - set this to the maximum # of cycles you want things that cause slowdown/virus resistance to be able to add a bonus up to DISEASE_SLOWDOWN_RECOVERY_BONUS.
//// Scales down linearly over time.
-#define DISEASE_SLOWDOWN_RECOVERY_BONUS_DURATION 100
+#define DISEASE_SLOWDOWN_RECOVERY_BONUS_DURATION 200
/// Negative Malnutrition Recovery Penalty
//// Flat penalty to recovery chance if malnourished or starving
-#define DISEASE_MALNUTRITION_RECOVERY_PENALTY 1.5
+#define DISEASE_MALNUTRITION_RECOVERY_PENALTY 3
/// Satiety Recovery Multiplier - added chance to recover based on positive satiety
//// Multiplier of satiety/max_satiety if satiety is positive or zero. Increase to make satiety more valuable, decrease for less.
-#define DISEASE_SATIETY_RECOVERY_MULTIPLIER 1
+#define DISEASE_SATIETY_RECOVERY_MULTIPLIER 3
/// Good Sleeping Recovery Bonus - additive benefits for various types of good sleep (blanket, bed, darkness, pillows.)
//// Raise to make each factor add this much chance to recover.
-#define DISEASE_GOOD_SLEEPING_RECOVERY_BONUS 0.2
+#define DISEASE_GOOD_SLEEPING_RECOVERY_BONUS 0.6
/// Sleeping Recovery Multiplier - multiplies ALL recovery chance effects by this amount.
//// Set to 1 for no effect on recovery chances from sleeping.
-#define DISEASE_SLEEPING_RECOVERY_MULTIPLIER 2
+#define DISEASE_SLEEPING_RECOVERY_MULTIPLIER 6
/// Final Cure Chance Multiplier - multiplies the disease's cure chance to get the probability of moving from stage 1 to a final cure.
//// Must be greater than zero for diseases to self cure.
-#define DISEASE_FINAL_CURE_CHANCE_MULTIPLIER 3
+#define DISEASE_FINAL_CURE_CHANCE_MULTIPLIER 6
/// Symptom Offset Duration - number of cycles over which sleeping/having spaceacillin or a slowdown effect can prevent symptoms appearing
//// Set to maximum # of cycles you want to be able to offset symptoms. Scales down linearly over time.
-#define DISEASE_SYMPTOM_OFFSET_DURATION 100
+#define DISEASE_SYMPTOM_OFFSET_DURATION 200
/// Symptom Frequency Modifier
//// Raise to make symptoms fire less frequently, lower to make them fire more frequently. Keep at 0 or above.
diff --git a/code/_onclick/click_alt.dm b/code/_onclick/click_alt.dm
index 7f762a6e920ea..dfda35ebda9c8 100644
--- a/code/_onclick/click_alt.dm
+++ b/code/_onclick/click_alt.dm
@@ -24,8 +24,14 @@
client.loot_panel.open(tile)
return
- // Turfs don't have a click_alt currently, so this saves some time.
- if(!isturf(target) && can_perform_action(target, (target.interaction_flags_click | SILENT_ADJACENCY)))
+ var/can_use_click_action = FALSE
+ if(isturf(target))
+ // Turfs are special because they can't be used with can_perform_action
+ can_use_click_action = can_perform_turf_action(target)
+ else
+ can_use_click_action = can_perform_action(target, (target.interaction_flags_click | SILENT_ADJACENCY))
+
+ if(can_use_click_action)
// If it has a signal handler that returns a click action, done.
if(SEND_SIGNAL(target, COMSIG_CLICK_ALT, src) & CLICK_ACTION_ANY)
return
@@ -38,6 +44,13 @@
if(HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING))
return
+ /// No loot panel if it's on our person
+ if(isobj(target) && isliving(src))
+ var/mob/living/user = src
+ if(target in user.get_all_gear())
+ to_chat(user, span_warning("You can't search for this item, it's already in your inventory! Take it off first."))
+ return
+
client.loot_panel.open(tile)
@@ -71,3 +84,15 @@
/atom/proc/click_alt(mob/user)
SHOULD_CALL_PARENT(FALSE)
return NONE
+
+
+/// Helper proc to validate turfs. Used because can_perform_action does not support turfs.
+/mob/proc/can_perform_turf_action(turf/target)
+ if(!CanReach(target)) // No error message for parity with SILENT_ADJACENCY
+ return FALSE
+
+ if(incapacitated())
+ to_chat(src, span_warning("You can't use this!"))
+ return FALSE
+
+ return TRUE
diff --git a/code/_onclick/hud/parallax/parallax.dm b/code/_onclick/hud/parallax/parallax.dm
index 506226b41ead0..bcdcd0e74fed1 100644
--- a/code/_onclick/hud/parallax/parallax.dm
+++ b/code/_onclick/hud/parallax/parallax.dm
@@ -11,6 +11,10 @@
for(var/atom/movable/screen/plane_master/parallax as anything in get_true_plane_masters(PLANE_SPACE_PARALLAX))
parallax.unhide_plane(screenmob)
+ if(isnull(C.parallax_rock))
+ C.parallax_rock = new(null, src)
+ C.screen |= C.parallax_rock
+
if(!length(C.parallax_layers_cached))
C.parallax_layers_cached = list()
C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_1(null, src)
@@ -25,7 +29,7 @@
if (length(C.parallax_layers) > C.parallax_layers_max)
C.parallax_layers.len = C.parallax_layers_max
- C.screen |= (C.parallax_layers)
+ C.parallax_rock.vis_contents = C.parallax_layers
// We could do not do parallax for anything except the main plane group
// This could be changed, but it would require refactoring this whole thing
// And adding non client particular hooks for all the inputs, and I do not have the time I'm sorry :(
@@ -44,7 +48,7 @@
/datum/hud/proc/remove_parallax(mob/viewmob)
var/mob/screenmob = viewmob || mymob
var/client/C = screenmob.client
- C.screen -= (C.parallax_layers_cached)
+ C.screen -= (C.parallax_rock)
for(var/atom/movable/screen/plane_master/plane_master as anything in screenmob.hud_used.get_true_plane_masters(PLANE_SPACE))
if(screenmob != mymob)
C.screen -= locate(/atom/movable/screen/plane_master/parallax_white) in C.screen
@@ -104,83 +108,65 @@
update_parallax(screen_mob)
// This sets which way the current shuttle is moving (returns true if the shuttle has stopped moving so the caller can append their animation)
-/datum/hud/proc/set_parallax_movedir(new_parallax_movedir = 0, skip_windups, mob/viewmob)
+/datum/hud/proc/set_parallax_movedir(new_parallax_movedir = NONE, skip_windups, mob/viewmob)
. = FALSE
var/mob/screenmob = viewmob || mymob
var/client/C = screenmob.client
if(new_parallax_movedir == C.parallax_movedir)
return
- var/animatedir = new_parallax_movedir
- if(new_parallax_movedir == FALSE)
- var/animate_time = 0
- for(var/thing in C.parallax_layers)
- var/atom/movable/screen/parallax_layer/L = thing
- L.icon_state = initial(L.icon_state)
- L.update_o(C.view)
- var/T = PARALLAX_LOOP_TIME / L.speed
- if (T > animate_time)
- animate_time = T
- C.dont_animate_parallax = world.time + min(animate_time, PARALLAX_LOOP_TIME)
- animatedir = C.parallax_movedir
-
- var/matrix/newtransform
- switch(animatedir)
+
+ var/animation_dir = new_parallax_movedir || C.parallax_movedir
+ var/matrix/new_transform
+ switch(animation_dir)
if(NORTH)
- newtransform = matrix(1, 0, 0, 0, 1, 480)
+ new_transform = matrix(1, 0, 0, 0, 1, 480)
if(SOUTH)
- newtransform = matrix(1, 0, 0, 0, 1,-480)
+ new_transform = matrix(1, 0, 0, 0, 1,-480)
if(EAST)
- newtransform = matrix(1, 0, 480, 0, 1, 0)
+ new_transform = matrix(1, 0, 480, 0, 1, 0)
if(WEST)
- newtransform = matrix(1, 0,-480, 0, 1, 0)
-
- var/shortesttimer
- if(!skip_windups)
- for(var/thing in C.parallax_layers)
- var/atom/movable/screen/parallax_layer/L = thing
-
- var/T = PARALLAX_LOOP_TIME / L.speed
- if (isnull(shortesttimer))
- shortesttimer = T
- if (T < shortesttimer)
- shortesttimer = T
- L.transform = newtransform
- animate(L, transform = matrix(), time = T, easing = QUAD_EASING | (new_parallax_movedir ? EASE_IN : EASE_OUT), flags = ANIMATION_END_NOW)
- if (new_parallax_movedir)
- L.transform = newtransform
- animate(transform = matrix(), time = T) //queue up another animate so lag doesn't create a shutter
+ new_transform = matrix(1, 0,-480, 0, 1, 0)
+
+ var/longest_timer = 0
+ for(var/key in C.parallax_animate_timers)
+ deltimer(C.parallax_animate_timers[key])
+ C.parallax_animate_timers = list()
+ for(var/atom/movable/screen/parallax_layer/layer as anything in C.parallax_layers)
+ var/scaled_time = PARALLAX_LOOP_TIME / layer.speed
+ if(new_parallax_movedir == NONE) // If we're stopping, we need to stop on the same dime, yeah?
+ scaled_time = PARALLAX_LOOP_TIME
+ longest_timer = max(longest_timer, scaled_time)
+
+ if(skip_windups)
+ update_parallax_motionblur(C, layer, new_parallax_movedir, new_transform)
+ continue
- C.parallax_movedir = new_parallax_movedir
- if (C.parallax_animate_timer)
- deltimer(C.parallax_animate_timer)
- var/datum/callback/CB = CALLBACK(src, PROC_REF(update_parallax_motionblur), C, animatedir, new_parallax_movedir, newtransform)
- if(skip_windups)
- CB.Invoke()
- else
- C.parallax_animate_timer = addtimer(CB, min(shortesttimer, PARALLAX_LOOP_TIME), TIMER_CLIENT_TIME|TIMER_STOPPABLE)
+ layer.transform = new_transform
+ animate(layer, transform = matrix(), time = scaled_time, easing = QUAD_EASING | (new_parallax_movedir ? EASE_IN : EASE_OUT))
+ if (new_parallax_movedir == NONE)
+ continue
+ //queue up another animate so lag doesn't create a shutter
+ animate(transform = new_transform, time = 0)
+ animate(transform = matrix(), time = scaled_time / 2)
+ C.parallax_animate_timers[layer] = addtimer(CALLBACK(src, PROC_REF(update_parallax_motionblur), C, layer, new_parallax_movedir, new_transform), scaled_time, TIMER_CLIENT_TIME|TIMER_STOPPABLE)
+ C.dont_animate_parallax = world.time + min(longest_timer, PARALLAX_LOOP_TIME)
+ C.parallax_movedir = new_parallax_movedir
-/datum/hud/proc/update_parallax_motionblur(client/C, animatedir, new_parallax_movedir, matrix/newtransform)
+/datum/hud/proc/update_parallax_motionblur(client/C, atom/movable/screen/parallax_layer/layer, new_parallax_movedir, matrix/new_transform)
if(!C)
return
- C.parallax_animate_timer = FALSE
- for(var/thing in C.parallax_layers)
- var/atom/movable/screen/parallax_layer/L = thing
- if (!new_parallax_movedir)
- animate(L)
- continue
-
- var/newstate = initial(L.icon_state)
- var/T = PARALLAX_LOOP_TIME / L.speed
-
- if (newstate in icon_states(L.icon))
- L.icon_state = newstate
- L.update_o(C.view)
-
- L.transform = newtransform
-
- animate(L, transform = L.transform, time = 0, loop = -1, flags = ANIMATION_END_NOW)
- animate(transform = matrix(), time = T)
+ C.parallax_animate_timers -= layer
+
+ // If we are moving in a direction, we used the QUAD_EASING function with EASE_IN
+ // This means our position function is x^2. This is always LESS then the linear we're using here
+ // But if we just used the same time delay, our rate of change would mismatch. f'(1) = 2x for quad easing, rather then the 1 we get for linear
+ // (This is because of how derivatives work right?)
+ // Because of this, while our actual rate of change from before was PARALLAX_LOOP_TIME, our perceived rate of change was PARALLAX_LOOP_TIME / 2 (lower == faster).
+ // Let's account for that here
+ var/scaled_time = (PARALLAX_LOOP_TIME / layer.speed) / 2
+ animate(layer, transform = new_transform, time = 0, loop = -1, flags = ANIMATION_END_NOW)
+ animate(transform = matrix(), time = scaled_time)
/datum/hud/proc/update_parallax(mob/viewmob)
var/mob/screenmob = viewmob || mymob
@@ -217,36 +203,41 @@
var/our_speed = parallax_layer.speed
var/change_x
var/change_y
+ var/old_x = parallax_layer.offset_x
+ var/old_y = parallax_layer.offset_y
if(parallax_layer.absolute)
// We use change here so the typically large absolute objects (just lavaland for now) don't jitter so much
- change_x = (posobj.x - SSparallax.planet_x_offset) * our_speed + parallax_layer.offset_x
- change_y = (posobj.y - SSparallax.planet_y_offset) * our_speed + parallax_layer.offset_y
+ change_x = (posobj.x - SSparallax.planet_x_offset) * our_speed + old_x
+ change_y = (posobj.y - SSparallax.planet_y_offset) * our_speed + old_y
else
change_x = offset_x * our_speed
change_y = offset_y * our_speed
// This is how we tile parralax sprites
// It doesn't use change because we really don't want to animate this
- if(parallax_layer.offset_x - change_x > 240)
+ if(old_x - change_x > 240)
parallax_layer.offset_x -= 480
- else if(parallax_layer.offset_x - change_x < -240)
+ parallax_layer.pixel_w = parallax_layer.offset_x
+ else if(old_x - change_x < -240)
parallax_layer.offset_x += 480
- if(parallax_layer.offset_y - change_y > 240)
+ parallax_layer.pixel_w = parallax_layer.offset_x
+ if(old_y - change_y > 240)
parallax_layer.offset_y -= 480
- else if(parallax_layer.offset_y - change_y < -240)
+ parallax_layer.pixel_z = parallax_layer.offset_y
+ else if(old_y - change_y < -240)
parallax_layer.offset_y += 480
+ parallax_layer.pixel_z = parallax_layer.offset_y
- // Now that we have our offsets, let's do our positioning
parallax_layer.offset_x -= change_x
parallax_layer.offset_y -= change_y
-
- parallax_layer.screen_loc = "CENTER-7:[round(parallax_layer.offset_x, 1)],CENTER-7:[round(parallax_layer.offset_y, 1)]"
-
- // We're going to use a transform to "glide" that last movement out, so it looks nicer
+ // Now that we have our offsets, let's do our positioning
+ // We're going to use an animate to "glide" that last movement out, so it looks nicer
// Don't do any animates if we're not actually moving enough distance yeah? thanks lad
if(run_parralax && (largest_change * our_speed > 1))
- parallax_layer.transform = matrix(1,0,change_x, 0,1,change_y)
- animate(parallax_layer, transform=matrix(), time = glide_rate)
+ animate(parallax_layer, pixel_w = round(parallax_layer.offset_x, 1), pixel_z = round(parallax_layer.offset_y, 1), time = glide_rate)
+ else
+ parallax_layer.pixel_w = round(parallax_layer.offset_x, 1)
+ parallax_layer.pixel_z = round(parallax_layer.offset_y, 1)
/atom/movable/proc/update_parallax_contents()
for(var/mob/client_mob as anything in client_mobs_in_contents)
@@ -258,6 +249,15 @@
var/area/areaobj = get_area(client.eye)
hud_used.set_parallax_movedir(areaobj.parallax_movedir, TRUE)
+// Root object for parallax, all parallax layers are drawn onto this
+INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_home)
+/atom/movable/screen/parallax_home
+ icon = null
+ blend_mode = BLEND_ADD
+ plane = PLANE_SPACE_PARALLAX
+ screen_loc = "CENTER-7,CENTER-7"
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+
// We need parallax to always pass its args down into initialize, so we immediate init it
INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
/atom/movable/screen/parallax_layer
@@ -266,9 +266,9 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
var/offset_x = 0
var/offset_y = 0
var/absolute = FALSE
+ appearance_flags = APPEARANCE_UI | KEEP_TOGETHER
blend_mode = BLEND_ADD
plane = PLANE_SPACE_PARALLAX
- screen_loc = "CENTER-7,CENTER-7"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/atom/movable/screen/parallax_layer/Initialize(mapload, datum/hud/hud_owner, template = FALSE)
@@ -302,15 +302,17 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
// Turn the view size into a grid of correctly scaled overlays
var/list/viewscales = getviewsize(view)
- var/countx = CEILING((viewscales[1] / 2) * parallax_scaler, 1) + 1
- var/county = CEILING((viewscales[2] / 2) * parallax_scaler, 1) + 1
+ // This could be half the size but we need to provide space for parallax movement on mob movement, and movement on scroll from shuttles, so like this instead
+ var/countx = (CEILING((viewscales[1] / 2) * parallax_scaler, 1) + 1)
+ var/county = (CEILING((viewscales[2] / 2) * parallax_scaler, 1) + 1)
var/list/new_overlays = new
for(var/x in -countx to countx)
for(var/y in -county to county)
if(x == 0 && y == 0)
continue
var/mutable_appearance/texture_overlay = mutable_appearance(icon, icon_state)
- texture_overlay.transform = matrix(1, 0, x*480, 0, 1, y*480)
+ texture_overlay.pixel_w += 480 * x
+ texture_overlay.pixel_z += 480 * y
new_overlays += texture_overlay
cut_overlays()
add_overlay(new_overlays)
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index ea22327f13592..6f30f2a51355d 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -793,7 +793,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/splash)
food_image = image(icon = food_icon, icon_state = food_icon_state, pixel_x = -5)
food_image.plane = plane
food_image.appearance_flags |= KEEP_APART // To be unaffected by filters applied to src
- food_image.add_filter("simple_outline", 2, outline_filter(1, COLOR_BLACK))
+ food_image.add_filter("simple_outline", 2, outline_filter(1, COLOR_BLACK, OUTLINE_SHARP))
underlays += food_image // To be below filters applied to src
SetInvisibility(INVISIBILITY_ABSTRACT, name) // Start invisible, update later
diff --git a/code/controllers/subsystem/profiler.dm b/code/controllers/subsystem/profiler.dm
index dc06c2bc6ae7f..46d5b0fd57ba5 100644
--- a/code/controllers/subsystem/profiler.dm
+++ b/code/controllers/subsystem/profiler.dm
@@ -1,11 +1,8 @@
-#define PROFILER_FILENAME "profiler.json"
-#define SENDMAPS_FILENAME "sendmaps.json"
-
SUBSYSTEM_DEF(profiler)
name = "Profiler"
init_order = INIT_ORDER_PROFILER
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
- wait = 3000
+ wait = 300 SECONDS
var/fetch_cost = 0
var/write_cost = 0
@@ -56,12 +53,12 @@ SUBSYSTEM_DEF(profiler)
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]/[PROFILER_FILENAME]")
+ var/prof_file = file("[GLOB.log_directory]/profiler/profiler-[round(world.time * 0.1, 10)].json")
if(fexists(prof_file))
fdel(prof_file)
if(!length(current_sendmaps_data)) //Would be nice to have explicit proc to check this
stack_trace("Warning, sendmaps profiling stopped manually before dump.")
- var/sendmaps_file = file("[GLOB.log_directory]/[SENDMAPS_FILENAME]")
+ var/sendmaps_file = file("[GLOB.log_directory]/profiler/sendmaps-[round(world.time * 0.1, 10)].json")
if(fexists(sendmaps_file))
fdel(sendmaps_file)
@@ -70,5 +67,3 @@ SUBSYSTEM_DEF(profiler)
WRITE_FILE(sendmaps_file, current_sendmaps_data)
write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
-#undef PROFILER_FILENAME
-#undef SENDMAPS_FILENAME
diff --git a/code/datums/actions/cooldown_action.dm b/code/datums/actions/cooldown_action.dm
index 18fe9f22e8024..1c290c5f224c1 100644
--- a/code/datums/actions/cooldown_action.dm
+++ b/code/datums/actions/cooldown_action.dm
@@ -171,6 +171,9 @@
next_use_time = world.time + override_cooldown_time
else
next_use_time = world.time + cooldown_time
+ // Don't start a cooldown if we have a cooldown time of 0 seconds
+ if(next_use_time == world.time)
+ return
build_all_button_icons(UPDATE_BUTTON_STATUS)
START_PROCESSING(SSfastprocess, src)
diff --git a/code/datums/actions/mobs/ground_slam.dm b/code/datums/actions/mobs/ground_slam.dm
new file mode 100644
index 0000000000000..e00799196b589
--- /dev/null
+++ b/code/datums/actions/mobs/ground_slam.dm
@@ -0,0 +1,32 @@
+/datum/action/cooldown/mob_cooldown/ground_slam
+ name = "Ground Slam"
+ button_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon_state = "sniper_zoom"
+ desc = "Slams the ground sending out a shockwave around you."
+ cooldown_time = 10 SECONDS
+ /// The range of the slam
+ var/range = 5
+ /// The delay before the shockwave expands it's range
+ var/delay = 3
+ /// How far hit targets are thrown
+ var/throw_range = 8
+ /// Whether the target can move or not while the slam is occurring
+ var/can_move = FALSE
+
+/datum/action/cooldown/mob_cooldown/ground_slam/Activate(atom/target_atom)
+ disable_cooldown_actions()
+ RegisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move), override = TRUE)
+ do_slam(target_atom)
+ UnregisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE)
+ StartCooldown()
+ enable_cooldown_actions()
+ return TRUE
+
+/// Slams the ground around the source throwing back enemies caught nearby, delay is for the radius increase
+/datum/action/cooldown/mob_cooldown/ground_slam/proc/do_slam(atom/target)
+ wendigo_slam(owner, range, delay, throw_range)
+
+/datum/action/cooldown/mob_cooldown/ground_slam/proc/on_move(atom/source, atom/new_loc)
+ SIGNAL_HANDLER
+ if(!can_move)
+ return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
diff --git a/code/datums/actions/mobs/projectileattack.dm b/code/datums/actions/mobs/projectileattack.dm
index be7eff8963363..d8f8e6bdf6427 100644
--- a/code/datums/actions/mobs/projectileattack.dm
+++ b/code/datums/actions/mobs/projectileattack.dm
@@ -16,14 +16,23 @@
var/default_projectile_spread = 0
/// The multiplier to the projectiles speed (a value of 2 makes it twice as slow, 0.5 makes it twice as fast)
var/projectile_speed_multiplier = 1
+ /// Whether the target can move or not while the attack is occurring
+ var/can_move = TRUE
/datum/action/cooldown/mob_cooldown/projectile_attack/Activate(atom/target_atom)
disable_cooldown_actions()
+ RegisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move), override = TRUE)
attack_sequence(owner, target_atom)
+ UnregisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE)
StartCooldown()
enable_cooldown_actions()
return TRUE
+/datum/action/cooldown/mob_cooldown/projectile_attack/proc/on_move(atom/source, atom/new_loc)
+ SIGNAL_HANDLER
+ if(!can_move)
+ return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
+
/datum/action/cooldown/mob_cooldown/projectile_attack/proc/attack_sequence(mob/living/firer, atom/target)
shoot_projectile(firer, target, null, firer, rand(-default_projectile_spread, default_projectile_spread), null)
@@ -151,6 +160,25 @@
SLEEP_CHECK_DEATH(1.5 SECONDS, owner)
return ..()
+/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/wendigo
+ cooldown_time = 10 SECONDS
+ projectile_type = /obj/projectile/colossus/wendigo_shockwave/spiral
+ can_move = FALSE
+
+/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/wendigo/create_spiral_attack(mob/living/firer, atom/target, negative = pick(TRUE, FALSE))
+ wendigo_scream(firer)
+ var/shots_spiral = 40
+ var/angle_to_target = get_angle(firer, target)
+ var/spiral_direction = pick(-1, 1)
+ for(var/shot in 1 to shots_spiral)
+ var/shots_per_tick = 5 - enraged * 3
+ var/angle_change = (5 + enraged * shot / 6) * spiral_direction
+ for(var/count in 1 to shots_per_tick)
+ var/angle = angle_to_target + shot * angle_change + count * 360 / shots_per_tick
+ shoot_projectile(firer, target, angle, firer, null, null)
+ SLEEP_CHECK_DEATH(1, firer)
+ SLEEP_CHECK_DEATH(3 SECONDS, firer)
+
/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe
name = "All Directions"
button_icon = 'icons/effects/effects.dmi'
@@ -192,6 +220,13 @@
shoot_projectile(firer, target, null, firer, spread, null)
+/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/wendigo
+ cooldown_time = 10 SECONDS
+ projectile_type = /obj/projectile/colossus/wendigo_shockwave
+ shot_angles = list(-20, -10, 0, 10, 20)
+ projectile_speed_multiplier = 4
+
+
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/colossus
cooldown_time = 0.5 SECONDS
@@ -327,3 +362,54 @@
colossus.telegraph()
colossus.dir_shots.attack_sequence(firer, target)
SLEEP_CHECK_DEATH(1 SECONDS, firer)
+
+/datum/action/cooldown/mob_cooldown/projectile_attack/alternating_circle
+ name = "Alternating Shots"
+ button_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon_state = "sniper_zoom"
+ desc = "Fires projectiles around you in an alternating fashion."
+ cooldown_time = 10 SECONDS
+ projectile_type = /obj/projectile/colossus/wendigo_shockwave
+ can_move = FALSE
+ var/enraged = FALSE
+
+/datum/action/cooldown/mob_cooldown/projectile_attack/alternating_circle/attack_sequence(mob/living/firer, atom/target)
+ wendigo_scream(firer)
+ if(enraged)
+ projectile_speed_multiplier = 1
+ else
+ projectile_speed_multiplier = 1.5
+ var/shots_per = 24
+ for(var/shoot_times in 1 to 8)
+ var/offset = shoot_times % 2
+ for(var/shot in 1 to shots_per)
+ var/angle = shot * 360 / shots_per + (offset * 360 / shots_per) * 0.5
+ shoot_projectile(firer, target, angle, firer, null, null)
+ SLEEP_CHECK_DEATH(6 - enraged * 2, firer)
+ SLEEP_CHECK_DEATH(3 SECONDS, firer)
+
+/datum/action/cooldown/mob_cooldown/projectile_attack/wave
+ name = "Wave Shots"
+ button_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon_state = "sniper_zoom"
+ desc = "Fires projectiles around you in a circular wave."
+ cooldown_time = 10 SECONDS
+ projectile_type = /obj/projectile/colossus/wendigo_shockwave/wave
+ can_move = FALSE
+
+/datum/action/cooldown/mob_cooldown/projectile_attack/wave/attack_sequence(mob/living/firer, atom/target)
+ wendigo_scream(firer)
+ var/shots_per = 7
+ var/difference = 360 / shots_per
+ var/wave_direction = pick(-1, 1)
+ switch(wave_direction)
+ if(-1)
+ projectile_type = /obj/projectile/colossus/wendigo_shockwave/wave/alternate
+ if(1)
+ projectile_type = /obj/projectile/colossus/wendigo_shockwave/wave
+ for(var/shoot_times in 1 to 32)
+ for(var/shot in 1 to shots_per)
+ var/angle = shot * difference + shoot_times * 5 * wave_direction * -1
+ shoot_projectile(firer, target, angle, firer, null, null)
+ SLEEP_CHECK_DEATH(2, firer)
+ SLEEP_CHECK_DEATH(3 SECONDS, firer)
diff --git a/code/datums/actions/mobs/teleport.dm b/code/datums/actions/mobs/teleport.dm
new file mode 100644
index 0000000000000..7b7ffddf30b3d
--- /dev/null
+++ b/code/datums/actions/mobs/teleport.dm
@@ -0,0 +1,25 @@
+/datum/action/cooldown/mob_cooldown/teleport
+ name = "Teleport"
+ button_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon_state = "sniper_zoom"
+ desc = "Allows you to teleport a certain distance away from a position in a random direction."
+ cooldown_time = 10 SECONDS
+ /// The distance from the target
+ var/radius = 6
+
+/datum/action/cooldown/mob_cooldown/teleport/Activate(atom/target_atom)
+ disable_cooldown_actions()
+ teleport_to(target_atom)
+ StartCooldown()
+ enable_cooldown_actions()
+ return TRUE
+
+/// Handles randomly teleporting the owner around the target in view
+/datum/action/cooldown/mob_cooldown/teleport/proc/teleport_to(atom/teleport_target)
+ var/list/possible_ends = view(radius, teleport_target.loc) - view(radius - 1, teleport_target.loc)
+ for(var/turf/closed/cant_teleport_turf in possible_ends)
+ possible_ends -= cant_teleport_turf
+ if(!possible_ends.len)
+ return
+ var/turf/end = pick(possible_ends)
+ do_teleport(owner, end, 0, channel=TELEPORT_CHANNEL_BLUESPACE, forced = TRUE)
diff --git a/code/datums/components/echolocation.dm b/code/datums/components/echolocation.dm
index 60a6d0fa8aa3c..020c47ad875e1 100644
--- a/code/datums/components/echolocation.dm
+++ b/code/datums/components/echolocation.dm
@@ -4,11 +4,11 @@
/// Time between echolocations. IMPORTANT!! The effective time in local and the effective time in live are very different. The second is noticeably slower,
var/cooldown_time = 1 SECONDS
/// Time for the image to start fading out.
- var/image_expiry_time = 1.4 SECONDS
+ var/image_expiry_time = 0.7 SECONDS
/// Time for the image to fade in.
- var/fade_in_time = 0.4 SECONDS
+ var/fade_in_time = 0.2 SECONDS
/// Time for the image to fade out and delete itself.
- var/fade_out_time = 0.4 SECONDS
+ var/fade_out_time = 0.3 SECONDS
/// Are images static? If yes, spawns them on the turf and makes them not change location. Otherwise they change location and pixel shift with the original.
var/images_are_static = TRUE
/// With mobs that have this echo group in their echolocation receiver trait, we share echo images.
@@ -105,7 +105,7 @@
for(var/mob/living/viewer in filtered)
if(blocking_trait && HAS_TRAIT(viewer, blocking_trait))
continue
- if(HAS_TRAIT_FROM(viewer, TRAIT_ECHOLOCATION_RECEIVER, echo_group))
+ if(HAS_TRAIT_FROM(viewer, TRAIT_ECHOLOCATION_RECEIVER, echo_group) && isnull(receivers[viewer]))
receivers[viewer] = list()
for(var/atom/filtered_atom as anything in filtered)
show_image(saved_appearances["[filtered_atom.icon]-[filtered_atom.icon_state]"] || generate_appearance(filtered_atom), filtered_atom, current_time)
@@ -175,6 +175,7 @@
for(var/atom/rendered_atom as anything in receivers[echolocate_receiver])
if(receivers[echolocate_receiver][rendered_atom]["time"] <= from_when && echolocate_receiver.client)
echolocate_receiver.client.images -= receivers[echolocate_receiver][rendered_atom]["image"]
+ receivers[echolocate_receiver] -= rendered_atom
if(!length(receivers[echolocate_receiver]))
receivers -= echolocate_receiver
diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm
index bc60049e73ea6..da0a849989ec1 100644
--- a/code/datums/diseases/_disease.dm
+++ b/code/datums/diseases/_disease.dm
@@ -140,9 +140,9 @@
if(affected_mob.mob_mood) // this and most other modifiers below a shameless rip from sleeping healing buffs, but feeling good helps make it go away quicker
switch(affected_mob.mob_mood.sanity_level)
if(SANITY_LEVEL_GREAT)
- recovery_prob += 0.2
+ recovery_prob += 0.4
if(SANITY_LEVEL_NEUTRAL)
- recovery_prob += 0.1
+ recovery_prob += 0.2
if(SANITY_LEVEL_DISTURBED)
recovery_prob += 0
if(SANITY_LEVEL_UNSTABLE)
diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm
index 93edea10b41c6..3d8bfdf8837dd 100644
--- a/code/datums/diseases/advance/advance.dm
+++ b/code/datums/diseases/advance/advance.dm
@@ -266,12 +266,13 @@
properties["severity"] = round((properties["severity"] / 2), 1)
properties["severity"] *= (symptoms.len / VIRUS_SYMPTOM_LIMIT) //fewer symptoms, less severity
properties["severity"] = clamp(properties["severity"], 1, 7)
+ properties["capacity"] = get_symptom_weights()
// Assign the properties that are in the list.
/datum/disease/advance/proc/assign_properties()
if(properties?.len)
- if(properties["stealth"] >= 2)
+ if(properties["stealth"] >= properties["severity"])
visibility_flags |= HIDDEN_SCANNER
else
visibility_flags &= ~HIDDEN_SCANNER
@@ -287,7 +288,7 @@
spreading_modifier = max(CEILING(0.4 * properties["transmittable"], 1), 1)
cure_chance = clamp(7.5 - (0.5 * properties["resistance"]), 1, 10) // can be between 1 and 10
- stage_prob = max(0.5 * properties["stage_rate"], 1)
+ stage_prob = max(0.3 * properties["stage_rate"], 1)
set_severity(round(properties["severity"]), 1)
generate_cure(properties)
else
@@ -341,7 +342,7 @@
// Will generate a random cure, the more resistance the symptoms have, the harder the cure.
/datum/disease/advance/proc/generate_cure()
if(properties?.len)
- var/res = clamp(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
+ var/res = clamp(properties["resistance"] - (symptoms.len * 0.5), 1, advance_cures.len)
if(res == oldres)
return
cures = list(pick(advance_cures[res]))
@@ -402,11 +403,9 @@
// Add a symptom, if it is over the limit we take a random symptom away and add the new one.
/datum/disease/advance/proc/AddSymptom(datum/symptom/S)
-
if(HasSymptom(S))
return
-
- if(symptoms.len >= VIRUS_SYMPTOM_LIMIT)
+ while(get_symptom_weights() > VIRUS_SYMPTOM_LIMIT + S.weight)
RemoveSymptom(pick(symptoms))
symptoms += S
S.OnAdd(src)
@@ -423,6 +422,12 @@
S.name += " (neutered)"
S.OnRemove(src)
+/// How much of the symptom capacity is currently being used?
+/datum/disease/advance/proc/get_symptom_weights()
+ . = 0
+ for(var/datum/symptom/symptom as anything in symptoms)
+ . += symptom.weight
+
/*
Static Procs
diff --git a/code/datums/diseases/advance/symptoms/cough.dm b/code/datums/diseases/advance/symptoms/cough.dm
index 7368e99acc814..0a29a633a30ae 100644
--- a/code/datums/diseases/advance/symptoms/cough.dm
+++ b/code/datums/diseases/advance/symptoms/cough.dm
@@ -10,6 +10,7 @@
name = "Cough"
desc = "The virus irritates the throat of the host, causing occasional coughing. Each cough will try to infect bystanders who are within 1 tile of the host with the virus."
illness = "Jest Infection"
+ weight = 2
stealth = -1
resistance = 3
stage_speed = 1
diff --git a/code/datums/diseases/advance/symptoms/sneeze.dm b/code/datums/diseases/advance/symptoms/sneeze.dm
index 14a087da1238f..6771d57f20bca 100644
--- a/code/datums/diseases/advance/symptoms/sneeze.dm
+++ b/code/datums/diseases/advance/symptoms/sneeze.dm
@@ -10,6 +10,7 @@
name = "Sneezing"
desc = "The virus causes irritation of the nasal cavity, making the host sneeze occasionally. Sneezes from this symptom will spread the virus in a 4 meter cone in front of the host."
illness = "Bard Flu"
+ weight = 2
stealth = -2
resistance = 3
stage_speed = 0
diff --git a/code/datums/diseases/advance/symptoms/symptoms.dm b/code/datums/diseases/advance/symptoms/symptoms.dm
index 28ba45f8de4e0..5a4331b3c6183 100644
--- a/code/datums/diseases/advance/symptoms/symptoms.dm
+++ b/code/datums/diseases/advance/symptoms/symptoms.dm
@@ -39,6 +39,8 @@
var/naturally_occuring = TRUE
///If the symptom requires an organ for the effects to function, robotic organs are immune to disease unless inorganic biology symptom is present
var/required_organ
+ /// How much space does this symptom use?
+ var/weight = 1
/datum/symptom/New()
var/list/S = SSdisease.list_symptoms
@@ -106,6 +108,7 @@
var/list/data = list()
data["name"] = name
data["desc"] = desc
+ data["weight"] = weight
data["stealth"] = stealth
data["resistance"] = resistance
data["stage_speed"] = stage_speed
diff --git a/code/datums/elements/elevation.dm b/code/datums/elements/elevation.dm
index 92fba97a09414..b83548c6b5f41 100644
--- a/code/datums/elements/elevation.dm
+++ b/code/datums/elements/elevation.dm
@@ -18,8 +18,9 @@
if(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
- var/turf/turf = get_turf(target)
- if(turf)
+ var/atom/atom_target = target
+ if(isturf(atom_target.loc))
+ var/turf/turf = atom_target.loc
if(!HAS_TRAIT(turf, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift)))
RegisterSignal(turf, COMSIG_TURF_RESET_ELEVATION, PROC_REF(check_elevation))
RegisterSignal(turf, COMSIG_TURF_CHANGE, PROC_REF(pre_change_turf))
diff --git a/code/datums/elements/rust.dm b/code/datums/elements/rust.dm
index 060de19494fc0..396307197c49d 100644
--- a/code/datums/elements/rust.dm
+++ b/code/datums/elements/rust.dm
@@ -98,6 +98,8 @@
UnregisterSignal(source, COMSIG_ATOM_EXITED)
for(var/obj/effect/glowing_rune/rune_to_remove in source)
qdel(rune_to_remove)
+ for(var/mob/living/victim in source)
+ victim.remove_status_effect(/datum/status_effect/rust_corruption)
/datum/element/rust/heretic/proc/on_entered(turf/source, atom/movable/entered, ...)
SIGNAL_HANDLER
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 296a9031ae27e..9b33a901d9ebe 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -353,6 +353,7 @@
created.pixel_x = created.base_pixel_x + rand(-6, 6)
created.pixel_y = created.base_pixel_y + rand(-6, 6)
created.forceMove(target)
+ SSblackbox.record_feedback("nested tally", "lathe_printed_items", 1, list("[type]", "[created.type]"))
if(is_stack)
items_remaining = 0
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index c3621cd332958..fe03aaaf01e0d 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -454,7 +454,7 @@
if(!COOLDOWN_FINISHED(src, last_holopay_projection))
balloon_alert(user, "still recharging")
return
- if(can_be_used_in_payment(user))
+ if(!can_be_used_in_payment(user))
balloon_alert(user, "no account!")
to_chat(user, span_warning("You need a valid bank account to do this."))
return
diff --git a/code/modules/admin/verbs/lua/lua_state.dm b/code/modules/admin/verbs/lua/lua_state.dm
index 27994d966a7cb..bf2bcbd5a9003 100644
--- a/code/modules/admin/verbs/lua/lua_state.dm
+++ b/code/modules/admin/verbs/lua/lua_state.dm
@@ -111,8 +111,6 @@ GLOBAL_PROTECT(lua_usr)
for(var/path_element in function)
new_function_path += path_element
function = new_function_path
- var/msg = "[key_name(usr)] called the lua function \"[function]\" with arguments: [english_list(call_args)]"
- log_lua(msg)
var/tmp_usr = GLOB.lua_usr
GLOB.lua_usr = usr
diff --git a/code/modules/antagonists/malf_ai/malf_ai.dm b/code/modules/antagonists/malf_ai/malf_ai.dm
index b76452e6076f3..358b618df99aa 100644
--- a/code/modules/antagonists/malf_ai/malf_ai.dm
+++ b/code/modules/antagonists/malf_ai/malf_ai.dm
@@ -20,6 +20,8 @@
var/should_give_codewords = TRUE
///since the module purchasing is built into the antag info, we need to keep track of its compact mode here
var/module_picker_compactmode = FALSE
+ ///malf on_gain sound effect. Set here so Infected AI can override
+ var/malf_sound = 'sound/ambience/antag/malf.ogg'
/datum/antagonist/malf_ai/New(give_objectives = TRUE)
. = ..()
@@ -39,7 +41,8 @@
malfunction_flavor = strings(MALFUNCTION_FLAVOR_FILE, employer)
add_law_zero()
- owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
+ if(malf_sound)
+ owner.current.playsound_local(get_turf(owner.current), malf_sound, 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
owner.current.grant_language(/datum/language/codespeak, source = LANGUAGE_MALF)
var/datum/atom_hud/data/hackyhud = GLOB.huds[DATA_HUD_MALF_APC]
@@ -272,6 +275,8 @@
/datum/antagonist/malf_ai/infected
name = "Infected AI"
employer = "Infected AI"
+ can_assign_self_objectives = FALSE
+ malf_sound = null
///The player, to who is this AI slaved
var/datum/mind/boss
diff --git a/code/modules/cargo/bounties/mining.dm b/code/modules/cargo/bounties/mining.dm
index c49fc982a3ab9..933581bfdf9e2 100644
--- a/code/modules/cargo/bounties/mining.dm
+++ b/code/modules/cargo/bounties/mining.dm
@@ -46,16 +46,17 @@
/datum/bounty/item/mining/watcher_wreath
name = "Watcher Wreaths"
description = "Station 14's Research Director thinks they're onto a break-through on the cultural icons of some pagan beliefs. Ship them a few watcher wreaths for analysis."
+ include_subtypes = FALSE
reward = CARGO_CRATE_VALUE * 15
required_count = 3
- wanted_types = list(/obj/item/clothing/neck/wreath = FALSE)
+ wanted_types = list(/obj/item/clothing/neck/wreath = TRUE)
/datum/bounty/item/mining/icewing_wreath
name = "Icewing Wreath"
description = "We're getting some....weird messages from Station 14's Research Director. And most of what they said was incoherent. But they apparently want an icewing wreath. Could you send them one?"
reward = CARGO_CRATE_VALUE * 30
required_count = 1
- wanted_types = list(/obj/item/clothing/neck/wreath/icewing = FALSE)
+ wanted_types = list(/obj/item/clothing/neck/wreath/icewing = TRUE)
/datum/bounty/item/mining/bone_dagger
name = "Bone Daggers"
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index 3272620a86555..97924643604c5 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -197,6 +197,7 @@
var/list/parallax_layers
var/list/parallax_layers_cached
+ var/atom/movable/screen/parallax_home/parallax_rock
///this is the last recorded client eye by SSparallax/fire()
var/atom/movable/movingmob
var/turf/previous_turf
@@ -206,8 +207,8 @@
var/parallax_movedir = 0
/// How many parallax layers to show our client
var/parallax_layers_max = 4
- /// Timer for the area directional animation
- var/parallax_animate_timer
+ /// Timers for the area directional animation, one for each layer
+ var/list/parallax_animate_timers
/// Do we want to do parallax animations at all?
/// Exists to prevent laptop fires
var/do_parallax_animations = TRUE
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index c3163b3e0b169..1de6c330bfce9 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -601,6 +601,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
QDEL_NULL(void)
QDEL_NULL(tooltips)
QDEL_NULL(loot_panel)
+ QDEL_NULL(parallax_rock)
+ QDEL_LIST(parallax_layers_cached)
+ parallax_layers = null
seen_messages = null
Master.UpdateTickRate()
..() //Even though we're going to be hard deleted there are still some things that want to know the destroy is happening
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm
index 8906a6d2555cb..b2e0e16f9a82a 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm
@@ -302,6 +302,15 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
explosive_resistance = INFINITY
var/obj/item/hilbertshotel/parentSphere
+/turf/closed/indestructible/hoteldoor/Initialize(mapload)
+ . = ..()
+ register_context()
+
+/turf/closed/indestructible/hoteldoor/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+ context[SCREENTIP_CONTEXT_ALT_LMB] = "Peek through"
+ return CONTEXTUAL_SCREENTIP_SET
+
/turf/closed/indestructible/hoteldoor/proc/promptExit(mob/living/user)
if(!isliving(user))
return
@@ -345,6 +354,10 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
promptExit(user)
/turf/closed/indestructible/hoteldoor/click_alt(mob/user)
+ if(user.is_blind())
+ to_chat(user, span_warning("Drats! Your vision is too poor to use this!"))
+ return CLICK_ACTION_BLOCKING
+
to_chat(user, span_notice("You peak through the door's bluespace peephole..."))
user.reset_perspective(parentSphere)
var/datum/action/peephole_cancel/PHC = new
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index 8b82d4b7d7796..cd5a60a22f2ae 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -109,7 +109,7 @@
var/datum/record/crew/target = find_record(user_mob.real_name)
target?.wanted_status = WANTED_PAROLE
- security_radio.talk_into(src, "/p [user_mob.name] returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
+ security_radio.talk_into(src, "[user_mob.name] returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
user_mob.log_message("has completed their labor points goal and is now sending the gulag shuttle back to the station.", LOG_GAME)
to_chat(user_mob, span_notice("Shuttle received message and will be sent shortly."))
return TRUE
diff --git a/code/modules/mob/living/basic/jungle/venus_human_trap.dm b/code/modules/mob/living/basic/jungle/venus_human_trap.dm
index 6c0a6e2f9db8c..ec375283fcea0 100644
--- a/code/modules/mob/living/basic/jungle/venus_human_trap.dm
+++ b/code/modules/mob/living/basic/jungle/venus_human_trap.dm
@@ -216,15 +216,19 @@
QDEL_LIST(vines)
return ..()
-/datum/action/cooldown/mob_cooldown/projectile_attack/vine_tangle/Activate(atom/target_atom)
- if(isturf(target_atom) || istype(target_atom, /obj/structure/spacevine))
+/datum/action/cooldown/mob_cooldown/projectile_attack/vine_tangle/Activate(atom/movable/target_atom)
+ if(!ismovable(target_atom) || istype(target_atom, /obj/structure/spacevine))
+ return
+ if(target_atom.anchored)
+ owner.balloon_alert(owner, "can't pull!")
return
if(get_dist(owner, target_atom) > vine_grab_distance)
owner.balloon_alert(owner, "too far!")
return
- for(var/turf/blockage in get_line(owner, target_atom))
+ var/list/target_turfs = get_line(owner, target_atom) - list(get_turf(owner), get_turf(target_atom))
+ for(var/turf/blockage in target_turfs)
if(blockage.is_blocked_turf(exclude_mobs = TRUE))
- owner.balloon_alert(owner, "something's in the way!")
+ owner.balloon_alert(owner, "path blocked!")
return
var/datum/beam/new_vine = owner.Beam(target_atom, icon_state = "vine", time = vine_duration * (ismob(target_atom) ? 1 : 2), beam_type = /obj/effect/ebeam/vine, emissive = FALSE)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm
index ea048482e4f1f..31d2e62fba7dc 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm
@@ -20,6 +20,10 @@
maxbodytemp = INFINITY
vision_range = 5
aggro_vision_range = 18
+ // Pale purple, should be red enough to see stuff on lavaland
+ lighting_cutoff_red = 25
+ lighting_cutoff_green = 15
+ lighting_cutoff_blue = 35
move_force = MOVE_FORCE_OVERPOWERING
move_resist = MOVE_FORCE_OVERPOWERING
pull_force = MOVE_FORCE_OVERPOWERING
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
index d39c8a3e52bd9..8fc667df5a876 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
@@ -1,10 +1,4 @@
#define WENDIGO_ENRAGED (health <= maxHealth*0.5)
-#define WENDIGO_CIRCLE_SHOTCOUNT 24
-#define WENDIGO_CIRCLE_REPEATCOUNT 8
-#define WENDIGO_SPIRAL_SHOTCOUNT 40
-#define WENDIGO_WAVE_SHOTCOUNT 7
-#define WENDIGO_WAVE_REPEATCOUNT 32
-#define WENDIGO_SHOTGUN_SHOTCOUNT 5
/*
@@ -51,9 +45,6 @@ Difficulty: Hard
death_message = "falls to the ground in a bloody heap, shaking the arena."
death_sound = 'sound/effects/gravhit.ogg'
footstep_type = FOOTSTEP_MOB_HEAVY
- attack_action_types = list(/datum/action/innate/megafauna_attack/heavy_stomp,
- /datum/action/innate/megafauna_attack/teleport,
- /datum/action/innate/megafauna_attack/shockwave_scream)
summon_line = "GwaHOOOOOOOOOOOOOOOOOOOOO"
/// Saves the turf the megafauna was created at (spawns exit portal here)
var/turf/starting
@@ -61,37 +52,38 @@ Difficulty: Hard
var/stomp_range = 1
/// Stores directions the mob is moving, then calls that a move has fully ended when these directions are removed in moved
var/stored_move_dirs = 0
- /// If the wendigo is allowed to move
- var/can_move = TRUE
/// Time before the wendigo can scream again
var/scream_cooldown_time = 10 SECONDS
+ /// Teleport Ability
+ var/datum/action/cooldown/mob_cooldown/teleport/teleport
+ /// Shotgun Ability
+ var/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/wendigo/shotgun_blast
+ /// Ground Slam Ability
+ var/datum/action/cooldown/mob_cooldown/ground_slam/ground_slam
+ /// Alternating Projectiles Ability
+ var/datum/action/cooldown/mob_cooldown/projectile_attack/alternating_circle/alternating_circle
+ /// Spiral Projectiles Ability
+ var/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/wendigo/spiral
+ /// Wave Projectiles Ability
+ var/datum/action/cooldown/mob_cooldown/projectile_attack/wave/wave
/// Stores the last scream time so it doesn't spam it
COOLDOWN_DECLARE(scream_cooldown)
/mob/living/simple_animal/hostile/megafauna/wendigo/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT)
-
-/datum/action/innate/megafauna_attack/heavy_stomp
- name = "Heavy Stomp"
- button_icon = 'icons/mob/actions/actions_items.dmi'
- button_icon_state = "sniper_zoom"
- chosen_message = "You are now stomping the ground around you."
- chosen_attack_num = 1
-
-/datum/action/innate/megafauna_attack/teleport
- name = "Teleport"
- button_icon = 'icons/effects/bubblegum.dmi'
- button_icon_state = "smack ya one"
- chosen_message = "You are now teleporting at the target you click on."
- chosen_attack_num = 2
-
-/datum/action/innate/megafauna_attack/shockwave_scream
- name = "Shockwave Scream"
- button_icon = 'icons/mob/actions/actions_animal.dmi'
- button_icon_state = "expand"
- chosen_message = "You are now screeching, disorienting targets around you."
- chosen_attack_num = 3
+ teleport = new(src)
+ shotgun_blast = new(src)
+ ground_slam = new(src)
+ alternating_circle = new(src)
+ spiral = new(src)
+ wave = new(src)
+ teleport.Grant(src)
+ shotgun_blast.Grant(src)
+ ground_slam.Grant(src)
+ alternating_circle.Grant(src)
+ spiral.Grant(src)
+ wave.Grant(src)
/mob/living/simple_animal/hostile/megafauna/wendigo/Initialize(mapload)
. = ..()
@@ -108,13 +100,6 @@ Difficulty: Hard
move_to_delay = initial(move_to_delay)
if(client)
- switch(chosen_attack)
- if(1)
- heavy_stomp()
- if(2)
- try_teleport()
- if(3)
- shockwave_scream()
return
var/mob/living/living_target = target
@@ -127,28 +112,54 @@ Difficulty: Hard
chosen_attack = rand(1, 2)
switch(chosen_attack)
if(1)
- heavy_stomp()
+ ground_slam.Activate(target)
if(2)
- try_teleport()
+ teleport.Activate(target)
+ if(WENDIGO_ENRAGED)
+ shotgun_blast.Activate(target)
if(3)
do_teleport(src, starting, 0, channel=TELEPORT_CHANNEL_BLUESPACE, forced = TRUE)
- shockwave_scream()
+ var/shockwave_attack
+ if(WENDIGO_ENRAGED)
+ shockwave_attack = rand(1, 3)
+ else
+ shockwave_attack = rand(1, 2)
+ switch(shockwave_attack)
+ if(1)
+ alternating_circle.enraged = WENDIGO_ENRAGED
+ alternating_circle.Activate(target)
+ if(2)
+ spiral.enraged = WENDIGO_ENRAGED
+ spiral.Activate(target)
+ if(3)
+ wave.Activate(target)
+ update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 3 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 3 SECONDS))
/mob/living/simple_animal/hostile/megafauna/wendigo/Move(atom/newloc, direct)
- if(!can_move)
- return
stored_move_dirs |= direct
- return ..()
+ . = ..()
+ // Remove after anyways in case the movement was prevented
+ stored_move_dirs &= ~direct
/mob/living/simple_animal/hostile/megafauna/wendigo/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
. = ..()
stored_move_dirs &= ~movement_dir
if(!stored_move_dirs)
- INVOKE_ASYNC(src, PROC_REF(wendigo_slam), stomp_range, 1, 8)
+ INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(wendigo_slam), src, stomp_range, 1, 8)
-/// Slams the ground around the source throwing back enemies caught nearby, delay is for the radius increase
-/mob/living/simple_animal/hostile/megafauna/wendigo/proc/wendigo_slam(range, delay, throw_range)
- var/turf/origin = get_turf(src)
+/proc/wendigo_scream(mob/owner)
+ SLEEP_CHECK_DEATH(5, owner)
+ playsound(owner.loc, 'sound/magic/demon_dies.ogg', 600, FALSE, 10)
+ var/pixel_shift = rand(5, 15)
+ animate(owner, pixel_z = pixel_shift, time = 1, loop = 20, flags = ANIMATION_RELATIVE)
+ animate(pixel_z = -pixel_shift, time = 1, flags = ANIMATION_RELATIVE)
+ for(var/mob/living/dizzy_target in get_hearers_in_view(7, owner) - owner)
+ dizzy_target.set_dizzy_if_lower(12 SECONDS)
+ to_chat(dizzy_target, span_danger("[owner] screams loudly!"))
+ SLEEP_CHECK_DEATH(1 SECONDS, owner)
+
+/proc/wendigo_slam(mob/owner, range, delay, throw_range)
+ var/turf/origin = get_turf(owner)
if(!origin)
return
var/list/all_turfs = RANGE_TURFS(range, origin)
@@ -158,117 +169,16 @@ Difficulty: Hard
if(get_dist(origin, stomp_turf) > sound_range)
continue
new /obj/effect/temp_visual/small_smoke/halfsecond(stomp_turf)
- for(var/mob/living/target in stomp_turf)
- if(target == src || target.throwing)
+ for(var/mob/living/hit_mob in stomp_turf)
+ if(hit_mob == owner || hit_mob.throwing)
continue
- to_chat(target, span_userdanger("[src]'s ground slam shockwave sends you flying!"))
- var/turf/thrownat = get_ranged_target_turf_direct(src, target, throw_range, rand(-10, 10))
- target.throw_at(thrownat, 8, 2, null, TRUE, force = MOVE_FORCE_OVERPOWERING, gentle = TRUE)
- target.apply_damage(20, BRUTE, wound_bonus=CANT_WOUND)
- shake_camera(target, 2, 1)
+ to_chat(hit_mob, span_userdanger("[owner]'s ground slam shockwave sends you flying!"))
+ var/turf/thrownat = get_ranged_target_turf_direct(owner, hit_mob, throw_range, rand(-10, 10))
+ hit_mob.throw_at(thrownat, 8, 2, null, TRUE, force = MOVE_FORCE_OVERPOWERING, gentle = TRUE)
+ hit_mob.apply_damage(20, BRUTE, wound_bonus=CANT_WOUND)
+ shake_camera(hit_mob, 2, 1)
all_turfs -= stomp_turf
- sleep(delay)
-
-/// Larger but slower ground stomp
-/mob/living/simple_animal/hostile/megafauna/wendigo/proc/heavy_stomp()
- can_move = FALSE
- wendigo_slam(5, 3 - WENDIGO_ENRAGED, 8)
- update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 0 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 0 SECONDS))
- can_move = TRUE
-
-/// Teleports to a location 4 turfs away from the enemy in view
-/mob/living/simple_animal/hostile/megafauna/wendigo/proc/try_teleport()
- teleport(6)
- if(WENDIGO_ENRAGED)
- playsound(loc, 'sound/magic/clockwork/invoke_general.ogg', 100, TRUE)
- for(var/shots in 1 to WENDIGO_SHOTGUN_SHOTCOUNT)
- var/spread = shots * 10 - 30
- var/turf/startloc = get_step(get_turf(src), get_dir(src, target))
- var/turf/endloc = get_turf(target)
- if(!endloc)
- break
- var/obj/projectile/colossus/wendigo_shockwave/shockwave = new /obj/projectile/colossus/wendigo_shockwave(loc)
- shockwave.speed = 8
- shockwave.preparePixelProjectile(endloc, startloc, null, spread)
- shockwave.firer = src
- if(target)
- shockwave.original = target
- shockwave.fire()
- update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 0 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 0 SECONDS))
-
-/mob/living/simple_animal/hostile/megafauna/wendigo/proc/teleport(range = 6)
- var/list/possible_ends = view(range, target.loc) - view(range - 1, target.loc)
- for(var/turf/closed/cant_teleport_turf in possible_ends)
- possible_ends -= cant_teleport_turf
- if(!possible_ends.len)
- return
- var/turf/end = pick(possible_ends)
- do_teleport(src, end, 0, channel=TELEPORT_CHANNEL_BLUESPACE, forced = TRUE)
-
-/// Applies dizziness to all nearby enemies that can hear the scream and animates the wendigo shaking up and down as shockwave projectiles shoot outward
-/mob/living/simple_animal/hostile/megafauna/wendigo/proc/shockwave_scream()
- can_move = FALSE
- COOLDOWN_START(src, scream_cooldown, scream_cooldown_time)
- SLEEP_CHECK_DEATH(5, src)
- playsound(loc, 'sound/magic/demon_dies.ogg', 600, FALSE, 10)
- var/pixel_shift = rand(5, 15)
- animate(src, pixel_z = pixel_shift, time = 1, loop = 20, flags = ANIMATION_RELATIVE)
- animate(pixel_z = -pixel_shift, time = 1, flags = ANIMATION_RELATIVE)
- for(var/mob/living/dizzy_target in get_hearers_in_view(7, src) - src)
- dizzy_target.set_dizzy_if_lower(12 SECONDS)
- to_chat(dizzy_target, span_danger("The wendigo screams loudly!"))
- SLEEP_CHECK_DEATH(1 SECONDS, src)
- spiral_attack()
- update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 3 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 3 SECONDS))
- SLEEP_CHECK_DEATH(3 SECONDS, src)
- can_move = TRUE
-
-/// Shoots shockwave projectiles in a random preset pattern
-/mob/living/simple_animal/hostile/megafauna/wendigo/proc/spiral_attack()
- var/list/choices = list("Alternating Circle", "Spiral")
- if(WENDIGO_ENRAGED)
- choices += "Wave"
- var/spiral_type = pick(choices)
- switch(spiral_type)
- if("Alternating Circle")
- var/shots_per = WENDIGO_CIRCLE_SHOTCOUNT
- for(var/shoot_times in 1 to WENDIGO_CIRCLE_REPEATCOUNT)
- var/offset = shoot_times % 2
- for(var/shot in 1 to shots_per)
- var/angle = shot * 360 / shots_per + (offset * 360 / shots_per) * 0.5
- var/obj/projectile/colossus/wendigo_shockwave/shockwave = new /obj/projectile/colossus/wendigo_shockwave(loc)
- shockwave.firer = src
- shockwave.speed = 3 - WENDIGO_ENRAGED
- shockwave.fire(angle)
- SLEEP_CHECK_DEATH(6 - WENDIGO_ENRAGED * 2, src)
- if("Spiral")
- var/shots_spiral = WENDIGO_SPIRAL_SHOTCOUNT
- var/angle_to_target = get_angle(src, target)
- var/spiral_direction = pick(-1, 1)
- for(var/shot in 1 to shots_spiral)
- var/shots_per_tick = 5 - WENDIGO_ENRAGED * 3
- var/angle_change = (5 + WENDIGO_ENRAGED * shot / 6) * spiral_direction
- for(var/count in 1 to shots_per_tick)
- var/angle = angle_to_target + shot * angle_change + count * 360 / shots_per_tick
- var/obj/projectile/colossus/wendigo_shockwave/shockwave = new /obj/projectile/colossus/wendigo_shockwave(loc)
- shockwave.firer = src
- shockwave.damage = 15
- shockwave.fire(angle)
- SLEEP_CHECK_DEATH(1, src)
- if("Wave")
- var/shots_per = WENDIGO_WAVE_SHOTCOUNT
- var/difference = 360 / shots_per
- var/wave_direction = pick(-1, 1)
- for(var/shoot_times in 1 to WENDIGO_WAVE_REPEATCOUNT)
- for(var/shot in 1 to shots_per)
- var/angle = shot * difference + shoot_times * 5 * wave_direction * -1
- var/obj/projectile/colossus/wendigo_shockwave/shockwave = new /obj/projectile/colossus/wendigo_shockwave(loc)
- shockwave.firer = src
- shockwave.wave_movement = TRUE
- shockwave.speed = 8
- shockwave.wave_speed = 10 * wave_direction
- shockwave.fire(angle)
- SLEEP_CHECK_DEATH(2, src)
+ SLEEP_CHECK_DEATH(delay, owner)
/mob/living/simple_animal/hostile/megafauna/wendigo/death(gibbed, list/force_grant)
if(health > 0)
@@ -285,6 +195,7 @@ Difficulty: Hard
/obj/projectile/colossus/wendigo_shockwave
name = "wendigo shockwave"
+ speed = 2
/// If wave movement is enabled
var/wave_movement = FALSE
/// Amount the angle changes every pixel move
@@ -292,6 +203,17 @@ Difficulty: Hard
/// Amount of movements this projectile has made
var/pixel_moves = 0
+/obj/projectile/colossus/wendigo_shockwave/spiral
+ damage = 15
+
+/obj/projectile/colossus/wendigo_shockwave/wave
+ speed = 8
+ wave_movement = TRUE
+ wave_speed = 10
+
+/obj/projectile/colossus/wendigo_shockwave/wave/alternate
+ wave_speed = -10
+
/obj/projectile/colossus/wendigo_shockwave/pixel_move(trajectory_multiplier, hitscanning = FALSE)
. = ..()
if(wave_movement)
@@ -344,9 +266,3 @@ Difficulty: Hard
throwforce = 0
#undef WENDIGO_ENRAGED
-#undef WENDIGO_CIRCLE_SHOTCOUNT
-#undef WENDIGO_CIRCLE_REPEATCOUNT
-#undef WENDIGO_SPIRAL_SHOTCOUNT
-#undef WENDIGO_WAVE_SHOTCOUNT
-#undef WENDIGO_WAVE_REPEATCOUNT
-#undef WENDIGO_SHOTGUN_SHOTCOUNT
diff --git a/code/modules/mod/mod_paint.dm b/code/modules/mod/mod_paint.dm
index 1402a4aebc6bc..77af1f7290c83 100644
--- a/code/modules/mod/mod_paint.dm
+++ b/code/modules/mod/mod_paint.dm
@@ -151,7 +151,7 @@
if(!pick)
balloon_alert(user, "no skin picked!")
return
- mod.theme.set_skin(pick)
+ mod.theme.set_skin(mod, pick)
/obj/item/mod/paint/proc/check_menu(obj/item/mod/control/mod, mob/user)
if(user.incapacitated() || !user.is_holding(src) || !mod || mod.active || mod.activating)
@@ -186,7 +186,7 @@
if(!(skin in mod.theme.variants))
balloon_alert(user, "incompatible theme!")
return TRUE
- mod.theme.set_skin(skin)
+ mod.theme.set_skin(mod, skin)
balloon_alert(user, "skin applied")
qdel(src)
return TRUE
diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm
index ecfa570dde160..971ccaf5c72bf 100644
--- a/code/modules/mod/mod_theme.dm
+++ b/code/modules/mod/mod_theme.dm
@@ -143,6 +143,8 @@
control_part_datum.part_item = mod
mod.mod_parts["[mod.slot_flags]"] = control_part_datum
for(var/path in variants[default_skin])
+ if(!ispath(path))
+ continue
var/obj/item/mod_part = new path(mod)
if(mod_part.slot_flags == ITEM_SLOT_OCLOTHING && isclothing(mod_part))
var/obj/item/clothing/chestplate = mod_part
@@ -576,10 +578,14 @@
/obj/item/clothing/gloves/mod = list(
SEALED_CLOTHING = THICKMATERIAL,
CAN_OVERSLOT = TRUE,
+ UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE,
+ SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE,
),
/obj/item/clothing/shoes/mod = list(
SEALED_CLOTHING = THICKMATERIAL,
CAN_OVERSLOT = TRUE,
+ UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE,
+ SEALED_MESSAGE = BOOT_SEAL_MESSAGE,
),
),
)
@@ -1361,10 +1367,14 @@
/obj/item/clothing/gloves/mod = list(
SEALED_CLOTHING = THICKMATERIAL,
CAN_OVERSLOT = TRUE,
+ UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE,
+ SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE,
),
/obj/item/clothing/shoes/mod = list(
SEALED_CLOTHING = THICKMATERIAL,
CAN_OVERSLOT = TRUE,
+ UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE,
+ SEALED_MESSAGE = BOOT_SEAL_MESSAGE,
),
),
)
@@ -1506,6 +1516,8 @@
UNSEALED_CLOTHING = THICKMATERIAL|CASTING_CLOTHES,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
SEALED_INVISIBILITY = HIDEJUMPSUIT,
+ UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE,
+ SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE,
),
/obj/item/clothing/gloves/mod = list(
UNSEALED_CLOTHING = THICKMATERIAL,
@@ -2155,14 +2167,20 @@
/obj/item/clothing/suit/mod = list(
UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
SEALED_INVISIBILITY = HIDEJUMPSUIT,
+ UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE,
+ SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE,
),
/obj/item/clothing/gloves/mod = list(
UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
CAN_OVERSLOT = TRUE,
+ UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE,
+ SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE,
),
/obj/item/clothing/shoes/mod = list(
UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
CAN_OVERSLOT = TRUE,
+ UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE,
+ SEALED_MESSAGE = BOOT_SEAL_MESSAGE,
),
),
)
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index e2a197a33900c..a17a9bb8ed054 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -484,7 +484,10 @@
playsound(src, 'sound/machines/card_slide.ogg', 50)
/obj/item/modular_computer/proc/turn_on(mob/user, open_ui = TRUE)
- var/issynth = HAS_SILICON_ACCESS(user) // Robots and AIs get different activation messages.
+ var/issynth = FALSE // Robots and AIs get different activation messages.
+ if(user)
+ issynth = HAS_SILICON_ACCESS(user)
+
if(atom_integrity <= integrity_failure * max_integrity)
if(user)
if(issynth)
diff --git a/code/modules/modular_computers/computers/item/computer_circuit.dm b/code/modules/modular_computers/computers/item/computer_circuit.dm
index 2a6a0d70be971..35caaf3c85107 100644
--- a/code/modules/modular_computers/computers/item/computer_circuit.dm
+++ b/code/modules/modular_computers/computers/item/computer_circuit.dm
@@ -5,7 +5,9 @@
var/obj/item/modular_computer/computer
///Turns the PC on/off
var/datum/port/input/on_off
- ///When set, will print a piece of paper with the value as text.
+ ///Determines the text to be printed
+ var/datum/port/input/print_text
+ /// Print when triggered
var/datum/port/input/print
///Sent when turned on
@@ -18,6 +20,7 @@
var/datum/port/input/red
var/datum/port/input/green
var/datum/port/input/blue
+ var/datum/port/input/set_color
/obj/item/circuit_component/modpc/register_shell(atom/movable/shell)
. = ..()
@@ -39,10 +42,11 @@
* I hope you're cool with me doing it here.
*/
if(computer.has_light && isnull(lights))
- lights = add_input_port("Toggle Lights", PORT_TYPE_SIGNAL)
+ lights = add_input_port("Toggle Lights", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_flashlight))
red = add_input_port("Red", PORT_TYPE_NUMBER)
green = add_input_port("Green", PORT_TYPE_NUMBER)
blue = add_input_port("Blue", PORT_TYPE_NUMBER)
+ set_color = add_input_port("Set Color", PORT_TYPE_SIGNAL, trigger = PROC_REF(set_flashlight_color))
/obj/item/circuit_component/modpc/unregister_shell(atom/movable/shell)
if(computer)
@@ -51,45 +55,37 @@
return ..()
/obj/item/circuit_component/modpc/populate_ports()
- on_off = add_input_port("Turn On/Off", PORT_TYPE_SIGNAL)
- print = add_input_port("Print Text", PORT_TYPE_STRING)
+ on_off = add_input_port("Turn On/Off", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_power))
+ print_text = add_input_port("Print Text", PORT_TYPE_STRING)
+ print = add_input_port("Print", PORT_TYPE_SIGNAL, trigger = PROC_REF(print_text))
is_on = add_output_port("Turned On", PORT_TYPE_SIGNAL)
- is_on = add_output_port("Shut Down", PORT_TYPE_SIGNAL)
+ is_off = add_output_port("Shut Down", PORT_TYPE_SIGNAL)
/obj/item/circuit_component/modpc/pre_input_received(datum/port/input/port)
if(isnull(computer))
return
- if(COMPONENT_TRIGGERED_BY(print, port))
+ if(COMPONENT_TRIGGERED_BY(print_text, port))
print.set_value(html_encode(trim(print.value, MAX_PAPER_LENGTH)))
- else if(COMPONENT_TRIGGERED_BY(red, port))
- red.set_value(clamp(red.value, 0, 255))
- else if(COMPONENT_TRIGGERED_BY(blue, port))
- blue.set_value(clamp(blue.value, 0, 255))
- else if(COMPONENT_TRIGGERED_BY(green, port))
- green.set_value(clamp(green.value, 0, 255))
-
-/obj/item/circuit_component/modpc/input_received(datum/port/input/port)
- if(isnull(computer))
- return
- if(COMPONENT_TRIGGERED_BY(on_off, port))
- if(computer.enabled)
- INVOKE_ASYNC(computer, TYPE_PROC_REF(/obj/item/modular_computer, shutdown_computer))
- else
- INVOKE_ASYNC(computer, TYPE_PROC_REF(/obj/item/modular_computer, turn_on))
- return
- if(!computer.enabled)
- return
+/obj/item/circuit_component/modpc/proc/print_text(datum/source)
+ if(computer.enabled)
+ computer.print_text(print_text.value)
+
+/obj/item/circuit_component/modpc/proc/toggle_power(datum/source)
+ if(computer.enabled)
+ INVOKE_ASYNC(computer, TYPE_PROC_REF(/obj/item/modular_computer, shutdown_computer))
+ else
+ INVOKE_ASYNC(computer, TYPE_PROC_REF(/obj/item/modular_computer, turn_on))
- if(COMPONENT_TRIGGERED_BY(print, port))
- computer.print_text(print.value)
+/obj/item/circuit_component/modpc/proc/toggle_flashlight(datum/source)
+ computer.toggle_flashlight()
- if(lights)
- if(COMPONENT_TRIGGERED_BY(lights, port))
- computer.toggle_flashlight()
- if(COMPONENT_TRIGGERED_BY(red, port) || COMPONENT_TRIGGERED_BY(green, port) || COMPONENT_TRIGGERED_BY(blue, port))
- computer.set_flashlight_color(rgb(red.value || 0, green.value || 0, blue.value || 0))
+/obj/item/circuit_component/modpc/proc/set_flashlight_color(datum/source)
+ red.set_value(clamp(red.value, 0, 255))
+ blue.set_value(clamp(blue.value, 0, 255))
+ green.set_value(clamp(green.value, 0, 255))
+ computer.set_flashlight_color(rgb(red.value || 0, green.value || 0, blue.value || 0))
/obj/item/circuit_component/modpc/proc/computer_on(datum/source, mob/user)
SIGNAL_HANDLER
diff --git a/code/modules/projectiles/guns/energy/beam_rifle.dm b/code/modules/projectiles/guns/energy/beam_rifle.dm
index 1c5b025baea80..11399e9c24dad 100644
--- a/code/modules/projectiles/guns/energy/beam_rifle.dm
+++ b/code/modules/projectiles/guns/energy/beam_rifle.dm
@@ -71,6 +71,8 @@
var/current_zoom_x = 0
var/current_zoom_y = 0
+ var/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/trace = null
+
/obj/item/gun/energy/beam_rifle/apply_fantasy_bonuses(bonus)
. = ..()
delay = modify_fantasy_variable("delay", delay, -bonus * 2)
@@ -192,16 +194,19 @@
if(diff < AIMING_BEAM_ANGLE_CHANGE_THRESHOLD && !force_update)
return
aiming_lastangle = lastangle
- var/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/P = new
- P.gun = src
- P.wall_pierce_amount = wall_pierce_amount
- P.structure_pierce_amount = structure_piercing
- P.do_pierce = projectile_setting_pierce
+ // ONLY ONE at once (since fire can sleep)
+ if(trace)
+ QDEL_NULL(trace)
+ trace = new
+ trace.gun = src
+ trace.wall_pierce_amount = wall_pierce_amount
+ trace.structure_pierce_amount = structure_piercing
+ trace.do_pierce = projectile_setting_pierce
if(aiming_time)
var/percent = ((100/aiming_time)*aiming_time_left)
- P.color = rgb(255 * percent,255 * ((100 - percent) / 100),0)
+ trace.color = rgb(255 * percent,255 * ((100 - percent) / 100),0)
else
- P.color = rgb(0, 255, 0)
+ trace.color = rgb(0, 255, 0)
var/turf/curloc = get_turf(src)
var/atom/target_atom = current_user.client.mouse_object_ref?.resolve()
@@ -211,8 +216,9 @@
return
targloc = get_turf_in_angle(lastangle, curloc, 10)
var/mouse_modifiers = params2list(current_user.client.mouseParams)
- P.preparePixelProjectile(targloc, current_user, mouse_modifiers, 0)
- P.fire(lastangle)
+ trace.preparePixelProjectile(targloc, current_user, mouse_modifiers, 0)
+ trace.fire(lastangle)
+ trace = null
/obj/item/gun/energy/beam_rifle/process()
if(!aiming)
@@ -259,6 +265,7 @@
aiming_time_left = aiming_time
aiming = FALSE
QDEL_LIST(current_tracers)
+ QDEL_NULL(trace)
stop_zooming(user)
/obj/item/gun/energy/beam_rifle/proc/set_user(mob/user)
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 872bf0cdd5e48..43e4e160d06a1 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -817,6 +817,8 @@
RegisterSignal(src, COMSIG_ATOM_ATTACK_HAND, PROC_REF(attempt_parry))
if(hitscan)
process_hitscan()
+ if(QDELETED(src))
+ return
if(!(datum_flags & DF_ISPROCESSING))
START_PROCESSING(SSprojectiles, src)
pixel_move(pixel_speed_multiplier, FALSE) //move it now!
@@ -911,6 +913,9 @@
qdel(src)
return //Kill!
pixel_move(1, TRUE)
+ // No kevinz I do not care that this is a hitscan weapon, it is not allowed to travel 100 turfs in a tick
+ if(CHECK_TICK && QDELETED(src))
+ return
/obj/projectile/proc/pixel_move(trajectory_multiplier, hitscanning = FALSE)
if(!loc || !trajectory)
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index 4acb1aa0a33c6..2771bc1adb25d 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -241,7 +241,7 @@
flushing = TRUE
flushAnimation()
sleep(1 SECONDS)
- if(last_sound < world.time + 1)
+ if(last_sound < world.time - 1) //Prevents piles of items from playing a dozen sounds at once
playsound(src, 'sound/machines/disposalflush.ogg', 50, FALSE, FALSE)
last_sound = world.time
sleep(0.5 SECONDS)
diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm
index bdd31f4e9a04c..cc6a45a5f1f13 100644
--- a/code/modules/research/machinery/_production.dm
+++ b/code/modules/research/machinery/_production.dm
@@ -414,6 +414,7 @@
created.pixel_x = created.base_pixel_x + rand(-6, 6)
created.pixel_y = created.base_pixel_y + rand(-6, 6)
+ SSblackbox.record_feedback("nested tally", "lathe_printed_items", 1, list("[type]", "[created.type]"))
if(is_stack)
items_remaining = 0
diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
index bd9bbfca91f27..d13b90e5659f7 100644
--- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
+++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
@@ -580,10 +580,10 @@
. = ..()
var/mob/living/mobtarget = target
if(mobtarget.move_resist == MOVE_FORCE_OVERPOWERING) //No megafauna or bolted AIs, please.
- to_chat(source, "[span_warning("[src] is unable to lift [mobtarget].")]")
+ balloon_alert(source, "too strong!")
return
if(secmech.cargo_hold.contents.len >= secmech.cargo_hold.cargo_capacity)
- to_chat(source, "[icon2html(src, source)][span_warning("Not enough room in cargo compartment!")]")
+ balloon_alert(source, "no room!")
return
playsound(chassis, clampsound, 50, FALSE, -6)
diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm
index 2dce26624ad25..47c116cbc6029 100644
--- a/code/modules/vehicles/mecha/mech_fabricator.dm
+++ b/code/modules/vehicles/mecha/mech_fabricator.dm
@@ -260,22 +260,23 @@
*
* Returns FALSE is the machine cannot dispense the part on the appropriate turf.
* Return TRUE if the part was successfully dispensed.
- * * D - Design datum to attempt to dispense.
+ * * dispensed_design - Design datum to attempt to dispense.
*/
-/obj/machinery/mecha_part_fabricator/proc/dispense_built_part(datum/design/D)
- var/obj/item/I = new D.build_path(src)
+/obj/machinery/mecha_part_fabricator/proc/dispense_built_part(datum/design/dispensed_design)
+ var/obj/item/built_part = new dispensed_design.build_path(src)
+ SSblackbox.record_feedback("nested tally", "lathe_printed_items", 1, list("[type]", "[built_part.type]"))
being_built = null
var/turf/exit = get_step(src,(dir))
if(exit.density)
say("Error! The part outlet is obstructed.")
- desc = "It's trying to dispense the fabricated [D.name], but the part outlet is obstructed."
- stored_part = I
+ desc = "It's trying to dispense the fabricated [dispensed_design.name], but the part outlet is obstructed."
+ stored_part = built_part
return FALSE
- say("The fabrication of [I] is now complete.")
- I.forceMove(exit)
+ say("The fabrication of [built_part] is now complete.")
+ built_part.forceMove(exit)
top_job_id += 1
diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm
index 1bed2350f08c8..be9dc0d69c337 100644
--- a/code/modules/vehicles/mecha/working/ripley.dm
+++ b/code/modules/vehicles/mecha/working/ripley.dm
@@ -396,8 +396,13 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo)
return ..()
/obj/item/mecha_parts/mecha_equipment/ejector/seccage/container_resist_act(mob/living/user)
- to_chat(user, span_notice("You begin attempting a breakout. (This will take around 45 seconds and [chassis] need to remain stationary.)"))
- if(!do_after(user, 1 MINUTES, target = chassis))
+ var/breakout_time = 1 MINUTES
+
+ if (user.mob_size > MOB_SIZE_HUMAN)
+ breakout_time = 6 SECONDS
+
+ to_chat(user, span_notice("You begin attempting a breakout. (This will take around [DisplayTimeText(breakout_time)] and [chassis] needs to remain stationary.)"))
+ if(!do_after(user, breakout_time, target = chassis))
return
to_chat(user, span_notice("You break out of the [src]."))
playsound(chassis, 'sound/items/crowbar.ogg', 100, TRUE)
diff --git a/code/modules/wiremod/shell/module.dm b/code/modules/wiremod/shell/module.dm
index 9061bac3e300e..14092f5d2c83c 100644
--- a/code/modules/wiremod/shell/module.dm
+++ b/code/modules/wiremod/shell/module.dm
@@ -271,7 +271,7 @@
SIGNAL_HANDLER
var/string_list = list()
var/is_deployed = TRUE
- for(var/obj/item/part as anything in attached_module.mod.mod_parts)
+ for(var/obj/item/part as anything in attached_module.mod.get_parts())
if(part.loc == attached_module.mod)
is_deployed = FALSE
else
diff --git a/config/dynamic.json b/config/dynamic.json
index a4a1eb7ebdbfb..5761dbabc324e 100644
--- a/config/dynamic.json
+++ b/config/dynamic.json
@@ -117,10 +117,6 @@
"weight": 0
},
- "Sentient Disease": {
- "weight": 0
- },
-
"Space Pirates": {
"weight": 0
},
diff --git a/html/changelogs/AutoChangeLog-pr-83399.yml b/html/changelogs/AutoChangeLog-pr-83399.yml
new file mode 100644
index 0000000000000..750fedb54e781
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83399.yml
@@ -0,0 +1,4 @@
+author: "jlsnow301"
+delete-after: True
+changes:
+ - bugfix: "Lootpanel no longer opens up when alt clicking objects on your person"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83420.yml b/html/changelogs/AutoChangeLog-pr-83420.yml
deleted file mode 100644
index 1d1cb39750c2a..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83420.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "YesterdaysPromise"
-delete-after: True
-changes:
- - image: "Cleaned a single stray pixel in a single frame of a bite telegraphing accidentaly found while re-organizing the files."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83421.yml b/html/changelogs/AutoChangeLog-pr-83421.yml
deleted file mode 100644
index 9a03244707dcd..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83421.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Melbert"
-delete-after: True
-changes:
- - refactor: "Refactored the way high toxins cause you to vomit."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83425.yml b/html/changelogs/AutoChangeLog-pr-83425.yml
new file mode 100644
index 0000000000000..4bb476e3ce13b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83425.yml
@@ -0,0 +1,6 @@
+author: "FlufflesTheDog"
+delete-after: True
+changes:
+ - bugfix: "some missing modsuit (un)sealing messages should no longer be missing"
+ - bugfix: "MOD circuit adapter core deployed parts output should work again"
+ - bugfix: "Modsuit painter works again"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83431.yml b/html/changelogs/AutoChangeLog-pr-83431.yml
new file mode 100644
index 0000000000000..0aa1c01e555ec
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83431.yml
@@ -0,0 +1,5 @@
+author: "jlsnow301"
+delete-after: True
+changes:
+ - rscadd: "Added a screentip for hilbert's hotel door"
+ - bugfix: "Fixed alt-click interaction with hilbert's hotel door"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83432.yml b/html/changelogs/AutoChangeLog-pr-83432.yml
deleted file mode 100644
index 53ebc36723874..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83432.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "by INFRARED_BARON"
-delete-after: True
-changes:
- - image: "Changes the sprites of bone and ash drake armor (suit + helmet mob/objs)"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83453.yml b/html/changelogs/AutoChangeLog-pr-83453.yml
deleted file mode 100644
index cc036ce9d1498..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83453.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Time-Green"
-delete-after: True
-changes:
- - rscdel: "Removes sentient disease from the game"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83455.yml b/html/changelogs/AutoChangeLog-pr-83455.yml
deleted file mode 100644
index d7f9b7d0dd1b6..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83455.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Time-Green"
-delete-after: True
-changes:
- - rscdel: "Miasma and gibs no longer generates random diseases"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83460.yml b/html/changelogs/AutoChangeLog-pr-83460.yml
new file mode 100644
index 0000000000000..859ba4611eeab
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83460.yml
@@ -0,0 +1,4 @@
+author: "Mey-Ha-Zah"
+delete-after: True
+changes:
+ - image: "Revamped Contractor Gear. You'll stand out more now, but hey, that's why the syndicate contracts out work in the first place."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83470.yml b/html/changelogs/AutoChangeLog-pr-83470.yml
new file mode 100644
index 0000000000000..753c455022860
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83470.yml
@@ -0,0 +1,4 @@
+author: "Capsandi"
+delete-after: True
+changes:
+ - sound: "Disposal chutes will no longer play a sound for each item when many items enter it at once"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83472.yml b/html/changelogs/AutoChangeLog-pr-83472.yml
new file mode 100644
index 0000000000000..6eb62ab86bce6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83472.yml
@@ -0,0 +1,4 @@
+author: "Melbert"
+delete-after: True
+changes:
+ - bugfix: "The Bar on Icebox should receive less trash"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83486.yml b/html/changelogs/AutoChangeLog-pr-83486.yml
deleted file mode 100644
index 1ae1044efe103..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83486.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "necromanceranne"
-delete-after: True
-changes:
- - bugfix: "Material floor tiles once again have their improved sprite."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83498.yml b/html/changelogs/AutoChangeLog-pr-83498.yml
new file mode 100644
index 0000000000000..98532aea8dc63
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83498.yml
@@ -0,0 +1,4 @@
+author: "Absolucy"
+delete-after: True
+changes:
+ - bugfix: "Fix a rare issue where a turf would remain permanently \"elevated\" if an elevated object was initialized inside of a non-turf object."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83506.yml b/html/changelogs/AutoChangeLog-pr-83506.yml
new file mode 100644
index 0000000000000..d9db6982d0ef9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83506.yml
@@ -0,0 +1,4 @@
+author: "NewyearnewmeUwu"
+delete-after: True
+changes:
+ - bugfix: "Fixed a typo preventing creation of paystands using an ID."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83518.yml b/html/changelogs/AutoChangeLog-pr-83518.yml
new file mode 100644
index 0000000000000..54333ae06168e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83518.yml
@@ -0,0 +1,4 @@
+author: "Time-Green"
+delete-after: True
+changes:
+ - rscdel: "Wipes the last echo of sentient disease from existence"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83523.yml b/html/changelogs/AutoChangeLog-pr-83523.yml
new file mode 100644
index 0000000000000..2db25d83372e9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83523.yml
@@ -0,0 +1,4 @@
+author: "FearfulFurnishing"
+delete-after: True
+changes:
+ - bugfix: "fixed watcher wreath bounties being incompletable"
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml
index 0bc768070518f..aaa901966a304 100644
--- a/html/changelogs/archive/2024-05.yml
+++ b/html/changelogs/archive/2024-05.yml
@@ -700,3 +700,56 @@
- qol: Made borg inventory not shift around depending on equipped items
tmyqlfpir:
- bugfix: '[Ice Box Station] Dorm 1''s door no longer shares ID with dorm 2''s door'
+2024-05-27:
+ Melbert:
+ - refactor: Refactored the way high toxins cause you to vomit.
+ Time-Green:
+ - rscdel: Removes sentient disease from the game
+ - rscdel: Miasma and gibs no longer generates random diseases
+ YesterdaysPromise:
+ - image: Cleaned a single stray pixel in a single frame of a bite telegraphing accidentaly
+ found while re-organizing the files.
+ by INFRARED_BARON:
+ - image: Changes the sprites of bone and ash drake armor (suit + helmet mob/objs)
+ necromanceranne:
+ - bugfix: Material floor tiles once again have their improved sprite.
+2024-05-28:
+ Echriser:
+ - bugfix: computers with no lights can now turn on using the on/off signal
+ - bugfix: RGB lights on PDA circuits now use a signal
+ - bugfix: the is_off signal now works on consoles
+ - bugfix: printing text on a console component now uses a signal
+ - refactor: each input signal in console circuits now have their own proc
+ EnterTheJake:
+ - bugfix: Rust debuffs now gets properly removed if you derust a tile you are standing
+ on.
+ Fikou:
+ - image: makes food hud burger icon have a sharp outline
+ Fluffles:
+ - bugfix: echolocation is less laggy. and works.
+ Higgin:
+ - balance: Viruses now self-heal much more effectively with good mood, sleep, food,
+ and spaceacillin.
+ - balance: Viruses now punish being hungry more. Stay fed!
+ - balance: Spaceacillin now gives 200 ticks of symptom resistance, declining over
+ time, rather than 100.
+ - balance: Viruses now progress slightly slower.
+ - balance: Viruses now only hide if their stealth stat is greater than their total
+ computed severity.
+ Jacquerel:
+ - balance: Mobs significantly larger than humans, such as Space Dragons and Xenomorph
+ Queens, breakout of being arrested by a mech significantly faster.
+ - bugfix: Venus Man Traps cannot use vines to drag around machines or objects that
+ are bolted, welded, rooted to, or otherwise are part of the ground
+ - bugfix: Standing on a table will not prevent you from being grappled by a Venus
+ Man Trap
+ LemonInTheDark:
+ - refactor: I have reworked how parallax and its animations (space travel) work.
+ Please report any bugs lads!
+ Pickle-Coding:
+ - spellcheck: Fixes labour camp shuttle retrieval message starting with "/p".
+ Whoneedspacee:
+ - refactor: Wendigos abilities have been changed into actions that can be added
+ to any mob.
+ zxaber:
+ - qol: Traitor-created Infected AIs no longer hear the Malf AI antag sound alert.
diff --git a/icons/mob/clothing/head/spacehelm.dmi b/icons/mob/clothing/head/spacehelm.dmi
index 181e5eb2e6865..0b9f3d4a36eb4 100644
Binary files a/icons/mob/clothing/head/spacehelm.dmi and b/icons/mob/clothing/head/spacehelm.dmi differ
diff --git a/icons/mob/clothing/suits/spacesuit.dmi b/icons/mob/clothing/suits/spacesuit.dmi
index 3c381ecd56f94..0067c4bf36a8c 100644
Binary files a/icons/mob/clothing/suits/spacesuit.dmi and b/icons/mob/clothing/suits/spacesuit.dmi differ
diff --git a/icons/mob/inhands/weapons/melee_lefthand.dmi b/icons/mob/inhands/weapons/melee_lefthand.dmi
index 79a362a009007..d1ac470b093ff 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 222f8955396c6..8c18a06de3a24 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/obj/clothing/head/spacehelm.dmi b/icons/obj/clothing/head/spacehelm.dmi
index ee8127e4964bb..c2830a9d9335f 100644
Binary files a/icons/obj/clothing/head/spacehelm.dmi and b/icons/obj/clothing/head/spacehelm.dmi differ
diff --git a/icons/obj/clothing/suits/spacesuit.dmi b/icons/obj/clothing/suits/spacesuit.dmi
index 84f84ac978e85..922ad05c35e7a 100644
Binary files a/icons/obj/clothing/suits/spacesuit.dmi and b/icons/obj/clothing/suits/spacesuit.dmi differ
diff --git a/icons/obj/weapons/baton.dmi b/icons/obj/weapons/baton.dmi
index e97547d851745..2d5100ec4d414 100644
Binary files a/icons/obj/weapons/baton.dmi and b/icons/obj/weapons/baton.dmi differ
diff --git a/sound/machines/hiss.ogg b/sound/machines/hiss.ogg
index a1b725eab931e..73ace2de31fcf 100644
Binary files a/sound/machines/hiss.ogg and b/sound/machines/hiss.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index d35ffe575fabd..165b2419ccc35 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -852,6 +852,7 @@
#include "code\datums\actions\mobs\dash.dm"
#include "code\datums\actions\mobs\defensive_mode.dm"
#include "code\datums\actions\mobs\fire_breath.dm"
+#include "code\datums\actions\mobs\ground_slam.dm"
#include "code\datums\actions\mobs\lava_swoop.dm"
#include "code\datums\actions\mobs\meteors.dm"
#include "code\datums\actions\mobs\mobcooldown.dm"
@@ -860,6 +861,7 @@
#include "code\datums\actions\mobs\projectileattack.dm"
#include "code\datums\actions\mobs\sign_language.dm"
#include "code\datums\actions\mobs\sneak.dm"
+#include "code\datums\actions\mobs\teleport.dm"
#include "code\datums\actions\mobs\transform_weapon.dm"
#include "code\datums\actions\mobs\sequences\dash_attack.dm"
#include "code\datums\actions\mobs\sequences\projectile.dm"
diff --git a/tgui/packages/tgui/interfaces/Pandemic/Symptom.tsx b/tgui/packages/tgui/interfaces/Pandemic/Symptom.tsx
index cdbb49f715fca..5fa92583f2e51 100644
--- a/tgui/packages/tgui/interfaces/Pandemic/Symptom.tsx
+++ b/tgui/packages/tgui/interfaces/Pandemic/Symptom.tsx
@@ -70,7 +70,7 @@ const Thresholds = (props) => {
/** Displays the numerical trait modifiers for a virus symptom */
const Traits = (props) => {
const {
- symptom: { level, resistance, stage_speed, stealth, transmission },
+ symptom: { level, weight, resistance, stage_speed, stealth, transmission },
} = props;
return (
@@ -81,6 +81,11 @@ const Traits = (props) => {
{level}
+
+
+ {weight}
+
+
{resistance}
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentientdisease.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentientdisease.ts
deleted file mode 100644
index a9c11eda72910..0000000000000
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentientdisease.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Antagonist, Category } from '../base';
-
-const SentientDisease: Antagonist = {
- key: 'sentientdisease',
- name: 'Sentient Disease',
- description: [
- `
- Mutate and spread yourself and infect as much of the crew as possible
- with a deadly plague of your own creation.
- `,
- ],
- category: Category.Midround,
-};
-
-export default SentientDisease;