diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index f42db558563..c64fcdefaca 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -442,6 +442,8 @@
#define COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH "obj_default_unfasten_wrench"
///from base of /turf/proc/levelupdate(). (intact) true to hide and false to unhide
#define COMSIG_OBJ_HIDE "obj_hide"
+/// from /obj/item/toy/crayon/spraycan/afterattack: (color_is_dark)
+#define COMSIG_OBJ_PAINTED "obj_painted"
// /obj/machinery signals
diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index c54c7bae57d..0b7e5b585e3 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -42,7 +42,10 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define RAD_PROTECT_CONTENTS_1 (1 << 17)
/// should this object be allowed to be contaminated
#define RAD_NO_CONTAMINATE_1 (1 << 18)
-
+/// Should this object be paintable with very dark colors?
+#define ALLOW_DARK_PAINTS_1 (1 << 19)
+/// Should this object be unpaintable?
+#define UNPAINTABLE_1 (1 << 20)
/// If the thing can reflect light (lasers/energy)
#define RICOCHET_SHINY (1<<0)
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 2e7ffd49133..46719b900a2 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -385,6 +385,12 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH,
else
return "#FFFFFF"
+/// Converts "#RRGGBB" to list(0xRR, 0xGG, 0xBB)
+/proc/hex2rgb(color)
+ var/r = hex2num(copytext(color, 2, 4))
+ var/g = hex2num(copytext(color, 4, 6))
+ var/b = hex2num(copytext(color, 6, 8))
+ return list(r, g, b)
//This is a weird one:
//It returns a list of all var names found in the string
@@ -426,10 +432,8 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH,
/proc/color_hex2num(A)
if(!A || length(A) != length_char(A))
return 0
- var/R = hex2num(copytext(A, 2, 4))
- var/G = hex2num(copytext(A, 4, 6))
- var/B = hex2num(copytext(A, 6, 8))
- return R+G+B
+ var/rgb = hex2rgb(A)
+ return rgb[1] + rgb[2] + rgb[3]
//word of warning: using a matrix like this as a color value will simplify it back to a string after being set
/proc/color_hex2color_matrix(string)
diff --git a/code/datums/components/paintable.dm b/code/datums/components/paintable.dm
deleted file mode 100644
index a0ed2873c90..00000000000
--- a/code/datums/components/paintable.dm
+++ /dev/null
@@ -1,31 +0,0 @@
-/datum/component/spraycan_paintable
- var/current_paint
-
-/datum/component/spraycan_paintable/Initialize()
- RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/Repaint)
-
-/datum/component/spraycan_paintable/Destroy()
- RemoveCurrentCoat()
- return ..()
-
-/datum/component/spraycan_paintable/proc/RemoveCurrentCoat()
- var/atom/A = parent
- A.remove_atom_colour(FIXED_COLOUR_PRIORITY, current_paint)
-
-/datum/component/spraycan_paintable/proc/Repaint(datum/source, obj/item/toy/crayon/spraycan/spraycan, mob/living/user)
- SIGNAL_HANDLER
-
- if(!istype(spraycan) || user.a_intent == INTENT_HARM)
- return
- . = COMPONENT_NO_AFTERATTACK
- if(spraycan.is_capped)
- to_chat(user, "Take the cap off first!")
- return
- RemoveCurrentCoat()
- if(spraycan.use_charges(user, 2))
- var/colour = spraycan.paint_color
- current_paint = colour
- var/atom/A = parent
- A.add_atom_colour(colour, FIXED_COLOUR_PRIORITY)
- playsound(spraycan, 'sound/effects/spray.ogg', 5, TRUE, 5)
- to_chat(user, "You spray [spraycan] on [A], painting it.")
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 31702bffe7a..5bc04648583 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -1,3 +1,5 @@
+#define DARK_COLOR_LIGHTNESS_THRESHOLD 0.25
+
#define RANDOM_GRAFFITI "Random Graffiti"
#define RANDOM_LETTER "Random Letter"
#define RANDOM_PUNCTUATION "Random Punctuation"
@@ -730,13 +732,18 @@
return
- if(istype(target, /obj/structure/window))
+ if(isobj(target) && !(target.flags_1 & UNPAINTABLE_1))
if(actually_paints)
+ var/list/rgb = hex2rgb(paint_color)
+ var/list/hsl = rgb2hsl(rgb[1], rgb[2], rgb[3])
+ var/color_is_dark = hsl[3] < DARK_COLOR_LIGHTNESS_THRESHOLD
+
+ if (color_is_dark && !(target.flags_1 & ALLOW_DARK_PAINTS_1))
+ to_chat(user, "A color that dark on an object like this? Surely not...")
+ return FALSE
+
target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
- if(color_hex2num(paint_color) < 255)
- target.set_opacity(255)
- else
- target.set_opacity(initial(target.opacity))
+ SEND_SIGNAL(target, COMSIG_OBJ_PAINTED, color_is_dark)
. = use_charges(user, 2)
reagents.trans_to(target, ., volume_multiplier, transfered_by = user, methods = VAPOR)
@@ -829,6 +836,7 @@
charges = -1
desc = "Now with 30% more bluespace technology."
+#undef DARK_COLOR_LIGHTNESS_THRESHOLD
#undef RANDOM_GRAFFITI
#undef RANDOM_LETTER
#undef RANDOM_PUNCTUATION
diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm
index 2cb503f7d3b..1885a3da5a1 100644
--- a/code/game/objects/structures/artstuff.dm
+++ b/code/game/objects/structures/artstuff.dm
@@ -40,6 +40,7 @@
desc = "Draw out your soul on this canvas!"
icon = 'icons/obj/artstuff.dmi'
icon_state = "11x11"
+ flags_1 = UNPAINTABLE_1
resistance_flags = FLAMMABLE
var/width = 11
var/height = 11
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 499ffe5c044..e7537f526b6 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -64,6 +64,9 @@
real_explosion_block = explosion_block
explosion_block = EXPLOSION_BLOCK_PROC
+ flags_1 |= ALLOW_DARK_PAINTS_1
+ RegisterSignal(src, COMSIG_OBJ_PAINTED, .proc/on_painted)
+
/obj/structure/window/ComponentInitialize()
. = ..()
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS ,null,CALLBACK(src, .proc/can_be_rotated),CALLBACK(src,.proc/after_rotation))
@@ -283,6 +286,14 @@
ini_dir = dir
add_fingerprint(user)
+/obj/structure/window/proc/on_painted(is_dark_color)
+ SIGNAL_HANDLER
+
+ if (is_dark_color)
+ set_opacity(255)
+ else
+ set_opacity(initial(opacity))
+
/obj/structure/window/Destroy()
density = FALSE
air_update_turf(1)
diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm
index a214d653f71..c52470461e7 100644
--- a/code/modules/mining/equipment/explorer_gear.dm
+++ b/code/modules/mining/equipment/explorer_gear.dm
@@ -69,10 +69,6 @@
armor = list(MELEE = 70, BULLET = 40, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 100)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe)
-/obj/item/clothing/suit/space/hostile_environment/Initialize()
- . = ..()
- AddComponent(/datum/component/spraycan_paintable)
-
/obj/item/clothing/suit/space/hostile_environment/process()
. = ..()
var/mob/living/carbon/C = loc
@@ -96,7 +92,6 @@
/obj/item/clothing/head/helmet/space/hostile_environment/Initialize()
. = ..()
- AddComponent(/datum/component/spraycan_paintable)
update_icon()
/obj/item/clothing/head/helmet/space/hostile_environment/update_overlays()
diff --git a/tgstation.dme b/tgstation.dme
index c9ec525ab14..a243b83d3a5 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -447,7 +447,6 @@
#include "code\datums\components\omen.dm"
#include "code\datums\components\orbiter.dm"
#include "code\datums\components\overlay_lighting.dm"
-#include "code\datums\components\paintable.dm"
#include "code\datums\components\payment.dm"
#include "code\datums\components\pellet_cloud.dm"
#include "code\datums\components\pricetag.dm"