mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-09 16:12:17 +00:00
[MIRROR] Dna, Bodyrecord, Xenochi Revive Refactor (#11038)
Co-authored-by: Will <7099514+Willburd@users.noreply.github.com> Co-authored-by: Cameron Lennox <killer65311@gmail.com>
This commit is contained in:
committed by
GitHub
parent
48b3e8f772
commit
75e167a92f
@@ -593,6 +593,8 @@
|
||||
#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit"
|
||||
///Whenever EquipRanked is called, called after job is set
|
||||
#define COMSIG_JOB_RECEIVED "job_received"
|
||||
///When the mob's dna and species have been fully applied
|
||||
#define COMSIG_HUMAN_DNA_FINALIZED "human_dna_finished"
|
||||
|
||||
// /datum/species signals
|
||||
|
||||
|
||||
@@ -103,8 +103,8 @@ var/SMALLSIZEBLOCK = 0
|
||||
#define DNA_UI_GENDER 14
|
||||
#define DNA_UI_BEARD_STYLE 15
|
||||
#define DNA_UI_HAIR_STYLE 16
|
||||
#define DNA_UI_EAR_STYLE 17 // VOREStation snippet.
|
||||
#define DNA_UI_EAR_SECONDARY_STYLE 18 // VOREStation snippet.
|
||||
#define DNA_UI_EAR_STYLE 17
|
||||
#define DNA_UI_EAR_SECONDARY_STYLE 18
|
||||
#define DNA_UI_TAIL_STYLE 19
|
||||
#define DNA_UI_PLAYERSCALE 20
|
||||
#define DNA_UI_TAIL_R 21
|
||||
@@ -152,9 +152,14 @@ var/SMALLSIZEBLOCK = 0
|
||||
#define DNA_UI_WING2_B 57
|
||||
#define DNA_UI_WING3_R 58
|
||||
#define DNA_UI_WING3_G 59
|
||||
#define DNA_UI_WING3_B 60 // VOREStation snippet end.
|
||||
#define DNA_UI_WING3_B 60
|
||||
#define DNA_UI_WING_ALPHA 61
|
||||
#define DNA_UI_LENGTH 61 // VOREStation Edit - Needs to match the highest number above.
|
||||
#define DNA_UI_GRAD_STYLE 62
|
||||
#define DNA_UI_GRAD_R 63
|
||||
#define DNA_UI_GRAD_G 64
|
||||
#define DNA_UI_GRAD_B 65
|
||||
// Needs to match the highest number above.
|
||||
#define DNA_UI_LENGTH 65
|
||||
|
||||
#define DNA_SE_LENGTH 90 // Traitgenes (Expanded from 49 to 84, there have been a considerable expansion of genes.
|
||||
// This leaves room for future expansion. This can be arbitrarily raised without worry if genes start to get crowded.
|
||||
|
||||
@@ -96,17 +96,18 @@
|
||||
#define ROBOT_NOTIFICATION_AI_SHELL 5
|
||||
|
||||
// Appearance change flags
|
||||
#define APPEARANCE_UPDATE_DNA 0x1
|
||||
#define APPEARANCE_RACE (0x2|APPEARANCE_UPDATE_DNA)
|
||||
#define APPEARANCE_GENDER (0x4|APPEARANCE_UPDATE_DNA)
|
||||
#define APPEARANCE_SKIN 0x8
|
||||
#define APPEARANCE_HAIR 0x10
|
||||
#define APPEARANCE_HAIR_COLOR 0x20
|
||||
#define APPEARANCE_FACIAL_HAIR 0x40
|
||||
#define APPEARANCE_FACIAL_HAIR_COLOR 0x80
|
||||
#define APPEARANCE_EYE_COLOR 0x100
|
||||
#define APPEARANCE_RACE 0x1
|
||||
#define APPEARANCE_GENDER 0x2
|
||||
#define APPEARANCE_SKIN 0x4
|
||||
#define APPEARANCE_HAIR 0x8
|
||||
#define APPEARANCE_HAIR_COLOR 0x10
|
||||
#define APPEARANCE_FACIAL_HAIR 0x20
|
||||
#define APPEARANCE_FACIAL_HAIR_COLOR 0x40
|
||||
#define APPEARANCE_EYE_COLOR 0x80
|
||||
#define APPEARANCE_ALL_HAIR (APPEARANCE_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR|APPEARANCE_FACIAL_HAIR_COLOR)
|
||||
#define APPEARANCE_ALL 0xFFFF
|
||||
#define APPEARANCE_MISC 0x100
|
||||
#define APPEARANCE_ALL_COSMETIC (APPEARANCE_GENDER|APPEARANCE_SKIN|APPEARANCE_ALL_HAIR|APPEARANCE_EYE_COLOR|APPEARANCE_MISC)
|
||||
#define APPEARANCE_ALL 0xFFFF
|
||||
|
||||
// Click cooldown
|
||||
#define DEFAULT_ATTACK_COOLDOWN 8 //Default timeout for aggressive actions
|
||||
|
||||
2
code/__defines/var_copy.dm
Normal file
2
code/__defines/var_copy.dm
Normal file
@@ -0,0 +1,2 @@
|
||||
/// Use this when copying vars[] to skip some built in byond ones that get really unhappy when you access them like that. Used like if(BLACKLISTED_COPY_VARS) in switch or list(BLACKLISTED_COPY_VARS)
|
||||
#define BLACKLISTED_COPY_VARS "ATOM_TOPIC_EXAMINE","type","loc","locs","vars","parent","parent_type","verbs","ckey","key","_active_timers", "_datum_components", "_listen_lookup", "_signal_procs"
|
||||
@@ -308,7 +308,9 @@ GLOBAL_LIST_EMPTY(mannequins)
|
||||
*/
|
||||
|
||||
// Custom species icon bases
|
||||
var/list/blacklisted_icons = list(SPECIES_CUSTOM,SPECIES_PROMETHEAN) //VOREStation Edit
|
||||
///These are icons that you DO NOT want to be selectable!
|
||||
var/list/blacklisted_icons = list(SPECIES_CUSTOM,SPECIES_PROMETHEAN)
|
||||
///These are icons that you WANT to be selectable, even if they're a whitelist species!
|
||||
var/list/whitelisted_icons = list(SPECIES_FENNEC,SPECIES_XENOHYBRID,SPECIES_VOX,SPECIES_SHADEKIN) //CHOMPedit
|
||||
for(var/species_name in GLOB.playable_species)
|
||||
if(species_name in blacklisted_icons)
|
||||
|
||||
@@ -861,22 +861,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
||||
else
|
||||
O=new original.type(locate(0,0,0))
|
||||
|
||||
var/static/list/blacklisted_var_names = list(
|
||||
"ATOM_TOPIC_EXAMINE",
|
||||
"type",
|
||||
"loc",
|
||||
"locs",
|
||||
"vars",
|
||||
"parent",
|
||||
"parent_type",
|
||||
"verbs",
|
||||
"ckey",
|
||||
"key",
|
||||
"_active_timers", // ChompEDIT - blacklist timers
|
||||
"_datum_components", // ChompEDIT - blacklist DCS
|
||||
"_listen_lookup", // ChompEDIT - blacklist signal listeners
|
||||
"_signal_procs" // ChompEDIT - blacklist signal procs
|
||||
)
|
||||
var/static/list/blacklisted_var_names = list(BLACKLISTED_COPY_VARS)
|
||||
if(perfectcopy)
|
||||
if((O) && (original))
|
||||
for(var/V in original.vars)
|
||||
|
||||
@@ -1,31 +1,43 @@
|
||||
/datum/component/xenochimera
|
||||
var/laststress = 0
|
||||
var/mob/living/carbon/human/owner
|
||||
VAR_PRIVATE/laststress = 0
|
||||
VAR_PRIVATE/mob/living/carbon/human/owner
|
||||
var/feral = 0
|
||||
var/revive_ready = REVIVING_READY
|
||||
var/revive_finished = FALSE
|
||||
var/regen_sounds = list(
|
||||
VAR_PRIVATE/regen_sounds = list(
|
||||
'sound/effects/mob_effects/xenochimera/regen_1.ogg',
|
||||
'sound/effects/mob_effects/xenochimera/regen_2.ogg',
|
||||
'sound/effects/mob_effects/xenochimera/regen_4.ogg',
|
||||
'sound/effects/mob_effects/xenochimera/regen_3.ogg',
|
||||
'sound/effects/mob_effects/xenochimera/regen_5.ogg'
|
||||
)
|
||||
VAR_PRIVATE/datum/transhuman/body_record/revival_record
|
||||
|
||||
/datum/component/xenochimera/Initialize()
|
||||
if(!ishuman(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
owner = parent
|
||||
RegisterSignal(owner, COMSIG_XENOCHIMERA_COMPONENT, PROC_REF(handle_comp))
|
||||
RegisterSignal(owner, COMSIG_HUMAN_DNA_FINALIZED, PROC_REF(handle_record))
|
||||
add_verb(owner, /mob/living/carbon/human/proc/reconstitute_form)
|
||||
|
||||
/datum/component/xenochimera/Destroy(force)
|
||||
UnregisterSignal(owner, COMSIG_XENOCHIMERA_COMPONENT)
|
||||
UnregisterSignal(owner, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
remove_verb(owner, /mob/living/carbon/human/proc/reconstitute_form)
|
||||
qdel_null(revival_record)
|
||||
owner = null
|
||||
. = ..()
|
||||
|
||||
/datum/component/xenochimera/proc/handle_record()
|
||||
SIGNAL_HANDLER
|
||||
if(QDELETED(owner))
|
||||
return
|
||||
qdel_null(revival_record)
|
||||
revival_record = new(owner)
|
||||
|
||||
/datum/component/xenochimera/proc/handle_comp()
|
||||
SIGNAL_HANDLER
|
||||
if(QDELETED(owner))
|
||||
return
|
||||
handle_feralness()
|
||||
@@ -42,6 +54,19 @@
|
||||
if(!owner.lying)
|
||||
owner.lay_down()
|
||||
|
||||
/datum/component/xenochimera/proc/set_revival_delay(var/time)
|
||||
revive_ready = REVIVING_NOW
|
||||
revive_finished = (world.time + time SECONDS) // When do we finish reviving? Allows us to find out when we're done, called by the alert currently.
|
||||
|
||||
/datum/component/xenochimera/proc/trigger_revival(var/from_save_slot)
|
||||
ASSERT(revival_record)
|
||||
if(owner.isSynthetic())
|
||||
revival_record.revive_xenochimera(owner,TRUE,from_save_slot)
|
||||
else
|
||||
revival_record.revive_xenochimera(owner,FALSE,from_save_slot)
|
||||
if(from_save_slot)
|
||||
handle_record() // Update record
|
||||
|
||||
/datum/component/xenochimera/proc/handle_feralness()
|
||||
//first, calculate how stressed the chimera is
|
||||
|
||||
@@ -254,103 +279,102 @@
|
||||
/mob/living/carbon/human/proc/reconstitute_form() //Scree's race ability.in exchange for: No cloning.
|
||||
set name = "Reconstitute Form"
|
||||
set category = "Abilities.Xenochimera"
|
||||
|
||||
var/datum/component/xenochimera/xc = get_xenochimera_component()
|
||||
if(!xc)
|
||||
return
|
||||
if(is_incorporeal())
|
||||
to_chat(src, "You cannot regenerate while incorporeal.")
|
||||
return
|
||||
// Sanity is mostly handled in chimera_regenerate()
|
||||
if(stat == DEAD)
|
||||
var/confirm = tgui_alert(src, "Are you sure you want to regenerate your corpse? This process can take up to thirty minutes.", "Confirm Regeneration", list("Yes", "No"))
|
||||
var/confirm = tgui_alert(src, "Are you sure you want to regenerate your corpse? This process can take up to thirty minutes. Additionally, you may regenerate your appearance based on your current form or the appearance of the currently loaded slot.", "Confirm Regeneration", list("Yes", "No"))
|
||||
if(confirm == "Yes")
|
||||
chimera_regenerate()
|
||||
else if (quickcheckuninjured())
|
||||
var/confirm = tgui_alert(src, "Are you sure you want to regenerate? As you are uninjured this will only take 30 seconds and match your appearance to your character slot.", "Confirm Regeneration", list("Yes", "No"))
|
||||
xc.chimera_regenerate()
|
||||
else if(quickcheckuninjured())
|
||||
var/confirm = tgui_alert(src, "Are you sure you want to regenerate? As you are uninjured this will only take 30 seconds. Additionally, you may regenerate your appearance based on your current form or the appearance of the currently loaded slot.", "Confirm Regeneration", list("Yes", "No"))
|
||||
if(confirm == "Yes")
|
||||
chimera_regenerate()
|
||||
xc.chimera_regenerate()
|
||||
else
|
||||
var/confirm = tgui_alert(src, "Are you sure you want to completely reconstruct your form? This process can take up to fifteen minutes, depending on how hungry you are, and you will be unable to move.", "Confirm Regeneration", list("Yes", "No"))
|
||||
var/confirm = tgui_alert(src, "Are you sure you want to completely reconstruct your form? This process can take up to fifteen minutes, depending on how hungry you are, and you will be unable to move. Additionally, you may regenerate your appearance based on your current form or the appearance of the currently loaded slot", "Confirm Regeneration", list("Yes", "No"))
|
||||
if(confirm == "Yes")
|
||||
chimera_regenerate()
|
||||
xc.chimera_regenerate()
|
||||
|
||||
/mob/living/carbon/human/proc/chimera_regenerate()
|
||||
var/datum/component/xenochimera/xc = get_xenochimera_component()
|
||||
if(!xc)
|
||||
/datum/component/xenochimera/proc/chimera_regenerate()
|
||||
if(!owner)
|
||||
return
|
||||
//If they're already regenerating
|
||||
switch(xc.revive_ready)
|
||||
switch(revive_ready)
|
||||
if(REVIVING_NOW)
|
||||
to_chat(src, "You are already reconstructing, just wait for the reconstruction to finish!")
|
||||
to_chat(owner, "You are already reconstructing, just wait for the reconstruction to finish!")
|
||||
return
|
||||
if(REVIVING_DONE)
|
||||
to_chat(src, "Your reconstruction is done, but you need to hatch now.")
|
||||
to_chat(owner, "Your reconstruction is done, but you need to hatch now.")
|
||||
return
|
||||
if(xc.revive_ready > world.time)
|
||||
to_chat(src, "You can't use that ability again so soon!")
|
||||
if(revive_ready > world.time)
|
||||
to_chat(owner, "You can't use that ability again so soon!")
|
||||
return
|
||||
|
||||
var/time = min(900, (120+780/(1 + nutrition/100))) //capped at 15 mins, roughly 6 minutes at 250 (yellow) nutrition, 4.1 minutes at 500 (grey), cannot be below 2 mins
|
||||
if (quickcheckuninjured()) //if you're completely uninjured, then you get a speedymode - check health first for quickness
|
||||
var/time = min(900, (120+780/(1 + owner.nutrition/100))) //capped at 15 mins, roughly 6 minutes at 250 (yellow) nutrition, 4.1 minutes at 500 (grey), cannot be below 2 mins
|
||||
if (owner.quickcheckuninjured()) //if you're completely uninjured, then you get a speedymode - check health first for quickness
|
||||
time = 30
|
||||
|
||||
//Clicked regen while dead.
|
||||
if(stat == DEAD)
|
||||
if(owner.stat == DEAD)
|
||||
|
||||
//reviving from dead takes extra nutriment to be provided from outside OR takes twice as long and consumes extra at the end
|
||||
if(!hasnutriment())
|
||||
if(!owner.hasnutriment())
|
||||
time = time*2
|
||||
|
||||
to_chat(src, "You begin to reconstruct your form. You will not be able to move during this time. It should take aproximately [round(time)] seconds.")
|
||||
to_chat(owner, "You begin to reconstruct your form. You will not be able to move during this time. It should take aproximately [round(time)] seconds.")
|
||||
|
||||
//Scary spawnerization.
|
||||
xc.revive_ready = REVIVING_NOW
|
||||
xc.revive_finished = (world.time + time SECONDS) // When do we finish reviving? Allows us to find out when we're done, called by the alert currently.
|
||||
throw_alert("regen", /obj/screen/alert/xenochimera/reconstitution)
|
||||
set_revival_delay(time)
|
||||
owner.throw_alert("regen", /obj/screen/alert/xenochimera/reconstitution)
|
||||
addtimer(CALLBACK(src, PROC_REF(chimera_regenerate_ready)), time SECONDS, TIMER_DELETE_ME)
|
||||
|
||||
//Clicked regen while NOT dead
|
||||
else
|
||||
to_chat(src, "You begin to reconstruct your form. You will not be able to move during this time. It should take aproximately [round(time)] seconds.")
|
||||
to_chat(owner, "You begin to reconstruct your form. You will not be able to move during this time. It should take aproximately [round(time)] seconds.")
|
||||
|
||||
//Waiting for regen after being alive
|
||||
xc.revive_ready = REVIVING_NOW
|
||||
xc.revive_finished = (world.time + time SECONDS) // When do we finish reviving? Allows us to find out when we're done, called by the alert currently.
|
||||
throw_alert("regen", /obj/screen/alert/xenochimera/reconstitution)
|
||||
set_revival_delay(time)
|
||||
owner.throw_alert("regen", /obj/screen/alert/xenochimera/reconstitution)
|
||||
addtimer(CALLBACK(src, PROC_REF(chimera_regenerate_nutrition)), time SECONDS, TIMER_DELETE_ME)
|
||||
owner.lying = TRUE
|
||||
// open_appearance_editor()
|
||||
|
||||
/mob/living/carbon/human/proc/chimera_regenerate_nutrition()
|
||||
var/datum/component/xenochimera/xc = get_xenochimera_component()
|
||||
if(!xc)
|
||||
/datum/component/xenochimera/proc/chimera_regenerate_nutrition()
|
||||
if(!owner)
|
||||
return
|
||||
//Slightly different flavour messages
|
||||
if(stat != DEAD || hasnutriment())
|
||||
to_chat(src, span_notice("Consciousness begins to stir as your new body awakens, ready to hatch.."))
|
||||
if(owner.stat != DEAD || owner.hasnutriment())
|
||||
to_chat(owner, span_notice("Consciousness begins to stir as your new body awakens, ready to hatch.."))
|
||||
else
|
||||
to_chat(src, span_warning("Consciousness begins to stir as your battered body struggles to recover from its ordeal.."))
|
||||
add_verb(src, /mob/living/carbon/human/proc/hatch)
|
||||
xc.revive_ready = REVIVING_DONE
|
||||
src << sound('sound/effects/mob_effects/xenochimera/hatch_notification.ogg',0,0,0,30)
|
||||
clear_alert("regen")
|
||||
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
|
||||
to_chat(owner, span_warning("Consciousness begins to stir as your battered body struggles to recover from its ordeal.."))
|
||||
add_verb(owner, /mob/living/carbon/human/proc/hatch)
|
||||
revive_ready = REVIVING_DONE
|
||||
owner << sound('sound/effects/mob_effects/xenochimera/hatch_notification.ogg',0,0,0,30)
|
||||
owner.clear_alert("regen")
|
||||
owner.throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
|
||||
|
||||
/mob/living/carbon/human/proc/chimera_regenerate_ready()
|
||||
var/datum/component/xenochimera/xc = get_xenochimera_component()
|
||||
if(!xc)
|
||||
/datum/component/xenochimera/proc/chimera_regenerate_ready()
|
||||
if(!owner)
|
||||
return
|
||||
// check to see if they've been fixed by outside forces in the meantime such as defibbing
|
||||
if(stat != DEAD)
|
||||
to_chat(src, span_notice("Your body has recovered from its ordeal, ready to regenerate itself again."))
|
||||
xc.revive_ready = REVIVING_READY //reset their cooldown
|
||||
clear_alert("regen")
|
||||
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
|
||||
if(owner.stat != DEAD)
|
||||
to_chat(owner, span_notice("Your body has recovered from its ordeal, ready to regenerate itself again."))
|
||||
revive_ready = REVIVING_READY //reset their cooldown
|
||||
owner.clear_alert("regen")
|
||||
owner.throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
|
||||
|
||||
// Was dead, still dead.
|
||||
else
|
||||
to_chat(src, span_notice("Consciousness begins to stir as your new body awakens, ready to hatch."))
|
||||
add_verb(src, /mob/living/carbon/human/proc/hatch)
|
||||
xc.revive_ready = REVIVING_DONE
|
||||
src << sound('sound/effects/mob_effects/xenochimera/hatch_notification.ogg',0,0,0,30)
|
||||
clear_alert("regen")
|
||||
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
|
||||
to_chat(owner, span_notice("Consciousness begins to stir as your new body awakens, ready to hatch."))
|
||||
add_verb(owner, /mob/living/carbon/human/proc/hatch)
|
||||
revive_ready = REVIVING_DONE
|
||||
owner << sound('sound/effects/mob_effects/xenochimera/hatch_notification.ogg',0,0,0,30)
|
||||
owner.clear_alert("regen")
|
||||
owner.throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
|
||||
|
||||
/mob/living/carbon/human/proc/hatch()
|
||||
set name = "Hatch"
|
||||
@@ -359,71 +383,95 @@
|
||||
if(!xc)
|
||||
return
|
||||
if(xc.revive_ready != REVIVING_DONE)
|
||||
//Hwhat?
|
||||
remove_verb(src, /mob/living/carbon/human/proc/hatch)
|
||||
return
|
||||
return //Hwhat?
|
||||
|
||||
var/confirm = tgui_alert(src, "Are you sure you want to hatch right now? This will be very obvious to anyone in view.", "Confirm Regeneration", list("Yes", "No"))
|
||||
// Default is use internal record, even if closes menu
|
||||
var/reload_slot = tgui_alert(src, "Regenerate from your current form, or from the appearance of your current character slot(This will not change your current species or traits.)", "Regenerate Form", list("Current Form", "From Slot"))
|
||||
|
||||
// Check if valid to load from this slot
|
||||
var/from_slot = ""
|
||||
from_slot = "You'll hatch using your current appearance"
|
||||
if(reload_slot == "From Slot" && client)
|
||||
if(client.prefs.species == SPECIES_PROTEAN) // Exploit protection
|
||||
to_chat(src,span_warning("You cannot copy nanoform prosthetic limbs from this species. Please try another character."))
|
||||
return
|
||||
var/slot_is_synth = ((O_BRAIN in client.prefs.organ_data) && client.prefs.organ_data[O_BRAIN])
|
||||
if(slot_is_synth && !isSynthetic()) // Prevents some pretty weird situations
|
||||
to_chat(src,span_warning("Cannot apply character appearance. [slot_is_synth ? "The slot's character is synthetic." : "The slot's character is organic."] Slot must match the current body's synthetic state. Please try another character."))
|
||||
return
|
||||
from_slot = "You'll hatch using [client.prefs.real_name]'s appearance"
|
||||
|
||||
var/confirm = tgui_alert(src, "Are you sure you want to hatch right now? This will be very obvious to anyone in view. [from_slot]! Are you sure?", "Confirm Regeneration", list("Yes", "No"))
|
||||
if(confirm == "Yes")
|
||||
|
||||
///This makes xenochimera shoot out their robotic limbs if they're not a FBP.
|
||||
if(!isSynthetic()) //If we aren't repairing robotic limbs (FBP) we reject any robot limbs we have and kick them out!
|
||||
for(var/O in organs_by_name)
|
||||
var/obj/item/organ/external/organ = organs_by_name[O]
|
||||
if(!istype(organ, /obj/item/organ/external))
|
||||
continue
|
||||
if(!organ.robotic)
|
||||
continue
|
||||
else
|
||||
organ.removed()
|
||||
///End of xenochimera limb rejection code.
|
||||
|
||||
//Dead when hatching
|
||||
//var/sickness_duration = 10 MINUTES //CHOMPedit
|
||||
var/has_braindamage = FALSE
|
||||
if(stat == DEAD)
|
||||
// var/sickness_duration = 10 MINUTES //CHOMPedit
|
||||
//Reviving from ded takes extra nutrition - if it isn't provided from outside sources, it comes from you
|
||||
if(!hasnutriment())
|
||||
nutrition=nutrition * 0.75
|
||||
// sickness_duration = 20 MINUTES //CHOMPedit
|
||||
chimera_hatch()
|
||||
// add_modifier(/datum/modifier/resleeving_sickness/chimera, sickness_duration) //CHOMPedit
|
||||
//sickness_duration = 20 MINUTES //CHOMPedit
|
||||
has_braindamage = TRUE
|
||||
|
||||
// Finalize!
|
||||
remove_verb(src, /mob/living/carbon/human/proc/hatch)
|
||||
clear_alert("hatch")
|
||||
xc.chimera_hatch((reload_slot == "From Slot" && client))
|
||||
visible_message(span_warning(span_huge("[src] rises to \his feet."))) //Bloody hell...
|
||||
if(has_braindamage)
|
||||
//add_modifier(/datum/modifier/resleeving_sickness/chimera, sickness_duration) //CHOMPedit
|
||||
adjustBrainLoss(5) // if they're reviving from dead, they come back with 5 brainloss on top of whatever's unhealed.
|
||||
visible_message(span_warning("<p>" + span_huge("The former corpse staggers to its feet, all its former wounds having vanished...") + "</p>")) //Bloody hell...
|
||||
clear_alert("hatch")
|
||||
return
|
||||
|
||||
//Alive when hatching
|
||||
else
|
||||
chimera_hatch()
|
||||
|
||||
visible_message(span_warning("<p>" + span_huge("[src] rises to \his feet.") + "</p>")) //Bloody hell...
|
||||
clear_alert("hatch")
|
||||
|
||||
/mob/living/carbon/human/proc/chimera_hatch()
|
||||
var/datum/component/xenochimera/xc = get_xenochimera_component()
|
||||
if(!xc)
|
||||
/datum/component/xenochimera/proc/chimera_hatch(var/from_save_slot)
|
||||
if(!owner)
|
||||
return
|
||||
remove_verb(src, /mob/living/carbon/human/proc/hatch)
|
||||
to_chat(src, span_notice("Your new body awakens, bursting free from your old skin."))
|
||||
|
||||
remove_verb(owner, /mob/living/carbon/human/proc/hatch)
|
||||
to_chat(owner, span_notice("Your new body awakens, bursting free from your old skin."))
|
||||
//Modify and record values (half nutrition and braindamage)
|
||||
var/old_nutrition = nutrition
|
||||
var/braindamage = min(5, max(0, (brainloss-1) * 0.5)) //brainloss is tricky to heal and might take a couple of goes to get rid of completely.
|
||||
var/uninjured=quickcheckuninjured()
|
||||
//I did have special snowflake code, but this is easier. //It's also EXTREMELY BAD AND LETS THEM SAVEFILE HACK.
|
||||
revive()
|
||||
mutations.Remove(HUSK)
|
||||
setBrainLoss(braindamage)
|
||||
species.update_vore_belly_def_variant()
|
||||
var/old_nutrition = owner.nutrition
|
||||
var/braindamage = min(5, max(0, (owner.brainloss-1) * 0.5)) //brainloss is tricky to heal and might take a couple of goes to get rid of completely.
|
||||
var/uninjured=owner.quickcheckuninjured()
|
||||
trigger_revival(from_save_slot)
|
||||
|
||||
owner.mutations.Remove(HUSK)
|
||||
owner.setBrainLoss(braindamage)
|
||||
owner.species.update_vore_belly_def_variant()
|
||||
|
||||
if(!uninjured)
|
||||
nutrition = old_nutrition * 0.5
|
||||
owner.nutrition = old_nutrition * 0.5
|
||||
//Drop everything
|
||||
for(var/obj/item/W in src)
|
||||
drop_from_inventory(W)
|
||||
for(var/obj/item/W in owner)
|
||||
owner.drop_from_inventory(W)
|
||||
//Visual effects
|
||||
var/T = get_turf(src)
|
||||
var/blood_color = species.blood_color
|
||||
var/flesh_color = species.flesh_color
|
||||
var/T = get_turf(owner)
|
||||
var/blood_color = owner.species.blood_color
|
||||
var/flesh_color = owner.species.flesh_color
|
||||
new /obj/effect/gibspawner/human/xenochimera(T, null, flesh_color, blood_color)
|
||||
visible_message(span_danger("<p>" + span_huge("The lifeless husk of [src] bursts open, revealing a new, intact copy in the pool of viscera.") + "</p>")) //Bloody hell...
|
||||
owner.visible_message(span_danger(span_huge("The lifeless husk of [owner] bursts open, revealing a new, intact copy in the pool of viscera."))) //Bloody hell...
|
||||
playsound(T, 'sound/effects/mob_effects/xenochimera/hatch.ogg', 50)
|
||||
else //lower cost for doing a quick cosmetic revive
|
||||
nutrition = old_nutrition * 0.9
|
||||
owner.nutrition = old_nutrition * 0.9
|
||||
|
||||
//Unfreeze some things
|
||||
does_not_breathe = FALSE
|
||||
update_canmove()
|
||||
stunned = 2
|
||||
owner.does_not_breathe = FALSE
|
||||
owner.update_canmove()
|
||||
owner.AdjustStunned(2)
|
||||
|
||||
xc.revive_ready = world.time + 10 MINUTES //set the cooldown, Reduced this to 10 minutes, you're playing with fire if you're reviving that often.
|
||||
revive_ready = world.time + 10 MINUTES //set the cooldown, Reduced this to 10 minutes, you're playing with fire if you're reviving that often.
|
||||
|
||||
/datum/modifier/resleeving_sickness/chimera //near identical to the regular version, just with different flavortexts
|
||||
name = "imperfect regeneration"
|
||||
|
||||
@@ -63,10 +63,6 @@ GLOBAL_LIST_EMPTY_TYPED(dna_genes_bad, /datum/gene/trait)
|
||||
var/gender_specific_species_sounds = FALSE
|
||||
var/species_sounds_male = "None"
|
||||
var/species_sounds_female = "None"
|
||||
var/grad_style = 0
|
||||
var/r_grad = 0
|
||||
var/g_grad = 0
|
||||
var/b_grad = 0
|
||||
var/custom_say
|
||||
var/custom_ask
|
||||
var/custom_whisper
|
||||
@@ -74,55 +70,43 @@ GLOBAL_LIST_EMPTY_TYPED(dna_genes_bad, /datum/gene/trait)
|
||||
var/list/custom_heat = list()
|
||||
var/list/custom_cold = list()
|
||||
var/digitigrade = 0 //0, Not FALSE, for future use as indicator for digitigrade types
|
||||
var/custom_footstep = FOOTSTEP_MOB_SHOE
|
||||
|
||||
// New stuff
|
||||
var/species = SPECIES_HUMAN
|
||||
var/list/body_markings = list()
|
||||
var/list/body_markings_genetic = list()
|
||||
var/list/genetic_modifiers = list() // Modifiers with the MODIFIER_GENETIC flag are saved. Note that only the type is saved, not an instance.
|
||||
|
||||
// Make a copy of this strand.
|
||||
// USE THIS WHEN COPYING STUFF OR YOU'LL GET CORRUPTION!
|
||||
// Can you imagine, this used to be done manually, var by var?
|
||||
/datum/dna/proc/Clone()
|
||||
var/datum/dna/new_dna = new()
|
||||
new_dna.unique_enzymes=unique_enzymes
|
||||
new_dna.b_type=b_type
|
||||
new_dna.real_name=real_name
|
||||
new_dna.species=species
|
||||
new_dna.body_markings=body_markings.Copy()
|
||||
new_dna.base_species=base_species
|
||||
new_dna.custom_species=custom_species
|
||||
new_dna.species_traits=species_traits.Copy()
|
||||
new_dna.blood_color=blood_color
|
||||
new_dna.blood_reagents=blood_reagents
|
||||
new_dna.scale_appearance = scale_appearance
|
||||
new_dna.offset_override = offset_override
|
||||
new_dna.synth_markings = synth_markings
|
||||
new_dna.custom_speech_bubble = custom_speech_bubble
|
||||
new_dna.species_sounds = species_sounds
|
||||
new_dna.gender_specific_species_sounds = gender_specific_species_sounds
|
||||
new_dna.species_sounds_male = species_sounds_male
|
||||
new_dna.species_sounds_female = species_sounds_female
|
||||
new_dna.grad_style = grad_style
|
||||
new_dna.r_grad = r_grad
|
||||
new_dna.g_grad = g_grad
|
||||
new_dna.b_grad = b_grad
|
||||
new_dna.custom_say=custom_say
|
||||
new_dna.custom_ask=custom_ask
|
||||
new_dna.custom_whisper=custom_whisper
|
||||
new_dna.custom_exclaim=custom_exclaim
|
||||
new_dna.custom_heat=custom_heat
|
||||
new_dna.custom_cold=custom_cold
|
||||
new_dna.digitigrade=src.digitigrade
|
||||
var/list/body_markings_genetic = (body_markings - body_marking_nopersist_list)
|
||||
new_dna.body_markings=body_markings_genetic.Copy()
|
||||
for(var/b=1;b<=DNA_SE_LENGTH;b++)
|
||||
new_dna.SE[b]=SE[b]
|
||||
if(b<=DNA_UI_LENGTH)
|
||||
new_dna.UI[b]=UI[b]
|
||||
for(var/A in vars)
|
||||
switch(A)
|
||||
if(BLACKLISTED_COPY_VARS)
|
||||
continue
|
||||
if("dirtyUI")
|
||||
dirtyUI=1
|
||||
continue
|
||||
if("dirtySE")
|
||||
dirtySE=1
|
||||
continue
|
||||
if("body_markings")
|
||||
var/list/body_markings_genetic = body_markings.Copy()
|
||||
body_markings_genetic -= body_marking_nopersist_list
|
||||
new_dna.vars[A] = body_markings_genetic
|
||||
continue
|
||||
if(islist(vars[A]))
|
||||
var/list/L = vars[A]
|
||||
new_dna.vars[A] = L.Copy()
|
||||
continue
|
||||
new_dna.vars[A] = vars[A]
|
||||
// Finish up by updating enzymes/identity from our UI/SEs
|
||||
new_dna.UpdateUI()
|
||||
new_dna.UpdateSE()
|
||||
return new_dna
|
||||
|
||||
///////////////////////////////////////
|
||||
// UNIQUE IDENTITY
|
||||
///////////////////////////////////////
|
||||
@@ -138,6 +122,11 @@ GLOBAL_LIST_EMPTY_TYPED(dna_genes_bad, /datum/gene/trait)
|
||||
if(!defer)
|
||||
UpdateUI()
|
||||
|
||||
/**
|
||||
* Beginning of mob to dna, and dna to mob transfer procs.
|
||||
* Ensure that ResetUIFrom() and ApplyToMob() mirror each other. All vars should be read FROM the mob, and written back to it!
|
||||
* ALL dna logic for reading from the mob, storing the dna data, and writing that dna data back to the mob should be here, and ONLY here.
|
||||
*/
|
||||
/datum/dna/proc/ResetUIFrom(var/mob/living/carbon/human/character)
|
||||
// INITIALIZE!
|
||||
ResetUI(1)
|
||||
@@ -174,6 +163,11 @@ GLOBAL_LIST_EMPTY_TYPED(dna_genes_bad, /datum/gene/trait)
|
||||
if(character.wing_style)
|
||||
wing_style = wing_styles_list.Find(character.wing_style.type)
|
||||
|
||||
// Hairgrad
|
||||
var/grad_style = 0
|
||||
if(character.grad_style)
|
||||
grad_style = GLOB.hair_gradients.Find(character.grad_style)
|
||||
|
||||
// Playerscale (This assumes list is sorted big->small)
|
||||
var/size_multiplier = GLOB.player_sizes_list.len // If fail to find, take smallest
|
||||
for(var/N in GLOB.player_sizes_list)
|
||||
@@ -194,10 +188,6 @@ GLOBAL_LIST_EMPTY_TYPED(dna_genes_bad, /datum/gene/trait)
|
||||
src.gender_specific_species_sounds = character.species.gender_specific_species_sounds
|
||||
src.species_sounds_male = character.species.species_sounds_male
|
||||
src.species_sounds_female = character.species.species_sounds_female
|
||||
src.grad_style = character.grad_style
|
||||
src.r_grad = character.r_grad
|
||||
src.g_grad = character.g_grad
|
||||
src.b_grad = character.b_grad
|
||||
src.species_traits = character.species.traits.Copy()
|
||||
src.custom_say = character.custom_say
|
||||
src.custom_ask = character.custom_ask
|
||||
@@ -206,6 +196,7 @@ GLOBAL_LIST_EMPTY_TYPED(dna_genes_bad, /datum/gene/trait)
|
||||
src.custom_heat = character.custom_heat
|
||||
src.custom_cold = character.custom_cold
|
||||
src.digitigrade = character.digitigrade
|
||||
src.custom_footstep = character.custom_footstep
|
||||
|
||||
// +1 to account for the none-of-the-above possibility
|
||||
SetUIValueRange(DNA_UI_EAR_STYLE, ear_style + 1, ear_styles_list.len + 1, 1)
|
||||
@@ -213,6 +204,7 @@ GLOBAL_LIST_EMPTY_TYPED(dna_genes_bad, /datum/gene/trait)
|
||||
SetUIValueRange(DNA_UI_TAIL_STYLE, tail_style + 1, tail_styles_list.len + 1, 1)
|
||||
SetUIValueRange(DNA_UI_PLAYERSCALE, size_multiplier, GLOB.player_sizes_list.len, 1)
|
||||
SetUIValueRange(DNA_UI_WING_STYLE, wing_style + 1, wing_styles_list.len + 1, 1)
|
||||
SetUIValueRange(DNA_UI_GRAD_STYLE, grad_style, GLOB.hair_gradients.len, 1)
|
||||
|
||||
SetUIValueRange(DNA_UI_TAIL_R, character.r_tail, 255, 1)
|
||||
SetUIValueRange(DNA_UI_TAIL_G, character.g_tail, 255, 1)
|
||||
@@ -253,6 +245,10 @@ GLOBAL_LIST_EMPTY_TYPED(dna_genes_bad, /datum/gene/trait)
|
||||
SetUIValueRange(DNA_UI_EARS3_B, character.b_ears3, 255, 1)
|
||||
SetUIValueRange(DNA_UI_EARS_ALPHA,character.a_ears, 255, 1)
|
||||
|
||||
SetUIValueRange(DNA_UI_GRAD_R, character.r_grad, 255, 1)
|
||||
SetUIValueRange(DNA_UI_GRAD_G, character.g_grad, 255, 1)
|
||||
SetUIValueRange(DNA_UI_GRAD_B, character.b_grad, 255, 1)
|
||||
|
||||
for(var/channel in 1 to DNA_UI_EARS_SECONDARY_COLOR_CHANNEL_COUNT)
|
||||
var/offset = DNA_UI_EARS_SECONDARY_START + (channel - 1) * 3
|
||||
var/list/read_rgb = ReadRGB(LAZYACCESS(character.ear_secondary_colors, channel) || "#ffffff")
|
||||
@@ -294,6 +290,180 @@ GLOBAL_LIST_EMPTY_TYPED(dna_genes_bad, /datum/gene/trait)
|
||||
|
||||
UpdateUI()
|
||||
|
||||
/datum/dna/proc/ApplyToMob(var/mob/living/carbon/human/H)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Apply UIs to character
|
||||
//Hair color
|
||||
H.r_hair = GetUIValueRange(DNA_UI_HAIR_R, 255)
|
||||
H.g_hair = GetUIValueRange(DNA_UI_HAIR_G, 255)
|
||||
H.b_hair = GetUIValueRange(DNA_UI_HAIR_B, 255)
|
||||
|
||||
//Facial hair color
|
||||
H.r_facial = GetUIValueRange(DNA_UI_BEARD_R, 255)
|
||||
H.g_facial = GetUIValueRange(DNA_UI_BEARD_G, 255)
|
||||
H.b_facial = GetUIValueRange(DNA_UI_BEARD_B, 255)
|
||||
|
||||
//Skin color (Tone for humans is seperate)
|
||||
H.r_skin = GetUIValueRange(DNA_UI_SKIN_R, 255)
|
||||
H.g_skin = GetUIValueRange(DNA_UI_SKIN_G, 255)
|
||||
H.b_skin = GetUIValueRange(DNA_UI_SKIN_B, 255)
|
||||
|
||||
H.s_tone = 35 - GetUIValueRange(DNA_UI_SKIN_TONE, 220) // Value can be negative.
|
||||
|
||||
//Eye color
|
||||
H.r_eyes = GetUIValueRange(DNA_UI_EYES_R, 255)
|
||||
H.g_eyes = GetUIValueRange(DNA_UI_EYES_G, 255)
|
||||
H.b_eyes = GetUIValueRange(DNA_UI_EYES_B, 255)
|
||||
H.update_eyes()
|
||||
|
||||
//Hair gradient color
|
||||
H.r_grad = GetUIValueRange(DNA_UI_GRAD_R, 255)
|
||||
H.g_grad = GetUIValueRange(DNA_UI_GRAD_G, 255)
|
||||
H.b_grad = GetUIValueRange(DNA_UI_GRAD_B, 255)
|
||||
|
||||
//Sex... Needs future support for properly handling things other then just male/female. UIs have the capability to do so!
|
||||
if(H.gender != NEUTER)
|
||||
if (GetUIState(DNA_UI_GENDER))
|
||||
H.gender = FEMALE
|
||||
else
|
||||
H.gender = MALE
|
||||
|
||||
//Body markings
|
||||
for(var/tag in body_markings)
|
||||
var/obj/item/organ/external/E = H.organs_by_name[tag]
|
||||
if(E)
|
||||
var/list/marklist = body_markings[tag]
|
||||
E.markings = marklist.Copy()
|
||||
|
||||
//Hair style
|
||||
var/hair = GetUIValueRange(DNA_UI_HAIR_STYLE,hair_styles_list.len)
|
||||
if((0 < hair) && (hair <= hair_styles_list.len))
|
||||
H.h_style = hair_styles_list[hair]
|
||||
|
||||
//Facial Hair
|
||||
var/beard = GetUIValueRange(DNA_UI_BEARD_STYLE,facial_hair_styles_list.len)
|
||||
if((0 < beard) && (beard <= facial_hair_styles_list.len))
|
||||
H.f_style = facial_hair_styles_list[beard]
|
||||
|
||||
// Ears
|
||||
var/ears = GetUIValueRange(DNA_UI_EAR_STYLE, ear_styles_list.len + 1) - 1
|
||||
if(ears < 1)
|
||||
H.ear_style = null
|
||||
else if((0 < ears) && (ears <= ear_styles_list.len))
|
||||
H.ear_style = ear_styles_list[ear_styles_list[ears]]
|
||||
var/ears_secondary = GetUIValueRange(DNA_UI_EAR_SECONDARY_STYLE, ear_styles_list.len + 1) - 1
|
||||
if(ears_secondary < 1)
|
||||
H.ear_secondary_style = null
|
||||
else if((0 < ears_secondary) && (ears_secondary <= ear_styles_list.len))
|
||||
H.ear_secondary_style = ear_styles_list[ear_styles_list[ears_secondary]]
|
||||
|
||||
// Ear Color
|
||||
H.r_ears = GetUIValueRange(DNA_UI_EARS_R, 255)
|
||||
H.g_ears = GetUIValueRange(DNA_UI_EARS_G, 255)
|
||||
H.b_ears = GetUIValueRange(DNA_UI_EARS_B, 255)
|
||||
H.r_ears2 = GetUIValueRange(DNA_UI_EARS2_R, 255)
|
||||
H.g_ears2 = GetUIValueRange(DNA_UI_EARS2_G, 255)
|
||||
H.b_ears2 = GetUIValueRange(DNA_UI_EARS2_B, 255)
|
||||
H.r_ears3 = GetUIValueRange(DNA_UI_EARS3_R, 255)
|
||||
H.g_ears3 = GetUIValueRange(DNA_UI_EARS3_G, 255)
|
||||
H.b_ears3 = GetUIValueRange(DNA_UI_EARS3_B, 255)
|
||||
H.a_ears = GetUIValueRange(DNA_UI_EARS_ALPHA, 255)
|
||||
H.a_ears2 = GetUIValueRange(DNA_UI_EARS_SECONDARY_ALPHA, 255)
|
||||
|
||||
LAZYINITLIST(H.ear_secondary_colors)
|
||||
H.ear_secondary_colors.len = max(length(H.ear_secondary_colors), DNA_UI_EARS_SECONDARY_COLOR_CHANNEL_COUNT)
|
||||
for(var/channel in 1 to DNA_UI_EARS_SECONDARY_COLOR_CHANNEL_COUNT)
|
||||
var/offset = DNA_UI_EARS_SECONDARY_START + (channel - 1) * 3
|
||||
H.ear_secondary_colors[channel] = rgb(
|
||||
GetUIValueRange(offset, 255),
|
||||
GetUIValueRange(offset + 1, 255),
|
||||
GetUIValueRange(offset + 2, 255),
|
||||
)
|
||||
|
||||
//Tail
|
||||
var/tail = GetUIValueRange(DNA_UI_TAIL_STYLE, tail_styles_list.len + 1) - 1
|
||||
if(tail < 1)
|
||||
H.tail_style = null
|
||||
else if((0 < tail) && (tail <= tail_styles_list.len))
|
||||
H.tail_style = tail_styles_list[tail_styles_list[tail]]
|
||||
|
||||
//Wing
|
||||
var/wing = GetUIValueRange(DNA_UI_WING_STYLE, wing_styles_list.len + 1) - 1
|
||||
if(wing < 1)
|
||||
H.wing_style = null
|
||||
else if((0 < wing) && (wing <= wing_styles_list.len))
|
||||
H.wing_style = wing_styles_list[wing_styles_list[wing]]
|
||||
|
||||
//Wing Color
|
||||
H.r_wing = GetUIValueRange(DNA_UI_WING_R, 255)
|
||||
H.g_wing = GetUIValueRange(DNA_UI_WING_G, 255)
|
||||
H.b_wing = GetUIValueRange(DNA_UI_WING_B, 255)
|
||||
H.r_wing2 = GetUIValueRange(DNA_UI_WING2_R, 255)
|
||||
H.g_wing2 = GetUIValueRange(DNA_UI_WING2_G, 255)
|
||||
H.b_wing2 = GetUIValueRange(DNA_UI_WING2_B, 255)
|
||||
H.r_wing3 = GetUIValueRange(DNA_UI_WING3_R, 255)
|
||||
H.g_wing3 = GetUIValueRange(DNA_UI_WING3_G, 255)
|
||||
H.b_wing3 = GetUIValueRange(DNA_UI_WING3_B, 255)
|
||||
H.a_wing = GetUIValueRange(DNA_UI_WING_ALPHA, 255)
|
||||
|
||||
// Playerscale
|
||||
var/size = GetUIValueRange(DNA_UI_PLAYERSCALE, GLOB.player_sizes_list.len)
|
||||
if((0 < size) && (size <= GLOB.player_sizes_list.len))
|
||||
H.resize(GLOB.player_sizes_list[GLOB.player_sizes_list[size]], TRUE, ignore_prefs = TRUE)
|
||||
|
||||
// Tail/Taur Color
|
||||
H.r_tail = GetUIValueRange(DNA_UI_TAIL_R, 255)
|
||||
H.g_tail = GetUIValueRange(DNA_UI_TAIL_G, 255)
|
||||
H.b_tail = GetUIValueRange(DNA_UI_TAIL_B, 255)
|
||||
H.r_tail2 = GetUIValueRange(DNA_UI_TAIL2_R, 255)
|
||||
H.g_tail2 = GetUIValueRange(DNA_UI_TAIL2_G, 255)
|
||||
H.b_tail2 = GetUIValueRange(DNA_UI_TAIL2_B, 255)
|
||||
H.r_tail3 = GetUIValueRange(DNA_UI_TAIL3_R, 255)
|
||||
H.g_tail3 = GetUIValueRange(DNA_UI_TAIL3_G, 255)
|
||||
H.b_tail3 = GetUIValueRange(DNA_UI_TAIL3_B, 255)
|
||||
H.a_tail = GetUIValueRange(DNA_UI_TAIL_ALPHA, 255)
|
||||
|
||||
// Hair gradiant
|
||||
var/grad = GetUIValueRange(DNA_UI_GRAD_STYLE,GLOB.hair_gradients.len)
|
||||
if((0 < grad) && (grad <= GLOB.hair_gradients.len))
|
||||
H.grad_style = GLOB.hair_gradients[grad]
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Custom species and other cosmetic vars
|
||||
H.custom_species = custom_species
|
||||
H.custom_say = custom_say
|
||||
H.custom_ask = custom_ask
|
||||
H.custom_whisper = custom_whisper
|
||||
H.custom_exclaim = custom_exclaim
|
||||
H.custom_speech_bubble = custom_speech_bubble
|
||||
H.custom_heat = custom_heat
|
||||
H.custom_cold = custom_cold
|
||||
H.custom_footstep = custom_footstep
|
||||
H.digitigrade = digitigrade
|
||||
|
||||
// If synths have character markings
|
||||
H.synth_markings = synth_markings
|
||||
|
||||
// Scaling style
|
||||
H.fuzzy = scale_appearance
|
||||
H.offset_override = offset_override
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Get a copy of the species datum to edit for ourselves
|
||||
// anything that sets stuff in species MUST be done beyond here!
|
||||
H.species.produceCopy(species_traits, H, base_species, FALSE) // Traitgenes edit - reset_dna flag required, or genes get reset on resleeve
|
||||
|
||||
// Update species blood with our blood color from dna!
|
||||
H.species.blood_reagents = blood_reagents
|
||||
H.species.blood_color = blood_color
|
||||
H.species.species_sounds = species_sounds
|
||||
H.species.gender_specific_species_sounds = gender_specific_species_sounds
|
||||
H.species.species_sounds_male = species_sounds_male
|
||||
H.species.species_sounds_female = species_sounds_female
|
||||
/**
|
||||
* End of mob to dna, and dna to mob transfer procs.
|
||||
*/
|
||||
|
||||
// Set a DNA UI block's raw value.
|
||||
/datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0)
|
||||
if (block<=0) return
|
||||
|
||||
@@ -132,172 +132,29 @@
|
||||
return output
|
||||
|
||||
// Use mob.UpdateAppearance()
|
||||
/mob/proc/UpdateAppearance(var/list/UI=null)
|
||||
return FALSE
|
||||
|
||||
// Simpler. Don't specify UI in order for the mob to use its own.
|
||||
/mob/proc/UpdateAppearance(var/list/UI=null)
|
||||
if(ishuman(src))
|
||||
if(UI!=null)
|
||||
src.dna.UI=UI
|
||||
src.dna.UpdateUI()
|
||||
dna.check_integrity()
|
||||
var/mob/living/carbon/human/H = src
|
||||
H.r_hair = dna.GetUIValueRange(DNA_UI_HAIR_R, 255)
|
||||
H.g_hair = dna.GetUIValueRange(DNA_UI_HAIR_G, 255)
|
||||
H.b_hair = dna.GetUIValueRange(DNA_UI_HAIR_B, 255)
|
||||
/mob/living/carbon/human/UpdateAppearance(var/list/UI=null)
|
||||
// Rebuild off UI arg if not null
|
||||
if(UI!=null)
|
||||
src.dna.UI=UI
|
||||
src.dna.UpdateUI()
|
||||
|
||||
H.r_facial = dna.GetUIValueRange(DNA_UI_BEARD_R, 255)
|
||||
H.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255)
|
||||
H.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255)
|
||||
// Setup dna
|
||||
dna.check_integrity()
|
||||
dna.ApplyToMob(src)
|
||||
|
||||
H.r_skin = dna.GetUIValueRange(DNA_UI_SKIN_R, 255)
|
||||
H.g_skin = dna.GetUIValueRange(DNA_UI_SKIN_G, 255)
|
||||
H.b_skin = dna.GetUIValueRange(DNA_UI_SKIN_B, 255)
|
||||
// Apply dna changes to organ icons
|
||||
force_update_organs()
|
||||
force_update_limbs()
|
||||
|
||||
H.r_eyes = dna.GetUIValueRange(DNA_UI_EYES_R, 255)
|
||||
H.g_eyes = dna.GetUIValueRange(DNA_UI_EYES_G, 255)
|
||||
H.b_eyes = dna.GetUIValueRange(DNA_UI_EYES_B, 255)
|
||||
H.update_eyes()
|
||||
//H.update_body(0) //Done in force_update_limbs already
|
||||
update_eyes()
|
||||
update_hair()
|
||||
|
||||
H.s_tone = 35 - dna.GetUIValueRange(DNA_UI_SKIN_TONE, 220) // Value can be negative.
|
||||
|
||||
if(H.gender != NEUTER)
|
||||
if (dna.GetUIState(DNA_UI_GENDER))
|
||||
H.gender = FEMALE
|
||||
else
|
||||
H.gender = MALE
|
||||
|
||||
//Body markings
|
||||
for(var/tag in dna.body_markings)
|
||||
var/obj/item/organ/external/E = H.organs_by_name[tag]
|
||||
if(E)
|
||||
var/list/marklist = dna.body_markings[tag]
|
||||
E.markings = marklist.Copy()
|
||||
|
||||
//Hair
|
||||
var/hair = dna.GetUIValueRange(DNA_UI_HAIR_STYLE,hair_styles_list.len)
|
||||
if((0 < hair) && (hair <= hair_styles_list.len))
|
||||
H.h_style = hair_styles_list[hair]
|
||||
|
||||
//Facial Hair
|
||||
var/beard = dna.GetUIValueRange(DNA_UI_BEARD_STYLE,facial_hair_styles_list.len)
|
||||
if((0 < beard) && (beard <= facial_hair_styles_list.len))
|
||||
H.f_style = facial_hair_styles_list[beard]
|
||||
|
||||
// Ears
|
||||
var/ears = dna.GetUIValueRange(DNA_UI_EAR_STYLE, ear_styles_list.len + 1) - 1
|
||||
if(ears < 1)
|
||||
H.ear_style = null
|
||||
else if((0 < ears) && (ears <= ear_styles_list.len))
|
||||
H.ear_style = ear_styles_list[ear_styles_list[ears]]
|
||||
var/ears_secondary = dna.GetUIValueRange(DNA_UI_EAR_SECONDARY_STYLE, ear_styles_list.len + 1) - 1
|
||||
if(ears_secondary < 1)
|
||||
H.ear_secondary_style = null
|
||||
else if((0 < ears_secondary) && (ears_secondary <= ear_styles_list.len))
|
||||
H.ear_secondary_style = ear_styles_list[ear_styles_list[ears_secondary]]
|
||||
|
||||
// Ear Color
|
||||
H.r_ears = dna.GetUIValueRange(DNA_UI_EARS_R, 255)
|
||||
H.g_ears = dna.GetUIValueRange(DNA_UI_EARS_G, 255)
|
||||
H.b_ears = dna.GetUIValueRange(DNA_UI_EARS_B, 255)
|
||||
H.r_ears2 = dna.GetUIValueRange(DNA_UI_EARS2_R, 255)
|
||||
H.g_ears2 = dna.GetUIValueRange(DNA_UI_EARS2_G, 255)
|
||||
H.b_ears2 = dna.GetUIValueRange(DNA_UI_EARS2_B, 255)
|
||||
H.r_ears3 = dna.GetUIValueRange(DNA_UI_EARS3_R, 255)
|
||||
H.g_ears3 = dna.GetUIValueRange(DNA_UI_EARS3_G, 255)
|
||||
H.b_ears3 = dna.GetUIValueRange(DNA_UI_EARS3_B, 255)
|
||||
H.a_ears = dna.GetUIValueRange(DNA_UI_EARS_ALPHA, 255)
|
||||
H.a_ears2 = dna.GetUIValueRange(DNA_UI_EARS_SECONDARY_ALPHA, 255)
|
||||
|
||||
LAZYINITLIST(H.ear_secondary_colors)
|
||||
H.ear_secondary_colors.len = max(length(H.ear_secondary_colors), DNA_UI_EARS_SECONDARY_COLOR_CHANNEL_COUNT)
|
||||
for(var/channel in 1 to DNA_UI_EARS_SECONDARY_COLOR_CHANNEL_COUNT)
|
||||
var/offset = DNA_UI_EARS_SECONDARY_START + (channel - 1) * 3
|
||||
H.ear_secondary_colors[channel] = rgb(
|
||||
dna.GetUIValueRange(offset, 255),
|
||||
dna.GetUIValueRange(offset + 1, 255),
|
||||
dna.GetUIValueRange(offset + 2, 255),
|
||||
)
|
||||
|
||||
//Tail
|
||||
var/tail = dna.GetUIValueRange(DNA_UI_TAIL_STYLE, tail_styles_list.len + 1) - 1
|
||||
if(tail < 1)
|
||||
H.tail_style = null
|
||||
else if((0 < tail) && (tail <= tail_styles_list.len))
|
||||
H.tail_style = tail_styles_list[tail_styles_list[tail]]
|
||||
|
||||
//Wing
|
||||
var/wing = dna.GetUIValueRange(DNA_UI_WING_STYLE, wing_styles_list.len + 1) - 1
|
||||
if(wing < 1)
|
||||
H.wing_style = null
|
||||
else if((0 < wing) && (wing <= wing_styles_list.len))
|
||||
H.wing_style = wing_styles_list[wing_styles_list[wing]]
|
||||
|
||||
//Wing Color
|
||||
H.r_wing = dna.GetUIValueRange(DNA_UI_WING_R, 255)
|
||||
H.g_wing = dna.GetUIValueRange(DNA_UI_WING_G, 255)
|
||||
H.b_wing = dna.GetUIValueRange(DNA_UI_WING_B, 255)
|
||||
H.r_wing2 = dna.GetUIValueRange(DNA_UI_WING2_R, 255)
|
||||
H.g_wing2 = dna.GetUIValueRange(DNA_UI_WING2_G, 255)
|
||||
H.b_wing2 = dna.GetUIValueRange(DNA_UI_WING2_B, 255)
|
||||
H.r_wing3 = dna.GetUIValueRange(DNA_UI_WING3_R, 255)
|
||||
H.g_wing3 = dna.GetUIValueRange(DNA_UI_WING3_G, 255)
|
||||
H.b_wing3 = dna.GetUIValueRange(DNA_UI_WING3_B, 255)
|
||||
H.a_wing = dna.GetUIValueRange(DNA_UI_WING_ALPHA, 255)
|
||||
|
||||
// Playerscale
|
||||
var/size = dna.GetUIValueRange(DNA_UI_PLAYERSCALE, GLOB.player_sizes_list.len)
|
||||
if((0 < size) && (size <= GLOB.player_sizes_list.len))
|
||||
H.resize(GLOB.player_sizes_list[GLOB.player_sizes_list[size]], TRUE, ignore_prefs = TRUE)
|
||||
|
||||
// Tail/Taur Color
|
||||
H.r_tail = dna.GetUIValueRange(DNA_UI_TAIL_R, 255)
|
||||
H.g_tail = dna.GetUIValueRange(DNA_UI_TAIL_G, 255)
|
||||
H.b_tail = dna.GetUIValueRange(DNA_UI_TAIL_B, 255)
|
||||
H.r_tail2 = dna.GetUIValueRange(DNA_UI_TAIL2_R, 255)
|
||||
H.g_tail2 = dna.GetUIValueRange(DNA_UI_TAIL2_G, 255)
|
||||
H.b_tail2 = dna.GetUIValueRange(DNA_UI_TAIL2_B, 255)
|
||||
H.r_tail3 = dna.GetUIValueRange(DNA_UI_TAIL3_R, 255)
|
||||
H.g_tail3 = dna.GetUIValueRange(DNA_UI_TAIL3_G, 255)
|
||||
H.b_tail3 = dna.GetUIValueRange(DNA_UI_TAIL3_B, 255)
|
||||
H.a_tail = dna.GetUIValueRange(DNA_UI_TAIL_ALPHA, 255)
|
||||
|
||||
// Technically custom_species is not part of the UI, but this place avoids merge problems.
|
||||
H.custom_species = dna.custom_species
|
||||
H.custom_say = dna.custom_say
|
||||
H.custom_ask = dna.custom_ask
|
||||
H.custom_whisper = dna.custom_whisper
|
||||
H.custom_exclaim = dna.custom_exclaim
|
||||
H.species.blood_color = dna.blood_color
|
||||
H.fuzzy = dna.scale_appearance
|
||||
H.offset_override = dna.offset_override
|
||||
H.synth_markings = dna.synth_markings
|
||||
H.custom_speech_bubble = dna.custom_speech_bubble
|
||||
H.grad_style = dna.grad_style
|
||||
H.r_grad = dna.r_grad
|
||||
H.g_grad = dna.g_grad
|
||||
H.b_grad = dna.b_grad
|
||||
H.custom_heat = dna.custom_heat
|
||||
H.custom_cold = dna.custom_cold
|
||||
var/datum/species/S = H.species
|
||||
S.produceCopy(dna.species_traits, H, dna.base_species, FALSE) // Traitgenes edit - reset_dna flag required, or genes get reset on resleeve
|
||||
H.dna.blood_reagents = dna.blood_reagents
|
||||
H.dna.blood_color = dna.blood_color
|
||||
H.species.blood_reagents = H.dna.blood_reagents
|
||||
H.species.blood_color = H.dna.blood_color
|
||||
H.species.species_sounds = dna.species_sounds
|
||||
H.species.gender_specific_species_sounds = dna.gender_specific_species_sounds
|
||||
H.species.species_sounds_male = dna.species_sounds_male
|
||||
H.species.species_sounds_female = dna.species_sounds_female
|
||||
|
||||
H.force_update_organs() //VOREStation Add - Gotta do this too
|
||||
H.force_update_limbs()
|
||||
//H.update_body(0) //VOREStation Edit - Done in force_update_limbs already
|
||||
H.update_eyes()
|
||||
H.update_hair()
|
||||
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/proc/force_update_organs()
|
||||
for(var/obj/item/organ/O as anything in organs + internal_organs)
|
||||
|
||||
@@ -38,16 +38,21 @@
|
||||
|
||||
/datum/dna2/record/proc/copy()
|
||||
var/datum/dna2/record/newrecord = new /datum/dna2/record
|
||||
qdel_swap(newrecord.dna, dna.Clone())
|
||||
newrecord.types = types
|
||||
newrecord.name = name
|
||||
newrecord.mind = mind
|
||||
newrecord.ckey = ckey
|
||||
newrecord.languages = languages
|
||||
newrecord.implant = implant
|
||||
newrecord.flavor = flavor
|
||||
newrecord.gender = gender
|
||||
newrecord.genetic_modifiers = genetic_modifiers.Copy()
|
||||
for(var/A in vars)
|
||||
switch(A)
|
||||
if(BLACKLISTED_COPY_VARS)
|
||||
continue
|
||||
if("id")
|
||||
newrecord.id = copytext(md5(dna.real_name), 2, 6) // update this specially
|
||||
continue
|
||||
if("dna")
|
||||
qdel_swap(newrecord.dna, dna.Clone())
|
||||
continue
|
||||
if(islist(vars[A]))
|
||||
var/list/L = vars[A]
|
||||
newrecord.vars[A] = L.Copy()
|
||||
continue
|
||||
newrecord.vars[A] = vars[A]
|
||||
return newrecord
|
||||
|
||||
|
||||
@@ -65,7 +70,7 @@
|
||||
interact_offline = 1
|
||||
circuit = /obj/item/circuitboard/clonescanner
|
||||
var/locked = 0
|
||||
var/datum/weakref/occupant = null
|
||||
VAR_PRIVATE/datum/weakref/weakref_occupant = null
|
||||
var/obj/item/reagent_containers/glass/beaker = null
|
||||
var/opened = 0
|
||||
var/damage_coeff
|
||||
@@ -81,6 +86,18 @@
|
||||
eject_occupant()
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/dna_scannernew/proc/set_occupant(var/mob/living/L)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
if(!L)
|
||||
weakref_occupant = null
|
||||
return
|
||||
weakref_occupant = WEAKREF(L)
|
||||
|
||||
/obj/machinery/dna_scannernew/proc/get_occupant()
|
||||
RETURN_TYPE(/mob/living)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
return weakref_occupant?.resolve()
|
||||
|
||||
/obj/machinery/dna_scannernew/RefreshParts()
|
||||
scan_level = 0
|
||||
damage_coeff = 0
|
||||
@@ -112,7 +129,7 @@
|
||||
return
|
||||
|
||||
/obj/machinery/dna_scannernew/proc/eject_occupant()
|
||||
var/mob/living/carbon/WC = occupant?.resolve()
|
||||
var/mob/living/carbon/WC = get_occupant()
|
||||
go_out()
|
||||
for(var/obj/O in src)
|
||||
if((!istype(O,/obj/item/reagent_containers)) && (!istype(O,/obj/item/circuitboard/clonescanner)) && (!istype(O,/obj/item/stock_parts)) && (!istype(O,/obj/item/stack/cable_coil)))
|
||||
@@ -122,7 +139,7 @@
|
||||
M.forceMove(get_turf(src))
|
||||
|
||||
/obj/machinery/dna_scannernew/MouseDrop_T(var/mob/target, var/mob/user) //Allows borgs to clone people without external assistance
|
||||
var/mob/living/carbon/WC = occupant?.resolve()
|
||||
var/mob/living/carbon/WC = get_occupant()
|
||||
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user)|| !ishuman(target) || WC)
|
||||
return
|
||||
// Traitgenes Do not allow buckled or ridden mobs
|
||||
@@ -144,13 +161,13 @@
|
||||
if(!ishuman(usr) && !issmall(usr)) //Make sure they're a mob that has dna
|
||||
to_chat(usr, span_notice("Try as you might, you can not climb up into the scanner."))
|
||||
return
|
||||
if(occupant)
|
||||
var/mob/living/carbon/WC = get_occupant()
|
||||
if(WC)
|
||||
to_chat(usr, span_warning("The scanner is already occupied!"))
|
||||
return
|
||||
if(usr.abiotic())
|
||||
to_chat(usr, span_warning("The subject cannot have abiotic items on."))
|
||||
return
|
||||
var/mob/living/carbon/WC = occupant?.resolve()
|
||||
if(WC)
|
||||
to_chat(usr, span_warning("There is already something inside."))
|
||||
return
|
||||
@@ -158,7 +175,7 @@
|
||||
usr.client.perspective = EYE_PERSPECTIVE
|
||||
usr.client.eye = src
|
||||
usr.forceMove(src)
|
||||
occupant = WEAKREF(usr)
|
||||
set_occupant(usr)
|
||||
icon_state = "scanner_1"
|
||||
add_fingerprint(usr)
|
||||
SStgui.update_uis(src)
|
||||
@@ -182,7 +199,7 @@
|
||||
return
|
||||
|
||||
else if(istype(item, /obj/item/organ/internal/brain))
|
||||
if(occupant)
|
||||
if(get_occupant())
|
||||
to_chat(user, span_warning("The scanner is already occupied!"))
|
||||
return
|
||||
var/obj/item/organ/internal/brain/brain = item
|
||||
@@ -202,7 +219,7 @@
|
||||
var/obj/item/grab/G = item
|
||||
if(!ismob(G.affecting))
|
||||
return
|
||||
if(occupant)
|
||||
if(get_occupant())
|
||||
to_chat(user, span_warning("The scanner is already occupied!"))
|
||||
return
|
||||
if(G.affecting.abiotic())
|
||||
@@ -219,10 +236,10 @@
|
||||
if(beaker)
|
||||
beaker.forceMove(get_turf(src))
|
||||
beaker = null
|
||||
if(occupant)
|
||||
var/mob/living/carbon/WC = occupant.resolve()
|
||||
var/mob/living/carbon/WC = get_occupant()
|
||||
if(WC)
|
||||
WC.forceMove(get_turf(src))
|
||||
occupant = null
|
||||
set_occupant(null)
|
||||
// Disconnect from our terminal
|
||||
for(var/dirfind in GLOB.cardinal)
|
||||
var/obj/machinery/computer/scan_consolenew/console = locate(/obj/machinery/computer/scan_consolenew, get_step(src, dirfind))
|
||||
@@ -237,7 +254,7 @@
|
||||
M.client.perspective = EYE_PERSPECTIVE
|
||||
M.client.eye = src
|
||||
M.forceMove(src)
|
||||
occupant = WEAKREF(M)
|
||||
set_occupant(M)
|
||||
icon_state = "scanner_1"
|
||||
|
||||
// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
|
||||
@@ -254,9 +271,9 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/dna_scannernew/proc/go_out()
|
||||
if((!(occupant) || locked))
|
||||
var/mob/living/carbon/WC = get_occupant()
|
||||
if((!WC || locked))
|
||||
return
|
||||
var/mob/living/carbon/WC = occupant.resolve()
|
||||
if(WC.client)
|
||||
WC.client.eye = WC.client.mob
|
||||
WC.client.perspective = MOB_PERSPECTIVE
|
||||
@@ -268,7 +285,7 @@
|
||||
break
|
||||
else
|
||||
WC.forceMove(loc)
|
||||
occupant = null
|
||||
set_occupant(null)
|
||||
icon_state = "scanner_0"
|
||||
SStgui.update_uis(src)
|
||||
|
||||
@@ -395,7 +412,7 @@
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/tgui_interact(mob/user, datum/tgui/ui)
|
||||
var/mob/living/carbon/WC = connected?.occupant?.resolve()
|
||||
var/mob/living/carbon/WC = connected?.get_occupant()
|
||||
if(!connected || user == WC || user.stat)
|
||||
return
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
@@ -408,7 +425,7 @@
|
||||
var/data[0]
|
||||
data["selectedMenuKey"] = selected_menu_key
|
||||
data["locked"] = src.connected.locked
|
||||
data["hasOccupant"] = connected.occupant ? 1 : 0
|
||||
data["hasOccupant"] = connected.get_occupant() ? 1 : 0
|
||||
|
||||
data["isInjectorReady"] = injector_ready
|
||||
|
||||
@@ -448,7 +465,7 @@
|
||||
data["selectedUITargetHex"] = selected_ui_target_hex
|
||||
|
||||
var/occupantData[0]
|
||||
var/mob/living/carbon/WC = connected?.occupant?.resolve()
|
||||
var/mob/living/carbon/WC = connected?.get_occupant()
|
||||
if(!WC || !WC.dna)
|
||||
occupantData["name"] = null
|
||||
occupantData["stat"] = null
|
||||
@@ -522,7 +539,7 @@
|
||||
return TRUE
|
||||
if("toggleLock")
|
||||
playsound(src, 'sound/machines/button.ogg', 30, 1, 0)
|
||||
if(connected && connected.occupant)
|
||||
if(connected && connected.get_occupant())
|
||||
connected.locked = !(connected.locked)
|
||||
return TRUE
|
||||
|
||||
@@ -541,9 +558,9 @@
|
||||
return TRUE
|
||||
if("injectRejuvenators")
|
||||
playsound(src, 'sound/machines/button.ogg', 30, 1, 0)
|
||||
if(!connected.occupant || !connected.beaker)
|
||||
if(!connected.get_occupant() || !connected.beaker)
|
||||
return TRUE
|
||||
var/mob/living/carbon/WC = connected?.occupant?.resolve()
|
||||
var/mob/living/carbon/WC = connected?.get_occupant()
|
||||
var/inject_amount = clamp(round(text2num(params["amount"]), 5), 0, 50) // round to nearest 5 and clamp to 0-50
|
||||
if(!inject_amount)
|
||||
return TRUE
|
||||
@@ -561,9 +578,9 @@
|
||||
selected_se_subblock = clamp(select_subblock, 1, DNA_BLOCK_SIZE)
|
||||
return TRUE
|
||||
if("pulseSERadiation")
|
||||
if(!connected?.occupant)
|
||||
if(!connected?.get_occupant())
|
||||
return TRUE
|
||||
var/mob/living/carbon/WC = connected?.occupant?.resolve()
|
||||
var/mob/living/carbon/WC = connected?.get_occupant()
|
||||
playsound(src, "keyboard", 40)
|
||||
var/block = WC.dna.GetSESubBlock(selected_se_block,selected_se_subblock)
|
||||
//var/original_block=block
|
||||
@@ -604,7 +621,7 @@
|
||||
// Traitgenes Moved SE and UI saves to storing the entire body record
|
||||
if("saveDNA")
|
||||
playsound(src, "keyboard", 40) // into console
|
||||
var/mob/living/carbon/WC = connected?.occupant?.resolve()
|
||||
var/mob/living/carbon/WC = connected?.get_occupant()
|
||||
if(WC && WC.dna)
|
||||
// Traitgenes Properly clone records
|
||||
var/datum/transhuman/body_record/databuf = new /datum/transhuman/body_record()
|
||||
@@ -631,7 +648,7 @@
|
||||
tgui_modal_input(src, "changeBufferLabel", "Please enter the new buffer label:", null, list("id" = bufferId), buffer.mydna.name, TGUI_MODAL_INPUT_MAX_LENGTH_NAME)
|
||||
return TRUE
|
||||
if("transfer")
|
||||
var/mob/living/carbon/WC = connected?.occupant?.resolve()
|
||||
var/mob/living/carbon/WC = connected?.get_occupant()
|
||||
if(!WC || (NOCLONE in WC.mutations) || !WC.dna)
|
||||
return TRUE
|
||||
irradiating = 2
|
||||
@@ -673,7 +690,7 @@
|
||||
playsound(src, "keyboard", 40)
|
||||
var/datum/transhuman/body_record/buf = buffers[bufferId]
|
||||
// Send printable record to first sleevepod in area
|
||||
print_sleeve(usr, buf)
|
||||
print_sleeve(ui.user, buf)
|
||||
return TRUE
|
||||
|
||||
if("wipeDisk")
|
||||
@@ -774,12 +791,12 @@
|
||||
to_chat(user, span_danger( "Error: Cannot grow synthetic."))
|
||||
return
|
||||
//No pods
|
||||
var/obj/machinery/clonepod/transhuman/pod = locate() in get_area(src)
|
||||
var/obj/machinery/clonepod/pod = locate() in get_area(src)
|
||||
if(!pod)
|
||||
to_chat(user, span_danger( "Error: No growpods detected."))
|
||||
return
|
||||
//Already doing someone.
|
||||
if(pod.occupant)
|
||||
if(pod.get_occupant())
|
||||
to_chat(user, span_danger( "Error: Growpod is currently occupied."))
|
||||
return
|
||||
//Not enough materials.
|
||||
@@ -805,7 +822,7 @@
|
||||
to_chat(user, span_notice( "Initiating growing cycle..."))
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/proc/do_irradiate(var/lock_state, var/block)
|
||||
var/mob/living/carbon/WC = connected?.occupant?.resolve()
|
||||
var/mob/living/carbon/WC = connected?.get_occupant()
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
if(!WC)
|
||||
@@ -840,7 +857,7 @@
|
||||
WC.regenerate_icons()
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/proc/do_pulse(var/lock_state)
|
||||
var/mob/living/carbon/WC = connected?.occupant?.resolve()
|
||||
var/mob/living/carbon/WC = connected?.get_occupant()
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
@@ -872,7 +889,7 @@
|
||||
|
||||
playsound(src, "keyboard", 40)
|
||||
|
||||
var/mob/living/carbon/WC = connected?.occupant?.resolve()
|
||||
var/mob/living/carbon/WC = connected?.get_occupant()
|
||||
if(!WC)
|
||||
return TRUE
|
||||
var/datum/transhuman/body_record/buf = buffers[bufferId] // Traitgenes- Use bodyrecords
|
||||
|
||||
@@ -77,7 +77,8 @@
|
||||
|
||||
to_chat(src, span_notice("We can now re-adapt, reverting our evolution so that we may start anew, if needed."))
|
||||
|
||||
var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages, T.identifying_gender, T.flavor_texts, T.modifiers)
|
||||
var/saved_dna = T.dna.Clone() /// Prevent transforming bugginess.
|
||||
var/datum/absorbed_dna/newDNA = new(T.real_name, saved_dna, T.species.name, T.languages, T.identifying_gender, T.flavor_texts, T.modifiers)
|
||||
absorbDNA(newDNA)
|
||||
|
||||
if(T.mind && T.mind.changeling)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
icon = 'icons/obj/cloning.dmi'
|
||||
icon_state = "pod_0"
|
||||
req_access = list(access_genetics) // For premature unlocking.
|
||||
var/mob/living/occupant
|
||||
VAR_PRIVATE/datum/weakref/weakref_occupant = null
|
||||
var/heal_level = 20 // The clone is released once its health reaches this level.
|
||||
var/heal_rate = 1
|
||||
var/locked = 0
|
||||
@@ -54,12 +54,25 @@
|
||||
default_apply_parts()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/clonepod/proc/set_occupant(var/mob/living/L)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
if(!L)
|
||||
weakref_occupant = null
|
||||
return
|
||||
weakref_occupant = WEAKREF(L)
|
||||
|
||||
/obj/machinery/clonepod/proc/get_occupant()
|
||||
RETURN_TYPE(/mob/living)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
return weakref_occupant?.resolve()
|
||||
|
||||
/obj/machinery/clonepod/attack_ai(mob/user as mob)
|
||||
|
||||
add_hiddenprint(user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/clonepod/attack_hand(mob/user as mob)
|
||||
var/mob/living/occupant = get_occupant()
|
||||
if((isnull(occupant)) || (stat & NOPOWER))
|
||||
return
|
||||
if((!isnull(occupant)) && (occupant.stat != 2))
|
||||
@@ -68,27 +81,27 @@
|
||||
return
|
||||
|
||||
//Start growing a human clone in the pod!
|
||||
/obj/machinery/clonepod/proc/growclone(var/datum/dna2/record/R)
|
||||
/obj/machinery/clonepod/proc/growclone(var/datum/transhuman/body_record/BR)
|
||||
if(mess || attempting)
|
||||
return 0
|
||||
var/datum/mind/clonemind = locate(R.mind)
|
||||
var/datum/mind/clonemind = locate(BR.mydna.mind)
|
||||
|
||||
if(!istype(clonemind, /datum/mind)) //not a mind
|
||||
return 0
|
||||
if(clonemind.current && clonemind.current.stat != DEAD) //mind is associated with a non-dead body
|
||||
return 0
|
||||
if(clonemind.active) //somebody is using that mind
|
||||
if(ckey(clonemind.key) != R.ckey)
|
||||
if(ckey(clonemind.key) != BR.ckey)
|
||||
return 0
|
||||
else
|
||||
for(var/mob/observer/dead/G in player_list)
|
||||
if(G.ckey == R.ckey)
|
||||
if(G.ckey == BR.ckey)
|
||||
if(G.can_reenter_corpse)
|
||||
break
|
||||
else
|
||||
return 0
|
||||
|
||||
for(var/modifier_type in R.genetic_modifiers) //Can't be cloned, even if they had a previous scan
|
||||
for(var/modifier_type in BR.genetic_modifiers) //Can't be cloned, even if they had a previous scan
|
||||
if(istype(modifier_type, /datum/modifier/no_clone))
|
||||
return 0
|
||||
|
||||
@@ -102,23 +115,20 @@
|
||||
spawn(30)
|
||||
eject_wait = 0
|
||||
|
||||
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src, R.dna.species)
|
||||
occupant = H
|
||||
|
||||
if(!R.dna.real_name) //to prevent null names
|
||||
R.dna.real_name = "clone ([rand(0,999)])"
|
||||
H.real_name = R.dna.real_name
|
||||
H.gender = R.gender
|
||||
//Get the clone body ready, let's calculate their health so the pod doesn't immediately eject them!!!
|
||||
var/mob/living/carbon/human/H = BR.produce_human_mob(src,FALSE, FALSE, "clone ([rand(0,999)])")
|
||||
SEND_SIGNAL(H, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
//Get the clone body ready
|
||||
H.adjustCloneLoss(150) // New damage var so you can't eject a clone early then stab them to abuse the current damage system --NeoFite
|
||||
var/damage_to_deal = H.getMaxHealth() * 1.5 //If you have 100, you get 150. Have 200? Get 300. 25hp? get 37.5
|
||||
H.adjustCloneLoss(damage_to_deal) // New damage var so you can't eject a clone early then stab them to abuse the current damage system --NeoFite
|
||||
H.Paralyse(4)
|
||||
|
||||
//Here let's calculate their health so the pod doesn't immediately eject them!!!
|
||||
H.updatehealth()
|
||||
H.set_cloned_appearance()
|
||||
|
||||
// Move mind to body along with key
|
||||
clonemind.transfer_to(H)
|
||||
H.ckey = R.ckey
|
||||
H.ckey = BR.ckey
|
||||
to_chat(H, span_warning(span_bold("Consciousness slowly creeps over you as your body regenerates.") + "<br>" + span_bold(span_large("Your recent memories are fuzzy, and it's hard to remember anything from today...")) + \
|
||||
"<br>" + span_notice(span_italics("So this is what cloning feels like?"))))
|
||||
|
||||
@@ -127,48 +137,29 @@
|
||||
update_antag_icons(H.mind)
|
||||
// -- End mode specific stuff
|
||||
|
||||
if(!R.dna)
|
||||
H.dna = new /datum/dna()
|
||||
qdel_swap(H.dna, new /datum/dna())
|
||||
else
|
||||
qdel_swap(H.dna, R.dna)
|
||||
H.UpdateAppearance()
|
||||
H.sync_dna_traits(FALSE) // Traitgenes Sync traits to genetics if needed
|
||||
H.sync_organ_dna()
|
||||
H.initialize_vessel()
|
||||
|
||||
H.set_cloned_appearance()
|
||||
update_icon()
|
||||
|
||||
// A modifier is added which makes the new clone be unrobust.
|
||||
// Upgraded cloners can reduce the time of the modifier, up to 80%
|
||||
var/modifier_lower_bound = 25 MINUTES
|
||||
var/modifier_upper_bound = 40 MINUTES
|
||||
|
||||
// Upgraded cloners can reduce the time of the modifier, up to 80%
|
||||
var/clone_sickness_length = abs(((heal_level - 20) / 100 ) - 1)
|
||||
clone_sickness_length = between(0.2, clone_sickness_length, 1.0) // Caps it off just incase.
|
||||
modifier_lower_bound = round(modifier_lower_bound * clone_sickness_length, 1)
|
||||
modifier_upper_bound = round(modifier_upper_bound * clone_sickness_length, 1)
|
||||
|
||||
H.add_modifier(H.species.cloning_modifier, rand(modifier_lower_bound, modifier_upper_bound))
|
||||
|
||||
// Modifier that doesn't do anything.
|
||||
H.add_modifier(/datum/modifier/cloned)
|
||||
|
||||
// This is really stupid.
|
||||
for(var/modifier_type in R.genetic_modifiers)
|
||||
H.add_modifier(modifier_type)
|
||||
|
||||
for(var/datum/language/L in R.languages)
|
||||
H.add_language(L.name)
|
||||
|
||||
H.flavor_texts = R.flavor.Copy()
|
||||
H.suiciding = 0
|
||||
// Finished!
|
||||
update_icon()
|
||||
set_occupant(H)
|
||||
attempting = 0
|
||||
|
||||
return 1
|
||||
|
||||
//Grow clones to maturity then kick them out. FREELOADERS
|
||||
/obj/machinery/clonepod/process()
|
||||
var/mob/living/occupant = get_occupant()
|
||||
if(stat & NOPOWER) //Autoeject if power is lost
|
||||
if(occupant)
|
||||
locked = 0
|
||||
@@ -210,7 +201,7 @@
|
||||
return
|
||||
|
||||
else if((!occupant) || (occupant.loc != src))
|
||||
occupant = null
|
||||
set_occupant(null)
|
||||
if(locked)
|
||||
locked = 0
|
||||
return
|
||||
@@ -219,6 +210,7 @@
|
||||
|
||||
//Let's unlock this early I guess. Might be too early, needs tweaking.
|
||||
/obj/machinery/clonepod/attackby(obj/item/W as obj, mob/user as mob)
|
||||
var/mob/living/occupant = get_occupant()
|
||||
if(isnull(occupant))
|
||||
if(default_deconstruction_screwdriver(user, W))
|
||||
return
|
||||
@@ -272,7 +264,7 @@
|
||||
..()
|
||||
|
||||
/obj/machinery/clonepod/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(isnull(occupant))
|
||||
if(isnull(get_occupant()))
|
||||
return
|
||||
to_chat(user, "You force an emergency ejection.")
|
||||
locked = 0
|
||||
@@ -301,7 +293,7 @@
|
||||
heal_level = max(min((efficiency * 15) + 10, 100), MINIMUM_HEAL_LEVEL)
|
||||
|
||||
/obj/machinery/clonepod/proc/get_completion()
|
||||
. = (100 * ((occupant.health + 100) / (heal_level + 100)))
|
||||
. = (100 * ((get_occupant().health + 100) / (heal_level + 100)))
|
||||
|
||||
/obj/machinery/clonepod/verb/eject()
|
||||
set name = "Eject Cloner"
|
||||
@@ -324,20 +316,21 @@
|
||||
update_icon()
|
||||
return
|
||||
|
||||
var/mob/living/occupant = get_occupant()
|
||||
if(!(occupant))
|
||||
return
|
||||
|
||||
if(occupant.client)
|
||||
occupant.client.eye = occupant.client.mob
|
||||
occupant.client.perspective = MOB_PERSPECTIVE
|
||||
occupant.loc = src.loc
|
||||
occupant.forceMove(get_turf(src))
|
||||
eject_wait = 0 //If it's still set somehow.
|
||||
if(ishuman(occupant)) //Need to be safe.
|
||||
var/mob/living/carbon/human/patient = occupant
|
||||
if(!(patient.species.flags & NO_DNA)) //If, for some reason, someone makes a genetically-unalterable clone, let's not make them permanently disabled.
|
||||
domutcheck(occupant) //Waiting until they're out before possible transforming.
|
||||
occupant.UpdateAppearance()
|
||||
occupant = null
|
||||
set_occupant(null)
|
||||
|
||||
update_icon()
|
||||
return
|
||||
@@ -400,6 +393,7 @@
|
||||
return 0
|
||||
|
||||
/obj/machinery/clonepod/proc/malfunction()
|
||||
var/mob/living/occupant = get_occupant()
|
||||
if(occupant)
|
||||
connected_message("Critical Error!")
|
||||
mess = 1
|
||||
@@ -421,21 +415,21 @@
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
for(var/atom/movable/A as mob|obj in src)
|
||||
A.loc = src.loc
|
||||
A.forceMove(get_turf(src))
|
||||
ex_act(severity)
|
||||
qdel(src)
|
||||
return
|
||||
if(2.0)
|
||||
if(prob(50))
|
||||
for(var/atom/movable/A as mob|obj in src)
|
||||
A.loc = src.loc
|
||||
A.forceMove(get_turf(src))
|
||||
ex_act(severity)
|
||||
qdel(src)
|
||||
return
|
||||
if(3.0)
|
||||
if(prob(25))
|
||||
for(var/atom/movable/A as mob|obj in src)
|
||||
A.loc = src.loc
|
||||
A.forceMove(get_turf(src))
|
||||
ex_act(severity)
|
||||
qdel(src)
|
||||
return
|
||||
@@ -444,7 +438,7 @@
|
||||
/obj/machinery/clonepod/update_icon()
|
||||
..()
|
||||
icon_state = "pod_0"
|
||||
if(occupant && !(stat & NOPOWER))
|
||||
if(get_occupant() && !(stat & NOPOWER))
|
||||
icon_state = "pod_1"
|
||||
else if(mess)
|
||||
icon_state = "pod_g"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
var/list/scantemp = null
|
||||
var/menu = MENU_MAIN //Which menu screen to display
|
||||
var/list/records = null
|
||||
var/datum/dna2/record/active_record = null
|
||||
var/datum/transhuman/body_record/active_BR = null
|
||||
var/obj/item/disk/body_record/diskette = null // Traitgenes - Storing the entire body record
|
||||
var/loading = 0 // Nice loading text
|
||||
var/autoprocess = 0
|
||||
@@ -34,27 +34,26 @@
|
||||
|
||||
/obj/machinery/computer/cloning/Destroy()
|
||||
releasecloner()
|
||||
for(var/datum/dna2/record/R in records)
|
||||
qdel(R.dna)
|
||||
qdel(R)
|
||||
for(var/datum/transhuman/body_record/BR in records)
|
||||
qdel(BR)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/cloning/process()
|
||||
if(!scanner || !pods.len || !autoprocess || stat & NOPOWER)
|
||||
return
|
||||
|
||||
if(scanner.occupant && can_autoprocess())
|
||||
scan_mob(scanner.occupant)
|
||||
if(scanner.get_occupant() && can_autoprocess())
|
||||
scan_mob(scanner.get_occupant())
|
||||
|
||||
if(!LAZYLEN(records))
|
||||
return
|
||||
|
||||
for(var/obj/machinery/clonepod/pod in pods)
|
||||
if(!(pod.occupant || pod.mess) && (pod.efficiency > 5))
|
||||
for(var/datum/dna2/record/R in records)
|
||||
if(!(pod.occupant || pod.mess))
|
||||
if(pod.growclone(R))
|
||||
records.Remove(R)
|
||||
if(!(pod.get_occupant() || pod.mess) && (pod.efficiency > 5))
|
||||
for(var/datum/transhuman/body_record/BR in records)
|
||||
if(!(pod.get_occupant() || pod.mess))
|
||||
if(pod.growclone(BR))
|
||||
records.Remove(BR)
|
||||
|
||||
/obj/machinery/computer/cloning/proc/updatemodules()
|
||||
scanner = findscanner()
|
||||
@@ -67,8 +66,8 @@
|
||||
var/obj/machinery/dna_scannernew/scannerf = null
|
||||
|
||||
//Try to find scanner on adjacent tiles first
|
||||
for(dir in list(NORTH,EAST,SOUTH,WEST))
|
||||
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, dir))
|
||||
for(var/scan_dir in list(NORTH,EAST,SOUTH,WEST))
|
||||
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, scan_dir))
|
||||
if(scannerf)
|
||||
return scannerf
|
||||
|
||||
@@ -97,7 +96,7 @@
|
||||
if(istype(W, /obj/item/disk/body_record/)) //Traitgenes Storing the entire body record
|
||||
if(!diskette)
|
||||
user.drop_item()
|
||||
W.loc = src
|
||||
W.forceMove(src)
|
||||
diskette = W
|
||||
to_chat(user, "You insert [W].")
|
||||
SStgui.update_uis(src)
|
||||
@@ -154,17 +153,18 @@
|
||||
if(pod.efficiency > 5)
|
||||
canpodautoprocess = 1
|
||||
|
||||
var/mob/living/occupant = pod.get_occupant()
|
||||
var/status = "idle"
|
||||
if(pod.mess)
|
||||
status = "mess"
|
||||
else if(pod.occupant && !(pod.stat & NOPOWER))
|
||||
else if(occupant && !(pod.stat & NOPOWER))
|
||||
status = "cloning"
|
||||
tempods.Add(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"] = tempods
|
||||
|
||||
@@ -178,16 +178,16 @@
|
||||
else
|
||||
data["autoallowed"] = 0
|
||||
if(scanner)
|
||||
data["occupant"] = scanner.occupant
|
||||
data["occupant"] = scanner.get_occupant()
|
||||
data["locked"] = scanner.locked
|
||||
data["temp"] = temp
|
||||
data["scantemp"] = scantemp
|
||||
data["disk"] = diskette
|
||||
data["selected_pod"] = "\ref[selected_pod]"
|
||||
var/list/temprecords[0]
|
||||
for(var/datum/dna2/record/R in records)
|
||||
var tempRealName = R.dna.real_name
|
||||
temprecords.Add(list(list("record" = "\ref[R]", "realname" = sanitize(tempRealName))))
|
||||
for(var/datum/transhuman/body_record/BR in records)
|
||||
var tempRealName = BR.mydna.dna.real_name
|
||||
temprecords.Add(list(list("record" = "\ref[BR]", "realname" = sanitize(tempRealName))))
|
||||
data["records"] = temprecords
|
||||
|
||||
if(selected_pod && (selected_pod in pods) && selected_pod.get_biomass() >= CLONE_BIOMASS)
|
||||
@@ -206,67 +206,68 @@
|
||||
. = TRUE
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
if(params["id"] == "del_rec" && active_record)
|
||||
if(params["id"] == "del_rec" && active_BR)
|
||||
var/obj/item/card/id/C = ui.user.get_active_hand()
|
||||
if(!istype(C) && !istype(C, /obj/item/pda))
|
||||
set_temp("ID not in hand.", "danger")
|
||||
return
|
||||
if(check_access(C))
|
||||
records.Remove(active_record)
|
||||
qdel(active_record.dna)
|
||||
qdel(active_record)
|
||||
records.Remove(active_BR)
|
||||
qdel(active_BR) // Already deletes dna in destroy()
|
||||
set_temp("Record deleted.", "success")
|
||||
menu = MENU_RECORDS
|
||||
else
|
||||
set_temp("Access denied.", "danger")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/scanner_occupant = scanner.get_occupant()
|
||||
|
||||
switch(action)
|
||||
if("scan")
|
||||
if(!scanner || !scanner.occupant || loading)
|
||||
if(!scanner || !scanner_occupant || loading)
|
||||
return
|
||||
set_scan_temp("Scanner ready.", "good")
|
||||
loading = TRUE
|
||||
|
||||
spawn(20)
|
||||
if(can_brainscan() && scan_mode)
|
||||
scan_mob(scanner.occupant, scan_brain = TRUE)
|
||||
scan_mob(scanner_occupant, scan_brain = TRUE)
|
||||
else
|
||||
scan_mob(scanner.occupant)
|
||||
scan_mob(scanner_occupant)
|
||||
loading = FALSE
|
||||
SStgui.update_uis(src)
|
||||
if("autoprocess")
|
||||
autoprocess = text2num(params["on"]) > 0
|
||||
if("lock")
|
||||
if(isnull(scanner) || !scanner.occupant) //No locking an open scanner.
|
||||
if(isnull(scanner) || !scanner_occupant) //No locking an open scanner.
|
||||
return
|
||||
scanner.locked = !scanner.locked
|
||||
if("view_rec")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
active_record = locate(ref)
|
||||
if(istype(active_record))
|
||||
if(isnull(active_record.ckey))
|
||||
qdel(active_record)
|
||||
active_BR = locate(ref)
|
||||
if(istype(active_BR))
|
||||
if(isnull(active_BR.ckey))
|
||||
qdel(active_BR)
|
||||
set_temp("Error: Record corrupt.", "danger")
|
||||
else
|
||||
var/obj/item/implant/health/H = null
|
||||
if(active_record.implant)
|
||||
H = locate(active_record.implant)
|
||||
if(active_BR.mydna.implant)
|
||||
H = locate(active_BR.mydna.implant)
|
||||
var/list/payload = list(
|
||||
activerecord = "\ref[active_record]",
|
||||
activerecord = "\ref[active_BR]",
|
||||
health = (H && istype(H)) ? H.sensehealth() : "",
|
||||
realname = sanitize(active_record.dna.real_name),
|
||||
unidentity = active_record.dna.uni_identity,
|
||||
strucenzymes = active_record.dna.struc_enzymes,
|
||||
realname = sanitize(active_BR.mydna.dna.real_name),
|
||||
unidentity = active_BR.mydna.dna.uni_identity,
|
||||
strucenzymes = active_BR.mydna.dna.struc_enzymes,
|
||||
)
|
||||
tgui_modal_message(src, action, "", null, payload)
|
||||
else
|
||||
active_record = null
|
||||
active_BR = null
|
||||
set_temp("Error: Record missing.", "danger")
|
||||
if("del_rec")
|
||||
if(!active_record)
|
||||
if(!active_BR)
|
||||
return
|
||||
tgui_modal_boolean(src, action, "Please confirm that you want to delete the record by holding your ID and pressing Delete:", yes_text = "Delete", no_text = "Cancel")
|
||||
if("disk") // Disk management.
|
||||
@@ -277,24 +278,24 @@
|
||||
if(isnull(diskette) || isnull(diskette.stored)) // Traitgenes Storing the entire body record
|
||||
set_temp("Error: The disk's data could not be read.", "danger")
|
||||
return
|
||||
else if(isnull(active_record))
|
||||
else if(isnull(active_BR))
|
||||
set_temp("Error: No active record was found.", "danger")
|
||||
menu = MENU_MAIN
|
||||
return
|
||||
|
||||
active_record = diskette.stored.mydna // Traitgenes Storing the entire body record
|
||||
active_BR = new(diskette.stored) // Traitgenes Storing the entire body record
|
||||
set_temp("Successfully loaded from disk.", "success")
|
||||
if("save")
|
||||
if(isnull(diskette) || isnull(active_record)) // Traitgenes Removed readonly
|
||||
if(isnull(diskette) || isnull(active_BR)) // Traitgenes Removed readonly
|
||||
set_temp("Error: The data could not be saved.", "danger")
|
||||
return
|
||||
|
||||
diskette.stored.mydna = active_record // Traitgenes Storing the entire body record
|
||||
diskette.name = "data disk - '[active_record.dna.real_name]'"
|
||||
diskette.stored = new(active_BR) // Traitgenes Storing the entire body record
|
||||
diskette.name = "data disk - '[active_BR.mydna.dna.real_name]'"
|
||||
set_temp("Successfully saved to disk.", "success")
|
||||
if("eject")
|
||||
if(!isnull(diskette))
|
||||
diskette.loc = loc
|
||||
diskette.forceMove(get_turf(src))
|
||||
diskette = null
|
||||
if("refresh")
|
||||
SStgui.update_uis(src)
|
||||
@@ -309,7 +310,7 @@
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
var/datum/dna2/record/C = locate(ref)
|
||||
var/datum/transhuman/body_record/C = locate(ref)
|
||||
//Look for that player! They better be dead!
|
||||
if(istype(C))
|
||||
tgui_modal_clear(src)
|
||||
@@ -321,7 +322,7 @@
|
||||
var/cloneresult
|
||||
if(!selected_pod)
|
||||
set_temp("Error: No cloning pod selected.", "danger")
|
||||
else if(pod.occupant)
|
||||
else if(pod.get_occupant())
|
||||
set_temp("Error: The cloning pod is currently occupied.", "danger")
|
||||
else if(pod.get_biomass() < CLONE_BIOMASS)
|
||||
set_temp("Error: Not enough biomass.", "danger")
|
||||
@@ -335,7 +336,6 @@
|
||||
set_temp("Initiating cloning cycle...", "success")
|
||||
playsound(src, 'sound/machines/medbayscanner1.ogg', 100, 1)
|
||||
records.Remove(C)
|
||||
qdel(C.dna)
|
||||
qdel(C)
|
||||
menu = MENU_MAIN
|
||||
else
|
||||
@@ -407,49 +407,38 @@
|
||||
return
|
||||
|
||||
for(var/obj/machinery/clonepod/pod in pods)
|
||||
if(pod.occupant && pod.occupant.mind == subject.mind)
|
||||
var/mob/living/occupant = pod.get_occupant()
|
||||
if(occupant && occupant.mind == subject.mind)
|
||||
set_scan_temp("Subject already getting cloned.")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
subject.dna.check_integrity()
|
||||
|
||||
var/datum/dna2/record/R = new /datum/dna2/record()
|
||||
qdel_swap(R.dna, subject.dna)
|
||||
R.ckey = subject.ckey
|
||||
R.id = copytext(md5(subject.real_name), 2, 6)
|
||||
R.name = R.dna.real_name
|
||||
R.types = DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE
|
||||
R.languages = subject.languages
|
||||
R.gender = subject.gender
|
||||
R.flavor = subject.flavor_texts.Copy()
|
||||
for(var/datum/modifier/mod in subject.modifiers)
|
||||
if(mod.flags & MODIFIER_GENETIC)
|
||||
R.genetic_modifiers.Add(mod.type)
|
||||
var/datum/transhuman/body_record/BR = new(subject)
|
||||
|
||||
//Add an implant if needed
|
||||
var/obj/item/implant/health/imp = locate(/obj/item/implant/health, subject)
|
||||
if (isnull(imp))
|
||||
imp = new /obj/item/implant/health(subject)
|
||||
imp.implanted = subject
|
||||
R.implant = "\ref[imp]"
|
||||
BR.mydna.implant = "\ref[imp]"
|
||||
//Update it if needed
|
||||
else
|
||||
R.implant = "\ref[imp]"
|
||||
BR.mydna.implant = "\ref[imp]"
|
||||
|
||||
if (!isnull(subject.mind)) //Save that mind so traitors can continue traitoring after cloning.
|
||||
R.mind = "\ref[subject.mind]"
|
||||
BR.mydna.mind = "\ref[subject.mind]"
|
||||
|
||||
records += R
|
||||
records += BR
|
||||
set_scan_temp("Subject successfully scanned.", "good")
|
||||
SStgui.update_uis(src)
|
||||
|
||||
//Find a specific record by key.
|
||||
/obj/machinery/computer/cloning/proc/find_record(var/find_key)
|
||||
var/selected_record = null
|
||||
for(var/datum/dna2/record/R in records)
|
||||
if(R.ckey == find_key)
|
||||
selected_record = R
|
||||
for(var/datum/transhuman/body_record/BR in records)
|
||||
if(BR.mydna.ckey == find_key)
|
||||
selected_record = BR
|
||||
break
|
||||
return selected_record
|
||||
|
||||
|
||||
@@ -271,6 +271,8 @@
|
||||
if(def_lang)
|
||||
P.default_language = def_lang
|
||||
|
||||
SEND_SIGNAL(P, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
protean_brain.brainmob.mind.transfer_to(P)
|
||||
protean_brain.loc = BR
|
||||
protean_refactory = null
|
||||
|
||||
@@ -135,6 +135,8 @@
|
||||
avatar.sync_organ_dna()
|
||||
avatar.initialize_vessel()
|
||||
|
||||
SEND_SIGNAL(avatar, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
var/newname = sanitize(tgui_input_text(avatar, "Your mind feels foggy. You're certain your name is [occupant.real_name], but it could also be [avatar.name]. Would you like to change it to something else?", "Name change", null, MAX_NAME_LEN), MAX_NAME_LEN)
|
||||
if (newname)
|
||||
avatar.real_name = newname
|
||||
|
||||
@@ -314,6 +314,8 @@
|
||||
avatar.sync_organ_dna()
|
||||
avatar.initialize_vessel()
|
||||
|
||||
SEND_SIGNAL(avatar, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
if(tf)
|
||||
var/mob/living/new_form = avatar.transform_into_mob(tf, TRUE) // No need to check prefs when the occupant already chose to transform.
|
||||
if(isliving(new_form)) // Make sure the mob spawned properly.
|
||||
|
||||
@@ -106,6 +106,8 @@
|
||||
if(is_lang_whitelisted(usr,chosen_language) || (avatar.species && (chosen_language.name in avatar.species.secondary_langs)))
|
||||
avatar.add_language(lang)
|
||||
|
||||
SEND_SIGNAL(avatar, COMSIG_HUMAN_DNA_FINALIZED)
|
||||
|
||||
avatar.regenerate_icons()
|
||||
avatar.update_transform()
|
||||
job_master.EquipRank(avatar,JOB_VR, 1, FALSE)
|
||||
|
||||
@@ -257,6 +257,8 @@
|
||||
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)
|
||||
|
||||
new_character.regenerate_icons()
|
||||
|
||||
new_character.update_transform()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -533,7 +533,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()
|
||||
@@ -544,7 +544,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)
|
||||
@@ -554,6 +555,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
|
||||
|
||||
@@ -581,7 +583,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,
|
||||
@@ -616,17 +617,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
|
||||
|
||||
@@ -801,11 +801,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,
|
||||
@@ -410,3 +402,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()
|
||||
|
||||
@@ -447,15 +447,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
|
||||
|
||||
@@ -514,3 +514,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
|
||||
@@ -293,8 +296,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
|
||||
|
||||
|
||||
@@ -151,9 +151,9 @@
|
||||
if(comp.revive_ready >= 1) // if it's not reviving, start doing so
|
||||
comp.revive_ready = REVIVING_READY // overrides the normal cooldown
|
||||
H.visible_message(span_info("[H] shudders briefly, then relaxes, faint movements stirring within."))
|
||||
H.chimera_regenerate()
|
||||
comp.chimera_regenerate()
|
||||
else if(comp.revive_ready == REVIVING_DONE)// already reviving, check if they're ready to hatch
|
||||
H.chimera_hatch()
|
||||
comp.chimera_hatch()
|
||||
H.visible_message(span_danger(span_huge("[H] violently convulses and then bursts open, revealing a new, intact copy in the pool of viscera."))) // Hope you were wearing waterproofs, doc...
|
||||
H.adjustBrainLoss(10) // they're reviving from dead, so take 10 brainloss
|
||||
else //they're already reviving but haven't hatched. Give a little message to tell them to wait.
|
||||
|
||||
@@ -188,6 +188,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,86 +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)
|
||||
H.resleeve_lock = current_project.ckey //CHOMPAdd, keep the lock
|
||||
/*CHOMPRemove Start
|
||||
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"
|
||||
*///CHOMPRemove End
|
||||
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)
|
||||
@@ -124,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()
|
||||
@@ -150,6 +59,7 @@
|
||||
return 1
|
||||
|
||||
/obj/machinery/clonepod/transhuman/process()
|
||||
var/mob/living/occupant = get_occupant()
|
||||
if(stat & NOPOWER)
|
||||
if(occupant)
|
||||
locked = 0
|
||||
@@ -190,7 +100,7 @@
|
||||
return
|
||||
|
||||
else if((!occupant) || (occupant.loc != src))
|
||||
occupant = null
|
||||
set_occupant(null)
|
||||
if(locked)
|
||||
locked = 0
|
||||
update_icon()
|
||||
@@ -199,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)]"
|
||||
|
||||
@@ -298,103 +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)
|
||||
H.resleeve_lock = current_project.ckey //CHOMPAdd, keep the lock
|
||||
/*CHOMPRemove Start
|
||||
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"
|
||||
*///CHOMPRemove End
|
||||
|
||||
//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
|
||||
//CHOMPEdit Start
|
||||
H.ooc_notes_favs = current_project.body_oocfavs
|
||||
H.ooc_notes_maybes = current_project.body_oocmaybes
|
||||
H.ooc_notes_style = current_project.body_oocstyle
|
||||
//CHOMPEdit End
|
||||
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
|
||||
@@ -470,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
|
||||
@@ -487,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)
|
||||
@@ -513,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)
|
||||
@@ -583,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
|
||||
|
||||
@@ -665,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
|
||||
|
||||
@@ -679,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)
|
||||
@@ -687,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()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useBackend } from 'tgui/backend';
|
||||
import { Button, ColorBox, LabeledList, Section } from 'tgui-core/components';
|
||||
import { Button, LabeledList, Section } from 'tgui-core/components';
|
||||
|
||||
import type { Data, species } from './types';
|
||||
|
||||
@@ -35,65 +35,8 @@ export const AppearanceChangerSpecies = (props) => {
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<LabeledList.Item label="Custom Species Name">
|
||||
<Button icon="pen" onClick={() => act('race_name')}>
|
||||
{data.species_name ? data.species_name : specimen}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Species Appearance">
|
||||
<Button
|
||||
icon="pen"
|
||||
disabled={!data.use_custom_icon}
|
||||
onClick={() => act('base_icon')}
|
||||
>
|
||||
{data.base_icon ? data.base_icon : specimen}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Blood Reagent">
|
||||
<Button icon="pen" onClick={() => act('blood_reagent')}>
|
||||
{data.blood_reagent}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Blood Color">
|
||||
<Button icon="pen" onClick={() => act('blood_color')}>
|
||||
{data.blood_color}
|
||||
</Button>
|
||||
<ColorBox color={data.blood_color} mr={1} />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Digitigrade">
|
||||
<Button icon="pen" onClick={() => act('digitigrade')}>
|
||||
{data.digitigrade ? 'Yes' : 'No'}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Species Sound">
|
||||
<Button icon="pen" onClick={() => act('species_sound')}>
|
||||
{data.species_sound}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
<Section title="Sizing">
|
||||
<LabeledList.Item label="Scale">
|
||||
<Button icon="pen" onClick={() => act('size_scale')}>
|
||||
{data.size_scale}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Scale Appearance">
|
||||
<Button icon="pen" onClick={() => act('scale_appearance')}>
|
||||
{data.scale_appearance}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Scale Offset">
|
||||
<Button icon="pen" onClick={() => act('offset_override')}>
|
||||
{data.offset_override}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Weight">
|
||||
<Button icon="pen" onClick={() => act('weight')}>
|
||||
{data.weight}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</Section>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import { useBackend } from 'tgui/backend';
|
||||
import {
|
||||
Button,
|
||||
ColorBox,
|
||||
LabeledList,
|
||||
Section,
|
||||
Stack,
|
||||
} from 'tgui-core/components';
|
||||
|
||||
import type { Data } from './types';
|
||||
|
||||
export const AppearanceChangerMisc = (props) => {
|
||||
const { act, data } = useBackend<Data>();
|
||||
const { specimen } = data;
|
||||
return (
|
||||
<Section title="Misc" fill scrollable>
|
||||
<Stack vertical fill>
|
||||
<Section title="Load Currently Selected Savefile">
|
||||
<LabeledList.Item label="Load Savefile">
|
||||
<Button icon="pen" onClick={() => act('load_saveslot')}>
|
||||
{'Load'}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</Section>
|
||||
<Section title="Appearance">
|
||||
<LabeledList.Item label="Species Appearance">
|
||||
<Button
|
||||
icon="pen"
|
||||
disabled={!data.use_custom_icon}
|
||||
onClick={() => act('base_icon')}
|
||||
>
|
||||
{data.base_icon ? data.base_icon : specimen}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Digitigrade">
|
||||
<Button icon="pen" onClick={() => act('digitigrade')}>
|
||||
{data.digitigrade ? 'Yes' : 'No'}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Custom Species Name">
|
||||
<Button icon="pen" onClick={() => act('race_name')}>
|
||||
{data.species_name ? data.species_name : specimen}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Species Sound">
|
||||
<Button icon="pen" onClick={() => act('species_sound')}>
|
||||
{data.species_sound}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</Section>
|
||||
<Section title="Scaling">
|
||||
<LabeledList.Item label="Scale">
|
||||
<Button icon="pen" onClick={() => act('size_scale')}>
|
||||
{data.size_scale}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Scale Offset">
|
||||
<Button icon="pen" onClick={() => act('offset_override')}>
|
||||
{data.offset_override}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Scale Appearance">
|
||||
<Button icon="pen" onClick={() => act('scale_appearance')}>
|
||||
{data.scale_appearance}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</Section>
|
||||
<Section title="Sizing">
|
||||
<LabeledList.Item label="Weight">
|
||||
<Button icon="pen" onClick={() => act('weight')}>
|
||||
{data.weight}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</Section>
|
||||
<Section title="Blood">
|
||||
<LabeledList.Item label="Blood Reagent">
|
||||
<Button icon="pen" onClick={() => act('blood_reagent')}>
|
||||
{data.blood_reagent}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Blood Color">
|
||||
<Stack align="center">
|
||||
<Stack.Item>
|
||||
<Button icon="pen" onClick={() => act('blood_color')}>
|
||||
{data.blood_color}
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<ColorBox color={data.blood_color} mr={1} />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</LabeledList.Item>
|
||||
</Section>
|
||||
</Stack>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -16,4 +16,5 @@ export const TAB_EARS2 = 7;
|
||||
export const TAB_TAIL = 8;
|
||||
export const TAB_WINGS = 9;
|
||||
export const TAB_MARKINGS = 10;
|
||||
export const TAB_MISC = 11;
|
||||
export const MARKINGS_PER_PAGE = 30;
|
||||
|
||||
@@ -21,6 +21,7 @@ import { AppearanceChangerColors } from './AppearanceChangerColors';
|
||||
import { AppearanceChangerFlavor } from './AppearanceChangerFlavor';
|
||||
import { AppearanceChangerHeader } from './AppearanceChangerHeader';
|
||||
import { AppearanceChangerMarkings } from './AppearanceChangerMarkings';
|
||||
import { AppearanceChangerMisc } from './AppearanceChangerMisc';
|
||||
import {
|
||||
AppearanceChangerHair,
|
||||
AppearanceChangerParts,
|
||||
@@ -34,6 +35,7 @@ import {
|
||||
TAB_GENDER,
|
||||
TAB_HAIR,
|
||||
TAB_MARKINGS,
|
||||
TAB_MISC,
|
||||
TAB_RACE,
|
||||
TAB_TAIL,
|
||||
TAB_WINGS,
|
||||
@@ -60,6 +62,7 @@ export const AppearanceChanger = (props) => {
|
||||
wing_style,
|
||||
wing_styles,
|
||||
change_race,
|
||||
change_misc,
|
||||
change_gender,
|
||||
change_eye_color,
|
||||
change_skin_tone,
|
||||
@@ -90,7 +93,7 @@ export const AppearanceChanger = (props) => {
|
||||
) : (
|
||||
<AppearanceChangerDefaultError />
|
||||
);
|
||||
tab[TAB_FLAVOR] = change_race ? (
|
||||
tab[TAB_FLAVOR] = change_misc ? (
|
||||
<AppearanceChangerFlavor />
|
||||
) : (
|
||||
<AppearanceChangerDefaultError />
|
||||
@@ -180,6 +183,11 @@ export const AppearanceChanger = (props) => {
|
||||
) : (
|
||||
<AppearanceChangerDefaultError />
|
||||
);
|
||||
tab[TAB_MISC] = change_misc ? (
|
||||
<AppearanceChangerMisc />
|
||||
) : (
|
||||
<AppearanceChangerDefaultError />
|
||||
);
|
||||
|
||||
let firstAccesibleTab = -1;
|
||||
if (change_race) {
|
||||
@@ -378,6 +386,14 @@ export const AppearanceChanger = (props) => {
|
||||
</Tabs.Tab>
|
||||
</>
|
||||
) : null}
|
||||
{change_misc ? (
|
||||
<Tabs.Tab
|
||||
selected={tabIndex === TAB_MISC}
|
||||
onClick={() => setTabIndex(TAB_MISC)}
|
||||
>
|
||||
Misc
|
||||
</Tabs.Tab>
|
||||
) : null}
|
||||
</Tabs>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>{tab[tabIndex]}</Stack.Item>
|
||||
|
||||
@@ -17,6 +17,7 @@ export type Data = {
|
||||
tail_styles: styles[];
|
||||
markings: { marking_name: string; marking_color: string }[];
|
||||
change_race: BooleanLike;
|
||||
change_misc: BooleanLike;
|
||||
change_gender: BooleanLike;
|
||||
genders: genders;
|
||||
id_genders: genders;
|
||||
|
||||
@@ -179,6 +179,7 @@
|
||||
#include "code\__defines\typeids.dm"
|
||||
#include "code\__defines\unit_tests.dm"
|
||||
#include "code\__defines\update_icons.dm"
|
||||
#include "code\__defines\var_copy.dm"
|
||||
#include "code\__defines\vchatlog.dm"
|
||||
#include "code\__defines\verb_manager.dm"
|
||||
#include "code\__defines\visualnet.dm"
|
||||
|
||||
Reference in New Issue
Block a user