diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index ee1ebd0cfe1..59af9d98210 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -488,3 +488,13 @@ GLOBAL_LIST_INIT(heretic_path_to_color, list( #define EYE_COLOR_WEED_PRIORITY 20 #define EYE_COLOR_LUMINESCENT_PRIORITY 30 #define EYE_COLOR_CULT_PRIORITY 40 + +// Client color priorities + +#define CLIENT_COLOR_GLASSES_PRIORITY 1 // Lowest there is, used by glasses +#define CLIENT_COLOR_HELMET_PRIORITY 2 // Same but for helmets +#define CLIENT_COLOR_ORGAN_PRIORITY 3 // For heads and organs +#define CLIENT_COLOR_FILTER_PRIORITY 4 // Filters which should go ontop of previous ones +#define CLIENT_COLOR_TEMPORARY_PRIORITY 5 // Temporary flashing effects +#define CLIENT_COLOR_IMPORTANT_PRIORITY 6 // Gameplay important hints signifying antag status or near-death, should be always shown +#define CLIENT_COLOR_OVERRIDE_PRIORITY 7 // For effects that are meant to mask all others for technical reasons diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index 21a5f00e31b..f333318c94e 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -231,3 +231,7 @@ /// Orders cameras by their `c_tag` ascending /proc/cmp_camera_ctag_asc(obj/machinery/camera/a, obj/machinery/camera/b) return sorttext(b.c_tag, a.c_tag) + +/// Sorts client colors based on their priority +/proc/cmp_client_colours(datum/client_colour/first_color, datum/client_colour/second_color) + return second_color.priority - first_color.priority diff --git a/code/__HELPERS/colors.dm b/code/__HELPERS/colors.dm index 28677669768..8e9ac7def5b 100644 --- a/code/__HELPERS/colors.dm +++ b/code/__HELPERS/colors.dm @@ -47,6 +47,8 @@ var/list/color = rgb2num(HTMLstring) return rgb(255 - color[1], 255 - color[2], 255 - color[3]) +#define TEMP_COLOR_SOURCE "temp_flash" + ///Flash a color on the passed mob /proc/flash_color(mob_or_client, flash_color=COLOR_CULT_RED, flash_time=20) var/mob/flashed_mob @@ -60,11 +62,13 @@ return var/datum/client_colour/temp/temp_color = new(flashed_mob) - temp_color.colour = flash_color + temp_color.color = flash_color temp_color.fade_in = flash_time * 0.25 temp_color.fade_out = flash_time * 0.25 QDEL_IN(temp_color, (flash_time * 0.5) + 1) - flashed_mob.add_client_colour(temp_color) + flashed_mob.add_client_colour(temp_color, TEMP_COLOR_SOURCE) + +#undef TEMP_COLOR_SOURCE /// Blends together two colors (passed as 3 or 4 length lists) using the screen blend mode /// Much like multiply, screen effects the brightness of the resulting color diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm index 346ef4d64f8..4cc71bb091b 100644 --- a/code/__HELPERS/spatial_info.dm +++ b/code/__HELPERS/spatial_info.dm @@ -26,6 +26,7 @@ alerts = null screens = null client_colours = null + color_filter_store = null hud_possible = null /// references to everything "on" the turf we are assigned to, that we care about. populated in assign() and cleared in unassign(). /// movables iside of other movables count as being "on" if they have get_turf(them) == our turf. intentionally not a lazylist diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm index 2af37fa13a8..846869901d6 100644 --- a/code/datums/brain_damage/mild.dm +++ b/code/datums/brain_damage/mild.dm @@ -280,11 +280,11 @@ lose_text = span_notice("The world feels bright and colorful again.") /datum/brain_trauma/mild/color_blindness/on_gain() - owner.add_client_colour(/datum/client_colour/monochrome/colorblind) + owner.add_client_colour(/datum/client_colour/monochrome, TRAUMA_TRAIT) return ..() /datum/brain_trauma/mild/color_blindness/on_lose(silent) - owner.remove_client_colour(/datum/client_colour/monochrome/colorblind) + owner.remove_client_colour(TRAUMA_TRAIT) return ..() /datum/brain_trauma/mild/possessive diff --git a/code/datums/components/echolocation.dm b/code/datums/components/echolocation.dm index 4fda54ac0f5..2600d77d7ba 100644 --- a/code/datums/components/echolocation.dm +++ b/code/datums/components/echolocation.dm @@ -16,7 +16,7 @@ /// This trait blocks us from receiving echolocation. var/blocking_trait /// Ref of the client color we give to the echolocator. - var/client_color + var/client_colour /// Associative list of receivers to lists of atoms they are rendering (those atoms are associated to data of the image and time they were rendered at). var/list/receivers = list() /// All the saved appearances, keyed by icon-icon_state. @@ -55,10 +55,10 @@ src.images_are_static = images_are_static if(!isnull(blocking_trait)) src.blocking_trait = blocking_trait - if(ispath(color_path)) - client_color = echolocator.add_client_colour(color_path) src.echo_group = echo_group || REF(src) - echolocator.add_traits(list(TRAIT_ECHOLOCATION_RECEIVER, TRAIT_TRUE_NIGHT_VISION), echo_group) //so they see all the tiles they echolocated, even if they are in the dark + if(ispath(color_path)) + client_colour = echolocator.add_client_colour(color_path, src.echo_group) + echolocator.add_traits(list(TRAIT_ECHOLOCATION_RECEIVER, TRAIT_TRUE_NIGHT_VISION), src.echo_group) //so they see all the tiles they echolocated, even if they are in the dark echolocator.become_blind(ECHOLOCATION_TRAIT) echolocator.overlay_fullscreen("echo", /atom/movable/screen/fullscreen/echo, echo_icon) START_PROCESSING(SSfastprocess, src) @@ -66,7 +66,7 @@ /datum/component/echolocation/Destroy(force) STOP_PROCESSING(SSfastprocess, src) var/mob/living/echolocator = parent - QDEL_NULL(client_color) + QDEL_NULL(client_colour) echolocator.remove_traits(list(TRAIT_ECHOLOCATION_RECEIVER, TRAIT_TRUE_NIGHT_VISION), echo_group) echolocator.cure_blind(ECHOLOCATION_TRAIT) echolocator.clear_fullscreen("echo") diff --git a/code/datums/components/manual_heart.dm b/code/datums/components/manual_heart.dm index d8d74854900..fb815cdfdbb 100644 --- a/code/datums/components/manual_heart.dm +++ b/code/datums/components/manual_heart.dm @@ -69,7 +69,7 @@ to_chat(parent, span_userdanger("You feel your heart start beating normally again!")) var/mob/living/carbon/carbon_parent = parent if(istype(carbon_parent)) - carbon_parent.remove_client_colour(/datum/client_colour/manual_heart_blood) + carbon_parent.remove_client_colour(REF(src)) /datum/component/manual_heart/proc/restart() SIGNAL_HANDLER @@ -85,7 +85,7 @@ pump_action.build_all_button_icons(UPDATE_BUTTON_STATUS) var/mob/living/carbon/carbon_parent = parent if(istype(carbon_parent)) - carbon_parent.remove_client_colour(/datum/client_colour/manual_heart_blood) //prevents red overlay from getting stuck + carbon_parent.remove_client_colour(REF(src)) //prevents red overlay from getting stuck STOP_PROCESSING(SSdcs, src) /// Worker proc that checks logic for if a pump can happen, and applies effects from doing so @@ -98,7 +98,7 @@ if(HAS_TRAIT(carbon_owner, TRAIT_NOBLOOD)) return carbon_owner.blood_volume = min(carbon_owner.blood_volume + (blood_loss * 0.5), BLOOD_VOLUME_MAXIMUM) - carbon_owner.remove_client_colour(/datum/client_colour/manual_heart_blood) + carbon_owner.remove_client_colour(REF(src)) add_colour = TRUE carbon_owner.adjustBruteLoss(-heal_brute) carbon_owner.adjustFireLoss(-heal_burn) @@ -119,7 +119,7 @@ to_chat(carbon_parent, span_userdanger("You have to keep pumping your blood!")) COOLDOWN_START(src, heart_timer, MANUAL_HEART_GRACE_PERIOD) //give two full seconds before losing more blood if(add_colour) - carbon_parent.add_client_colour(/datum/client_colour/manual_heart_blood) + carbon_parent.add_client_colour(/datum/client_colour/manual_heart_blood, REF(src)) add_colour = FALSE ///If a new heart is added, start processing. @@ -134,7 +134,7 @@ pump_action.build_all_button_icons(UPDATE_BUTTON_STATUS) var/mob/living/carbon/carbon_parent = parent if(istype(carbon_parent)) - carbon_parent.remove_client_colour(/datum/client_colour/manual_heart_blood) //prevents red overlay from getting stuck + carbon_parent.remove_client_colour(REF(src)) //prevents red overlay from getting stuck START_PROCESSING(SSdcs, src) ///If the heart is removed, stop processing. diff --git a/code/datums/elements/wearable_client_colour.dm b/code/datums/elements/wearable_client_colour.dm index 8757dd1098c..d2fde7cffc4 100644 --- a/code/datums/elements/wearable_client_colour.dm +++ b/code/datums/elements/wearable_client_colour.dm @@ -6,6 +6,8 @@ var/datum/client_colour/colour_type ///The slot(s) that enable the client colour var/equip_slots = NONE + ///Source for the client colour + var/colour_source ///For items that want costumizable client colours var/custom_colour ///if forced is false, we check that the user has the TRAIT_SEE_WORN_COLOURS before adding the colour. @@ -13,7 +15,7 @@ ///On examine, it'll tell which you have to press to toggle TRAIT_SEE_WORN_COLOURS. var/key_info = "Figure it out yourself how" -/datum/element/wearable_client_colour/Attach(obj/item/target, colour_type, equip_slots, custom_colour, forced = FALSE, comsig_toggle = COMSIG_CLICK_ALT) +/datum/element/wearable_client_colour/Attach(obj/item/target, colour_type, equip_slots, colour_source, custom_colour, forced = FALSE, comsig_toggle = COMSIG_CLICK_ALT) . = ..() if(!isitem(target)) return ELEMENT_INCOMPATIBLE @@ -23,6 +25,7 @@ src.colour_type = colour_type src.equip_slots = equip_slots + src.colour_source = colour_source src.custom_colour = custom_colour src.forced = forced @@ -90,19 +93,19 @@ var/datum/client_colour/colour_to_add = colour_type if(custom_colour) colour_to_add = new colour_to_add - colour_to_add.colour = custom_colour - equipper.add_client_colour(colour_to_add) + colour_to_add.color = custom_colour + equipper.add_client_colour(colour_to_add, colour_source) /datum/element/wearable_client_colour/proc/on_trait_removed(mob/source, trait) SIGNAL_HANDLER - source.remove_client_colour(colour_type) + source.remove_client_colour(colour_source) /datum/element/wearable_client_colour/proc/remove_client_colour(mob/dropper) if(!forced) UnregisterSignal(dropper, list(SIGNAL_ADDTRAIT(TRAIT_SEE_WORN_COLOURS), SIGNAL_REMOVETRAIT(TRAIT_SEE_WORN_COLOURS))) if(!HAS_TRAIT(dropper, TRAIT_SEE_WORN_COLOURS)) return - dropper.remove_client_colour(colour_type) + dropper.remove_client_colour(colour_source) /datum/element/wearable_client_colour/proc/toggle_see_worn_colors(obj/item/source, mob/clicker) SIGNAL_HANDLER diff --git a/code/datums/quirks/neutral_quirks/monochromatic.dm b/code/datums/quirks/neutral_quirks/monochromatic.dm index 6c1b8c2ef78..3295ca321a8 100644 --- a/code/datums/quirks/neutral_quirks/monochromatic.dm +++ b/code/datums/quirks/neutral_quirks/monochromatic.dm @@ -12,7 +12,7 @@ ) /datum/quirk/monochromatic/add(client/client_source) - quirk_holder.add_client_colour(/datum/client_colour/monochrome) + quirk_holder.add_client_colour(/datum/client_colour/monochrome, QUIRK_TRAIT) /datum/quirk/monochromatic/post_add() if(is_detective_job(quirk_holder.mind.assigned_role)) @@ -20,4 +20,4 @@ quirk_holder.playsound_local(quirk_holder, 'sound/ambience/security/ambidet1.ogg', 50, FALSE) /datum/quirk/monochromatic/remove() - quirk_holder.remove_client_colour(/datum/client_colour/monochrome) + quirk_holder.remove_client_colour(QUIRK_TRAIT) diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index f75516c9868..8a82f4fba05 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -436,7 +436,7 @@ owner.log_message("entered a blood frenzy", LOG_ATTACK) to_chat(owner, span_narsiesmall("KILL, KILL, KILL! YOU HAVE NO ALLIES ANYMORE, NO TEAM MATES OR ALLEGIANCES! KILL THEM ALL!")) - var/datum/client_colour/colour = owner.add_client_colour(/datum/client_colour/bloodlust) + var/datum/client_colour/colour = owner.add_client_colour(/datum/client_colour/bloodlust, REF(src)) QDEL_IN(colour, 1.1 SECONDS) return TRUE diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 1d089ddbb39..91577046210 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -574,7 +574,7 @@ return FALSE RegisterSignal(owner, COMSIG_MOVABLE_HEAR, PROC_REF(hypnotize)) ADD_TRAIT(owner, TRAIT_MUTE, TRAIT_STATUS_EFFECT(id)) - owner.add_client_colour(/datum/client_colour/monochrome/trance) + owner.add_client_colour(/datum/client_colour/monochrome, REF(src)) owner.visible_message("[stun ? span_warning("[owner] stands still as [owner.p_their()] eyes seem to focus on a distant point.") : ""]", \ span_warning(pick("You feel your thoughts slow down...", "You suddenly feel extremely dizzy...", "You feel like you're in the middle of a dream...","You feel incredibly relaxed..."))) return TRUE @@ -588,7 +588,7 @@ UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) REMOVE_TRAIT(owner, TRAIT_MUTE, TRAIT_STATUS_EFFECT(id)) owner.remove_status_effect(/datum/status_effect/dizziness) - owner.remove_client_colour(/datum/client_colour/monochrome/trance) + owner.remove_client_colour(REF(src)) to_chat(owner, span_warning("You snap out of your trance!")) /datum/status_effect/trance/get_examine_text() diff --git a/code/datums/status_effects/debuffs/vision/blindness.dm b/code/datums/status_effects/debuffs/vision/blindness.dm index c0e5249cad6..caf8e98a2b0 100644 --- a/code/datums/status_effects/debuffs/vision/blindness.dm +++ b/code/datums/status_effects/debuffs/vision/blindness.dm @@ -4,6 +4,8 @@ /// Blindness /datum/status_effect/grouped/blindness + // This is not "remove on fullheal" as in practice, + // fullheal should instead remove all the sources and in turn cure this id = "blindness" tick_interval = STATUS_EFFECT_NO_TICK alert_type = /atom/movable/screen/alert/status_effect/blind @@ -11,37 +13,52 @@ SIGNAL_REMOVETRAIT(TRAIT_SIGHT_BYPASS), SIGNAL_ADDTRAIT(TRAIT_SIGHT_BYPASS), ) - // This is not "remove on fullheal" as in practice, - // fullheal should instead remove all the sources and in turn cure this + /// List of sources which prevent SIGHT_BYPASS from working + var/static/list/blocking_sources = list( + QUIRK_TRAIT, // Meant to be completely immutable + ECHOLOCATION_TRAIT, // Breaks the UI badly + UNCONSCIOUS_TRAIT, // Duh + ) /datum/status_effect/grouped/blindness/on_apply() - if(!CAN_BE_BLIND(owner)) + if (!CAN_BE_BLIND(owner)) return FALSE RegisterSignals(owner, update_signals, PROC_REF(update_blindness)) - update_blindness() - return ..() +/datum/status_effect/grouped/blindness/source_added(source, ...) + update_blindness() + +/datum/status_effect/grouped/blindness/source_removed(source, removing) + if (!removing) + update_blindness() + /datum/status_effect/grouped/blindness/proc/update_blindness() - if(!CAN_BE_BLIND(owner)) // future proofing + if (!CAN_BE_BLIND(owner)) // future proofing qdel(src) return - if(HAS_TRAIT(owner, TRAIT_SIGHT_BYPASS)) - make_unblind() + if (!HAS_TRAIT(owner, TRAIT_SIGHT_BYPASS)) + make_blind() return - make_blind() + + for (var/blocker in blocking_sources) + if (owner.is_blind_from(blocker)) + make_blind() + return + + make_unblind() /datum/status_effect/grouped/blindness/proc/make_blind() owner.overlay_fullscreen(id, /atom/movable/screen/fullscreen/blind) // You are blind - at most, able to make out shapes near you - owner.add_client_colour(/datum/client_colour/monochrome/blind) + owner.add_client_colour(/datum/client_colour/monochrome, REF(src)) /datum/status_effect/grouped/blindness/proc/make_unblind() owner.clear_fullscreen(id) - owner.remove_client_colour(/datum/client_colour/monochrome/blind) + owner.remove_client_colour(REF(src)) /datum/status_effect/grouped/blindness/on_remove() make_unblind() diff --git a/code/modules/client/client_colour.dm b/code/modules/client/client_colour.dm index 08e79c305a4..2bee4dda956 100644 --- a/code/modules/client/client_colour.dm +++ b/code/modules/client/client_colour.dm @@ -1,35 +1,21 @@ -#define PRIORITY_ABSOLUTE 1 -#define PRIORITY_HIGH 10 -#define PRIORITY_NORMAL 100 -#define PRIORITY_LOW 1000 +#define CLIENT_COLOR_VALUE_INDEX 1 +#define CLIENT_COLOR_PRIORITY_INDEX 2 -/** - * Client Colour Priority System By RemieRichards (then refactored by another contributor) - * A System that gives finer control over which client.colour value to display on screen - * so that the "highest priority" one is always displayed as opposed to the default of - * "whichever was set last is displayed". - * - * Refactored to allow multiple overlapping client colours - * (e.g. wearing blue glasses under a yellow visor, even though the result is a little unsatured.) - * As well as some support for animated colour transitions. - * - * Define subtypes of this datum - */ /datum/client_colour - ///The color we want to give to the client. This has to be either a hexadecimal color or a color matrix. - var/colour - ///The mob that owns this client_colour. + /// Color given to the client, can be a hex color, color matrix or a filter + var/color + /// The mob that owns this client_colour var/mob/owner - /** - * We prioritize colours with higher priority (lower numbers), so they don't get overriden by less important ones: - * eg: "Bloody screen" > "goggles colour" as the former is much more important - */ - var/priority = PRIORITY_NORMAL - ///Will this client_colour prevent ones of lower priority from being applied? + /// Priority of this color, higher values are rendered above lower ones + var/priority = CLIENT_COLOR_FILTER_PRIORITY + /// Will this client_colour prevent ones of lower priority from being applied? var/override = FALSE - ///IF non-zero, 'animate_client_colour(fade_in)' will be called instead of 'update_client_colour' when added. + /// If set to TRUE, all colors below and above this one will be rendered in separate filters + /// If color is a filter, forced to TRUE + var/split_filters = FALSE + /// If non-zero, 'animate_client_colour(fade_in)' will be called instead of 'update_client_colour' when added. var/fade_in = 0 - ///Same as above, but on removal. + /// If non-zero, 'animate_client_colour(fade_out)' will be called instead of 'update_client_colour' when removed. var/fade_out = 0 /datum/client_colour/New(mob/owner) @@ -42,229 +28,248 @@ owner = null return ..() -///Sets a new colour, then updates the owner's screen colour. -/datum/client_colour/proc/update_colour(new_colour, anim_time, easing = 0) - colour = new_colour +///Sets a new color, then updates the owner's screen color. +/datum/client_colour/proc/update_color(new_color, anim_time, easing = 0) + color = new_color owner.animate_client_colour(anim_time, easing) /** - * Adds an instance of colour_type to the mob's client_colours list - * colour_type - a typepath (subtyped from /datum/client_colour) + * Add a color filter to the client + * new_color - client_colour datum or typepath to be added + * source - associated source for the client color + * force - if TRUE, colors of the same source will be replaced even if it is of the same type */ -/mob/proc/add_client_colour(colour_type_or_datum) - if(QDELING(src)) +/mob/proc/add_client_colour(datum/client_colour/new_color, source, force = FALSE) + if (QDELING(src)) return - var/datum/client_colour/colour - if(istype(colour_type_or_datum, /datum/client_colour)) - colour = colour_type_or_datum - else if(ispath(colour_type_or_datum, /datum/client_colour)) - colour = new colour_type_or_datum(src) - else - CRASH("Invalid colour type or datum for add_client_color: [colour_type_or_datum || "null"]") - BINARY_INSERT(colour, client_colours, /datum/client_colour, colour, priority, COMPARE_KEY) - animate_client_colour(colour.fade_in) - return colour + if (ispath(new_color)) + new_color = new new_color(src) + + if (!istype(new_color)) + CRASH("Invalid color type or datum for add_client_colour: [new_color ? "[new_color] ([new_color.type])" : "null"]") + + // Ensure that if a color with this source is already present, we either abort or get rid of it + var/datum/client_colour/existing_color = get_client_colour(source) + if (existing_color) + if (existing_color.type == new_color.type && !force) + return existing_color + qdel(existing_color) + client_colours[new_color] = source + animate_client_colour(new_color.fade_in) + return new_color /** - * Removes an instance of colour_type from the mob's client_colours list - * colour_type - a typepath (subtyped from /datum/client_colour) - */ -/mob/proc/remove_client_colour(colour_type) - if(!ispath(colour_type, /datum/client_colour)) - return + * Removes a color type from a specific source from mob's client_colours list + * source - color source to remove +*/ - for(var/datum/client_colour/colour as anything in client_colours) - if(colour.type == colour_type) - qdel(colour) +/mob/proc/remove_client_colour(source) + var/datum/client_colour/existing_color = get_client_colour(source) + if (!existing_color) + return FALSE + qdel(existing_color) + return TRUE + +/mob/proc/get_client_colour(source) + for(var/datum/client_colour/color as anything in client_colours) + if (client_colours[color] == source) + return color + +/mob/proc/get_client_colour_filters() + . = list() + // sortTim sorts the passed list instead of making the copy, and so does reverse_range + var/list/used_colors = reverse_range(sortTim(client_colours.Copy(), GLOBAL_PROC_REF(cmp_client_colours))) + var/current_color = null + var/color_num = 0 + var/color_prio = 1 + + for (var/datum/client_colour/client_color as anything in used_colors) + color_num += 1 + + var/list/filter_color = null + if (islist(client_color.color)) + filter_color = client_color.color + // If our list has "type" in it then its a filter + if (!filter_color["type"]) + filter_color = null + + if (client_color.split_filters || filter_color) + if (current_color) + . += list(list(color_matrix_filter(current_color), color_prio)) + color_prio += 1 + current_color = null + + . += list(list(filter_color || color_matrix_filter(client_color.color), color_prio)) + color_prio += 1 + continue + + if (!current_color) + current_color = client_color.color + if (client_color.override) + break + continue + + var/list/color_list = current_color + if (!islist(color_list)) + color_list = color_to_full_rgba_matrix(color_list) + var/list/cur_list = color_to_full_rgba_matrix(client_color.color) + + for (var/i in 1 to 20) + color_list[i] = (color_list[i] * (color_num - 1) + cur_list[i]) / color_num + current_color = color_list + + if (client_color.override) break -/** - * Gets the resulting colour/tone from client_colours. - * In the case of multiple colours, they'll be converted to RGBA matrices for compatibility, - * summed together, and then each element divided by the number of matrices. (except we do this with lists because byond) - * target is the target variable. - */ -#define MIX_CLIENT_COLOUR(target)\ - var/_our_colour;\ - var/_number_colours = 0;\ - var/_pool_closed = INFINITY;\ - for(var/_c in client_colours){\ - var/datum/client_colour/_colour = _c;\ - if(_pool_closed < _colour.priority){\ - break\ - };\ - _number_colours++;\ - if(_colour.override){\ - _pool_closed = _colour.priority\ - };\ - if(!_our_colour){\ - _our_colour = _colour.colour;\ - continue\ - };\ - if(_number_colours == 2){\ - _our_colour = color_to_full_rgba_matrix(_our_colour)\ - };\ - var/list/_colour_matrix = color_to_full_rgba_matrix(_colour.colour);\ - var/list/_L = _our_colour;\ - for(var/_i in 1 to 20){\ - _L[_i] += _colour_matrix[_i]\ - };\ - };\ - if(_number_colours > 1){\ - var/list/_L = _our_colour;\ - for(var/_i in 1 to 20){\ - _L[_i] /= _number_colours\ - };\ - };\ - target = _our_colour\ + if (current_color) + . += list(list(color_matrix_filter(current_color), color_prio)) -#define CLIENT_COLOR_FILTER_KEY "fake_client_color" - -/** - * Resets the mob's client.color to null, and then reapplies a new color based - * on the client_colour datums it currently has. - */ /mob/proc/update_client_colour() - if(isnull(hud_used)) + if (isnull(hud_used)) return - var/new_color = "" - if(length(client_colours)) - MIX_CLIENT_COLOUR(new_color) + for (var/atom/movable/screen/plane_master/game_plane as anything in hud_used.get_true_plane_masters(RENDER_PLANE_GAME)) + for (var/filter_id in color_filter_store) + game_plane.remove_filter(filter_id) - for(var/atom/movable/screen/plane_master/game_plane as anything in hud_used.get_true_plane_masters(RENDER_PLANE_GAME)) - if(new_color) - game_plane.add_filter(CLIENT_COLOR_FILTER_KEY, 2, color_matrix_filter(new_color)) - else - game_plane.remove_filter(CLIENT_COLOR_FILTER_KEY) + color_filter_store.Cut() + var/list/applied_filters = get_client_colour_filters() -///Works similarly to 'update_client_colour', but animated. -/mob/proc/animate_client_colour(anim_time = 2 SECONDS, anim_easing = NONE) - if(anim_time <= 0) + for (var/list/color_filter as anything in applied_filters) + var/added_color = color_filter[CLIENT_COLOR_VALUE_INDEX] + var/filter_priority = color_filter[CLIENT_COLOR_PRIORITY_INDEX] + for (var/atom/movable/screen/plane_master/game_plane as anything in hud_used.get_true_plane_masters(RENDER_PLANE_GAME)) + var/filter_id = "client_colour_[filter_priority]" + game_plane.add_filter(filter_id, filter_priority, added_color) + color_filter_store |= filter_id + +/// Works similarly to 'update_client_colour', but animated. +/mob/proc/animate_client_colour(anim_time = 1 SECONDS, anim_easing = NONE) + if (isnull(hud_used)) + return + + if(anim_time <= -1) return update_client_colour() - if(isnull(hud_used)) - return - var/anim_color = "" - if(length(client_colours)) - MIX_CLIENT_COLOUR(anim_color) + for (var/atom/movable/screen/plane_master/game_plane as anything in hud_used.get_true_plane_masters(RENDER_PLANE_GAME)) + for (var/filter_id in color_filter_store) + game_plane.remove_filter(filter_id) - for(var/atom/movable/screen/plane_master/game_plane as anything in hud_used.get_true_plane_masters(RENDER_PLANE_GAME)) - if(anim_color) - game_plane.add_filter(CLIENT_COLOR_FILTER_KEY, 2, color_matrix_filter()) - game_plane.transition_filter(CLIENT_COLOR_FILTER_KEY, color_matrix_filter(anim_color), anim_time, anim_easing) - else - game_plane.transition_filter(CLIENT_COLOR_FILTER_KEY, color_matrix_filter(), anim_time, anim_easing) - // This leaves a blank color filter on the hud which is, fine I guess? + color_filter_store.Cut() + var/list/applied_filters = get_client_colour_filters() -#undef MIX_CLIENT_COLOUR + for (var/list/color_filter as anything in applied_filters) + var/added_color = color_filter[CLIENT_COLOR_VALUE_INDEX] + var/filter_priority = color_filter[CLIENT_COLOR_PRIORITY_INDEX] + for (var/atom/movable/screen/plane_master/game_plane as anything in hud_used.get_true_plane_masters(RENDER_PLANE_GAME)) + var/filter_id = "client_colour_[filter_priority]" + game_plane.add_filter(filter_id, filter_priority, color_matrix_filter()) + game_plane.transition_filter(filter_id, added_color, anim_time, anim_easing) + color_filter_store |= filter_id -#undef CLIENT_COLOR_FILTER_KEY +// Color types -/datum/client_colour/glass_colour - priority = PRIORITY_LOW - -/datum/client_colour/glass_colour/green - colour = "#aaffaa" - -/datum/client_colour/glass_colour/lightgreen - colour = "#ccffcc" - -/datum/client_colour/glass_colour/blue - colour = "#aaaaff" - -/datum/client_colour/glass_colour/lightblue - colour = "#ccccff" - -/datum/client_colour/glass_colour/yellow - colour = "#ffff66" - -/datum/client_colour/glass_colour/lightyellow - colour = "#ffffaa" - -/datum/client_colour/glass_colour/red - colour = "#ffaaaa" - -/datum/client_colour/glass_colour/lightred - colour = "#ffcccc" - -/datum/client_colour/glass_colour/darkred - colour = "#bb5555" - -/datum/client_colour/glass_colour/orange - colour = "#ffbb99" - -/datum/client_colour/glass_colour/lightorange - colour = "#ffddaa" - -/datum/client_colour/glass_colour/purple - colour = "#ff99ff" - -/datum/client_colour/glass_colour/lightpurple - colour = "#ffccff" - -/datum/client_colour/glass_colour/gray - colour = "#cccccc" - -///A client colour that makes the screen look a bit more grungy, halloweenesque even. +///A client color that makes the screen look a bit more grungy, halloweenesque even. /datum/client_colour/halloween_helmet - colour = list(0.75,0.13,0.13,0, 0.13,0.7,0.13,0, 0.13,0.13,0.75,0, -0.06,-0.09,-0.08,1, 0,0,0,0) + priority = CLIENT_COLOR_HELMET_PRIORITY + color = list(/*R*/ 0.75,0.13,0.13,0, /*G*/ 0.13,0.7,0.13,0, /*B*/ 0.13,0.13,0.75,0, /*A*/ -0.06,-0.09,-0.08,1, /*C*/ 0,0,0,0) /datum/client_colour/flash_hood - colour = COLOR_MATRIX_POLAROID - -/datum/client_colour/glass_colour/nightmare - colour = list(255,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, -130,0,0,0) //every color is either red or black - -/datum/client_colour/malfunction - colour = list(/*R*/ 0,0,0,0, /*G*/ 0,175,0,0, /*B*/ 0,0,0,0, /*A*/ 0,0,0,1, /*C*/0,-130,0,0) // Matrix colors + priority = CLIENT_COLOR_HELMET_PRIORITY + color = COLOR_MATRIX_POLAROID /datum/client_colour/perceptomatrix - colour = list(/*R*/ 1,0,0,0, /*G*/ 0,1,0,0, /*B*/ 0,0,1,0, /*A*/ 0,0,0,1, /*C*/0,-0.02,-0.02,0) // veeery slightly pink + priority = CLIENT_COLOR_HELMET_PRIORITY + color = list(/*R*/ 1,0,0,0, /*G*/ 0,1,0,0, /*B*/ 0,0,1,0, /*A*/ 0,0,0,1, /*C*/ 0,-0.02,-0.02,0) // veeery slightly pink + +/datum/client_colour/rave + priority = CLIENT_COLOR_HELMET_PRIORITY + +/datum/client_colour/malfunction + priority = CLIENT_COLOR_ORGAN_PRIORITY + color = list(/*R*/ 0,0,0,0, /*G*/ 0,175,0,0, /*B*/ 0,0,0,0, /*A*/ 0,0,0,1, /*C*/ 0,-130,0,0) // Matrix colors /datum/client_colour/monochrome - colour = COLOR_MATRIX_GRAYSCALE - priority = PRIORITY_HIGH //we can't see colors anyway! - override = TRUE - fade_in = 20 - fade_out = 20 + color = COLOR_MATRIX_GRAYSCALE + priority = CLIENT_COLOR_FILTER_PRIORITY + split_filters = TRUE + fade_in = 2 SECONDS + fade_out = 2 SECONDS -/datum/client_colour/monochrome/colorblind - priority = PRIORITY_HIGH - -/datum/client_colour/monochrome/trance - priority = PRIORITY_NORMAL - -/datum/client_colour/monochrome/blind - priority = PRIORITY_NORMAL +/datum/client_colour/monochrome/glasses + priority = CLIENT_COLOR_GLASSES_PRIORITY /datum/client_colour/bloodlust - priority = PRIORITY_ABSOLUTE // Only anger. - colour = list(0,0,0,0,0,0,0,0,0,1,0,0) //pure red. - fade_out = 10 + priority = CLIENT_COLOR_IMPORTANT_PRIORITY + color = list(0,0,0,0,0,0,0,0,0,1,0,0) // pure red + fade_out = 1 SECONDS /datum/client_colour/bloodlust/New(mob/owner) ..() if(owner) - addtimer(CALLBACK(src, PROC_REF(update_colour), list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0), 10, SINE_EASING|EASE_OUT), 0.1 SECONDS) - -/datum/client_colour/rave - priority = PRIORITY_LOW - -/datum/client_colour/psyker - priority = PRIORITY_ABSOLUTE - override = TRUE - colour = list(0.8,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0) + addtimer(CALLBACK(src, PROC_REF(update_color), list(/*R*/ 1,0,0, /*G*/ 0.8,0.2,0, /*B*/ 0.8,0,0.2, /*C*/ 0.1,0,0), 10, SINE_EASING|EASE_OUT), 0.1 SECONDS) /datum/client_colour/manual_heart_blood - priority = PRIORITY_ABSOLUTE - colour = COLOR_RED + priority = CLIENT_COLOR_IMPORTANT_PRIORITY + color = COLOR_RED + +/datum/client_colour/psyker + priority = CLIENT_COLOR_OVERRIDE_PRIORITY + color = list(0.8,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0) + override = TRUE /datum/client_colour/temp - priority = PRIORITY_HIGH + priority = CLIENT_COLOR_TEMPORARY_PRIORITY -#undef PRIORITY_ABSOLUTE -#undef PRIORITY_HIGH -#undef PRIORITY_NORMAL -#undef PRIORITY_LOW +/datum/client_colour/glass_colour + priority = CLIENT_COLOR_GLASSES_PRIORITY + +/datum/client_colour/glass_colour/green + color = "#aaffaa" + +/datum/client_colour/glass_colour/lightgreen + color = "#ccffcc" + +/datum/client_colour/glass_colour/blue + color = "#aaaaff" + +/datum/client_colour/glass_colour/lightblue + color = "#ccccff" + +/datum/client_colour/glass_colour/yellow + color = "#ffff66" + +/datum/client_colour/glass_colour/lightyellow + color = "#ffffaa" + +/datum/client_colour/glass_colour/red + color = "#ffaaaa" + +/datum/client_colour/glass_colour/lightred + color = "#ffcccc" + +/datum/client_colour/glass_colour/darkred + color = "#bb5555" + +/datum/client_colour/glass_colour/orange + color = "#ffbb99" + +/datum/client_colour/glass_colour/lightorange + color = "#ffddaa" + +/datum/client_colour/glass_colour/purple + color = "#ff99ff" + +/datum/client_colour/glass_colour/lightpurple + color = "#ffccff" + +/datum/client_colour/glass_colour/gray + color = "#cccccc" + +/datum/client_colour/glass_colour/nightmare + color = list(/*R*/ 255,0,0,0, /*G*/ 0,0,0,0, /*B*/ 0,0,0,0, /*A*/ 0,0,0,1, /*C*/ -130,0,0,0) //every color is either red or black + split_filters = TRUE + +#undef CLIENT_COLOR_VALUE_INDEX +#undef CLIENT_COLOR_PRIORITY_INDEX diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 811c6f2bc34..46858f57341 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -30,7 +30,7 @@ /obj/item/clothing/glasses/Initialize(mapload) . = ..() if(glass_colour_type) - AddElement(/datum/element/wearable_client_colour, glass_colour_type, ITEM_SLOT_EYES, forced = forced_glass_color) + AddElement(/datum/element/wearable_client_colour, glass_colour_type, ITEM_SLOT_EYES, GLASSES_TRAIT, forced = forced_glass_color) /obj/item/clothing/glasses/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] is stabbing \the [src] into [user.p_their()] eyes! It looks like [user.p_theyre()] trying to commit suicide!")) @@ -64,10 +64,10 @@ /obj/item/clothing/glasses/proc/change_glass_color(new_color_type) if(glass_colour_type) - RemoveElement(/datum/element/wearable_client_colour, glass_colour_type, ITEM_SLOT_EYES, forced = forced_glass_color) + RemoveElement(/datum/element/wearable_client_colour, glass_colour_type, ITEM_SLOT_EYES, GLASSES_TRAIT, forced = forced_glass_color) glass_colour_type = new_color_type if(glass_colour_type) - AddElement(/datum/element/wearable_client_colour, glass_colour_type, ITEM_SLOT_EYES, forced = forced_glass_color) + AddElement(/datum/element/wearable_client_colour, glass_colour_type, ITEM_SLOT_EYES, GLASSES_TRAIT, forced = forced_glass_color) /obj/item/clothing/glasses/meson name = "optical meson scanner" @@ -442,7 +442,7 @@ /obj/item/clothing/glasses/sunglasses/noir name = "noir glasses" desc = "A pair of sleek, futuristic glasses that allow the wearer to see the world in a different light." - glass_colour_type = /datum/client_colour/monochrome + glass_colour_type = /datum/client_colour/monochrome/glasses forced_glass_color = TRUE ///Syndicate item that upgrades the flash protection of your eyes. diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index 3b74106d436..a5833dc78f7 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -251,9 +251,9 @@ if(isnull(.)) return if(new_value) - AddElement(/datum/element/wearable_client_colour, /datum/client_colour/halloween_helmet, ITEM_SLOT_HEAD, forced = TRUE) + AddElement(/datum/element/wearable_client_colour, /datum/client_colour/halloween_helmet, ITEM_SLOT_HEAD, HELMET_TRAIT, forced = TRUE) else - RemoveElement(/datum/element/wearable_client_colour, /datum/client_colour/halloween_helmet, ITEM_SLOT_HEAD, forced = TRUE) + RemoveElement(/datum/element/wearable_client_colour, /datum/client_colour/halloween_helmet, ITEM_SLOT_HEAD, HELMET_TRAIT, forced = TRUE) update_icon(UPDATE_OVERLAYS) /obj/item/clothing/head/utility/hardhat/pumpkinhead/update_overlays() diff --git a/code/modules/clothing/head/perceptomatrix.dm b/code/modules/clothing/head/perceptomatrix.dm index f3be4abd459..ed45ce0f9e3 100644 --- a/code/modules/clothing/head/perceptomatrix.dm +++ b/code/modules/clothing/head/perceptomatrix.dm @@ -64,7 +64,6 @@ /obj/item/clothing/head/helmet/perceptomatrix/Initialize(mapload) . = ..() - update_appearance(UPDATE_ICON_STATE) update_anomaly_state() AddComponent(/datum/component/adjust_fishing_difficulty, -7) // PSYCHIC FISHING @@ -74,9 +73,11 @@ . = ..() if(slot & ITEM_SLOT_HEAD) RegisterSignal(user, COMSIG_MOB_BEFORE_SPELL_CAST, PROC_REF(pre_cast_core_check)) + user.update_sight() /obj/item/clothing/head/helmet/perceptomatrix/dropped(mob/living/user, silent) UnregisterSignal(user, COMSIG_MOB_BEFORE_SPELL_CAST) + user.update_sight() ..() // Prevent casting the spell w/o the core. @@ -93,7 +94,7 @@ clothing_flags = PERCEPTOMATRIX_INACTIVE_FLAGS detach_clothing_traits(additional_clothing_traits) QDEL_LIST(active_components) - RemoveElement(/datum/element/wearable_client_colour, /datum/client_colour/perceptomatrix, ITEM_SLOT_HEAD, forced = TRUE) + RemoveElement(/datum/element/wearable_client_colour, /datum/client_colour/perceptomatrix, ITEM_SLOT_HEAD, HELMET_TRAIT, forced = TRUE) return clothing_flags = PERCEPTOMATRIX_ACTIVE_FLAGS @@ -107,7 +108,7 @@ antimagic_flags = MAGIC_RESISTANCE_MIND, \ inventory_flags = ITEM_SLOT_HEAD, \ ) - AddElement(/datum/element/wearable_client_colour, /datum/client_colour/perceptomatrix, ITEM_SLOT_HEAD, forced = TRUE) + AddElement(/datum/element/wearable_client_colour, /datum/client_colour/perceptomatrix, ITEM_SLOT_HEAD, HELMET_TRAIT, forced = TRUE) update_icon_state() diff --git a/code/modules/clothing/suits/costume.dm b/code/modules/clothing/suits/costume.dm index 3ef1b1691ca..2b35592f06d 100644 --- a/code/modules/clothing/suits/costume.dm +++ b/code/modules/clothing/suits/costume.dm @@ -23,7 +23,7 @@ /obj/item/clothing/head/hooded/flashsuit/Initialize(mapload) . = ..() - AddElement(/datum/element/wearable_client_colour, /datum/client_colour/flash_hood, ITEM_SLOT_HEAD, forced = TRUE) + AddElement(/datum/element/wearable_client_colour, /datum/client_colour/flash_hood, ITEM_SLOT_HEAD, HELMET_TRAIT, forced = TRUE) /obj/item/clothing/suit/costume/pirate name = "pirate coat" diff --git a/code/modules/mining/lavaland/mining_loot/megafauna/bubblegum.dm b/code/modules/mining/lavaland/mining_loot/megafauna/bubblegum.dm index c77964cfc44..c16c58dc282 100644 --- a/code/modules/mining/lavaland/mining_loot/megafauna/bubblegum.dm +++ b/code/modules/mining/lavaland/mining_loot/megafauna/bubblegum.dm @@ -121,7 +121,7 @@ var/health_consumed = butchered.maxHealth * 0.1 user.heal_ordered_damage(health_consumed, list(BRUTE, BURN, TOX)) to_chat(user, span_notice("You heal from the corpse of [butchered].")) - var/datum/client_colour/color_effect = user.add_client_colour(/datum/client_colour/bloodlust) + var/datum/client_colour/color_effect = user.add_client_colour(/datum/client_colour/bloodlust, HELMET_TRAIT) QDEL_IN(color_effect, 1 SECONDS) // Soulscythe diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 7ea6966b84d..2fb966cd061 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -184,7 +184,10 @@ /// On [/mob] so clientless mobs will throw alerts properly. var/list/alerts = list() var/list/screens = list() + /// Assoc list of client_colour datum -> source it came from var/list/client_colours = list() + /// List of filter names used in the past client color update for cleanup + var/list/color_filter_store = list() var/hud_type = /datum/hud var/datum/focus //What receives our keyboard inputs. src by default diff --git a/code/modules/mod/modules/modules_maint.dm b/code/modules/mod/modules/modules_maint.dm index f1b9154358b..989481af76c 100644 --- a/code/modules/mod/modules/modules_maint.dm +++ b/code/modules/mod/modules/modules_maint.dm @@ -135,8 +135,8 @@ return ..() /obj/item/mod/module/visor/rave/on_activation() - rave_screen = mod.wearer.add_client_colour(/datum/client_colour/rave) - rave_screen.update_colour(rainbow_order[rave_number]) + rave_screen = mod.wearer.add_client_colour(/datum/client_colour/rave, REF(src)) + rave_screen.update_color(rainbow_order[rave_number]) music_player.start_music(mod.wearer) /obj/item/mod/module/visor/rave/on_deactivation(display_message = TRUE, deleting = FALSE) @@ -161,7 +161,7 @@ if(rave_number > length(rainbow_order)) rave_number = 1 mod.wearer.update_clothing(mod.slot_flags) - rave_screen.update_colour(rainbow_order[rave_number]) + rave_screen.update_color(rainbow_order[rave_number]) /obj/item/mod/module/visor/rave/get_configuration() . = ..() diff --git a/code/modules/research/xenobiology/crossbreeding/_clothing.dm b/code/modules/research/xenobiology/crossbreeding/_clothing.dm index 5f92ec2cb55..91f13560f2f 100644 --- a/code/modules/research/xenobiology/crossbreeding/_clothing.dm +++ b/code/modules/research/xenobiology/crossbreeding/_clothing.dm @@ -44,7 +44,7 @@ Slimecrossing Armor /obj/item/clothing/glasses/prism_glasses/Initialize(mapload) . = ..() - AddElement(/datum/element/wearable_client_colour, /datum/client_colour/glass_colour, ITEM_SLOT_EYES, glasses_color, forced_glass_color) + AddElement(/datum/element/wearable_client_colour, /datum/client_colour/glass_colour, ITEM_SLOT_EYES, GLASSES_TRAIT, glasses_color, forced_glass_color) /obj/structure/light_prism name = "light prism" @@ -76,9 +76,9 @@ Slimecrossing Armor var/new_color = input(owner, "Choose the lens color:", "Color change",glasses.glasses_color) as color|null if(!new_color) return - RemoveElement(/datum/element/wearable_client_colour, /datum/client_colour/glass_colour, ITEM_SLOT_EYES, glasses.glasses_color, glasses.forced_glass_color) + RemoveElement(/datum/element/wearable_client_colour, /datum/client_colour/glass_colour, ITEM_SLOT_EYES, GLASSES_TRAIT, glasses.glasses_color, glasses.forced_glass_color) glasses.glasses_color = new_color - AddElement(/datum/element/wearable_client_colour, /datum/client_colour/glass_colour, ITEM_SLOT_EYES, new_color, glasses.forced_glass_color) + AddElement(/datum/element/wearable_client_colour, /datum/client_colour/glass_colour, ITEM_SLOT_EYES, GLASSES_TRAIT, new_color, glasses.forced_glass_color) /datum/action/item_action/place_light_prism name = "Fabricate Light Prism" diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index 61899a8dbec..d5107e9a402 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -404,10 +404,7 @@ if (severity == EMP_HEAVY) glitch_duration *= 2 - owner.add_client_colour(/datum/client_colour/malfunction) - - addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living/carbon/human, remove_client_colour), /datum/client_colour/malfunction), glitch_duration) - return + QDEL_IN(owner.add_client_colour(/datum/client_colour/malfunction, HEAD_TRAIT), glitch_duration) #undef EMP_GLITCH diff --git a/code/modules/unit_tests/blindness.dm b/code/modules/unit_tests/blindness.dm index e4e6a4667fd..6ab6058aa61 100644 --- a/code/modules/unit_tests/blindness.dm +++ b/code/modules/unit_tests/blindness.dm @@ -52,14 +52,14 @@ // Check for the status effect, duh TEST_ASSERT(dummy.is_blind(), "Dummy, [status_message], did not have the blind status effect.") // Being more technical, we need to check for client color and screen overlays - TEST_ASSERT(HAS_CLIENT_COLOR(dummy, /datum/client_colour/monochrome/blind), "Dummy, [status_message], did not have the monochrome client color.") + TEST_ASSERT(HAS_CLIENT_COLOR(dummy, /datum/client_colour/monochrome), "Dummy, [status_message], did not have the monochrome client color.") TEST_ASSERT(HAS_SCREEN_OVERLAY(dummy, /atom/movable/screen/fullscreen/blind), "Dummy, [status_message], did not have a blind screen overlay in their list of screens.") /datum/unit_test/blindness/proc/check_if_not_blind(mob/living/carbon/human/dummy, status_message = "after being cured of blindness") // Check for no status effect TEST_ASSERT(!dummy.is_blind(), "Dummy, [status_message], still had the blindness status effect.") // Check that the client color and screen overlay are gone - TEST_ASSERT(!HAS_CLIENT_COLOR(dummy, /datum/client_colour/monochrome/blind), "Dummy, [status_message], still had the monochrome client color.") + TEST_ASSERT(!HAS_CLIENT_COLOR(dummy, /datum/client_colour/monochrome), "Dummy, [status_message], still had the monochrome client color.") TEST_ASSERT(!HAS_SCREEN_OVERLAY(dummy, /atom/movable/screen/fullscreen/blind), "Dummy, [status_message], still had the blind sceen overlay.") /** diff --git a/code/modules/unit_tests/client_colours.dm b/code/modules/unit_tests/client_colours.dm index 55b6e0b24ad..7275394eb4f 100644 --- a/code/modules/unit_tests/client_colours.dm +++ b/code/modules/unit_tests/client_colours.dm @@ -5,5 +5,11 @@ for(var/datum/client_colour/colour as anything in subtypesof(/datum/client_colour)) // colours can be color matrices (lists), which initial() cannot read. colour = new colour - if(!color_to_full_rgba_matrix(colour.colour, FALSE)) - TEST_FAIL("[colour.type] has an invalid default colour value: [colour.colour]") + if (islist(colour.color)) + var/list/potential_filter = colour.color + // If our list has "type" in it then its a filter, ignore that + if (potential_filter["type"]) + continue + + if(!color_to_full_rgba_matrix(colour.color, FALSE)) + TEST_FAIL("[colour.type] has an invalid default colour value: [colour.color]")