diff --git a/code/datums/dna.dm b/code/datums/dna.dm index f3e7c256753..67af9914e43 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -453,6 +453,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) /////////////////////////// DNA MOB-PROCS ////////////////////// /mob/proc/set_species(datum/species/mrace, icon_update = 1) + SHOULD_NOT_SLEEP(TRUE) return /mob/living/brain/set_species(datum/species/mrace, icon_update = 1) @@ -475,7 +476,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) else return death_sound = new_race.death_sound - dna.species.on_species_loss(src, new_race, pref_load) + + if (dna.species.properly_gained) + dna.species.on_species_loss(src, new_race, pref_load) + var/datum/species/old_species = dna.species dna.species = new_race dna.species.on_species_gain(src, old_species, pref_load) diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 6ef13c5bcd8..32138e14426 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -168,7 +168,10 @@ Medical HUD! Basic mode needs suit sensors on. //called when a living mob changes health /mob/living/proc/med_hud_set_health() - var/image/holder = hud_list[HEALTH_HUD] + var/image/holder = hud_list?[HEALTH_HUD] + if (isnull(holder)) + return + holder.icon_state = "hud[RoundHealth(src)]" var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size @@ -179,7 +182,10 @@ Medical HUD! Basic mode needs suit sensors on. //called when a carbon changes stat, virus or XENO_HOST /mob/living/proc/med_hud_set_status() - var/image/holder = hud_list[STATUS_HUD] + var/image/holder = hud_list?[STATUS_HUD] + if (isnull(holder)) + return + var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) @@ -188,7 +194,10 @@ Medical HUD! Basic mode needs suit sensors on. holder.icon_state = "hudhealthy" /mob/living/carbon/med_hud_set_status() - var/image/holder = hud_list[STATUS_HUD] + var/image/holder = hud_list?[STATUS_HUD] + if (isnull(holder)) + return + var/icon/I = icon(icon, icon_state, dir) var/virus_threat = check_virus() holder.pixel_y = I.Height() - world.icon_size diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index fc4a4472218..77fe81fdb7e 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -28,7 +28,7 @@ human.dna.blood_type = random_blood_type() human.dna.features["mcolor"] = "#[random_color()]" - human.dna.species.randomize_active_underwear(human) + human.dna.species.randomize_active_underwear_only(human) for(var/datum/species/species_path as anything in subtypesof(/datum/species)) var/datum/species/new_species = new species_path diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 854633c8f47..ab8fdf658be 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1,6 +1,6 @@ /mob/living/carbon/Initialize(mapload) . = ..() - create_reagents(1000, REAGENT_HOLDER_ALIVE) + create_carbon_reagents() update_body_parts() //to update the carbon's new bodyparts appearance register_context() @@ -205,6 +205,12 @@ /mob/living/carbon/proc/canBeHandcuffed() return FALSE +/mob/living/carbon/proc/create_carbon_reagents() + if (!isnull(reagents)) + return + + create_reagents(1000, REAGENT_HOLDER_ALIVE) + /mob/living/carbon/Topic(href, href_list) ..() if(href_list["embedded_object"] && usr.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE)) @@ -976,11 +982,14 @@ to_chat(user, span_notice("You retrieve some of [src]\'s internal organs!")) remove_all_embedded_objects() -/mob/living/carbon/proc/create_bodyparts() +/// Creates body parts for this carbon completely from scratch. +/// Optionally takes a map of body zones to what type to instantiate instead of them. +/mob/living/carbon/proc/create_bodyparts(list/overrides) var/l_arm_index_next = -1 var/r_arm_index_next = 0 - for(var/bodypart_path in bodyparts) - var/obj/item/bodypart/bodypart_instance = new bodypart_path() + for(var/obj/item/bodypart/bodypart_path as anything in bodyparts) + var/real_body_part_path = overrides?[initial(bodypart_path.body_zone)] || bodypart_path + var/obj/item/bodypart/bodypart_instance = new real_body_part_path() bodypart_instance.set_owner(src) bodyparts.Remove(bodypart_path) add_bodypart(bodypart_instance) diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 0e57e685644..4678acaa603 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -69,7 +69,9 @@ /// Total level of visualy impairing items var/tinttotal = 0 - ///Gets filled up in [create_bodyparts()][/mob/living/carbon/proc/create_bodyparts] + /// Gets filled up in [/datum/species/proc/replace_body]. + /// Will either contain a list of typepaths if nothing has been created yet, + /// or a list of the body part objects. var/list/bodyparts = list( /obj/item/bodypart/chest, /obj/item/bodypart/head, diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 869d64a2b55..5c91bd65ef8 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -83,7 +83,6 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) return /proc/create_consistent_human_dna(mob/living/carbon/human/target) - target.create_dna() target.dna.initialize_dna(skip_index = TRUE) target.dna.features["body_markings"] = "None" target.dna.features["ears"] = "None" diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 0818d64fa48..57835a277af 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -4,16 +4,16 @@ icon_state = "" //Remove the inherent human icon that is visible on the map editor. We're rendering ourselves limb by limb, having it still be there results in a bug where the basic human icon appears below as south in all directions and generally looks nasty. - //initialize limbs first - create_bodyparts() - setup_mood() + create_dna() + dna.species.create_fresh_body(src) setup_human_dna() - prepare_huds() //Prevents a nasty runtime on human init - if(dna.species) - INVOKE_ASYNC(src, PROC_REF(set_species), dna.species.type) + create_carbon_reagents() + set_species(dna.species.type) + + prepare_huds() //Prevents a nasty runtime on human init //initialise organs create_internal_organs() //most of it is done in set_species now, this is only for parent call @@ -42,7 +42,6 @@ /mob/living/carbon/human/proc/setup_human_dna() //initialize dna. for spawned humans; overwritten by other code - create_dna(src) randomize_human(src) dna.initialize_dna() @@ -999,9 +998,10 @@ var/race = null var/use_random_name = TRUE -/mob/living/carbon/human/species/Initialize(mapload) - . = ..() - INVOKE_ASYNC(src, PROC_REF(set_species), race) +/mob/living/carbon/human/species/create_dna() + dna = new /datum/dna(src) + if (!isnull(race)) + dna.species = new race /mob/living/carbon/human/species/set_species(datum/species/mrace, icon_update, pref_load) . = ..() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 25b22952bd6..84170c7d3de 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -220,6 +220,10 @@ GLOBAL_LIST_EMPTY(features_by_species) /// This supresses the "dosen't appear to be himself" examine text for if the mob is run by an AI controller. Should be used on any NPC human subtypes. Monkeys are the prime example. var/ai_controlled_species = FALSE + /// Was on_species_gain ever actually called? + /// Species code is really odd... + var/properly_gained = FALSE + /////////// // PROCS // /////////// @@ -445,7 +449,9 @@ GLOBAL_LIST_EMPTY(features_by_species) C.mob_biotypes = inherent_biotypes - replace_body(C, src) + if (old_species.type != type) + replace_body(C, src) + regenerate_organs(C, old_species, visual_only = C.visual_only_organs) INVOKE_ASYNC(src, PROC_REF(worn_items_fit_body_check), C, TRUE) @@ -499,6 +505,8 @@ GLOBAL_LIST_EMPTY(features_by_species) SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species) + properly_gained = TRUE + /** * Proc called when a carbon is no longer this species. * @@ -780,11 +788,16 @@ GLOBAL_LIST_EMPTY(features_by_species) human_mob.hairstyle = random_hairstyle(human_mob.gender) human_mob.update_body_parts() -///Proc that will randomise the underwear (i.e. top, pants and socks) of a species' associated mob -/datum/species/proc/randomize_active_underwear(mob/living/carbon/human/human_mob) +///Proc that will randomise the underwear (i.e. top, pants and socks) of a species' associated mob, +/// but will not update the body right away. +/datum/species/proc/randomize_active_underwear_only(mob/living/carbon/human/human_mob) human_mob.undershirt = random_undershirt(human_mob.gender) human_mob.underwear = random_underwear(human_mob.gender) human_mob.socks = random_socks(human_mob.gender) + +///Proc that will randomise the underwear (i.e. top, pants and socks) of a species' associated mob +/datum/species/proc/randomize_active_underwear(mob/living/carbon/human/human_mob) + randomize_active_underwear_only(human_mob) human_mob.update_body() ///Proc that will randomize all the external organs (i.e. horns, frills, tails etc.) of a species' associated mob @@ -2173,3 +2186,7 @@ GLOBAL_LIST_EMPTY(features_by_species) new_part.replace_limb(target, TRUE) new_part.update_limb(is_creating = TRUE) qdel(old_part) + +/// Creates body parts for the target completely from scratch based on the species +/datum/species/proc/create_fresh_body(mob/living/carbon/target) + target.create_bodyparts(bodypart_overrides)