[MIRROR] 81182 81367 81399 (#26492)

* Implements rgb2num, uses it to replace all our manual rgb reading. Redoes HSV management (#81182)

[Converts all manual extraction of rbg with rgb2num. It's just
better](https://github.com/tgstation/tgstation/commit/ae798eabd5aa94dd577169553905d3efd7a7136d)

[Yanks out old HSV management, replaces it with list
stuff](https://github.com/tgstation/tgstation/commit/4997e86051d6388e495524dccba1f3258a47bb48)

There's this old lummy era clunky code that passed HSV as text

We can now cleanly replace it with passing hsv as lists from a rgb2hsv
proc

So let's just do that.

Also, cleans up spraytan code (and ethereal lighting)

Code better

* Refactors fire overlays once again to make it not get stuck so often (#81367)

Maybe finally fixes #77701

A big reason why this kept happening is because fire uses standing
overlays. But fire isn't managed by mobs anymore. Meaning in some
situations, fire can cease to exist but the overlay can still be on the
mob. So it gets stuck.

So like, why use standing overlays anymore? We can just hook
`update_overlays` signal.
Isn't that neat.

🆑 Melbert
refactor: Fire effects get added to mobs in a different way now. Maybe
it will get stuck less. Report any oddities.
/🆑

* Fix Flaky Failure From Fire  (#81399)

## About The Pull Request

Closes #81396 , Closes #81391 , Closes #81403, Closes #81402

I don't know why but I thought this proc was only called once, when the
mob entered the turf. That was silly.

And going back at it, I'm not entirely sure why I tied
`TRAIT_NO_EXTINGUISH` to the element anyways, rather than the lava like
it originally was.

While going back over this, I cleaned up the proc a bit. 

## Changelog

Not necessary

* There we go?

* Bruh moment

---------

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
This commit is contained in:
Useroth
2024-02-13 01:03:58 +01:00
committed by GitHub
parent 3d9735a577
commit 7bb2f5055e
39 changed files with 317 additions and 655 deletions
@@ -3568,7 +3568,7 @@
"aSn" = (
/obj/structure/table,
/obj/machinery/light/directional/west{
bulb_colour = "#e8eaff "
bulb_colour = "#e8eaff"
},
/obj/item/soap,
/obj/item/soap,
+1
View File
@@ -1,3 +1,4 @@
// spacemandmm doesn't really implement gradient() right, so let's just handle that here yeah?
#define rgb_gradient(index, args...) UNLINT(gradient(args, index))
#define hsl_gradient(index, args...) UNLINT(gradient(args, space = COLORSPACE_HSL, index))
#define hsv_gradient(index, args...) UNLINT(gradient(args, space = COLORSPACE_HSV, index))
+4 -13
View File
@@ -102,23 +102,14 @@ GLOBAL_LIST_INIT(em_block_color, EM_BLOCK_COLOR)
/// A globaly cached version of [EM_MASK_MATRIX] for quick access.
GLOBAL_LIST_INIT(em_mask_matrix, EM_MASK_MATRIX)
/// Returns the red part of a #RRGGBB hex sequence as number
#define GETREDPART(hexa) hex2num(copytext(hexa, 2, 4))
/// Returns the green part of a #RRGGBB hex sequence as number
#define GETGREENPART(hexa) hex2num(copytext(hexa, 4, 6))
/// Returns the blue part of a #RRGGBB hex sequence as number
#define GETBLUEPART(hexa) hex2num(copytext(hexa, 6, 8))
/// Parse the hexadecimal color into lumcounts of each perspective.
#define PARSE_LIGHT_COLOR(source) \
do { \
if (source.light_color != COLOR_WHITE) { \
var/__light_color = source.light_color; \
source.lum_r = GETREDPART(__light_color) / 255; \
source.lum_g = GETGREENPART(__light_color) / 255; \
source.lum_b = GETBLUEPART(__light_color) / 255; \
var/list/color_parts = rgb2num(source.light_color); \
source.lum_r = color_parts[1] / 255; \
source.lum_g = color_parts[2] / 255; \
source.lum_b = color_parts[3] / 255; \
} else { \
source.lum_r = 1; \
source.lum_g = 1; \
+3 -6
View File
@@ -500,9 +500,6 @@
#define ROBOTIC_BRUTE_EXAMINE_TEXT "denting"
#define ROBOTIC_BURN_EXAMINE_TEXT "charring"
// If a mob has a higher threshold than this, the icon shown will be increased to the big fire icon.
#define MOB_BIG_FIRE_STACK_THRESHOLD 3
#define GRAB_PIXEL_SHIFT_PASSIVE 6
#define GRAB_PIXEL_SHIFT_AGGRESSIVE 12
#define GRAB_PIXEL_SHIFT_NECK 16
@@ -781,8 +778,8 @@ GLOBAL_LIST_INIT(human_heights_to_offsets, list(
#define WOUND_LAYER 3
/// Blood cult ascended halo layer, because there's currently no better solution for adding/removing
#define HALO_LAYER 2
/// Fire layer when you're on fire
#define FIRE_LAYER 1
/// The highest most layer for mob overlays. Unused
#define HIGHEST_LAYER 1
#define UPPER_BODY "upper body"
#define LOWER_BODY "lower body"
@@ -823,7 +820,7 @@ GLOBAL_LIST_INIT(layers_to_offset, list(
// BODY_BEHIND_LAYER (external organs like wings)
// BODY_FRONT_LAYER (external organs like wings)
// DAMAGE_LAYER (full body)
// FIRE_LAYER (full body)
// HIGHEST_LAYER (full body)
// UNIFORM_LAYER (full body)
// WOUND_LAYER (full body)
))
+5
View File
@@ -31,6 +31,11 @@
/// If the incapacitated status effect will ignore a mob being agressively grabbed
#define IGNORE_GRAB (1<<2)
/// Maxamounts of fire stacks a mob can get
#define MAX_FIRE_STACKS 20
/// If a mob has a higher threshold than this, the icon shown will be increased to the big fire icon.
#define MOB_BIG_FIRE_STACK_THRESHOLD 3
// Grouped effect sources, see also code/__DEFINES/traits.dm
#define STASIS_MACHINE_EFFECT "stasis_machine"
+2 -2
View File
@@ -353,8 +353,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_TUMOR_SUPPRESSED "brain_tumor_suppressed"
/// Prevents hallucinations from the hallucination brain trauma (RDS)
#define TRAIT_RDS_SUPPRESSED "rds_suppressed"
/// mobs that have this trait cannot be extinguished
#define TRAIT_PERMANENTLY_ONFIRE "permanently_onfire"
/// Mobs that have this trait cannot be extinguished
#define TRAIT_NO_EXTINGUISH "no_extinguish"
/// Indicates if the mob is currently speaking with sign language
#define TRAIT_SIGN_LANG "sign_language"
/// This mob is able to use sign language over the radio.
+4 -11
View File
@@ -19,13 +19,8 @@
/// Given a color in the format of "#RRGGBB" or "#RRGGBBAA", gives back a 4 entry list with the number values of each
/proc/split_color(color)
var/list/output = list()
output += hex2num(copytext(color, 2, 4))
output += hex2num(copytext(color, 4, 6))
output += hex2num(copytext(color, 6, 8))
if(length(color) == 9)
output += hex2num(copytext(color, 8, 10))
else
var/list/output = rgb2num(color)
if(length(output) == 3)
output += 255
return output
@@ -49,10 +44,8 @@
CRASH("Given non-HTML argument!")
else if(length_char(HTMLstring) != 7)
CRASH("Given non-hex symbols in argument!")
var/textr = copytext(HTMLstring, 2, 4)
var/textg = copytext(HTMLstring, 4, 6)
var/textb = copytext(HTMLstring, 6, 8)
return rgb(255 - hex2num(textr), 255 - hex2num(textg), 255 - hex2num(textb))
var/list/color = rgb2num(HTMLstring)
return rgb(255 - color[1], 255 - color[2], 255 - color[3])
///Flash a color on the passed mob
/proc/flash_color(mob_or_client, flash_color="#960000", flash_time=20)
+82 -346
View File
@@ -1,14 +1,22 @@
/*
IconProcs README
A BYOND library for manipulating icons and colors
by Lummox JR
version 1.0
The IconProcs library was made to make a lot of common icon operations much easier. BYOND's icon manipulation
routines are very capable but some of the advanced capabilities like using alpha transparency can be unintuitive to beginners.
CHANGING ICONS
Several new procs have been added to the /icon datum to simplify working with icons. To use them,
remember you first need to setup an /icon var like so:
GLOBAL_DATUM_INIT(my_icon, /icon, new('iconfile.dmi'))
icon/ChangeOpacity(amount = 1)
A very common operation in DM is to try to make an icon more or less transparent. Making an icon more
transparent is usually much easier than making it less so, however. This proc basically is a frontend
@@ -40,58 +48,53 @@ icon/UseAlphaMask(mask, mode)
Sometimes you may want to take the alpha values from one icon and use them on a different icon.
This proc will do that. Just supply the icon whose alpha mask you want to use, and src will change
so it has the same colors as before but uses the mask for opacity.
COLOR MANAGEMENT AND HSV
RGB isn't the only way to represent color. Sometimes it's more useful to work with a model called HSV, which stands for hue, saturation, and value.
* The hue of a color describes where it is along the color wheel. It goes from red to yellow to green to
cyan to blue to magenta and back to red.
* The saturation of a color is how much color is in it. A color with low saturation will be more gray,
and with no saturation at all it is a shade of gray.
* The value of a color determines how bright it is. A high-value color is vivid, moderate value is dark,
and no value at all is black.
Just as BYOND uses "#rrggbb" to represent RGB values, a similar format is used for HSV: "#hhhssvv". The hue is three
hex digits because it ranges from 0 to 0x5FF.
* 0 to 0xFF - red to yellow
* 0x100 to 0x1FF - yellow to green
* 0x200 to 0x2FF - green to cyan
* 0x300 to 0x3FF - cyan to blue
* 0x400 to 0x4FF - blue to magenta
* 0x500 to 0x5FF - magenta to red
Knowing this, you can figure out that red is "#000ffff" in HSV format, which is hue 0 (red), saturation 255 (as colorful as possible),
value 255 (as bright as possible). Green is "#200ffff" and blue is "#400ffff".
More than one HSV color can match the same RGB color.
While rgb is typically stored in the #rrggbb" format (with optional "aa" on the end), HSV never needs to be displayed.
Most procs that work in HSV "space" will simply accept RGB inputs and convert them in place using rgb2num(color, space = COLORSPACE_HSV).
That said, if you want to manually modify these values rgb2hsv() will hand you back a list in the format list(hue, saturation, value, alpha).
Converting back is simple, just a hsv2rgb(hsv) call
Hue ranges from 0 to 360 (it's in degrees of a color wheel)
Saturation ranges from 0 to 100
Value ranges from 0 to 100
Knowing this, you can figure out that red is list(0, 100, 100) in HSV format, which is hue 0 (red), saturation 100 (as colorful as possible),
value 255 (as bright as possible). Green is list(120, 100, 100) and blue is list(240, 100, 100).
It is worth noting that while we do not have helpers for them currently, these same ideas apply to all of byond's color spaces
HSV (hue saturation value), HSL (hue satriation luminosity) and HCY (hue chroma luminosity)
Here are some procs you can use for color management:
ReadRGB(rgb)
Takes an RGB string like "#ffaa55" and converts it to a list such as list(255,170,85). If an RGBA format is used
that includes alpha, the list will have a fourth item for the alpha value.
hsv(hue, sat, val, apha)
Counterpart to rgb(), this takes the values you input and converts them to a string in "#hhhssvv" or "#hhhssvvaa"
format. Alpha is not included in the result if null.
ReadHSV(rgb)
Takes an HSV string like "#100FF80" and converts it to a list such as list(256,255,128). If an HSVA format is used that
includes alpha, the list will have a fourth item for the alpha value.
RGBtoHSV(rgb)
Takes an RGB or RGBA string like "#ffaa55" and converts it into an HSV or HSVA color such as "#080aaff".
HSVtoRGB(hsv)
Takes an HSV or HSVA string like "#080aaff" and converts it into an RGB or RGBA color such as "#ff55aa".
BlendRGB(rgb1, rgb2, amount)
Blends between two RGB or RGBA colors using regular RGB blending. If amount is 0, the first color is the result;
if 1, the second color is the result. 0.5 produces an average of the two. Values outside the 0 to 1 range are allowed as well.
The returned value is an RGB or RGBA color.
BlendHSV(hsv1, hsv2, amount)
Blends between two HSV or HSVA colors using HSV blending, which tends to produce nicer results than regular RGB
Returns an RGB or RGBA string
BlendHSV(rgb1, rgb2, amount)
Blends between two RGB or RGBA colors using HSV blending, which tends to produce nicer results than regular RGB
blending because the brightness of the color is left intact. If amount is 0, the first color is the result; if 1,
the second color is the result. 0.5 produces an average of the two. Values outside the 0 to 1 range are allowed as well.
The returned value is an HSV or HSVA color.
BlendRGBasHSV(rgb1, rgb2, amount)
Like BlendHSV(), but the colors used and the return value are RGB or RGBA colors. The blending is done in HSV form.
Returns an RGB or RGBA string
HueToAngle(hue)
Converts a hue to an angle range of 0 to 360. Angle 0 is red, 120 is green, and 240 is blue.
AngleToHue(hue)
Converts an angle to a hue in the valid range.
RotateHue(hsv, angle)
Takes an HSV or HSVA value and rotates the hue forward through red, green, and blue by an angle from 0 to 360.
(Rotating red by 60° produces yellow.) The result is another HSV or HSVA color with the same saturation and value
as the original, but a different hue.
RotateHue(rgb, angle)
Takes an RGB or RGBA value and rotates the hue forward through red, green, and blue by an angle from 0 to 360.
(Rotating red by 60° produces yellow.)
Returns an RGB or RGBA string
GrayScale(rgb)
Takes an RGB or RGBA color and converts it to grayscale. Returns an RGB or RGBA string.
ColorTone(rgb, tone)
@@ -101,33 +104,42 @@ ColorTone(rgb, tone)
/*
Get Flat Icon DEMO by DarkCampainger
This is a test for the get flat icon proc, modified approprietly for icons and their states.
Probably not a good idea to run this unless you want to see how the proc works in detail.
mob
icon = 'old_or_unused.dmi'
icon_state = "green"
Login()
// Testing image underlays
underlays += image(icon='old_or_unused.dmi',icon_state="red")
underlays += image(icon='old_or_unused.dmi',icon_state="red", pixel_x = 32)
underlays += image(icon='old_or_unused.dmi',icon_state="red", pixel_x = -32)
// Testing image overlays
add_overlay(image(icon='old_or_unused.dmi',icon_state="green", pixel_x = 32, pixel_y = -32))
add_overlay(image(icon='old_or_unused.dmi',icon_state="green", pixel_x = 32, pixel_y = 32))
add_overlay(image(icon='old_or_unused.dmi',icon_state="green", pixel_x = -32, pixel_y = -32))
// Testing icon file overlays (defaults to mob's state)
add_overlay('_flat_demoIcons2.dmi')
// Testing icon_state overlays (defaults to mob's icon)
add_overlay("white")
// Testing dynamic icon overlays
var/icon/I = icon('old_or_unused.dmi', icon_state="aqua")
I.Shift(NORTH,16,1)
add_overlay(I)
// Testing dynamic image overlays
I=image(icon=I,pixel_x = -32, pixel_y = 32)
add_overlay(I)
// Testing object types (and layers)
add_overlay(/obj/effect/overlay_test)
loc = locate (10,10,1)
verb
Browse_Icon()
@@ -138,9 +150,11 @@ mob
src<<browse_rsc(getFlatIcon(src), iconName)
// Display the icon in their browser
src<<browse("<body bgcolor='#000000'><p><img src='[iconName]'></p></body>")
Output_Icon()
set name = "2. Output Icon"
to_chat(src, "Icon is: [icon2base64html(getFlatIcon(src))]")
Label_Icon()
set name = "3. Label Icon"
// Give it a name for the cache
@@ -151,9 +165,11 @@ mob
src<<browse_rsc(I, iconName)
// Update the label to show it
winset(src,"imageLabel","image='[REF(I)]'");
Add_Overlay()
set name = "4. Add Overlay"
add_overlay(image(icon='old_or_unused.dmi',icon_state="yellow",pixel_x = rand(-64,32), pixel_y = rand(-64,32))
Stress_Test()
set name = "5. Stress Test"
for(var/i = 0 to 1000)
@@ -162,17 +178,20 @@ mob
if(prob(5))
Add_Overlay()
Browse_Icon()
Cache_Test()
set name = "6. Cache Test"
for(var/i = 0 to 1000)
getFlatIcon(src)
Browse_Icon()
/obj/effect/overlay_test
icon = 'old_or_unused.dmi'
icon_state = "blue"
pixel_x = -24
pixel_y = 24
layer = TURF_LAYER // Should appear below the rest of the overlays
world
view = "7x7"
maxx = 20
@@ -252,330 +271,45 @@ world
// apply mask
Blend(mask_icon, ICON_ADD)
/*
HSV format is represented as "#hhhssvv" or "#hhhssvvaa"
Hue ranges from 0 to 0x5ff (1535)
0x000 = red
0x100 = yellow
0x200 = green
0x300 = cyan
0x400 = blue
0x500 = magenta
Saturation is from 0 to 0xff (255)
More saturation = more color
Less saturation = more gray
Value ranges from 0 to 0xff (255)
Higher value means brighter color
*/
/// Converts an rgb color into a list storing hsva
/// Exists because it's useful to have a guarenteed alpha value
/proc/rgb2hsv(rgb)
var/list/hsv = rgb2num(rgb, COLORSPACE_HSV)
if(length(hsv) < 4)
hsv += 255 // Max alpha, just to make life easy
return hsv
/proc/ReadRGB(rgb)
if(!rgb)
return
// interpret the HSV or HSVA value
var/i=1,start=1
if(text2ascii(rgb) == 35) ++start // skip opening #
var/ch,which=0,r=0,g=0,b=0,alpha=0,usealpha
var/digits=0
for(i=start, i <= length(rgb), ++i)
ch = text2ascii(rgb, i)
if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102)
break
++digits
if(digits == 8)
break
var/single = digits < 6
if(digits != 3 && digits != 4 && digits != 6 && digits != 8)
return
if(digits == 4 || digits == 8)
usealpha = 1
for(i=start, digits>0, ++i)
ch = text2ascii(rgb, i)
if(ch >= 48 && ch <= 57)
ch -= 48
else if(ch >= 65 && ch <= 70)
ch -= 55
else if(ch >= 97 && ch <= 102)
ch -= 87
else
break
--digits
switch(which)
if(0)
r = (r << 4) | ch
if(single)
r |= r << 4
++which
else if(!(digits & 1))
++which
if(1)
g = (g << 4) | ch
if(single)
g |= g << 4
++which
else if(!(digits & 1))
++which
if(2)
b = (b << 4) | ch
if(single)
b |= b << 4
++which
else if(!(digits & 1))
++which
if(3)
alpha = (alpha << 4) | ch
if(single)
alpha |= alpha << 4
. = list(r, g, b)
if(usealpha)
. += alpha
/proc/ReadHSV(hsv)
if(!hsv)
return
// interpret the HSV or HSVA value
var/i=1,start=1
if(text2ascii(hsv) == 35)
++start // skip opening #
var/ch,which=0,hue=0,sat=0,val=0,alpha=0,usealpha
var/digits=0
for(i=start, i <= length(hsv), ++i)
ch = text2ascii(hsv, i)
if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102)
break
++digits
if(digits == 9)
break
if(digits > 7)
usealpha = 1
if(digits <= 4)
++which
if(digits <= 2)
++which
for(i=start, digits>0, ++i)
ch = text2ascii(hsv, i)
if(ch >= 48 && ch <= 57)
ch -= 48
else if(ch >= 65 && ch <= 70)
ch -= 55
else if(ch >= 97 && ch <= 102)
ch -= 87
else
break
--digits
switch(which)
if(0)
hue = (hue << 4) | ch
if(digits == (usealpha ? 6 : 4))
++which
if(1)
sat = (sat << 4) | ch
if(digits == (usealpha ? 4 : 2))
++which
if(2)
val = (val << 4) | ch
if(digits == (usealpha ? 2 : 0))
++which
if(3)
alpha = (alpha << 4) | ch
. = list(hue, sat, val)
if(usealpha)
. += alpha
/proc/HSVtoRGB(hsv)
if(!hsv)
/// Converts a list storing hsva into an rgb color
/proc/hsv2rgb(hsv)
if(length(hsv) < 3)
return "#000000"
var/list/HSV = ReadHSV(hsv)
if(!HSV)
return "#000000"
var/hue = HSV[1]
var/sat = HSV[2]
var/val = HSV[3]
// Compress hue into easier-to-manage range
hue -= hue >> 8
if(hue >= 0x5fa)
hue -= 0x5fa
var/hi,mid,lo,r,g,b
hi = val
lo = round((255 - sat) * val / 255, 1)
mid = lo + round(abs(round(hue, 510) - hue) * (hi - lo) / 255, 1)
if(hue >= 765)
if(hue >= 1275) {r=hi; g=lo; b=mid}
else if(hue >= 1020) {r=mid; g=lo; b=hi }
else {r=lo; g=mid; b=hi }
else
if(hue >= 510) {r=lo; g=hi; b=mid}
else if(hue >= 255) {r=mid; g=hi; b=lo }
else {r=hi; g=mid; b=lo }
return (HSV.len > 3) ? rgb(r,g,b,HSV[4]) : rgb(r,g,b)
/proc/RGBtoHSV(rgb)
if(!rgb)
return "#0000000"
var/list/RGB = ReadRGB(rgb)
if(!RGB)
return "#0000000"
var/r = RGB[1]
var/g = RGB[2]
var/b = RGB[3]
var/hi = max(r,g,b)
var/lo = min(r,g,b)
var/val = hi
var/sat = hi ? round((hi-lo) * 255 / hi, 1) : 0
var/hue = 0
if(sat)
var/dir
var/mid
if(hi == r)
if(lo == b) {hue=0; dir=1; mid=g}
else {hue=1535; dir=-1; mid=b}
else if(hi == g)
if(lo == r) {hue=512; dir=1; mid=b}
else {hue=511; dir=-1; mid=r}
else if(hi == b)
if(lo == g) {hue=1024; dir=1; mid=r}
else {hue=1023; dir=-1; mid=g}
hue += dir * round((mid-lo) * 255 / (hi-lo), 1)
return hsv(hue, sat, val, (RGB.len>3 ? RGB[4] : null))
/proc/hsv(hue, sat, val, alpha)
if(hue < 0 || hue >= 1536)
hue %= 1536
if(hue < 0)
hue += 1536
if((hue & 0xFF) == 0xFF)
++hue
if(hue >= 1536)
hue = 0
if(sat < 0)
sat = 0
if(sat > 255)
sat = 255
if(val < 0)
val = 0
if(val > 255)
val = 255
. = "#"
. += TO_HEX_DIGIT(hue >> 8)
. += TO_HEX_DIGIT(hue >> 4)
. += TO_HEX_DIGIT(hue)
. += TO_HEX_DIGIT(sat >> 4)
. += TO_HEX_DIGIT(sat)
. += TO_HEX_DIGIT(val >> 4)
. += TO_HEX_DIGIT(val)
if(!isnull(alpha))
if(alpha < 0)
alpha = 0
if(alpha > 255)
alpha = 255
. += TO_HEX_DIGIT(alpha >> 4)
. += TO_HEX_DIGIT(alpha)
if(length(hsv) == 3)
return rgb(hsv[1], hsv[2], hsv[3], space = COLORSPACE_HSV)
return rgb(hsv[1], hsv[2], hsv[3], hsv[4], space = COLORSPACE_HSV)
/*
Smooth blend between HSV colors
Smooth blend between RGB colors interpreted as HSV
amount=0 is the first color
amount=1 is the second color
amount=0.5 is directly between the two colors
amount<0 or amount>1 are allowed
*/
/proc/BlendHSV(hsv1, hsv2, amount)
var/list/HSV1 = ReadHSV(hsv1)
var/list/HSV2 = ReadHSV(hsv2)
// add missing alpha if needed
if(HSV1.len < HSV2.len)
HSV1 += 255
else if(HSV2.len < HSV1.len)
HSV2 += 255
var/usealpha = HSV1.len > 3
// normalize hsv values in case anything is screwy
if(HSV1[1] > 1536)
HSV1[1] %= 1536
if(HSV2[1] > 1536)
HSV2[1] %= 1536
if(HSV1[1] < 0)
HSV1[1] += 1536
if(HSV2[1] < 0)
HSV2[1] += 1536
if(!HSV1[3]) {HSV1[1] = 0; HSV1[2] = 0}
if(!HSV2[3]) {HSV2[1] = 0; HSV2[2] = 0}
// no value for one color means don't change saturation
if(!HSV1[3])
HSV1[2] = HSV2[2]
if(!HSV2[3])
HSV2[2] = HSV1[2]
// no saturation for one color means don't change hues
if(!HSV1[2])
HSV1[1] = HSV2[1]
if(!HSV2[2])
HSV2[1] = HSV1[1]
// Compress hues into easier-to-manage range
HSV1[1] -= HSV1[1] >> 8
HSV2[1] -= HSV2[1] >> 8
var/hue_diff = HSV2[1] - HSV1[1]
if(hue_diff > 765)
hue_diff -= 1530
else if(hue_diff <= -765)
hue_diff += 1530
var/hue = round(HSV1[1] + hue_diff * amount, 1)
var/sat = round(HSV1[2] + (HSV2[2] - HSV1[2]) * amount, 1)
var/val = round(HSV1[3] + (HSV2[3] - HSV1[3]) * amount, 1)
var/alpha = usealpha ? round(HSV1[4] + (HSV2[4] - HSV1[4]) * amount, 1) : null
// normalize hue
if(hue < 0 || hue >= 1530)
hue %= 1530
if(hue < 0)
hue += 1530
// decompress hue
hue += round(hue / 255)
return hsv(hue, sat, val, alpha)
return hsv_gradient(amount, 0, hsv1, 1, hsv2, "loop")
/*
Smooth blend between RGB colors
amount=0 is the first color
amount=1 is the second color
amount=0.5 is directly between the two colors
amount<0 or amount>1 are allowed
*/
/proc/BlendRGB(rgb1, rgb2, amount)
var/list/RGB1 = ReadRGB(rgb1)
var/list/RGB2 = ReadRGB(rgb2)
// add missing alpha if needed
if(RGB1.len < RGB2.len)
RGB1 += 255
else if(RGB2.len < RGB1.len)
RGB2 += 255
var/usealpha = RGB1.len > 3
var/r = round(RGB1[1] + (RGB2[1] - RGB1[1]) * amount, 1)
var/g = round(RGB1[2] + (RGB2[2] - RGB1[2]) * amount, 1)
var/b = round(RGB1[3] + (RGB2[3] - RGB1[3]) * amount, 1)
var/alpha = usealpha ? round(RGB1[4] + (RGB2[4] - RGB1[4]) * amount, 1) : null
return isnull(alpha) ? rgb(r, g, b) : rgb(r, g, b, alpha)
/proc/BlendRGBasHSV(rgb1, rgb2, amount)
return HSVtoRGB(RGBtoHSV(rgb1), RGBtoHSV(rgb2), amount)
return rgb_gradient(amount, 0, rgb1, 1, rgb2, "loop")
/proc/HueToAngle(hue)
// normalize hsv in case anything is screwy
@@ -596,10 +330,9 @@ world
hue += round(hue / 255)
return hue
// positive angle rotates forward through red->green->blue
/proc/RotateHue(hsv, angle)
var/list/HSV = ReadHSV(hsv)
/proc/RotateHue(rgb, angle)
var/list/HSV = rgb2hsv(rgb)
// normalize hsv in case anything is screwy
if(HSV[1] >= 1536)
@@ -622,18 +355,18 @@ world
// decompress hue
HSV[1] += round(HSV[1] / 255)
return hsv(HSV[1], HSV[2], HSV[3], (HSV.len > 3 ? HSV[4] : null))
return hsv2rgb(HSV)
// Convert an rgb color to grayscale
/proc/GrayScale(rgb)
var/list/RGB = ReadRGB(rgb)
var/list/RGB = rgb2num(rgb)
var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11
return (RGB.len > 3) ? rgb(gray, gray, gray, RGB[4]) : rgb(gray, gray, gray)
// Change grayscale color to black->tone->white range
/proc/ColorTone(rgb, tone)
var/list/RGB = ReadRGB(rgb)
var/list/TONE = ReadRGB(tone)
var/list/RGB = rgb2num(rgb)
var/list/TONE = rgb2num(tone)
var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11
var/tone_gray = TONE[1]*0.3 + TONE[2]*0.59 + TONE[3]*0.11
@@ -1013,7 +746,9 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
var/static/list/humanoid_icon_cache = list()
if(icon_id && humanoid_icon_cache[icon_id])
return humanoid_icon_cache[icon_id]
var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key)
if(prefs)
prefs.apply_prefs_to(body, TRUE)
@@ -1319,6 +1054,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
GLOBAL_LIST_EMPTY(transformation_animation_objects)
/*
* Creates animation that turns current icon into result appearance from top down.
*
+2 -2
View File
@@ -178,7 +178,7 @@ round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), ro
if(!color)
return COLOR_MATRIX_IDENTITY
if(istext(color))
var/list/L = ReadRGB(color)
var/list/L = rgb2num(color)
if(!L)
var/message = "Invalid/unsupported color ([color]) argument in color_to_full_rgba_matrix()"
if(return_identity_on_fail)
@@ -193,7 +193,7 @@ round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), ro
if(3 to 5) // row-by-row hexadecimals
. = list()
for(var/a in 1 to L.len)
var/list/rgb = ReadRGB(L[a])
var/list/rgb = rgb2num(L[a])
for(var/b in rgb)
. += b/255
if(length(rgb) % 4) // RGB has no alpha instruction
+8 -7
View File
@@ -338,14 +338,15 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH,
var/length = length(string)
if((length != 7 && length != 9) || length != length_char(string))
return COLOR_MATRIX_IDENTITY
var/r = hex2num(copytext(string, 2, 4))/255
var/g = hex2num(copytext(string, 4, 6))/255
var/b = hex2num(copytext(string, 6, 8))/255
// For runtime safety
. = COLOR_MATRIX_IDENTITY
var/list/color = rgb2num(string)
var/r = color[1] / 255
var/g = color[2] / 255
var/b = color[3] / 255
var/a = 1
if(length == 9)
a = hex2num(copytext(string, 8, 10))/255
if(!isnum(r) || !isnum(g) || !isnum(b) || !isnum(a))
return COLOR_MATRIX_IDENTITY
if(length(color) == 4)
a = color[4] / 255
return list(r,0,0,0, 0,g,0,0, 0,0,b,0, 0,0,0,a, 0,0,0,0)
//will drop all values not on the diagonal
+1 -1
View File
@@ -318,6 +318,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_NO_DEBRAIN_OVERLAY" = TRAIT_NO_DEBRAIN_OVERLAY,
"TRAIT_NO_DNA_COPY" = TRAIT_NO_DNA_COPY,
"TRAIT_NO_DNA_SCRAMBLE" = TRAIT_NO_DNA_SCRAMBLE,
"TRAIT_NO_EXTINGUISH" = TRAIT_NO_EXTINGUISH,
"TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM,
"TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE,
"TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM,
@@ -354,7 +355,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_PASSTABLE" = TRAIT_PASSTABLE,
"TRAIT_PERFECT_ATTACKER" = TRAIT_PERFECT_ATTACKER,
"TRAIT_PERMANENTLY_MORTAL" = TRAIT_PERMANENTLY_MORTAL,
"TRAIT_PERMANENTLY_ONFIRE" = TRAIT_PERMANENTLY_ONFIRE,
"TRAIT_PHOTOGRAPHER" = TRAIT_PHOTOGRAPHER,
"TRAIT_PIERCEIMMUNE" = TRAIT_PIERCEIMMUNE,
"TRAIT_PLANT_SAFE" = TRAIT_PLANT_SAFE,
+1 -1
View File
@@ -129,6 +129,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_NO_AUGMENTS" = TRAIT_NO_AUGMENTS,
"TRAIT_NO_BLOOD_OVERLAY" = TRAIT_NO_BLOOD_OVERLAY,
"TRAIT_NO_DNA_COPY" = TRAIT_NO_DNA_COPY,
"TRAIT_NO_EXTINGUISH" = TRAIT_NO_EXTINGUISH,
"TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE,
"TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM,
"TRAIT_NO_SLIP_ALL" = TRAIT_NO_SLIP_ALL,
@@ -162,7 +163,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_PARALYSIS_R_LEG" = TRAIT_PARALYSIS_R_LEG,
"TRAIT_PASSTABLE" = TRAIT_PASSTABLE,
"TRAIT_PERFECT_ATTACKER" = TRAIT_PERFECT_ATTACKER,
"TRAIT_PERMANENTLY_ONFIRE" = TRAIT_PERMANENTLY_ONFIRE,
"TRAIT_PHOTOGRAPHER" = TRAIT_PHOTOGRAPHER,
"TRAIT_PIERCEIMMUNE" = TRAIT_PIERCEIMMUNE,
"TRAIT_PLANT_SAFE" = TRAIT_PLANT_SAFE,
@@ -0,0 +1,24 @@
/// When applied to a mob, they will always have a fire overlay regardless of if they are *actually* on fire.
/datum/element/perma_fire_overlay
/datum/element/perma_fire_overlay/Attach(atom/target)
. = ..()
if(!isliving(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(add_fire_overlay))
target.update_appearance(UPDATE_OVERLAYS)
/datum/element/perma_fire_overlay/Detach(atom/target)
. = ..()
UnregisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS)
target.update_appearance(UPDATE_OVERLAYS)
/datum/element/perma_fire_overlay/proc/add_fire_overlay(mob/living/source, list/overlays)
SIGNAL_HANDLER
var/mutable_appearance/created_overlay = source.get_fire_overlay(stacks = MAX_FIRE_STACKS, on_fire = TRUE)
if(isnull(created_overlay))
return
overlays |= created_overlay
@@ -7,7 +7,7 @@
/// Current amount of stacks we have
var/stacks
/// Maximum of stacks that we could possibly get
var/stack_limit = 20
var/stack_limit = MAX_FIRE_STACKS
/// What status effect types do we remove uppon being applied. These are just deleted without any deduction from our or their stacks when forced.
var/list/enemy_types
/// What status effect types do we merge into if they exist. Ignored when forced.
@@ -116,12 +116,8 @@
owner.clear_alert(ALERT_FIRE)
else if(!was_on_fire && owner.on_fire)
owner.throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire)
/**
* Used to update owner's effect overlay
*/
/datum/status_effect/fire_handler/proc/update_overlay()
owner.update_appearance(UPDATE_OVERLAYS)
update_particles()
/datum/status_effect/fire_handler/fire_stacks
id = "fire_stacks" //fire_stacks and wet_stacks should have different IDs or else has_status_effect won't work
@@ -132,8 +128,6 @@
/// If we're on fire
var/on_fire = FALSE
/// Stores current fire overlay icon state, for optimisation purposes
var/last_icon_state
/// Reference to the mob light emitter itself
var/obj/effect/dummy/lighting_obj/moblight
/// Type of mob light emitter we use when on fire
@@ -160,8 +154,6 @@
return TRUE
deal_damage(seconds_between_ticks)
update_overlay()
update_particles()
/datum/status_effect/fire_handler/fire_stacks/update_particles()
if(on_fire)
@@ -239,8 +231,6 @@
moblight = new moblight_type(owner)
cache_stacks()
update_overlay()
update_particles()
SEND_SIGNAL(owner, COMSIG_LIVING_IGNITED, owner)
return TRUE
@@ -254,8 +244,6 @@
owner.clear_mood_event("on_fire")
SEND_SIGNAL(owner, COMSIG_LIVING_EXTINGUISHED, owner)
cache_stacks()
update_overlay()
update_particles()
for(var/obj/item/equipped in owner.get_equipped_items())
equipped.extinguish()
@@ -263,16 +251,26 @@
if(on_fire)
extinguish()
set_stacks(0)
update_overlay()
update_particles()
UnregisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS)
owner.update_appearance(UPDATE_OVERLAYS)
return ..()
/datum/status_effect/fire_handler/fire_stacks/update_overlay()
last_icon_state = owner.update_fire_overlay(stacks, on_fire, last_icon_state)
/datum/status_effect/fire_handler/fire_stacks/on_apply()
. = ..()
update_overlay()
RegisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(add_fire_overlay))
owner.update_appearance(UPDATE_OVERLAYS)
/datum/status_effect/fire_handler/fire_stacks/proc/add_fire_overlay(mob/living/source, list/overlays)
SIGNAL_HANDLER
if(stacks <= 0 || !on_fire)
return
var/mutable_appearance/created_overlay = owner.get_fire_overlay(stacks, on_fire)
if(isnull(created_overlay))
return
overlays |= created_overlay
/obj/effect/dummy/lighting_obj/moblight/fire
name = "fire"
+3 -3
View File
@@ -1,7 +1,7 @@
#define STATUE_FILTER "statue_filter"
#define FILTER_COLOR "#34b347"
#define RECALL_DURATION 3 SECONDS
#define MINIMUM_COLOR_VALUE 60
#define MINIMUM_COLOR_VALUE 20
/obj/item/frog_statue
name = "frog statue"
@@ -151,8 +151,8 @@
to_chat(user, span_warning("Please choose a valid color."))
select_frog_color(user, new_frog)
return
var/temp_hsv = RGBtoHSV(frog_color)
if(ReadHSV(temp_hsv)[3] < MINIMUM_COLOR_VALUE)
var/list/hsv_frog = rgb2hsv(frog_color)
if(hsv_frog[3] < MINIMUM_COLOR_VALUE)
to_chat(user, span_danger("This color is too dark!"))
select_frog_color(user, new_frog)
return
+2 -2
View File
@@ -516,10 +516,10 @@
if(!greyscale_colors)
// Generate a random valid lizard color for our plushie friend
var/generated_lizard_color = "#" + random_color()
var/temp_hsv = RGBtoHSV(generated_lizard_color)
var/list/lizard_hsv = rgb2hsv(generated_lizard_color)
// If our color is too dark, use the classic green lizard plush color
if(ReadHSV(temp_hsv)[3] < ReadHSV("#7F7F7F")[3])
if(lizard_hsv[3] < 50)
generated_lizard_color = "#66ff33"
// Set our greyscale colors to the lizard color we made + black eyes
+1 -1
View File
@@ -73,7 +73,7 @@
if(new_choice == null)
return
var/list/new_rgb = ReadRGB(new_choice)
var/list/new_rgb = rgb2num(new_choice)
for(var/option in original_options)
if(option == "Color Pick" || option == "Deconstruct" || option == "Silo Link")
continue
+4 -4
View File
@@ -24,13 +24,13 @@
//Generate random valid colors for paper and ribbon
var/generated_base_color = "#" + random_color()
var/generated_ribbon_color = "#" + random_color()
var/temp_base_hsv = RGBtoHSV(generated_base_color)
var/temp_ribbon_hsv = RGBtoHSV(generated_ribbon_color)
var/list/base_hsv = rgb2hsv(generated_base_color)
var/list/ribbon_hsv = rgb2hsv(generated_ribbon_color)
//If colors are too dark, set to original colors
if(ReadHSV(temp_base_hsv)[3] < ReadHSV("7F7F7F")[3])
if(base_hsv[3] < 50)
generated_base_color = "#00FF00"
if(ReadHSV(temp_ribbon_hsv)[3] < ReadHSV("7F7F7F")[3])
if(ribbon_hsv[3] < 50)
generated_ribbon_color = "#FF0000"
//Set layers to these colors, base then ribbon
+2 -3
View File
@@ -180,12 +180,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28)
else if(HAS_TRAIT(race_changer, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(race_changer, TRAIT_FIXED_MUTANT_COLORS))
var/new_mutantcolor = input(race_changer, "Choose your skin color:", "Race change", race_changer.dna.features["mcolor"]) as color|null
if(new_mutantcolor)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
var/list/mutant_hsv = rgb2hsv(new_mutantcolor)
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
if(mutant_hsv[3] >= 50) // mutantcolors must be bright
race_changer.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
race_changer.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK)
else
to_chat(race_changer, span_notice("Invalid color. Your color is not bright enough."))
return TRUE
+18 -13
View File
@@ -52,7 +52,8 @@
/turf/open/lava/Destroy()
for(var/mob/living/leaving_mob in contents)
REMOVE_TRAIT(leaving_mob, TRAIT_PERMANENTLY_ONFIRE, TURF_TRAIT)
leaving_mob.RemoveElement(/datum/element/perma_fire_overlay)
REMOVE_TRAIT(leaving_mob, TRAIT_NO_EXTINGUISH, TURF_TRAIT)
return ..()
/turf/open/lava/update_overlays()
@@ -144,7 +145,8 @@
/turf/open/lava/Exited(atom/movable/gone, direction)
. = ..()
if(isliving(gone) && !islava(gone.loc))
REMOVE_TRAIT(gone, TRAIT_PERMANENTLY_ONFIRE, TURF_TRAIT)
gone.RemoveElement(/datum/element/perma_fire_overlay)
REMOVE_TRAIT(gone, TRAIT_NO_EXTINGUISH, TURF_TRAIT)
/turf/open/lava/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(burn_stuff(AM))
@@ -292,11 +294,10 @@
if(QDELETED(burn_target))
return FALSE
. = TRUE
if(isobj(burn_target))
var/obj/burn_obj = burn_target
if(burn_obj.resistance_flags & ON_FIRE) // already on fire; skip it.
return
return TRUE
if(!(burn_obj.resistance_flags & FLAMMABLE))
burn_obj.resistance_flags |= FLAMMABLE //Even fireproof things burn up in lava
if(burn_obj.resistance_flags & FIRE_PROOF)
@@ -305,17 +306,21 @@
burn_obj.set_armor_rating(FIRE, 50)
burn_obj.fire_act(temperature_damage, 1000 * seconds_per_tick)
if(istype(burn_obj, /obj/structure/closet))
var/obj/structure/closet/burn_closet = burn_obj
for(var/burn_content in burn_closet.contents)
for(var/burn_content in burn_target)
burn_stuff(burn_content)
return
return TRUE
var/mob/living/burn_living = burn_target
ADD_TRAIT(burn_living, TRAIT_PERMANENTLY_ONFIRE, TURF_TRAIT)
burn_living.ignite_mob()
burn_living.adjust_fire_stacks(lava_firestacks * seconds_per_tick)
burn_living.update_fire()
burn_living.adjustFireLoss(lava_damage * seconds_per_tick)
if(isliving(burn_target))
var/mob/living/burn_living = burn_target
if(!HAS_TRAIT_FROM(burn_living, TRAIT_NO_EXTINGUISH, TURF_TRAIT))
burn_living.AddElement(/datum/element/perma_fire_overlay)
ADD_TRAIT(burn_living, TRAIT_NO_EXTINGUISH, TURF_TRAIT)
burn_living.adjust_fire_stacks(lava_firestacks * seconds_per_tick)
burn_living.ignite_mob()
burn_living.adjustFireLoss(lava_damage * seconds_per_tick)
return TRUE
return FALSE
/turf/open/lava/can_cross_safely(atom/movable/crossing)
return HAS_TRAIT(src, TRAIT_LAVA_STOPPED) || HAS_TRAIT(crossing, immunity_trait ) || HAS_TRAIT(crossing, TRAIT_MOVE_FLYING)
+3 -3
View File
@@ -612,10 +612,10 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
GLOB.narsie_effect_last_modified = started
var/starting_color = GLOB.starlight_color
var/list/target_color = ReadHSV(RGBtoHSV(starting_color))
var/list/target_color = rgb2hsv(starting_color)
target_color[2] = target_color[2] * 0.4
target_color[3] = target_color[3] * 0.5
var/mid_color = HSVtoRGB(hsv(target_color[1], target_color[2], target_color[3]))
var/mid_color = hsv2rgb(target_color)
var/end_color = "#c21d57"
for(var/i in 1 to 9)
if(GLOB.narsie_effect_last_modified > started)
@@ -639,7 +639,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
for(var/i in 1 to 4)
if(GLOB.narsie_effect_last_modified > started)
return
var/starlight_color = hsv_gradient(i, 1, starting_color, 4, end_color)
var/starlight_color = BlendHSV(i / 4, starting_color, end_color)
set_starlight(starlight_color)
sleep(8 SECONDS)
@@ -348,7 +348,7 @@
var/gas_weight = air.gases[gas_path][MOLES]
if(!gas_weight)
continue
var/gas_color = RGBtoHSV(initial(gas_path.primary_color))
var/gas_color = initial(gas_path.primary_color)
current_weight += gas_weight
if(!current_color)
current_color = gas_color
@@ -363,8 +363,6 @@
if(empty_weight > 0)
current_color = BlendHSV("#000000", current_color, current_weight / (empty_weight + current_weight))
current_color = HSVtoRGB(current_color)
if(gasmix_color != current_color)
gasmix_color = current_color
UpdateGasVisuals()
+11 -11
View File
@@ -270,17 +270,17 @@
/mob/living/basic/on_fire_stack(seconds_per_tick, datum/status_effect/fire_handler/fire_stacks/fire_handler)
adjust_bodytemperature((maximum_survivable_temperature + (fire_handler.stacks * 12)) * 0.5 * seconds_per_tick)
/mob/living/basic/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
var/mutable_appearance/fire_overlay = mutable_appearance('icons/mob/effects/onfire.dmi', "generic_fire")
if(on_fire && isnull(last_icon_state))
add_overlay(fire_overlay)
return fire_overlay
else if(!on_fire && !isnull(last_icon_state))
cut_overlay(fire_overlay)
return null
else if(on_fire && !isnull(last_icon_state))
return last_icon_state
return null
/mob/living/basic/get_fire_overlay(stacks, on_fire)
var/fire_icon = "generic_fire"
if(!GLOB.fire_appearances[fire_icon])
GLOB.fire_appearances[fire_icon] = mutable_appearance(
'icons/mob/effects/onfire.dmi',
fire_icon,
-HIGHEST_LAYER,
appearance_flags = RESET_COLOR,
)
return GLOB.fire_appearances[fire_icon]
/mob/living/basic/put_in_hands(obj/item/I, del_on_fail = FALSE, merge_stacks = TRUE, ignore_animation = TRUE)
. = ..()
@@ -1,5 +1,5 @@
/// You can't make a dragon darker than this, it'd be hard to see
#define REJECT_DARK_COLOUR_THRESHOLD 50
#define REJECT_DARK_COLOUR_THRESHOLD 20
/// Any interactions executed by the space dragon
#define DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION "space dragon interaction"
@@ -101,8 +101,8 @@
to_chat(src, span_warning("Not a valid colour, please try again."))
select_colour()
return
var/temp_hsv = RGBtoHSV(chosen_colour)
if(ReadHSV(temp_hsv)[3] < REJECT_DARK_COLOUR_THRESHOLD)
var/list/skin_hsv = rgb2hsv(chosen_colour)
if(skin_hsv[3] < REJECT_DARK_COLOUR_THRESHOLD)
to_chat(src, span_danger("Invalid colour. Your colour is not bright enough."))
select_colour()
return
@@ -278,8 +278,8 @@
update_held_items()
update_worn_handcuffs()
update_worn_legcuffs()
update_fire()
update_body()
update_appearance(UPDATE_OVERLAYS)
/mob/living/carbon/update_held_items()
. = ..()
@@ -315,27 +315,18 @@
hands += I.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE)
return hands
/mob/living/carbon/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
var/fire_icon = "[dna?.species.fire_overlay || "human"]_[stacks > MOB_BIG_FIRE_STACK_THRESHOLD ? "big_fire" : "small_fire"][suffix]"
/mob/living/carbon/get_fire_overlay(stacks, on_fire)
var/fire_icon = "[dna?.species.fire_overlay || "human"]_[stacks > MOB_BIG_FIRE_STACK_THRESHOLD ? "big_fire" : "small_fire"]"
if(!GLOB.fire_appearances[fire_icon])
GLOB.fire_appearances[fire_icon] = mutable_appearance('icons/mob/effects/onfire.dmi', fire_icon, -FIRE_LAYER, appearance_flags = RESET_COLOR)
GLOB.fire_appearances[fire_icon] = mutable_appearance(
'icons/mob/effects/onfire.dmi',
fire_icon,
-HIGHEST_LAYER,
appearance_flags = RESET_COLOR,
)
if((stacks > 0 && on_fire) || HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE))
if(fire_icon == last_icon_state)
return last_icon_state
remove_overlay(FIRE_LAYER)
overlays_standing[FIRE_LAYER] = GLOB.fire_appearances[fire_icon]
apply_overlay(FIRE_LAYER)
return fire_icon
if(!last_icon_state)
return last_icon_state
remove_overlay(FIRE_LAYER)
apply_overlay(FIRE_LAYER)
return null
return GLOB.fire_appearances[fire_icon]
/mob/living/carbon/update_damage_overlays()
remove_overlay(DAMAGE_LAYER)
@@ -41,12 +41,6 @@
var/current_color
var/default_color
var/r1
var/g1
var/b1
var/static/r2 = 237
var/static/g2 = 164
var/static/b2 = 149
var/EMPeffect = FALSE
var/emageffect = FALSE
var/obj/effect/dummy/lighting_obj/ethereal_light
@@ -61,9 +55,6 @@
return
default_color = new_ethereal.dna.features["ethcolor"]
fixed_hair_color = default_color
r1 = GETREDPART(default_color)
g1 = GETGREENPART(default_color)
b1 = GETBLUEPART(default_color)
RegisterSignal(new_ethereal, COMSIG_ATOM_EMAG_ACT, PROC_REF(on_emag_act))
RegisterSignal(new_ethereal, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act))
RegisterSignal(new_ethereal, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur))
@@ -116,15 +107,16 @@
SIGNAL_HANDLER
if(isnull(ethereal_light))
return
if(default_color != ethereal.dna.features["ethcolor"])
var/new_color = ethereal.dna.features["ethcolor"]
r1 = GETREDPART(new_color)
g1 = GETGREENPART(new_color)
b1 = GETBLUEPART(new_color)
if(ethereal.stat != DEAD && !EMPeffect)
var/healthpercent = max(ethereal.health, 0) / 100
if(!emageffect)
current_color = rgb(r2 + ((r1-r2)*healthpercent), g2 + ((g1-g2)*healthpercent), b2 + ((b1-b2)*healthpercent))
var/static/list/skin_color = rgb2num("#eda495")
var/list/colors = rgb2num(ethereal.dna.features["ethcolor"])
var/list/built_color = list()
for(var/i in 1 to 3)
built_color += skin_color[i] + ((colors[i] - skin_color[i]) * healthpercent)
current_color = rgb(built_color[1], built_color[2], built_color[3])
ethereal_light.set_light_range_power_color(1 + (2 * healthpercent), 1 + (1 * healthpercent), current_color)
ethereal_light.set_light_on(TRUE)
fixed_mut_color = current_color
@@ -116,7 +116,7 @@
else
internal_fire = FALSE
H.update_fire()
H.update_appearance(UPDATE_OVERLAYS)
/datum/species/plasmaman/handle_fire(mob/living/carbon/human/H, seconds_per_tick, no_protection = FALSE)
if(internal_fire)
@@ -13,12 +13,6 @@
RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_TOXIMMUNE), PROC_REF(on_toximmune_trait_gain))
RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_GENELESS), PROC_REF(on_geneless_trait_gain))
RegisterSignals(src, list(
SIGNAL_ADDTRAIT(TRAIT_PERMANENTLY_ONFIRE),
SIGNAL_REMOVETRAIT(TRAIT_PERMANENTLY_ONFIRE),
), PROC_REF(update_permanently_on_fire))
/**
* On gain of TRAIT_AGENDER
*
@@ -90,12 +84,6 @@
reagents.end_metabolization(keep_liverless = TRUE)
///On gain of TRAIT_PERMANENTLY_ONFIRE, update the visuals if not on fire
/mob/living/carbon/proc/update_permanently_on_fire(datum/source)
SIGNAL_HANDLER
if(!on_fire)
update_fire()
/**
* On gain of TRAIT_VIRUSIMMUNE
*
+9 -15
View File
@@ -1654,11 +1654,6 @@ GLOBAL_LIST_EMPTY(fire_appearances)
return fire_status.ignite(silent)
/mob/living/proc/update_fire()
var/datum/status_effect/fire_handler/fire_stacks/fire_stacks = has_status_effect(/datum/status_effect/fire_handler/fire_stacks)
if(fire_stacks)
fire_stacks.update_overlay()
/**
* Extinguish all fire on the mob
*
@@ -1666,7 +1661,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
* Signals the extinguishing.
*/
/mob/living/proc/extinguish_mob()
if(HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE)) //The everlasting flames will not be extinguished
if(HAS_TRAIT(src, TRAIT_NO_EXTINGUISH)) //The everlasting flames will not be extinguished
return
var/datum/status_effect/fire_handler/fire_stacks/fire_status = has_status_effect(/datum/status_effect/fire_handler/fire_stacks)
if(!fire_status || !fire_status.on_fire)
@@ -1685,13 +1680,13 @@ GLOBAL_LIST_EMPTY(fire_appearances)
/mob/living/proc/adjust_fire_stacks(stacks, fire_type = /datum/status_effect/fire_handler/fire_stacks)
if(stacks < 0)
if(HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE)) //You can't reduce fire stacks of the everlasting flames
if(HAS_TRAIT(src, TRAIT_NO_EXTINGUISH)) //You can't reduce fire stacks of the everlasting flames
return
stacks = max(-fire_stacks, stacks)
apply_status_effect(fire_type, stacks)
/mob/living/proc/adjust_wet_stacks(stacks, wet_type = /datum/status_effect/fire_handler/wet_stacks)
if(HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE)) //The everlasting flames will not be extinguished
if(HAS_TRAIT(src, TRAIT_NO_EXTINGUISH)) //The everlasting flames will not be extinguished
return
if(stacks < 0)
stacks = max(fire_stacks, stacks)
@@ -1769,19 +1764,18 @@ GLOBAL_LIST_EMPTY(fire_appearances)
ignite_mob()
/**
* Sets fire overlay of the mob.
* Gets the fire overlay to use for this mob
*
* Vars:
* Args:
* * stacks: Current amount of fire_stacks
* * on_fire: If we're lit on fire
* * last_icon_state: Holds last fire overlay icon state, used for optimization
* * suffix: Suffix for the fire icon state for special fire types
*
* This should return last_icon_state for the fire status efect
* Return a mutable appearance, the overlay that will be applied.
*/
/mob/living/proc/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
return last_icon_state
/mob/living/proc/get_fire_overlay(stacks, on_fire)
RETURN_TYPE(/mutable_appearance)
return null
/**
* Handles effects happening when mob is on normal fire
+10 -17
View File
@@ -360,7 +360,7 @@
var/mutable_appearance/head_overlay = hat.build_worn_icon(default_layer = 20, default_icon_file = 'icons/mob/clothing/head/default.dmi')
head_overlay.pixel_z += hat_offset
add_overlay(head_overlay)
update_fire()
update_appearance(UPDATE_OVERLAYS)
/mob/living/silicon/robot/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
if(same_z_layer)
@@ -1034,26 +1034,19 @@
/mob/living/silicon/robot/proc/untip_roleplay()
to_chat(src, span_notice("Your frustration has empowered you! You can now right yourself faster!"))
/mob/living/silicon/robot/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
var/fire_icon = "generic_fire[suffix]"
/mob/living/silicon/robot/get_fire_overlay(stacks, on_fire)
var/fire_icon = "generic_fire"
if(!GLOB.fire_appearances[fire_icon])
var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/effects/onfire.dmi', fire_icon, -FIRE_LAYER)
new_fire_overlay.appearance_flags = RESET_COLOR
var/mutable_appearance/new_fire_overlay = mutable_appearance(
'icons/mob/effects/onfire.dmi',
fire_icon,
-HIGHEST_LAYER,
appearance_flags = RESET_COLOR,
)
GLOB.fire_appearances[fire_icon] = new_fire_overlay
if(stacks && on_fire)
if(last_icon_state == fire_icon)
return last_icon_state
add_overlay(GLOB.fire_appearances[fire_icon])
return fire_icon
if(!last_icon_state)
return last_icon_state
cut_overlay(GLOB.fire_appearances[fire_icon])
return null
return GLOB.fire_appearances[fire_icon]
/// Draw power from the robot
/mob/living/silicon/robot/proc/draw_power(power_to_draw)
+36 -18
View File
@@ -186,9 +186,12 @@
. += mutable_appearance(overlay_icon, base_state)
//SKYRAT EDIT ADDITION BEGIN - AESTHETICS
// SKYRAT EDIT ADDITION BEGIN - AESTHETICS
#define LIGHT_ON_DELAY_UPPER (2 SECONDS)
#define LIGHT_ON_DELAY_LOWER (0.25 SECONDS)
/// Dynamically calculate nightshift brightness
#define NIGHTSHIFT_LIGHT_MODIFIER 0.15
#define NIGHTSHIFT_COLOR_MODIFIER 0.15
//SKYRAT EDIT END
// Area sensitivity is traditionally tied directly to power use, as an optimization
@@ -211,16 +214,15 @@
/obj/machinery/light/proc/handle_fire(area/source, new_fire)
SIGNAL_HANDLER
update(instant = TRUE, play_sound = FALSE) //SKYRAT EDIT CHANGE
update(instant = TRUE, play_sound = FALSE) //SKYRAT EDIT CHANGE - ORIGINAL: update()
// update the icon_state and luminosity of the light depending on its state
/obj/machinery/light/proc/update(trigger = TRUE, instant = FALSE, play_sound = TRUE) //SKYRAT EDIT CHANGE
/obj/machinery/light/proc/update(trigger = TRUE, instant = FALSE, play_sound = TRUE) // SKYRAT EDIT CHANGE
switch(status)
if(LIGHT_BROKEN,LIGHT_BURNED,LIGHT_EMPTY)
on = FALSE
low_power_mode = FALSE
if(on)
/* SKYRAT EDIT ORIGINAL
var/brightness_set = brightness
var/power_set = bulb_power
var/color_set = bulb_colour
@@ -234,15 +236,31 @@
power_set = fire_power
brightness_set = fire_brightness
else if (nightshift_enabled)
brightness_set = nightshift_brightness
power_set = nightshift_light_power
brightness_set -= brightness_set * NIGHTSHIFT_LIGHT_MODIFIER // SKYRAT EDIT CHANGE - ORIGINAL: brightness_set = nightshift_brightness
power_set -= power_set * NIGHTSHIFT_LIGHT_MODIFIER // SKYRAT EDIT CHANGE - ORIGINAL: power_set = nightshift_light_power
if(!color)
color_set = nightshift_light_color
// SKYRAT EDIT ADDITION START - Dynamic nightshift color
if(!color_set)
// Adjust light values to be warmer. I doubt caching would speed this up by any worthwhile amount, as it's all very fast number and string operations.
// Convert to numbers for easier manipulation.
var/list/color_parts = rgb2num(bulb_colour)
var/red = color_parts[1]
var/green = color_parts[2]
var/blue = color_parts[3]
red += round(red * NIGHTSHIFT_COLOR_MODIFIER)
green -= round(green * NIGHTSHIFT_COLOR_MODIFIER * 0.3)
red = clamp(red, 0, 255) // clamp to be safe, or you can end up with an invalid hex value
green = clamp(green, 0, 255)
blue = clamp(blue, 0, 255)
color_set = rgb(red, green, blue) // Splice the numbers together and turn them back to hex.
// SKYRAT EDIT ADDITION END
else if (major_emergency)
color_set = bulb_low_power_colour
brightness_set = brightness * bulb_major_emergency_brightness_mul
var/matching = light && brightness_set == light.light_range && power_set == light.light_power && color_set == light.light_color
if(!matching)
if(!matching && (maploaded || instant)) // SKYRAT EDIT CHANGE - ORIGINAL: if(!matching)
switchcount++
if( prob( min(60, (switchcount**2)*0.01) ) )
if(trigger)
@@ -254,17 +272,15 @@
l_power = power_set,
l_color = color_set
)
*/
//SKYRAT EDIT CHANGE BEGIN - AESTHETICS
if(instant)
turn_on(trigger, play_sound)
else if(maploaded)
turn_on(trigger, play_sound)
maploaded = FALSE
else if(!turning_on)
// SKYRAT EDIT ADDITION START
maploaded = FALSE
if(play_sound)
playsound(src.loc, 'modular_skyrat/modules/aesthetics/lights/sound/light_on.ogg', 65, 1)
else if(!matching && !turning_on)
switchcount++
turning_on = TRUE
addtimer(CALLBACK(src, PROC_REF(turn_on), trigger, play_sound), rand(LIGHT_ON_DELAY_LOWER, LIGHT_ON_DELAY_UPPER))
//SKYRAT EDIT END
addtimer(CALLBACK(src, PROC_REF(delayed_turn_on), trigger, play_sound, color_set, power_set, brightness_set), rand(LIGHT_ON_DELAY_LOWER, LIGHT_ON_DELAY_UPPER))
// SKYRAT EDIT ADDITION END
else if(has_emergency_power(LIGHT_EMERGENCY_POWER_USE) && !turned_off())
use_power = IDLE_POWER_USE
low_power_mode = TRUE
@@ -280,7 +296,9 @@
//SKYRAT EDIT ADDITION BEGIN - AESTHETICS
#undef LIGHT_ON_DELAY_UPPER
#undef LIGHT_ON_DELAY_LOWER
//SKYRAT EDIT END
#undef NIGHTSHIFT_LIGHT_MODIFIER
#undef NIGHTSHIFT_COLOR_MODIFIER
// SKYRAT EDIT ADDITION END
/obj/machinery/light/update_current_power_usage()
if(!on && static_power_used > 0) //Light is off but still powered
@@ -642,31 +642,17 @@
exposed_human.skin_tone = "mixed3"
//take current alien color and darken it slightly
else if(HAS_TRAIT(exposed_human, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(exposed_human, TRAIT_FIXED_MUTANT_COLORS))
var/newcolor = ""
var/string = exposed_human.dna.features["mcolor"]
var/len = length(string)
var/char = ""
var/ascii = 0
for(var/i=1, i <= len, i += length(char))
char = string[i]
ascii = text2ascii(char)
switch(ascii)
if(48)
newcolor += "0"
if(49 to 57)
newcolor += ascii2text(ascii-1) //numbers 1 to 9
if(97)
newcolor += "9"
if(98 to 102)
newcolor += ascii2text(ascii-1) //letters b to f lowercase
if(65)
newcolor += "9"
if(66 to 70)
newcolor += ascii2text(ascii+31) //letters B to F - translates to lowercase
else
break
if(ReadHSV(newcolor)[3] >= ReadHSV("#7F7F7F")[3])
exposed_human.dna.features["mcolor"] = newcolor
var/list/existing_color = rgb2num(exposed_human.dna.features["mcolor"])
var/list/darkened_color = list()
// Reduces each part of the color by 16
for(var/channel in existing_color)
darkened_color += max(channel - 17, 0)
var/new_color = rgb(darkened_color[1], darkened_color[2], darkened_color[3])
var/list/new_hsv = rgb2hsv(new_color)
// Can't get too dark now
if(new_hsv[3] >= 50)
exposed_human.dna.features["mcolor"] = new_color
exposed_human.update_body(is_creating = TRUE)
if((methods & INGEST) && show_message)
@@ -68,16 +68,20 @@
human_user.skin_tone = new_s_tone
human_user.dna.update_ui_block(DNA_SKIN_TONE_BLOCK)
#define MIN_MCOLOR_VALUE 50
if(HAS_TRAIT(human_user, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(human_user, TRAIT_FIXED_MUTANT_COLORS))
var/new_mutantcolor = input(user, "Choose your skin color:", "Race change", human_user.dna.features["mcolor"]) as color|null
if(new_mutantcolor)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
var/mutantcolor_hsv = rgb2hsv(new_mutantcolor)
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
if(mutantcolor_hsv[3] >= MIN_MCOLOR_VALUE) // mutantcolors must be bright
human_user.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
else
to_chat(human_user, span_notice("Invalid color. Your color is not bright enough."))
#undef MIN_MCOLOR_VALUE
human_user.update_body()
human_user.update_body_parts()
@@ -41,7 +41,7 @@
. = ..()
var/pre_light_range = 0
var/pre_light_power = 0
var/pre_light_color = ""
var/pre_light_color = initial(light_color)
var/lights_overlay = ""
var/frame_state
@@ -20,52 +20,24 @@
var/flicker_timer = null
var/roundstart_flicker = FALSE
/obj/machinery/light/proc/turn_on(trigger, play_sound = TRUE)
/obj/machinery/light/proc/delayed_turn_on(trigger, play_sound = TRUE, color_set, power_set, brightness_set)
if(QDELETED(src))
return
turning_on = FALSE
if(!on)
return
var/area/local_area = get_room_area(src)
var/new_brightness = brightness
var/new_power = bulb_power
var/new_color = bulb_colour
if (local_area?.fire)
new_color = fire_colour
new_brightness = fire_brightness
else if(color)
new_color = color
else if (nightshift_enabled)
new_brightness -= new_brightness * NIGHTSHIFT_LIGHT_MODIFIER
new_power -= new_power * NIGHTSHIFT_LIGHT_MODIFIER
if(!color && nightshift_light_color)
new_color = nightshift_light_color
else if(color) // In case it's spraypainted.
new_color = color
else // Adjust light values to be warmer. I doubt caching would speed this up by any worthwhile amount, as it's all very fast number and string operations.
// Convert to numbers for easier manipulation.
var/red = GETREDPART(bulb_colour)
var/green = GETGREENPART(bulb_colour)
var/blue = GETBLUEPART(bulb_colour)
red += round(red * NIGHTSHIFT_COLOR_MODIFIER)
green -= round(green * NIGHTSHIFT_COLOR_MODIFIER * 0.3)
red = clamp(red, 0, 255) // clamp to be safe, or you can end up with an invalid hex value
green = clamp(green, 0, 255)
blue = clamp(blue, 0, 255)
new_color = "#[num2hex(red, 2)][num2hex(green, 2)][num2hex(blue, 2)]" // Splice the numbers together and turn them back to hex.
var/matching = light && new_brightness == light.light_range && new_power == light.light_power && new_color == light.light_color
if(!matching)
switchcount++
if( prob( min(60, (switchcount**2)*0.01) ) )
if(trigger)
burn_out()
else
use_power = ACTIVE_POWER_USE
set_light(new_brightness, new_power, new_color)
if(play_sound)
playsound(src.loc, 'modular_skyrat/modules/aesthetics/lights/sound/light_on.ogg', 65, 1)
if( prob( min(60, (switchcount**2)*0.01) ) )
if(trigger)
burn_out()
else
use_power = ACTIVE_POWER_USE
set_light(
l_range = brightness_set,
l_power = power_set,
l_color = color_set
)
if(play_sound)
playsound(src.loc, 'modular_skyrat/modules/aesthetics/lights/sound/light_on.ogg', 65, 1)
/obj/machinery/light/proc/start_flickering()
on = FALSE
@@ -68,4 +68,4 @@
icon_state = "[model.cyborg_base_icon]-wreck"
update_fire()
update_appearance(UPDATE_OVERLAYS)
@@ -131,14 +131,14 @@
switch(sprite_type.color_src)
if(USE_MATRIXED_COLORS)
finished_list += ReadRGB("[color_list[1]]00")
finished_list += ReadRGB("[color_list[2]]00")
finished_list += ReadRGB("[color_list[3]]00")
finished_list += rgb2num("[color_list[1]]00")
finished_list += rgb2num("[color_list[2]]00")
finished_list += rgb2num("[color_list[3]]00")
if(USE_ONE_COLOR)
var/padded_string = "[color_list[1]]00"
finished_list += ReadRGB(padded_string)
finished_list += ReadRGB(padded_string)
finished_list += ReadRGB(padded_string)
finished_list += rgb2num(padded_string)
finished_list += rgb2num(padded_string)
finished_list += rgb2num(padded_string)
finished_list += list(0,0,0,255)
for(var/index in 1 to finished_list.len)
@@ -191,31 +191,6 @@
mind.transfer_to(xeno_to_transfer_to)
qdel(src)
/mob/living/carbon/alien/adult/skyrat/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
var/fire_icon = "generic_fire[suffix]"
if(!GLOB.fire_appearances[fire_icon])
var/mutable_appearance/xeno_fire_overlay = mutable_appearance('icons/mob/effects/onfire.dmi', fire_icon, -FIRE_LAYER, appearance_flags = RESET_COLOR)
xeno_fire_overlay.pixel_x = on_fire_pixel_x
xeno_fire_overlay.pixel_y = on_fire_pixel_y
GLOB.fire_appearances[fire_icon] = xeno_fire_overlay
if((stacks > 0 && on_fire) || HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE))
if(fire_icon == last_icon_state)
return last_icon_state
remove_overlay(FIRE_LAYER)
overlays_standing[FIRE_LAYER] = GLOB.fire_appearances[fire_icon]
apply_overlay(FIRE_LAYER)
return fire_icon
if(!last_icon_state)
return last_icon_state
remove_overlay(FIRE_LAYER)
apply_overlay(FIRE_LAYER)
return null
/mob/living/carbon/alien/adult/skyrat/findQueen() //Yes we really do need to do this whole thing to let the queen finder work
if(hud_used)
hud_used.alien_queen_finder.cut_overlays()
+1
View File
@@ -1538,6 +1538,7 @@
#include "code\datums\elements\openspace_item_click_handler.dm"
#include "code\datums\elements\ore_collecting.dm"
#include "code\datums\elements\organ_set_bonus.dm"
#include "code\datums\elements\permanent_fire_overlay.dm"
#include "code\datums\elements\pet_bonus.dm"
#include "code\datums\elements\plant_backfire.dm"
#include "code\datums\elements\point_of_interest.dm"