From 11c6c90c3bd43278ea27f1de77911e73b849bbd8 Mon Sep 17 00:00:00 2001 From: Runa-Dacino Date: Fri, 15 Mar 2024 19:03:27 +0100 Subject: [PATCH] add(colormate): Ports recolouring for simple mobs and cyborgs Original PR: https://github.com/CHOMPStation2/CHOMPStation2/pull/7415 Original Author: https://github.com/Kashargul Personal Addition: * Added config for letting simples/robots spawn with recolour verb * Added verb for admins to temporarily edit the config on live. --- code/__defines/misc_vr.dm | 7 +- code/controllers/configuration.dm | 8 + code/datums/colormate.dm | 213 ++++++++++++++++++ code/game/machinery/painter_vr.dm | 4 - code/modules/admin/admin_verb_lists_vr.dm | 3 +- code/modules/admin/admin_verbs_vr.dm | 17 ++ .../modules/mob/living/silicon/robot/robot.dm | 20 ++ .../mob/living/simple_mob/simple_mob.dm | 17 ++ vorestation.dme | 1 + 9 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 code/datums/colormate.dm diff --git a/code/__defines/misc_vr.dm b/code/__defines/misc_vr.dm index 9c5896a8066..114448b9167 100644 --- a/code/__defines/misc_vr.dm +++ b/code/__defines/misc_vr.dm @@ -14,6 +14,11 @@ #define VANTAG_KIDNAP "vantag_kidnap" #define VANTAG_KILL "vantag_kill" +// ColorMate states +#define COLORMATE_TINT 1 +#define COLORMATE_HSV 2 +#define COLORMATE_MATRIX 3 + #define DEPARTMENT_OFFDUTY "Off-Duty" #define ANNOUNCER_NAME "Facility PA" @@ -81,4 +86,4 @@ #define RESIZE_A_HUGEBIG (RESIZE_HUGE + RESIZE_BIG) / 2 #define RESIZE_A_BIGNORMAL (RESIZE_BIG + RESIZE_NORMAL) / 2 #define RESIZE_A_NORMALSMALL (RESIZE_NORMAL + RESIZE_SMALL) / 2 -#define RESIZE_A_SMALLTINY (RESIZE_SMALL + RESIZE_TINY) / 2 \ No newline at end of file +#define RESIZE_A_SMALLTINY (RESIZE_SMALL + RESIZE_TINY) / 2 diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index b4b5d955e76..e0bc68325cf 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -304,6 +304,10 @@ var/list/gamemode_cache = list() var/static/invoke_youtubedl = null + //Enables/Disables the appropriate mob type from obtaining the verb on spawn. Still allows admins to manually give it to them. + var/static/allow_robot_recolor = FALSE + var/static/allow_simple_mob_recolor = FALSE + /datum/configuration/New() var/list/L = subtypesof(/datum/game_mode) for (var/T in L) @@ -1047,6 +1051,10 @@ var/list/gamemode_cache = list() if("loadout_whitelist") config.loadout_whitelist = text2num(value) + if("allow_robot_recolor") + config.allow_robot_recolor = 1 + if("allow_simple_mob_recolor") + config.allow_simple_mob_recolor = 1 else log_misc("Unknown setting in configuration: '[name]'") diff --git a/code/datums/colormate.dm b/code/datums/colormate.dm new file mode 100644 index 00000000000..2149191543f --- /dev/null +++ b/code/datums/colormate.dm @@ -0,0 +1,213 @@ +/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() + . = 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()) + 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 = input(inserted, "Choose a color: ", "ColorMate colour picking", activecolor) as color|null + if(chosen_color) + activecolor = chosen_color + return TRUE + if("paint") + do_paint(inserted) + temp = "Painted Successfully!" + if(istype(inserted, /mob/living/simple_mob)) + var/mob/living/simple_mob/M = inserted + M.has_recoloured = TRUE + if(istype(inserted, /mob/living/silicon/robot)) + 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_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() + 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, usr)) + return get_flat_icon(inserted, dir=SOUTH, no_anim=TRUE) + + if(COLORMATE_TINT) + if(!check_valid_color(activecolor, usr)) + 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, usr)) + 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/game/machinery/painter_vr.dm b/code/game/machinery/painter_vr.dm index 95b0e4a4ef6..53614b2f904 100644 --- a/code/game/machinery/painter_vr.dm +++ b/code/game/machinery/painter_vr.dm @@ -1,7 +1,3 @@ -#define COLORMATE_TINT 1 -#define COLORMATE_HSV 2 -#define COLORMATE_MATRIX 3 - /obj/machinery/gear_painter name = "Color Mate" desc = "A machine to give your apparel a fresh new color!" diff --git a/code/modules/admin/admin_verb_lists_vr.dm b/code/modules/admin/admin_verb_lists_vr.dm index cc249bb4d8a..92e6620411a 100644 --- a/code/modules/admin/admin_verb_lists_vr.dm +++ b/code/modules/admin/admin_verb_lists_vr.dm @@ -222,7 +222,8 @@ var/list/admin_verbs_server = list( /client/proc/recipe_dump, /client/proc/panicbunker, /client/proc/paranoia_logging, - /client/proc/ip_reputation + /client/proc/ip_reputation, + /client/proc/toggle_spawning_with_recolour ) var/list/admin_verbs_debug = list( diff --git a/code/modules/admin/admin_verbs_vr.dm b/code/modules/admin/admin_verbs_vr.dm index 3a65d070d2b..7b6bf90c528 100644 --- a/code/modules/admin/admin_verbs_vr.dm +++ b/code/modules/admin/admin_verbs_vr.dm @@ -120,3 +120,20 @@ usr << browse(dat, "window=library") onclose(usr, "library") + +/client/proc/toggle_spawning_with_recolour() + set name = "Toggle Simple/Robot recolour verb" + set desc = "Makes it so new robots/simple_mobs spawn with a verb to recolour themselves for this round. You must set them separately." + set category = "Server" + + if(!check_rights(R_SERVER)) + return + + var/which = tgui_alert(usr, "Which do you want to toggle?", "Choose Recolour Toggle", list("Robot", "Simple Mob")) + switch(which) + if("Robot") + config.allow_robot_recolor = !config.allow_robot_recolor + to_chat(usr, "You have [config.allow_robot_recolor ? "enabled" : "disabled"] newly spawned cyborgs to spawn with the recolour verb") + if("Simple Mob") + config.allow_simple_mob_recolor = !config.allow_simple_mob_recolor + to_chat(usr, "You have [config.allow_simple_mob_recolor ? "enabled" : "disabled"] newly spawned simple mobs to spawn with the recolour verb") diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index ce59e59bb51..bd7f419f7f6 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -113,6 +113,8 @@ /mob/living/proc/lend_prey_control ) + var/has_recoloured = FALSE + /mob/living/silicon/robot/New(loc, var/unfinished = 0) spark_system = new /datum/effect/effect/system/spark_spread() spark_system.set_up(5, 0, src) @@ -174,6 +176,8 @@ hud_list[IMPTRACK_HUD] = gen_hud_image('icons/mob/hud.dmi', src, "hudblank", plane = PLANE_CH_IMPTRACK) hud_list[SPECIALROLE_HUD] = gen_hud_image('icons/mob/hud.dmi', src, "hudblank", plane = PLANE_CH_SPECIAL) + + /mob/living/silicon/robot/LateInitialize() . = ..() update_icon() @@ -818,6 +822,18 @@ module.Destroy() module = null updatename("Default") + has_recoloured = FALSE + +/mob/living/silicon/robot/proc/ColorMate() + set name = "Recolour Module" + set category = "Robot Commands" + set desc = "Allows to recolour once." + + if(!has_recoloured) + var/datum/ColorMate/recolour = new /datum/ColorMate(usr) + recolour.tgui_interact(usr) + return + to_chat(usr, "You've already recoloured yourself once. Ask for a module reset for another.") /mob/living/silicon/robot/attack_hand(mob/user) @@ -1253,10 +1269,14 @@ /mob/living/silicon/robot/proc/add_robot_verbs() src.verbs |= robot_verbs_default src.verbs |= silicon_subsystems + if(config.allow_robot_recolor) + src.verbs |= /mob/living/silicon/robot/proc/ColorMate /mob/living/silicon/robot/proc/remove_robot_verbs() src.verbs -= robot_verbs_default src.verbs -= silicon_subsystems + if(config.allow_robot_recolor) + src.verbs |= /mob/living/silicon/robot/proc/ColorMate // Uses power from cyborg's cell. Returns 1 on success or 0 on failure. // Properly converts using CELLRATE now! Amount is in Joules. diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm index fe671688919..2046ad0106c 100644 --- a/code/modules/mob/living/simple_mob/simple_mob.dm +++ b/code/modules/mob/living/simple_mob/simple_mob.dm @@ -174,6 +174,8 @@ var/injury_enrages = FALSE // Do injuries enrage (aka strengthen) our mob? If yes, we'll interpret how hurt we are differently. // VOREStation Add End + var/has_recoloured = FALSE + /mob/living/simple_mob/Initialize() verbs -= /mob/verb/observe health = maxHealth @@ -193,6 +195,10 @@ if(organ_names) organ_names = GET_DECL(organ_names) + if(config.allow_simple_mob_recolor) + verbs |= /mob/living/simple_mob/proc/ColorMate + + return ..() /mob/living/simple_mob/Destroy() @@ -337,3 +343,14 @@ . = ..() // Calling parent here, actually updating our mob on how hurt we are. // VOREStation Add End + +/mob/living/simple_mob/proc/ColorMate() + set name = "Recolour" + set category = "Abilities" + set desc = "Allows to recolour once." + + if(!has_recoloured) + var/datum/ColorMate/recolour = new /datum/ColorMate(usr) + recolour.tgui_interact(usr) + return + to_chat(usr, "You've already recoloured yourself once. You are only allowed to recolour yourself once during a around.") diff --git a/vorestation.dme b/vorestation.dme index e6fb7099fd8..d93ed8edf4c 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -336,6 +336,7 @@ #include "code\datums\category.dm" #include "code\datums\chat_message.dm" #include "code\datums\chat_payload.dm" +#include "code\datums\colormate.dm" #include "code\datums\datacore.dm" #include "code\datums\datum.dm" #include "code\datums\datumvars.dm"