From a1da8c5e00a7c048944040444eb27c2953e93c74 Mon Sep 17 00:00:00 2001
From: Kashargul <144968721+Kashargul@users.noreply.github.com>
Date: Sat, 16 Dec 2023 21:14:48 +0100
Subject: [PATCH] self recolour for simple mob / robot (#7415)
---
code/__defines/misc_ch.dm | 7 +-
.../code/datums/colormate/colormate.dm | 219 ++++++++++++++++++
.../code/game/machinery/colormate.dm | 6 +-
.../modules/mob/living/silicon/robot/robot.dm | 16 ++
.../mob/living/simple_mob/simple_mob.dm | 12 +
vorestation.dme | 1 +
6 files changed, 255 insertions(+), 6 deletions(-)
create mode 100644 modular_chomp/code/datums/colormate/colormate.dm
diff --git a/code/__defines/misc_ch.dm b/code/__defines/misc_ch.dm
index 58f0f9ac4d..c3ca475a8d 100644
--- a/code/__defines/misc_ch.dm
+++ b/code/__defines/misc_ch.dm
@@ -31,4 +31,9 @@
#define VANTAG_VORE_D "vantag_vore_d"
#define VANTAG_VORE_DE "vantag_vore_de"
#define VANTAG_VORE_DD "vantag_vore_dd"
-#define VANTAG_VORE_DA "vantag_vore_da"
\ No newline at end of file
+#define VANTAG_VORE_DA "vantag_vore_da"
+
+// ColorMate states
+#define COLORMATE_TINT 1
+#define COLORMATE_HSV 2
+#define COLORMATE_MATRIX 3
diff --git a/modular_chomp/code/datums/colormate/colormate.dm b/modular_chomp/code/datums/colormate/colormate.dm
new file mode 100644
index 0000000000..5f23d25260
--- /dev/null
+++ b/modular_chomp/code/datums/colormate/colormate.dm
@@ -0,0 +1,219 @@
+/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", name)
+ ui.open()
+
+/datum/ColorMate/ui_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/modular_chomp/code/game/machinery/colormate.dm b/modular_chomp/code/game/machinery/colormate.dm
index e3a3537352..71104d9930 100644
--- a/modular_chomp/code/game/machinery/colormate.dm
+++ b/modular_chomp/code/game/machinery/colormate.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!"
@@ -297,4 +293,4 @@
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
\ No newline at end of file
+ return TRUE
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/robot.dm b/modular_chomp/code/modules/mob/living/silicon/robot/robot.dm
index d9f3588b4d..20e7757f1e 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/robot.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/robot.dm
@@ -1,6 +1,7 @@
/mob/living/silicon/robot
var/sleeper_resting = FALSE //Enable resting belly sprites for dogborgs that have the sprites
var/datum/matter_synth/water_res = null //Enable water for lick clean
+ var/has_recoloured = FALSE
/mob/living/silicon/robot/verb/purge_nutrition()
set name = "Purge Nutrition"
@@ -28,3 +29,18 @@
to_chat(src, "You refill the extinguisher using your water reserves.")
else
to_chat(src, "Insufficient water reserves.")
+
+/mob/living/silicon/robot/module_reset()
+ ..()
+ has_recoloured = FALSE
+
+/mob/living/silicon/robot/verb/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.")
diff --git a/modular_chomp/code/modules/mob/living/simple_mob/simple_mob.dm b/modular_chomp/code/modules/mob/living/simple_mob/simple_mob.dm
index b8ed4037ba..8bbf3cb06a 100644
--- a/modular_chomp/code/modules/mob/living/simple_mob/simple_mob.dm
+++ b/modular_chomp/code/modules/mob/living/simple_mob/simple_mob.dm
@@ -3,6 +3,7 @@
var/list/speech_sounds = list()
var/speech_chance = 75 //mobs can be a bit more emotive than carbon/humans
var/speech_sound_enabled = TRUE
+ var/has_recoloured = FALSE
//vars for vore_icons toggle control
var/vore_icons_cache = null // null by default. Going from ON to OFF should store vore_icons val here, OFF to ON reset as null
@@ -132,3 +133,14 @@
/mob/living/simple_mob/proc/character_directory_species()
return "simplemob"
+
+/mob/living/simple_mob/verb/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 02c40a0f97..cc36199df7 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -4607,6 +4607,7 @@
#include "modular_chomp\code\datums\autolathe\general_ch.dm"
#include "modular_chomp\code\datums\browser\color_matrix_picker.dm"
#include "modular_chomp\code\datums\changelog\changelog.dm"
+#include "modular_chomp\code\datums\colormate\colormate.dm"
#include "modular_chomp\code\datums\components\gargoyle.dm"
#include "modular_chomp\code\datums\components\squeak.dm"
#include "modular_chomp\code\datums\components\xenoqueen.dm"