From 65a5e0a614ca8b094164bfdc75abefb7fa970c4e Mon Sep 17 00:00:00 2001 From: CHOMPStation2StaffMirrorBot <94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com> Date: Sun, 21 Sep 2025 16:34:50 -0700 Subject: [PATCH] [MIRROR] fixes one of my first ever coding sins here (#11720) Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> --- code/__defines/misc.dm | 2 + code/datums/browser.dm | 13 +- code/datums/colormate.dm | 223 ------------ code/datums/status_effects/_status_effect.dm | 10 +- code/game/machinery/painter_vr.dm | 22 +- .../preference_setup/loadout/02_loadout.dm | 6 +- .../preference_setup/loadout/gear_tweaks.dm | 21 +- .../modules/mob/living/silicon/robot/robot.dm | 8 +- .../mob/living/simple_mob/simple_mob.dm | 8 +- code/modules/tgui_input/matrix.dm | 336 ++++++++++++++++++ modular_chomp/code/_onclick/hud/alert.dm | 13 +- .../tgui/interfaces/ColorMate/index.tsx | 219 +++++++----- .../tgui/interfaces/ColorMate/types.ts | 7 +- vorestation.dme | 2 +- 14 files changed, 525 insertions(+), 365 deletions(-) delete mode 100644 code/datums/colormate.dm create mode 100644 code/modules/tgui_input/matrix.dm diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 939ff6f513..041333d1fe 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -533,6 +533,8 @@ GLOBAL_LIST_INIT(all_volume_channels, list( #define COLORMATE_HSV 2 #define COLORMATE_MATRIX 3 +#define DEFAULT_COLORMATRIX list(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) + #define DEPARTMENT_OFFDUTY "Off-Duty" #define ANNOUNCER_NAME "Facility PA" diff --git a/code/datums/browser.dm b/code/datums/browser.dm index c66ddb4be5..de153f9113 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -508,8 +508,8 @@ if(!user) return if(!values) - values = list(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) - if(values.len < 12) + values = DEFAULT_COLORMATRIX + if(length(values) < 12) values.len = 12 var/list/output = list() output += "
" @@ -580,8 +580,13 @@ var/client/C = user user = C.mob else - return + return null + var/datum/browser/modal/color_matrix_picker/B = new(user, message, title, button1, button2, button3, stealfocus, timeout, values) B.open() B.wait() - return list("button" = B.selected_button, "matrix" = B.color_matrix) + if(B.selected_button == 3 || !B.selected_button) + return values + if((B.selected_button == 2) || !islist(B.color_matrix) || !ISINRANGE(length(B.color_matrix), 9, 20)) + return list() + return B.color_matrix diff --git a/code/datums/colormate.dm b/code/datums/colormate.dm deleted file mode 100644 index cfa5a118b2..0000000000 --- a/code/datums/colormate.dm +++ /dev/null @@ -1,223 +0,0 @@ -/datum/ColorMate - var/name = "colouring" - var/atom/movable/inserted - var/activecolor = "#FFFFFF" - var/list/color_matrix_last - var/active_mode = COLORMATE_HSV - - var/build_hue = 0 - var/build_sat = 1 - var/build_val = 1 - - /// Minimum lightness for normal mode - var/minimum_normal_lightness = 50 - /// Minimum lightness for matrix mode, tested using 4 test colors of full red, green, blue, white. - var/minimum_matrix_lightness = 75 - /// Minimum matrix tests that must pass for something to be considered a valid color (see above) - var/minimum_matrix_tests = 2 - /// Temporary messages - var/temp - -/datum/ColorMate/New(mob/user) - color_matrix_last = list( - 1, 0, 0, - 0, 1, 0, - 0, 0, 1, - 0, 0, 0, - ) - if(istype(user)) - inserted = user - . = ..() - -/datum/ColorMate/Destroy() - inserted = null - . = ..() - -/datum/ColorMate/tgui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "ColorMate", src.name) - ui.set_autoupdate(FALSE) //This might be a bit intensive, better to not update it every few ticks - ui.open() - -/datum/ColorMate/tgui_state(mob/user) - return GLOB.tgui_conscious_state - -/datum/ColorMate/tgui_data(mob/user) - . = list() - .["activemode"] = active_mode - .["matrixcolors"] = list( - "rr" = color_matrix_last[1], - "rg" = color_matrix_last[2], - "rb" = color_matrix_last[3], - "gr" = color_matrix_last[4], - "gg" = color_matrix_last[5], - "gb" = color_matrix_last[6], - "br" = color_matrix_last[7], - "bg" = color_matrix_last[8], - "bb" = color_matrix_last[9], - "cr" = color_matrix_last[10], - "cg" = color_matrix_last[11], - "cb" = color_matrix_last[12], - ) - .["buildhue"] = build_hue - .["buildsat"] = build_sat - .["buildval"] = build_val - if(temp) - .["temp"] = temp - if(inserted) - .["item"] = list() - .["item"]["name"] = inserted.name - .["item"]["sprite"] = icon2base64(get_flat_icon(inserted,dir=SOUTH,no_anim=TRUE)) - .["item"]["preview"] = icon2base64(build_preview(user)) - else - .["item"] = null - -/datum/ColorMate/tgui_act(action, params) - . = ..() - if(.) - return - if(inserted) - switch(action) - if("switch_modes") - active_mode = text2num(params["mode"]) - return TRUE - if("choose_color") - var/chosen_color = tgui_color_picker(inserted, "Choose a color: ", "ColorMate colour picking", activecolor) - if(chosen_color) - activecolor = chosen_color - return TRUE - if("paint") - do_paint(inserted) - temp = "Painted Successfully!" - if(isanimal(inserted)) - var/mob/living/simple_mob/M = inserted - M.has_recoloured = TRUE - if(isrobot(inserted)) - var/mob/living/silicon/robot/R = inserted - R.has_recoloured = TRUE - Destroy() - if("drop") - temp = "" - Destroy() - if("clear") - inserted.remove_atom_colour(FIXED_COLOUR_PRIORITY) - playsound(src, 'sound/effects/spray3.ogg', 50, 1) - temp = "Cleared Successfully!" - return TRUE - if("set_matrix_color") - color_matrix_last[params["color"]] = params["value"] - return TRUE - if("set_matrix_string") - if(params["value"]) - var/list/colours = splittext(params["value"], ",") - if(colours.len > 12) - colours.Cut(13) - for(var/i = 1, i <= colours.len, i++) - var/number = text2num(colours[i]) - if(isnum(number)) - color_matrix_last[i] = clamp(number, -10, 10) - return TRUE - if("set_hue") - build_hue = clamp(text2num(params["buildhue"]), 0, 360) - return TRUE - if("set_sat") - build_sat = clamp(text2num(params["buildsat"]), -10, 10) - return TRUE - if("set_val") - build_val = clamp(text2num(params["buildval"]), -10, 10) - return TRUE - -/datum/ColorMate/proc/do_paint(mob/user) - var/color_to_use - switch(active_mode) - if(COLORMATE_TINT) - color_to_use = activecolor - if(COLORMATE_MATRIX) - color_to_use = rgb_construct_color_matrix( - text2num(color_matrix_last[1]), - text2num(color_matrix_last[2]), - text2num(color_matrix_last[3]), - text2num(color_matrix_last[4]), - text2num(color_matrix_last[5]), - text2num(color_matrix_last[6]), - text2num(color_matrix_last[7]), - text2num(color_matrix_last[8]), - text2num(color_matrix_last[9]), - text2num(color_matrix_last[10]), - text2num(color_matrix_last[11]), - text2num(color_matrix_last[12]), - ) - if(COLORMATE_HSV) - color_to_use = color_matrix_hsv(build_hue, build_sat, build_val) - color_matrix_last = color_to_use - if(!color_to_use || !check_valid_color(color_to_use, user)) - to_chat(user, span_notice("Invalid color.")) - return FALSE - inserted.add_atom_colour(color_to_use, FIXED_COLOUR_PRIORITY) - playsound(src, 'sound/effects/spray3.ogg', 50, 1) - return TRUE - -/// Produces the preview image of the item, used in the UI, the way the color is not stacking is a sin. -/datum/ColorMate/proc/build_preview(mob/user) - if(inserted) //sanity - var/list/cm - switch(active_mode) - if(COLORMATE_MATRIX) - cm = rgb_construct_color_matrix( - text2num(color_matrix_last[1]), - text2num(color_matrix_last[2]), - text2num(color_matrix_last[3]), - text2num(color_matrix_last[4]), - text2num(color_matrix_last[5]), - text2num(color_matrix_last[6]), - text2num(color_matrix_last[7]), - text2num(color_matrix_last[8]), - text2num(color_matrix_last[9]), - text2num(color_matrix_last[10]), - text2num(color_matrix_last[11]), - text2num(color_matrix_last[12]), - ) - if(!check_valid_color(cm, user)) - return get_flat_icon(inserted, dir=SOUTH, no_anim=TRUE) - - if(COLORMATE_TINT) - if(!check_valid_color(activecolor, user)) - return get_flat_icon(inserted, dir=SOUTH, no_anim=TRUE) - - if(COLORMATE_HSV) - cm = color_matrix_hsv(build_hue, build_sat, build_val) - color_matrix_last = cm - if(!check_valid_color(cm, user)) - return get_flat_icon(inserted, dir=SOUTH, no_anim=TRUE) - - var/cur_color = inserted.color - inserted.color = null - inserted.color = (active_mode == COLORMATE_TINT ? activecolor : cm) - var/icon/preview = get_flat_icon(inserted, dir=SOUTH, no_anim=TRUE) - inserted.color = cur_color - temp = "" - - . = preview - -/datum/ColorMate/proc/check_valid_color(list/cm, mob/user) - if(!islist(cm)) // normal - var/list/HSV = ReadHSV(RGBtoHSV(cm)) - if(HSV[3] < minimum_normal_lightness) - temp = "[cm] is too dark (Minimum lightness: [minimum_normal_lightness])" - return FALSE - return TRUE - else // matrix - // We test using full red, green, blue, and white - // A predefined number of them must pass to be considered valid - var/passed = 0 -#define COLORTEST(thestring, thematrix) passed += (ReadHSV(RGBtoHSV(RGBMatrixTransform(thestring, thematrix)))[3] >= minimum_matrix_lightness) - COLORTEST("FF0000", cm) - COLORTEST("00FF00", cm) - COLORTEST("0000FF", cm) - COLORTEST("FFFFFF", cm) -#undef COLORTEST - if(passed < minimum_matrix_tests) - temp = "Matrix is too dark. (passed [passed] out of [minimum_matrix_tests] required tests. Minimum lightness: [minimum_matrix_lightness])." - return FALSE - return TRUE diff --git a/code/datums/status_effects/_status_effect.dm b/code/datums/status_effects/_status_effect.dm index 31e937a88a..76d31e683b 100644 --- a/code/datums/status_effects/_status_effect.dm +++ b/code/datums/status_effects/_status_effect.dm @@ -24,9 +24,9 @@ var/on_remove_on_mob_delete = FALSE /// The typepath to the alert thrown by the status effect when created. /// Status effect "name"s and "description"s are shown to the owner here. - var/alert_type = /atom/movable/alert/status_effect + var/alert_type = /atom/movable/screen/alert/status_effect /// The alert itself, created in [proc/on_creation] (if alert_type is specified). - VAR_FINAL/atom/movable/alert/status_effect/linked_alert + VAR_FINAL/atom/movable/screen/alert/status_effect/linked_alert /// If TRUE, and we have an alert, we will show a duration on the alert var/show_duration = FALSE /// Used to define if the status effect should be using SSfastprocess or SSprocessing @@ -64,7 +64,7 @@ tick_interval = world.time + tick_interval if(alert_type) - var/atom/movable/alert/status_effect/new_alert = owner.throw_alert(id, alert_type) + var/atom/movable/screen/alert/status_effect/new_alert = owner.throw_alert(id, alert_type) new_alert.attached_effect = src //so the alert can reference us, if it needs to linked_alert = new_alert //so we can reference the alert, if we need to update_shown_duration() @@ -242,13 +242,13 @@ update_shown_duration() /// Alert base type for status effect alerts -/atom/movable/alert/status_effect +/atom/movable/screen/alert/status_effect name = "Curse of Mundanity" desc = "You don't feel any different..." // maptext_y = 2 /// The status effect we're linked to var/datum/status_effect/attached_effect -/atom/movable/alert/status_effect/Destroy() +/atom/movable/screen/alert/status_effect/Destroy() attached_effect = null //Don't keep a ref now return ..() diff --git a/code/game/machinery/painter_vr.dm b/code/game/machinery/painter_vr.dm index 5894a8d41e..70e8ce9dbd 100644 --- a/code/game/machinery/painter_vr.dm +++ b/code/game/machinery/painter_vr.dm @@ -85,12 +85,6 @@ return tgui_interact(user) -/obj/machinery/gear_painter/tgui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "ColorMate", name) - ui.open() - /obj/machinery/gear_painter/proc/insert_mob(mob/victim, mob/user) if(inserted) return @@ -154,12 +148,13 @@ if(temp) .["temp"] = temp if(inserted) - .["item"] = list() - .["item"]["name"] = inserted.name - .["item"]["sprite"] = icon2base64(get_flat_icon(inserted,dir=SOUTH,no_anim=TRUE)) - .["item"]["preview"] = icon2base64(build_preview(user)) + .["item_name"] = inserted.name + .["item_sprite"] = icon2base64(get_flat_icon(inserted,dir=SOUTH,no_anim=TRUE)) + .["item_preview"] = icon2base64(build_preview(user)) else - .["item"] = null + .["item_name"] = null + .["item_sprite"] = null + .["item_preview"] = null /obj/machinery/gear_painter/tgui_act(action, params, datum/tgui/ui) . = ..() @@ -176,7 +171,8 @@ activecolor = chosen_color return TRUE if("paint") - do_paint(ui.user) + if(!do_paint(ui.user)) + return TRUE temp = "Painted Successfully!" return TRUE if("drop") @@ -236,7 +232,7 @@ color_to_use = color_matrix_hsv(build_hue, build_sat, build_val) color_matrix_last = color_to_use if(!color_to_use || !check_valid_color(color_to_use, user)) - to_chat(user, span_notice("Invalid color.")) + temp = "Invalid color!" return FALSE inserted.add_atom_colour(color_to_use, FIXED_COLOUR_PRIORITY) playsound(src, 'sound/effects/spray3.ogg', 50, 1) diff --git a/code/modules/client/preference_setup/loadout/02_loadout.dm b/code/modules/client/preference_setup/loadout/02_loadout.dm index 7338988ae1..2e2db2c804 100644 --- a/code/modules/client/preference_setup/loadout/02_loadout.dm +++ b/code/modules/client/preference_setup/loadout/02_loadout.dm @@ -245,7 +245,11 @@ var/list/gear_datums = list() var/datum/gear_tweak/tweak = locate(params["tweak"]) if(!tweak || !gear || !(tweak in gear.gear_tweaks)) return TOPIC_HANDLED - var/metadata = tweak.get_metadata(user, get_tweak_metadata(gear, tweak)) + var/metadata + if(istype(tweak, /datum/gear_tweak/matrix_recolor)) + metadata = tweak.get_metadata(user, get_tweak_metadata(gear, tweak), gear) + else + metadata = tweak.get_metadata(user, get_tweak_metadata(gear, tweak)) if(!metadata) return TOPIC_HANDLED set_tweak_metadata(gear, tweak, metadata) diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm index 2fd7abfdbd..1ca8c7cea4 100644 --- a/code/modules/client/preference_setup/loadout/gear_tweaks.dm +++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm @@ -59,20 +59,23 @@ GLOBAL_DATUM_INIT(gear_tweak_free_matrix_recolor, /datum/gear_tweak/matrix_recol /datum/gear_tweak/matrix_recolor/get_default() return null -/datum/gear_tweak/matrix_recolor/get_metadata(user, metadata) - var/list/returned = color_matrix_picker(user, "Pick a color matrix for this item", "Matrix Recolor", "Ok", "Erase", "Cancel", TRUE, 10 MINUTES, islist(metadata) && metadata) - var/list/L = returned["matrix"] - if(returned["button"] == 3) +/datum/gear_tweak/matrix_recolor/get_metadata(user, metadata, datum/gear/gear) + if(!istype(gear)) + CRASH("Matrix metadata called by [user] without gear!") + var/list/returned = tgui_input_colormatrix(user, "Pick a color matrix for this item", "Matrix Recolor", gear.path, metadata, TRUE) + if(!returned) return metadata - if((returned["button"] == 2) || !islist(L) || !ISINRANGE(L.len, 9, 20)) - return list() var/identity = TRUE var/static/list/ones = list(1, 5, 9) - for(var/i in 1 to L.len) - if(L[i] != ((i in ones)? 1 : 0)) + var/static/list/offsets = list(10, 11, 12) + for(var/i in 1 to length(returned)) + if(returned[i] != ((i in ones) ? 1 : 0)) identity = FALSE break - return identity? list() : L + if(returned[i] != ((i in offsets) ? 0 : 1)) + identity = FALSE + break + return identity ? list() : returned /datum/gear_tweak/matrix_recolor/tweak_item(obj/item/I, metadata) . = ..() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 5b0a959a6b..4c31ba165f 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -916,11 +916,11 @@ set category = "Abilities.Settings" set desc = "Allows to recolour once." - if(!has_recoloured) - var/datum/ColorMate/recolour = new /datum/ColorMate(src) - recolour.tgui_interact(src) + if(has_recoloured) + to_chat(src, "You've already recoloured yourself once. Ask for a module reset for another.") return - to_chat(src, "You've already recoloured yourself once. Ask for a module reset for another.") + + tgui_input_colormatrix(src, "Allows you to recolor yourself", "Robot Recolor", src, ui_state = GLOB.tgui_conscious_state) /mob/living/silicon/robot/attack_hand(mob/user) if(LAZYLEN(buckled_mobs)) diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm index 79f6b5089b..4f53e277e1 100644 --- a/code/modules/mob/living/simple_mob/simple_mob.dm +++ b/code/modules/mob/living/simple_mob/simple_mob.dm @@ -424,11 +424,11 @@ set category = "Abilities.Settings" set desc = "Allows to recolour once." - if(!has_recoloured) - var/datum/ColorMate/recolour = new /datum/ColorMate(src) - recolour.tgui_interact(src) + if(has_recoloured) + to_chat(src, "You've already recoloured yourself once. You are only allowed to recolour yourself once during a around.") return - to_chat(src, "You've already recoloured yourself once. You are only allowed to recolour yourself once during a around.") + + tgui_input_colormatrix(src, "Allows you to recolor yourself", "Animal Recolor", src, ui_state = GLOB.tgui_conscious_state) //Thermal vision adding diff --git a/code/modules/tgui_input/matrix.dm b/code/modules/tgui_input/matrix.dm new file mode 100644 index 0000000000..2ac97c8ff8 --- /dev/null +++ b/code/modules/tgui_input/matrix.dm @@ -0,0 +1,336 @@ +/** + * Creates a TGUI window with a matrix input. Returns the user's response as list | null. + * + * This proc should be used to create windows for matrix entry that the caller will wait for a response from. + * If tgui fancy chat is turned off: Will return a normal input. If a max or min value is specified, will + * validate the input inside the UI and ui_act. + * + * Arguments: + * * user - The user to show the matrix input to. + * * message - The content of the matrix input, shown in the body of the TGUI window. + * * title - The title of the matrix input modal, shown on the top of the TGUI window. + * * target - The target where the matrix will be applied to. + * * matrix_only - uses a static mode and allows fallback to non tgui. Only use this if you only care about the return value. + * * default - The default (or current) value, shown as a placeholder. Users can press refresh with this. + * * timeout - The timeout of the matrix input, after which the modal will close and qdel itself. Set to zero for no timeout. + */ +/proc/tgui_input_colormatrix(mob/user, message, title = "Matrix Recolor", atom/movable/target, list/default = DEFAULT_COLORMATRIX, matrix_only = FALSE, timeout = 10 MINUTES, ui_state = GLOB.tgui_always_state) + if (!user) + user = usr + if (!istype(user)) + if (istype(user, /client)) + var/client/client = user + user = client.mob + else + return null + + if (isnull(user.client)) + return null + + if(!islist(default) || !length(default)) + default = DEFAULT_COLORMATRIX + + if(length(default) < 12) + default.len = 12 + + // Client does NOT have tgui_input on and we only want a matrix, or we haven't passed a preview path or object: Returns regular input + if(!user.read_preference(/datum/preference/toggle/tgui_input_mode) && matrix_only || (!ispath(target) && !isatom(target))) + return color_matrix_picker(user, message, title, "Ok", "Erase", "Cancel", TRUE, timeout, default) + var/was_path = ispath(target) + var/atom/movable/real_target = was_path ? new target : target + var/datum/tgui_input_colormatrix/matrix_input = new(user, message, title, real_target, default, matrix_only, timeout, ui_state, was_path) + matrix_input.tgui_interact(user) + matrix_input.wait() + // We only created it for the preview + if(was_path) + qdel(real_target) + if (matrix_input) + . = matrix_input.entry + qdel(matrix_input) + +/** + * # tgui_input_colormatrix + * + * Datum used for instantiating and using a TGUI-controlled color matrix input that prompts the user with + * a message and has an input for color matrix entry. + */ +/datum/tgui_input_colormatrix + /// Boolean field describing if the tgui_input_colormatrix was closed by the user. + var/closed + /// The entry that the user has return_typed in. + var/entry + /// The prompt's body, if any, of the TGUI window. + var/message + /// The target for our display + var/atom/movable/target + /// The base color matrix + var/list/default + /// static mode users can't change + var/matrix_only + /// our default list should not be edited as it might be a reference + var/list/color_matrix_last + /// The time at which the number input was created, for displaying timeout progress. + var/start_time + /// The lifespan of the color matrix input, after which the window will close and delete itself. + var/timeout + /// The title of the TGUI window + var/title + /// The TGUI UI state that will be returned in ui_state(). Default: always_state + var/datum/tgui_state/state + /// Internal var to remember if we only passed a path before + var/was_path + + var/activecolor = "#FFFFFF" + var/active_mode = COLORMATE_HSV + + var/build_hue = 0 + var/build_sat = 1 + var/build_val = 1 + + /// Minimum lightness for normal mode + var/minimum_normal_lightness = 50 + /// Minimum lightness for matrix mode, tested using 4 test colors of full red, green, blue, white. + var/minimum_matrix_lightness = 75 + /// Minimum matrix tests that must pass for something to be considered a valid color (see above) + var/minimum_matrix_tests = 2 + /// Temporary messages + var/temp + +/datum/tgui_input_colormatrix/New(mob/user, message, title, atom/movable/target, list/default, matrix_only, timeout, ui_state, was_path) + src.default = default + src.message = message + src.target = target + src.title = title + src.state = ui_state + src.was_path = was_path + src.matrix_only = matrix_only + if(matrix_only) + active_mode = COLORMATE_MATRIX + if (timeout) + src.timeout = timeout + start_time = world.time + QDEL_IN(src, timeout) + color_matrix_last = default.Copy() + +/datum/tgui_input_colormatrix/Destroy(force) + SStgui.close_uis(src) + state = null + target = null + return ..() + +/** + * Waits for a user's response to the tgui_input_colormatrix's prompt before returning. Returns early if + * the window was closed by the user. + */ +/datum/tgui_input_colormatrix/proc/wait() + while (!entry && !closed && !QDELETED(src)) + stoplag(1) + +/datum/tgui_input_colormatrix/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ColorMate") + ui.set_autoupdate(FALSE) //This might be a bit intensive, better to not update it every few ticks + ui.open() + +/datum/tgui_input_colormatrix/tgui_close(mob/user) + . = ..() + closed = TRUE + +/datum/tgui_input_colormatrix/tgui_state(mob/user) + return state + +/datum/tgui_input_colormatrix/tgui_static_data(mob/user) + var/list/data = list() + data["message"] = message + data["title"] = title + data["item_name"] = target.name + data["item_sprite"] = icon2base64(get_flat_icon(target,dir=SOUTH,no_anim=TRUE)) + data["matrix_only"] = matrix_only + return data + +/datum/tgui_input_colormatrix/tgui_data(mob/user) + var/list/data = list() + data["activemode"] = active_mode + data["matrixcolors"] = list( + "rr" = color_matrix_last[1], + "rg" = color_matrix_last[2], + "rb" = color_matrix_last[3], + "gr" = color_matrix_last[4], + "gg" = color_matrix_last[5], + "gb" = color_matrix_last[6], + "br" = color_matrix_last[7], + "bg" = color_matrix_last[8], + "bb" = color_matrix_last[9], + "cr" = color_matrix_last[10], + "cg" = color_matrix_last[11], + "cb" = color_matrix_last[12], + ) + data["buildhue"] = build_hue + data["buildsat"] = build_sat + data["buildval"] = build_val + data["item_preview"] = icon2base64(build_preview(user)) + if(temp) + data["temp"] = temp + if(timeout) + data["timeout"] = CLAMP01((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS)) + return data + +/datum/tgui_input_colormatrix/tgui_act(action, list/params, datum/tgui/ui) + . = ..() + if (.) + return + switch(action) + if("switch_modes") + active_mode = text2num(params["mode"]) + return TRUE + if("choose_color") + var/chosen_color = tgui_color_picker(ui.user, "Choose a color: ", "[title] colour picking", activecolor) + if(chosen_color) + activecolor = chosen_color + return TRUE + if("paint") + if(!do_paint(ui.user, !was_path)) + return TRUE + set_entry(color_matrix_last) + temp = "Painted Successfully!" + closed = TRUE + SStgui.close_uis(src) + return TRUE + if("drop") + temp = "" + closed = TRUE + SStgui.close_uis(src) + return TRUE + if("clear") + target.remove_atom_colour(FIXED_COLOUR_PRIORITY) + playsound(src, 'sound/effects/spray3.ogg', 50, 1) + temp = "Cleared Successfully!" + color_matrix_last = DEFAULT_COLORMATRIX + return TRUE + if("set_matrix_color") + color_matrix_last[params["color"]] = params["value"] + return TRUE + if("set_matrix_string") + if(params["value"]) + var/list/colours = splittext(params["value"], ",") + if(length(colours) > 12) + colours.Cut(13) + for(var/i = 1, i <= length(colours), i++) + var/number = text2num(colours[i]) + if(isnum(number)) + color_matrix_last[i] = clamp(number, -10, 10) + return TRUE + if("set_hue") + build_hue = clamp(text2num(params["buildhue"]), 0, 360) + return TRUE + if("set_sat") + build_sat = clamp(text2num(params["buildsat"]), -10, 10) + return TRUE + if("set_val") + build_val = clamp(text2num(params["buildval"]), -10, 10) + return TRUE + +/datum/tgui_input_colormatrix/proc/set_entry(entry) + src.entry = entry + +/datum/tgui_input_colormatrix/proc/do_paint(mob/user, apply) + var/color_to_use + switch(active_mode) + if(COLORMATE_TINT) + color_to_use = activecolor + if(COLORMATE_MATRIX) + color_to_use = rgb_construct_color_matrix( + text2num(color_matrix_last[1]), + text2num(color_matrix_last[2]), + text2num(color_matrix_last[3]), + text2num(color_matrix_last[4]), + text2num(color_matrix_last[5]), + text2num(color_matrix_last[6]), + text2num(color_matrix_last[7]), + text2num(color_matrix_last[8]), + text2num(color_matrix_last[9]), + text2num(color_matrix_last[10]), + text2num(color_matrix_last[11]), + text2num(color_matrix_last[12]), + ) + if(COLORMATE_HSV) + color_to_use = color_matrix_hsv(build_hue, build_sat, build_val) + color_matrix_last = color_to_use + if(!color_to_use || !check_valid_color(color_to_use, user)) + temp = "Invalid color!" + return FALSE + if(apply) + target.add_atom_colour(color_to_use, FIXED_COLOUR_PRIORITY) + playsound(src, 'sound/effects/spray3.ogg', 50, 1) + if(isanimal(target)) + var/mob/living/simple_mob/M = target + M.has_recoloured = TRUE + if(isrobot(target)) + var/mob/living/silicon/robot/R = target + R.has_recoloured = TRUE + return TRUE + +/// Produces the preview image of the item, used in the UI, the way the color is not stacking is a sin. +/datum/tgui_input_colormatrix/proc/build_preview(mob/user) + if(target) //sanity + var/list/cm + switch(active_mode) + if(COLORMATE_MATRIX) + cm = rgb_construct_color_matrix( + text2num(color_matrix_last[1]), + text2num(color_matrix_last[2]), + text2num(color_matrix_last[3]), + text2num(color_matrix_last[4]), + text2num(color_matrix_last[5]), + text2num(color_matrix_last[6]), + text2num(color_matrix_last[7]), + text2num(color_matrix_last[8]), + text2num(color_matrix_last[9]), + text2num(color_matrix_last[10]), + text2num(color_matrix_last[11]), + text2num(color_matrix_last[12]), + ) + if(!check_valid_color(cm, user)) + return get_flat_icon(target, dir=SOUTH, no_anim=TRUE) + + if(COLORMATE_TINT) + if(!check_valid_color(activecolor, user)) + return get_flat_icon(target, dir=SOUTH, no_anim=TRUE) + + if(COLORMATE_HSV) + cm = color_matrix_hsv(build_hue, build_sat, build_val) + color_matrix_last = cm + if(!check_valid_color(cm, user)) + return get_flat_icon(target, dir=SOUTH, no_anim=TRUE) + + var/cur_color = target.color + target.color = null + target.color = (active_mode == COLORMATE_TINT ? activecolor : cm) + var/icon/preview = get_flat_icon(target, dir=SOUTH, no_anim=TRUE) + target.color = cur_color + temp = "" + + . = preview + +/datum/tgui_input_colormatrix/proc/check_valid_color(list/cm, mob/user) + if(!islist(cm)) // normal + var/list/HSV = ReadHSV(RGBtoHSV(cm)) + if(HSV[3] < minimum_normal_lightness) + temp = "[cm] is too dark (Minimum lightness: [minimum_normal_lightness])" + return FALSE + return TRUE + else // matrix + // We test using full red, green, blue, and white + // A predefined number of them must pass to be considered valid + var/passed = 0 +#define COLORTEST(thestring, thematrix) passed += (ReadHSV(RGBtoHSV(RGBMatrixTransform(thestring, thematrix)))[3] >= minimum_matrix_lightness) + COLORTEST("FF0000", cm) + COLORTEST("00FF00", cm) + COLORTEST("0000FF", cm) + COLORTEST("FFFFFF", cm) +#undef COLORTEST + if(passed < minimum_matrix_tests) + temp = "Matrix is too dark. (passed [passed] out of [minimum_matrix_tests] required tests. Minimum lightness: [minimum_matrix_lightness])." + return FALSE + return TRUE diff --git a/modular_chomp/code/_onclick/hud/alert.dm b/modular_chomp/code/_onclick/hud/alert.dm index b15585d07a..fe93786ea5 100644 --- a/modular_chomp/code/_onclick/hud/alert.dm +++ b/modular_chomp/code/_onclick/hud/alert.dm @@ -1,14 +1,3 @@ -/atom/movable/alert/open_ticket +/atom/movable/screen/alert/open_ticket icon = 'modular_chomp/icons/logo.dmi' - name = "Admin Chat Request" - desc = "A Administrator would like to chat with you. \ - Click here to begin." icon_state = "32x32" - -/atom/movable/alert/open_ticket/Click() - if(!usr || !usr.client) return - - // Open a new chat with the user - var/datum/ticket_chat/TC = new() - TC.T = usr.client.current_ticket - TC.tgui_interact(usr.client.mob) diff --git a/tgui/packages/tgui/interfaces/ColorMate/index.tsx b/tgui/packages/tgui/interfaces/ColorMate/index.tsx index 9f2131b7cc..1f116dd647 100644 --- a/tgui/packages/tgui/interfaces/ColorMate/index.tsx +++ b/tgui/packages/tgui/interfaces/ColorMate/index.tsx @@ -6,6 +6,7 @@ import { Image, NoticeBox, Section, + Stack, Table, Tabs, } from 'tgui-core/components'; @@ -17,7 +18,16 @@ import type { Data } from './types'; export const ColorMate = (props) => { const { act, data } = useBackend(); - const { activemode, temp, item } = data; + const { + activemode, + temp, + item_name, + item_sprite, + item_preview, + title, + message, + matrix_only, + } = data; const tab: React.JSX.Element[] = []; @@ -25,95 +35,128 @@ export const ColorMate = (props) => { tab[2] = ; tab[3] = ; + const height = 720 + (matrix_only ? -20 : 0) + (message ? 20 : 0); + return ( - + -
- {temp ? {temp} : null} - {item && Object.keys(item).length ? ( - <> - - -
-
Item:
- -
-
- -
-
Preview:
- -
-
-
- - - act('switch_modes', { - mode: 1, - }) - } - > - Tint coloring (Simple) - - - act('switch_modes', { - mode: 2, - }) - } - > - HSV coloring (Normal) - - - act('switch_modes', { - mode: 3, - }) - } - > - Matrix coloring (Advanced) - - -
Coloring: {item.name}
- - - - - - - - {tab[activemode] || Error} - -
- - ) : ( -
No item inserted.
- )} +
+ + {!!temp && ( + + {temp} + + )} + + {message} + + + {item_name ? ( + <> + + +
+
Item:
+ +
+
+ +
+
Preview:
+ +
+
+
+ {!matrix_only && ( + + + act('switch_modes', { + mode: 1, + }) + } + > + Tint coloring (Simple) + + + act('switch_modes', { + mode: 2, + }) + } + > + HSV coloring (Normal) + + + act('switch_modes', { + mode: 3, + }) + } + > + Matrix coloring (Advanced) + + + )} +
Coloring: {item_name}
+ + + act('paint')} + > + Paint + + act('clear')} + > + Clear + + act('drop')} + > + Eject + + + + {tab[activemode] || Error} + +
+ + ) : ( +
No item inserted.
+ )} +
+
diff --git a/tgui/packages/tgui/interfaces/ColorMate/types.ts b/tgui/packages/tgui/interfaces/ColorMate/types.ts index a56bab9c7b..c649090754 100644 --- a/tgui/packages/tgui/interfaces/ColorMate/types.ts +++ b/tgui/packages/tgui/interfaces/ColorMate/types.ts @@ -18,5 +18,10 @@ export type Data = { buildsat: number; buildval: number; temp: string | null; - item: { name: string; sprite: string; preview: string } | null; + item_name: string | null; + item_sprite: string | null; + item_preview: string | null; + message?: string; + title?: string; + matrix_only?: number; }; diff --git a/vorestation.dme b/vorestation.dme index bd113b8938..d37af1bec3 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -547,7 +547,6 @@ #include "code\datums\chat_message.dm" #include "code\datums\chat_payload.dm" #include "code\datums\cogbar.dm" -#include "code\datums\colormate.dm" #include "code\datums\datacore.dm" #include "code\datums\datum.dm" #include "code\datums\datumvars.dm" @@ -4767,6 +4766,7 @@ #include "code\modules\tgui_input\checkboxes.dm" #include "code\modules\tgui_input\color.dm" #include "code\modules\tgui_input\list.dm" +#include "code\modules\tgui_input\matrix.dm" #include "code\modules\tgui_input\number.dm" #include "code\modules\tgui_input\text.dm" #include "code\modules\tgui_input\say_modal\modal.dm"