diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 28a824d3576..83849c86068 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -330,6 +330,31 @@ var/list/bloody_footprints_cache = list() #define GHOST_ORBIT_SQUARE "square" #define GHOST_ORBIT_PENTAGON "pentagon" +//Ghost showing preferences: +#define GHOST_ACCS_NONE 1 +#define GHOST_ACCS_DIR 50 +#define GHOST_ACCS_FULL 100 + +#define GHOST_ACCS_NONE_NAME "default sprites" +#define GHOST_ACCS_DIR_NAME "only directional sprites" +#define GHOST_ACCS_FULL_NAME "full accessories" + +#define GHOST_ACCS_DEFAULT_OPTION GHOST_ACCS_FULL + +var/global/list/ghost_accs_options = list(GHOST_ACCS_NONE, GHOST_ACCS_DIR, GHOST_ACCS_FULL) //So save files can be sanitized properly. + +#define GHOST_OTHERS_SIMPLE 1 +#define GHOST_OTHERS_DEFAULT_SPRITE 50 +#define GHOST_OTHERS_THEIR_SETTING 100 + +#define GHOST_OTHERS_SIMPLE_NAME "white ghost" +#define GHOST_OTHERS_DEFAULT_SPRITE_NAME "default sprites" +#define GHOST_OTHERS_THEIR_SETTING_NAME "their setting" + +#define GHOST_OTHERS_DEFAULT_OPTION GHOST_OTHERS_THEIR_SETTING + +var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DEFAULT_SPRITE, GHOST_OTHERS_THEIR_SETTING) //Same as ghost_accs_options. + //Bloodcrawling #define BLOODCRAWL 1 #define BLOODCRAWL_EAT 2 diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 6c968640473..5116c62e83e 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -28,6 +28,10 @@ var/global/list/ears_list = list() var/global/list/frills_list = list() var/global/list/spines_list = list() var/global/list/animated_spines_list = list() + +var/global/list/ghost_forms_with_directions_list = list("ghost") //stores the ghost forms that support directional sprites +var/global/list/ghost_forms_with_accessories_list = list("ghost") //stores the ghost forms that support hair and other such things + //Backpacks #define GBACKPACK "Grey Backpack" #define GSATCHEL "Grey Satchel" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index efcaa9bbbb6..52fece2c3e8 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -34,6 +34,8 @@ var/list/preferences_datums = list() var/chat_toggles = TOGGLES_DEFAULT_CHAT var/ghost_form = "ghost" var/ghost_orbit = GHOST_ORBIT_CIRCLE + var/ghost_accs = GHOST_ACCS_DEFAULT_OPTION + var/ghost_others = GHOST_OTHERS_DEFAULT_OPTION var/ghost_hud = 1 var/inquisitive_ghost = 1 var/allow_midround_antag = 1 @@ -357,6 +359,27 @@ var/list/preferences_datums = list() dat += "Ghost Form: [ghost_form]
" dat += "Ghost Orbit: [ghost_orbit]
" + var/button_name = "If you see this something went wrong." + switch(ghost_accs) + if(GHOST_ACCS_FULL) + button_name = GHOST_ACCS_FULL_NAME + if(GHOST_ACCS_DIR) + button_name = GHOST_ACCS_DIR_NAME + if(GHOST_ACCS_NONE) + button_name = GHOST_ACCS_NONE_NAME + + dat += "Ghost Accessories: [button_name]
" + + switch(ghost_others) + if(GHOST_OTHERS_THEIR_SETTING) + button_name = GHOST_OTHERS_THEIR_SETTING_NAME + if(GHOST_OTHERS_DEFAULT_SPRITE) + button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME + if(GHOST_OTHERS_SIMPLE) + button_name = GHOST_OTHERS_SIMPLE_NAME + + dat += "Ghosts of Others: [button_name]
" + if (SERVERTOOLS && config.maprotation) var/p_map = preferred_map if (!p_map) @@ -752,6 +775,26 @@ var/list/preferences_datums = list() if(new_orbit) ghost_orbit = new_orbit + if("ghostaccs") + var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,GHOST_ACCS_FULL_NAME, GHOST_ACCS_DIR_NAME, GHOST_ACCS_NONE_NAME) + switch(new_ghost_accs) + if(GHOST_ACCS_FULL_NAME) + ghost_accs = GHOST_ACCS_FULL + if(GHOST_ACCS_DIR_NAME) + ghost_accs = GHOST_ACCS_DIR + if(GHOST_ACCS_NONE_NAME) + ghost_accs = GHOST_ACCS_NONE + + if("ghostothers") + var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,GHOST_OTHERS_THEIR_SETTING_NAME, GHOST_OTHERS_DEFAULT_SPRITE_NAME, GHOST_OTHERS_SIMPLE_NAME) + switch(new_ghost_others) + if(GHOST_OTHERS_THEIR_SETTING_NAME) + ghost_others = GHOST_OTHERS_THEIR_SETTING + if(GHOST_OTHERS_DEFAULT_SPRITE_NAME) + ghost_others = GHOST_OTHERS_DEFAULT_SPRITE + if(GHOST_OTHERS_SIMPLE_NAME) + ghost_others = GHOST_OTHERS_SIMPLE + if("name") var/new_name = reject_bad_name( input(user, "Choose your character's name:", "Character Preference") as text|null ) if(new_name) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 2c33814b78a..1ebfd9ecf5b 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -2,7 +2,7 @@ #define SAVEFILE_VERSION_MIN 8 //This is the current version, anything below this will attempt to update (if it's not obsolete) -#define SAVEFILE_VERSION_MAX 13 +#define SAVEFILE_VERSION_MAX 14 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn This proc checks if the current directory of the savefile S needs updating @@ -218,6 +218,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["toggles"] >> toggles S["ghost_form"] >> ghost_form S["ghost_orbit"] >> ghost_orbit + S["ghost_accs"] >> ghost_accs + S["ghost_others"] >> ghost_others S["preferred_map"] >> preferred_map S["ignoring"] >> ignoring S["ghost_hud"] >> ghost_hud @@ -239,6 +241,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) ghost_form = sanitize_inlist(ghost_form, ghost_forms, initial(ghost_form)) ghost_orbit = sanitize_inlist(ghost_orbit, ghost_orbits, initial(ghost_orbit)) + ghost_accs = sanitize_inlist(ghost_accs, ghost_accs_options, GHOST_ACCS_DEFAULT_OPTION) + ghost_others = sanitize_inlist(ghost_others, ghost_others_options, GHOST_OTHERS_DEFAULT_OPTION) return 1 @@ -265,6 +269,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["chat_toggles"] << chat_toggles S["ghost_form"] << ghost_form S["ghost_orbit"] << ghost_orbit + S["ghost_accs"] << ghost_accs + S["ghost_others"] << ghost_others S["preferred_map"] << preferred_map S["ignoring"] << ignoring S["ghost_hud"] << ghost_hud diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index 7bc1302fa19..0892ba85a1a 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -212,26 +212,23 @@ var/global/list/ghost_forms = list("ghost","ghostking","ghostian2","skeleghost", "ghost_cyan","ghost_dblue","ghost_dred","ghost_dgreen", \ "ghost_dcyan","ghost_grey","ghost_dyellow","ghost_dpink", "ghost_purpleswirl","ghost_funkypurp","ghost_pinksherbert","ghost_blazeit",\ "ghost_mellow","ghost_rainbow","ghost_camo","ghost_fire") -/client/verb/pick_form() - set name = "Choose Ghost Form" - set category = "Preferences" - set desc = "Choose your preferred ghostly appearance." +/client/proc/pick_form() if(!is_content_unlocked()) + alert("This setting is for accounts with BYOND premium only.") return var/new_form = input(src, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in ghost_forms if(new_form) prefs.ghost_form = new_form prefs.save_preferences() if(istype(mob,/mob/dead/observer)) - mob.icon_state = new_form + var/mob/dead/observer/O = mob + O.update_icon(new_form) var/global/list/ghost_orbits = list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOST_ORBIT_SQUARE,GHOST_ORBIT_HEXAGON,GHOST_ORBIT_PENTAGON) -/client/verb/pick_ghost_orbit() - set name = "Choose Ghost Orbit" - set category = "Preferences" - set desc = "Choose your preferred ghostly orbit." +/client/proc/pick_ghost_orbit() if(!is_content_unlocked()) + alert("This setting is for accounts with BYOND premium only.") return var/new_orbit = input(src, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND",null) as null|anything in ghost_orbits if(new_orbit) @@ -241,6 +238,50 @@ var/global/list/ghost_orbits = list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS var/mob/dead/observer/O = mob O.ghost_orbit = new_orbit +/client/proc/pick_ghost_accs() + var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,"full accessories", "only directional sprites", "default sprites") + switch(new_ghost_accs) + if("full accessories") + prefs.ghost_accs = GHOST_ACCS_FULL + if("only directional sprites") + prefs.ghost_accs = GHOST_ACCS_DIR + if("default sprites") + prefs.ghost_accs = GHOST_ACCS_NONE + if(istype(mob, /mob/dead/observer)) + var/mob/dead/observer/O = mob + O.update_icon() + +/client/verb/pick_ghost_customization() + set name = "Ghost Customization" + set category = "Preferences" + set desc = "Customize your ghastly appearance." + if(is_content_unlocked()) + switch(alert("Which setting do you want to change?",,"Ghost Form","Ghost Orbit","Ghost Accessories")) + if("Ghost Form") + pick_form() + if("Ghost Orbit") + pick_ghost_orbit() + if("Ghost Accessories") + pick_ghost_accs() + else + pick_ghost_accs() + +/client/verb/pick_ghost_others() + set name = "Ghost Display Settings" + set category = "Preferences" + set desc = "Change display settings for the ghosts of other players." + var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,"Their Setting", "Default Sprites", "White Ghost") + switch(new_ghost_others) + if("Their Setting") + prefs.ghost_others = GHOST_OTHERS_THEIR_SETTING + if("Default Sprites") + prefs.ghost_others = GHOST_OTHERS_DEFAULT_SPRITE + if("White Ghost") + prefs.ghost_others = GHOST_OTHERS_SIMPLE + if(istype(mob, /mob/dead/observer)) + var/mob/dead/observer/O = mob + O.updateghostsight() + /client/verb/toggle_intent_style() set name = "Toggle Intent Selection Style" set category = "Preferences" diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index db43b633b86..bd9bd81d748 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -1,13 +1,16 @@ /mob/dead/observer/Login() ..() + ghost_accs = client.prefs.ghost_accs + ghost_others = client.prefs.ghost_others + var/preferred_form = null + if(check_rights(R_ADMIN, 0)) has_unlimited_silicon_privilege = 1 if(client.prefs.unlock_content) - icon_state = client.prefs.ghost_form - if (ghostimage) - ghostimage.icon_state = src.icon_state + preferred_form = client.prefs.ghost_form ghost_orbit = client.prefs.ghost_orbit + update_icon(preferred_form) updateghostimages() diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index c55fc9840a2..7f89e56f794 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -1,4 +1,7 @@ -var/list/image/ghost_darkness_images = list() //this is a list of images for things ghosts should still be able to see when they toggle darkness +var/list/image/ghost_darkness_images = list() //this is a list of images for things ghosts should still be able to see when they toggle darkness, BUT NOT THE GHOSTS THEMSELVES! +var/list/image/ghost_images_full = list() //this is a list of full images of the ghosts themselves +var/list/image/ghost_images_default = list() //this is a list of the default (non-accessorized, non-dir) images of the ghosts themselves +var/list/image/ghost_images_simple = list() //this is a list of all ghost images as the simple white ghost /mob/dead/observer name = "ghost" desc = "It's a g-g-g-g-ghooooost!" //jinkies! @@ -23,18 +26,44 @@ var/list/image/ghost_darkness_images = list() //this is a list of images for thi var/atom/movable/following = null var/fun_verbs = 0 var/image/ghostimage = null //this mobs ghost image, for deleting and stuff + var/image/ghostimage_default = null //this mobs ghost image without accessories and dirs + var/image/ghostimage_simple = null //this mob with the simple white ghost sprite var/ghostvision = 1 //is the ghost able to see things humans can't? var/seedarkness = 1 var/ghost_hud_enabled = 1 //did this ghost disable the on-screen HUD? var/data_hud_seen = 0 //this should one of the defines in __DEFINES/hud.dm var/ghost_orbit = GHOST_ORBIT_CIRCLE + //These variables store hair data if the ghost originates from a species with head and/or facial hair. + var/hair_style + var/hair_color + var/image/hair_image + var/facial_hair_style + var/facial_hair_color + var/image/facial_hair_image + + var/updatedir = 1 //Do we have to update our dir as the ghost moves around? + var/lastsetting = null //Stores the last setting that ghost_others was set to, for a little more efficiency when we update ghost images. Null means no update is necessary + + //We store copies of the ghost display preferences locally so they can be referred to even if no client is connected. + //If there's a bug with changing your ghost settings, it's probably related to this. + var/ghost_accs = GHOST_ACCS_DEFAULT_OPTION + var/ghost_others = GHOST_OTHERS_DEFAULT_OPTION + /mob/dead/observer/New(mob/body) verbs += /mob/dead/observer/proc/dead_tele ghostimage = image(src.icon,src,src.icon_state) - ghost_darkness_images |= ghostimage + if(icon_state in ghost_forms_with_directions_list) + ghostimage_default = image(src.icon,src,src.icon_state + "_nodir") + else + ghostimage_default = image(src.icon,src,src.icon_state) + ghostimage_simple = image(src.icon,src,"ghost_nodir") + ghost_images_full |= ghostimage + ghost_images_default |= ghostimage_default + ghost_images_simple |= ghostimage_simple updateallghostimages() + var/turf/T if(ismob(body)) T = get_turf(body) //Where is the body located? @@ -50,6 +79,16 @@ var/list/image/ghost_darkness_images = list() //this is a list of images for thi name = random_unique_name(gender) mind = body.mind //we don't transfer the mind but we keep a reference to it. + if(ishuman(body)) + var/mob/living/carbon/human/body_human = body + if(HAIR in body_human.dna.species.specflags) + hair_style = body_human.hair_style + hair_color = brighten_color(body_human.hair_color) + if(FACEHAIR in body_human.dna.species.specflags) + facial_hair_style = body_human.facial_hair_style + facial_hair_color = brighten_color(body_human.facial_hair_color) + + update_icon() if(!T) T = pick(latejoin) //Safety in case we cannot find the body's position @@ -77,6 +116,98 @@ var/list/image/ghost_darkness_images = list() //this is a list of images for thi /mob/dead/CanPass(atom/movable/mover, turf/target, height=0) return 1 + +/* + * This proc will update the icon of the ghost itself, with hair overlays, as well as the ghost image. + * Please call update_icon(icon_state) from now on when you want to update the icon_state of the ghost, + * or you might end up with hair on a sprite that's not supposed to get it. + * Hair will always update its dir, so if your sprite has no dirs the haircut will go all over the place. + * |- Ricotez + */ +/mob/dead/observer/proc/update_icon(new_form) + if(client) //We update our preferences in case they changed right before update_icon was called. + ghost_accs = client.prefs.ghost_accs + ghost_others = client.prefs.ghost_others + + if(hair_image) + overlays -= hair_image + ghostimage.overlays -= hair_image + hair_image = null + + if(facial_hair_image) + overlays -= facial_hair_image + ghostimage.overlays -= facial_hair_image + facial_hair_image = null + + + if(new_form) + icon_state = new_form + if(icon_state in ghost_forms_with_directions_list) + ghostimage_default.icon_state = new_form + "_nodir" //if this icon has dirs, the default ghostimage must use its nodir version or clients with the preference set to default sprites only will see the dirs + else + ghostimage_default.icon_state = new_form + + if(ghost_accs >= GHOST_ACCS_DIR && icon_state in ghost_forms_with_directions_list) //if this icon has dirs AND the client wants to show them, we make sure we update the dir on movement + updatedir = 1 + else + updatedir = 0 //stop updating the dir in case we want to show accessories with dirs on a ghost sprite without dirs + dir = 2 //reset the dir to its default so the sprites all properly align up + + if(ghost_accs == GHOST_ACCS_FULL && icon_state in ghost_forms_with_accessories_list) //check if this form supports accessories and if the client wants to show them + var/datum/sprite_accessory/S + if(facial_hair_style) + S = facial_hair_styles_list[facial_hair_style] + if(S) + facial_hair_image = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) + if(facial_hair_color) + facial_hair_image.color = "#" + facial_hair_color + facial_hair_image.alpha = 200 + overlays += facial_hair_image + ghostimage.overlays += facial_hair_image + if(hair_style) + S = hair_styles_list[hair_style] + if(S) + hair_image = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) + if(hair_color) + hair_image.color = "#" + hair_color + hair_image.alpha = 200 + overlays += hair_image + ghostimage.overlays += hair_image + +/* + * Increase the brightness of a color by calculating the average distance between the R, G and B values, + * and maximum brightness, then adding 30% of that average to R, G and B. + * + * I'll make this proc global and move it to its own file in a future update. |- Ricotez + */ +/mob/proc/brighten_color(input_color) + var/r_val + var/b_val + var/g_val + var/color_format = lentext(input_color) + if(color_format == 3) + r_val = hex2num(copytext(input_color, 1, 2))*16 + g_val = hex2num(copytext(input_color, 2, 3))*16 + b_val = hex2num(copytext(input_color, 3, 0))*16 + else if(color_format == 6) + r_val = hex2num(copytext(input_color, 1, 3)) + g_val = hex2num(copytext(input_color, 3, 5)) + b_val = hex2num(copytext(input_color, 5, 0)) + else + return 0 //If the color format is not 3 or 6, you're using an unexpected way to represent a color. + + r_val += (255 - r_val) * 0.4 + if(r_val > 255) + r_val = 255 + g_val += (255 - g_val) * 0.4 + if(g_val > 255) + g_val = 255 + b_val += (255 - b_val) * 0.4 + if(b_val > 255) + b_val = 255 + + return num2hex(r_val, 2) + num2hex(g_val, 2) + num2hex(b_val, 2) + /* Transfer_mind is there to check if mob is being deleted/not going to have a body. Works together with spawning an observer, noted above. @@ -112,6 +243,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/Move(NewLoc, direct) + if(updatedir) + dir = direct //only update dir if we actually need it, so overlays won't spin on base sprites that don't have directions of their own if(NewLoc) loc = NewLoc for(var/obj/effect/step_trigger/S in NewLoc) @@ -239,6 +372,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp orbit(target,orbitsize, FALSE, 20, rot_seg) /mob/dead/observer/orbit() + dir = 2 //reset dir so the right directional sprites show up ..() //restart our floating animation after orbit is done. sleep 2 //orbit sets up a 2ds animation when it finishes, so we wait for that to end @@ -310,12 +444,16 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp updateghostsight() /mob/dead/observer/proc/updateghostsight() - if (!seedarkness) - see_invisible = SEE_INVISIBLE_NOLIGHTING - else + if(client) + ghost_others = client.prefs.ghost_others //A quick update just in case this setting was changed right before calling the proc + + if (seedarkness) see_invisible = SEE_INVISIBLE_OBSERVER - if (!ghostvision) + if (!ghostvision || ghost_others <= GHOST_OTHERS_DEFAULT_SPRITE) see_invisible = SEE_INVISIBLE_LIVING + else + see_invisible = SEE_INVISIBLE_NOLIGHTING + updateghostimages() /proc/updateallghostimages() @@ -325,13 +463,37 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/proc/updateghostimages() if (!client) return - if (seedarkness || !ghostvision) + + if(lastsetting) + switch(lastsetting) //checks the setting we last came from, for a little efficiency so we don't try to delete images from the client that it doesn't have anyway + if(GHOST_OTHERS_THEIR_SETTING) + client.images -= ghost_images_full + if(GHOST_OTHERS_DEFAULT_SPRITE) + client.images -= ghost_images_default + if(GHOST_OTHERS_SIMPLE) + client.images -= ghost_images_simple + + if ((seedarkness || !ghostvision) && client.prefs.ghost_others == GHOST_OTHERS_THEIR_SETTING) client.images -= ghost_darkness_images - else + lastsetting = null + else if(ghostvision && (!seedarkness || client.prefs.ghost_others <= GHOST_OTHERS_DEFAULT_SPRITE)) //add images for the 60inv things ghosts can normally see when darkness is enabled so they can see them now - client.images |= ghost_darkness_images - if (ghostimage) - client.images -= ghostimage //remove ourself + if(!lastsetting) + client.images |= ghost_darkness_images + switch(client.prefs.ghost_others) + if(GHOST_OTHERS_THEIR_SETTING) + client.images |= ghost_images_full + if (ghostimage) + client.images -= ghostimage //remove ourself + if(GHOST_OTHERS_DEFAULT_SPRITE) + client.images |= ghost_images_default + if(ghostimage_default) + client.images -= ghostimage_default + if(GHOST_OTHERS_SIMPLE) + client.images |= ghost_images_simple + if(ghostimage_simple) + client.images -= ghostimage_simple + lastsetting = client.prefs.ghost_others /mob/dead/observer/verb/possess() set category = "Ghost" diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 55d3ee7370d..5ca261d34b0 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -131,9 +131,16 @@ client.prefs.real_name = random_unique_name(gender) if(client.prefs.be_random_body) client.prefs.random_character(gender) + if(HAIR in client.prefs.pref_species.specflags) + observer.hair_style = client.prefs.hair_style + observer.hair_color = observer.brighten_color(client.prefs.hair_color) + if(FACEHAIR in client.prefs.pref_species.specflags) + observer.facial_hair_style = client.prefs.facial_hair_style + observer.facial_hair_color = observer.brighten_color(client.prefs.facial_hair_color) observer.real_name = client.prefs.real_name observer.name = observer.real_name observer.key = key + observer.update_icon() observer.stopLobbySound() qdel(mind) diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index c3a70d8615f..3a74a701ed0 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ