Files
Bubberstation/code/game/objects/items/paint.dm
SmArtKar a27949d5f5 Advanced Color Shifting: Spraypaint Edition (#88201)
## About The Pull Request

"If GAGS is such a good system, why isn't there GAGS 2?" - Sun Tzu

GAGS is very neat but it has one glaring issue: it needs sprites to be
greyscaled in advance to be used. On the other hand we have color
matrices, but they're hard to use and even harder to get good results
from. The logical solution grew out of a discord argument about colors
this morning after @LemonInTheDark decided to toy around with HSL
matrices using filters on live servers.

This PR implements Color Transition Filters as an additional option for
atom colors - passing a transition filter matrix into
``add_atom_colour`` will "recolor" the atom into the passed color by
using an HSL filter (since color only supports RGB values and matrices).
Normal color matrices are now also supported in atom colors, in case
anyone needs to use them there. ``color_transition_filter`` has 2 modes:
``SATURATION_MULTIPLY`` which only changes the hue and shifts saturation
of the original icon, and ``SATURATION_OVERRIDE`` which changes
saturation and light values to more correctly fit the passed color.
Multiply mode does a far better job at recoloring clothing or objects
with obvious highlights, but fails to color pale or white objects, while
Override mode is closer to what we have right now (just doesn't produce
rancid blobs of color nearly as much)

Here are some examples of colored clothes, mechs, items and tiles using
the new system.

Green RD? Sure.

![image](https://github.com/user-attachments/assets/6d79cac3-15a5-4850-abae-19219e1d4bdb)

Atmos MODsuit colored with a speed potion

![4cTKpeu](https://github.com/user-attachments/assets/9106e74c-8d60-489a-9ef7-4d154ddbbdf9)

Why override mode exists in the first place

![dreamseeker_fAKn811LXT](https://github.com/user-attachments/assets/3d3bea8c-5e27-4390-a924-0c243265fa6a)

Aftermath of a colorful reagent grenade.

![image](https://github.com/user-attachments/assets/ba4c78c5-cba5-42da-ac4d-7861bb329b68)

As you can see, the colors are far brighter and significantly less
acidic, since they're no longer just used as multipliers for existing
colors but instead shift the palette of the sprite towards themselves.

In order to bypass the main downside of "default" Multiply mode,
spraycans have received a new right click function "coat with paint",
which will color the item using the Override mode. Left Click mode lost
its coloring restrictions (RMB still has them), and color
sampling/prosthetic recoloring has been moved to Ctrl Click instead.
Here's the full list of all systems/items that now use color transition
filters:
 * Drying items
 * Deep frying items
 * Slime blueprints/potions/coloring crossbreeds
 * Colorful reagent
 * Spraycans
 * Paint buckets

## Why It's Good For The Game

Our coloring system is ***really*** bad, to the point where we're
preventing players from using any dark colors because item icons become
unintelligible when colored into them.

## Changelog
🆑 SmArtKar, LemonInTheDark
add: Changed how spraycans color items - "old" mode is still availible
via right click.
refactor: Refactored how some items and effects color things so that
they look prettier.
/🆑
2024-12-13 00:12:14 -08:00

142 lines
4.0 KiB
Plaintext

//NEVER USE THIS IT SUX -PETETHEGOAT
//IT SUCKS A BIT LESS -GIACOM
/obj/item/paint
gender= PLURAL
name = "paint"
desc = "Used to recolor floors and walls. Can be removed by the janitor."
icon = 'icons/obj/art/paint.dmi'
icon_state = "paint_neutral"
inhand_icon_state = "paintcan"
w_class = WEIGHT_CLASS_NORMAL
resistance_flags = FLAMMABLE
max_integrity = 100
/// With what color will we paint with
var/paint_color = COLOR_WHITE
/// How many uses are left
var/paintleft = 200
/obj/item/paint/Initialize(mapload)
. = ..()
AddElement(/datum/element/falling_hazard, damage = 20, wound_bonus = 5, hardhat_safety = TRUE, crushes = FALSE) // You ever watched home alone?
/obj/item/paint/red
name = "red paint"
paint_color = COLOR_RED
icon_state = "paint_red"
/obj/item/paint/green
name = "green paint"
paint_color = COLOR_VIBRANT_LIME
icon_state = "paint_green"
/obj/item/paint/blue
name = "blue paint"
paint_color = COLOR_BLUE
icon_state = "paint_blue"
/obj/item/paint/yellow
name = "yellow paint"
paint_color = COLOR_YELLOW
icon_state = "paint_yellow"
/obj/item/paint/violet
name = "violet paint"
paint_color = COLOR_MAGENTA
icon_state = "paint_violet"
/obj/item/paint/black
name = "black paint"
paint_color = COLOR_ALMOST_BLACK
icon_state = "paint_black"
/obj/item/paint/white
name = "white paint"
paint_color = COLOR_WHITE
icon_state = "paint_white"
/obj/item/paint/anycolor
gender = PLURAL
name = "adaptive paint"
icon_state = "paint_neutral"
/obj/item/paint/anycolor/cyborg
paintleft = INFINITY
/obj/item/paint/anycolor/attack_self(mob/user)
if(paintleft <= 0)
balloon_alert(user, "no paint left!")
return // Don't do any of the following because there's no paint left to be able to change the color of
var/list/possible_colors = list(
"black" = image(icon = src.icon, icon_state = "paint_black"),
"blue" = image(icon = src.icon, icon_state = "paint_blue"),
"green" = image(icon = src.icon, icon_state = "paint_green"),
"red" = image(icon = src.icon, icon_state = "paint_red"),
"violet" = image(icon = src.icon, icon_state = "paint_violet"),
"white" = image(icon = src.icon, icon_state = "paint_white"),
"yellow" = image(icon = src.icon, icon_state = "paint_yellow")
)
var/picked_color = show_radial_menu(user, src, possible_colors, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 38, require_near = TRUE)
switch(picked_color)
if("black")
paint_color = COLOR_ALMOST_BLACK
if("blue")
paint_color = COLOR_BLUE
if("green")
paint_color = COLOR_VIBRANT_LIME
if("red")
paint_color = COLOR_RED
if("violet")
paint_color = COLOR_MAGENTA
if("white")
paint_color = COLOR_WHITE
if("yellow")
paint_color = COLOR_YELLOW
else
return
icon_state = "paint_[picked_color]"
add_fingerprint(user)
/**
* Checks if we are allowed to interact with a radial menu
*
* Arguments:
* * user The mob interacting with the menu
*/
/obj/item/paint/anycolor/proc/check_menu(mob/user)
if(!istype(user))
return FALSE
if(!user.is_holding(src))
return FALSE
if(user.incapacitated)
return FALSE
return TRUE
/obj/item/paint/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isturf(interacting_with) || isspaceturf(interacting_with))
return NONE
if(paintleft <= 0)
return NONE
paintleft--
var/color_type = SATURATION_MULTIPLY
if (LAZYACCESS(modifiers, RIGHT_CLICK))
color_type = SATURATION_OVERRIDE
interacting_with.add_atom_colour(color_transition_filter(paint_color, color_type), WASHABLE_COLOUR_PRIORITY)
if(paintleft <= 0)
icon_state = "paint_empty"
return ITEM_INTERACT_SUCCESS
/obj/item/paint/paint_remover
gender = PLURAL
name = "paint remover"
desc = "Used to remove color from anything."
icon_state = "paint_neutral"
/obj/item/paint/paint_remover/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isturf(interacting_with) || !isobj(interacting_with))
return NONE
if(interacting_with.color != initial(interacting_with.color))
interacting_with.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
return ITEM_INTERACT_SUCCESS
return NONE