diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 3a8ee870e5b..3239b4a0226 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -236,4 +236,8 @@
#define USE_FAIL_DEAD 4
#define USE_FAIL_INCAPACITATED 5
#define USE_FAIL_NOT_IN_USER 6
-#define USE_FAIL_IS_SILICON 7
\ No newline at end of file
+#define USE_FAIL_IS_SILICON 7
+
+//Useful for building semicolon-delimited time readouts when trying to find slowdowns in procs
+var/world_time_test = 0
+#define TIMETEST ;world << "TIME DBG;[__FILE__];[__LINE__]; [round(world.tick_usage)]% ([round(world.tick_usage - world_time_test)]%)";world_time_test = world.tick_usage
\ No newline at end of file
diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index e1215bb9017..725812066cc 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -264,3 +264,12 @@ Proc for attack log creation, because really why not
humans += H
return humans
+
+/proc/cached_character_icon(var/mob/desired)
+ var/cachekey = "\ref[desired][desired.real_name]"
+
+ if(cached_character_icons[cachekey])
+ . = cached_character_icons[cachekey]
+ else
+ . = getCompoundIcon(desired)
+ cached_character_icons[cachekey] = .
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index 274c0c0903d..3c282c9c3fb 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -243,7 +243,7 @@
L.fields["citizenship"] = H.citizenship
L.fields["faction"] = H.personal_faction
L.fields["religion"] = H.religion
- L.fields["image"] = getFlatIcon(H) //This is god-awful
+ L.fields["image"] = icon(cached_character_icon(H), dir = SOUTH)
L.fields["antagfac"] = H.antag_faction
L.fields["antagvis"] = H.antag_vis
if(H.exploit_record && !jobban_isbanned(H, "Records"))
@@ -256,182 +256,13 @@
/proc/generate_record_id()
return add_zero(num2hex(rand(1, 65535)), 4) //no point generating higher numbers because of the limitations of num2hex
-/proc/get_id_photo(var/mob/living/carbon/human/H, var/assigned_role)
- var/icon/preview_icon = null
-
- var/g = "m"
- if (H.gender == FEMALE)
- g = "f"
-
- var/icon/icobase = H.species.icobase
-
- preview_icon = new /icon(icobase, "torso_[g]")
- var/icon/temp
- temp = new /icon(icobase, "groin_[g]")
- preview_icon.Blend(temp, ICON_OVERLAY)
- temp = new /icon(icobase, "head_[g]")
- preview_icon.Blend(temp, ICON_OVERLAY)
-
- for(var/obj/item/organ/external/E in H.organs)
- preview_icon.Blend(E.get_icon(), ICON_OVERLAY)
-
- //Tail
- var/use_species_tail = H.species.get_tail(H)
- if(use_species_tail)
- temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[use_species_tail]_s")
- preview_icon.Blend(temp, ICON_OVERLAY)
-
- // Skin tone
- if(H.species.flags & HAS_SKIN_TONE)
- if (H.s_tone >= 0)
- preview_icon.Blend(rgb(H.s_tone, H.s_tone, H.s_tone), ICON_ADD)
- else
- preview_icon.Blend(rgb(-H.s_tone, -H.s_tone, -H.s_tone), ICON_SUBTRACT)
-
- // Skin color
- if(H.species.flags & HAS_SKIN_TONE)
- if(!H.species || H.species.flags & HAS_SKIN_COLOR)
- preview_icon.Blend(rgb(H.r_skin, H.g_skin, H.b_skin), ICON_ADD)
-
- var/use_eye_icon = "eyes_s"
- var/obj/item/organ/external/head/temp_head = H.get_organ(BP_HEAD)
- if(temp_head) use_eye_icon = temp_head.eye_icon
- var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = use_eye_icon)
-
- if (H.species.flags & HAS_EYE_COLOR)
- eyes_s.Blend(rgb(H.r_eyes, H.g_eyes, H.b_eyes), ICON_ADD)
-
- var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style]
- if(hair_style)
- var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
- hair_s.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD)
- eyes_s.Blend(hair_s, ICON_OVERLAY)
-
- var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style]
- if(facial_hair_style)
- var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
- facial_s.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD)
- eyes_s.Blend(facial_s, ICON_OVERLAY)
-
- var/icon/clothes_s = null
- if(!assigned_role) assigned_role = H.mind.assigned_role
- switch(assigned_role)
- if("Head of Personnel")
- clothes_s = new /icon('icons/mob/uniform.dmi', "hop_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
- if("Bartender")
- clothes_s = new /icon('icons/mob/uniform.dmi', "ba_suit_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- if("Gardener")
- clothes_s = new /icon('icons/mob/uniform.dmi', "hydroponics_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- if("Chef")
- clothes_s = new /icon('icons/mob/uniform.dmi', "chef_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- if("Janitor")
- clothes_s = new /icon('icons/mob/uniform.dmi', "janitor_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- if("Librarian")
- clothes_s = new /icon('icons/mob/uniform.dmi', "red_suit_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- if("Quartermaster")
- clothes_s = new /icon('icons/mob/uniform.dmi', "qm_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
- if("Cargo Technician")
- clothes_s = new /icon('icons/mob/uniform.dmi', "cargotech_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- if("Shaft Miner")
- clothes_s = new /icon('icons/mob/uniform.dmi', "miner_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- if("Lawyer")
- clothes_s = new /icon('icons/mob/uniform.dmi', "internalaffairs_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
- if("Chaplain")
- clothes_s = new /icon('icons/mob/uniform.dmi', "chapblack_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- if("Research Director")
- clothes_s = new /icon('icons/mob/uniform.dmi', "director_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY)
- if("Scientist")
- clothes_s = new /icon('icons/mob/uniform.dmi', "sciencewhite_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY)
- if("Chemist")
- clothes_s = new /icon('icons/mob/uniform.dmi', "chemistrywhite_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_chem_open"), ICON_OVERLAY)
- if("Chief Medical Officer")
- clothes_s = new /icon('icons/mob/uniform.dmi', "cmo_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_cmo_open"), ICON_OVERLAY)
- if("Medical Doctor")
- clothes_s = new /icon('icons/mob/uniform.dmi', "medical_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY)
- if("Geneticist")
- clothes_s = new /icon('icons/mob/uniform.dmi', "geneticswhite_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_gen_open"), ICON_OVERLAY)
- if("Virologist")
- clothes_s = new /icon('icons/mob/uniform.dmi', "virologywhite_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_vir_open"), ICON_OVERLAY)
- if("Colony Director")
- clothes_s = new /icon('icons/mob/uniform.dmi', "captain_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
- if("Head of Security")
- clothes_s = new /icon('icons/mob/uniform.dmi', "hosred_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY)
- if("Warden")
- clothes_s = new /icon('icons/mob/uniform.dmi', "warden_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY)
- if("Detective")
- clothes_s = new /icon('icons/mob/uniform.dmi', "detective_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/suit.dmi', "detective"), ICON_OVERLAY)
- if("Security Officer")
- clothes_s = new /icon('icons/mob/uniform.dmi', "secred_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY)
- if("Chief Engineer")
- clothes_s = new /icon('icons/mob/uniform.dmi', "chief_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY)
- if("Station Engineer")
- clothes_s = new /icon('icons/mob/uniform.dmi', "engine_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "orange"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY)
- if("Atmospheric Technician")
- clothes_s = new /icon('icons/mob/uniform.dmi', "atmos_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY)
- if("Roboticist")
- clothes_s = new /icon('icons/mob/uniform.dmi', "robotics_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY)
- else
- clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s")
- clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
- preview_icon.Blend(eyes_s, ICON_OVERLAY)
- if(clothes_s)
- preview_icon.Blend(clothes_s, ICON_OVERLAY)
- qdel(eyes_s)
- qdel(clothes_s)
-
- return preview_icon
-
/datum/datacore/proc/CreateGeneralRecord(var/mob/living/carbon/human/H, var/id)
ResetPDAManifest()
var/icon/front
var/icon/side
- if(H)
- front = getFlatIcon(H, SOUTH, always_use_defdir = 1)
- side = getFlatIcon(H, WEST, always_use_defdir = 1)
- else
- var/mob/living/carbon/human/dummy = new()
- front = new(get_id_photo(dummy), dir = SOUTH)
- side = new(get_id_photo(dummy), dir = WEST)
- qdel(dummy)
+ var/icon/charicon = cached_character_icon(H)
+ front = icon(charicon, dir = SOUTH)
+ side = icon(charicon, dir = WEST)
if(!id) id = text("[]", add_zero(num2hex(rand(1, 65536)), 4))
var/datum/data/record/G = new /datum/data/record()
diff --git a/code/game/objects/items/weapons/id cards/station_ids.dm b/code/game/objects/items/weapons/id cards/station_ids.dm
index 4c1e4b9aaff..e833aee2280 100644
--- a/code/game/objects/items/weapons/id cards/station_ids.dm
+++ b/code/game/objects/items/weapons/id cards/station_ids.dm
@@ -55,8 +55,9 @@
name = "[src.registered_name]'s ID Card ([src.assignment])"
/obj/item/weapon/card/id/proc/set_id_photo(var/mob/M)
- front = getFlatIcon(M, SOUTH, always_use_defdir = 1)
- side = getFlatIcon(M, WEST, always_use_defdir = 1)
+ var/icon/charicon = cached_character_icon(M)
+ front = icon(charicon,dir = SOUTH)
+ side = icon(charicon,dir = WEST)
/mob/proc/set_id_info(var/obj/item/weapon/card/id/id_card)
id_card.age = 0
diff --git a/code/global.dm b/code/global.dm
index f71b19d587d..3ec087e1a43 100644
--- a/code/global.dm
+++ b/code/global.dm
@@ -191,3 +191,7 @@ var/list/station_departments = list("Command", "Medical", "Engineering", "Scienc
//Icons for in-game HUD glasses. Why don't we just share these a little bit?
var/static/icon/ingame_hud = icon('icons/mob/hud.dmi')
var/static/icon/ingame_hud_med = icon('icons/mob/hud_med.dmi')
+
+//Keyed list for caching icons so you don't need to make them for records, IDs, etc all separately.
+//Could be useful for AI impersonation or something at some point?
+var/static/list/cached_character_icons = list()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 2fd8f4170f9..7bf27fbfefa 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1095,7 +1095,7 @@
var/self = 0
if(usr.stat || usr.restrained() || !isliving(usr)) return
-
+
var/datum/gender/TU = gender_datums[usr.get_visible_gender()]
var/datum/gender/T = gender_datums[get_visible_gender()]
@@ -1120,7 +1120,7 @@
else
usr << "You failed to check the pulse. Try again."
-/mob/living/carbon/human/proc/set_species(var/new_species, var/default_colour)
+/mob/living/carbon/human/proc/set_species(var/new_species, var/default_colour, var/regen_icons = TRUE)
if(!dna)
if(!new_species)
@@ -1180,7 +1180,7 @@
maxHealth = species.total_health
spawn(0)
- regenerate_icons()
+ if(regen_icons) regenerate_icons()
if(vessel.total_volume < species.blood_volume)
vessel.maximum_volume = species.blood_volume
vessel.add_reagent("blood", species.blood_volume - vessel.total_volume)
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 1cdb98eaa78..7e7caf5b8f5 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -370,7 +370,7 @@
//character.apply_traits() //VOREStation Removal
- character.lastarea = get_area(loc)
+ // character.lastarea = get_area(loc) //create_character() does this
// Moving wheelchair if they have one
if(character.buckled && istype(character.buckled, /obj/structure/bed/chair/wheelchair))
character.buckled.loc = character.loc
@@ -492,7 +492,7 @@
//new_character.dna.UpdateSE()
// Do the initial caching of the player's body icons.
- //new_character.force_update_limbs() //VOREStation Removal - This is done in copy_to, don't waste time.
+ //new_character.force_update_limbs()
new_character.update_eyes()
new_character.regenerate_icons()