diff --git a/SQL/migrate/V005__Body_markings.sql b/SQL/migrate/V005__Body_markings.sql
new file mode 100644
index 00000000000..36a2a2ebb77
--- /dev/null
+++ b/SQL/migrate/V005__Body_markings.sql
@@ -0,0 +1,7 @@
+--
+-- Implemented in PR #2607.
+-- Character body marking migration file
+--
+
+ALTER TABLE `ss13_characters`
+ ADD `body_markings` TEXT NULL DEFAULT NULL AFTER `organs_robotic`;
diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm
index ad552101331..d1cfe21357e 100644
--- a/code/_helpers/global_lists.dm
+++ b/code/_helpers/global_lists.dm
@@ -46,6 +46,7 @@ var/global/list/facial_hair_styles_list = list() //stores /datum/sprite_accessor
var/global/list/facial_hair_styles_male_list = list()
var/global/list/facial_hair_styles_female_list = list()
var/global/list/skin_styles_female_list = list() //unused
+var/global/list/body_marking_styles_list = list()
//Underwear
var/global/list/underwear_m = list("White" = "m1", "Grey" = "m2", "Green" = "m3", "Blue" = "m4", "Black" = "m5", "Mankini" = "m6", "None") //Curse whoever made male/female underwear diffrent colours
var/global/list/underwear_f = list("Red" = "f1", "White" = "f2", "Yellow" = "f3", "Blue" = "f4", "Black" = "f5", "Thong" = "f6", "Black Sports" = "f7","White Sports" = "f8","None")
@@ -117,6 +118,12 @@ var/global/list/cloaking_devices = list()
else
facial_hair_styles_male_list += H.name
facial_hair_styles_female_list += H.name
+
+ //Body markings
+ paths = subtypesof(/datum/sprite_accessory/marking)
+ for(var/path in paths)
+ var/datum/sprite_accessory/marking/M = new path()
+ body_marking_styles_list[M.name] = M
//Surgery Steps - Initialize all /datum/surgery_step into a list
paths = subtypesof(/datum/surgery_step)
diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm
index e30de18f4e2..421da3b6b60 100644
--- a/code/game/dna/dna2.dm
+++ b/code/game/dna/dna2.dm
@@ -84,6 +84,7 @@ var/global/list/datum/dna/gene/dna_genes[0]
// New stuff
var/species = "Human"
+ var/list/body_markings = list()
// Make a copy of this strand.
// USE THIS WHEN COPYING STUFF OR YOU'LL GET CORRUPTION!
@@ -93,6 +94,7 @@ var/global/list/datum/dna/gene/dna_genes[0]
new_dna.b_type=b_type
new_dna.real_name=real_name
new_dna.species=species
+ new_dna.body_markings=body_markings.Copy()
for(var/b=1;b<=DNA_SE_LENGTH;b++)
new_dna.SE[b]=SE[b]
if(b<=DNA_UI_LENGTH)
@@ -152,6 +154,11 @@ var/global/list/datum/dna/gene/dna_genes[0]
SetUIValueRange(DNA_UI_HAIR_STYLE, hair, hair_styles_list.len, 1)
SetUIValueRange(DNA_UI_BEARD_STYLE, beard, facial_hair_styles_list.len,1)
+ body_markings.Cut()
+ for(var/obj/item/organ/external/E in character.organs)
+ if(E.markings.len)
+ body_markings[E.limb_name] = E.markings.Copy()
+
UpdateUI()
// Set a DNA UI block's raw value.
diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm
index 19b32fef2ea..cee13661d66 100644
--- a/code/game/dna/dna2_helpers.dm
+++ b/code/game/dna/dna2_helpers.dm
@@ -163,6 +163,13 @@
else
H.gender = MALE
+ //Body markings
+ for(var/tag in dna.body_markings)
+ var/obj/item/organ/external/E = H.organs_by_name[tag]
+ if(E)
+ var/list/marklist = dna.body_markings[tag]
+ E.markings = marklist.Copy()
+
//Hair
var/hair = dna.GetUIValueRange(DNA_UI_HAIR_STYLE,hair_styles_list.len)
if((0 < hair) && (hair <= hair_styles_list.len))
diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index 33ad44ecfa1..caa084cf61e 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -25,6 +25,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
S["disabilities"] >> pref.disabilities
S["organ_data"] >> pref.organ_data
S["rlimb_data"] >> pref.rlimb_data
+ S["body_markings"] >> pref.body_markings
/datum/category_item/player_setup_item/general/body/save_character(var/savefile/S)
S["species"] << pref.species
@@ -47,6 +48,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
S["disabilities"] << pref.disabilities
S["organ_data"] << pref.organ_data
S["rlimb_data"] << pref.rlimb_data
+ S["body_markings"] << pref.body_markings
/datum/category_item/player_setup_item/general/body/gather_load_query()
return list("ss13_characters" = list("vars" = list("species",
@@ -60,7 +62,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
"b_type",
"disabilities",
"organs_data" = "organ_data",
- "organs_robotic" = "rlimb_data"),
+ "organs_robotic" = "rlimb_data",
+ "body_markings"),
"args" = list("id")))
/datum/category_item/player_setup_item/general/body/gather_load_parameters()
@@ -79,6 +82,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
"disabilities",
"organs_data",
"organs_robotic",
+ "body_markings",
"id" = 1,
"ckey" = 1))
@@ -95,6 +99,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
"disabilities" = pref.disabilities,
"organs_data" = list2params(pref.organ_data),
"organs_robotic"= list2params(pref.rlimb_data),
+ "body_markings" = json_encode(pref.body_markings),
"id" = pref.current_character,
"ckey" = pref.client.ckey)
@@ -131,6 +136,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.organ_data = params2list(pref.organ_data)
if (pref.rlimb_data)
pref.rlimb_data = params2list(pref.rlimb_data)
+ if (pref.body_markings)
+ pref.body_markings = json_decode(pref.body_markings)
pref.r_hair = sanitize_integer(pref.r_hair, 0, 255, initial(pref.r_hair))
pref.g_hair = sanitize_integer(pref.g_hair, 0, 255, initial(pref.g_hair))
@@ -154,6 +161,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.organ_data = list()
if (!pref.rlimb_data || !islist(pref.rlimb_data))
pref.rlimb_data = list()
+ if (!pref.body_markings || !islist(pref.body_markings))
+ pref.body_markings = list()
/datum/category_item/player_setup_item/general/body/content(var/mob/user)
pref.update_preview_icon()
@@ -269,6 +278,12 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
. += "
Body Color
"
. += "Change Color
"
+ . += "
Body Markings +
"
+ for(var/M in pref.body_markings)
+ . += "[M] - Color"
+ . += ""
+ . += "
"
+
/datum/category_item/player_setup_item/general/body/proc/has_flag(var/datum/species/mob_species, var/flag)
return mob_species && (mob_species.appearance_flags & flag)
@@ -350,6 +365,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.organ_data.Cut()
pref.rlimb_data.Cut()
+ pref.body_markings.Cut()
return TOPIC_REFRESH
@@ -437,6 +453,32 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.f_style = new_f_style
return TOPIC_REFRESH
+ else if(href_list["marking_style"])
+ var/list/usable_markings = pref.body_markings.Copy() ^ body_marking_styles_list.Copy()
+ for(var/M in usable_markings)
+ var/datum/sprite_accessory/S = usable_markings[M]
+ if(!S.species_allowed.len)
+ continue
+ else if(!(pref.species in S.species_allowed))
+ usable_markings -= M
+
+ var/new_marking = input(user, "Choose a body marking:", "Character Preference") as null|anything in usable_markings
+ if(new_marking && CanUseTopic(user))
+ pref.body_markings[new_marking] = "#000000" //New markings start black
+ return TOPIC_REFRESH
+
+ else if(href_list["marking_remove"])
+ var/M = href_list["marking_remove"]
+ pref.body_markings -= M
+ return TOPIC_REFRESH
+
+ else if(href_list["marking_color"])
+ var/M = href_list["marking_color"]
+ var/mark_color = input(user, "Choose the [M] color: ", "Character Preference", pref.body_markings[M]) as color|null
+ if(mark_color && CanUseTopic(user))
+ pref.body_markings[M] = "[mark_color]"
+ return TOPIC_REFRESH
+
else if(href_list["limbs"])
var/list/acceptable_organ_input = list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand")
var/limb_name = input(user, "Which limb do you want to change?") as null|anything in acceptable_organ_input
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 1e3369e1149..5592e4b343c 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -104,6 +104,7 @@ datum/preferences
// will probably not be able to do this for head and torso ;)
var/list/organ_data = list()
var/list/rlimb_data = list()
+ var/list/body_markings = list() // "name" = "#rgbcolor"
var/list/player_alt_titles = new() // the default name of a job like "Medical Doctor"
var/list/flavor_texts = list()
@@ -388,6 +389,19 @@ datum/preferences
else if(status == "mechanical")
I.robotize()
+ for(var/N in character.organs_by_name)
+ var/obj/item/organ/external/O = character.organs_by_name[N]
+ O.markings.Cut()
+
+ for(var/M in body_markings)
+ var/datum/sprite_accessory/marking/mark_datum = body_marking_styles_list[M]
+ var/mark_color = "[body_markings[M]]"
+
+ for(var/BP in mark_datum.body_parts)
+ var/obj/item/organ/external/O = character.organs_by_name[BP]
+ if(O)
+ O.markings[M] = list("color" = mark_color, "datum" = mark_datum)
+
character.underwear = underwear
character.undershirt = undershirt
@@ -545,6 +559,7 @@ datum/preferences
organ_data = list()
rlimb_data = list()
+ body_markings = list()
player_alt_titles = new()
flavor_texts = list()
diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm
index 27ca3bd7874..1744f5f453f 100644
--- a/code/modules/mob/new_player/sprite_accessories.dm
+++ b/code/modules/mob/new_player/sprite_accessories.dm
@@ -972,3 +972,132 @@
icon_state = "default"
icon = 'icons/mob/human_races/r_skrell.dmi'
species_allowed = list("Skrell")
+
+/*
+////////////////////////////
+/ =--------------------= /
+/ == Body Markings == /
+/ =--------------------= /
+////////////////////////////
+*/
+/datum/sprite_accessory/marking
+ icon = 'icons/mob/human_races/markings.dmi'
+ do_colouration = 1 //Almost all of them have it, COLOR_ADD
+
+ species_allowed = list()
+
+ var/body_parts = list() //A list of bodyparts this covers, TODO: port defines for organs someday
+
+ tiger_stripes
+ name = "Tiger Stripes (Tajara)"
+ icon_state = "tiger"
+ body_parts = list("l_foot","r_foot","l_leg","r_leg","l_arm","r_arm","chest","groin")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ taj_paw_socks
+ name = "Socks Coloration (Tajara)"
+ icon_state = "taj_pawsocks"
+ body_parts = list("l_foot","r_foot","l_leg","r_leg","l_arm","r_arm","l_hand","r_hand")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ una_paw_socks
+ name = "Socks Coloration (Unathi)"
+ icon_state = "una_pawsocks"
+ body_parts = list("l_foot","r_foot","l_leg","r_leg","l_arm","r_arm","l_hand","r_hand")
+ species_allowed = list("Unathi")
+
+ paw_socks
+ name = "Socks Coloration (Generic)"
+ icon_state = "pawsocks"
+ body_parts = list("l_foot","r_foot","l_leg","r_leg","l_arm","r_arm","l_hand","r_hand")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara", "Unathi")
+
+ paw_socks_belly
+ name = "Socks,Belly Coloration (Generic)"
+ icon_state = "pawsocksbelly"
+ body_parts = list("l_foot","r_foot","l_leg","r_leg","l_arm","r_arm","l_hand","r_hand","groin","chest")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara", "Unathi")
+
+ belly_hands_feet
+ name = "Hands,Feet,Belly Color (Minor)"
+ icon_state = "bellyhandsfeetsmall"
+ body_parts = list("l_foot","r_foot","l_leg","r_leg","l_arm","r_arm","l_hand","r_hand","groin","chest")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara", "Unathi")
+
+ hands_feet_belly_full
+ name = "Hands,Feet,Belly Color (Major)"
+ icon_state = "bellyhandsfeet"
+ body_parts = list("l_foot","r_foot","l_leg","r_leg","l_arm","r_arm","l_hand","r_hand","groin","chest")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara", "Unathi")
+
+ patches
+ name = "Color Patches"
+ icon_state = "patches"
+ body_parts = list("l_foot","r_foot","l_leg","r_leg","l_arm","r_arm","l_hand","r_hand","chest","groin")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ patchesface
+ name = "Color Patches (Face)"
+ icon_state = "patchesface"
+ body_parts = list("head")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ tigerhead
+ name = "Tiger Stripes (Head, Minor)"
+ icon_state = "tigerhead"
+ body_parts = list("head")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ tigerface
+ name = "Tiger Stripes (Head, Major)"
+ icon_state = "tigerface"
+ body_parts = list("head")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ backstripe
+ name = "Back Stripe"
+ icon_state = "backstripe"
+ body_parts = list("chest")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara", "Unathi")
+
+ taj_nose
+ name = "Nose Color"
+ icon_state = "taj_nose"
+ body_parts = list("head")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ taj_muzzle
+ name = "Muzzle Color"
+ icon_state = "taj_muzzle"
+ body_parts = list("head")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ taj_face
+ name = "Cheeks Color"
+ icon_state = "taj_face"
+ body_parts = list("head")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ taj_all
+ name = "All Tajara Head"
+ icon_state = "taj_all"
+ body_parts = list("head")
+ species_allowed = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara")
+
+ una_face
+ name = "Face Color"
+ icon_state = "una_face"
+ body_parts = list("head")
+ species_allowed = list("Unathi")
+
+ una_facelow
+ name = "Face Color Low"
+ icon_state = "una_facelow"
+ body_parts = list("head")
+ species_allowed = list("Unathi")
+
+ una_scutes
+ name = "Scutes"
+ icon_state = "una_scutes"
+ body_parts = list("chest")
+ species_allowed = list("Unathi")
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index 2fc97926547..de404b15d6f 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -58,6 +58,7 @@
var/can_stand
var/body_hair
var/painted = 0
+ var/list/markings = list() // Markings (body_markings) to apply to the icon
/obj/item/organ/external/Destroy()
if(parent && parent.children)
diff --git a/code/modules/organs/organ_icon.dm b/code/modules/organs/organ_icon.dm
index 8812db6fb9d..d9d64244a27 100644
--- a/code/modules/organs/organ_icon.dm
+++ b/code/modules/organs/organ_icon.dm
@@ -8,7 +8,7 @@
if(organ.children && organ.children.len)
for(var/obj/item/organ/external/child in organ.children)
add_overlay(child.mob_icon)
-
+
overlays |= organ.mob_icon
/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/human)
@@ -39,13 +39,13 @@
/obj/item/organ/external/head/sync_colour_to_human(var/mob/living/carbon/human/human)
..()
- var/obj/item/organ/eyes/eyes
+ var/obj/item/organ/eyes/eyes
if (species.vision_organ)
eyes = owner.internal_organs_by_name[species.vision_organ]
else
eyes = owner.internal_organs_by_name["eyes"]
- if(eyes)
+ if(eyes)
eyes.update_colour()
/obj/item/organ/external/head/removed()
@@ -73,6 +73,13 @@
overlays |= lip_icon
mob_icon.Blend(lip_icon, ICON_OVERLAY)
+ for(var/M in markings)
+ var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"]
+ var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[limb_name]")
+ mark_s.Blend(markings[M]["color"], ICON_ADD)
+ overlays |= mark_s //So when it's not on your body, it has icons
+ mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons
+
if(owner.f_style)
var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[owner.f_style]
if(facial_hair_style && facial_hair_style.species_allowed && (species.get_bodytype() in facial_hair_style.species_allowed))
@@ -137,6 +144,14 @@
else if(s_col && s_col.len >= 3)
mob_icon.Blend(rgb(s_col[1], s_col[2], s_col[3]), ICON_ADD)
+ //Body markings, does not include head, duplicated (sadly) above.
+ for(var/M in markings)
+ var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"]
+ var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[limb_name]")
+ mark_s.Blend(markings[M]["color"], ICON_ADD)
+ overlays |= mark_s //So when it's not on your body, it has icons
+ mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons
+
if(body_hair && islist(h_col) && h_col.len >= 3)
var/list/limb_icon_cache = SSicon_cache.limb_icon_cache
var/cache_key = "[body_hair]-[icon_name]-[h_col[1]][h_col[2]][h_col[3]]"
diff --git a/html/changelogs/alberky-PR-2607.yml b/html/changelogs/alberky-PR-2607.yml
new file mode 100644
index 00000000000..12991ab8ef7
--- /dev/null
+++ b/html/changelogs/alberky-PR-2607.yml
@@ -0,0 +1,6 @@
+author: Alberyk
+
+delete-after: True
+
+changes:
+ - rscadd: "Added a body marking system, ported from Polaris."
diff --git a/icons/mob/human_races/markings.dmi b/icons/mob/human_races/markings.dmi
new file mode 100644
index 00000000000..677b63d85c3
Binary files /dev/null and b/icons/mob/human_races/markings.dmi differ