diff --git a/code/__DEFINES/color/color_priority.dm b/code/__DEFINES/color/color_priority.dm
new file mode 100644
index 0000000000..040ff5003a
--- /dev/null
+++ b/code/__DEFINES/color/color_priority.dm
@@ -0,0 +1,6 @@
+//different types of atom colorations
+#define ADMIN_COLOUR_PRIORITY 1 //only used by rare effects like greentext coloring mobs and when admins varedit color
+#define TEMPORARY_COLOUR_PRIORITY 2 //e.g. purple effect of the revenant on a mob, black effect when mob electrocuted
+#define WASHABLE_COLOUR_PRIORITY 3 //color splashed onto an atom (e.g. paint on turf)
+#define FIXED_COLOUR_PRIORITY 4 //color inherent to the atom (e.g. blob color)
+#define COLOUR_PRIORITY_AMOUNT 4 //how many priority levels there are.
diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/color/colors.dm
similarity index 100%
rename from code/__DEFINES/colors.dm
rename to code/__DEFINES/color/colors.dm
diff --git a/code/__DEFINES/color/lum.dm b/code/__DEFINES/color/lum.dm
new file mode 100644
index 0000000000..942462b573
--- /dev/null
+++ b/code/__DEFINES/color/lum.dm
@@ -0,0 +1,4 @@
+//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1.
+#define LUMA_R 0.213
+#define LUMA_G 0.715
+#define LUMA_B 0.072
diff --git a/code/__DEFINES/layers_planes.dm b/code/__DEFINES/layers_planes.dm
index 531629c7cd..2550084207 100644
--- a/code/__DEFINES/layers_planes.dm
+++ b/code/__DEFINES/layers_planes.dm
@@ -5,9 +5,10 @@
#define CLICKCATCHER_PLANE -99
-#define PLANE_SPACE -95
+#define PLANE_SPACE -98
#define PLANE_SPACE_RENDER_TARGET "PLANE_SPACE"
-#define PLANE_SPACE_PARALLAX -90
+
+#define PLANE_SPACE_PARALLAX -95
#define PLANE_SPACE_PARALLAX_RENDER_TARGET "PLANE_SPACE_PARALLAX"
#define OPENSPACE_LAYER 17 //Openspace layer over all
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 1410a5d99a..0b5c277a3a 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -345,18 +345,6 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
//TODO Move to a pref
#define STATION_GOAL_BUDGET 1
-//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1.
-#define LUMA_R 0.213
-#define LUMA_G 0.715
-#define LUMA_B 0.072
-
-//different types of atom colorations
-#define ADMIN_COLOUR_PRIORITY 1 //only used by rare effects like greentext coloring mobs and when admins varedit color
-#define TEMPORARY_COLOUR_PRIORITY 2 //e.g. purple effect of the revenant on a mob, black effect when mob electrocuted
-#define WASHABLE_COLOUR_PRIORITY 3 //color splashed onto an atom (e.g. paint on turf)
-#define FIXED_COLOUR_PRIORITY 4 //color inherent to the atom (e.g. blob color)
-#define COLOUR_PRIORITY_AMOUNT 4 //how many priority levels there are.
-
//Endgame Results
#define NUKE_NEAR_MISS 1
#define NUKE_MISS_STATION 2
@@ -568,3 +556,8 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define SHOES_KNOTTED 2
#define WANTED_FILE "wanted_message.json"
+
+// Notification action types
+#define NOTIFY_JUMP "jump"
+#define NOTIFY_ATTACK "attack"
+#define NOTIFY_ORBIT "orbit"
diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index cd13510366..cb95aab8c0 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -34,12 +34,6 @@
#define TOGGLES_DEFAULT_CHAT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_PULLR|CHAT_GHOSTWHISPER|CHAT_GHOSTPDA|CHAT_GHOSTRADIO|CHAT_LOOC|CHAT_BANKCARD)
-#define PARALLAX_INSANE -1 //for show offs
-#define PARALLAX_HIGH 0 //default.
-#define PARALLAX_MED 1
-#define PARALLAX_LOW 2
-#define PARALLAX_DISABLE 3 //this option must be the highest number
-
#define PIXEL_SCALING_AUTO 0
#define PIXEL_SCALING_1X 1
#define PIXEL_SCALING_1_2X 1.5
@@ -50,10 +44,6 @@
#define SCALING_METHOD_DISTORT "distort"
#define SCALING_METHOD_BLUR "blur"
-#define PARALLAX_DELAY_DEFAULT world.tick_lag
-#define PARALLAX_DELAY_MED 1
-#define PARALLAX_DELAY_LOW 2
-
#define SEC_DEPT_NONE "None"
#define SEC_DEPT_RANDOM "Random"
#define SEC_DEPT_ENGINEERING "Engineering"
diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/rendering/atom_hud.dm
similarity index 95%
rename from code/__DEFINES/atom_hud.dm
rename to code/__DEFINES/rendering/atom_hud.dm
index 386473a3ae..f62a7f6103 100644
--- a/code/__DEFINES/atom_hud.dm
+++ b/code/__DEFINES/rendering/atom_hud.dm
@@ -62,9 +62,4 @@
#define ANTAG_HUD_FUGITIVE 25
#define ANTAG_HUD_HERETIC 26
-// Notification action types
-#define NOTIFY_JUMP "jump"
-#define NOTIFY_ATTACK "attack"
-#define NOTIFY_ORBIT "orbit"
-
#define ADD_HUD_TO_COOLDOWN 20 //cooldown for being shown the images for any particular data hud
diff --git a/code/__DEFINES/rendering/parallax.dm b/code/__DEFINES/rendering/parallax.dm
new file mode 100644
index 0000000000..8170b4190d
--- /dev/null
+++ b/code/__DEFINES/rendering/parallax.dm
@@ -0,0 +1,13 @@
+#define PARALLAX_DELAY_DEFAULT world.tick_lag
+#define PARALLAX_DELAY_MED 1
+#define PARALLAX_DELAY_LOW 2
+
+// WARNING - client.prefs uses this, if you change these make sure to update the code in preferences!
+#define PARALLAX_DISABLE 0
+#define PARALLAX_LOW 1
+#define PARALLAX_MED 2
+#define PARALLAX_HIGH 3
+#define PARALLAX_INSANE 4 // default
+
+// keep this false until we can fix it being a seizure hazard/ugly as sin
+#define PARALLAX_ROTATION_ANIMATIONS FALSE
diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm
index a188bf8363..862cc27f04 100644
--- a/code/__DEFINES/shuttles.dm
+++ b/code/__DEFINES/shuttles.dm
@@ -44,7 +44,6 @@
#define SHUTTLE_TRANSIT_BORDER 10
-#define PARALLAX_LOOP_TIME 25
#define HYPERSPACE_END_TIME 5
#define HYPERSPACE_WARMUP 1
diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices/color_matrix.dm
similarity index 59%
rename from code/__HELPERS/matrices.dm
rename to code/__HELPERS/matrices/color_matrix.dm
index 59fbb4ffc0..e4a4a9bb48 100644
--- a/code/__HELPERS/matrices.dm
+++ b/code/__HELPERS/matrices/color_matrix.dm
@@ -1,85 +1,3 @@
-/matrix/proc/TurnTo(old_angle, new_angle)
- . = 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 = 10, 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
-
-//Dumps the matrix data in format a-f
-/matrix/proc/tolist()
- . = list()
- . += a
- . += b
- . += c
- . += d
- . += e
- . += f
-
-//Dumps the matrix data in a matrix-grid format
-/*
- a d 0
- b e 0
- c f 1
-*/
-/matrix/proc/togrid()
- . = list()
- . += a
- . += d
- . += 0
- . += b
- . += e
- . += 0
- . += c
- . += f
- . += 1
-
-//The X pixel offset of this matrix
-/matrix/proc/get_x_shift()
- . = c
-
-//The Y pixel offset of this matrix
-/matrix/proc/get_y_shift()
- . = f
-
-/matrix/proc/get_x_skew()
- . = b
-
-/matrix/proc/get_y_skew()
- . = d
-
-//Skews a matrix in a particular direction
-//Missing arguments are treated as no skew in that direction
-
-//As Rotation is defined as a scale+skew, these procs will break any existing rotation
-//Unless the result is multiplied against the current matrix
-/matrix/proc/set_skew(x = 0, y = 0)
- b = x
- d = y
-
-
/////////////////////
// COLOUR MATRICES //
/////////////////////
@@ -114,12 +32,64 @@ list(0.393,0.349,0.272,0, 0.769,0.686,0.534,0, 0.189,0.168,0.131,0, 0,0,0,1, 0,0
return list(R + value,R,R,0, G,G + value,G,0, B,B,B + value,0, 0,0,0,1, 0,0,0,0)
+/**
+ * Exxagerates or removes colors
+ */
+/proc/color_matrix_saturation_percent(percent)
+ if(percent == 0)
+ return color_matrix_identity()
+ percent = clamp(percent, -100, 100)
+ if(percent > 0)
+ percent *= 3
+ var/x = 1 + percent / 100
+ var/inv = 1 - x
+ var/R = LUMA_R * inv
+ var/G = LUMA_G * inv
+ var/B = LUMA_B * inv
+
+ return list(R + x,R,R, G,G + x,G, B,B,B + x)
+
//Changes distance colors have from rgb(127,127,127) grey
//1 is identity. 0 makes everything grey >1 blows out colors and greys
/proc/color_matrix_contrast(value)
var/add = (1 - value) / 2
return list(value,0,0,0, 0,value,0,0, 0,0,value,0, 0,0,0,1, add,add,add,0)
+/**
+ * Exxagerates or removes brightness
+ */
+/proc/color_matrix_contrast_percent(percent)
+ var/static/list/delta_index = list(
+ 0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11,
+ 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
+ 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
+ 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68,
+ 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
+ 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
+ 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25,
+ 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8,
+ 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0,
+ 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8,
+ 10.0)
+ percent = clamp(percent, -100, 100)
+ if(percent == 0)
+ return color_matrix_identity()
+
+ var/x = 0
+ if (percent < 0)
+ x = 127 + percent / 100 * 127;
+ else
+ x = percent % 1
+ if(x == 0)
+ x = delta_index[percent]
+ else
+ x = delta_index[percent] * (1-x) + delta_index[percent+1] * x//use linear interpolation for more granularity.
+ x = x * 127 + 127
+
+ var/mult = x / 127
+ var/add = 0.5 * (127-x) / 255
+ return list(mult,0,0, 0,mult,0, 0,0,mult, add,add,add)
+
//Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting greys
//0 is identity, 120 moves reds to greens, 240 moves reds to blues
/proc/color_matrix_rotate_hue(angle)
@@ -134,6 +104,26 @@ round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), ro
0,0,0,1,
0,0,0,0)
+/**
+ * Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting whites
+ * TODO: Need a version that only affects one color (ie shift red to blue but leave greens and blues alone)
+ */
+/proc/color_matrix_rotation(angle)
+ if(angle == 0)
+ return color_matrix_identity()
+ angle = clamp(angle, -180, 180)
+ var/cos = cos(angle)
+ var/sin = sin(angle)
+
+ var/constA = 0.143
+ var/constB = 0.140
+ var/constC = -0.283
+ return list(
+ LUMA_R + cos * (1-LUMA_R) + sin * -LUMA_R, LUMA_R + cos * -LUMA_R + sin * constA, LUMA_R + cos * -LUMA_R + sin * -(1-LUMA_R),
+ LUMA_G + cos * -LUMA_G + sin * -LUMA_G, LUMA_G + cos * (1-LUMA_G) + sin * constB, LUMA_G + cos * -LUMA_G + sin * LUMA_G,
+ LUMA_B + cos * -LUMA_B + sin * (1-LUMA_B), LUMA_B + cos * -LUMA_B + sin * constC, LUMA_B + cos * (1-LUMA_B) + sin * LUMA_B
+ )
+
//These next three rotate values about one axis only
//x is the red axis, y is the green axis, z is the blue axis.
/proc/color_matrix_rotate_x(angle)
@@ -183,3 +173,9 @@ round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), ro
*/
/proc/rgb_construct_color_matrix(rr = 1, rg, rb, gr, gg = 1, gb, br, bg, bb = 1, cr, cg, cb)
return list(rr, rg, rb, gr, gg, gb, br, bg, bb, cr, cg, cb)
+
+/**
+ * Assembles a color matrix, defaulting to identity
+ */
+/proc/rgba_construct_color_matrix(rr = 1, rg, rb, ra, gr, gg = 1, gb, ga, br, bg, bb = 1, ba, ar, ag, ab, aa = 1, cr, cg, cb, ca)
+ return list(rr, rg, rb, ra, gr, gg, gb, ga, br, bg, bb, ba, ar, ag, ab, aa, cr, cg, cb, ca)
diff --git a/code/__HELPERS/matrices/transform_matrix.dm b/code/__HELPERS/matrices/transform_matrix.dm
new file mode 100644
index 0000000000..251ef8151f
--- /dev/null
+++ b/code/__HELPERS/matrices/transform_matrix.dm
@@ -0,0 +1,86 @@
+/matrix/proc/TurnTo(old_angle, new_angle)
+ . = 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 = 10, 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
+
+//Dumps the matrix data in format a-f
+/matrix/proc/tolist()
+ . = list()
+ . += a
+ . += b
+ . += c
+ . += d
+ . += e
+ . += f
+
+//Dumps the matrix data in a matrix-grid format
+/*
+ a d 0
+ b e 0
+ c f 1
+*/
+/matrix/proc/togrid()
+ . = list()
+ . += a
+ . += d
+ . += 0
+ . += b
+ . += e
+ . += 0
+ . += c
+ . += f
+ . += 1
+
+//The X pixel offset of this matrix
+/matrix/proc/get_x_shift()
+ . = c
+
+//The Y pixel offset of this matrix
+/matrix/proc/get_y_shift()
+ . = f
+
+/matrix/proc/get_x_skew()
+ . = b
+
+/matrix/proc/get_y_skew()
+ . = d
+
+//Skews a matrix in a particular direction
+//Missing arguments are treated as no skew in that direction
+
+//As Rotation is defined as a scale+skew, these procs will break any existing rotation
+//Unless the result is multiplied against the current matrix
+/matrix/proc/set_skew(x = 0, y = 0)
+ b = x
+ d = y
+
+/**
+ * constructs a transform matrix, defaulting to identity
+ */
+/proc/transform_matrix_construct(a = 1, b, c, d = 1, e, f)
+ return matrix(a, b, c, d, e, f)
diff --git a/code/__HELPERS/priority_announce.dm b/code/__HELPERS/priority_announce.dm
index 1aaebc5f32..1609c5f208 100644
--- a/code/__HELPERS/priority_announce.dm
+++ b/code/__HELPERS/priority_announce.dm
@@ -152,7 +152,7 @@
continue
to_chat(mob_to_teleport, announcement)
SEND_SOUND(mob_to_teleport, meeting_sound) //no preferences here, you must hear the funny sound
- mob_to_teleport.overlay_fullscreen("emergency_meeting", /atom/movable/screen/fullscreen/emergency_meeting, 1)
+ mob_to_teleport.overlay_fullscreen("emergency_meeting", /atom/movable/screen/fullscreen/scaled/emergency_meeting, 1)
addtimer(CALLBACK(mob_to_teleport, /mob/.proc/clear_fullscreen, "emergency_meeting"), 3 SECONDS)
if (is_station_level(mob_to_teleport.z)) //teleport the mob to the crew meeting
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 1b72cc71b1..773adc061f 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -470,51 +470,6 @@
else
setDir(WEST, ismousemovement)
-//debug
-/atom/movable/screen/proc/scale_to(x1,y1)
- if(!y1)
- y1 = x1
- var/matrix/M = new
- M.Scale(x1,y1)
- transform = M
-
-/atom/movable/screen/click_catcher
- icon = 'icons/mob/screen_gen.dmi'
- icon_state = "catcher"
- plane = CLICKCATCHER_PLANE
- mouse_opacity = MOUSE_OPACITY_OPAQUE
- screen_loc = "CENTER"
-
-#define MAX_SAFE_BYOND_ICON_SCALE_TILES (MAX_SAFE_BYOND_ICON_SCALE_PX / world.icon_size)
-#define MAX_SAFE_BYOND_ICON_SCALE_PX (33 * 32) //Not using world.icon_size on purpose.
-
-/atom/movable/screen/click_catcher/proc/UpdateGreed(view_size_x = 15, view_size_y = 15)
- var/icon/newicon = icon('icons/mob/screen_gen.dmi', "catcher")
- var/ox = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_x)
- var/oy = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_y)
- var/px = view_size_x * world.icon_size
- var/py = view_size_y * world.icon_size
- var/sx = min(MAX_SAFE_BYOND_ICON_SCALE_PX, px)
- var/sy = min(MAX_SAFE_BYOND_ICON_SCALE_PX, py)
- newicon.Scale(sx, sy)
- icon = newicon
- screen_loc = "CENTER-[(ox-1)*0.5],CENTER-[(oy-1)*0.5]"
- var/matrix/M = new
- M.Scale(px/sx, py/sy)
- transform = M
-
-/atom/movable/screen/click_catcher/Click(location, control, params)
- var/list/modifiers = params2list(params)
- if(modifiers["middle"] && iscarbon(usr))
- var/mob/living/carbon/C = usr
- C.swap_hand()
- else
- var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr.client ? usr.client.eye : usr), usr.client)
- params += "&catcher=1"
- if(T)
- T.Click(location, control, params)
- . = 1
-
/* MouseWheelOn */
/mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params)
diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm
deleted file mode 100644
index 81442b602f..0000000000
--- a/code/_onclick/hud/fullscreen.dm
+++ /dev/null
@@ -1,192 +0,0 @@
-/mob/proc/overlay_fullscreen(category, type, severity)
- var/atom/movable/screen/fullscreen/screen = screens[category]
- if (!screen || screen.type != type)
- // needs to be recreated
- clear_fullscreen(category, FALSE)
- screens[category] = screen = new type()
- else if ((!severity || severity == screen.severity) && (!client || screen.screen_loc != "CENTER-7,CENTER-7" || screen.view == client.view))
- // doesn't need to be updated
- return screen
-
- screen.icon_state = "[initial(screen.icon_state)][severity]"
- screen.severity = severity
- if (client && screen.should_show_to(src))
- screen.update_for_view(client.view)
- client.screen += screen
-
- return screen
-
-/mob/proc/clear_fullscreen(category, animated = 10)
- var/atom/movable/screen/fullscreen/screen = screens[category]
- if(!screen)
- return
-
- screens -= category
-
- if(animated)
- animate(screen, alpha = 0, time = animated)
- addtimer(CALLBACK(src, .proc/clear_fullscreen_after_animate, screen), animated, TIMER_CLIENT_TIME)
- else
- if(client)
- client.screen -= screen
- qdel(screen)
-
-/mob/proc/clear_fullscreen_after_animate(atom/movable/screen/fullscreen/screen)
- if(client)
- client.screen -= screen
- qdel(screen)
-
-/mob/proc/clear_fullscreens()
- for(var/category in screens)
- clear_fullscreen(category)
-
-/mob/proc/hide_fullscreens()
- if(client)
- for(var/category in screens)
- client.screen -= screens[category]
-
-/mob/proc/reload_fullscreen()
- if(client)
- var/atom/movable/screen/fullscreen/screen
- for(var/category in screens)
- screen = screens[category]
- if(screen.should_show_to(src))
- screen.update_for_view(client.view)
- client.screen |= screen
- else
- client.screen -= screen
-
-/atom/movable/screen/fullscreen
- icon = 'icons/mob/screen_full.dmi'
- icon_state = "default"
- screen_loc = "CENTER-7,CENTER-7"
- layer = FULLSCREEN_LAYER
- plane = FULLSCREEN_PLANE
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- var/view = 7
- var/severity = 0
- var/show_when_dead = FALSE
-
-/atom/movable/screen/fullscreen/proc/update_for_view(client_view)
- if (screen_loc == "CENTER-7,CENTER-7" && view != client_view)
- var/list/actualview = getviewsize(client_view)
- view = client_view
- transform = matrix(actualview[1]/FULLSCREEN_OVERLAY_RESOLUTION_X, 0, 0, 0, actualview[2]/FULLSCREEN_OVERLAY_RESOLUTION_Y, 0)
-
-/atom/movable/screen/fullscreen/proc/should_show_to(mob/mymob)
- if(!show_when_dead && mymob.stat == DEAD)
- return FALSE
- return TRUE
-
-/atom/movable/screen/fullscreen/Destroy()
- severity = 0
- . = ..()
-
-/atom/movable/screen/fullscreen/emergency_meeting
- icon_state = "emergency_meeting"
- show_when_dead = TRUE
- layer = CURSE_LAYER
- plane = SPLASHSCREEN_PLANE
-
-/atom/movable/screen/fullscreen/brute
- icon_state = "brutedamageoverlay"
- layer = UI_DAMAGE_LAYER
- plane = FULLSCREEN_PLANE
-
-/atom/movable/screen/fullscreen/oxy
- icon_state = "oxydamageoverlay"
- layer = UI_DAMAGE_LAYER
- plane = FULLSCREEN_PLANE
-
-/atom/movable/screen/fullscreen/crit
- icon_state = "passage"
- layer = CRIT_LAYER
- plane = FULLSCREEN_PLANE
-
-/atom/movable/screen/fullscreen/crit/vision
- icon_state = "oxydamageoverlay"
- layer = BLIND_LAYER
-
-/atom/movable/screen/fullscreen/blind
- icon_state = "blackimageoverlay"
- layer = BLIND_LAYER
- plane = FULLSCREEN_PLANE
-
-/atom/movable/screen/fullscreen/curse
- icon_state = "curse"
- layer = CURSE_LAYER
- plane = FULLSCREEN_PLANE
-
-/atom/movable/screen/fullscreen/impaired
- icon_state = "impairedoverlay"
-
-/atom/movable/screen/fullscreen/blurry
- icon = 'icons/mob/screen_gen.dmi'
- screen_loc = "WEST,SOUTH to EAST,NORTH"
- icon_state = "blurry"
-
-/atom/movable/screen/fullscreen/flash
- icon = 'icons/mob/screen_gen.dmi'
- screen_loc = "WEST,SOUTH to EAST,NORTH"
- icon_state = "flash"
-
-/atom/movable/screen/fullscreen/flash/static
- icon = 'icons/mob/screen_gen.dmi'
- screen_loc = "WEST,SOUTH to EAST,NORTH"
- icon_state = "noise"
-
-/atom/movable/screen/fullscreen/high
- icon = 'icons/mob/screen_gen.dmi'
- screen_loc = "WEST,SOUTH to EAST,NORTH"
- icon_state = "druggy"
-
-/atom/movable/screen/fullscreen/color_vision
- icon = 'icons/mob/screen_gen.dmi'
- screen_loc = "WEST,SOUTH to EAST,NORTH"
- icon_state = "flash"
- alpha = 80
-
-/atom/movable/screen/fullscreen/color_vision/green
- color = "#00ff00"
-
-/atom/movable/screen/fullscreen/color_vision/red
- color = "#ff0000"
-
-/atom/movable/screen/fullscreen/color_vision/blue
- color = "#0000ff"
-
-/atom/movable/screen/fullscreen/cinematic_backdrop
- icon = 'icons/mob/screen_gen.dmi'
- screen_loc = "WEST,SOUTH to EAST,NORTH"
- icon_state = "flash"
- plane = SPLASHSCREEN_PLANE
- layer = SPLASHSCREEN_LAYER - 1
- color = "#000000"
- show_when_dead = TRUE
-
-/atom/movable/screen/fullscreen/lighting_backdrop
- icon = 'icons/mob/screen_gen.dmi'
- icon_state = "flash"
- transform = matrix(200, 0, 0, 0, 200, 0)
- plane = LIGHTING_PLANE
- blend_mode = BLEND_OVERLAY
- show_when_dead = TRUE
-
-//Provides darkness to the back of the lighting plane
-/atom/movable/screen/fullscreen/lighting_backdrop/lit
- invisibility = INVISIBILITY_LIGHTING
- layer = BACKGROUND_LAYER+21
- color = "#000"
- show_when_dead = TRUE
-
-//Provides whiteness in case you don't see lights so everything is still visible
-/atom/movable/screen/fullscreen/lighting_backdrop/unlit
- layer = BACKGROUND_LAYER+20
- show_when_dead = TRUE
-
-/atom/movable/screen/fullscreen/see_through_darkness
- icon_state = "nightvision"
- plane = LIGHTING_PLANE
- layer = LIGHTING_LAYER
- blend_mode = BLEND_ADD
- show_when_dead = TRUE
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 144a38e728..c5f57d9b78 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -133,7 +133,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
return FALSE
screenmob.client.screen = list()
- screenmob.client.apply_clickcatcher()
+ screenmob.client.update_clickcatcher()
var/display_hud_version = version
if(!display_hud_version) //If 0 or blank, display the next hud version
@@ -193,8 +193,6 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
persistent_inventory_update(screenmob)
screenmob.update_action_buttons(1)
reorganize_alerts()
- screenmob.reload_fullscreen()
- update_parallax_pref(screenmob)
// ensure observers get an accurate and up-to-date view
if (!viewmob)
@@ -204,6 +202,8 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
else if (viewmob.hud_used)
viewmob.hud_used.plane_masters_update()
+ screenmob.reload_rendering()
+
return TRUE
/datum/hud/proc/plane_masters_update()
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 83b8d7be48..4fa2dd538a 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -174,7 +174,7 @@
/datum/hud/human/New(mob/living/carbon/human/owner)
..()
- owner.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/see_through_darkness)
+ owner.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/special/see_through_darkness)
var/widescreenlayout = FALSE //CIT CHANGE - adds support for different hud layouts depending on widescreen pref
if(owner.client && owner.client.prefs && owner.client.prefs.widescreenpref) //CIT CHANGE - ditto
diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm
deleted file mode 100755
index a98fec03c4..0000000000
--- a/code/_onclick/hud/parallax.dm
+++ /dev/null
@@ -1,322 +0,0 @@
-
-/datum/hud/proc/create_parallax(mob/viewmob)
- var/mob/screenmob = viewmob || mymob
- var/client/C = screenmob.client
- if (!apply_parallax_pref(viewmob)) //don't want shit computers to crash when specing someone with insane parallax, so use the viewer's pref
- return
-
- if(!length(C.parallax_layers_cached))
- C.parallax_layers_cached = list()
- C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_1(null, C.view)
- C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_2(null, C.view)
- C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/planet(null, C.view)
- if(SSparallax.random_layer)
- C.parallax_layers_cached += new SSparallax.random_layer
- C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_3(null, C.view)
-
- C.parallax_layers = C.parallax_layers_cached.Copy()
-
- if (length(C.parallax_layers) > C.parallax_layers_max)
- C.parallax_layers.len = C.parallax_layers_max
-
- C.screen |= (C.parallax_layers)
- var/atom/movable/screen/plane_master/PM = screenmob.hud_used.plane_masters["[PLANE_SPACE]"]
- if(screenmob != mymob)
- C.screen -= locate(/atom/movable/screen/plane_master/parallax_white) in C.screen
- C.screen += PM
- PM.color = list(
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 1, 1, 1, 1,
- 0, 0, 0, 0
- )
-
-
-/datum/hud/proc/remove_parallax(mob/viewmob)
- var/mob/screenmob = viewmob || mymob
- var/client/C = screenmob.client
- C.screen -= (C.parallax_layers_cached)
- var/atom/movable/screen/plane_master/PM = screenmob.hud_used.plane_masters["[PLANE_SPACE]"]
- if(screenmob != mymob)
- C.screen -= locate(/atom/movable/screen/plane_master/parallax_white) in C.screen
- C.screen += PM
- PM.color = initial(PM.color)
- C.parallax_layers = null
-
-/datum/hud/proc/apply_parallax_pref(mob/viewmob)
- var/mob/screenmob = viewmob || mymob
- var/client/C = screenmob.client
- if(C.prefs)
- var/pref = C.prefs.parallax
- if (isnull(pref))
- pref = PARALLAX_HIGH
- switch(C.prefs.parallax)
- if (PARALLAX_INSANE)
- C.parallax_throttle = FALSE
- C.parallax_layers_max = 5
- return TRUE
-
- if (PARALLAX_MED)
- C.parallax_throttle = PARALLAX_DELAY_MED
- C.parallax_layers_max = 3
- return TRUE
-
- if (PARALLAX_LOW)
- C.parallax_throttle = PARALLAX_DELAY_LOW
- C.parallax_layers_max = 1
- return TRUE
-
- if (PARALLAX_DISABLE)
- return FALSE
-
- //This is high parallax.
- C.parallax_throttle = PARALLAX_DELAY_DEFAULT
- C.parallax_layers_max = 4
- return TRUE
-
-/datum/hud/proc/update_parallax_pref(mob/viewmob)
- remove_parallax(viewmob)
- create_parallax(viewmob)
- update_parallax()
-
-// 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, skip_windups)
- . = FALSE
- var/client/C = mymob.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)
- if(NORTH)
- newtransform = matrix(1, 0, 0, 0, 1, 480)
- if(SOUTH)
- newtransform = matrix(1, 0, 0, 0, 1,-480)
- if(EAST)
- newtransform = 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
-
- C.parallax_movedir = new_parallax_movedir
- if (C.parallax_animate_timer)
- deltimer(C.parallax_animate_timer)
- var/datum/callback/CB = CALLBACK(src, .proc/update_parallax_motionblur, C, animatedir, new_parallax_movedir, newtransform)
- if(skip_windups)
- CB.InvokeAsync()
- else
- C.parallax_animate_timer = addtimer(CB, min(shortesttimer, PARALLAX_LOOP_TIME), TIMER_CLIENT_TIME|TIMER_STOPPABLE)
-
-
-/datum/hud/proc/update_parallax_motionblur(client/C, animatedir, new_parallax_movedir, matrix/newtransform)
- 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 = matrix(), time = T, loop = -1, flags = ANIMATION_END_NOW)
-
-/datum/hud/proc/update_parallax()
- var/client/C = mymob.client
- var/turf/posobj = get_turf(C.eye)
- if(!posobj)
- return
- var/area/areaobj = posobj.loc
-
- // Update the movement direction of the parallax if necessary (for shuttles)
- set_parallax_movedir(areaobj.parallax_movedir, FALSE)
-
- var/force
- if(!C.previous_turf || (C.previous_turf.z != posobj.z))
- C.previous_turf = posobj
- force = TRUE
-
- if (!force && world.time < C.last_parallax_shift+C.parallax_throttle)
- return
-
- //Doing it this way prevents parallax layers from "jumping" when you change Z-Levels.
- var/offset_x = posobj.x - C.previous_turf.x
- var/offset_y = posobj.y - C.previous_turf.y
-
- if(!offset_x && !offset_y && !force)
- return
-
- var/last_delay = world.time - C.last_parallax_shift
- last_delay = min(last_delay, C.parallax_throttle)
- C.previous_turf = posobj
- C.last_parallax_shift = world.time
-
- for(var/thing in C.parallax_layers)
- var/atom/movable/screen/parallax_layer/L = thing
- L.update_status(mymob)
- if (L.view_sized != C.view)
- L.update_o(C.view)
-
- var/change_x
- var/change_y
-
- if(L.absolute)
- L.offset_x = -(posobj.x - SSparallax.planet_x_offset) * L.speed
- L.offset_y = -(posobj.y - SSparallax.planet_y_offset) * L.speed
- else
- change_x = offset_x * L.speed
- L.offset_x -= change_x
- change_y = offset_y * L.speed
- L.offset_y -= change_y
-
- if(L.offset_x > 240)
- L.offset_x -= 480
- if(L.offset_x < -240)
- L.offset_x += 480
- if(L.offset_y > 240)
- L.offset_y -= 480
- if(L.offset_y < -240)
- L.offset_y += 480
-
-
- if(!areaobj.parallax_movedir && C.dont_animate_parallax <= world.time && (offset_x || offset_y) && abs(offset_x) <= max(C.parallax_throttle/world.tick_lag+1,1) && abs(offset_y) <= max(C.parallax_throttle/world.tick_lag+1,1) && (round(abs(change_x)) > 1 || round(abs(change_y)) > 1))
- L.transform = matrix(1, 0, offset_x*L.speed, 0, 1, offset_y*L.speed)
- animate(L, transform=matrix(), time = last_delay)
-
- L.screen_loc = "CENTER-7:[round(L.offset_x,1)],CENTER-7:[round(L.offset_y,1)]"
-
-/atom/movable/proc/update_parallax_contents()
- if(length(client_mobs_in_contents))
- for(var/thing in client_mobs_in_contents)
- var/mob/M = thing
- if(M?.client && M.hud_used && length(M.client.parallax_layers))
- M.hud_used.update_parallax()
-
-/mob/proc/update_parallax_teleport() //used for arrivals shuttle
- if(client?.eye && hud_used && length(client.parallax_layers))
- var/area/areaobj = get_area(client.eye)
- hud_used.set_parallax_movedir(areaobj.parallax_movedir, TRUE)
-
-/atom/movable/screen/parallax_layer
- icon = 'icons/effects/parallax.dmi'
- var/speed = 1
- var/offset_x = 0
- var/offset_y = 0
- var/view_sized
- var/absolute = FALSE
- 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, view)
- . = ..()
- if (!view)
- view = world.view
- update_o(view)
-
-/atom/movable/screen/parallax_layer/proc/update_o(view)
- if (!view)
- view = world.view
-
- var/list/viewscales = getviewsize(view)
- var/countx = CEILING((viewscales[1]/2)/(480/world.icon_size), 1)+1
- var/county = CEILING((viewscales[2]/2)/(480/world.icon_size), 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)
- new_overlays += texture_overlay
- cut_overlays()
- add_overlay(new_overlays)
- view_sized = view
-
-/atom/movable/screen/parallax_layer/proc/update_status(mob/M)
- return
-
-/atom/movable/screen/parallax_layer/layer_1
- icon_state = "layer1"
- speed = 0.6
- layer = 1
-
-/atom/movable/screen/parallax_layer/layer_2
- icon_state = "layer2"
- speed = 1
- layer = 2
-
-/atom/movable/screen/parallax_layer/layer_3
- icon_state = "layer3"
- speed = 1.4
- layer = 3
-
-/atom/movable/screen/parallax_layer/random
- blend_mode = BLEND_OVERLAY
- speed = 3
- layer = 3
-
-/atom/movable/screen/parallax_layer/random/space_gas
- icon_state = "space_gas"
-
-/atom/movable/screen/parallax_layer/random/space_gas/Initialize(mapload, view)
- . = ..()
- src.add_atom_colour(SSparallax.random_parallax_color, ADMIN_COLOUR_PRIORITY)
-
-/atom/movable/screen/parallax_layer/random/asteroids
- icon_state = "asteroids"
-
-/atom/movable/screen/parallax_layer/planet
- icon_state = "planet"
- blend_mode = BLEND_OVERLAY
- absolute = TRUE //Status of seperation
- speed = 3
- layer = 30
-
-/atom/movable/screen/parallax_layer/planet/update_status(mob/M)
- var/client/C = M.client
- var/turf/posobj = get_turf(C.eye)
- if(!posobj)
- return
- invisibility = is_station_level(posobj.z) ? 0 : INVISIBILITY_ABSTRACT
-
-/atom/movable/screen/parallax_layer/planet/update_o()
- return //Shit won't move
diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm
index bb6a9cd925..d83a81fa45 100644
--- a/code/_onclick/hud/plane_master.dm
+++ b/code/_onclick/hud/plane_master.dm
@@ -124,8 +124,8 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/atom/movable/screen/plane_master/lighting/backdrop(mob/mymob)
- mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/lighting_backdrop/lit)
- mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/lighting_backdrop/unlit)
+ mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/special/lighting_backdrop/lit)
+ mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/special/lighting_backdrop/unlit)
/*!
* This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.
@@ -143,7 +143,6 @@
add_filter("emissives", 1, alpha_mask_filter(render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE))
add_filter("object_lighting", 2, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE))
-
/**
* Handles emissive overlays and emissive blockers.
*/
@@ -163,9 +162,10 @@
plane = PLANE_SPACE_PARALLAX
blend_mode = BLEND_MULTIPLY
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ render_target = PLANE_SPACE_PARALLAX_RENDER_TARGET
/atom/movable/screen/plane_master/parallax_white
- name = "parallax whitifier plane master"
+ name = "parallax backdrop/space turf plane master"
plane = PLANE_SPACE
/atom/movable/screen/plane_master/camera_static
@@ -174,7 +174,6 @@
appearance_flags = PLANE_MASTER
blend_mode = BLEND_OVERLAY
-
//Reserved to chat messages, so they are still displayed above the field of vision masking.
/atom/movable/screen/plane_master/chat_messages
name = "runechat plane master"
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index d431e6d3cd..78fc32480f 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -11,7 +11,6 @@
// Otherwise jump
else if(A.loc)
forceMove(get_turf(A))
- update_parallax_contents()
/mob/dead/observer/ClickOn(var/atom/A, var/params)
if(check_click_intercept(params,A))
diff --git a/code/game/alternate_appearance.dm b/code/_rendering/atom_huds/alternate_appearance.dm
similarity index 100%
rename from code/game/alternate_appearance.dm
rename to code/_rendering/atom_huds/alternate_appearance.dm
diff --git a/code/datums/hud.dm b/code/_rendering/atom_huds/atom_hud.dm
similarity index 97%
rename from code/datums/hud.dm
rename to code/_rendering/atom_huds/atom_hud.dm
index 1c23d5f2a0..07b403284b 100644
--- a/code/datums/hud.dm
+++ b/code/_rendering/atom_huds/atom_hud.dm
@@ -124,9 +124,3 @@ GLOBAL_LIST_INIT(huds, list(
/mob/dead/new_player/reload_huds()
return
-
-/mob/proc/add_click_catcher()
- client.screen += client.void
-
-/mob/dead/new_player/add_click_catcher()
- return
diff --git a/code/game/data_huds.dm b/code/_rendering/atom_huds/data_huds.dm
similarity index 100%
rename from code/game/data_huds.dm
rename to code/_rendering/atom_huds/data_huds.dm
diff --git a/code/_rendering/clickcatcher/clickcatcher.dm b/code/_rendering/clickcatcher/clickcatcher.dm
new file mode 100644
index 0000000000..524f753e98
--- /dev/null
+++ b/code/_rendering/clickcatcher/clickcatcher.dm
@@ -0,0 +1,74 @@
+/atom/movable/screen/click_catcher
+ icon = 'icons/screen/clickcatcher.dmi'
+ icon_state = "catcher"
+ appearance_flags = TILE_BOUND | NO_CLIENT_COLOR | RESET_TRANSFORM | RESET_COLOR | RESET_ALPHA
+ plane = CLICKCATCHER_PLANE
+ plane = CLICKCATCHER_PLANE
+ mouse_opacity = MOUSE_OPACITY_OPAQUE
+ screen_loc = "CENTER"
+
+/*
+#define MAX_SAFE_BYOND_ICON_SCALE_TILES (MAX_SAFE_BYOND_ICON_SCALE_PX / world.icon_size)
+#define MAX_SAFE_BYOND_ICON_SCALE_PX (33 * 32) //Not using world.icon_size on purpose.
+
+/atom/movable/screen/click_catcher/proc/UpdateFill(view_size_x = 15, view_size_y = 15)
+ var/icon/newicon = icon('icons/mob/screen_gen.dmi', "catcher")
+ var/ox = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_x)
+ var/oy = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_y)
+ var/px = view_size_x * world.icon_size
+ var/py = view_size_y * world.icon_size
+ var/sx = min(MAX_SAFE_BYOND_ICON_SCALE_PX, px)
+ var/sy = min(MAX_SAFE_BYOND_ICON_SCALE_PX, py)
+ newicon.Scale(sx, sy)
+ icon = newicon
+ screen_loc = "CENTER-[(ox-1)*0.5],CENTER-[(oy-1)*0.5]"
+ var/matrix/M = new
+ M.Scale(px/sx, py/sy)
+ transform = M
+
+#undef MAX_SAFE_BYOND_ICON_SCALE_TILES
+#undef MAX_SAFE_BYOND_ICON_SCALE_PX
+*/
+
+/atom/movable/screen/click_catcher/proc/UpdateFill(view_size_x, view_size_y)
+ screen_loc = "1,1 to [view_size_x],[view_size_y]"
+
+/atom/movable/screen/click_catcher/Click(location, control, params)
+ var/list/modifiers = params2list(params)
+ if(modifiers["middle"] && iscarbon(usr))
+ var/mob/living/carbon/C = usr
+ C.swap_hand()
+ else
+ var/turf/T = Parse(modifiers["screen-loc"], get_turf(usr.client?.eye || usr), usr.client)
+ params += "&catcher=1"
+ if(T)
+ T.Click(location, control, params)
+ return TRUE
+
+/atom/movable/screen/click_catcher/proc/Parse(scr_loc, turf/origin, client/C)
+ // screen-loc: Pixel coordinates in screen_loc format ("[tile_x]:[pixel_x],[tile_y]:[pixel_y]")
+ if(!scr_loc)
+ return null
+ var/tX = splittext(scr_loc, ",")
+ var/tY = splittext(tX[2], ":")
+ var/tZ = origin.z
+ tY = tY[1]
+ tX = splittext(tX[1], ":")
+ tX = tX[1]
+ var/list/actual_view = getviewsize(C ? C.view : world.view)
+ tX = clamp(origin.x + text2num(tX) - round(actual_view[1] / 2) - 1, 1, world.maxx)
+ tY = clamp(origin.y + text2num(tY) - round(actual_view[2] / 2) - 1, 1, world.maxy)
+ return locate(tX, tY, tZ)
+
+/**
+ * Makes a clickcatcher if necessary, and ensures it's fit to our size.
+ */
+/client/proc/update_clickcatcher(list/view_override)
+ if(!click_catcher)
+ click_catcher = new
+ screen |= click_catcher
+ if(view_override)
+ click_catcher.UpdateFill(view_override[1], view_override[2])
+ else
+ var/list/view_list = getviewsize(view)
+ click_catcher.UpdateFill(view_list[1], view_list[2])
diff --git a/code/_rendering/fullscreen/fullscreen.dm b/code/_rendering/fullscreen/fullscreen.dm
new file mode 100644
index 0000000000..dd8f697891
--- /dev/null
+++ b/code/_rendering/fullscreen/fullscreen.dm
@@ -0,0 +1,234 @@
+/**
+ * Adds a fullscreen overlay
+ *
+ * @params
+ * - category - string - must exist. will overwrite any other screen in this category. defaults to type.
+ * - type - the typepath of the screen
+ * - severity - severity - different screen objects have differing severities
+ */
+/mob/proc/overlay_fullscreen(category, type, severity)
+ ASSERT(type)
+ if(!category)
+ category = type
+ var/atom/movable/screen/fullscreen/screen = fullscreens[category]
+ if (!screen || screen.type != type)
+ // needs to be recreated
+ clear_fullscreen(category, 0)
+ fullscreens[category] = screen = new type
+ screen.SetSeverity(severity)
+ if(client && screen.ShouldShow(src))
+ screen.SetView(client.view)
+ client.screen += screen
+ return screen
+
+/**
+ * Wipes a fullscreen of a certain category
+ *
+ * Second argument is for animation delay.
+ */
+/mob/proc/clear_fullscreen(category, animated = 10)
+ if(!fullscreens)
+ return
+ var/atom/movable/screen/fullscreen/screen = fullscreens[category]
+ fullscreens -= category
+ if(!screen)
+ return
+ if(animated > 0)
+ animate(screen, alpha = 0, time = animated)
+ addtimer(CALLBACK(src, .proc/_remove_fullscreen_direct, screen), animated, TIMER_CLIENT_TIME)
+ else
+ if(client)
+ client.screen -= screen
+ qdel(screen)
+
+/mob/proc/_remove_fullscreen_direct(atom/movable/screen/fullscreen/screen)
+ if(client)
+ client.screen -= screen
+ qdel(screen)
+
+/**
+ * Wipes all fullscreens
+ */
+/mob/proc/wipe_fullscreens()
+ for(var/category in fullscreens)
+ clear_fullscreen(category)
+
+/**
+ * Removes fullscreens from client but not the mob
+ */
+/mob/proc/hide_fullscreens()
+ if(client)
+ for(var/category in fullscreens)
+ client.screen -= fullscreens[category]
+
+/**
+ * Ensures all fullscreens are on client.
+ */
+/mob/proc/reload_fullscreen()
+ if(client)
+ var/atom/movable/screen/fullscreen/screen
+ for(var/category in fullscreens)
+ screen = fullscreens[category]
+ if(screen.ShouldShow(src))
+ screen.SetView(client.view)
+ client.screen |= screen
+ else
+ client.screen -= screen
+
+/atom/movable/screen/fullscreen
+ icon = 'icons/screen/fullscreen_15x15.dmi'
+ icon_state = "default"
+ screen_loc = "CENTER-7,CENTER-7"
+ layer = FULLSCREEN_LAYER
+ plane = FULLSCREEN_PLANE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ /// current view we're adapted to
+ var/view_current
+ /// min severity
+ var/severity_min = 0
+ /// max severity
+ var/severity_max = INFINITY
+ /// current severity
+ var/severity = 0
+ /// show this while dead
+ var/show_when_dead = FALSE
+
+/atom/movable/screen/fullscreen/proc/SetSeverity(severity)
+ src.severity = clamp(severity, severity_min, severity_max)
+ icon_state = "[initial(icon_state)][severity]"
+
+/atom/movable/screen/fullscreen/proc/SetView(client_view)
+ view_current = client_view
+
+/atom/movable/screen/fullscreen/proc/ShouldShow(mob/M)
+ if(!show_when_dead && M.stat == DEAD)
+ return FALSE
+ return TRUE
+
+/atom/movable/screen/fullscreen/Destroy()
+ SetSeverity(0)
+ return ..()
+
+/atom/movable/screen/fullscreen/scaled
+ icon = 'icons/screen/fullscreen_15x15.dmi'
+ screen_loc = "CENTER-7,CENTER-7"
+ /// size of sprite in tiles
+ var/size_x = 15
+ /// size of sprite in tiles
+ var/size_y = 15
+
+/atom/movable/screen/fullscreen/scaled/SetView(client_view)
+ if(view_current != client_view)
+ var/list/actualview = getviewsize(client_view)
+ view_current = client_view
+ transform = matrix(actualview[1] / size_x, 0, 0, 0, actualview[2] / size_y, 0)
+ return ..()
+
+/atom/movable/screen/fullscreen/scaled/brute
+ icon_state = "brutedamageoverlay"
+ layer = UI_DAMAGE_LAYER
+ plane = FULLSCREEN_PLANE
+
+/atom/movable/screen/fullscreen/scaled/oxy
+ icon_state = "oxydamageoverlay"
+ layer = UI_DAMAGE_LAYER
+ plane = FULLSCREEN_PLANE
+
+/atom/movable/screen/fullscreen/scaled/crit
+ icon_state = "passage"
+ layer = CRIT_LAYER
+ plane = FULLSCREEN_PLANE
+
+/atom/movable/screen/fullscreen/scaled/crit/vision
+ icon_state = "oxydamageoverlay"
+ layer = BLIND_LAYER
+
+/atom/movable/screen/fullscreen/scaled/blind
+ icon_state = "blackimageoverlay"
+ layer = BLIND_LAYER
+ plane = FULLSCREEN_PLANE
+
+/atom/movable/screen/fullscreen/scaled/curse
+ icon_state = "curse"
+ layer = CURSE_LAYER
+ plane = FULLSCREEN_PLANE
+
+/atom/movable/screen/fullscreen/scaled/impaired
+ icon_state = "impairedoverlay"
+
+/atom/movable/screen/fullscreen/scaled/emergency_meeting
+ icon_state = "emergency_meeting"
+ show_when_dead = TRUE
+ layer = CURSE_LAYER
+ plane = SPLASHSCREEN_PLANE
+
+/atom/movable/screen/fullscreen/tiled/blurry
+ icon = 'icons/mob/screen_gen.dmi'
+ screen_loc = "WEST,SOUTH to EAST,NORTH"
+ icon_state = "cloudy"
+
+/atom/movable/screen/fullscreen/tiled/flash
+ icon = 'icons/mob/screen_gen.dmi'
+ screen_loc = "WEST,SOUTH to EAST,NORTH"
+ icon_state = "flash"
+
+/atom/movable/screen/fullscreen/tiled/flash/static
+ icon = 'icons/mob/screen_gen.dmi'
+ screen_loc = "WEST,SOUTH to EAST,NORTH"
+ icon_state = "noise"
+
+/atom/movable/screen/fullscreen/tiled/high
+ icon = 'icons/mob/screen_gen.dmi'
+ screen_loc = "WEST,SOUTH to EAST,NORTH"
+ icon_state = "druggy"
+
+/atom/movable/screen/fullscreen/tiled/color_vision
+ icon = 'icons/mob/screen_gen.dmi'
+ screen_loc = "WEST,SOUTH to EAST,NORTH"
+ icon_state = "flash"
+ alpha = 80
+
+/atom/movable/screen/fullscreen/tiled/color_vision/green
+ color = "#00ff00"
+
+/atom/movable/screen/fullscreen/tiled/color_vision/red
+ color = "#ff0000"
+
+/atom/movable/screen/fullscreen/tiled/color_vision/blue
+ color = "#0000ff"
+
+/atom/movable/screen/fullscreen/tiled/cinematic_backdrop
+ icon = 'icons/mob/screen_gen.dmi'
+ screen_loc = "WEST,SOUTH to EAST,NORTH"
+ icon_state = "flash"
+ plane = SPLASHSCREEN_PLANE
+ layer = SPLASHSCREEN_LAYER - 1
+ color = "#000000"
+ show_when_dead = TRUE
+
+/atom/movable/screen/fullscreen/special/lighting_backdrop
+ icon = 'icons/mob/screen_gen.dmi'
+ icon_state = "flash"
+ transform = matrix(200, 0, 0, 0, 200, 0)
+ plane = LIGHTING_PLANE
+ blend_mode = BLEND_OVERLAY
+ show_when_dead = TRUE
+
+//Provides darkness to the back of the lighting plane
+/atom/movable/screen/fullscreen/special/lighting_backdrop/lit
+ invisibility = INVISIBILITY_LIGHTING
+ layer = BACKGROUND_LAYER+21
+ color = "#000"
+ show_when_dead = TRUE
+
+//Provides whiteness in case you don't see lights so everything is still visible
+/atom/movable/screen/fullscreen/special/lighting_backdrop/unlit
+ layer = BACKGROUND_LAYER+20
+ show_when_dead = TRUE
+
+/atom/movable/screen/fullscreen/special/see_through_darkness
+ icon_state = "nightvision"
+ plane = LIGHTING_PLANE
+ layer = LIGHTING_LAYER
+ blend_mode = BLEND_ADD
+ show_when_dead = TRUE
diff --git a/code/_rendering/mob.dm b/code/_rendering/mob.dm
new file mode 100644
index 0000000000..49095d0910
--- /dev/null
+++ b/code/_rendering/mob.dm
@@ -0,0 +1,21 @@
+/**
+ * initializes screen rendering. call on mob new
+ */
+/mob/proc/init_rendering()
+
+/**
+ * loads screen rendering. call on mob login
+ */
+/mob/proc/reload_rendering()
+ if(!client.parallax_holder)
+ client.CreateParallax()
+ else
+ client.parallax_holder.Reset(force = TRUE)
+ client.update_clickcatcher()
+ reload_fullscreen()
+
+/**
+ * destroys screen rendering. call on mob del
+ */
+/mob/proc/dispose_rendering()
+ wipe_fullscreens()
diff --git a/code/_rendering/parallax/parallax.dm b/code/_rendering/parallax/parallax.dm
new file mode 100644
index 0000000000..dbd27ae762
--- /dev/null
+++ b/code/_rendering/parallax/parallax.dm
@@ -0,0 +1,28 @@
+/**
+ * Holds parallax information.
+ */
+/datum/parallax
+ /// List of parallax objects - these are cloned to a parallax holder using Clone on each.
+ var/list/atom/movable/screen/parallax_layer/objects
+ /// Parallax layers
+ var/layers = 0
+
+/datum/parallax/New(create_objects = TRUE)
+ if(create_objects)
+ objects = CreateObjects()
+ layers = objects.len
+
+/datum/parallax/Destroy()
+ QDEL_LIST(objects)
+ return ..()
+
+/**
+ * Gets a new version of the objects inside - used when applying to a holder.
+ */
+/datum/parallax/proc/GetObjects()
+ . = list()
+ for(var/atom/movable/screen/parallax_layer/layer in objects)
+ . += layer.Clone()
+
+/datum/parallax/proc/CreateObjects()
+ . = objects = list()
diff --git a/code/_rendering/parallax/parallax_holder.dm b/code/_rendering/parallax/parallax_holder.dm
new file mode 100644
index 0000000000..8a9e4b71a9
--- /dev/null
+++ b/code/_rendering/parallax/parallax_holder.dm
@@ -0,0 +1,311 @@
+/**
+ * # Parallax holders
+ *
+ * Holds all the information about a client's parallax
+ *
+ * Not on mob because parallax is area based, not mob based.
+ *
+ * How parallax works:
+ * - Layers - normal layers, scroll with movement to relative position, can scroll
+ * - Absolute - absolute layers, scroll with movement to absolute position, cannot scroll
+ * - Vis - vis_contents-like model - things in this are directly applied and get no processing whatsoever. Things like overmap ships can use this.
+ */
+/datum/parallax_holder
+ /// Client that owns us
+ var/client/owner
+ /// The parallax object we're currently rendering
+ var/datum/parallax/parallax
+ /// Eye we were last anchored to - used to detect eye changes
+ var/atom/cached_eye
+ /// force this eye as the "real" eye - useful for secondary maps
+ var/atom/forced_eye
+ /// last turf loc
+ var/turf/last
+ /// last area - for parallax scrolling/loop animations
+ var/area/last_area
+ /// Holder object for vis
+ var/atom/movable/screen/parallax_vis/vis_holder
+ /// are we not on the main map? if so, put map id here
+ var/secondary_map
+ /// all layers
+ var/list/atom/movable/screen/parallax_layer/layers
+ /// vis contents
+ var/list/atom/movable/vis
+ /// currently scrolling?
+ var/scrolling = FALSE
+ /// current scroll speed in DS per scroll
+ var/scroll_speed
+ /// current scroll turn - applied after angle. if angle is 0 (picture moving north) and turn is 90, it would be like if you turned your viewport 90 deg clockwise.
+ var/scroll_turn
+ /// override planemaster we manipulate for turning and other effects
+ var/atom/movable/screen/plane_master/parallax/planemaster_override
+
+/datum/parallax_holder/New(client/C, secondary_map, forced_eye, planemaster_override)
+ owner = C
+ if(!owner)
+ CRASH("No client")
+ src.secondary_map = secondary_map
+ src.forced_eye = forced_eye
+ src.planemaster_override = planemaster_override
+ Reset()
+
+/datum/parallax_holder/Destroy()
+ if(owner)
+ if(owner.parallax_holder == src)
+ owner.parallax_holder = null
+ Remove()
+ HardResetAnimations()
+ QDEL_NULL(vis_holder)
+ QDEL_NULL(parallax)
+ layers = null
+ vis = null
+ last = null
+ forced_eye = cached_eye = null
+ owner = null
+ return ..()
+
+/datum/parallax_holder/proc/Reset(auto_z_change, force)
+ if(!(cached_eye = Eye()))
+ // if no eye, tear down
+ last = cached_eye = last_area = null
+ SetParallax(null, null, auto_z_change)
+ return
+ // first, check loc
+ var/turf/T = get_turf(cached_eye)
+ if(!T)
+ // if in nullspace, tear down
+ last = cached_eye = last_area = null
+ SetParallax(null, null, auto_z_change)
+ return
+ // set last loc and eye
+ last = T
+ last_area = T.loc
+ // rebuild parallax
+ SetParallax(SSparallax.get_parallax_datum(T.z), null, auto_z_change, force)
+ // hard reset positions to correct positions
+ for(var/atom/movable/screen/parallax_layer/L in layers)
+ L.ResetPosition(T.x, T.y)
+
+// better updates via client_mobs_in_contents can be created again when important recursive contents is ported!
+/datum/parallax_holder/proc/Update(full)
+ if(!full && !cached_eye || (get_turf(cached_eye) == last))
+ return
+ if(!owner) // why are we here
+ if(!QDELETED(src))
+ qdel(src)
+ return
+ if(cached_eye != Eye())
+ // eye mismatch, reset
+ Reset()
+ return
+ var/turf/T = get_turf(cached_eye)
+ if(!last || T.z != last.z)
+ // z mismatch, reset
+ Reset()
+ return
+ // get rel offsets
+ var/rel_x = T.x - last.x
+ var/rel_y = T.y - last.y
+ // set last
+ last = T
+ // move
+ for(var/atom/movable/screen/parallax_layer/L in layers)
+ L.RelativePosition(T.x, T.y, rel_x, rel_y)
+ // process scrolling/movedir
+ if(last_area != T.loc)
+ last_area = T.loc
+ UpdateMotion()
+
+/**
+ * Gets the eye we should be centered on
+ */
+/datum/parallax_holder/proc/Eye()
+ return forced_eye || owner?.eye
+
+/**
+ * Gets the base parallax planemaster for things like turning
+ */
+/datum/parallax_holder/proc/GetPlaneMaster()
+ return planemaster_override || (owner && (locate(/atom/movable/screen/plane_master/parallax) in owner?.screen))
+
+/**
+ * Syncs us to our parallax objects. Does NOT check if we should have those objects, that's Reset()'s job.
+ *
+ * Doesn't move/update positions/screen locs either.
+ *
+ * Also ensures movedirs are correct for the eye's pos.
+ */
+/datum/parallax_holder/proc/Sync(auto_z_change, force)
+ layers = list()
+ for(var/atom/movable/screen/parallax_layer/L in parallax.objects)
+ layers += L
+ L.map_id = secondary_map
+ if(!istype(vis_holder))
+ vis_holder = new /atom/movable/screen/parallax_vis
+ var/turf/T = get_turf(cached_eye)
+ vis_holder.vis_contents = vis = T? SSparallax.get_parallax_vis_contents(T.z) : list()
+ UpdateMotion(auto_z_change, force)
+
+/**
+ * Updates motion if needed
+ */
+/datum/parallax_holder/proc/UpdateMotion(auto_z_change, force)
+ var/turf/T = get_turf(cached_eye)
+ if(!T)
+ if(scroll_speed || scroll_turn)
+ HardResetAnimations()
+ return
+ var/list/ret = SSparallax.get_parallax_motion(T.z)
+ if(ret)
+ Animation(ret[1], ret[2], auto_z_change? 0 : ret[3], auto_z_change? 0 : ret[4], force)
+ else
+ var/area/A = T.loc
+ Animation(A.parallax_move_speed, A.parallax_move_angle, auto_z_change? 0 : null, auto_z_change? 0 : null, force)
+
+/datum/parallax_holder/proc/Apply(client/C = owner)
+ if(QDELETED(C))
+ return
+ . = list()
+ for(var/atom/movable/screen/parallax_layer/L in layers)
+ if(L.parallax_intensity > owner.prefs.parallax)
+ continue
+ if(!L.ShouldSee(C, last))
+ continue
+ L.SetView(C.view, TRUE)
+ . |= L
+ C.screen |= .
+ if(!secondary_map)
+ var/atom/movable/screen/plane_master/parallax_white/PM = locate() in C.screen
+ if(PM)
+ PM.color = list(
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 0, 0, 0, 0
+ )
+
+/datum/parallax_holder/proc/Remove(client/C = owner)
+ if(QDELETED(C))
+ return
+ C.screen -= layers
+ if(!secondary_map)
+ var/atom/movable/screen/plane_master/parallax_white/PM = locate() in C.screen
+ if(PM)
+ PM.color = initial(PM.color)
+
+/datum/parallax_holder/proc/SetParallaxType(path)
+ if(!ispath(path, /datum/parallax))
+ CRASH("Invalid path")
+ SetParallax(new path)
+
+/datum/parallax_holder/proc/SetParallax(datum/parallax/P, delete_old = TRUE, auto_z_change, force)
+ if(P == parallax)
+ return
+ Remove()
+ if(delete_old && istype(parallax) && !QDELETED(parallax))
+ qdel(parallax)
+ HardResetAnimations()
+ parallax = P
+ if(!parallax)
+ return
+ Sync(auto_z_change, force)
+ Apply()
+
+/**
+ * Runs a modifier to parallax as an animation.
+ *
+ * @params
+ * speed - ds per loop
+ * turn - angle clockwise from north to turn the motion to
+ * windup - ds to spend on windups. 0 for immediate.
+ * turn_speed - ds to spend on turning. 0 for immediate.
+ */
+/datum/parallax_holder/proc/Animation(speed = 25, turn = 0, windup = speed, turn_speed = speed, force)
+ // Parallax doesn't currently use this method of rotating.
+
+ // #if !PARALLAX_ROTATION_ANIMATIONS
+ // turn_speed = 0
+ // #endif
+
+ if(speed == 0)
+ StopScrolling(turn = turn, time = windup)
+ return
+ // if(turn != scroll_turn && GetPlaneMaster())
+ // // first handle turn. we turn the planemaster
+ // var/matrix/turn_transform = matrix()
+ // turn_transform.Turn(turn)
+ // scroll_turn = turn
+ // animate(GetPlaneMaster(), transform = turn_transform, time = turn_speed, easing = QUAD_EASING | EASE_IN, flags = ANIMATION_END_NOW | ANIMATION_LINEAR_TRANSFORM)
+ if(scroll_speed == speed && !force)
+ // we're done
+ return
+ // speed diff?
+ scroll_speed = speed
+ scrolling = TRUE
+ // always scroll from north; turn handles everything
+ for(var/atom/movable/screen/parallax_layer/P in layers)
+ if(P.absolute)
+ continue
+ var/matrix/translate_matrix = matrix()
+ translate_matrix.Translate(cos(turn) * 480, sin(turn) * 480)
+ var/matrix/target_matrix = matrix()
+ var/move_speed = speed * P.speed
+ // do the first segment by shifting down one screen
+ P.transform = translate_matrix
+ animate(P, transform = target_matrix, time = move_speed, easing = QUAD_EASING|EASE_IN, flags = ANIMATION_END_NOW)
+ // queue up another incase lag makes QueueLoop not fire on time, this time by shifting up
+ animate(transform = translate_matrix, time = 0)
+ animate(transform = target_matrix, time = move_speed)
+ P.QueueLoop(move_speed, speed * P.speed, translate_matrix, target_matrix)
+
+/**
+ * Smoothly stops the animation, turning to a certain angle as needed.
+ */
+/datum/parallax_holder/proc/StopScrolling(turn = 0, time = 30)
+ // reset turn
+ if(turn != scroll_turn && GetPlaneMaster())
+ var/matrix/turn_transform = matrix()
+ turn_transform.Turn(turn)
+ scroll_turn = turn
+ animate(GetPlaneMaster(), transform = turn_transform, time = time, easing = QUAD_EASING | EASE_OUT, flags = ANIMATION_END_NOW | ANIMATION_LINEAR_TRANSFORM)
+ if(scroll_speed == 0)
+ // we're done
+ scrolling = FALSE
+ scroll_speed = 0
+ return
+ scrolling = FALSE
+ scroll_speed = 0
+ // someone can do the math for "stop after a smooth iteration" later.
+ for(var/atom/movable/screen/parallax_layer/P in layers)
+ if(P.absolute)
+ continue
+ P.CancelAnimation()
+ var/matrix/translate_matrix = matrix()
+ translate_matrix.Translate(cos(turn) * 480, sin(turn) * 480)
+ P.transform = translate_matrix
+ animate(P, transform = matrix(), time = time, easing = QUAD_EASING | EASE_OUT)
+
+/**
+ * fully resets animation state
+ */
+/datum/parallax_holder/proc/HardResetAnimations()
+ // reset vars
+ scroll_turn = 0
+ scroll_speed = 0
+ scrolling = FALSE
+ // reset turn
+ if(GetPlaneMaster())
+ animate(GetPlaneMaster(), transform = matrix(), time = 0, flags = ANIMATION_END_NOW)
+ // reset objects
+ for(var/atom/movable/screen/parallax_layer/P in layers)
+ if(P.absolute)
+ continue
+ P.CancelAnimation()
+ animate(P, transform = matrix(), time = 0, flags = ANIMATION_END_NOW)
+
+/client/proc/CreateParallax()
+ if(!parallax_holder)
+ parallax_holder = new(src)
+/atom/movable/screen/parallax_vis
+ screen_loc = "CENTER,CENTER"
diff --git a/code/_rendering/parallax/parallax_object.dm b/code/_rendering/parallax/parallax_object.dm
new file mode 100644
index 0000000000..8307fc5f08
--- /dev/null
+++ b/code/_rendering/parallax/parallax_object.dm
@@ -0,0 +1,137 @@
+
+/atom/movable/screen/parallax_layer
+ icon = 'icons/screen/parallax.dmi'
+ blend_mode = BLEND_ADD
+ plane = PLANE_SPACE_PARALLAX
+ screen_loc = "CENTER-7,CENTER-7"
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ appearance_flags = PIXEL_SCALE | KEEP_TOGETHER
+
+ // notice - all parallax layers are 15x15 tiles. They roll over every 240 pixels.
+ /// pixel x/y shift per real x/y
+ var/speed = 1
+ /// current cached offset x
+ var/offset_x = 0
+ /// current cached offset y
+ var/offset_y = 0
+ /// normal centered x
+ var/center_x = 0
+ /// normal centered y
+ var/center_y = 0
+ /// absolute - always determine shift x/y as a function of real x/y instead of allowing for relative scroll.
+ var/absolute = FALSE
+ /// parallax level required to see this
+ var/parallax_intensity = PARALLAX_INSANE
+ /// current view we're adapted to
+ var/view_current
+ /// dynamic self tile - tile to our view size. set this to false for static parallax layers.
+ var/dynamic_self_tile = TRUE
+ /// map id
+ var/map_id
+ /// queued animation timerid
+ var/queued_animation
+
+/atom/movable/screen/parallax_layer/proc/ResetPosition(x, y)
+ // remember that our offsets/directiosn are relative to the player's viewport
+ // this means we need to scroll reverse to them.
+ offset_x = -(center_x + speed * x)
+ offset_y = -(center_y + speed * y)
+ if(!absolute)
+ if(offset_x > 240)
+ offset_x -= 480
+ if(offset_x < -240)
+ offset_x += 480
+ if(offset_y > 240)
+ offset_y -= 480
+ if(offset_y < -240)
+ offset_y += 480
+ screen_loc = "[map_id && "[map_id]:"]CENTER-7:[round(offset_x,1)],CENTER-7:[round(offset_y,1)]"
+
+/atom/movable/screen/parallax_layer/proc/RelativePosition(x, y, rel_x, rel_y)
+ if(absolute)
+ return ResetPosition(x, y)
+ offset_x -= rel_x * speed
+ offset_y -= rel_y * speed
+ if(offset_x > 240)
+ offset_x -= 480
+ if(offset_x < -240)
+ offset_x += 480
+ if(offset_y > 240)
+ offset_y -= 480
+ if(offset_y < -240)
+ offset_y += 480
+ screen_loc = "[map_id && "[map_id]:"]CENTER-7:[round(offset_x,1)],CENTER-7:[round(offset_y,1)]"
+
+/atom/movable/screen/parallax_layer/proc/SetView(client_view = world.view, force_update = FALSE)
+ if(view_current == client_view && !force_update)
+ return
+ view_current = client_view
+ if(!dynamic_self_tile)
+ return
+ var/list/real_view = getviewsize(client_view)
+ var/count_x = CEILING((real_view[1] / 2) / 15, 1) + 1
+ var/count_y = CEILING((real_view[2] / 2) / 15, 1) + 1
+ var/list/new_overlays = GetOverlays()
+ for(var/x in -count_x to count_x)
+ for(var/y in -count_y to count_y)
+ if(!x && !y)
+ continue
+ var/mutable_appearance/clone = new
+ // appearance clone
+ clone.icon = icon
+ clone.icon_state = icon_state
+ clone.overlays = GetOverlays()
+ // do NOT inherit our overlays! parallax layers should never have overlays,
+ // because if it inherited us it'll result in exponentially increasing overlays
+ // due to cut_overlays() above over there being a queue operation and not instant!
+ // clone.overlays = list()
+ // currently instantly using overlays =.
+ // clone.blend_mode = blend_mode
+ // clone.mouse_opacity = mouse_opacity
+ // clone.plane = plane
+ // clone.layer = layer
+ // shift to position
+ clone.transform = matrix(1, 0, x * 480, 0, 1, y * 480)
+ new_overlays += clone
+ overlays = new_overlays
+
+/atom/movable/screen/parallax_layer/proc/ShouldSee(client/C, atom/location)
+ return TRUE
+
+/**
+ * Return "natural" overlays, as we're goin to do some fuckery to overlays above.
+ */
+/atom/movable/screen/parallax_layer/proc/GetOverlays()
+ return list()
+
+/atom/movable/screen/parallax_layer/proc/Clone()
+ var/atom/movable/screen/parallax_layer/layer = new type
+ layer.speed = speed
+ layer.offset_x = offset_x
+ layer.offset_y = offset_y
+ layer.absolute = absolute
+ layer.parallax_intensity = parallax_intensity
+ layer.view_current = view_current
+ layer.appearance = appearance
+
+/atom/movable/screen/parallax_layer/proc/default_x()
+ return center_x
+
+/atom/movable/screen/parallax_layer/proc/default_y()
+ return center_y
+
+/atom/movable/screen/parallax_layer/proc/QueueLoop(delay, speed, matrix/translate_matrix, matrix/target_matrix)
+ if(queued_animation)
+ CancelAnimation()
+ queued_animation = addtimer(CALLBACK(src, .proc/_loop, speed, translate_matrix, target_matrix), delay, TIMER_STOPPABLE)
+
+/atom/movable/screen/parallax_layer/proc/_loop(speed, matrix/translate_matrix = matrix(1, 0, 0, 0, 1, 480), matrix/target_matrix = matrix())
+ transform = translate_matrix
+ animate(src, transform = target_matrix, time = speed, loop = -1)
+ animate(transform = translate_matrix, time = 0)
+ queued_animation = null
+
+/atom/movable/screen/parallax_layer/proc/CancelAnimation()
+ if(queued_animation)
+ deltimer(queued_animation)
+ queued_animation = null
diff --git a/code/_rendering/parallax/types/space.dm b/code/_rendering/parallax/types/space.dm
new file mode 100644
index 0000000000..38ad62aede
--- /dev/null
+++ b/code/_rendering/parallax/types/space.dm
@@ -0,0 +1,66 @@
+/datum/parallax/space
+ var/static/planet_offset_x = rand(100, 160)
+ var/static/planet_offset_y = rand(100, 160)
+ var/static/random_layer = pickweightAllowZero(list(
+ /atom/movable/screen/parallax_layer/space/random/asteroids = 35,
+ /atom/movable/screen/parallax_layer/space/random/space_gas = 35,
+ null = 30
+ ))
+ var/static/random_gas_color = pick(COLOR_TEAL, COLOR_GREEN, COLOR_YELLOW, COLOR_CYAN, COLOR_ORANGE, COLOR_PURPLE)
+
+/datum/parallax/space/CreateObjects()
+ . = ..()
+ . += new /atom/movable/screen/parallax_layer/space/layer_1
+ . += new /atom/movable/screen/parallax_layer/space/layer_2
+ . += new /atom/movable/screen/parallax_layer/space/layer_3
+ var/atom/movable/screen/parallax_layer/space/planet/P = new
+ P.pixel_x = planet_offset_x
+ P.pixel_y = planet_offset_y
+ . += P
+ if(random_layer)
+ . += new random_layer
+ if(ispath(random_layer, /atom/movable/screen/parallax_layer/space/random/space_gas))
+ var/atom/movable/screen/parallax_layer/space/random/space_gas/SG = locate(random_layer) in objects
+ SG.add_atom_colour(random_gas_color, ADMIN_COLOUR_PRIORITY)
+
+/atom/movable/screen/parallax_layer/space/layer_1
+ icon_state = "layer1"
+ speed = 0.6
+ layer = 1
+ parallax_intensity = PARALLAX_LOW
+
+/atom/movable/screen/parallax_layer/space/layer_2
+ icon_state = "layer2"
+ speed = 1
+ layer = 2
+ parallax_intensity = PARALLAX_MED
+
+/atom/movable/screen/parallax_layer/space/layer_3
+ icon_state = "layer3"
+ speed = 1.4
+ layer = 3
+ parallax_intensity = PARALLAX_HIGH
+
+/atom/movable/screen/parallax_layer/space/random
+ blend_mode = BLEND_OVERLAY
+ speed = 3
+ layer = 3
+ parallax_intensity = PARALLAX_INSANE
+
+/atom/movable/screen/parallax_layer/space/random/space_gas
+ icon_state = "space_gas"
+
+/atom/movable/screen/parallax_layer/space/random/asteroids
+ icon_state = "asteroids"
+
+/atom/movable/screen/parallax_layer/space/planet
+ icon_state = "planet"
+ blend_mode = BLEND_OVERLAY
+ absolute = TRUE //Status of seperation
+ speed = 3
+ layer = 30
+ dynamic_self_tile = FALSE
+
+/atom/movable/screen/parallax_layer/space/planet/ShouldSee(client/C, atom/location)
+ var/turf/T = get_turf(location)
+ return ..() && T && is_station_level(T.z)
diff --git a/code/controllers/subsystem/parallax.dm b/code/controllers/subsystem/parallax.dm
index 86bd517602..248b33d86d 100644
--- a/code/controllers/subsystem/parallax.dm
+++ b/code/controllers/subsystem/parallax.dm
@@ -5,21 +5,6 @@ SUBSYSTEM_DEF(parallax)
priority = FIRE_PRIORITY_PARALLAX
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/list/currentrun
- var/planet_x_offset = 128
- var/planet_y_offset = 128
- var/random_layer
- var/random_parallax_color
-
-
-//These are cached per client so needs to be done asap so people joining at roundstart do not miss these.
-/datum/controller/subsystem/parallax/PreInit()
- . = ..()
- if(prob(70)) //70% chance to pick a special extra layer
- random_layer = pick(/atom/movable/screen/parallax_layer/random/space_gas, /atom/movable/screen/parallax_layer/random/asteroids)
- random_parallax_color = pick(COLOR_TEAL, COLOR_GREEN, COLOR_YELLOW, COLOR_CYAN, COLOR_ORANGE, COLOR_PURPLE)//Special color for random_layer1. Has to be done here so everyone sees the same color. [COLOR_SILVER]
- planet_y_offset = rand(100, 160)
- planet_x_offset = rand(100, 160)
-
/datum/controller/subsystem/parallax/fire(resumed = FALSE)
if (!resumed)
@@ -28,28 +13,82 @@ SUBSYSTEM_DEF(parallax)
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
- while(length(currentrun))
- var/client/processing_client = currentrun[currentrun.len]
- currentrun.len--
- if (QDELETED(processing_client) || !processing_client.eye)
+ if(times_fired % 5) // lazy tick
+ while(length(currentrun))
+ var/client/processing_client = currentrun[currentrun.len]
+ currentrun.len--
+ if (QDELETED(processing_client) || !processing_client.eye)
+ if (MC_TICK_CHECK)
+ return
+ continue
+ processing_client.parallax_holder?.Update()
if (MC_TICK_CHECK)
return
- continue
-
- var/atom/movable/movable_eye = processing_client.eye
- if(!istype(movable_eye))
- continue
-
- for (movable_eye; isloc(movable_eye.loc) && !isturf(movable_eye.loc); movable_eye = movable_eye.loc);
-
- if(movable_eye == processing_client.movingmob)
+ else // full tick
+ while(length(currentrun))
+ var/client/processing_client = currentrun[currentrun.len]
+ currentrun.len--
+ if (QDELETED(processing_client) || !processing_client.eye)
+ if (MC_TICK_CHECK)
+ return
+ continue
+ processing_client.parallax_holder?.Update(TRUE)
if (MC_TICK_CHECK)
return
- continue
- if(!isnull(processing_client.movingmob))
- LAZYREMOVE(processing_client.movingmob.client_mobs_in_contents, processing_client.mob)
- LAZYADD(movable_eye.client_mobs_in_contents, processing_client.mob)
- processing_client.movingmob = movable_eye
- if (MC_TICK_CHECK)
- return
+
currentrun = null
+
+/**
+ * Gets parallax type for zlevel.
+ */
+/datum/controller/subsystem/parallax/proc/get_parallax_type(z)
+ return /datum/parallax/space
+
+/**
+ * Gets parallax for zlevel.
+ */
+/datum/controller/subsystem/parallax/proc/get_parallax_datum(z)
+ var/datum_type = get_parallax_type(z)
+ return new datum_type
+
+/**
+ * Gets parallax added vis contents for zlevel
+ */
+/datum/controller/subsystem/parallax/proc/get_parallax_vis_contents(z)
+ return list()
+
+/**
+ * Gets parallax motion for a zlevel
+ *
+ * Returns null or list(speed, dir deg clockwise from north, windup, turnrate)
+ * THE RETURNED LIST MUST BE A 4-TUPLE, OR PARALLAX WILL CRASH.
+ * DO NOT SCREW WITH THIS UNLESS YOU KNOW WHAT YOU ARE DOING.
+ *
+ * This will override area motion
+ */
+/datum/controller/subsystem/parallax/proc/get_parallax_motion(z)
+ return null
+
+/**
+ * updates all parallax for clients on a z
+ */
+/datum/controller/subsystem/parallax/proc/update_clients_on_z(z)
+ for(var/client/C in GLOB.clients)
+ if(C.mob.z == z)
+ C.parallax_holder?.Update()
+
+/**
+ * resets all parallax for clients on a z
+ */
+/datum/controller/subsystem/parallax/proc/reset_clients_on_z(z)
+ for(var/client/C in GLOB.clients)
+ if(C.mob.z == z)
+ C.parallax_holder?.Reset()
+
+/**
+ * updates motion of all clients on z
+ */
+/datum/controller/subsystem/parallax/proc/update_z_motion(z)
+ for(var/client/C in GLOB.clients)
+ if(C.mob.z == z)
+ C.parallax_holder?.UpdateMotion()
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index 6af79d4d14..da295d70e2 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -513,7 +513,9 @@ SUBSYSTEM_DEF(shuttle)
if(!midpoint)
return FALSE
var/area/shuttle/transit/A = new()
- A.parallax_movedir = travel_dir
+ A.parallax_moving = TRUE
+ A.parallax_move_angle = dir2angle(travel_dir)
+ A.parallax_move_speed = M.parallax_speed
A.contents = proposal.reserved_turfs
var/obj/docking_port/stationary/transit/new_transit_dock = new(midpoint)
new_transit_dock.reserved_area = proposal
diff --git a/code/datums/cinematic.dm b/code/datums/cinematic.dm
index 2a8a0ea98a..6052b84364 100644
--- a/code/datums/cinematic.dm
+++ b/code/datums/cinematic.dm
@@ -101,7 +101,7 @@
if(!C)
return
watching += C
- M.overlay_fullscreen("cinematic",/atom/movable/screen/fullscreen/cinematic_backdrop)
+ M.overlay_fullscreen("cinematic",/atom/movable/screen/fullscreen/tiled/cinematic_backdrop)
C.screen += screen
//Sound helper
diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm
index 911ca7ecbe..c336213388 100644
--- a/code/datums/components/tackle.dm
+++ b/code/datums/components/tackle.dm
@@ -370,7 +370,7 @@
user.emote("scream")
user.gain_trauma(/datum/brain_trauma/severe/paralysis/spinesnapped) // oopsie indeed!
shake_camera(user, 7, 7)
- user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
+ user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
user.clear_fullscreen("flash", 4.5)
if(94 to 98)
@@ -381,7 +381,7 @@
user.gain_trauma_type(BRAIN_TRAUMA_MILD)
user.playsound_local(get_turf(user), 'sound/weapons/flashbang.ogg', 100, TRUE, 8, 0.9)
shake_camera(user, 6, 6)
- user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
+ user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
user.clear_fullscreen("flash", 3.5)
if(84 to 93)
@@ -394,7 +394,7 @@
user.playsound_local(get_turf(user), 'sound/weapons/flashbang.ogg', 100, TRUE, 8, 0.9)
user.DefaultCombatKnockdown(40)
shake_camera(user, 5, 5)
- user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
+ user.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
user.clear_fullscreen("flash", 2.5)
if(64 to 83)
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 2e0df8917d..a6562f2710 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -771,7 +771,7 @@
/datum/status_effect/necropolis_curse/proc/apply_curse(set_curse)
curse_flags |= set_curse
if(curse_flags & CURSE_BLINDING)
- owner.overlay_fullscreen("curse", /atom/movable/screen/fullscreen/curse, 1)
+ owner.overlay_fullscreen("curse", /atom/movable/screen/fullscreen/scaled/curse, 1)
/datum/status_effect/necropolis_curse/proc/remove_curse(remove_curse)
if(remove_curse & CURSE_BLINDING)
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 6ad95c8b56..b922f52315 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -50,7 +50,12 @@
var/has_gravity = FALSE
- var/parallax_movedir = 0
+ /// Parallax moving?
+ var/parallax_moving = FALSE
+ /// Parallax move speed - 0 to disable
+ var/parallax_move_speed = 0
+ /// Parallax move dir - degrees clockwise from north
+ var/parallax_move_angle = 0
var/list/ambientsounds = GENERIC
flags_1 = CAN_BE_DIRTY_1
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 391d3b467d..5da389fbb8 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -28,7 +28,6 @@
var/pass_flags = 0
var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move
var/atom/movable/moving_from_pull //attempt to resume grab after moving instead of before.
- var/list/client_mobs_in_contents // This contains all the client mobs within this container
var/list/acted_explosions //for explosion dodging
var/datum/forced_movement/force_moving = null //handled soley by forced_movement.dm
@@ -108,8 +107,6 @@
for(var/movable_content in contents)
qdel(movable_content)
- LAZYCLEARLIST(client_mobs_in_contents)
-
moveToNullspace()
/atom/movable/proc/update_emissive_block()
diff --git a/code/game/atoms_movement.dm b/code/game/atoms_movement.dm
index 43a22c9df0..9fd007e9ee 100644
--- a/code/game/atoms_movement.dm
+++ b/code/game/atoms_movement.dm
@@ -176,12 +176,8 @@
if (!inertia_moving)
inertia_next_move = world.time + inertia_move_delay
newtonian_move(Dir)
- if (length(client_mobs_in_contents))
- update_parallax_contents()
-
return TRUE
-
// Make sure you know what you're doing if you call this, this is intended to only be called by byond directly.
// You probably want CanPass()
/atom/movable/Cross(atom/movable/AM)
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 4d4ddf2f52..b680377d0a 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -407,7 +407,7 @@
/obj/machinery/camera/get_remote_view_fullscreens(mob/user)
if(view_range == short_range) //unfocused
- user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
+ user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/scaled/impaired, 2)
/obj/machinery/camera/update_remote_sight(mob/living/user)
user.see_invisible = SEE_INVISIBLE_LIVING //can't see ghosts through cameras
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index 9d675bc5dd..992807bed7 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -275,7 +275,7 @@
if(final)
playsound(origin, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0)
remote_eye.setLoc(get_turf(final))
- C.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash/static)
+ C.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash/static)
C.clear_fullscreen("flash", 3) //Shorter flash than normal since it's an ~~advanced~~ console!
else
playsound(origin, 'sound/machines/terminal_prompt_deny.ogg', 25, 0)
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index f01342a903..af4d098157 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -531,7 +531,7 @@
/obj/structure/closet/get_remote_view_fullscreens(mob/user)
if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
- user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1)
+ user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/scaled/impaired, 1)
/obj/structure/closet/emp_act(severity)
. = ..()
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index 6a588a61cd..73268009ce 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -139,7 +139,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
/obj/structure/bodycontainer/get_remote_view_fullscreens(mob/user)
if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
- user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
+ user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/scaled/impaired, 2)
/*
* Morgue
*/
diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm
index 21bf732493..a9c0984bbc 100644
--- a/code/modules/admin/callproc/callproc.dm
+++ b/code/modules/admin/callproc/callproc.dm
@@ -115,9 +115,9 @@ GLOBAL_PROTECT(LastAdminCalledProc)
//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
- return call("/proc/[procname]")(arglist(arguments))
- else if(target != world)
- return call(target, procname)(arglist(arguments))
+ return text2path("/proc/[procname]")? call("/proc/[procname]")(arglist(arguments)) : null
+ else if(target != world && istype(target, /datum)) // isdatum check incase someone manages to call WrapAdminProcCall(global) which would otherwise crash the process entirely
+ return hascall(target, procname)? call(target, procname)(arglist(arguments)) : null
else
log_admin("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
index ca07f9a50b..79fd63adcc 100644
--- a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
+++ b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
@@ -3,11 +3,19 @@
/proc/_abs(A)
return abs(A)
-/proc/_animate(atom/A, set_vars, time = 10, loop = 1, easing = LINEAR_EASING, flags = null)
- var/mutable_appearance/MA = new()
- for(var/v in set_vars)
- MA.vars[v] = set_vars[v]
- animate(A, appearance = MA, time, loop, easing, flags)
+/proc/_animate(atom/A, list/data, time = 10, loop = 1, easing = LINEAR_EASING, flags = null)
+ if(!istype(A))
+ return
+ animate(A, appearance = data, time = time, loop = loop, easing = easing, flags = flags)
+
+/proc/_animate_adv(atom/A, list/data, loop = 1, easing = LINEAR_EASING, flags = NONE)
+ if(!A || !islist(data) || data.len < 1)
+ return
+ animate(A, appearance = (data[1] - "time"), time = data[1]["time"], loop = loop, easing = easing, flags = flags)
+ if(data.len < 2)
+ return
+ for(var/i in 2 to data.len)
+ animate(appearance = (data[i] - "time"), time = data[i]["time"])
/proc/_acrccos(A)
return arccos(A)
diff --git a/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm b/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm
index 3609037f58..562d6a0c94 100644
--- a/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/city_of_cogs_rift.dm
@@ -69,7 +69,7 @@
do_sparks(5, TRUE, AM)
if(isliving(AM))
var/mob/living/L = AM
- L.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash/static)
+ L.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash/static)
L.clear_fullscreen("flash", 5)
var/obj/item/transfer_valve/TTV = locate() in L.GetAllContents()
if(TTV)
diff --git a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
index 2391658613..44c57b77ad 100644
--- a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
+++ b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
@@ -141,7 +141,7 @@
if(isliving(M.current) && M.current.stat != DEAD)
var/turf/t_turf = isAI(M.current) ? get_step(get_step(src, NORTH),NORTH) : get_turf(src) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark.
do_teleport(M.current, t_turf, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
- M.current.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
+ M.current.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
M.current.clear_fullscreen("flash", 5)
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, FALSE)
recalls_remaining--
@@ -311,7 +311,7 @@
var/turf/T = get_turf(M)
if(is_servant_of_ratvar(M) && (!T || T.z != z))
M.forceMove(get_step(src, SOUTH))
- M.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
+ M.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
M.clear_fullscreen("flash", 5)
progress_in_seconds += GATEWAY_SUMMON_RATE
switch(progress_in_seconds)
diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm
index fd7e6fb98d..619129f679 100644
--- a/code/modules/antagonists/devil/true_devil/_true_devil.dm
+++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm
@@ -104,7 +104,7 @@
/mob/living/carbon/true_devil/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
return 666
-/mob/living/carbon/true_devil/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/flash, override_protection = 0)
+/mob/living/carbon/true_devil/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/tiled/flash, override_protection = 0)
if(mind && has_bane(BANE_LIGHT))
mind.disrupt_spells(-500)
return ..() //flashes don't stop devils UNLESS it's their bane.
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index 6c9ce28bc7..c652a7f791 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -439,7 +439,7 @@
return // we don't see the pipe network while inside cryo.
/obj/machinery/atmospherics/components/unary/cryo_cell/get_remote_view_fullscreens(mob/user)
- user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1)
+ user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/scaled/impaired, 1)
/obj/machinery/atmospherics/components/unary/cryo_cell/can_crawl_through()
return // can't ventcrawl in or out of cryo.
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index 70aab57e0a..41c4480c74 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -4,6 +4,16 @@
//BLACK MAGIC THINGS//
//////////////////////
parent_type = /datum
+
+ ///////////////
+ // Rendering //
+ ///////////////
+
+ /// Click catcher
+ var/atom/movable/screen/click_catcher/click_catcher
+ /// Parallax holder
+ var/datum/parallax_holder/parallax_holder
+
////////////////
//ADMIN THINGS//
////////////////
@@ -153,20 +163,6 @@
///When was the last time we warned them about not cryoing without an ahelp, set to -5 minutes so that rounstart cryo still warns
var/cryo_warned = -5 MINUTES
- var/list/parallax_layers
- var/list/parallax_layers_cached
- var/atom/movable/movingmob
- var/turf/previous_turf
- ///world.time of when we can state animate()ing parallax again
- var/dont_animate_parallax
- ///world.time of last parallax update
- var/last_parallax_shift
- ///ds between parallax updates
- var/parallax_throttle = 0
- var/parallax_movedir = 0
- var/parallax_layers_max = 3
- var/parallax_animate_timer
-
/**
* Assoc list with all the active maps - when a screen obj is added to
* a map, it's put in here as well.
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index ccca7c93cb..9948802bc9 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -444,8 +444,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
send_resources()
- generate_clickcatcher()
- apply_clickcatcher()
+ update_clickcatcher()
if(prefs.lastchangelog != GLOB.changelog_hash) //bolds the changelog button on the interface so we know there are updates.
to_chat(src, "You have unread updates in the changelog.")
@@ -535,9 +534,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
send2adminchat("Server", "[cheesy_message] (No admins online)")
QDEL_LIST_ASSOC_VAL(char_render_holders)
- if(movingmob != null)
- movingmob.client_mobs_in_contents -= mob
- UNSETEMPTY(movingmob.client_mobs_in_contents)
// 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
@@ -1014,7 +1010,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
var/list/old_view = getviewsize(view)
view = new_size
var/list/actualview = getviewsize(view)
- apply_clickcatcher(actualview)
+ update_clickcatcher()
+ parallax_holder.Reset()
mob.reload_fullscreen()
if (isliving(mob))
var/mob/living/M = mob
@@ -1023,17 +1020,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
addtimer(CALLBACK(src,.verb/fit_viewport,10)) //Delayed to avoid wingets from Login calls.
SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_CHANGE_VIEW, src, old_view, actualview)
-/client/proc/generate_clickcatcher()
- if(!void)
- void = new()
- screen += void
-
-/client/proc/apply_clickcatcher(list/actualview)
- generate_clickcatcher()
- if(!actualview)
- actualview = getviewsize(view)
- void.UpdateGreed(actualview[1],actualview[2])
-
/client/proc/AnnouncePR(announcement)
if(prefs && prefs.chat_toggles & CHAT_PULLR)
to_chat(src, announcement)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 952a11338a..3272060835 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -164,7 +164,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/clientfps = 0
- var/parallax
+ var/parallax = PARALLAX_INSANE
var/ambientocclusion = TRUE
///Should we automatically fit the viewport?
@@ -2816,14 +2816,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
toggles ^= MIDROUND_ANTAG
if("parallaxup")
- parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
- if (parent && parent.mob && parent.mob.hud_used)
- parent.mob.hud_used.update_parallax_pref(parent.mob)
+ parallax = WRAP(parallax + 1, PARALLAX_DISABLE, PARALLAX_INSANE + 1)
+ parent?.parallax_holder?.Reset()
if("parallaxdown")
- parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
- if (parent && parent.mob && parent.mob.hud_used)
- parent.mob.hud_used.update_parallax_pref(parent.mob)
+ parallax = WRAP(parallax - 1, PARALLAX_DISABLE, PARALLAX_INSANE + 1)
+ parent?.parallax_holder?.Reset()
// Citadel edit - Prefs don't work outside of this. :c
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index f683ba0ee3..72b2f5d949 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
-#define SAVEFILE_VERSION_MAX 52
+#define SAVEFILE_VERSION_MAX 53
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -343,6 +343,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
marking_list += list(list(part, old_marking_value, copied_color_list))
features["mam_body_markings"] = marking_list
+ if(current_version < 53)
+ parallax = PARALLAX_INSANE
+
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
return
@@ -469,7 +472,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot))
toggles = sanitize_integer(toggles, 0, 16777215, initial(toggles))
clientfps = sanitize_integer(clientfps, 0, 1000, 0)
- parallax = sanitize_integer(parallax, PARALLAX_INSANE, PARALLAX_DISABLE, null)
+ parallax = sanitize_integer(parallax, PARALLAX_DISABLE, PARALLAX_INSANE, null)
ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion))
auto_fit_viewport = sanitize_integer(auto_fit_viewport, 0, 1, initial(auto_fit_viewport))
widescreenpref = sanitize_integer(widescreenpref, 0, 1, initial(widescreenpref))
diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm
index ce767ae00d..90b6da26fa 100644
--- a/code/modules/mob/dead/dead.dm
+++ b/code/modules/mob/dead/dead.dm
@@ -126,5 +126,5 @@ INITIALIZE_IMMEDIATE(/mob/dead)
return ..()
/mob/dead/onTransitZ(old_z,new_z)
- ..()
+ . = ..()
update_z(new_z)
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 2068ed47e8..48244a91be 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -578,8 +578,6 @@
Spl.Fade(TRUE)
character.playsound_local(get_turf(character), 'sound/voice/ApproachingTG.ogg', 25)
- character.update_parallax_teleport()
-
job.standard_assign_skills(character.mind)
SSticker.minds += character.mind
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 0f30fe20fc..624db8caf5 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -377,8 +377,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
ghostize(0, penalize = TRUE)
-
-
/mob/dead/observer/Move(NewLoc, direct)
if (SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_MOVE, NewLoc) & COMPONENT_MOVABLE_BLOCK_PRE_MOVE)
return
@@ -388,7 +386,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(NewLoc)
forceMove(NewLoc)
- update_parallax_contents()
else
forceMove(get_turf(src)) //Get out of closets and such as a ghost
if((direct & NORTH) && y < world.maxy)
@@ -487,9 +484,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(!L || !L.len)
to_chat(usr, "No area available.")
return
-
usr.forceMove(pick(L))
- update_parallax_contents()
/mob/dead/observer/proc/view_gas()
set category = "Ghost"
@@ -568,7 +563,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
A.forceMove(T)
- A.update_parallax_contents()
else
to_chat(A, "This mob is not located in the game world.")
diff --git a/code/modules/mob/dead/observer/respawn.dm b/code/modules/mob/dead/observer/respawn.dm
index 94ebf42a2a..32f775ed46 100644
--- a/code/modules/mob/dead/observer/respawn.dm
+++ b/code/modules/mob/dead/observer/respawn.dm
@@ -165,7 +165,7 @@
/**
* Actual proc that removes us and puts us back on lobby
- *
+ *
* Returns the new mob.
*/
/mob/dead/observer/proc/transfer_to_lobby()
@@ -174,8 +174,7 @@
return
client.screen.Cut()
client.view_size.resetToDefault()
- client.generate_clickcatcher()
- client.apply_clickcatcher()
+ client.update_clickcatcher()
client.view_size.setDefault(getScreenSize(client.prefs.widescreenpref))
client.view_size.resetToDefault()
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 6acd604ca5..61839ce123 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -646,7 +646,7 @@
become_blind(EYES_COVERED)
else if(tinttotal >= TINT_DARKENED)
cure_blind(EYES_COVERED)
- overlay_fullscreen("tint", /atom/movable/screen/fullscreen/impaired, 2)
+ overlay_fullscreen("tint", /atom/movable/screen/fullscreen/scaled/impaired, 2)
else
cure_blind(EYES_COVERED)
clear_fullscreen("tint", 0)
@@ -722,10 +722,10 @@
visionseverity = 9
if(-INFINITY to -24)
visionseverity = 10
- overlay_fullscreen("critvision", /atom/movable/screen/fullscreen/crit/vision, visionseverity)
+ overlay_fullscreen("critvision", /atom/movable/screen/fullscreen/scaled/crit/vision, visionseverity)
else
clear_fullscreen("critvision")
- overlay_fullscreen("crit", /atom/movable/screen/fullscreen/crit, severity)
+ overlay_fullscreen("crit", /atom/movable/screen/fullscreen/scaled/crit, severity)
else
clear_fullscreen("crit")
clear_fullscreen("critvision")
@@ -749,7 +749,7 @@
severity = 6
if(45 to INFINITY)
severity = 7
- overlay_fullscreen("oxy", /atom/movable/screen/fullscreen/oxy, severity)
+ overlay_fullscreen("oxy", /atom/movable/screen/fullscreen/scaled/oxy, severity)
else
clear_fullscreen("oxy")
@@ -770,7 +770,7 @@
severity = 5
if(85 to INFINITY)
severity = 6
- overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity)
+ overlay_fullscreen("brute", /atom/movable/screen/fullscreen/scaled/brute, severity)
else
clear_fullscreen("brute")
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 46ba9a5eb0..a12d6614fa 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -361,7 +361,7 @@
return embeds
-/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/flash, override_protection = 0)
+/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/tiled/flash, override_protection = 0)
. = ..()
var/damage = override_protection ? intensity : intensity - get_eye_protection()
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index c75654e10b..199a6b44be 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -209,7 +209,7 @@
update_tint()
if(G.vision_correction)
if(HAS_TRAIT(src, TRAIT_NEARSIGHT))
- overlay_fullscreen("nearsighted", /atom/movable/screen/fullscreen/impaired, 1)
+ overlay_fullscreen("nearsighted", /atom/movable/screen/fullscreen/scaled/impaired, 1)
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
update_sight()
if(!QDELETED(src))
diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm
index 5b5aa9d5c0..f7cb0e0760 100644
--- a/code/modules/mob/living/carbon/status_procs.dm
+++ b/code/modules/mob/living/carbon/status_procs.dm
@@ -5,7 +5,7 @@
/mob/living/carbon/adjust_drugginess(amount)
druggy = max(druggy+amount, 0)
if(druggy)
- overlay_fullscreen("high", /atom/movable/screen/fullscreen/high)
+ overlay_fullscreen("high", /atom/movable/screen/fullscreen/tiled/high)
throw_alert("high", /atom/movable/screen/alert/high)
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "high", /datum/mood_event/high)
sound_environment_override = SOUND_ENVIRONMENT_DRUGGED
@@ -18,7 +18,7 @@
/mob/living/carbon/set_drugginess(amount)
druggy = max(amount, 0)
if(druggy)
- overlay_fullscreen("high", /atom/movable/screen/fullscreen/high)
+ overlay_fullscreen("high", /atom/movable/screen/fullscreen/tiled/high)
throw_alert("high", /atom/movable/screen/alert/high)
else
clear_fullscreen("high")
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 28fd4e0451..2070d07e14 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -579,7 +579,7 @@
UNLINT(livingdoll.filters += filter(type="alpha", icon = mob_mask))
livingdoll.filters += filter(type="drop_shadow", size = -1)
if(severity > 0)
- overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity)
+ overlay_fullscreen("brute", /atom/movable/screen/fullscreen/scaled/brute, severity)
else
clear_fullscreen("brute")
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 7423a164a4..5ce80c5575 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -539,7 +539,7 @@
//called when the mob receives a bright flash
-/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/flash, override_protection = 0)
+/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/tiled/flash, override_protection = 0)
if((override_protection || get_eye_protection() < intensity) && (override_blindness_check || !(HAS_TRAIT(src, TRAIT_BLIND))))
overlay_fullscreen("flash", type)
addtimer(CALLBACK(src, .proc/clear_fullscreen, "flash", 25), 25)
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index dcaa28b39c..3fad48e584 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -84,7 +84,6 @@
if(ai.client && !ai.multicam_on)
ai.client.eye = src
update_ai_detect_hud()
- update_parallax_contents()
//Holopad
if(istype(ai.current, /obj/machinery/holopad))
var/obj/machinery/holopad/H = ai.current
diff --git a/code/modules/mob/living/silicon/pai/death.dm b/code/modules/mob/living/silicon/pai/death.dm
index c2bc49f9a8..07cb671706 100644
--- a/code/modules/mob/living/silicon/pai/death.dm
+++ b/code/modules/mob/living/silicon/pai/death.dm
@@ -4,7 +4,7 @@
stat = DEAD
update_mobility()
update_sight()
- clear_fullscreens()
+ wipe_fullscreens()
//New pAI's get a brand new mind to prevent meta stuff from their previous life. This new mind causes problems down the line if it's not deleted here.
remove_from_alive_mob_list()
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index 6c9d508fd8..55d0336671 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -144,6 +144,6 @@
P.on_hit(src, 0, def_zone)
return BULLET_ACT_HIT
-/mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/flash/static)
+/mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/tiled/flash/static)
if(affect_silicon)
return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
index de6b858f79..be596b0292 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
@@ -113,7 +113,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
severity = 7
hud_used.healths.icon_state = "elite_health[severity]"
if(severity > 0)
- overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity)
+ overlay_fullscreen("brute", /atom/movable/screen/fullscreen/scaled/brute, severity)
else
clear_fullscreen("brute")
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 02e88e3741..498ca19a39 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -599,7 +599,7 @@
/mob/living/proc/become_nearsighted(source)
if(!HAS_TRAIT(src, TRAIT_NEARSIGHT))
- overlay_fullscreen("nearsighted", /atom/movable/screen/fullscreen/impaired, 1)
+ overlay_fullscreen("nearsighted", /atom/movable/screen/fullscreen/scaled/impaired, 1)
ADD_TRAIT(src, TRAIT_NEARSIGHT, source)
/mob/living/proc/cure_husk(source)
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 7d2daac326..aac55c614b 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -58,10 +58,6 @@
//readd this mob's HUDs (antag, med, etc)
reload_huds()
- reload_fullscreen() // Reload any fullscreen overlays this mob has.
-
- add_click_catcher()
-
sync_mind()
//Reload alternate appearances
@@ -93,6 +89,9 @@
if(has_field_of_vision && CONFIG_GET(flag/use_field_of_vision))
LoadComponent(/datum/component/field_of_vision, field_of_vision_type)
+ // load rendering
+ reload_rendering()
+
AddElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
// optimized area sound effects. Enable during events (compile flag when 😳)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index d240f97a23..03c5e76e87 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1,25 +1,3 @@
-/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game.
- remove_from_mob_list()
- remove_from_dead_mob_list()
- remove_from_alive_mob_list()
- GLOB.all_clockwork_mobs -= src
- focus = null
- LAssailant = null
- movespeed_modification = null
- for (var/alert in alerts)
- clear_alert(alert, TRUE)
- if(observers && observers.len)
- for(var/M in observers)
- var/mob/dead/observe = M
- observe.reset_perspective(null)
- qdel(hud_used)
- for(var/cc in client_colours)
- qdel(cc)
- client_colours = null
- ghostize()
- ..()
- return QDEL_HINT_HARDDEL
-
/mob/Initialize()
add_to_mob_list()
if(stat == DEAD)
@@ -38,8 +16,32 @@
update_config_movespeed()
update_movespeed(TRUE)
initialize_actionspeed()
+ init_rendering()
hook_vr("mob_new",list(src))
+/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game.
+ remove_from_mob_list()
+ remove_from_dead_mob_list()
+ remove_from_alive_mob_list()
+ GLOB.all_clockwork_mobs -= src
+ focus = null
+ LAssailant = null
+ movespeed_modification = null
+ for (var/alert in alerts)
+ clear_alert(alert, TRUE)
+ if(observers && observers.len)
+ for(var/M in observers)
+ var/mob/dead/observe = M
+ observe.reset_perspective(null)
+ dispose_rendering()
+ qdel(hud_used)
+ for(var/cc in client_colours)
+ qdel(cc)
+ client_colours = null
+ ghostize()
+ ..()
+ return QDEL_HINT_HARDDEL
+
/mob/GenerateTag()
tag = "mob_[next_mob_id++]"
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 8e6226069c..527b0c0917 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -16,6 +16,10 @@
attack_hand_unwieldlyness = CLICK_CD_MELEE
attack_hand_speed = 0
+ // Rendering
+ /// Fullscreen objects
+ var/list/fullscreens = list()
+
/// What receives our keyboard input. src by default.
var/datum/focus
@@ -143,7 +147,6 @@
var/registered_z
var/list/alerts = list() // contains /atom/movable/screen/alert only // On /mob so clientless mobs will throw alerts properly
- var/list/screens = list()
var/list/client_colours = list()
var/hud_type = /datum/hud
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index bfd4cfcd29..1da355a419 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -110,6 +110,11 @@
SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_MOVE, src, direction, n, oldloc, add_delay)
+/mob/Moved(atom/OldLoc, Dir)
+ . = ..()
+ if(client)
+ client.parallax_holder.Update()
+
/// Process_Grab(): checks for grab, attempts to break if so. Return TRUE to prevent movement.
/client/proc/Process_Grab()
if(mob.pulledby)
@@ -398,3 +403,8 @@
/mob/proc/canZMove(direction, turf/target)
return FALSE
+
+/mob/onTransitZ(old_z, new_z)
+ . = ..()
+ if(old_z != new_z)
+ client?.parallax_holder?.Reset()
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 089484ea9f..da1919443a 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -53,7 +53,7 @@
if(eye_blind) // UNCONSCIOUS or has blind trait, or has temporary blindness
if(stat == CONSCIOUS || stat == SOFT_CRIT)
throw_alert("blind", /atom/movable/screen/alert/blind)
- overlay_fullscreen("blind", /atom/movable/screen/fullscreen/blind)
+ overlay_fullscreen("blind", /atom/movable/screen/fullscreen/scaled/blind)
// You are blind why should you be able to make out details like color, only shapes near you
// add_client_colour(/datum/client_colour/monochrome/blind)
else // CONSCIOUS no blind trait, no blindness
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index 7fc57ee3a7..85b5cdac51 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -465,7 +465,7 @@
/obj/machinery/disposal/bin/get_remote_view_fullscreens(mob/user)
if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
- user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
+ user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/scaled/impaired, 2)
//Delivery Chute
diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
index 7109c87999..4a03844a33 100644
--- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm
+++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
@@ -302,7 +302,7 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337)
user.reset_perspective(parentSphere)
user.set_machine(src)
var/datum/action/peepholeCancel/PHC = new
- user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1)
+ user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/scaled/impaired, 1)
PHC.Grant(user)
return TRUE
diff --git a/code/modules/shuttle/docking.dm b/code/modules/shuttle/docking.dm
index 5c96bca07c..103e331039 100644
--- a/code/modules/shuttle/docking.dm
+++ b/code/modules/shuttle/docking.dm
@@ -162,7 +162,7 @@
for(var/i in 1 to areas_to_move.len)
CHECK_TICK
var/area/internal_area = areas_to_move[i]
- internal_area.afterShuttleMove(new_parallax_dir) //areas
+ internal_area.afterShuttleMove(new_parallax_dir, parallax_speed) //areas
for(var/i in 1 to old_turfs.len)
CHECK_TICK
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index cc37fbbcc4..2a15558e64 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -461,11 +461,11 @@
for(var/area/shuttle/escape/E in GLOB.sortedAreas)
areas += E
hyperspace_sound(HYPERSPACE_END, areas)
- if(time_left <= PARALLAX_LOOP_TIME)
+ if(time_left <= parallax_speed)
var/area_parallax = FALSE
for(var/place in shuttle_areas)
var/area/shuttle/shuttle_area = place
- if(shuttle_area.parallax_movedir)
+ if(shuttle_area.parallax_moving)
area_parallax = TRUE
break
if(area_parallax)
diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index a215b58b55..029d50585a 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -356,7 +356,7 @@
playsound(console, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0)
remote_eye.setLoc(T)
to_chat(target, "Jumped to [selected]")
- C.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash/static)
+ C.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash/static)
C.clear_fullscreen("flash", 3)
else
playsound(console, 'sound/machines/terminal_prompt_deny.ogg', 25, 0)
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index 8c1b3fa955..ceb9b7adea 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -117,8 +117,6 @@ All ShuttleMove procs go here
if(rotation)
shuttleRotate(rotation)
- update_parallax_contents()
-
return TRUE
/atom/movable/proc/lateShuttleMove(turf/oldT, list/movement_force, move_dir)
@@ -153,16 +151,21 @@ All ShuttleMove procs go here
//The old turf has now been given back to the area that turf originaly belonged to
var/area/old_dest_area = newT.loc
- parallax_movedir = old_dest_area.parallax_movedir
-
+ parallax_moving = old_dest_area.parallax_moving
+ parallax_move_angle = old_dest_area.parallax_move_angle
+ parallax_move_speed = old_dest_area.parallax_move_speed
old_dest_area.contents -= newT
contents += newT
newT.change_area(old_dest_area, src)
return TRUE
// Called on areas after everything has been moved
-/area/proc/afterShuttleMove(new_parallax_dir)
- parallax_movedir = new_parallax_dir
+/area/proc/afterShuttleMove(new_parallax_dir, speed)
+ if(!new_parallax_dir)
+ parallax_moving = FALSE
+ return
+ parallax_move_angle = dir2angle(new_parallax_dir)
+ parallax_move_speed = speed
return TRUE
/area/proc/lateShuttleMove()
@@ -309,6 +312,7 @@ All ShuttleMove procs go here
if(buckled)
shake_force *= 0.25
shake_camera(src, shake_force, 1)
+ client?.parallax_holder?.Reset(auto_z_change = FALSE, force = TRUE)
/mob/living/lateShuttleMove(turf/oldT, list/movement_force, move_dir)
if(buckled)
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index 0eb7f6ee20..d3e52410d6 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -367,6 +367,9 @@
var/can_move_docking_ports = FALSE
var/list/hidden_turfs = list()
+ /// parallax speed in seconds per loop
+ var/parallax_speed = 25
+
/obj/docking_port/mobile/register(replace = FALSE)
. = ..()
if(!id)
@@ -709,27 +712,24 @@
create_ripples(destination, tl)
var/obj/docking_port/stationary/S0 = get_docked()
- if(istype(S0, /obj/docking_port/stationary/transit) && timeLeft(1) <= PARALLAX_LOOP_TIME)
+ if(istype(S0, /obj/docking_port/stationary/transit) && timeLeft(1) <= parallax_speed)
+ var/parallax_ongoing = FALSE
for(var/place in shuttle_areas)
var/area/shuttle/shuttle_area = place
- if(shuttle_area.parallax_movedir)
- parallax_slowdown()
+ if(shuttle_area.parallax_moving)
+ parallax_ongoing = TRUE
+ if(parallax_ongoing)
+ parallax_slowdown()
/obj/docking_port/mobile/proc/parallax_slowdown()
- for(var/place in shuttle_areas)
- var/area/shuttle/shuttle_area = place
- shuttle_area.parallax_movedir = FALSE
- if(assigned_transit?.assigned_area)
- assigned_transit.assigned_area.parallax_movedir = FALSE
- var/list/L0 = return_ordered_turfs(x, y, z, dir)
- for (var/thing in L0)
- var/turf/T = thing
- if(!T || !istype(T.loc, area_type))
- continue
- for (var/thing2 in T)
- var/atom/movable/AM = thing2
- if (length(AM.client_mobs_in_contents))
- AM.update_parallax_contents()
+ for(var/mob/M in GLOB.player_list)
+ var/area/A = get_area(M)
+ if(A in shuttle_areas)
+ M.client?.parallax_holder?.StopScrolling(A.parallax_move_angle, parallax_speed)
+ for(var/area/shuttle_area in shuttle_areas + assigned_transit?.assigned_area)
+ shuttle_area.parallax_moving = FALSE
+ shuttle_area.parallax_move_speed = 0
+ shuttle_area.parallax_move_angle = 0
/obj/docking_port/mobile/proc/check_transit_zone()
if(assigned_transit)
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index 9861a1b639..06865a0f39 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -41,7 +41,7 @@
return
switch(eye_damaged)
if(BLURRY_VISION_ONE, BLURRY_VISION_TWO)
- owner.overlay_fullscreen("eye_damage", /atom/movable/screen/fullscreen/impaired, eye_damaged)
+ owner.overlay_fullscreen("eye_damage", /atom/movable/screen/fullscreen/scaled/impaired, eye_damaged)
if(BLIND_VISION_THREE)
owner.become_blind(EYE_DAMAGE)
if(ishuman(owner))
@@ -106,7 +106,7 @@
else if(eye_damaged == BLIND_VISION_THREE)
owner.become_blind(EYE_DAMAGE)
if(eye_damaged && eye_damaged != BLIND_VISION_THREE)
- owner.overlay_fullscreen("eye_damage", /atom/movable/screen/fullscreen/impaired, eye_damaged)
+ owner.overlay_fullscreen("eye_damage", /atom/movable/screen/fullscreen/scaled/impaired, eye_damaged)
else
owner.clear_fullscreen("eye_damage")
diff --git a/icons/screen/clickcatcher.dmi b/icons/screen/clickcatcher.dmi
new file mode 100644
index 0000000000..50a3616991
Binary files /dev/null and b/icons/screen/clickcatcher.dmi differ
diff --git a/icons/screen/fullscreen_15x15.dmi b/icons/screen/fullscreen_15x15.dmi
new file mode 100644
index 0000000000..502e9ad3f9
Binary files /dev/null and b/icons/screen/fullscreen_15x15.dmi differ
diff --git a/icons/screen/fullscreen_tiled.dmi b/icons/screen/fullscreen_tiled.dmi
new file mode 100644
index 0000000000..11b70842ec
Binary files /dev/null and b/icons/screen/fullscreen_tiled.dmi differ
diff --git a/icons/screen/parallax.dmi b/icons/screen/parallax.dmi
new file mode 100644
index 0000000000..36dd36ee7a
Binary files /dev/null and b/icons/screen/parallax.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 50a44347a4..38e9409074 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -28,7 +28,6 @@
#include "code\__DEFINES\admin.dm"
#include "code\__DEFINES\antagonists.dm"
#include "code\__DEFINES\atmospherics.dm"
-#include "code\__DEFINES\atom_hud.dm"
#include "code\__DEFINES\blackmarket.dm"
#include "code\__DEFINES\botany.dm"
#include "code\__DEFINES\callbacks.dm"
@@ -37,7 +36,6 @@
#include "code\__DEFINES\citadel_defines.dm"
#include "code\__DEFINES\cleaning.dm"
#include "code\__DEFINES\clockcult.dm"
-#include "code\__DEFINES\colors.dm"
#include "code\__DEFINES\combat.dm"
#include "code\__DEFINES\configuration.dm"
#include "code\__DEFINES\construction.dm"
@@ -144,6 +142,9 @@
#include "code\__DEFINES\_flags\shields.dm"
#include "code\__DEFINES\admin\keybindings.dm"
#include "code\__DEFINES\chemistry\reactions.dm"
+#include "code\__DEFINES\color\color_priority.dm"
+#include "code\__DEFINES\color\colors.dm"
+#include "code\__DEFINES\color\lum.dm"
#include "code\__DEFINES\combat\attack_types.dm"
#include "code\__DEFINES\combat\block.dm"
#include "code\__DEFINES\combat\block_parry.dm"
@@ -155,6 +156,8 @@
#include "code\__DEFINES\material\worth.dm"
#include "code\__DEFINES\mobs\innate_abilities.dm"
#include "code\__DEFINES\mobs\slowdowns.dm"
+#include "code\__DEFINES\rendering\atom_hud.dm"
+#include "code\__DEFINES\rendering\parallax.dm"
#include "code\__DEFINES\research\anomalies.dm"
#include "code\__DEFINES\research\stock_parts.dm"
#include "code\__DEFINES\skills\defines.dm"
@@ -187,7 +190,6 @@
#include "code\__HELPERS\level_traits.dm"
#include "code\__HELPERS\lighting.dm"
#include "code\__HELPERS\markov.dm"
-#include "code\__HELPERS\matrices.dm"
#include "code\__HELPERS\mobs.dm"
#include "code\__HELPERS\mouse_control.dm"
#include "code\__HELPERS\names.dm"
@@ -212,6 +214,8 @@
#include "code\__HELPERS\verbs.dm"
#include "code\__HELPERS\view.dm"
#include "code\__HELPERS\yelling.dm"
+#include "code\__HELPERS\matrices\color_matrix.dm"
+#include "code\__HELPERS\matrices\transform_matrix.dm"
#include "code\__HELPERS\sorts\__main.dm"
#include "code\__HELPERS\sorts\InsertSort.dm"
#include "code\__HELPERS\sorts\MergeSort.dm"
@@ -267,7 +271,6 @@
#include "code\_onclick\hud\credits.dm"
#include "code\_onclick\hud\devil.dm"
#include "code\_onclick\hud\drones.dm"
-#include "code\_onclick\hud\fullscreen.dm"
#include "code\_onclick\hud\generic_dextrous.dm"
#include "code\_onclick\hud\ghost.dm"
#include "code\_onclick\hud\guardian.dm"
@@ -277,7 +280,6 @@
#include "code\_onclick\hud\map_popups.dm"
#include "code\_onclick\hud\monkey.dm"
#include "code\_onclick\hud\movable_screen_objects.dm"
-#include "code\_onclick\hud\parallax.dm"
#include "code\_onclick\hud\picture_in_picture.dm"
#include "code\_onclick\hud\plane_master.dm"
#include "code\_onclick\hud\radial.dm"
@@ -292,6 +294,16 @@
#include "code\_onclick\hud\screen_objects\stamina.dm"
#include "code\_onclick\hud\screen_objects\storage.dm"
#include "code\_onclick\hud\screen_objects\vore.dm"
+#include "code\_rendering\mob.dm"
+#include "code\_rendering\atom_huds\alternate_appearance.dm"
+#include "code\_rendering\atom_huds\atom_hud.dm"
+#include "code\_rendering\atom_huds\data_huds.dm"
+#include "code\_rendering\clickcatcher\clickcatcher.dm"
+#include "code\_rendering\fullscreen\fullscreen.dm"
+#include "code\_rendering\parallax\parallax.dm"
+#include "code\_rendering\parallax\parallax_holder.dm"
+#include "code\_rendering\parallax\parallax_object.dm"
+#include "code\_rendering\parallax\types\space.dm"
#include "code\controllers\admin.dm"
#include "code\controllers\configuration_citadel.dm"
#include "code\controllers\controller.dm"
@@ -442,7 +454,6 @@
#include "code\datums\forced_movement.dm"
#include "code\datums\holocall.dm"
#include "code\datums\http.dm"
-#include "code\datums\hud.dm"
#include "code\datums\mind.dm"
#include "code\datums\mutable_appearance.dm"
#include "code\datums\numbered_display.dm"
@@ -783,12 +794,10 @@
#include "code\datums\wounds\loss.dm"
#include "code\datums\wounds\pierce.dm"
#include "code\datums\wounds\slash.dm"
-#include "code\game\alternate_appearance.dm"
#include "code\game\atoms.dm"
#include "code\game\atoms_movable.dm"
#include "code\game\atoms_movement.dm"
#include "code\game\communications.dm"
-#include "code\game\data_huds.dm"
#include "code\game\say.dm"
#include "code\game\shuttle_engines.dm"
#include "code\game\sound.dm"