mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-18 02:25:06 +01:00
Dna, Bodyrecord, Xenochi Revive Refactor (#17732)
* changeling fix * Move body spawning into BR * small fix, organization * replace xeno regen * Body descriptor system removed * Revert "Body descriptor system removed" This reverts commit04a0aa3ac8. * massive bodyrecord copy refactor * this too * dna copying is now sane * make a merge easier * better file for this * may we ensure peace everlasting * linter * oops, missed the test * fixed up * furthering the test * different way to check * looking promising * required exclusions * more test * another tweak * setup better * globin * test name change * really mess up that monkey * gradient style to UI entry * scramble ignore * illegal species * scramble fix * grad fix, more test fixes * doing that right * need these too * missed defferal * missed pathing * documentation wall * blood color needs a safety * promethean prep * this early set isn't needed * some protections * fixed waddler nulltest * failure test * intensify scan * second fail test * noticing * dna test case * other dna test case * Test is bunk * huge dna cleanup, better signal * don't edit these * documentation * Do not use loc = src.loc * oops * Use weakrefs in pods * remaining weakrefs * reduce changes in pr * cloning computer does not rotate itself when used * moved body design to new BR code, and fixed screen size * badlinting * updated * No instakilling teshari * jiggles you * TGUI * move along * m ove it * Update AppearanceChangerMisc.tsx * this too * gender is race whoops * Allow old clonepods too * xc * further encapsulation and some fixes * oops * misc not race * separated that * custom footsteps exchanged * Custom speech bubble and xenochi stuff * Update xenochimera.dm * remove digileg snowflake * try this * Update xenochimera.dm * proper close * Always update our DNA * awa * extremely laggy check removed, actually useless * explaining * lower delay time * slower jigglin * Revert "slower jigglin" This reverts commitc801f7d7f5. * disable appearance editor due to various issues * Promie love * xenochi vanity test * lmao * earwings * wording and slot revival * mobvar? * Phasing out specific shapeshifter appearances If you have access to changing your icon, you can change whatever you want. * saveslot loading * more * synth * Shoot out limbs * almost ready * nullcheck * xenochi revive handles size and weight correctly * weaver cocoon updated xenochi internal record after tf * cannot remove from lost limbs * limbs properly respawn on slot revive --------- Co-authored-by: C.L. <killer65311@gmail.com>
This commit is contained in:
@@ -561,6 +561,8 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
if(is_lang_whitelisted(src,chosen_language) || (new_character.species && (chosen_language.name in new_character.species.secondary_langs)))
|
||||
new_character.add_language(lang)
|
||||
|
||||
SEND_SIGNAL(new_character, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
//If desired, apply equipment.
|
||||
if(equipment)
|
||||
if(charjob)
|
||||
|
||||
@@ -532,7 +532,7 @@ var/list/preferences_datums = list()
|
||||
else
|
||||
var/bodytype
|
||||
var/datum/species/selected_species = GLOB.all_species[species]
|
||||
if(custom_base)
|
||||
if(selected_species.selects_bodytype && custom_base) //Everyone technically has custom_base set to HUMAN, but only some species actually select it.
|
||||
bodytype = custom_base
|
||||
else
|
||||
bodytype = selected_species.get_bodytype()
|
||||
@@ -543,7 +543,8 @@ var/list/preferences_datums = list()
|
||||
|
||||
for(var/N in character.organs_by_name)
|
||||
var/obj/item/organ/external/O = character.organs_by_name[N]
|
||||
O.markings.Cut()
|
||||
if(O)
|
||||
O.markings.Cut()
|
||||
|
||||
var/priority = 0
|
||||
for(var/M in body_markings)
|
||||
@@ -553,6 +554,7 @@ var/list/preferences_datums = list()
|
||||
for(var/BP in mark_datum.body_parts)
|
||||
var/obj/item/organ/external/O = character.organs_by_name[BP]
|
||||
if(O)
|
||||
if(!islist(body_markings[M][BP])) continue
|
||||
O.markings[M] = list("color" = body_markings[M][BP]["color"], "datum" = mark_datum, "priority" = priority, "on" = body_markings[M][BP]["on"])
|
||||
character.markings_len = priority
|
||||
|
||||
@@ -580,7 +582,6 @@ var/list/preferences_datums = list()
|
||||
character.fuzzy = fuzzy
|
||||
character.offset_override = offset_override
|
||||
character.voice_freq = voice_freq
|
||||
character.size_multiplier = size_multiplier
|
||||
character.resize(size_multiplier, animate = FALSE, ignore_prefs = TRUE)
|
||||
|
||||
var/list/traits_to_copy = list(/datum/trait/neutral/tall,
|
||||
@@ -615,17 +616,16 @@ var/list/preferences_datums = list()
|
||||
|
||||
var/datum/species/selected_species = GLOB.all_species[species]
|
||||
var/bodytype_selected
|
||||
if(custom_base)
|
||||
if(selected_species.selects_bodytype && custom_base)
|
||||
bodytype_selected = custom_base
|
||||
else
|
||||
bodytype_selected = selected_species.get_bodytype(character)
|
||||
|
||||
character.dna.base_species = bodytype_selected
|
||||
character.species.base_species = bodytype_selected
|
||||
character.species.icobase = character.species.get_icobase()
|
||||
character.species.deform = character.species.get_icobase(get_deform = TRUE)
|
||||
character.species.vanity_base_fit = bodytype_selected
|
||||
if (istype(character.species, /datum/species/shapeshifter))
|
||||
if(istype(character.species, /datum/species/shapeshifter))
|
||||
wrapped_species_by_ref["\ref[character]"] = bodytype_selected
|
||||
|
||||
character.custom_species = custom_species
|
||||
|
||||
@@ -800,11 +800,11 @@
|
||||
//We REALLY don't need to go through every variable. Doing so makes this lag like hell on 515
|
||||
/datum/species/proc/copy_variables(var/datum/species/S, var/list/whitelist)
|
||||
//List of variables to ignore, trying to copy type will runtime.
|
||||
//var/list/blacklist = list("type", "loc", "client", "ckey")
|
||||
//var/list/blacklist = list(BLACKLISTED_COPY_VARS)
|
||||
//Makes thorough copy of species datum.
|
||||
for(var/i in whitelist)
|
||||
if(!(i in S.vars)) //Don't copy incompatible vars.
|
||||
continue
|
||||
//if(!(i in S.vars)) // This check SOUNDS like a good idea, until you realize it loops over every var in base datum + species datum + byond builtin vars for EACH var in the whitelist. All the vars in whitelist are in the base species datum anyway, so this is unneeded.
|
||||
// continue
|
||||
if(S.vars[i] != vars[i] && !islist(vars[i])) //If vars are same, no point in copying.
|
||||
S.vars[i] = vars[i]
|
||||
|
||||
|
||||
@@ -109,16 +109,8 @@ var/datum/species/shapeshifter/promethean/prometheans
|
||||
cold_discomfort_strings = list("You feel too cool.")
|
||||
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/shapeshifter_select_shape,
|
||||
/mob/living/carbon/human/proc/shapeshifter_select_colour,
|
||||
/mob/living/carbon/human/proc/shapeshifter_select_hair,
|
||||
/mob/living/carbon/human/proc/shapeshifter_select_hair_colors,
|
||||
/mob/living/carbon/human/proc/shapeshifter_select_gender,
|
||||
/mob/living/carbon/human/proc/innate_shapeshifting,
|
||||
/mob/living/carbon/human/proc/regenerate,
|
||||
/mob/living/carbon/human/proc/shapeshifter_select_wings,
|
||||
/mob/living/carbon/human/proc/shapeshifter_select_tail,
|
||||
/mob/living/carbon/human/proc/shapeshifter_select_ears,
|
||||
/mob/living/carbon/human/proc/shapeshifter_select_secondary_ears,
|
||||
/mob/living/carbon/human/proc/prommie_blobform,
|
||||
/mob/living/proc/set_size,
|
||||
/mob/living/carbon/human/proc/promethean_select_opaqueness,
|
||||
@@ -411,3 +403,9 @@ var/datum/species/shapeshifter/promethean/prometheans
|
||||
return
|
||||
else
|
||||
prommie_intoblob()
|
||||
|
||||
/mob/living/carbon/human/proc/innate_shapeshifting()
|
||||
set name = "Transform Appearance"
|
||||
set category = "Abilities.Superpower"
|
||||
var/datum/tgui_module/appearance_changer/innate/I = new(src, src)
|
||||
I.tgui_interact(src)
|
||||
|
||||
@@ -679,7 +679,12 @@
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/// Revives a body using the client's preferences if human
|
||||
/mob/living/proc/revive()
|
||||
revival_healing_action()
|
||||
|
||||
/// Performs the actual healing of Aheal, seperate from revive() because it does not use client prefs. Will not heal everything, and expects to be called through revive() or with a bodyrecord doing a respawn/revive.
|
||||
/mob/living/proc/revival_healing_action()
|
||||
rejuvenate()
|
||||
if(buckled)
|
||||
buckled.unbuckle_mob()
|
||||
@@ -701,6 +706,8 @@
|
||||
if(ai_holder) // AI gets told to sleep when killed. Since they're not dead anymore, wake it up.
|
||||
ai_holder.go_wake()
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
/mob/living/proc/rejuvenate()
|
||||
if(reagents)
|
||||
reagents.clear_reagents()
|
||||
|
||||
@@ -437,15 +437,15 @@
|
||||
var/datum/language/keylang = GLOB.all_languages[client.prefs.language_custom_keys[key]]
|
||||
if(keylang)
|
||||
new_character.language_keys[key] = keylang
|
||||
// VOREStation Add: Preferred Language Setting;
|
||||
if(client.prefs.preferred_language) // Do we have a preferred language?
|
||||
var/datum/language/def_lang = GLOB.all_languages[client.prefs.preferred_language]
|
||||
if(def_lang)
|
||||
new_character.default_language = def_lang
|
||||
// VOREStation Add End
|
||||
// And uncomment this, too.
|
||||
//new_character.dna.UpdateSE()
|
||||
|
||||
SEND_SIGNAL(new_character, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
// Do the initial caching of the player's body icons.
|
||||
new_character.force_update_limbs()
|
||||
new_character.update_icons_body()
|
||||
|
||||
@@ -37,7 +37,7 @@ GLOBAL_LIST_INIT(fancy_sprite_accessory_color_channel_names, list("Primary", "Se
|
||||
var/gender = NEUTER
|
||||
|
||||
// Restrict some styles to specific species. Default to all species to avoid runtimes in character creator.
|
||||
var/list/species_allowed = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_UNATHI, SPECIES_TAJARAN, SPECIES_TESHARI, SPECIES_NEVREAN, SPECIES_AKULA, SPECIES_SERGAL, SPECIES_FENNEC, SPECIES_ZORREN_HIGH, SPECIES_VULPKANIN, SPECIES_XENOCHIMERA, SPECIES_XENOHYBRID, SPECIES_VASILISSAN, SPECIES_RAPALA, SPECIES_PROTEAN, SPECIES_ALRAUNE, SPECIES_WEREBEAST, SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW, SPECIES_ALTEVIAN, SPECIES_LLEILL, SPECIES_HANNER, SPECIES_ZADDAT, SPECIES_SPARKLE)
|
||||
var/list/species_allowed = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_UNATHI, SPECIES_TAJARAN, SPECIES_TESHARI, SPECIES_NEVREAN, SPECIES_AKULA, SPECIES_SERGAL, SPECIES_FENNEC, SPECIES_ZORREN_HIGH, SPECIES_VULPKANIN, SPECIES_XENOCHIMERA, SPECIES_XENOHYBRID, SPECIES_VASILISSAN, SPECIES_RAPALA, SPECIES_PROTEAN, SPECIES_ALRAUNE, SPECIES_WEREBEAST, SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW, SPECIES_ALTEVIAN, SPECIES_LLEILL, SPECIES_HANNER, SPECIES_ZADDAT, SPECIES_SPARKLE, SPECIES_PROMETHEAN)
|
||||
|
||||
// Whether or not the accessory can be affected by colouration
|
||||
var/do_colouration = 1
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
var/extra_overlay2
|
||||
var/desc = DEVELOPER_WARNING_NAME
|
||||
em_block = TRUE
|
||||
species_allowed = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_UNATHI, SPECIES_TAJARAN, SPECIES_TESHARI, SPECIES_NEVREAN, SPECIES_AKULA, SPECIES_SERGAL, SPECIES_FENNEC, SPECIES_ZORREN_HIGH, SPECIES_VULPKANIN, SPECIES_XENOCHIMERA, SPECIES_XENOHYBRID, SPECIES_VASILISSAN, SPECIES_RAPALA, SPECIES_PROTEAN, SPECIES_ALRAUNE, SPECIES_WEREBEAST, SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW, SPECIES_ALTEVIAN, SPECIES_LLEILL, SPECIES_HANNER, SPECIES_SPARKLE)
|
||||
species_allowed = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_UNATHI, SPECIES_TAJARAN, SPECIES_TESHARI, SPECIES_NEVREAN, SPECIES_AKULA, SPECIES_SERGAL, SPECIES_FENNEC, SPECIES_ZORREN_HIGH, SPECIES_VULPKANIN, SPECIES_XENOCHIMERA, SPECIES_XENOHYBRID, SPECIES_VASILISSAN, SPECIES_RAPALA, SPECIES_PROTEAN, SPECIES_ALRAUNE, SPECIES_WEREBEAST, SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW, SPECIES_ALTEVIAN, SPECIES_LLEILL, SPECIES_HANNER, SPECIES_SPARKLE, SPECIES_PROMETHEAN)
|
||||
|
||||
/**
|
||||
* Gets the number of color channels we have.
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
var/extra_overlay_w // Flapping state for extra overlay
|
||||
var/extra_overlay2_w
|
||||
|
||||
species_allowed = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_UNATHI, SPECIES_TAJARAN, SPECIES_TESHARI, SPECIES_NEVREAN, SPECIES_AKULA, SPECIES_SERGAL, SPECIES_FENNEC, SPECIES_ZORREN_HIGH, SPECIES_VULPKANIN, SPECIES_XENOCHIMERA, SPECIES_XENOHYBRID, SPECIES_VASILISSAN, SPECIES_RAPALA, SPECIES_PROTEAN, SPECIES_ALRAUNE, SPECIES_WEREBEAST, SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW, SPECIES_ALTEVIAN, SPECIES_LLEILL, SPECIES_HANNER, SPECIES_SPARKLE)
|
||||
species_allowed = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_UNATHI, SPECIES_TAJARAN, SPECIES_TESHARI, SPECIES_NEVREAN, SPECIES_AKULA, SPECIES_SERGAL, SPECIES_FENNEC, SPECIES_ZORREN_HIGH, SPECIES_VULPKANIN, SPECIES_XENOCHIMERA, SPECIES_XENOHYBRID, SPECIES_VASILISSAN, SPECIES_RAPALA, SPECIES_PROTEAN, SPECIES_ALRAUNE, SPECIES_WEREBEAST, SPECIES_SHADEKIN, SPECIES_SHADEKIN_CREW, SPECIES_ALTEVIAN, SPECIES_LLEILL, SPECIES_HANNER, SPECIES_SPARKLE, SPECIES_PROMETHEAN)
|
||||
|
||||
var/wing_offset = 0
|
||||
var/multi_dir = FALSE // Does it use different sprites at different layers? _front will be added for sprites on low layer, _back to high layer
|
||||
|
||||
@@ -497,3 +497,5 @@
|
||||
var/new_speech_bubble = tgui_input_list(src, "Pick new voice (default for automatic selection)", "Character Preference", GLOB.selectable_speech_bubbles)
|
||||
if(new_speech_bubble)
|
||||
custom_speech_bubble = new_speech_bubble
|
||||
if(dna)
|
||||
dna.custom_speech_bubble = new_speech_bubble
|
||||
|
||||
@@ -216,6 +216,9 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
|
||||
..()
|
||||
|
||||
/obj/item/organ/internal/brain/slime/proc/reviveBody()
|
||||
// TODO - Reference how xenochimera component handles revival from bodyrecord in the future.
|
||||
// This requires a promie/protean component for transformation and regeneration.
|
||||
// This shouldn't use a brain mob for caching dna. That's what BRs are for.
|
||||
var/datum/dna2/record/R = new /datum/dna2/record()
|
||||
qdel_swap(R.dna, brainmob.dna.Clone())
|
||||
R.ckey = brainmob.ckey
|
||||
@@ -288,8 +291,10 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
|
||||
for(var/datum/language/L in R.languages)
|
||||
H.add_language(L.name)
|
||||
H.flavor_texts = R.flavor.Copy()
|
||||
qdel(R.dna)
|
||||
qdel(R)
|
||||
|
||||
SEND_SIGNAL(H, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
qdel(R) // Record already deletes dna
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -187,6 +187,8 @@
|
||||
if(def_lang)
|
||||
new_character.default_language = def_lang
|
||||
|
||||
SEND_SIGNAL(new_character, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
//If desired, apply equipment.
|
||||
if(equip_body)
|
||||
if(charjob)
|
||||
|
||||
@@ -148,16 +148,17 @@
|
||||
var/list/clonepods = list()
|
||||
for(var/obj/machinery/clonepod/transhuman/pod in pods)
|
||||
var/status = "idle"
|
||||
var/mob/living/occupant = pod.get_occupant()
|
||||
if(pod.mess)
|
||||
status = "mess"
|
||||
else if(pod.occupant && !(pod.stat & NOPOWER))
|
||||
else if(occupant && !(pod.stat & NOPOWER))
|
||||
status = "cloning"
|
||||
clonepods += list(list(
|
||||
"pod" = REF(pod),
|
||||
"name" = sanitize(capitalize(pod.name)),
|
||||
"biomass" = pod.get_biomass(),
|
||||
"status" = status,
|
||||
"progress" = (pod.occupant && pod.occupant.stat != DEAD) ? pod.get_completion() : 0
|
||||
"progress" = (occupant && occupant.stat != DEAD) ? pod.get_completion() : 0
|
||||
))
|
||||
data["pods"] = clonepods
|
||||
|
||||
@@ -177,8 +178,8 @@
|
||||
resleevers += list(list(
|
||||
"sleever" = REF(resleever),
|
||||
"name" = sanitize(capitalize(resleever.name)),
|
||||
"occupied" = !!resleever.occupant,
|
||||
"occupant" = resleever.occupant ? resleever.occupant.real_name : "None"
|
||||
"occupied" = !!resleever.get_occupant(),
|
||||
"occupant" = resleever.get_occupant() ? resleever.get_occupant().real_name : "None"
|
||||
))
|
||||
data["sleevers"] = resleevers
|
||||
|
||||
@@ -322,7 +323,7 @@
|
||||
return
|
||||
|
||||
//Already doing someone.
|
||||
if(pod.occupant)
|
||||
if(pod.get_occupant())
|
||||
set_temp("Error: Growpod is currently occupied.", "danger")
|
||||
active_br = null
|
||||
return
|
||||
@@ -375,26 +376,26 @@
|
||||
switch(mode)
|
||||
if(1) //Body resleeving
|
||||
//No body to sleeve into.
|
||||
if(!sleever.occupant)
|
||||
if(!sleever.get_occupant())
|
||||
set_temp("Error: Resleeving pod is not occupied.", "danger")
|
||||
active_mr = null
|
||||
return
|
||||
|
||||
//OOC body lock thing.
|
||||
if(sleever.occupant.resleeve_lock && active_mr.ckey != sleever.occupant.resleeve_lock)
|
||||
if(sleever.get_occupant().resleeve_lock && active_mr.ckey != sleever.get_occupant().resleeve_lock)
|
||||
set_temp("Error: Mind incompatible with body.", "danger")
|
||||
active_mr = null
|
||||
return
|
||||
|
||||
var/list/subtargets = list()
|
||||
for(var/mob/living/carbon/human/H in sleever.occupant)
|
||||
for(var/mob/living/carbon/human/H in sleever.get_occupant())
|
||||
if(H.resleeve_lock && active_mr.ckey != H.resleeve_lock)
|
||||
continue
|
||||
subtargets += H
|
||||
if(subtargets.len)
|
||||
var/oc_sanity = sleever.occupant
|
||||
var/oc_sanity = sleever.get_occupant()
|
||||
override = tgui_input_list(ui.user,"Multiple bodies detected. Select target for resleeving of [active_mr.mindname] manually. Sleeving of primary body is unsafe with sub-contents, and is not listed.", "Resleeving Target", subtargets)
|
||||
if(!override || oc_sanity != sleever.occupant || !(override in sleever.occupant))
|
||||
if(!override || oc_sanity != sleever.get_occupant() || !(override in sleever.get_occupant()))
|
||||
set_temp("Error: Target selection aborted.", "danger")
|
||||
active_mr = null
|
||||
return
|
||||
@@ -558,7 +559,7 @@
|
||||
if(!selected_sleever)
|
||||
can_sleeve_active = FALSE
|
||||
set_temp("Error: Cannot sleeve due to no selected sleever.", "danger")
|
||||
if(selected_sleever && !selected_sleever.occupant)
|
||||
if(selected_sleever && !selected_sleever.get_occupant())
|
||||
can_sleeve_active = FALSE
|
||||
set_temp("Error: Cannot sleeve due to lack of sleever occupant.", "danger")
|
||||
else
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
if(!designer_gui)
|
||||
designer_gui = new(src, null)
|
||||
designer_gui.linked_body_design_console = WEAKREF(src)
|
||||
CallAsync(designer_gui, TYPE_PROC_REF(/datum/tgui_module/appearance_changer,jiggle_map))
|
||||
if(!designer_gui.owner)
|
||||
designer_gui.make_fake_owner()
|
||||
selected_record = FALSE
|
||||
|
||||
@@ -134,6 +134,11 @@
|
||||
speciesname = M.custom_species ? M.custom_species : null
|
||||
bodygender = M.gender
|
||||
body_oocnotes = M.ooc_notes
|
||||
body_ooclikes = M.ooc_notes_likes
|
||||
body_oocdislikes = M.ooc_notes_dislikes
|
||||
body_oocfavs = M.ooc_notes_favs
|
||||
body_oocmaybes = M.ooc_notes_maybes
|
||||
body_oocstyle = M.ooc_notes_style
|
||||
sizemult = M.size_multiplier
|
||||
weight = M.weight
|
||||
aflags = M.appearance_flags
|
||||
@@ -204,7 +209,6 @@
|
||||
if(add_to_db)
|
||||
SStranscore.add_body(src, database_key = database_key)
|
||||
|
||||
|
||||
/**
|
||||
* Make a deep copy of this record so it can be saved on a disk without modifications
|
||||
* to the original affecting the copy.
|
||||
@@ -214,28 +218,195 @@
|
||||
/datum/transhuman/body_record/proc/init_from_br(var/datum/transhuman/body_record/orig)
|
||||
ASSERT(!QDELETED(orig))
|
||||
ASSERT(istype(orig))
|
||||
src.mydna = new ()
|
||||
qdel_swap(src.mydna.dna, orig.mydna.dna.Clone())
|
||||
src.mydna.ckey = orig.mydna.ckey
|
||||
src.mydna.id = orig.mydna.id
|
||||
src.mydna.name = orig.mydna.name
|
||||
src.mydna.types = orig.mydna.types
|
||||
src.mydna.flavor = orig.mydna.flavor.Copy()
|
||||
src.ckey = orig.ckey
|
||||
src.locked = orig.locked
|
||||
src.client_ref = orig.client_ref
|
||||
src.mind_ref = orig.mind_ref
|
||||
src.synthetic = orig.synthetic
|
||||
src.speciesname = orig.speciesname
|
||||
src.bodygender = orig.bodygender
|
||||
src.body_oocnotes = orig.body_oocnotes
|
||||
src.body_ooclikes = orig.body_ooclikes
|
||||
src.body_oocdislikes = orig.body_oocdislikes
|
||||
src.limb_data = orig.limb_data.Copy()
|
||||
src.organ_data = orig.organ_data.Copy()
|
||||
src.genetic_modifiers = orig.genetic_modifiers.Copy()
|
||||
src.toocomplex = orig.toocomplex
|
||||
src.sizemult = orig.sizemult
|
||||
src.aflags = orig.aflags
|
||||
src.breath_type = orig.breath_type
|
||||
src.weight = orig.weight
|
||||
for(var/A in vars)
|
||||
switch(A)
|
||||
if(BLACKLISTED_COPY_VARS)
|
||||
continue
|
||||
if("mydna")
|
||||
mydna = orig.mydna.copy()
|
||||
continue
|
||||
if(islist(vars[A]))
|
||||
var/list/L = orig.vars[A]
|
||||
vars[A] = L.Copy()
|
||||
continue
|
||||
vars[A] = orig.vars[A]
|
||||
|
||||
/**
|
||||
* Spawning a body was once left entirely up to the machine doing it, but bodies are massivley complex
|
||||
* objects, and doing it this way lead to huge amounts of copypasted code to do the same thing.
|
||||
* If you want to spawn a body from a BR, please use these...
|
||||
*/
|
||||
|
||||
/// The core of resleeving, creates a mob based on the current record
|
||||
/datum/transhuman/body_record/proc/produce_human_mob(var/location, var/is_synthfab, var/force_unlock, var/backup_name)
|
||||
// These are broken up into steps, otherwise the proc gets massive and hard to read.
|
||||
var/mob/living/carbon/human/H = internal_producebody(location,backup_name)
|
||||
internal_producebody_handlesleevelock(H,force_unlock)
|
||||
internal_producebody_updatelimbandorgans(H)
|
||||
internal_producebody_updatednastate(H,is_synthfab)
|
||||
internal_producebody_virgoOOC(H)
|
||||
internal_producebody_misc(H)
|
||||
return H
|
||||
|
||||
/// Creates a human mob with the correct species, name, and a stable state.
|
||||
/datum/transhuman/body_record/proc/internal_producebody(var/location,var/backup_name)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
var/mob/living/carbon/human/H = new /mob/living/carbon/human(location, mydna.dna.species)
|
||||
if(!mydna.dna.real_name)
|
||||
mydna.dna.real_name = backup_name
|
||||
H.real_name = mydna.dna.real_name
|
||||
H.name = H.real_name
|
||||
for(var/datum/language/L in mydna.languages)
|
||||
H.add_language(L.name)
|
||||
H.suiciding = 0
|
||||
H.losebreath = 0
|
||||
H.mind = null
|
||||
|
||||
return H
|
||||
|
||||
/// Sets the new body's sleevelock status, to prevent impersonation by transfering an incorrect mind.
|
||||
/datum/transhuman/body_record/proc/internal_producebody_handlesleevelock(var/mob/living/carbon/human/H,var/force_unlock)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
PRIVATE_PROC(TRUE)
|
||||
if(locked && !force_unlock)
|
||||
if(ckey)
|
||||
H.resleeve_lock = ckey
|
||||
else
|
||||
// Ensure even body scans without an attached ckey respect locking
|
||||
H.resleeve_lock = "@badckey"
|
||||
|
||||
/// Either converts limbs to robotics or prosthetic states, or removes them entirely based off record.
|
||||
/datum/transhuman/body_record/proc/internal_producebody_updatelimbandorgans(var/mob/living/carbon/human/H,var/is_synthfab)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
//Fix the external organs
|
||||
for(var/part in limb_data)
|
||||
var/status = limb_data[part]
|
||||
if(status == null) continue //Species doesn't have limb? Child of amputated limb?
|
||||
|
||||
var/obj/item/organ/external/O = H.organs_by_name[part]
|
||||
if(!O) continue //Not an organ. Perhaps another amputation removed it already.
|
||||
|
||||
if(status == 1) //Normal limbs
|
||||
continue
|
||||
else if(status == 0) //Missing limbs
|
||||
O.remove_rejuv()
|
||||
else if(status) //Anything else is a manufacturer
|
||||
if(!is_synthfab)
|
||||
O.remove_rejuv() //Don't robotize them, leave them removed so robotics can attach a part.
|
||||
else
|
||||
O.robotize(status)
|
||||
|
||||
//Then the internal organs
|
||||
for(var/part in organ_data)
|
||||
var/status = organ_data[part]
|
||||
if(status == null) continue //Species doesn't have organ? Child of missing part?
|
||||
|
||||
var/obj/item/organ/I = H.internal_organs_by_name[part]
|
||||
if(!I) continue//Not an organ. Perhaps external conversion changed it already?
|
||||
|
||||
if(status == 0) //Normal organ
|
||||
continue
|
||||
else if(status == 1) //Assisted organ
|
||||
I.mechassist()
|
||||
else if(status == 2) //Mechanical organ
|
||||
I.robotize()
|
||||
else if(status == 3) //Digital organ
|
||||
I.digitize()
|
||||
|
||||
/// Transfers dna data to mob, and reinits traits and appearance from it
|
||||
/datum/transhuman/body_record/proc/internal_producebody_updatednastate(var/mob/living/carbon/human/H,var/is_synthfab)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
//Apply DNA from record
|
||||
if(!mydna.dna) // This case should never happen, but copied from clone pod... Who knows with this codebase.
|
||||
mydna.dna = new /datum/dna()
|
||||
qdel_swap(H.dna, mydna.dna.Clone())
|
||||
H.original_player = ckey
|
||||
|
||||
//Apply genetic modifiers, synths don't use these
|
||||
if(!is_synthfab)
|
||||
for(var/modifier_type in mydna.genetic_modifiers)
|
||||
H.add_modifier(modifier_type)
|
||||
|
||||
//Update appearance, remake icons
|
||||
H.UpdateAppearance()
|
||||
H.sync_dna_traits(FALSE) // Traitgenes Sync traits to genetics if needed
|
||||
H.sync_organ_dna()
|
||||
H.regenerate_icons()
|
||||
H.initialize_vessel()
|
||||
|
||||
/// Transfers VORE related information cached in the mob
|
||||
/datum/transhuman/body_record/proc/internal_producebody_virgoOOC(var/mob/living/carbon/human/H)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
PRIVATE_PROC(TRUE)
|
||||
H.ooc_notes = body_oocnotes
|
||||
H.ooc_notes_likes = body_ooclikes
|
||||
H.ooc_notes_dislikes = body_oocdislikes
|
||||
H.ooc_notes_favs = body_oocfavs
|
||||
H.ooc_notes_maybes = body_oocmaybes
|
||||
H.ooc_notes_style = body_oocstyle
|
||||
|
||||
/datum/transhuman/body_record/proc/internal_producebody_misc(var/mob/living/carbon/human/H)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
PRIVATE_PROC(TRUE)
|
||||
H.flavor_texts = mydna.flavor.Copy()
|
||||
H.resize(sizemult, FALSE)
|
||||
H.appearance_flags = aflags
|
||||
H.weight = weight
|
||||
if(speciesname)
|
||||
H.custom_species = speciesname
|
||||
|
||||
/**
|
||||
* Specialty revival procs. Uses the BR for data, but needs to handle some weird logic for xenochi/slimes
|
||||
*/
|
||||
/datum/transhuman/body_record/proc/revive_xenochimera(var/mob/living/carbon/human/H,var/heal_robot_limbs,var/from_save_slot)
|
||||
// Boy this one is complex, but what do we expect when trying to heal damage and organ loss in this game!
|
||||
if(!H || QDELETED(H)) // Someone, somewhere, will call this without any safety. I feel it in my bones cappin'
|
||||
return
|
||||
|
||||
// Don't unlock unwilling xenochi!
|
||||
internal_producebody_handlesleevelock(H,FALSE)
|
||||
|
||||
// Reset our organs/limbs.
|
||||
H.species.create_organs(H)
|
||||
internal_producebody_updatelimbandorgans(H, heal_robot_limbs)
|
||||
|
||||
//Don't boot out anyone already in the mob.
|
||||
if(!H.client || !H.key)
|
||||
for (var/obj/item/organ/internal/brain/CH in GLOB.all_brain_organs)
|
||||
if(CH.brainmob)
|
||||
if(CH.brainmob.real_name == H.real_name)
|
||||
if(CH.brainmob.mind)
|
||||
CH.brainmob.mind.transfer_to(H)
|
||||
qdel(CH)
|
||||
|
||||
// Traitgenes Disable all traits currently active, before species.produceCopy() applies them during updatednastate(). Relevant here as genetraits may not match prior dna!
|
||||
for(var/datum/gene/trait/gene in GLOB.dna_genes)
|
||||
if(gene.name in H.active_genes)
|
||||
gene.deactivate(H)
|
||||
H.active_genes -= gene.name
|
||||
|
||||
internal_producebody_updatednastate(H,FALSE)
|
||||
internal_producebody_virgoOOC(H) // Is this needed?
|
||||
internal_producebody_misc(H)
|
||||
|
||||
// Begin actual REVIVIAL. Do NOT use revive(). That uses client prefs and allows save hacking.
|
||||
H.revival_healing_action()
|
||||
|
||||
// Update record from vanity copy of slot if needed
|
||||
if(from_save_slot)
|
||||
H.client.prefs.vanity_copy_to(H,FALSE,TRUE,TRUE,FALSE)
|
||||
for(var/category in H.all_underwear) // No undies
|
||||
H.hide_underwear[category] = TRUE
|
||||
H.update_underwear()
|
||||
|
||||
return H
|
||||
|
||||
/datum/transhuman/body_record/proc/revive_promethean(var/mob/living/carbon/human/H)
|
||||
// TODO - See note in code\modules\organs\internal\brain.dm for slime brains
|
||||
return
|
||||
|
||||
@@ -29,83 +29,9 @@
|
||||
remove_biomass(CLONE_BIOMASS)
|
||||
|
||||
//Get the DNA and generate a new mob
|
||||
var/datum/dna2/record/R = current_project.mydna
|
||||
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src, R.dna.species)
|
||||
if(current_project.locked)
|
||||
if(current_project.ckey)
|
||||
H.resleeve_lock = current_project.ckey
|
||||
else
|
||||
// Ensure even body scans without an attached ckey respect locking
|
||||
H.resleeve_lock = "@badckey"
|
||||
var/mob/living/carbon/human/H = current_project.produce_human_mob(src,FALSE,FALSE,"clone ([rand(0,999)])")
|
||||
SEND_SIGNAL(H, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
//Fix the external organs
|
||||
for(var/part in current_project.limb_data)
|
||||
|
||||
var/status = current_project.limb_data[part]
|
||||
if(status == null) continue //Species doesn't have limb? Child of amputated limb?
|
||||
|
||||
var/obj/item/organ/external/O = H.organs_by_name[part]
|
||||
if(!O) continue //Not an organ. Perhaps another amputation removed it already.
|
||||
|
||||
if(status == 1) //Normal limbs
|
||||
continue
|
||||
else if(status == 0) //Missing limbs
|
||||
O.remove_rejuv()
|
||||
else if(status) //Anything else is a manufacturer
|
||||
O.remove_rejuv() //Don't robotize them, leave them removed so robotics can attach a part.
|
||||
|
||||
//Look, this machine can do this because [reasons] okay?!
|
||||
for(var/part in current_project.organ_data)
|
||||
|
||||
var/status = current_project.organ_data[part]
|
||||
if(status == null) continue //Species doesn't have organ? Child of missing part?
|
||||
|
||||
var/obj/item/organ/I = H.internal_organs_by_name[part]
|
||||
if(!I) continue//Not an organ. Perhaps external conversion changed it already?
|
||||
|
||||
if(status == 0) //Normal organ
|
||||
continue
|
||||
else if(status == 1) //Assisted organ
|
||||
I.mechassist()
|
||||
else if(status == 2) //Mechanical organ
|
||||
I.robotize()
|
||||
else if(status == 3) //Digital organ
|
||||
I.digitize()
|
||||
|
||||
|
||||
occupant = H
|
||||
|
||||
//Set the name or generate one
|
||||
if(!R.dna.real_name)
|
||||
R.dna.real_name = "clone ([rand(0,999)])"
|
||||
H.real_name = R.dna.real_name
|
||||
|
||||
//Apply DNA
|
||||
qdel_swap(H.dna, R.dna.Clone())
|
||||
H.original_player = current_project.ckey
|
||||
|
||||
//Apply genetic modifiers
|
||||
for(var/modifier_type in R.genetic_modifiers)
|
||||
H.add_modifier(modifier_type)
|
||||
|
||||
//Apply legs
|
||||
H.digitigrade = R.dna.digitigrade // ensure clone mob has digitigrade var set appropriately
|
||||
if(H.dna.digitigrade <> R.dna.digitigrade)
|
||||
H.dna.digitigrade = R.dna.digitigrade // ensure cloned DNA is set appropriately from record??? for some reason it doesn't get set right despite the override to datum/dna/Clone()
|
||||
|
||||
//Apply damage
|
||||
H.adjustCloneLoss((H.getMaxHealth() - (H.getMaxHealth()))*-0.75)
|
||||
H.Paralyse(4)
|
||||
H.updatehealth()
|
||||
|
||||
//Update appearance, remake icons
|
||||
H.UpdateAppearance()
|
||||
H.sync_dna_traits(FALSE) // Traitgenes Sync traits to genetics if needed
|
||||
H.sync_organ_dna()
|
||||
H.regenerate_icons()
|
||||
H.initialize_vessel()
|
||||
|
||||
// Traitgenes Moved breathing equipment to AFTER the genes set it
|
||||
//Give breathing equipment if needed
|
||||
if(current_project.breath_type != null && current_project.breath_type != GAS_O2)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/mask/breath(H), slot_wear_mask)
|
||||
@@ -121,25 +47,11 @@
|
||||
if(istype(H.internal,/obj/item/tank) && H.internals)
|
||||
H.internals.icon_state = "internal1"
|
||||
|
||||
//Basically all the VORE stuff
|
||||
H.ooc_notes = current_project.body_oocnotes
|
||||
H.ooc_notes_likes = current_project.body_ooclikes
|
||||
H.ooc_notes_dislikes = current_project.body_oocdislikes
|
||||
H.ooc_notes_favs = current_project.body_oocfavs
|
||||
H.ooc_notes_maybes = current_project.body_oocmaybes
|
||||
H.ooc_notes_style = current_project.body_oocstyle
|
||||
H.flavor_texts = current_project.mydna.flavor.Copy()
|
||||
H.resize(current_project.sizemult, FALSE)
|
||||
H.appearance_flags = current_project.aflags
|
||||
H.weight = current_project.weight
|
||||
if(current_project.speciesname)
|
||||
H.custom_species = current_project.speciesname
|
||||
|
||||
//Suiciding var
|
||||
H.suiciding = 0
|
||||
|
||||
//Making double-sure this is not set
|
||||
H.mind = null
|
||||
//Apply damage
|
||||
set_occupant(H)
|
||||
H.adjustCloneLoss((H.getMaxHealth() - (H.getMaxHealth()))*-0.75)
|
||||
H.Paralyse(4)
|
||||
H.updatehealth()
|
||||
|
||||
//Machine specific stuff at the end
|
||||
update_icon()
|
||||
@@ -147,6 +59,7 @@
|
||||
return 1
|
||||
|
||||
/obj/machinery/clonepod/transhuman/process()
|
||||
var/mob/living/occupant = get_occupant()
|
||||
if(stat & NOPOWER)
|
||||
if(occupant)
|
||||
locked = 0
|
||||
@@ -187,7 +100,7 @@
|
||||
return
|
||||
|
||||
else if((!occupant) || (occupant.loc != src))
|
||||
occupant = null
|
||||
set_occupant(null)
|
||||
if(locked)
|
||||
locked = 0
|
||||
update_icon()
|
||||
@@ -196,13 +109,14 @@
|
||||
return
|
||||
|
||||
/obj/machinery/clonepod/transhuman/get_completion()
|
||||
var/mob/living/occupant = get_occupant()
|
||||
if(occupant)
|
||||
return 100 * ((occupant.health + (occupant.getMaxHealth()))) / (occupant.getMaxHealth() + abs(occupant.getMaxHealth()))
|
||||
return 0
|
||||
|
||||
/obj/machinery/clonepod/transhuman/examine(mob/user, infix, suffix)
|
||||
. = ..()
|
||||
if(occupant)
|
||||
if(get_occupant())
|
||||
var/completion = get_completion()
|
||||
. += "Progress: [round(completion)]% [chat_progress_bar(round(completion), TRUE)]"
|
||||
|
||||
@@ -295,95 +209,16 @@
|
||||
return
|
||||
|
||||
//Get the DNA and generate a new mob
|
||||
var/datum/dna2/record/R = current_project.mydna
|
||||
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src, R.dna.species)
|
||||
if(current_project.locked)
|
||||
if(current_project.ckey)
|
||||
H.resleeve_lock = current_project.ckey
|
||||
else
|
||||
// Ensure even body scans without an attached ckey respect locking
|
||||
H.resleeve_lock = "@badckey"
|
||||
|
||||
//Fix the external organs
|
||||
for(var/part in current_project.limb_data)
|
||||
|
||||
var/status = current_project.limb_data[part]
|
||||
if(status == null) continue //Species doesn't have limb? Child of amputated limb?
|
||||
|
||||
var/obj/item/organ/external/O = H.organs_by_name[part]
|
||||
if(!O) continue //Not an organ. Perhaps another amputation removed it already.
|
||||
|
||||
if(status == 1) //Normal limbs
|
||||
continue
|
||||
else if(status == 0) //Missing limbs
|
||||
O.remove_rejuv()
|
||||
else if(status) //Anything else is a manufacturer
|
||||
O.robotize(status)
|
||||
|
||||
//Then the internal organs
|
||||
for(var/part in current_project.organ_data)
|
||||
|
||||
var/status = current_project.organ_data[part]
|
||||
if(status == null) continue //Species doesn't have organ? Child of missing part?
|
||||
|
||||
var/obj/item/organ/I = H.internal_organs_by_name[part]
|
||||
if(!I) continue//Not an organ. Perhaps external conversion changed it already?
|
||||
|
||||
if(status == 0) //Normal organ
|
||||
continue
|
||||
else if(status == 1) //Assisted organ
|
||||
I.mechassist()
|
||||
else if(status == 2) //Mechanical organ
|
||||
I.robotize()
|
||||
else if(status == 3) //Digital organ
|
||||
I.digitize()
|
||||
|
||||
//Set the name or generate one
|
||||
if(!R.dna.real_name)
|
||||
R.dna.real_name = "synth ([rand(0,999)])"
|
||||
H.real_name = R.dna.real_name
|
||||
|
||||
//Apply DNA
|
||||
qdel_swap(H.dna, R.dna.Clone())
|
||||
H.original_player = current_project.ckey
|
||||
|
||||
//Apply legs
|
||||
H.digitigrade = R.dna.digitigrade // ensure clone mob has digitigrade var set appropriately
|
||||
if(H.dna.digitigrade <> R.dna.digitigrade)
|
||||
H.dna.digitigrade = R.dna.digitigrade // ensure cloned DNA is set appropriately from record??? for some reason it doesn't get set right despite the override to datum/dna/Clone()
|
||||
var/mob/living/carbon/human/H = current_project.produce_human_mob(src,TRUE,FALSE,"synth ([rand(0,999)])")
|
||||
SEND_SIGNAL(H, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
//Apply damage
|
||||
H.adjustBruteLoss(brute_value)
|
||||
H.adjustFireLoss(burn_value)
|
||||
H.updatehealth()
|
||||
|
||||
//Update appearance, remake icons
|
||||
H.UpdateAppearance()
|
||||
H.sync_dna_traits(FALSE) // Traitgenes Sync traits to genetics if needed
|
||||
H.sync_organ_dna()
|
||||
H.regenerate_icons()
|
||||
H.initialize_vessel()
|
||||
|
||||
//Basically all the VORE stuff
|
||||
H.ooc_notes = current_project.body_oocnotes
|
||||
H.ooc_notes_likes = current_project.body_ooclikes
|
||||
H.ooc_notes_dislikes = current_project.body_oocdislikes
|
||||
H.flavor_texts = current_project.mydna.flavor.Copy()
|
||||
H.resize(current_project.sizemult)
|
||||
H.appearance_flags = current_project.aflags
|
||||
H.weight = current_project.weight
|
||||
if(current_project.speciesname)
|
||||
H.custom_species = current_project.speciesname
|
||||
|
||||
//Suiciding var
|
||||
H.suiciding = 0
|
||||
|
||||
//Making double-sure this is not set
|
||||
H.mind = null
|
||||
|
||||
//Plonk them here.
|
||||
H.regenerate_icons()
|
||||
H.loc = get_turf(src)
|
||||
H.forceMove(get_turf(src))
|
||||
|
||||
//Machine specific stuff at the end
|
||||
stored_material[MAT_STEEL] -= body_cost
|
||||
@@ -459,7 +294,7 @@
|
||||
var/blur_amount
|
||||
var/confuse_amount
|
||||
|
||||
var/mob/living/carbon/human/occupant = null
|
||||
VAR_PRIVATE/datum/weakref/weakref_occupant = null
|
||||
var/connected = null
|
||||
|
||||
var/sleevecards = 2
|
||||
@@ -476,6 +311,18 @@
|
||||
RefreshParts()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/transhuman/resleever/proc/set_occupant(var/mob/living/carbon/human/H)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
if(!H)
|
||||
weakref_occupant = null
|
||||
return
|
||||
weakref_occupant = WEAKREF(H)
|
||||
|
||||
/obj/machinery/transhuman/resleever/proc/get_occupant()
|
||||
RETURN_TYPE(/mob/living/carbon/human)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
return weakref_occupant?.resolve()
|
||||
|
||||
/obj/machinery/transhuman/resleever/RefreshParts()
|
||||
var/scan_rating = 0
|
||||
for(var/obj/item/stock_parts/scanning_module/SM in component_parts)
|
||||
@@ -502,14 +349,15 @@
|
||||
/obj/machinery/transhuman/resleever/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["occupied"] = !!occupant
|
||||
if(occupant)
|
||||
data["name"] = occupant.name
|
||||
data["health"] = occupant.health
|
||||
data["maxHealth"] = occupant.getMaxHealth()
|
||||
data["stat"] = occupant.stat
|
||||
data["mindStatus"] = !!occupant.mind
|
||||
data["mindName"] = occupant.mind?.name
|
||||
var/mob/living/carbon/human/H = get_occupant()
|
||||
data["occupied"] = !!H
|
||||
if(H)
|
||||
data["name"] = H.name
|
||||
data["health"] = H.health
|
||||
data["maxHealth"] = H.getMaxHealth()
|
||||
data["stat"] = H.stat
|
||||
data["mindStatus"] = !!H.mind
|
||||
data["mindName"] = H.mind?.name
|
||||
return data
|
||||
|
||||
/obj/machinery/transhuman/resleever/attackby(obj/item/W, mob/user)
|
||||
@@ -572,6 +420,7 @@
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/machinery/transhuman/resleever/proc/putmind(var/datum/transhuman/mind_record/MR, mode = 1, var/mob/living/carbon/human/override = null, var/db_key)
|
||||
var/mob/living/carbon/human/occupant = get_occupant()
|
||||
if((!occupant || !istype(occupant) || occupant.stat >= DEAD) && mode == 1)
|
||||
return 0
|
||||
|
||||
@@ -654,13 +503,14 @@
|
||||
return 1
|
||||
|
||||
/obj/machinery/transhuman/resleever/proc/go_out(var/mob/M)
|
||||
if(!( src.occupant ))
|
||||
var/mob/living/carbon/human/occupant = get_occupant()
|
||||
if(!occupant)
|
||||
return
|
||||
if (src.occupant.client)
|
||||
src.occupant.client.eye = src.occupant.client.mob
|
||||
src.occupant.client.perspective = MOB_PERSPECTIVE
|
||||
src.occupant.loc = src.loc
|
||||
src.occupant = null
|
||||
if (occupant.client)
|
||||
occupant.client.eye = occupant.client.mob
|
||||
occupant.client.perspective = MOB_PERSPECTIVE
|
||||
occupant.forceMove(get_turf(src))
|
||||
set_occupant(null)
|
||||
icon_state = "implantchair"
|
||||
return
|
||||
|
||||
@@ -668,7 +518,7 @@
|
||||
if(!ishuman(M))
|
||||
to_chat(usr, span_warning("\The [src] cannot hold this!"))
|
||||
return
|
||||
if(src.occupant)
|
||||
if(get_occupant())
|
||||
to_chat(usr, span_warning("\The [src] is already occupied!"))
|
||||
return
|
||||
if(M.client)
|
||||
@@ -676,7 +526,7 @@
|
||||
M.client.eye = src
|
||||
M.stop_pulling()
|
||||
M.loc = src
|
||||
src.occupant = M
|
||||
set_occupant(M)
|
||||
src.add_fingerprint(usr)
|
||||
icon_state = "implantchair_on"
|
||||
return 1
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
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,
|
||||
@@ -60,7 +61,7 @@
|
||||
cam_screen.name = "screen"
|
||||
cam_screen.assigned_map = map_name
|
||||
cam_screen.del_on_map_removal = FALSE
|
||||
cam_screen.screen_loc = "[map_name]:1,1"
|
||||
cam_screen.screen_loc = "[map_name]:3:-32,3:-48"
|
||||
|
||||
cam_plane_masters = get_tgui_plane_masters()
|
||||
|
||||
@@ -83,11 +84,19 @@
|
||||
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()
|
||||
@@ -101,6 +110,11 @@
|
||||
/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
|
||||
@@ -435,9 +449,8 @@
|
||||
if (owner.change_marking_color(mark_datum, marking_color))
|
||||
return TRUE
|
||||
if("rotate_view")
|
||||
if(can_change(owner, APPEARANCE_RACE))
|
||||
owner.set_dir(turn(owner.dir, 90))
|
||||
return TRUE
|
||||
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")
|
||||
@@ -465,35 +478,30 @@
|
||||
owner.custom_species = new_name
|
||||
return TRUE
|
||||
if("base_icon")
|
||||
if(owner.species.selects_bodytype == SELECTS_BODYTYPE_FALSE)
|
||||
var/datum/species/S = GLOB.all_species[owner.species.name]
|
||||
owner.species.base_species = S.base_species // Return to original form
|
||||
generate_data(ui.user, owner)
|
||||
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
|
||||
return TRUE
|
||||
var/list/choices
|
||||
var/datum/species/S = GLOB.all_species[owner.species.name]
|
||||
if(S.selects_bodytype == SELECTS_BODYTYPE_SHAPESHIFTER)
|
||||
choices = S.get_valid_shapeshifter_forms()
|
||||
else if(S.selects_bodytype == SELECTS_BODYTYPE_CUSTOM)
|
||||
choices = GLOB.custom_species_bases
|
||||
var/new_species = tgui_input_list(ui.user, "Please select basic shape.", "Body Shape", choices)
|
||||
if(new_species && can_change(owner, APPEARANCE_RACE))
|
||||
owner.species.base_species = new_species
|
||||
owner.regenerate_icons()
|
||||
generate_data(ui.user, owner)
|
||||
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
|
||||
return TRUE
|
||||
if("blood_reagent")
|
||||
var/new_blood_reagents = tgui_input_list(ui.user, "Please select blood restoration reagent:", "Character Preference", valid_bloodreagents)
|
||||
if(new_blood_reagents && can_change(owner, APPEARANCE_RACE))
|
||||
owner.dna.blood_reagents = new_blood_reagents
|
||||
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
|
||||
return TRUE
|
||||
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 marking color", "Marking color", current)
|
||||
if(blood_col && can_change(owner, APPEARANCE_RACE))
|
||||
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
|
||||
@@ -501,9 +509,9 @@
|
||||
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_RACE))
|
||||
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 && can_change(owner, APPEARANCE_RACE))
|
||||
if(unit_of_measurement)
|
||||
if(unit_of_measurement == "Pounds")
|
||||
new_weight = round(text2num(new_weight),4)
|
||||
if(unit_of_measurement == "Kilograms")
|
||||
@@ -513,7 +521,7 @@
|
||||
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_RACE))
|
||||
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()
|
||||
@@ -521,21 +529,21 @@
|
||||
changed_hook(APPEARANCECHANGER_CHANGED_RACE)
|
||||
return TRUE
|
||||
if("scale_appearance")
|
||||
if(can_change(owner, APPEARANCE_RACE))
|
||||
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_RACE))
|
||||
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_RACE))
|
||||
if(can_change(owner, APPEARANCE_MISC))
|
||||
owner.dna.digitigrade = !owner.dna.digitigrade
|
||||
owner.digitigrade = owner.dna.digitigrade
|
||||
owner.regenerate_icons()
|
||||
@@ -545,28 +553,37 @@
|
||||
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_RACE))
|
||||
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_RACE))
|
||||
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_RACE)) // allows empty to wipe flavor
|
||||
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_RACE)) // allows empty to wipe flavor
|
||||
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
|
||||
// ***********************************
|
||||
@@ -618,6 +635,7 @@
|
||||
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])"
|
||||
@@ -660,6 +678,7 @@
|
||||
// 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()
|
||||
@@ -747,6 +766,7 @@
|
||||
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)
|
||||
@@ -790,6 +810,8 @@
|
||||
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"])
|
||||
@@ -873,7 +895,7 @@
|
||||
local_skybox.cut_overlays()
|
||||
|
||||
/datum/tgui_module/appearance_changer/proc/update_dna(mob/living/carbon/human/target)
|
||||
if(target && (flags & APPEARANCE_UPDATE_DNA))
|
||||
if(target)
|
||||
target.update_dna()
|
||||
|
||||
/datum/tgui_module/appearance_changer/proc/can_change(mob/living/carbon/human/target, var/flag)
|
||||
@@ -1038,7 +1060,7 @@
|
||||
// *******************************************************
|
||||
/datum/tgui_module/appearance_changer/cocoon
|
||||
name ="Appearance Editor (Cocoon)"
|
||||
flags = APPEARANCE_ALL_HAIR | APPEARANCE_EYE_COLOR | APPEARANCE_SKIN
|
||||
flags = APPEARANCE_ALL_COSMETIC
|
||||
customize_usr = TRUE
|
||||
|
||||
/datum/tgui_module/appearance_changer/cocoon/tgui_status(mob/user, datum/tgui_state/state)
|
||||
@@ -1051,7 +1073,7 @@
|
||||
// *******************************************************
|
||||
/datum/tgui_module/appearance_changer/superpower
|
||||
name ="Appearance Editor (Superpower)"
|
||||
flags = APPEARANCE_ALL_HAIR | APPEARANCE_EYE_COLOR | APPEARANCE_SKIN
|
||||
flags = APPEARANCE_ALL_COSMETIC
|
||||
customize_usr = TRUE
|
||||
|
||||
/datum/tgui_module/appearance_changer/superpower/tgui_status(mob/user, datum/tgui_state/state)
|
||||
@@ -1060,6 +1082,19 @@
|
||||
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
|
||||
// *******************************************************
|
||||
@@ -1097,52 +1132,10 @@
|
||||
if(owner)
|
||||
UnregisterSignal(owner, COMSIG_OBSERVER_MOVED)
|
||||
qdel_null(owner)
|
||||
//Get the DNA and generate a new mob
|
||||
var/datum/dna2/record/R = current_project.mydna
|
||||
owner = new /mob/living/carbon/human(src, R.dna.species)
|
||||
//Fix the external organs
|
||||
for(var/part in current_project.limb_data)
|
||||
var/status = current_project.limb_data[part]
|
||||
if(status == null) continue //Species doesn't have limb? Child of amputated limb?
|
||||
var/obj/item/organ/external/O = owner.organs_by_name[part]
|
||||
if(!O) continue //Not an organ. Perhaps another amputation removed it already.
|
||||
if(status == 1) //Normal limbs
|
||||
continue
|
||||
else if(status == 0) //Missing limbs
|
||||
O.remove_rejuv()
|
||||
else if(status) //Anything else is a manufacturer
|
||||
O.remove_rejuv() //Don't robotize them, leave them removed so robotics can attach a part.
|
||||
for(var/part in current_project.organ_data)
|
||||
var/status = current_project.organ_data[part]
|
||||
if(status == null) continue //Species doesn't have organ? Child of missing part?
|
||||
var/obj/item/organ/I = owner.internal_organs_by_name[part]
|
||||
if(!I) continue//Not an organ. Perhaps external conversion changed it already?
|
||||
if(status == 0) //Normal organ
|
||||
continue
|
||||
else if(status == 1) //Assisted organ
|
||||
I.mechassist()
|
||||
else if(status == 2) //Mechanical organ
|
||||
I.robotize()
|
||||
else if(status == 3) //Digital organ
|
||||
I.digitize()
|
||||
//Set the name or generate one
|
||||
owner.real_name = R.dna.real_name
|
||||
owner.name = owner.real_name
|
||||
//Apply DNA
|
||||
owner.dna = R.dna.Clone()
|
||||
owner.original_player = current_project.ckey
|
||||
//Apply legs
|
||||
owner.digitigrade = R.dna.digitigrade // ensure clone mob has digitigrade var set appropriately
|
||||
if(owner.dna.digitigrade <> R.dna.digitigrade)
|
||||
owner.dna.digitigrade = R.dna.digitigrade // ensure cloned DNA is set appropriately from record??? for some reason it doesn't get set right despite the override to datum/dna/Clone()
|
||||
//Update appearance, remake icons
|
||||
owner.UpdateAppearance()
|
||||
owner.sync_dna_traits(FALSE)
|
||||
owner.sync_organ_dna()
|
||||
owner.initialize_vessel()
|
||||
owner.dna.blood_reagents = R.dna.blood_reagents
|
||||
owner.dna.blood_color = R.dna.blood_color
|
||||
owner.regenerate_icons()
|
||||
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
|
||||
|
||||
@@ -169,12 +169,12 @@ Please do not abuse this ability.
|
||||
var/datum/language/keylang = GLOB.all_languages[prey.prefs.language_custom_keys[key]]
|
||||
if(keylang)
|
||||
new_character.language_keys[key] = keylang
|
||||
// VOREStation Add: Preferred Language Setting;
|
||||
if(prey.prefs.preferred_language) // Do we have a preferred language?
|
||||
var/datum/language/def_lang = GLOB.all_languages[prey.prefs.preferred_language]
|
||||
if(def_lang)
|
||||
new_character.default_language = def_lang
|
||||
// VOREStation Add End
|
||||
|
||||
SEND_SIGNAL(new_character, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
new_character.regenerate_icons()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user