mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-17 18:13:34 +01:00
Yeah so I impulsively ported the entirety of this system without knowing what it did
This commit is contained in:
@@ -157,3 +157,20 @@
|
||||
|
||||
/// Color for dead external organs/zombies
|
||||
#define COLORTONE_DEAD_EXT_ORGAN "#0A3200"
|
||||
|
||||
|
||||
/// If this is a plain atom color
|
||||
#define ATOM_COLOR_TYPE_NORMAL "normal"
|
||||
/// If this is a color filter
|
||||
#define ATOM_COLOR_TYPE_FILTER "filter"
|
||||
// Indexes for color arrays
|
||||
#define ATOM_COLOR_VALUE_INDEX 1
|
||||
#define ATOM_COLOR_TYPE_INDEX 2
|
||||
#define ATOM_PRIORITY_COLOR_FILTER "atom_priority_color"
|
||||
#define ATOM_PRIORITY_COLOR_FILTER_PRIORITY -1
|
||||
/// Multiply pixel's saturation by color's saturation. Paints accents while keeping dim areas dim.
|
||||
#define SATURATION_MULTIPLY "multiply"
|
||||
/// Always affects the original pixel's saturation and lightness.
|
||||
#define SATURATION_OVERRIDE "always"
|
||||
|
||||
|
||||
|
||||
@@ -202,3 +202,19 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
|
||||
#define SCOPE_CLICK_MIDDLE (1<<2)
|
||||
/// Should the user hold the item in active hand to use it?
|
||||
#define SCOPE_NEED_ACTIVE_HAND (1<<3)
|
||||
|
||||
// for next define
|
||||
#define KEEP_TOGETHER_ORIGINAL "keep_together_original"
|
||||
|
||||
//setter for KEEP_TOGETHER to allow for multiple sources to set and unset it
|
||||
#define ADD_KEEP_TOGETHER(x, source)\
|
||||
if ((x.appearance_flags & KEEP_TOGETHER) && !HAS_TRAIT(x, TRAIT_KEEP_TOGETHER)) ADD_TRAIT(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL); \
|
||||
ADD_TRAIT(x, TRAIT_KEEP_TOGETHER, source);\
|
||||
x.appearance_flags |= KEEP_TOGETHER
|
||||
|
||||
#define REMOVE_KEEP_TOGETHER(x, source)\
|
||||
REMOVE_TRAIT(x, TRAIT_KEEP_TOGETHER, source);\
|
||||
if(HAS_TRAIT_FROM_ONLY(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL))\
|
||||
REMOVE_TRAIT(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL);\
|
||||
else if(!HAS_TRAIT(x, TRAIT_KEEP_TOGETHER))\
|
||||
x.appearance_flags &= ~KEEP_TOGETHER
|
||||
|
||||
@@ -45,3 +45,112 @@
|
||||
RGB[2] = clamp(RGB[2]+value,0,255)
|
||||
RGB[3] = clamp(RGB[3]+value,0,255)
|
||||
return rgb(RGB[1],RGB[2],RGB[3])
|
||||
|
||||
//PACS related code
|
||||
|
||||
/proc/color_transition_filter(new_color, saturation_behavior = SATURATION_MULTIPLY)
|
||||
if (islist(new_color))
|
||||
new_color = rgb(new_color[1], new_color[2], new_color[3])
|
||||
new_color = rgb2num(new_color, COLORSPACE_HSL)
|
||||
var/hue = new_color[1] / 360
|
||||
var/saturation = new_color[2] / 100
|
||||
var/added_saturation = 0
|
||||
var/deducted_light = 0
|
||||
if (saturation_behavior == SATURATION_OVERRIDE)
|
||||
added_saturation = saturation * 0.75
|
||||
deducted_light = saturation * 0.5
|
||||
saturation = min(saturation, 1 - added_saturation)
|
||||
|
||||
var/list/new_matrix = list(
|
||||
0, 0, 0, 0, // Ignore original hue
|
||||
0, saturation, 0, 0, // Multiply the saturation by ours
|
||||
0, 0, 1 - deducted_light, 0, // If we're highly saturated then remove a bit of lightness to keep some color in
|
||||
0, 0, 0, 1, // Preserve alpha
|
||||
hue, added_saturation, 0, 0, // And apply our preferred hue and some saturation if we're oversaturated
|
||||
)
|
||||
return color_matrix_filter(new_matrix, FILTER_COLOR_HSL)
|
||||
|
||||
/// Applies a color filter to a hex/RGB list color
|
||||
/proc/apply_matrix_to_color(color, list/matrix, colorspace = COLORSPACE_HSL)
|
||||
if (islist(color))
|
||||
color = rgb(color[1], color[2], color[3], color[4])
|
||||
color = rgb2num(color, colorspace)
|
||||
// Pad alpha if we're lacking it
|
||||
if (length(color) < 4)
|
||||
color += 255
|
||||
|
||||
// Do we have a constants row?
|
||||
var/has_constants = FALSE
|
||||
// Do we have an alpha row/parameters?
|
||||
var/has_alpha = FALSE
|
||||
|
||||
switch (length(matrix))
|
||||
if (9)
|
||||
has_constants = FALSE
|
||||
has_alpha = FALSE
|
||||
if (12)
|
||||
has_constants = TRUE
|
||||
has_alpha = FALSE
|
||||
if (16)
|
||||
has_constants = FALSE
|
||||
has_alpha = TRUE
|
||||
if (20)
|
||||
has_constants = TRUE
|
||||
has_alpha = TRUE
|
||||
else
|
||||
CRASH("Matrix of invalid length [length(matrix)] was passed into apply_matrix_to_color!")
|
||||
|
||||
var/list/new_color = list(0, 0, 0, 0)
|
||||
var/row_length = 3
|
||||
if (has_alpha)
|
||||
row_length = 4
|
||||
else
|
||||
new_color[4] = 255
|
||||
|
||||
for (var/row_index in 1 to length(matrix) / row_length)
|
||||
for (var/row_elem in 1 to row_length)
|
||||
var/elem = matrix[(row_index - 1) * row_length + row_elem]
|
||||
if (!has_constants || row_index != (length(matrix) / row_length))
|
||||
new_color[row_index] += color[row_elem] * elem
|
||||
continue
|
||||
|
||||
// Constant values at the end of the list (if we have such)
|
||||
if (colorspace != COLORSPACE_HSV && colorspace != COLORSPACE_HCY && colorspace != COLORSPACE_HSL)
|
||||
new_color[row_elem] += elem * 255
|
||||
continue
|
||||
|
||||
// HSV/HSL/HCY have non-255 maximums for their values
|
||||
var/multiplier = 255
|
||||
switch (row_elem)
|
||||
// Hue goes from 0 to 360
|
||||
if (1)
|
||||
multiplier = 360
|
||||
// Value, luminance, chroma, etc go from 0 to 100
|
||||
if (2 to 3)
|
||||
multiplier = 100
|
||||
// Alpha still goes from 0 to 255
|
||||
if (4)
|
||||
multiplier = 255
|
||||
new_color[row_elem] += elem * multiplier
|
||||
|
||||
var/rgbcolor = rgb(new_color[1], new_color[2], new_color[3], new_color[4], space = colorspace)
|
||||
return rgbcolor
|
||||
|
||||
/// Recursively applies a filter to a passed in static appearance, returns the modified appearance
|
||||
/proc/filter_appearance_recursive(mutable_appearance/filter, filter_to_apply)
|
||||
var/mutable_appearance/modify = new(filter)
|
||||
var/list/existing_filters = modify.filters.Copy()
|
||||
modify.filters = list(filter_to_apply) + existing_filters
|
||||
|
||||
// Ideally this should be recursive to check for KEEP_APART elements that need this applied to it
|
||||
// and RESET_COLOR flags but this is much simpler, and hopefully we don't have that point of layering here
|
||||
if(modify.appearance_flags & KEEP_TOGETHER)
|
||||
return modify
|
||||
|
||||
for(var/overlay_index in 1 to length(modify.overlays))
|
||||
modify.overlays[overlay_index] = filter_appearance_recursive(modify.overlays[overlay_index], filter_to_apply)
|
||||
|
||||
for(var/underlay_index in 1 to length(modify.underlays))
|
||||
modify.underlays[underlay_index] = filter_appearance_recursive(modify.underlays[underlay_index], filter_to_apply)
|
||||
|
||||
return modify
|
||||
|
||||
@@ -331,3 +331,9 @@ GLOBAL_LIST_INIT(master_filter_info, list(
|
||||
.["offset"] = offset
|
||||
if(!isnull(alpha))
|
||||
.["alpha"] = alpha
|
||||
|
||||
// PACS related
|
||||
/proc/convert_list_to_filter(list/list_filter)
|
||||
var/list/arguments = list_filter.Copy()
|
||||
arguments -= "priority"
|
||||
return filter(arglist(arguments))
|
||||
|
||||
@@ -131,6 +131,9 @@
|
||||
/// Gives a unique trait source for any given datum
|
||||
#define UNIQUE_TRAIT_SOURCE(target) "unique_source_[target.UID()]"
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Remember to update _globalvars/traits.dm if you're adding/removing/renaming traits.
|
||||
*/
|
||||
@@ -384,6 +387,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
//traits that should be properly converted to genetic mutations one day
|
||||
#define TRAIT_LASEREYES "laser_eyes"
|
||||
|
||||
|
||||
/// Trait aquired from being painted a certain color
|
||||
#define ATOM_COLOR_TRAIT "atom_color"
|
||||
|
||||
|
||||
//status effec traits
|
||||
/// Forces the user to stay unconscious.
|
||||
#define TRAIT_KNOCKEDOUT "knockedout"
|
||||
@@ -449,3 +457,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
/// Proc wrapper of remove_trait. You should only use this for callback. Otherwise, use the macro.
|
||||
/proc/callback_remove_trait(datum/target, trait, source)
|
||||
REMOVE_TRAIT(target, trait, source)
|
||||
|
||||
///Used for managing KEEP_TOGETHER in [appearance_flags]
|
||||
#define TRAIT_KEEP_TOGETHER "keep-together"
|
||||
|
||||
@@ -154,6 +154,9 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
|
||||
/atom/movable = list(
|
||||
"TRAIT_NO_EDGE_TRANSITIONS" = TRAIT_NO_EDGE_TRANSITIONS
|
||||
),
|
||||
/atom = list(
|
||||
"TRAIT_KEEP_TOGETHER" = TRAIT_KEEP_TOGETHER
|
||||
)
|
||||
))
|
||||
|
||||
|
||||
@@ -26,6 +26,6 @@
|
||||
var/colour = spraycan.colour
|
||||
current_paint = colour
|
||||
var/atom/A = parent
|
||||
A.add_atom_colour(colour, FIXED_COLOUR_PRIORITY)
|
||||
A.add_atom_colour(color_transition_filter(colour, SATURATION_MULTIPLY), ADMIN_COLOUR_PRIORITY)
|
||||
playsound(spraycan, 'sound/effects/spray.ogg', 5, TRUE, 5)
|
||||
to_chat(user, "<span class='notice'>You spray [spraycan] on [A], painting it.</span>")
|
||||
|
||||
+44
-15
@@ -59,6 +59,9 @@
|
||||
|
||||
var/list/atom_colours //used to store the different colors on an atom
|
||||
//its inherent color, the colored paint applied on it, special color effect etc...
|
||||
// currently used Color filter, cached because we apply it to all of our overlays. According to the original PR author, "Byond is Horrific."
|
||||
var/cached_color_filter
|
||||
|
||||
|
||||
/// Radiation insulation types
|
||||
var/rad_insulation = RAD_NO_INSULATION
|
||||
@@ -1245,7 +1248,12 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
|
||||
return
|
||||
if(colour_priority > length(atom_colours))
|
||||
return
|
||||
atom_colours[colour_priority] = coloration
|
||||
var/color_type = ATOM_COLOR_TYPE_NORMAL
|
||||
if (islist(coloration))
|
||||
var/list/color_matrix = coloration
|
||||
if(color_matrix["type"]=="color")
|
||||
color_type = ATOM_COLOR_TYPE_FILTER
|
||||
atom_colours[colour_priority] = list(coloration, color_type)
|
||||
update_atom_colour()
|
||||
|
||||
/*
|
||||
@@ -1257,8 +1265,13 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
|
||||
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
|
||||
if(colour_priority > length(atom_colours))
|
||||
return
|
||||
if(coloration && atom_colours[colour_priority] != coloration)
|
||||
return //if we don't have the expected color (for a specific priority) to remove, do nothing
|
||||
if(coloration && atom_colours[colour_priority])
|
||||
if (atom_colours[colour_priority][ATOM_COLOR_TYPE_INDEX] == ATOM_COLOR_TYPE_NORMAL)
|
||||
if(atom_colours[colour_priority][ATOM_COLOR_VALUE_INDEX]!=coloration)
|
||||
return // if we don't have the expected color to remove, don't do anything.
|
||||
else
|
||||
if(!islist(coloration) || !compare_list(coloration,atom_colours[colour_priority][ATOM_COLOR_VALUE_INDEX]["color"]))
|
||||
return
|
||||
atom_colours[colour_priority] = null
|
||||
update_atom_colour()
|
||||
|
||||
@@ -1267,19 +1280,35 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
|
||||
colour available
|
||||
*/
|
||||
/atom/proc/update_atom_colour()
|
||||
var/old_filter = cached_color_filter
|
||||
cached_color_filter = null
|
||||
remove_filter(ATOM_PRIORITY_COLOR_FILTER)
|
||||
REMOVE_KEEP_TOGETHER(src, ATOM_COLOR_TRAIT)
|
||||
|
||||
if(!atom_colours)
|
||||
atom_colours = list()
|
||||
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
|
||||
color = null
|
||||
for(var/C in atom_colours)
|
||||
if(islist(C))
|
||||
var/list/L = C
|
||||
if(length(L))
|
||||
color = L
|
||||
return
|
||||
else if(C)
|
||||
color = C
|
||||
return
|
||||
if (old_filter)
|
||||
update_appearance()
|
||||
return
|
||||
for(var/list/checked_color in atom_colours)
|
||||
if(checked_color[ATOM_COLOR_TYPE_INDEX] == ATOM_COLOR_TYPE_FILTER)
|
||||
add_filter(ATOM_PRIORITY_COLOR_FILTER, ATOM_PRIORITY_COLOR_FILTER_PRIORITY, checked_color[ATOM_COLOR_VALUE_INDEX])
|
||||
cached_color_filter = checked_color[ATOM_COLOR_VALUE_INDEX]
|
||||
break
|
||||
if(length(checked_color[ATOM_COLOR_VALUE_INDEX]))
|
||||
color = checked_color[ATOM_COLOR_VALUE_INDEX]
|
||||
break
|
||||
|
||||
ADD_KEEP_TOGETHER(src, ATOM_COLOR_TRAIT)
|
||||
if(cached_color_filter != old_filter)
|
||||
update_appearance()
|
||||
|
||||
/// Same as update_atom_color, but simplifies overlay coloring
|
||||
/atom/proc/color_atom_overlay(mutable_appearance/overlay)
|
||||
overlay.color = color
|
||||
if (!cached_color_filter)
|
||||
return overlay
|
||||
return filter_appearance_recursive(overlay, cached_color_filter)
|
||||
|
||||
|
||||
/** Call this when you want to present a renaming prompt to the user.
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
/obj/item/toy/crayon/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is jamming the [name] up [user.p_their()] nose and into [user.p_their()] brain. It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
user.add_atom_colour(color_transition_filter(colour, SATURATION_OVERRIDE), ADMIN_COLOUR_PRIORITY)
|
||||
return BRUTELOSS|OXYLOSS
|
||||
|
||||
/obj/item/toy/crayon/Initialize(mapload)
|
||||
|
||||
@@ -14,36 +14,42 @@
|
||||
if(!dyeable || !dye_color)
|
||||
return
|
||||
var/dye_key_selector = dye_key_override ? dye_key_override : dyeing_key
|
||||
if(!dye_key_selector)
|
||||
return FALSE
|
||||
if(!GLOB.dye_registry[dye_key_selector])
|
||||
stack_trace("Item just tried to be dyed with an invalid registry key: [dye_key_selector]")
|
||||
return FALSE
|
||||
var/obj/item/target_type = GLOB.dye_registry[dye_key_selector][dye_color]
|
||||
if(!target_type)
|
||||
return FALSE
|
||||
var/obj/item/target_obj = new target_type
|
||||
// update icons
|
||||
icon = initial(target_obj.icon)
|
||||
icon_state = initial(target_obj.icon_state)
|
||||
item_state = initial(target_obj.item_state)
|
||||
sprite_sheets = target_obj.sprite_sheets
|
||||
item_color = target_obj.item_color
|
||||
desc = target_obj.desc
|
||||
base_icon_state = target_obj.base_icon_state
|
||||
var/has_key = TRUE // If not, we're gonna assign it using the PACS system.
|
||||
if(dye_key_selector)
|
||||
if(!GLOB.dye_registry[dye_key_selector])
|
||||
stack_trace("Item just tried to be dyed with an invalid registry key: [dye_key_selector]")
|
||||
return FALSE
|
||||
var/obj/item/target_type = GLOB.dye_registry[dye_key_selector][dye_color]
|
||||
var/obj/item/target_obj = new target_type
|
||||
if(!target_type)
|
||||
return FALSE
|
||||
// update icons
|
||||
if(has_key)
|
||||
icon = initial(target_obj.icon)
|
||||
icon_state = initial(target_obj.icon_state)
|
||||
item_state = initial(target_obj.item_state)
|
||||
sprite_sheets = target_obj.sprite_sheets
|
||||
item_color = target_obj.item_color
|
||||
desc = target_obj.desc
|
||||
base_icon_state = target_obj.base_icon_state
|
||||
|
||||
// update inhand sprites
|
||||
lefthand_file = initial(target_obj.lefthand_file)
|
||||
righthand_file = initial(target_obj.righthand_file)
|
||||
inhand_x_dimension = initial(target_obj.inhand_x_dimension)
|
||||
inhand_y_dimension = initial(target_obj.inhand_y_dimension)
|
||||
// update inhand sprites
|
||||
lefthand_file = initial(target_obj.lefthand_file)
|
||||
righthand_file = initial(target_obj.righthand_file)
|
||||
inhand_x_dimension = initial(target_obj.inhand_x_dimension)
|
||||
inhand_y_dimension = initial(target_obj.inhand_y_dimension)
|
||||
|
||||
// update the name/description
|
||||
name = initial(target_obj.name)
|
||||
qdel(target_obj)
|
||||
else
|
||||
has_key = FALSE
|
||||
add_atom_colour(color_transition_filter(dye_color, SATURATION_MULTIPLY), ADMIN_COLOUR_PRIORITY)
|
||||
|
||||
// update the name/description
|
||||
name = initial(target_obj.name)
|
||||
desc += "\nThe colors look a little dodgy."
|
||||
qdel(target_obj)
|
||||
|
||||
update_appearance(ALL)
|
||||
return target_type
|
||||
return TRUE
|
||||
|
||||
/// Beanies use the color var for their appearance, we don't normally copy this over but we have to for beanies
|
||||
/obj/item/clothing/head/beanie/dye_item(dye_color, dye_key_override)
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
icon = 'icons/obj/clothing/under/security.dmi'
|
||||
armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 20, ACID = 20)
|
||||
strip_delay = 50
|
||||
dyeable = TRUE
|
||||
dyeing_key = FALSE
|
||||
sprite_sheets = list(
|
||||
"Human" = 'icons/mob/clothing/under/security.dmi',
|
||||
"Vox" = 'icons/mob/clothing/species/vox/under/security.dmi',
|
||||
|
||||
@@ -614,7 +614,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
else
|
||||
standing.overlays += image("icon" = 'icons/mob/accessories.dmi', "icon_state" = "[tie_color]")
|
||||
standing.alpha = w_uniform.alpha
|
||||
standing.color = w_uniform.color
|
||||
standing = w_uniform.color_atom_overlay(standing)
|
||||
overlays_standing[UNIFORM_LAYER] = standing
|
||||
|
||||
else if(!dna.species.nojumpsuit)
|
||||
@@ -816,7 +816,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
bloodsies.color = shoes.blood_color
|
||||
standing.overlays += bloodsies
|
||||
standing.alpha = shoes.alpha
|
||||
standing.color = shoes.color
|
||||
standing = shoes.color_atom_overlay(standing)
|
||||
overlays_standing[SHOES_LAYER] = standing
|
||||
else
|
||||
if(feet_blood_DNA) // Checks for feet to make sure we don't have mysterious floating blood.
|
||||
@@ -887,7 +887,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
bloodsies.color = head.blood_color
|
||||
standing.overlays += bloodsies
|
||||
standing.alpha = head.alpha
|
||||
standing.color = head.color
|
||||
standing = head.color_atom_overlay(standing)
|
||||
overlays_standing[HEAD_LAYER] = standing
|
||||
apply_overlay(HEAD_LAYER)
|
||||
|
||||
@@ -979,7 +979,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
standing.overlays += special_overlays
|
||||
|
||||
standing.alpha = wear_suit.alpha
|
||||
standing.color = wear_suit.color
|
||||
standing = wear_suit.color_atom_overlay(standing)
|
||||
overlays_standing[SUIT_LAYER] = standing
|
||||
|
||||
apply_overlay(SUIT_LAYER)
|
||||
@@ -1056,7 +1056,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
standing.overlays += bloodsies
|
||||
|
||||
standing.alpha = wear_mask.alpha
|
||||
standing.color = wear_mask.color
|
||||
standing = wear_mask.color_atom_overlay(standing)
|
||||
overlays_standing[FACEMASK_LAYER] = standing
|
||||
apply_overlay(FACEMASK_LAYER)
|
||||
|
||||
@@ -1107,7 +1107,8 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
|
||||
//create the image
|
||||
standing.alpha = back.alpha
|
||||
standing.color = back.color
|
||||
//standing.color = back.color
|
||||
standing = back.color_atom_overlay(standing)
|
||||
overlays_standing[BACK_LAYER] = standing
|
||||
apply_overlay(BACK_LAYER)
|
||||
|
||||
|
||||
@@ -613,7 +613,7 @@
|
||||
hsl[3] = max(hsl[3], 0.4)
|
||||
var/list/rgb = hsl2rgb(arglist(hsl))
|
||||
var/new_color = "#[num2hex(rgb[1], 2)][num2hex(rgb[2], 2)][num2hex(rgb[3], 2)]"
|
||||
color = new_color
|
||||
color = add_atom_colour(color_transition_filter(new_color, SATURATION_MULTIPLY), ADMIN_COLOUR_PRIORITY)
|
||||
to_chat(user, "<span class='notice'>You change [src]'s light bulb color.</span>")
|
||||
brightness_color = new_color
|
||||
update(TRUE, TRUE, FALSE)
|
||||
|
||||
Reference in New Issue
Block a user