diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index f9309b7768e..bd5997c8f3f 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -218,3 +218,4 @@ ///Plane master controller keys #define PLANE_MASTERS_GAME "plane_masters_game" +#define PLANE_MASTERS_COLORBLIND "plane_masters_colorblind" diff --git a/code/_onclick/hud/rendering/plane_master.dm b/code/_onclick/hud/rendering/plane_master.dm index 288a8b060f1..bb5883b9b02 100644 --- a/code/_onclick/hud/rendering/plane_master.dm +++ b/code/_onclick/hud/rendering/plane_master.dm @@ -269,3 +269,11 @@ render_target = FIELD_OF_VISION_BLOCKER_RENDER_TARGET mouse_opacity = MOUSE_OPACITY_TRANSPARENT render_relay_plane = null + +/atom/movable/screen/plane_master/hud + name = "HUD plane" + plane = HUD_PLANE + +/atom/movable/screen/plane_master/above_hud + name = "above HUD plane" + plane = ABOVE_HUD_PLANE diff --git a/code/_onclick/hud/rendering/plane_master_controller.dm b/code/_onclick/hud/rendering/plane_master_controller.dm index 8d0c98cbd90..faae549bc70 100644 --- a/code/_onclick/hud/rendering/plane_master_controller.dm +++ b/code/_onclick/hud/rendering/plane_master_controller.dm @@ -95,4 +95,30 @@ INITIALIZE_IMMEDIATE(/atom/movable/plane_master_controller) LIGHTING_PLANE, ) +/// Controller of all planes we're ok with changing with colorblind logic +/atom/movable/plane_master_controller/colorblind + name = PLANE_MASTERS_COLORBLIND + controlled_planes = list( + PLANE_SPACE_PARALLAX, + GRAVITY_PULSE_PLANE, + FLOOR_PLANE, + GAME_PLANE, + GAME_PLANE_FOV_HIDDEN, + GAME_PLANE_UPPER, + GAME_PLANE_UPPER_FOV_HIDDEN, + ABOVE_GAME_PLANE, + MASSIVE_OBJ_PLANE, + GHOST_PLANE, + POINT_PLANE, + RAD_TEXT_PLANE, + LIGHTING_PLANE, + O_LIGHTING_VISUAL_PLANE, + ABOVE_LIGHTING_PLANE, + CAMERA_STATIC_PLANE, + ATMOS_GROUP_PLANE, + FULLSCREEN_PLANE, + RUNECHAT_PLANE, + HUD_PLANE, + ABOVE_HUD_PLANE, + ) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 3ebbafcc3db..d74a6f06676 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -176,6 +176,7 @@ GLOBAL_PROTECT(admin_verbs_debug) /client/proc/set_dynex_scale, /client/proc/cmd_display_del_log, /client/proc/outfit_manager, + /client/proc/open_colorblind_test, /client/proc/generate_wikichem_list, /client/proc/modify_goals, /client/proc/debug_huds, diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index 1766af12483..f5b1bcfd848 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -32,6 +32,7 @@ GLOBAL_PROTECT(href_token) var/deadmined var/datum/filter_editor/filteriffic + var/datum/colorblind_tester/color_test = new /// Whether or not the user tried to connect, but was blocked by 2FA var/blocked_by_2fa = FALSE diff --git a/code/modules/admin/verbs/color_blind_test.dm b/code/modules/admin/verbs/color_blind_test.dm new file mode 100644 index 00000000000..5640149cd0a --- /dev/null +++ b/code/modules/admin/verbs/color_blind_test.dm @@ -0,0 +1,73 @@ +/// Used to test the game for issues with different types of color blindness +/// WARNING ASSHOLE: Because we can only apply matrixes, and can't preform gamma correction +/// https://web.archive.org/web/20220227030606/https://ixora.io/projects/colorblindness/color-blindness-simulation-research/ +/// The results of this tool aren't perfect. It's way better then nothing, but IT IS NOT A PROPER SIMULATION +/// Please do not make us look like assholes by assuming it is. Thanks. +/datum/colorblind_tester + /// List of simulated blindness -> matrix to use + /// Most of these matrixes are based off https://web.archive.org/web/20220227030606/https://ixora.io/projects/colorblindness/color-blindness-simulation-research/ + /// AGAIN, THESE ARE NOT PERFECT BECAUSE WE CANNOT COMPUTE GAMMA CORRECTION, AND CONVERT SRGB TO LINEAR RGB + /// Do not assume this is absolute + var/list/color_matrixes = list( + "Protanopia" = list(0.56,0.43,0,0, 0.55,0.44,0,0, 0,0.24,0.75,0, 0,0,0,1, 0,0,0,0), + "Deuteranopia" = list(0.62,0.37,0,0, 0.70,0.30,0,0, 0,0.30,0.70,0, 0,0,0,1, 0,0,0,0), + "Tritanopia" = list(0.95,0.5,0,0, 0,0.43,0.56,0, 0,0.47,0.52,0, 0,0,0,1, 0,0,0,0), + "Achromatopsia" = list(0.33,0.33,0.33,0, 0.33,0.33,0.33,0, 0.33,0.33,0.33,0, 0,0,0,1, 0,0,0,0), + ) + var/list/descriptions = list( + "Protanopia" = "No long wavelength cones, ends up not being able to see red light. Troubles with blue/green and red/green", + "Deuteranopia" = "No medium wavelength cones. Because the red and green parts of light nearly overlap in this space, trouble is mostly with red/green", + "Tritanopia" = "No short wavelength cones, so trouble with blue/green and yellow/violet. Aggressively rare, and equally hard to simulate", + "Achromatopsia" = "No cones at all, which leads to something close to monochromatic vision" + ) + var/selected_type = "" + +/datum/colorblind_tester/ui_state(mob/user) + return GLOB.admin_state + +/datum/colorblind_tester/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ColorBlindTester") + ui.open() + +/datum/colorblind_tester/ui_data() + var/list/data = list() + data["details"] = descriptions + data["selected"] = selected_type + return data + +/datum/colorblind_tester/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/datum/hud/our_hud = ui.user?.hud_used + if(!our_hud) // Nothing to act on + return + + switch(action) + if("set_matrix") + set_selected_type(params["name"], our_hud) + return TRUE + if("clear_matrix") + set_selected_type("", our_hud) + return TRUE + +/datum/colorblind_tester/proc/set_selected_type(selected, datum/hud/remove_from) + var/atom/movable/plane_master_controller/colorblind_plane = remove_from.plane_master_controllers[PLANE_MASTERS_COLORBLIND] + // This is dumb, but well + // The parralax plane has a blend mode of 4, or BLEND_MULTIPLY + // It's like that so it is properly masked by darkness and such + // The problem is blend modes apply to filters like this too + // So I need to manually set and reset its blendmode to allow for proper shading of the background + // Sorry... + var/atom/movable/screen/plane_master/parralax = colorblind_plane.controlled_planes["[PLANE_SPACE_PARALLAX]"] + if(selected_type) + colorblind_plane.remove_filter(selected_type) + parralax.blend_mode = initial(parralax.blend_mode) + selected_type = selected + if(selected_type) + var/list/matrix = color_matrixes[selected_type] + colorblind_plane.add_filter(selected_type, 0, color_matrix_filter(matrix)) + parralax.blend_mode = BLEND_DEFAULT diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 8dd56c898ea..a6f87aee54f 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -601,6 +601,15 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that usr << browse(replacetext(SSatoms.InitLog(), "\n", "
"), "window=initlog") +/client/proc/open_colorblind_test() + set category = "Debug" + set name = "Colorblind Testing" + set desc = "Change your view to a budget version of colorblindness to test for usability" + + if(!holder) + return + holder.color_test.ui_interact(mob) + /client/proc/debug_huds(i as num) set category = "Debug" set name = "Debug HUDs" diff --git a/tgstation.dme b/tgstation.dme index 27a3e99bba2..ca221d51901 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1909,6 +1909,7 @@ #include "code\modules\admin\verbs\borgpanel.dm" #include "code\modules\admin\verbs\BrokenInhands.dm" #include "code\modules\admin\verbs\cinematic.dm" +#include "code\modules\admin\verbs\color_blind_test.dm" #include "code\modules\admin\verbs\commandreport.dm" #include "code\modules\admin\verbs\deadsay.dm" #include "code\modules\admin\verbs\debug.dm" diff --git a/tgui/packages/tgui/interfaces/ColorBlindTester.js b/tgui/packages/tgui/interfaces/ColorBlindTester.js new file mode 100644 index 00000000000..76a1faac965 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ColorBlindTester.js @@ -0,0 +1,85 @@ +import { useBackend } from '../backend'; +import { Box, Button, NoticeBox, Section } from '../components'; +import { Window } from '../layouts'; + +export const ColorBlindTester = (props, context) => { + const { act, data } = useBackend(context); + const { details } = data; + return ( + + + + + HEY FUCKOS, these filters are based off VERY OLD and VERY FLAWED + matrixes. + + + There is NO GOOD WAY to do proper color blind simulation in + BYOND, because we have no way to extract the gamma of a pixel + without iterating all pixels on the screen, which we need to do to + properly correct for the human eye. + + + Because of this, this simulation is very imperfect. You will notice + things are much more bright then they should be. This is a direct + result of not being able to correct for gamma. + + + This tool exists so we have at least some form of baseline for + accessability, it is nowhere near gospel. + + + If I find you being a dick to someone over this I will clobber you + with a crowbar + + +
+ {Object.keys(details).map((category) => ( + + ))} +
+
+
+ ); +}; + +const ColorBlindCategory = (props, context) => { + const { act, data } = useBackend(context); + const { category } = props; + const { details, selected } = data; + if (category !== selected) { + return ( +
act("set_matrix", { + name: category, + })} /> + )}> + {details[category]} +
+ ); + } + return ( +
act("clear_matrix")} + /> + )}> + {details[category]} +
+ ); +};