From 56ae98801ad05ee696ff5f140c9e50d5b607c7f5 Mon Sep 17 00:00:00 2001 From: Rob Bailey Date: Fri, 18 Dec 2020 10:05:20 -0800 Subject: [PATCH] Filterrific! (#55246) Filter refactor + In Game Filter Editor Accessed via VV in the dropdown of atoms. "Edit Filters. Makes filters actually usable. Co-authored-by: ghgh --- code/__DEFINES/colors.dm | 98 ++++-- code/__DEFINES/vv.dm | 3 + code/__HELPERS/filters.dm | 305 +++++++++++++++++ code/_onclick/hud/plane_master.dm | 13 +- code/game/atoms.dm | 39 +++ code/modules/admin/holder2.dm | 1 + .../admin/view_variables/filterrific.dm | 99 ++++++ .../nukeop/equipment/borgchameleon.dm | 19 +- code/modules/client/client_procs.dm | 4 + fortune13.dme | 1 + tgui/packages/tgui/interfaces/Filteriffic.js | 307 ++++++++++++++++++ 11 files changed, 843 insertions(+), 46 deletions(-) create mode 100644 code/modules/admin/view_variables/filterrific.dm create mode 100644 tgui/packages/tgui/interfaces/Filteriffic.js diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index bd9ecac39fa..2f03a065908 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -1,37 +1,75 @@ // This is eventually for wjohn to add more color standardization stuff like I keep asking him >:( -#define COLOR_INPUT_DISABLED "#F0F0F0" -#define COLOR_INPUT_ENABLED "#D3B5B5" -#define COLOR_FLOORTILE_GRAY "#8D8B8B" -#define COLOR_ALMOST_BLACK "#333333" -#define COLOR_WHITE "#FFFFFF" -#define COLOR_BLACK "#000000" -#define COLOR_RED "#FF0000" -#define COLOR_RED_LIGHT "#FF3333" -#define COLOR_MAROON "#800000" -#define COLOR_YELLOW "#FFFF00" -#define COLOR_OLIVE "#808000" -#define COLOR_LIME "#32CD32" -#define COLOR_GREEN "#008000" -#define COLOR_CYAN "#00FFFF" -#define COLOR_TEAL "#008080" -#define COLOR_BLUE "#0000FF" -#define COLOR_BLUE_LIGHT "#33CCFF" -#define COLOR_NAVY "#000080" -#define COLOR_PINK "#FFC0CB" -#define COLOR_MAGENTA "#FF00FF" -#define COLOR_PURPLE "#800080" -#define COLOR_ORANGE "#FF9900" -#define COLOR_BEIGE "#CEB689" -#define COLOR_BLUE_GRAY "#75A2BB" -#define COLOR_BROWN "#BA9F6D" -#define COLOR_DARK_BROWN "#997C4F" -#define COLOR_DARK_ORANGE "#C3630C" + +#define COLOR_DARKMODE_BACKGROUND "#202020" +#define COLOR_DARKMODE_DARKBACKGROUND "#171717" +#define COLOR_DARKMODE_TEXT "#a4bad6" + +#define COLOR_WHITE "#FFFFFF" +#define COLOR_VERY_LIGHT_GRAY "#EEEEEE" +#define COLOR_SILVER "#C0C0C0" +#define COLOR_GRAY "#808080" +#define COLOR_FLOORTILE_GRAY "#8D8B8B" +#define COLOR_ALMOST_BLACK "#333333" +#define COLOR_BLACK "#000000" +#define COLOR_HALF_TRANSPARENT_BLACK "#0000007A" + +#define COLOR_RED "#FF0000" +#define COLOR_MOSTLY_PURE_RED "#FF3300" +#define COLOR_DARK_RED "#A50824" +#define COLOR_RED_LIGHT "#FF3333" +#define COLOR_MAROON "#800000" +#define COLOR_VIVID_RED "#FF3232" +#define COLOR_LIGHT_GRAYISH_RED "#E4C7C5" +#define COLOR_SOFT_RED "#FA8282" +#define COLOR_BUBBLEGUM_RED "#950A0A" + +#define COLOR_YELLOW "#FFFF00" +#define COLOR_VIVID_YELLOW "#FBFF23" +#define COLOR_VERY_SOFT_YELLOW "#FAE48E" + +#define COLOR_OLIVE "#808000" +#define COLOR_VIBRANT_LIME "#00FF00" +#define COLOR_LIME "#32CD32" +#define COLOR_VERY_PALE_LIME_GREEN "#DDFFD3" +#define COLOR_VERY_DARK_LIME_GREEN "#003300" +#define COLOR_GREEN "#008000" +#define COLOR_DARK_MODERATE_LIME_GREEN "#44964A" + +#define COLOR_CYAN "#00FFFF" +#define COLOR_DARK_CYAN "#00A2FF" +#define COLOR_TEAL "#008080" +#define COLOR_BLUE "#0000FF" +#define COLOR_BRIGHT_BLUE "#2CB2E8" +#define COLOR_MODERATE_BLUE "#555CC2" +#define COLOR_BLUE_LIGHT "#33CCFF" +#define COLOR_NAVY "#000080" +#define COLOR_BLUE_GRAY "#75A2BB" + +#define COLOR_PINK "#FFC0CB" +#define COLOR_MOSTLY_PURE_PINK "#E4005B" +#define COLOR_MAGENTA "#FF00FF" +#define COLOR_STRONG_MAGENTA "#B800B8" +#define COLOR_PURPLE "#800080" +#define COLOR_VIOLET "#B900F7" +#define COLOR_STRONG_VIOLET "#6927c5" + +#define COLOR_ORANGE "#FF9900" +#define COLOR_TAN_ORANGE "#FF7B00" +#define COLOR_BRIGHT_ORANGE "#E2853D" +#define COLOR_LIGHT_ORANGE "#ffc44d" +#define COLOR_PALE_ORANGE "#FFBE9D" +#define COLOR_BEIGE "#CEB689" +#define COLOR_DARK_ORANGE "#C3630C" +#define COLOR_DARK_MODERATE_ORANGE "#8B633B" + +#define COLOR_BROWN "#BA9F6D" +#define COLOR_DARK_BROWN "#997C4F" + #define COLOR_GREEN_GRAY "#99BB76" #define COLOR_RED_GRAY "#B4696A" #define COLOR_PALE_BLUE_GRAY "#98C5DF" #define COLOR_PALE_GREEN_GRAY "#B7D993" -#define COLOR_PALE_ORANGE "#FFC066" #define COLOR_PALE_RED_GRAY "#D59998" #define COLOR_PALE_PURPLE_GRAY "#CBB1CA" #define COLOR_PURPLE_GRAY "#AE8CA8" @@ -53,3 +91,7 @@ #define COLOR_ASSEMBLY_BLUE "#38559E" #define COLOR_ASSEMBLY_PURPLE "#6F6192" #define COLOR_ASSEMBLY_PINK "#ff4adc" + +#define COLOR_INPUT_DISABLED "#F0F0F0" +#define COLOR_INPUT_ENABLED "#D3B5B5" + diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 8f640f6e60b..97cf7266dd0 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -96,6 +96,9 @@ #define VV_HK_TRIGGER_EXPLOSION "explode" #define VV_HK_AUTO_RENAME "auto_rename" #define VV_HK_EDIT_COLOR_MATRIX "edit_color_matrix" +#define VV_HK_RADIATE "radiate" +#define VV_HK_EDIT_FILTERS "edit_filters" +#define VV_HK_ADD_AI "add_ai" // /obj #define VV_HK_OSAY "osay" diff --git a/code/__HELPERS/filters.dm b/code/__HELPERS/filters.dm index 1a193e29f0c..7be7ca5d732 100644 --- a/code/__HELPERS/filters.dm +++ b/code/__HELPERS/filters.dm @@ -1,3 +1,143 @@ +#define ICON_NOT_SET "Not Set" + +//This is stored as a nested list instead of datums or whatever because it json encodes nicely for usage in tgui +GLOBAL_LIST_INIT(master_filter_info, list( + "alpha" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "icon" = ICON_NOT_SET, + "render_source" = "", + "flags" = 0 + ), + "flags" = list( + "MASK_INVERSE" = MASK_INVERSE, + "MASK_SWAP" = MASK_SWAP + ) + ), + "angular_blur" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 1 + ) + ), + /* Not supported because making a proper matrix editor on the frontend would be a huge dick pain. + Uncomment if you ever implement it + "color" = list( + "defaults" = list( + "color" = matrix(), + "space" = FILTER_COLOR_RGB + ) + ), + */ + "displace" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = null, + "icon" = ICON_NOT_SET, + "render_source" = "" + ) + ), + "drop_shadow" = list( + "defaults" = list( + "x" = 1, + "y" = -1, + "size" = 1, + "offset" = 0, + "color" = COLOR_HALF_TRANSPARENT_BLACK + ) + ), + "blur" = list( + "defaults" = list( + "size" = 1 + ) + ), + "layer" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "icon" = ICON_NOT_SET, + "render_source" = "", + "flags" = FILTER_OVERLAY, + "color" = "", + "transform" = null, + "blend_mode" = BLEND_DEFAULT + ) + ), + "motion_blur" = list( + "defaults" = list( + "x" = 0, + "y" = 0 + ) + ), + "outline" = list( + "defaults" = list( + "size" = 0, + "color" = COLOR_BLACK, + "flags" = NONE + ), + "flags" = list( + "OUTLINE_SHARP" = OUTLINE_SHARP, + "OUTLINE_SQUARE" = OUTLINE_SQUARE + ) + ), + "radial_blur" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 0.01 + ) + ), + "rays" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 16, + "color" = COLOR_WHITE, + "offset" = 0, + "density" = 10, + "threshold" = 0.5, + "factor" = 0, + "flags" = FILTER_OVERLAY | FILTER_UNDERLAY + ), + "flags" = list( + "FILTER_OVERLAY" = FILTER_OVERLAY, + "FILTER_UNDERLAY" = FILTER_UNDERLAY + ) + ), + "ripple" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 1, + "repeat" = 2, + "radius" = 0, + "falloff" = 1, + "flags" = NONE + ), + "flags" = list( + "WAVE_BOUNDED" = WAVE_BOUNDED + ) + ), + "wave" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 1, + "offset" = 0, + "flags" = NONE + ), + "flags" = list( + "WAVE_SIDEWAYS" = WAVE_SIDEWAYS, + "WAVE_BOUNDED" = WAVE_BOUNDED + ) + ) +)) + +#undef ICON_NOT_SET + //Helpers to generate lists for filter helpers //This is the only practical way of writing these that actually produces sane lists /proc/alpha_mask_filter(x, y, icon/icon, render_source, flags) @@ -12,3 +152,168 @@ .["render_source"] = render_source if(!isnull(flags)) .["flags"] = flags + +/proc/angular_blur_filter(x, y, size) + . = list("type" = "angular_blur") + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(size)) + .["size"] = size + +/proc/color_matrix_filter(matrix/in_matrix, space) + . = list("type" = "color") + .["color"] = in_matrix + if(!isnull(space)) + .["space"] = space + +/proc/displacement_map_filter(icon, render_source, x, y, size = 32) + . = list("type" = "displace") + if(!isnull(icon)) + .["icon"] = icon + if(!isnull(render_source)) + .["render_source"] = render_source + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(size)) + .["size"] = size + +/proc/drop_shadow_filter(x, y, size, offset, color) + . = list("type" = "drop_shadow") + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(size)) + .["size"] = size + if(!isnull(offset)) + .["offset"] = offset + if(!isnull(color)) + .["color"] = color + +/proc/gauss_blur_filter(size) + . = list("type" = "blur") + if(!isnull(size)) + .["size"] = size + +/proc/layering_filter(icon, render_source, x, y, flags, color, transform, blend_mode) + . = list("type" = "layer") + if(!isnull(icon)) + .["icon"] = icon + if(!isnull(render_source)) + .["render_source"] = render_source + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(color)) + .["color"] = color + if(!isnull(flags)) + .["flags"] = flags + if(!isnull(transform)) + .["transform"] = transform + if(!isnull(blend_mode)) + .["blend_mode"] = blend_mode + +/proc/motion_blur_filter(x, y) + . = list("type" = "motion_blur") + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + +/proc/outline_filter(size, color, flags) + . = list("type" = "outline") + if(!isnull(size)) + .["size"] = size + if(!isnull(color)) + .["color"] = color + if(!isnull(flags)) + .["flags"] = flags + +/proc/radial_blur_filter(size, x, y) + . = list("type" = "radial_blur") + if(!isnull(size)) + .["size"] = size + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + +/proc/rays_filter(size, color, offset, density, threshold, factor, x, y, flags) + . = list("type" = "rays") + if(!isnull(size)) + .["size"] = size + if(!isnull(color)) + .["color"] = color + if(!isnull(offset)) + .["offset"] = offset + if(!isnull(density)) + .["density"] = density + if(!isnull(threshold)) + .["threshold"] = threshold + if(!isnull(factor)) + .["factor"] = factor + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(flags)) + .["flags"] = flags + +/proc/ripple_filter(radius, size, falloff, repeat, x, y, flags) + . = list("type" = "ripple") + if(!isnull(radius)) + .["radius"] = radius + if(!isnull(size)) + .["size"] = size + if(!isnull(falloff)) + .["falloff"] = falloff + if(!isnull(repeat)) + .["repeat"] = repeat + if(!isnull(flags)) + .["flags"] = flags + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + +/proc/wave_filter(x, y, size, offset, flags) + . = list("type" = "wave") + if(!isnull(size)) + .["size"] = size + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(offset)) + .["offset"] = offset + if(!isnull(flags)) + .["flags"] = flags + +/proc/apply_wibbly_filters(atom/in_atom, length) + for(var/i in 1 to 7) + //This is a very baffling and strange way of doing this but I am just preserving old functionality + var/X + var/Y + var/rsq + do + X = 60*rand() - 30 + Y = 60*rand() - 30 + rsq = X*X + Y*Y + while(rsq<100 || rsq>900) // Yeah let's just loop infinitely due to bad luck what's the worst that could happen? + var/random_roll = rand() + in_atom.add_filter("wibbly-[i]", 5, wave_filter(x = X, y = Y, size = rand() * 2.5 + 0.5, offset = random_roll)) + var/filter = in_atom.get_filter("wibbly-[i]") + animate(filter, offset = random_roll, time = 0, loop = -1, flags = ANIMATION_PARALLEL) + animate(offset = random_roll - 1, time = rand() * 20 + 10) + +/proc/remove_wibbly_filters(atom/in_atom) + var/filter + for(var/i in 1 to 7) + filter = in_atom.get_filter("wibbly-[i]") + animate(filter) + in_atom.remove_filter("wibbly-[i]") diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm index 6a1313c0c04..d1f530933c2 100644 --- a/code/_onclick/hud/plane_master.dm +++ b/code/_onclick/hud/plane_master.dm @@ -40,7 +40,7 @@ /atom/movable/screen/plane_master/proc/shadow(_size, _offset = 0, _x = 0, _y = 0, _color = "#04080FAA") filters += filter(type = "drop_shadow", x = _x, y = _y, color = _color, size = _size, offset = _offset) -/atom/movable/screen/plane_master/proc/clear_filters() +/atom/movable/screen/plane_master/clear_filters() filters = list() ///Contains just the floor @@ -226,3 +226,14 @@ render_target = O_LIGHTING_VISUAL_RENDER_TARGET mouse_opacity = MOUSE_OPACITY_TRANSPARENT blend_mode = BLEND_MULTIPLY + +// /atom/movable/screen/plane_master/runechat +// name = "runechat plane master" +// plane = RUNECHAT_PLANE +// appearance_flags = PLANE_MASTER +// blend_mode = BLEND_OVERLAY + +// /atom/movable/screen/plane_master/runechat/backdrop(mob/mymob) +// filters = list() +// if(istype(mymob) && mymob.client?.prefs?.ambientocclusion) +// add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA")) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index d1f6c448465..bc55519b124 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -947,6 +947,9 @@ VV_DROPDOWN_OPTION(VV_HK_ADD_REAGENT, "Add Reagent") VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EMP, "EMP Pulse") VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EXPLOSION, "Explosion") + VV_DROPDOWN_OPTION(VV_HK_RADIATE, "Radiate") + VV_DROPDOWN_OPTION(VV_HK_EDIT_FILTERS, "Edit Filters") + VV_DROPDOWN_OPTION(VV_HK_ADD_AI, "Add AI controller") /atom/vv_do_topic(list/href_list) . = ..() @@ -994,6 +997,10 @@ var/client/C = usr.client C?.open_color_matrix_editor(src) + if(href_list[VV_HK_EDIT_FILTERS] && check_rights(R_VAREDIT)) + var/client/C = usr.client + C?.open_filter_editor(src) + /atom/vv_get_header() . = ..() var/refid = REF(src) @@ -1257,6 +1264,34 @@ filters += filter(arglist(arguments)) UNSETEMPTY(filter_data) +/atom/proc/transition_filter(name, time, list/new_params, easing, loop) + var/filter = get_filter(name) + if(!filter) + return + + var/list/old_filter_data = filter_data[name] + + var/list/params = old_filter_data.Copy() + for(var/thing in new_params) + params[thing] = new_params[thing] + + animate(filter, new_params, time = time, easing = easing, loop = loop) + for(var/param in params) + filter_data[name][param] = params[param] + +/atom/proc/change_filter_priority(name, new_priority) + if(!filter_data || !filter_data[name]) + return + + filter_data[name]["priority"] = new_priority + update_filters() + +/obj/item/update_filters() + . = ..() + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() + /atom/proc/get_filter(name) if(filter_data && filter_data[name]) return filters[filter_data.Find(name)] @@ -1272,6 +1307,10 @@ filter_data -= name update_filters() +/atom/proc/clear_filters() + filter_data = null + filters = null + /atom/proc/intercept_zImpact(atom/movable/AM, levels = 1) . |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels) diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index 978f2d66907..b39054d0431 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -30,6 +30,7 @@ GLOBAL_PROTECT(href_token) /// if set to anything non-null, will make the admin see invisible objects, shrimple as var/see_invis_override + var/datum/filter_editor/filteriffic /datum/admins/New(datum/admin_rank/R, ckey, force_active = FALSE, protected) if(IsAdminAdvancedProcCall()) diff --git a/code/modules/admin/view_variables/filterrific.dm b/code/modules/admin/view_variables/filterrific.dm new file mode 100644 index 00000000000..e651028cbe6 --- /dev/null +++ b/code/modules/admin/view_variables/filterrific.dm @@ -0,0 +1,99 @@ +/datum/filter_editor + var/atom/target + +/datum/filter_editor/New(atom/target) + src.target = target + +/datum/filter_editor/ui_state(mob/user) + return GLOB.admin_state + +/datum/filter_editor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Filteriffic") + ui.open() + +/datum/filter_editor/ui_static_data(mob/user) + var/list/data = list() + data["filter_info"] = GLOB.master_filter_info + return data + +/datum/filter_editor/ui_data() + var/list/data = list() + data["target_name"] = target.name + data["target_filter_data"] = target.filter_data + return data + +/datum/filter_editor/ui_act(action, list/params) + . = ..() + if(.) + return + + switch(action) + if("add_filter") + var/target_name = params["name"] + while(target.filter_data && target.filter_data[target_name]) + target_name = "[target_name]-dupe" + target.add_filter(target_name, params["priority"], list("type" = params["type"])) + . = TRUE + if("remove_filter") + target.remove_filter(params["name"]) + . = TRUE + if("rename_filter") + var/list/filter_data = target.filter_data[params["name"]] + target.remove_filter(params["name"]) + target.add_filter(params["new_name"], filter_data["priority"], filter_data) + . = TRUE + if("edit_filter") + target.remove_filter(params["name"]) + target.add_filter(params["name"], params["priority"], params["new_filter"]) + . = TRUE + if("change_priority") + var/new_priority = params["new_priority"] + target.change_filter_priority(params["name"], new_priority) + . = TRUE + if("transition_filter_value") + target.transition_filter(params["name"], 4, params["new_data"]) + . = TRUE + if("modify_filter_value") + var/list/old_filter_data = target.filter_data[params["name"]] + var/list/new_filter_data = old_filter_data.Copy() + for(var/entry in params["new_data"]) + new_filter_data[entry] = params["new_data"][entry] + for(var/entry in new_filter_data) + if(entry == GLOB.master_filter_info[old_filter_data["type"]]["defaults"][entry]) + new_filter_data.Remove(entry) + target.remove_filter(params["name"]) + target.add_filter(params["name"], old_filter_data["priority"], new_filter_data) + . = TRUE + if("modify_color_value") + var/new_color = input(usr, "Pick new filter color", "Filteriffic Colors!") as color|null + if(new_color) + target.transition_filter(params["name"], 4, list("color" = new_color)) + . = TRUE + if("modify_icon_value") + var/icon/new_icon = input("Pick icon:", "Icon") as null|icon + if(new_icon) + target.filter_data[params["name"]]["icon"] = new_icon + target.update_filters() + . = TRUE + if("mass_apply") + if(!check_rights_for(usr.client, R_FUN)) + to_chat(usr, "900) - user.filters += filter(type="wave", x=X, y=Y, size=rand()*2.5+0.5, offset=rand()) - for(i=1, i<=7, ++i) - f = user.filters[start+i] - animate(f, offset=f:offset, time=0, loop=3, flags=ANIMATION_PARALLEL) - animate(offset=f:offset-1, time=rand()*20+10) + apply_wibbly_filters(user) if (do_after(user, 50, target=user) && user.cell.use(activationCost)) playsound(src, 'sound/effects/bamf.ogg', 100, TRUE, -6) to_chat(user, span_notice("I am now disguised as the US Government engineering borg \"[friendlyName]\".")) @@ -128,10 +116,7 @@ else to_chat(user, span_warning("The chameleon field fizzles.")) do_sparks(3, FALSE, user) - for(i=1, i<=min(7, user.filters.len), ++i) // removing filters that are animating does nothing, we gotta stop the animations first - f = user.filters[start+i] - animate(f) - user.filters = null + remove_wibbly_filters(user) animation_playing = FALSE /obj/item/borg_chameleon/process() diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index aad884a91fd..f5a8a70b5d5 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -1253,3 +1253,7 @@ GLOBAL_LIST_EMPTY(every_fucking_sound_file) nicebutt.update_genitals(TRUE) return TRUE */ +/client/proc/open_filter_editor(atom/in_atom) + if(holder) + holder.filteriffic = new /datum/filter_editor(in_atom) + holder.filteriffic.ui_interact(mob) diff --git a/fortune13.dme b/fortune13.dme index 34f8132b358..ec61072c56e 100644 --- a/fortune13.dme +++ b/fortune13.dme @@ -1574,6 +1574,7 @@ #include "code\modules\admin\view_variables\admin_delete.dm" #include "code\modules\admin\view_variables\color_matrix_editor.dm" #include "code\modules\admin\view_variables\debug_variables.dm" +#include "code\modules\admin\view_variables\filterrific.dm" #include "code\modules\admin\view_variables\get_variables.dm" #include "code\modules\admin\view_variables\mark_datum.dm" #include "code\modules\admin\view_variables\mass_edit_variables.dm" diff --git a/tgui/packages/tgui/interfaces/Filteriffic.js b/tgui/packages/tgui/interfaces/Filteriffic.js new file mode 100644 index 00000000000..39695ea54c8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Filteriffic.js @@ -0,0 +1,307 @@ +import { useBackend, useLocalState } from "../backend"; +import { Fragment } from 'inferno'; +import { Box, Button, Collapsible, ColorBox, Dropdown, Input, LabeledList, NoticeBox, NumberInput, Section } from '../components'; +import { Window } from '../layouts'; +import { map } from 'common/collections'; +import { toFixed } from 'common/math'; +import { numberOfDecimalDigits } from "../../common/math"; + +const FilterIntegerEntry = (props, context) => { + const { value, name, filterName } = props; + const { act } = useBackend(context); + return ( + act('modify_filter_value', { + name: filterName, + new_data: { + [name]: value, + }, + })} /> + ); +}; + +const FilterFloatEntry = (props, context) => { + const { value, name, filterName } = props; + const { act } = useBackend(context); + const [step, setStep] = useLocalState(context, `${filterName}-${name}`, 0.01); + return ( + + toFixed(value, numberOfDecimalDigits(step))} + width="80px" + onDrag={(e, value) => act('transition_filter_value', { + name: filterName, + new_data: { + [name]: value, + }, + })} /> + + Step: + + toFixed(value, 4)} + width="70px" + onChange={(e, value) => setStep(value)} /> + + ); +}; + +const FilterTextEntry = (props, context) => { + const { value, name, filterName } = props; + const { act } = useBackend(context); + + return ( + act('modify_filter_value', { + name: filterName, + new_data: { + [name]: value, + }, + })} /> + ); +}; + +const FilterColorEntry = (props, context) => { + const { value, filterName, name } = props; + const { act } = useBackend(context); + return ( + +