Files
CHOMPStation2/code/modules/tgui/modules/appearance_changer.dm
CHOMPStation2StaffMirrorBot a0c273ce1f [MIRROR] Changing changeling (Refactor) (#11142)
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
2025-07-05 04:54:55 +02:00

1151 lines
49 KiB
Plaintext

// *******************************************************
// Unified body transformation UI for inround TF or bodyrecord editing.
// Make a new subtype of this, and configure it for whatever changes
// that you will be allowing on the objects. This is a tgui UI and can
// be attached to any object.
//
// USE THIS instead of recoding tf/appearance editing for the forth time
// in this codebase. It should all be in one place, and extended for every
// new feature added to cosmetics. Be sure to update bodyrecords and their
// cloning/to/from mob procs as well.
//
// owner is the mob being transformed, ui.user is the mob using the interface
// if owner and user are the same, there is some special logic for self-tf.
// use can_change(owner, APPEARANCE_X) to validate if the owner is still in a
// valid state for the module to edit them.
// *******************************************************
/datum/tgui_module/appearance_changer
name = "Appearance Editor"
tgui_id = "AppearanceChanger"
var/flags = APPEARANCE_ALL_HAIR
var/mob/living/carbon/human/owner = null
var/list/valid_species = list()
var/list/valid_hairstyles = list()
var/list/valid_facial_hairstyles = list()
var/check_whitelist
var/list/whitelist
var/list/blacklist
var/customize_usr = FALSE
// Stuff needed to render the map
var/map_name
var/obj/screen/map_view/cam_screen
var/list/cam_plane_masters
var/obj/screen/background/cam_background
var/obj/screen/skybox/local_skybox
// Stuff for moving cameras
var/turf/last_camera_turf
var/list/valid_earstyles = list()
var/list/valid_tailstyles = list()
var/list/valid_wingstyles = list()
var/list/valid_gradstyles = list()
var/list/markings = null
var/cooldown //Anti-spam. If spammed, this can be REALLY laggy.
/datum/tgui_module/appearance_changer/New(
host,
mob/living/carbon/human/H,
check_species_whitelist = 1,
list/species_whitelist = list(),
list/species_blacklist = list())
. = ..()
map_name = "appearance_changer_[REF(src)]_map"
// Initialize map objects
cam_screen = new
cam_screen.name = "screen"
cam_screen.assigned_map = map_name
cam_screen.del_on_map_removal = FALSE
cam_screen.screen_loc = "[map_name]:3:-32,3:-48"
cam_plane_masters = get_tgui_plane_masters()
for(var/obj/screen/instance as anything in cam_plane_masters)
instance.assigned_map = map_name
instance.del_on_map_removal = FALSE
instance.screen_loc = "[map_name]:CENTER"
local_skybox = new()
local_skybox.assigned_map = map_name
local_skybox.del_on_map_removal = FALSE
local_skybox.screen_loc = "[map_name]:CENTER,CENTER"
cam_plane_masters += local_skybox
owner = H
cam_background = new
cam_background.assigned_map = map_name
cam_background.del_on_map_removal = FALSE
check_whitelist = check_species_whitelist
whitelist = species_whitelist
blacklist = species_blacklist
/datum/tgui_module/appearance_changer/proc/jiggle_map()
// Fix for weird byond bug, jiggles the map around a little
sleep(0.1 SECONDS)
cam_screen.screen_loc = "[map_name]:1,1"
sleep(0.1 SECONDS)
cam_screen.screen_loc = "[map_name]:3:-32,3:-48" // Align for larger icons and scales
/datum/tgui_module/appearance_changer/tgui_close(mob/user)
. = ..()
if(owner == user || !customize_usr)
close_ui()
UnregisterSignal(owner, COMSIG_OBSERVER_MOVED)
SEND_SIGNAL(owner, COMSIG_HUMAN_DNA_FINALIZED) // Update any components using our saved appearance
owner = null
last_camera_turf = null
cut_data()
/datum/tgui_module/appearance_changer/Destroy()
qdel(cam_screen)
QDEL_LIST(cam_plane_masters)
qdel(cam_background)
return ..()
/datum/tgui_module/appearance_changer/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return TRUE
if(cooldown > world.time)
to_chat(ui.user, span_warning("You are changing appearance too fast!"))
return FALSE
else
cooldown = world.time + 0.5 SECONDS
var/obj/machinery/computer/transhuman/designer/DC = null
var/datum/tgui_module/appearance_changer/body_designer/BD = null
if(istype(src,/datum/tgui_module/appearance_changer/body_designer))
BD = src
DC = BD.linked_body_design_console?.resolve()
switch(action)
if("race")
if(can_change(owner, APPEARANCE_RACE) && (params["race"] in valid_species))
if(owner.change_species(params["race"]))
if(params["race"] == "Custom Species")
owner.custom_species = sanitize(tgui_input_text(ui.user, "Input custom species name:",
"Custom Species Name", null, MAX_NAME_LEN), MAX_NAME_LEN)
cut_data()
generate_data(ui.user, owner)
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
return 1
if("gender")
if(can_change(owner, APPEARANCE_GENDER) && (params["gender"] in get_genders(owner)))
if(owner.change_gender(params["gender"]))
cut_data()
generate_data(ui.user, owner)
changed_hook(APPEARANCECHANGER_CHANGED_GENDER)
return 1
if("gender_id")
if(can_change(owner, APPEARANCE_GENDER) && (params["gender_id"] in all_genders_define_list))
owner.identifying_gender = params["gender_id"]
changed_hook(APPEARANCECHANGER_CHANGED_GENDER_ID)
return 1
if("skin_tone")
if(can_change_skin_tone(owner))
var/new_s_tone = tgui_input_number(ui.user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Skin Tone", -owner.s_tone + 35, 220, 1)
if(isnum(new_s_tone) && can_still_topic(ui.user, state))
new_s_tone = 35 - max(min( round(new_s_tone), 220),1)
changed_hook(APPEARANCECHANGER_CHANGED_SKINTONE)
return owner.change_skin_tone(new_s_tone)
if("skin_color")
if(can_change_skin_color(owner))
var/new_skin = tgui_color_picker(ui.user, "Choose your character's skin colour: ", "Skin Color", rgb(owner.r_skin, owner.g_skin, owner.b_skin))
if(new_skin && can_still_topic(ui.user, state))
var/r_skin = hex2num(copytext(new_skin, 2, 4))
var/g_skin = hex2num(copytext(new_skin, 4, 6))
var/b_skin = hex2num(copytext(new_skin, 6, 8))
if(owner.change_skin_color(r_skin, g_skin, b_skin))
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_SKINCOLOR)
return 1
if("hair")
if(can_change(owner, APPEARANCE_HAIR) && (params["name"] in valid_hairstyles))
if(owner.change_hair(params["name"]))
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE)
return 1
if("hair_grad")
var/picked = params["picked"]
if(picked && can_change(owner, APPEARANCE_HAIR_COLOR))
owner.grad_style = picked[1] // returned as a list
update_dna(owner)
owner.regenerate_icons()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE)
return 1
if("hair_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = tgui_color_picker(ui.user, "Please select hair color.", "Hair Color", rgb(owner.r_hair, owner.g_hair, owner.b_hair))
if(new_hair && can_still_topic(ui.user, state))
var/r_hair = hex2num(copytext(new_hair, 2, 4))
var/g_hair = hex2num(copytext(new_hair, 4, 6))
var/b_hair = hex2num(copytext(new_hair, 6, 8))
if(owner.change_hair_color(r_hair, g_hair, b_hair))
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("hair_color_grad")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_grad = tgui_color_picker(ui.user, "Please select hair gradiant color.", "Hair Color", rgb(owner.r_grad, owner.g_grad, owner.b_grad))
if(new_grad && can_still_topic(ui.user, state))
var/r_grad = hex2num(copytext(new_grad, 2, 4))
var/g_grad = hex2num(copytext(new_grad, 4, 6))
var/b_grad = hex2num(copytext(new_grad, 6, 8))
if(owner.change_grad_color(r_grad, g_grad, b_grad))
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("facial_hair")
if(can_change(owner, APPEARANCE_FACIAL_HAIR) && (params["name"] in valid_facial_hairstyles))
if(owner.change_facial_hair(params["name"]))
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_F_HAIRSTYLE)
return 1
if("facial_hair_color")
if(can_change(owner, APPEARANCE_FACIAL_HAIR_COLOR))
var/new_facial = tgui_color_picker(ui.user, "Please select facial hair color.", "Facial Hair Color", rgb(owner.r_facial, owner.g_facial, owner.b_facial))
if(new_facial && can_still_topic(ui.user, state))
var/r_facial = hex2num(copytext(new_facial, 2, 4))
var/g_facial = hex2num(copytext(new_facial, 4, 6))
var/b_facial = hex2num(copytext(new_facial, 6, 8))
if(owner.change_facial_hair_color(r_facial, g_facial, b_facial))
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_F_HAIRCOLOR)
return 1
if("eye_color")
if(can_change(owner, APPEARANCE_EYE_COLOR))
var/new_eyes = tgui_color_picker(ui.user, "Please select eye color.", "Eye Color", rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes))
if(new_eyes && can_still_topic(ui.user, state))
var/r_eyes = hex2num(copytext(new_eyes, 2, 4))
var/g_eyes = hex2num(copytext(new_eyes, 4, 6))
var/b_eyes = hex2num(copytext(new_eyes, 6, 8))
if(owner.change_eye_color(r_eyes, g_eyes, b_eyes))
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_EYES)
return 1
if("ear")
if(can_change(owner, APPEARANCE_ALL_HAIR))
var/datum/sprite_accessory/ears/instance = locate(params["ref"])
if(params["clear"])
instance = null
if(!istype(instance) && !params["clear"])
return FALSE
owner.ear_style = instance
owner.update_hair()
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE)
return TRUE
if("ear_secondary")
if(can_change(owner, APPEARANCE_ALL_HAIR))
var/datum/sprite_accessory/ears/instance = locate(params["ref"])
if(params["clear"])
instance = null
if(!istype(instance) && !params["clear"])
return FALSE
owner.ear_secondary_style = instance
if(!islist(owner.ear_secondary_colors))
owner.ear_secondary_colors = list()
if(instance && length(owner.ear_secondary_colors) < instance.get_color_channel_count())
owner.ear_secondary_colors.len = instance.get_color_channel_count()
owner.update_hair()
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE)
return TRUE
if("ears_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = tgui_color_picker(ui.user, "Please select ear color.", "Ear Color", rgb(owner.r_ears, owner.g_ears, owner.b_ears))
if(new_hair && can_still_topic(ui.user, state))
owner.r_ears = hex2num(copytext(new_hair, 2, 4))
owner.g_ears = hex2num(copytext(new_hair, 4, 6))
owner.b_ears = hex2num(copytext(new_hair, 6, 8))
update_dna(owner)
owner.update_hair()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("ears2_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = tgui_color_picker(ui.user, "Please select secondary ear color.", "2nd Ear Color", rgb(owner.r_ears2, owner.g_ears2, owner.b_ears2))
if(new_hair && can_still_topic(ui.user, state))
owner.r_ears2 = hex2num(copytext(new_hair, 2, 4))
owner.g_ears2 = hex2num(copytext(new_hair, 4, 6))
owner.b_ears2 = hex2num(copytext(new_hair, 6, 8))
update_dna(owner)
owner.update_hair()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("ears_alpha")
var/new_alpha = clamp(params["ears_alpha"], 0, 255)
if(isnum(new_alpha) && can_still_topic(ui.user, state))
owner.a_ears = new_alpha
update_dna(owner)
owner.update_hair()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("secondary_ears_alpha")
var/new_alpha = clamp(params["secondary_ears_alpha"], 0, 255)
if(isnum(new_alpha) && can_still_topic(ui.user, state))
owner.a_ears2 = new_alpha
update_dna(owner)
owner.update_hair()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("ears_secondary_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/channel = params["channel"]
if(channel > length(owner.ear_secondary_colors))
return TRUE
var/existing = LAZYACCESS(owner.ear_secondary_colors, channel) || "#ffffff"
var/new_color = tgui_color_picker(ui.user, "Please select ear color.", "2nd Ear Color", existing)
if(new_color && can_still_topic(ui.user, state))
owner.ear_secondary_colors[channel] = new_color
update_dna(owner)
owner.update_hair()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return TRUE
if("tail")
if(can_change(owner, APPEARANCE_ALL_HAIR))
var/datum/sprite_accessory/tail/instance = locate(params["ref"])
if(params["clear"])
instance = null
if(!istype(instance) && !params["clear"])
return FALSE
owner.tail_style = instance
owner.update_tail_showing()
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE)
return TRUE
if("tail_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = tgui_color_picker(ui.user, "Please select tail color.", "Tail Color", rgb(owner.r_tail, owner.g_tail, owner.b_tail))
if(new_hair && can_still_topic(ui.user, state))
owner.r_tail = hex2num(copytext(new_hair, 2, 4))
owner.g_tail = hex2num(copytext(new_hair, 4, 6))
owner.b_tail = hex2num(copytext(new_hair, 6, 8))
update_dna(owner)
owner.update_tail_showing()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("tail2_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = tgui_color_picker(ui.user, "Please select secondary tail color.", "2nd Tail Color", rgb(owner.r_tail2, owner.g_tail2, owner.b_tail2))
if(new_hair && can_still_topic(ui.user, state))
owner.r_tail2 = hex2num(copytext(new_hair, 2, 4))
owner.g_tail2 = hex2num(copytext(new_hair, 4, 6))
owner.b_tail2 = hex2num(copytext(new_hair, 6, 8))
update_dna(owner)
owner.update_tail_showing()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("tail3_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = tgui_color_picker(ui.user, "Please select tertiary tail color.", "3rd Tail Color", rgb(owner.r_tail3, owner.g_tail3, owner.b_tail3))
if(new_hair && can_still_topic(ui.user, state))
owner.r_tail3 = hex2num(copytext(new_hair, 2, 4))
owner.g_tail3 = hex2num(copytext(new_hair, 4, 6))
owner.b_tail3 = hex2num(copytext(new_hair, 6, 8))
update_dna(owner)
owner.update_tail_showing()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("tail_alpha")
var/new_alpha = clamp(params["tail_alpha"], 0, 255)
if(isnum(new_alpha) && can_still_topic(ui.user, state))
owner.a_tail = new_alpha
update_dna(owner)
owner.update_tail_showing()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("wing")
if(can_change(owner, APPEARANCE_ALL_HAIR))
var/datum/sprite_accessory/wing/instance = locate(params["ref"])
if(params["clear"])
instance = null
if(!istype(instance) && !params["clear"])
return FALSE
owner.wing_style = instance
owner.update_wing_showing()
update_dna(owner)
changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE)
return TRUE
if("wing_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = tgui_color_picker(ui.user, "Please select wing color.", "Wing Color", rgb(owner.r_wing, owner.g_wing, owner.b_wing))
if(new_hair && can_still_topic(ui.user, state))
owner.r_wing = hex2num(copytext(new_hair, 2, 4))
owner.g_wing = hex2num(copytext(new_hair, 4, 6))
owner.b_wing = hex2num(copytext(new_hair, 6, 8))
update_dna(owner)
owner.update_wing_showing()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("wing2_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = tgui_color_picker(ui.user, "Please select secondary wing color.", "2nd Wing Color", rgb(owner.r_wing2, owner.g_wing2, owner.b_wing2))
if(new_hair && can_still_topic(ui.user, state))
owner.r_wing2 = hex2num(copytext(new_hair, 2, 4))
owner.g_wing2 = hex2num(copytext(new_hair, 4, 6))
owner.b_wing2 = hex2num(copytext(new_hair, 6, 8))
update_dna(owner)
owner.update_wing_showing()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("wing3_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = tgui_color_picker(ui.user, "Please select tertiary wing color.", "3rd Wing Color", rgb(owner.r_wing3, owner.g_wing3, owner.b_wing3))
if(new_hair && can_still_topic(ui.user, state))
owner.r_wing3 = hex2num(copytext(new_hair, 2, 4))
owner.g_wing3 = hex2num(copytext(new_hair, 4, 6))
owner.b_wing3 = hex2num(copytext(new_hair, 6, 8))
update_dna(owner)
owner.update_wing_showing()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("wing_alpha")
var/new_alpha = clamp(params["wing_alpha"], 0, 255)
if(isnum(new_alpha) && can_still_topic(ui.user, state))
owner.a_wing = new_alpha
update_dna(owner)
owner.update_wing_showing()
changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR)
return 1
if("marking")
if(can_change(owner, APPEARANCE_ALL_HAIR))
var/todo = params["todo"]
var/name_marking = params["name"]
switch (todo)
if (0) //delete
if (name_marking)
var/datum/sprite_accessory/marking/mark_datum = body_marking_styles_list[name_marking]
if (owner.remove_marking(mark_datum))
changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE)
return TRUE
if (1) //add
if(name_marking && can_still_topic(ui.user, state))
var/datum/sprite_accessory/marking/mark_datum = body_marking_styles_list[name_marking]
if (owner.add_marking(mark_datum))
changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE)
return TRUE
if (2) //move up
var/datum/sprite_accessory/marking/mark_datum = body_marking_styles_list[name_marking]
if (owner.change_priority_of_marking(mark_datum, FALSE))
return TRUE
if (3) //move down
var/datum/sprite_accessory/marking/mark_datum = body_marking_styles_list[name_marking]
if (owner.change_priority_of_marking(mark_datum, TRUE))
return TRUE
if (4) //color
var/current = markings[name_marking] ? markings[name_marking]["color"] : "#000000"
var/marking_color = tgui_color_picker(ui.user, "Please select marking color", "Marking color", current)
if(marking_color && can_still_topic(ui.user, state))
var/datum/sprite_accessory/marking/mark_datum = body_marking_styles_list[name_marking]
if (owner.change_marking_color(mark_datum, marking_color))
return TRUE
if("rotate_view")
owner.set_dir(turn(owner.dir, 90))
return TRUE
if("rename")
if(owner)
var/raw_name = tgui_input_text(ui.user, "Choose the a name:", "Sleeve Name")
if(!isnull(raw_name) && can_change(owner, APPEARANCE_RACE))
var/new_name = sanitize_name(raw_name, owner.species, FALSE) // can't edit synths
if(new_name)
owner.dna.real_name = new_name
owner.real_name = new_name
owner.name = new_name
return TRUE
else
to_chat(ui.user, span_warning("Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ."))
return TRUE
if("char_name")
if(DC) // Only body designer does this. no hrefing
var/new_name = sanitize(tgui_input_text(ui.user, "Input character's name:", "Name", owner.name, MAX_NAME_LEN), MAX_NAME_LEN)
if(can_change(owner, APPEARANCE_RACE)) // new name can be empty, it uses base species if so
owner.name = new_name
owner.real_name = owner.name
owner.dna.real_name = owner.name
return TRUE
if("race_name")
var/new_name = sanitize(tgui_input_text(ui.user, "Input custom species name:", "Custom Species Name", owner.custom_species, MAX_NAME_LEN), MAX_NAME_LEN)
if(can_change(owner, APPEARANCE_RACE)) // new name can be empty, it uses base species if so
owner.custom_species = new_name
return TRUE
if("base_icon")
if(can_change(owner, APPEARANCE_MISC))
var/new_species = tgui_input_list(ui.user, "Please select basic shape.", "Body Shape", GLOB.custom_species_bases)
if(new_species)
owner.species.base_species = new_species
owner.species.icobase = owner.species.get_icobase()
owner.species.deform = owner.species.get_icobase(get_deform = TRUE)
owner.species.vanity_base_fit = new_species
if(istype(owner.species, /datum/species/shapeshifter)) //TODO: See if this is still needed.
wrapped_species_by_ref["\ref[owner]"] = new_species
owner.regenerate_icons()
generate_data(ui.user, owner)
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
return TRUE
if("blood_reagent") //you know, this feels REALLY odd to be able to change at will but WHATEVER, WE BALL.
if(can_change(owner, APPEARANCE_MISC))
var/new_blood_reagents = tgui_input_list(ui.user, "Please select blood restoration reagent:", "Character Preference", valid_bloodreagents)
if(new_blood_reagents)
owner.dna.blood_reagents = new_blood_reagents
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
return TRUE
if("blood_color")
var/current = owner.species.blood_color ? owner.species.blood_color : "#A10808"
var/blood_col = tgui_color_picker(ui.user, "Please select blood color", "Blood color", current)
if(blood_col && can_change(owner, APPEARANCE_MISC))
owner.dna.blood_color = blood_col
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
return TRUE
if("weight")
var/new_weight = tgui_input_number(ui.user, "Choose tbe character's relative body weight.\n\
This measurement should be set relative to a normal 5'10'' person's body and not the actual size of the character.\n\
([WEIGHT_MIN]-[WEIGHT_MAX])", "Character Preference", null, WEIGHT_MAX, WEIGHT_MIN, round_value=FALSE)
if(new_weight && can_change(owner, APPEARANCE_MISC))
var/unit_of_measurement = tgui_alert(ui.user, "Is that number in pounds (lb) or kilograms (kg)?", "Confirmation", list("Pounds", "Kilograms"))
if(unit_of_measurement)
if(unit_of_measurement == "Pounds")
new_weight = round(text2num(new_weight),4)
if(unit_of_measurement == "Kilograms")
new_weight = round(2.20462*text2num(new_weight),4)
owner.weight = sanitize_integer(new_weight, WEIGHT_MIN, WEIGHT_MAX, owner.weight)
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
return TRUE
if("size_scale")
var/new_size = tgui_input_number(ui.user, "Choose size, ranging from [RESIZE_MINIMUM * 100]% to [RESIZE_MAXIMUM * 100]%", "Set Size", null, RESIZE_MAXIMUM * 100, RESIZE_MINIMUM * 100)
if(new_size && ISINRANGE(new_size,RESIZE_MINIMUM * 100,RESIZE_MAXIMUM * 100) && can_change(owner, APPEARANCE_MISC))
owner.size_multiplier = new_size / 100
owner.update_transform(TRUE)
owner.regenerate_icons()
owner.set_dir(owner.dir) // Causes a visual update for fuzzy/offset
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
return TRUE
if("scale_appearance")
if(can_change(owner, APPEARANCE_MISC))
owner.dna.scale_appearance = !owner.dna.scale_appearance
owner.fuzzy = owner.dna.scale_appearance
owner.regenerate_icons()
owner.set_dir(owner.dir) // Causes a visual update for fuzzy/offset
return TRUE
if("offset_override")
if(can_change(owner, APPEARANCE_MISC))
owner.dna.offset_override = !owner.dna.offset_override
owner.offset_override = owner.dna.offset_override
owner.regenerate_icons()
owner.set_dir(owner.dir) // Causes a visual update for fuzzy/offset
return TRUE
if("digitigrade")
if(can_change(owner, APPEARANCE_MISC))
owner.dna.digitigrade = !owner.dna.digitigrade
owner.digitigrade = owner.dna.digitigrade
owner.regenerate_icons()
generate_data(ui.user, owner)
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
return TRUE
if("species_sound")
var/list/possible_species_sound_types = species_sound_map
var/choice = tgui_input_list(ui.user, "Which set of sounds would you like to use? (Cough, Sneeze, Scream, Pain, Gasp, Death)", "Species Sounds", possible_species_sound_types)
if(choice && can_change(owner, APPEARANCE_MISC))
owner.species.species_sounds = choice
return TRUE
if("flavor_text")
var/select_key = params["target"]
if(select_key && can_change(owner, APPEARANCE_MISC))
if(select_key in owner.flavor_texts)
switch(select_key)
if("general")
var/msg = strip_html_simple(tgui_input_text(ui.user,"Give a general description of the character. This will be shown regardless of clothings. Put in \"!clear\" to make blank.","Flavor Text",html_decode(owner.flavor_texts[select_key]), multiline = TRUE, prevent_enter = TRUE))
if(can_change(owner, APPEARANCE_MISC)) // allows empty to wipe flavor
if(msg == "!clear")
msg = ""
owner.flavor_texts[select_key] = msg
return TRUE
else
var/msg = strip_html_simple(tgui_input_text(ui.user,"Set the flavor text for their [select_key]. Put in \"!clear\" to make blank.","Flavor Text",html_decode(owner.flavor_texts[select_key]), multiline = TRUE, prevent_enter = TRUE))
if(can_change(owner, APPEARANCE_MISC)) // allows empty to wipe flavor
if(msg == "!clear")
msg = ""
owner.flavor_texts[select_key] = msg
return TRUE
if("load_saveslot") //saveslot_load
if(can_change(owner, APPEARANCE_ALL_COSMETIC))
if(tgui_alert(owner, "Are you certain you wish to load the currently selected savefile?", "Load Savefile", list("No","Yes")) == "Yes")
if(owner && owner.client) //sanity
owner.client.prefs.vanity_copy_to(owner, FALSE, TRUE, FALSE, FALSE)
return TRUE
return TRUE
else
return TRUE
// ***********************************
// Body designer UI
// ***********************************
if("view_brec")
var/datum/transhuman/body_record/BR = locate(params["view_brec"])
if(BR && istype(BR.mydna))
if(DC.allowed(ui.user) || BR.ckey == ui.user.ckey)
BD.load_record_to_body(BR)
owner.resleeve_lock = BR.locked
owner.changeling_locked = BR.changeling_locked
DC.selected_record = TRUE
return TRUE
if("view_stock_brec")
var/datum/species/S = GLOB.all_species[params["view_stock_brec"]]
if(S && (S.spawn_flags & (SPECIES_IS_WHITELISTED|SPECIES_CAN_JOIN)) == SPECIES_CAN_JOIN)
// Generate body record from species!
owner = new(null, S.name)
owner.real_name = "Stock [S.name] Body"
owner.name = owner.real_name
owner.dna.real_name = owner.real_name
owner.dna.base_species = S.base_species
owner.resleeve_lock = FALSE
owner.custom_species = "Custom Sleeve" // Custom name
DC.selected_record = TRUE
return TRUE
if("loadfromdisk")
if(!DC.disk)
return FALSE
if(DC.disk.stored && can_change(owner, APPEARANCE_RACE))
BD.load_record_to_body(DC.disk.stored)
DC.selected_record = TRUE
to_chat(ui.user,span_notice("\The [owner]'s bodyrecord was loaded from the disk."))
return TRUE
if("savetodisk")
if(!DC.selected_record)
return FALSE
if(!DC.disk)
return FALSE
if(owner.changeling_locked)
to_chat(ui.user, span_warning("ERROR: Record too complex. Disk does not have enough space to store this record."))
else if(owner.resleeve_lock)
var/answer = tgui_alert(ui.user,"This body record will be written to a disk and allow any mind to inhabit it. This is against the current body owner's configured OOC preferences for body impersonation. Please confirm that you have permission to do this, and are sure! Admins will be notified.","Mind Compatability",list("No","Yes"))
if(!answer)
return
if(answer == "No")
to_chat(ui.user, span_warning("ERROR: This body record is restricted."))
else
message_admins("[ui.user] wrote an unlocked version of [owner.real_name]'s bodyrecord to a disk. Their preferences do not allow body impersonation, but may be allowed with OOC consent.")
owner.resleeve_lock = FALSE // unlock it, even though it's only temp, so you don't get the warning every time
if(!owner.changeling_locked && (!owner.resleeve_lock && can_change(owner, APPEARANCE_RACE)))
// Create it from the mob
if(DC.disk.stored)
qdel_null(DC.disk.stored)
to_chat(ui.user,span_notice("\The [owner]'s bodyrecord was saved to the disk."))
owner.update_dna()
DC.disk.stored = new /datum/transhuman/body_record(owner, FALSE, FALSE) // Saves a COPY!
DC.disk.stored.locked = FALSE // remove lock
DC.disk.name = "[initial(DC.disk.name)] ([owner.real_name])"
return TRUE
if("ejectdisk")
if(!DC.disk)
return FALSE
if(can_change(owner, APPEARANCE_RACE))
to_chat(ui.user,span_notice("You eject the disk."))
DC.disk.forceMove(get_turf(DC))
DC.disk = null
return TRUE
if("back_to_library")
if(can_change(owner, APPEARANCE_RACE))
BD.make_fake_owner()
DC.selected_record = FALSE
return TRUE
return FALSE
/datum/tgui_module/appearance_changer/tgui_interact(mob/user, datum/tgui/ui = null, datum/tgui/parent_ui = null, datum/tgui_state/custom_state)
if(customize_usr && !owner)
if(!ishuman(user))
return TRUE
owner = user
if(!owner || !owner.species)
return
ui = SStgui.try_update_ui(user, src, ui)
if(!owner || !owner.species) //We tried to update our UI and no longer have an owner!
return
if(!ui)
owner.AddComponent(/datum/component/recursive_move)
RegisterSignal(owner, COMSIG_OBSERVER_MOVED, PROC_REF(update_active_camera_screen), TRUE)
// Register map objects
user.client.register_map_obj(cam_screen)
for(var/plane in cam_plane_masters)
user.client.register_map_obj(plane)
user.client.register_map_obj(cam_background)
// Open UI
ui = new(user, src, tgui_id, name)
ui.open()
CallAsync(src, PROC_REF(jiggle_map))
if(custom_state)
ui.set_state(custom_state)
update_active_camera_screen()
/datum/tgui_module/appearance_changer/tgui_static_data(mob/user)
var/list/data = ..()
generate_data(user, owner)
if(can_change(owner, APPEARANCE_RACE))
var/species[0]
for(var/specimen in valid_species)
species[++species.len] = list("specimen" = specimen)
data["species"] = species
if(can_change(owner, APPEARANCE_HAIR))
var/hair_styles[0]
for(var/hair_style in valid_hairstyles)
var/datum/sprite_accessory/hair/S = hair_styles_list[hair_style]
hair_styles[++hair_styles.len] = list("name" = hair_style, "icon" = S.icon, "icon_state" = "[S.icon_state]_s")
data["hair_styles"] = hair_styles
data["ear_styles"] = valid_earstyles
data["tail_styles"] = valid_tailstyles
data["wing_styles"] = valid_wingstyles
markings = owner.get_prioritised_markings()
var/list/usable_markings = markings.Copy() ^ body_marking_styles_list.Copy()
var/marking_styles[0]
for(var/marking_style in usable_markings)
if(marking_style == DEVELOPER_WARNING_NAME)
continue
var/datum/sprite_accessory/marking/S = body_marking_styles_list[marking_style]
var/our_iconstate = S.icon_state
if(LAZYLEN(S.body_parts))
our_iconstate += "-[S.body_parts[1]]"
marking_styles[++marking_styles.len] = list("name" = marking_style, "icon" = S.icon, "icon_state" = "[our_iconstate]")
data["marking_styles"] = marking_styles
if(can_change(owner, APPEARANCE_FACIAL_HAIR))
var/facial_hair_styles[0]
for(var/facial_hair_style in valid_facial_hairstyles)
var/datum/sprite_accessory/facial_hair/S = facial_hair_styles_list[facial_hair_style]
facial_hair_styles[++facial_hair_styles.len] = list("name" = facial_hair_style, "icon" = S.icon, "icon_state" = "[S.icon_state]_s")
data["facial_hair_styles"] = facial_hair_styles
if(can_change(owner, APPEARANCE_HAIR_COLOR))
data["hair_grads"] = valid_gradstyles
return data
/datum/tgui_module/appearance_changer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
generate_data(user, owner)
data["is_design_console"] = FALSE
data["disk"] = FALSE
data["selected_a_record"] = FALSE
data["character_records"] = list()
data["stock_records"] = list()
// Handle some unique stuff to the body design console
var/obj/machinery/computer/transhuman/designer/DC = null
if(istype(src,/datum/tgui_module/appearance_changer/body_designer))
var/datum/tgui_module/appearance_changer/body_designer/BD = src
DC = BD.linked_body_design_console?.resolve()
if(DC)
data["is_design_console"] = TRUE
data["disk"] = !isnull(DC.disk)
// Monkey is a placeholder, because I am not hackcoding the appearance changer to accept a null owner - Willbird
data["selected_a_record"] = DC.selected_record
if(!DC.selected_record)
// Load all records on station that can be printed
var/list/bodyrecords_list_ui = list()
for(var/N in DC.our_db.body_scans)
var/datum/transhuman/body_record/BR = DC.our_db.body_scans[N]
var/datum/species/S = GLOB.all_species[BR.mydna.dna.species]
if((S.spawn_flags & (SPECIES_IS_WHITELISTED|SPECIES_CAN_JOIN)) != SPECIES_CAN_JOIN || BR.synthetic) continue
bodyrecords_list_ui[++bodyrecords_list_ui.len] = list("name" = N, "recref" = "\ref[BR]")
data["character_records"] = bodyrecords_list_ui
// Load all stock records printable
var/list/stock_bodyrecords_list_ui = list()
for (var/N in GLOB.all_species)
var/datum/species/S = GLOB.all_species[N]
if((S.spawn_flags & (SPECIES_IS_WHITELISTED|SPECIES_CAN_JOIN)) != SPECIES_CAN_JOIN) continue
stock_bodyrecords_list_ui += N
data["stock_records"] = stock_bodyrecords_list_ui
data["change_race"] = can_change(owner, APPEARANCE_RACE)
data["change_misc"] = can_change(owner, APPEARANCE_MISC)
data["gender_id"] = can_change(owner, APPEARANCE_GENDER)
data["change_gender"] = can_change(owner, APPEARANCE_GENDER)
data["change_hair"] = can_change(owner, APPEARANCE_HAIR)
data["change_eye_color"] = can_change(owner, APPEARANCE_EYE_COLOR)
data["change_hair_color"] = can_change(owner, APPEARANCE_HAIR_COLOR)
data["change_facial_hair_color"] = can_change(owner, APPEARANCE_FACIAL_HAIR_COLOR)
// Drop out early, as we have nothing to edit, and are on the BR menu for the designer
return data
// species/body
data["species_name"] = owner.custom_species
data["use_custom_icon"] = (owner.species.selects_bodytype >= SELECTS_BODYTYPE_CUSTOM)
data["base_icon"] = owner.species.base_species
data["synthetic"] = owner.synthetic ? "Yes" : "No"
data["size_scale"] = player_size_name(owner.size_multiplier)
data["scale_appearance"] = owner.dna.scale_appearance ? "Fuzzy" : "Sharp"
data["offset_override"] = owner.dna.offset_override ? "Odd" : "Even"
data["weight"] = owner.weight
data["digitigrade"] = owner.digitigrade
data["blood_reagent"] = owner.dna.blood_reagents
data["blood_color"] = owner.dna.blood_color
data["species_sound"] = owner.species.species_sounds
// Are these needed? It seems to be only used if above is unset??
data["species_sounds_gendered"] = owner.species.gender_specific_species_sounds
data["species_sounds_female"] = owner.species.species_sounds_female
data["species_sounds_male"] = owner.species.species_sounds_male
// flavor
if(!owner.flavor_texts.len)
owner.flavor_texts["general"] = ""
owner.flavor_texts["head"] = ""
owner.flavor_texts["face"] = ""
owner.flavor_texts["eyes"] = ""
owner.flavor_texts["torso"] = ""
owner.flavor_texts["arms"] = ""
owner.flavor_texts["hands"] = ""
owner.flavor_texts["legs"] = ""
owner.flavor_texts["feet"] = ""
data["flavor_text"] = owner.flavor_texts.Copy()
data["name"] = owner.name
data["specimen"] = owner.species.name
data["gender"] = owner.gender
data["gender_id"] = owner.identifying_gender //This is saved to your MIND.
data["change_race"] = can_change(owner, APPEARANCE_RACE)
data["saveslot_load"] = can_change(owner, APPEARANCE_ALL_COSMETIC)
data["change_misc"] = can_change(owner, APPEARANCE_MISC)
data["change_gender"] = can_change(owner, APPEARANCE_GENDER)
if(data["change_gender"])
var/genders[0]
for(var/gender in get_genders(owner))
genders[++genders.len] = list("gender_name" = gender2text(gender), "gender_key" = gender)
data["genders"] = genders
var/id_genders[0]
for(var/gender in all_genders_define_list)
id_genders[++id_genders.len] = list("gender_name" = gender2text(gender), "gender_key" = gender)
data["id_genders"] = id_genders
data["change_hair"] = can_change(owner, APPEARANCE_HAIR)
if(data["change_hair"])
data["hair_style"] = owner.h_style
data["ear_style"] = owner.ear_style
data["ear_secondary_style"] = owner.ear_secondary_style?.name
data["tail_style"] = owner.tail_style
data["wing_style"] = owner.wing_style
var/list/markings_data[0]
markings = owner.get_prioritised_markings()
for (var/marking in markings)
markings_data[++markings_data.len] = list("marking_name" = marking, "marking_color" = markings[marking]["color"] ? markings[marking]["color"] : "#000000") //too tired to add in another submenu for bodyparts here
data["markings"] = markings_data
data["change_facial_hair"] = can_change(owner, APPEARANCE_FACIAL_HAIR)
if(data["change_facial_hair"])
data["facial_hair_style"] = owner.f_style
data["change_skin_tone"] = can_change_skin_tone(owner)
data["change_skin_color"] = can_change_skin_color(owner)
if(data["change_skin_color"])
data["skin_color"] = rgb(owner.r_skin, owner.g_skin, owner.b_skin)
data["change_eye_color"] = can_change(owner, APPEARANCE_EYE_COLOR)
if(data["change_eye_color"])
data["eye_color"] = rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes)
data["change_hair_color"] = can_change(owner, APPEARANCE_HAIR_COLOR)
if(data["change_hair_color"])
data["hair_color"] = rgb(owner.r_hair, owner.g_hair, owner.b_hair)
data["hair_color_grad"] = rgb(owner.r_grad, owner.g_grad, owner.b_grad)
data["ears_color"] = rgb(owner.r_ears, owner.g_ears, owner.b_ears)
data["ears2_color"] = rgb(owner.r_ears2, owner.g_ears2, owner.b_ears2)
// not a color, but it basically is
data["hair_grad"] = owner.grad_style
// secondary ear colors
var/list/ear_secondary_color_channels = owner.ear_secondary_colors || list()
ear_secondary_color_channels.len = owner.ear_secondary_style?.get_color_channel_count() || 0
data["ear_secondary_colors"] = ear_secondary_color_channels
data["tail_color"] = rgb(owner.r_tail, owner.g_tail, owner.b_tail)
data["tail2_color"] = rgb(owner.r_tail2, owner.g_tail2, owner.b_tail2)
data["tail3_color"] = rgb(owner.r_tail3, owner.g_tail3, owner.b_tail3)
data["wing_color"] = rgb(owner.r_wing, owner.g_wing, owner.b_wing)
data["wing2_color"] = rgb(owner.r_wing2, owner.g_wing2, owner.b_wing2)
data["wing3_color"] = rgb(owner.r_wing3, owner.g_wing3, owner.b_wing3)
data["wing_alpha"] = owner.a_wing
data["tail_alpha"] = owner.a_tail
data["ears_alpha"] = owner.a_ears
data["secondary_ears_alpha"] = owner.a_ears2
data["change_facial_hair_color"] = can_change(owner, APPEARANCE_FACIAL_HAIR_COLOR)
if(data["change_facial_hair_color"])
data["facial_hair_color"] = rgb(owner.r_facial, owner.g_facial, owner.b_facial)
return data
/datum/tgui_module/appearance_changer/tgui_static_data(mob/user)
var/list/data = ..()
data["mapRef"] = map_name
return data
/datum/tgui_module/appearance_changer/proc/update_active_camera_screen()
SIGNAL_HANDLER
cam_screen.vis_contents = list(owner) // Copied from the vore version.
cam_background.icon_state = "clear"
cam_background.fill_rect(1, 1, 1, 1)
local_skybox.cut_overlays()
/datum/tgui_module/appearance_changer/proc/update_dna(mob/living/carbon/human/target)
if(target)
target.update_dna()
/datum/tgui_module/appearance_changer/proc/can_change(mob/living/carbon/human/target, var/flag)
return target && (flags & flag)
/datum/tgui_module/appearance_changer/proc/can_change_skin_tone(mob/living/carbon/human/target)
return target && (flags & APPEARANCE_SKIN) &&target.species.appearance_flags & HAS_SKIN_TONE
/datum/tgui_module/appearance_changer/proc/can_change_skin_color(mob/living/carbon/human/target)
return target && (flags & APPEARANCE_SKIN) && target.species.appearance_flags & HAS_SKIN_COLOR
/datum/tgui_module/appearance_changer/proc/cut_data()
// Making the assumption that the available species remain constant
valid_hairstyles.Cut()
valid_facial_hairstyles.Cut()
valid_earstyles.Cut()
valid_tailstyles.Cut()
valid_wingstyles.Cut()
valid_gradstyles.Cut()
/datum/tgui_module/appearance_changer/proc/generate_data(mob/user, mob/living/carbon/human/target)
if(!ishuman(target))
return TRUE
if(!LAZYLEN(valid_species))
valid_species = target.generate_valid_species(check_whitelist, whitelist, blacklist)
if(!LAZYLEN(valid_hairstyles) || !LAZYLEN(valid_facial_hairstyles))
valid_hairstyles = target.generate_valid_hairstyles(check_gender = 0)
valid_facial_hairstyles = target.generate_valid_facial_hairstyles()
if(!LAZYLEN(valid_earstyles))
for(var/path in ear_styles_list)
var/datum/sprite_accessory/ears/instance = ear_styles_list[path]
if(can_use_sprite(instance, target, user))
valid_earstyles.Add(list(list(
"name" = instance.name,
"instance" = REF(instance),
"color" = !!instance.do_colouration,
"second_color" = !!instance.extra_overlay,
"icon" = instance.icon,
"icon_state" = instance.icon_state
)))
if(!LAZYLEN(valid_tailstyles))
for(var/path in tail_styles_list)
var/datum/sprite_accessory/tail/instance = tail_styles_list[path]
if(can_use_sprite(instance, target, user))
valid_tailstyles.Add(list(list(
"name" = instance.name,
"instance" = REF(instance),
"color" = !!instance.do_colouration,
"second_color" = !!instance.extra_overlay,
"icon" = instance.icon,
"icon_state" = instance.icon_state
)))
if(!LAZYLEN(valid_wingstyles))
for(var/path in wing_styles_list)
var/datum/sprite_accessory/wing/instance = wing_styles_list[path]
if(can_use_sprite(instance, target, user))
valid_wingstyles.Add(list(list(
"name" = instance.name,
"instance" = REF(instance),
"color" = !!instance.do_colouration,
"second_color" = !!instance.extra_overlay,
"icon" = instance.icon,
"icon_state" = instance.icon_state
)))
if(!LAZYLEN(valid_gradstyles))
for(var/key in GLOB.hair_gradients)
valid_gradstyles.Add(list(list(key)))
/datum/tgui_module/appearance_changer/proc/get_genders(mob/living/carbon/human/target)
var/datum/species/S = target.species
var/list/possible_genders = S.genders
if(!target.internal_organs_by_name["cell"])
return possible_genders
possible_genders = possible_genders.Copy()
possible_genders |= NEUTER
return possible_genders
// Used for subtypes to handle messaging or whatever.
/datum/tgui_module/appearance_changer/proc/changed_hook(flag)
return
/datum/tgui_module/appearance_changer/proc/can_use_sprite(datum/sprite_accessory/X, mob/living/carbon/human/target, mob/user)
if(X.name == DEVELOPER_WARNING_NAME)
return FALSE
if(!isnull(X.species_allowed) && !(target.species.name in X.species_allowed) && (!istype(target.species, /datum/species/custom))) // Letting custom species access wings/ears/tails.
return FALSE
if(LAZYLEN(X.ckeys_allowed) && !(user?.ckey in X.ckeys_allowed) && !(target.ckey in X.ckeys_allowed))
return FALSE
return TRUE
// Subtypes for specific items or machines:
// *******************************************************
// Salon Pro
// *******************************************************
/datum/tgui_module/appearance_changer/mirror
name = "SalonPro Nano-Mirror&trade;"
flags = APPEARANCE_ALL_HAIR
customize_usr = TRUE
/datum/tgui_module/appearance_changer/mirror/coskit
name = "SalonPro Porta-Makeover Deluxe&trade;"
// *******************************************************
// Vore TF
// *******************************************************
/datum/tgui_module/appearance_changer/vore
name = "Appearance Editor (Vore)"
flags = APPEARANCE_ALL
/datum/tgui_module/appearance_changer/vore/tgui_state(mob/user)
return GLOB.tgui_conscious_state
/datum/tgui_module/appearance_changer/vore/tgui_status(mob/user, datum/tgui_state/state)
if(!isbelly(owner.loc))
return STATUS_CLOSE
return ..()
/datum/tgui_module/appearance_changer/vore/update_active_camera_screen()
cam_screen.vis_contents = list(owner)
cam_background.icon_state = "clear"
cam_background.fill_rect(1, 1, 1, 1)
local_skybox.cut_overlays()
/datum/tgui_module/appearance_changer/vore/tgui_close(mob/user)
. = ..()
QDEL_IN(src, 1)
/datum/tgui_module/appearance_changer/vore/changed_hook(flag)
var/mob/living/carbon/human/M = owner
var/mob/living/O = usr
switch(flag)
if(APPEARANCECHANGER_CHANGED_RACE)
to_chat(M, span_notice("You lose sensation of your body, feeling only the warmth of everything around you... "))
to_chat(O, span_notice("Your body shifts as you make dramatic changes to your captive's body."))
if(APPEARANCECHANGER_CHANGED_GENDER)
to_chat(M, span_notice("Your body feels very strange..."))
to_chat(O, span_notice("You feel strange as you alter your captive's gender."))
if(APPEARANCECHANGER_CHANGED_GENDER_ID)
to_chat(M, span_notice("You start to feel... [capitalize(M.gender)]?"))
to_chat(O, span_notice("You feel strange as you alter your captive's gender identity."))
if(APPEARANCECHANGER_CHANGED_SKINTONE, APPEARANCECHANGER_CHANGED_SKINCOLOR)
to_chat(M, span_notice("Your body tingles all over..."))
to_chat(O, span_notice("You tingle as you make noticeable changes to your captive's body."))
if(APPEARANCECHANGER_CHANGED_HAIRSTYLE, APPEARANCECHANGER_CHANGED_HAIRCOLOR, APPEARANCECHANGER_CHANGED_F_HAIRSTYLE, APPEARANCECHANGER_CHANGED_F_HAIRCOLOR)
to_chat(M, span_notice("Your body tingles all over..."))
to_chat(O, span_notice("You tingle as you make noticeable changes to your captive's body."))
if(APPEARANCECHANGER_CHANGED_EYES)
to_chat(M, span_notice("You feel lightheaded and drowsy..."))
to_chat(O, span_notice("You feel warm as you make subtle changes to your captive's body."))
// *******************************************************
// Weaver Cocoon
// *******************************************************
/datum/tgui_module/appearance_changer/cocoon
name ="Appearance Editor (Cocoon)"
flags = APPEARANCE_ALL_COSMETIC
customize_usr = TRUE
/datum/tgui_module/appearance_changer/cocoon/tgui_status(mob/user, datum/tgui_state/state)
if(!istype(owner.loc, /obj/item/holder/micro))
return STATUS_CLOSE
return ..()
// *******************************************************
// Morph Superpower
// *******************************************************
/datum/tgui_module/appearance_changer/superpower
name ="Appearance Editor (Superpower)"
flags = APPEARANCE_ALL_COSMETIC
customize_usr = TRUE
/datum/tgui_module/appearance_changer/superpower/tgui_status(mob/user, datum/tgui_state/state)
var/datum/gene/G = get_gene_from_trait(/datum/trait/positive/superpower_morph)
if(!owner.dna.GetSEState(G.block))
return STATUS_CLOSE
return ..()
// *******************************************************
// Innate Species Transformation.
// *******************************************************
/datum/tgui_module/appearance_changer/innate
name ="Appearance Editor (Innate)"
flags = APPEARANCE_ALL_COSMETIC
customize_usr = TRUE
/datum/tgui_module/appearance_changer/innate/tgui_status(mob/user, datum/tgui_state/state)
if(owner.stat != CONSCIOUS)
return STATUS_CLOSE
return ..()
// *******************************************************
// Body design console
// *******************************************************
/datum/tgui_module/appearance_changer/body_designer
name ="Appearance Editor (Body Designer)"
flags = APPEARANCE_ALL
var/datum/weakref/linked_body_design_console = null
/datum/tgui_module/appearance_changer/body_designer/tgui_status(mob/user, datum/tgui_state/state)
if(!istype(host,/obj/machinery/computer/transhuman/designer))
return STATUS_CLOSE
return ..()
/datum/tgui_module/appearance_changer/body_designer/Destroy()
var/obj/machinery/computer/transhuman/designer/DC = linked_body_design_console?.resolve()
if(DC)
DC.selected_record = FALSE
DC.designer_gui = null // no hardrefs
. = ..()
/datum/tgui_module/appearance_changer/body_designer/proc/make_fake_owner()
// checks for monkey to tell if on the menu
if(owner)
UnregisterSignal(owner, COMSIG_OBSERVER_MOVED)
qdel_null(owner)
owner = new(src)
owner.set_species(SPECIES_LLEILL)
owner.species.produceCopy(owner.species.traits.Copy(),owner,null,FALSE)
owner.invisibility = INVISIBILITY_ABSTRACT
// Add listeners back
owner.AddComponent(/datum/component/recursive_move)
RegisterSignal(owner, COMSIG_OBSERVER_MOVED, PROC_REF(update_active_camera_screen), TRUE)
/datum/tgui_module/appearance_changer/body_designer/proc/load_record_to_body(var/datum/transhuman/body_record/current_project)
if(owner)
UnregisterSignal(owner, COMSIG_OBSERVER_MOVED)
qdel_null(owner)
owner = current_project.produce_human_mob(src,FALSE,FALSE,"Designer [rand(999)]")
// Update some specifics from the current record
owner.dna.blood_reagents = current_project.mydna.dna.blood_reagents
owner.dna.blood_color = current_project.mydna.dna.blood_color
owner.flavor_texts = current_project.mydna.flavor.Copy()
owner.resize(current_project.sizemult, FALSE)
owner.appearance_flags = current_project.aflags
owner.weight = current_project.weight
if(current_project.speciesname)
owner.custom_species = current_project.speciesname
// Add listeners back
owner.AddComponent(/datum/component/recursive_move)
RegisterSignal(owner, COMSIG_OBSERVER_MOVED, PROC_REF(update_active_camera_screen), TRUE)