mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 13:10:02 +01:00
Streamlines Life() a little (#96215)
## About The Pull Request Main changes - `handle_mutations` is gone, DNA Injectors are now managed via a status effect - `handle_diseases` is gone, disease stages are just handled via life signal - `handle_bodyparts` is gone, it was unused and in the future any implementations should use a life signal - `spec_life` is gone, the main content of it is now in `human/Life`, most children implementations now use life signal, zombie tongues now handle zombie groans - Life signal was split in two (pre and active) Other changes - DNA injector code was cleaned up considerably - HARS now alerts admins when you inject someone else with it like Monkey - `COPY_DNA_SE` is no longer mistakenly unused (meaning stuff like transformation sting no longer copies "active mutations") ## Why It's Good For The Game Across the course of a full round we spend the same amount of time doing literally nothing in life as we spend on handling human breathing. Now in the context of a full round this is 8 seconds. Which in the grand scheme of things, not a whole lot, but if we can get a tiny performance gain from... not doing literally nothing (especially when we can do these things cleaner with signals) that's a win in my book ## Changelog 🆑 Melbert refactor: Refactored dna injectors (both the ones that change appearance and activate mutations), report any oddities with them like failing to revert your appearance or mutations not applying correctly code: Ever so slightly changed how diseases tick, report any oddities code: Ever so slightly changed how some species mechanics tick, like golems and slimes, report any oddities code: The code behind printing appearance modifying dna injectors from genetics has changed, report any oddities code: Some backend transformation sting code changed slightly, report any oddities code: Zombie "idle" groaning is now tied to the tongue rather than the species itself admin: Force-injecting someone with HARS give an admin alert, the same as force-injecting someone with Monkey fix: Several methods of copying DNA (including transformation sting) mistakenly copied "active mutations", this has been fixed /🆑 --------- Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
This commit is contained in:
co-authored by
John Willard
parent
7cf48344fb
commit
e68c1edad1
@@ -21,8 +21,6 @@
|
||||
#define MUTATION_SOURCE_ACTIVATED "activated"
|
||||
///Source for mutations that have been added via mutators
|
||||
#define MUTATION_SOURCE_MUTATOR "mutator"
|
||||
///From timed dna injectors.
|
||||
#define MUTATION_SOURCE_TIMED_INJECTOR "timed_injector"
|
||||
///From mob/living/carbon/human/proc/crewlike_monkify()
|
||||
#define MUTATION_SOURCE_CREW_MONKEY "crew_monkey"
|
||||
#define MUTATION_SOURCE_MEDIEVAL_CTF "medieval_ctf"
|
||||
@@ -78,14 +76,14 @@
|
||||
#define FEATURE_TAILSPINES "tailspines" // Different from regular spines, these appear on tails
|
||||
#define FEATURE_LEGS "legs"
|
||||
|
||||
///flag for the transfer_flag argument from dna/proc/copy_dna(). This one makes it so the SE is copied too.
|
||||
// flag for the transfer_flag argument from dna/proc/copy_dna().
|
||||
/// Copies SE (mob's innate mutations)
|
||||
#define COPY_DNA_SE (1<<0)
|
||||
///flag for the transfer_flag argument from dna/proc/copy_dna(). This one copies the species.
|
||||
/// Copies the species.
|
||||
#define COPY_DNA_SPECIES (1<<1)
|
||||
///flag for the transfer_flag argument from dna/proc/copy_dna(). This one copies the mutations.
|
||||
/// Copies active mutations and anything mutated from other means
|
||||
#define COPY_DNA_MUTATIONS (1<<2)
|
||||
|
||||
|
||||
//organ slots
|
||||
#define ORGAN_SLOT_ADAMANTINE_RESONATOR "adamantine_resonator"
|
||||
#define ORGAN_SLOT_APPENDIX "appendix"
|
||||
|
||||
@@ -61,9 +61,11 @@
|
||||
///from base of mob/living/set_usable_legs()
|
||||
#define COMSIG_LIVING_LIMBLESS_SLOWDOWN "living_limbless_slowdown"
|
||||
///From living/Life(). (deltatime)
|
||||
#define COMSIG_LIVING_LIFE "living_life"
|
||||
#define COMSIG_LIVING_PRE_LIFE "living_pre_life"
|
||||
/// Block the Life() proc from proceeding... this should really only be done in some really wacky situations.
|
||||
#define COMPONENT_LIVING_CANCEL_LIFE_PROCESSING (1<<0)
|
||||
///From living/Life(). (deltatime)
|
||||
#define COMSIG_LIVING_LIFE "living_life"
|
||||
///From living/set_resting(): (new_resting, silent, instant)
|
||||
#define COMSIG_LIVING_RESTING "living_resting"
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
/datum/disease/proc/register_disease_signals()
|
||||
if(isnull(affected_mob))
|
||||
return
|
||||
RegisterSignal(affected_mob, COMSIG_LIVING_LIFE, PROC_REF(on_life))
|
||||
if(spread_flags & DISEASE_SPREAD_AIRBORNE)
|
||||
RegisterSignal(affected_mob, COMSIG_CARBON_PRE_BREATHE, PROC_REF(on_breath))
|
||||
|
||||
@@ -103,12 +104,21 @@
|
||||
/datum/disease/proc/unregister_disease_signals()
|
||||
if(isnull(affected_mob))
|
||||
return
|
||||
UnregisterSignal(affected_mob, COMSIG_CARBON_PRE_BREATHE)
|
||||
UnregisterSignal(affected_mob, list(COMSIG_LIVING_LIFE, COMSIG_CARBON_PRE_BREATHE))
|
||||
|
||||
// Proc to determine if the virus can resist natural recovery
|
||||
/datum/disease/proc/get_recovery_failure_chance()
|
||||
return 0
|
||||
|
||||
/datum/disease/proc/on_life(datum/source, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
if(HAS_TRAIT(affected_mob, TRAIT_STASIS) || QDELETED(src) || (affected_mob.stat == DEAD && !process_dead))
|
||||
return
|
||||
|
||||
stage_act(seconds_per_tick)
|
||||
|
||||
///Proc to process the disease and decide on whether to advance, cure or make the symptoms appear. Returns a boolean on whether to continue acting on the symptoms or not.
|
||||
/datum/disease/proc/stage_act(seconds_per_tick)
|
||||
var/slowdown = HAS_TRAIT(affected_mob, TRAIT_VIRUS_RESISTANCE) ? 0.5 : 1 // spaceacillin slows stage speed by 50%
|
||||
|
||||
+6
-11
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
GLOBAL_LIST_INIT(total_ui_len_by_block, populate_total_ui_len_by_block())
|
||||
|
||||
GLOBAL_LIST_INIT(standard_mutation_sources, list(MUTATION_SOURCE_ACTIVATED, MUTATION_SOURCE_MUTATOR, MUTATION_SOURCE_TIMED_INJECTOR))
|
||||
GLOBAL_LIST_INIT(standard_mutation_sources, list(MUTATION_SOURCE_ACTIVATED, MUTATION_SOURCE_MUTATOR))
|
||||
|
||||
/proc/populate_total_ui_len_by_block()
|
||||
. = list()
|
||||
@@ -44,10 +44,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
|
||||
var/real_name
|
||||
///All mutations are from now on here
|
||||
var/list/mutations
|
||||
///Temporary changes to the UE
|
||||
var/list/temporary_mutations
|
||||
///For temporary name/ui/ue/blood_type modifications
|
||||
var/list/previous
|
||||
var/mob/living/holder
|
||||
///List of which mutations this carbon has and its assigned block
|
||||
var/mutation_index[DNA_MUTATION_BLOCKS]
|
||||
@@ -77,8 +73,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
|
||||
QDEL_NULL(species)
|
||||
|
||||
LAZYNULL(mutations) //This only references mutations, just dereference.
|
||||
LAZYNULL(temporary_mutations) //^
|
||||
LAZYNULL(previous) //^
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -89,9 +83,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
|
||||
new_dna.unique_features = unique_features
|
||||
new_dna.features = features.Copy()
|
||||
new_dna.real_name = real_name
|
||||
new_dna.temporary_mutations = LAZYLISTDUPLICATE(temporary_mutations)
|
||||
new_dna.mutation_index = mutation_index
|
||||
new_dna.default_mutation_genes = default_mutation_genes
|
||||
if(transfer_flags & COPY_DNA_SE)
|
||||
new_dna.mutation_index = mutation_index
|
||||
new_dna.default_mutation_genes = default_mutation_genes
|
||||
//if the new DNA has a holder, transform them immediately, otherwise save it
|
||||
if(new_dna.holder)
|
||||
if (iscarbon(new_dna.holder))
|
||||
@@ -155,7 +149,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
|
||||
var/datum/mutation/actual_mutation = get_mutation(mutation_to_remove)
|
||||
|
||||
if(!actual_mutation || !(sources & actual_mutation.sources))
|
||||
return
|
||||
return FALSE
|
||||
|
||||
actual_mutation.sources -= sources
|
||||
|
||||
@@ -169,6 +163,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
|
||||
qdel(actual_mutation)
|
||||
|
||||
update_instability(FALSE)
|
||||
return TRUE
|
||||
|
||||
/datum/dna/proc/check_mutation(mutation_type)
|
||||
return get_mutation(mutation_type)
|
||||
|
||||
@@ -89,9 +89,8 @@
|
||||
var/list/valid_chrom_list = list()
|
||||
/// List of traits that are added or removed by the mutation with GENETIC_TRAIT source.
|
||||
var/list/mutation_traits
|
||||
|
||||
/datum/mutation/New()
|
||||
. = ..()
|
||||
/// if TRUE admins get alerted when someone force-injects someone else with this mutation
|
||||
var/warn_admins_on_inject = FALSE
|
||||
|
||||
/datum/mutation/Destroy()
|
||||
power_path = null
|
||||
|
||||
@@ -246,6 +246,7 @@
|
||||
instability = NEGATIVE_STABILITY_MAJOR // mmmonky
|
||||
remove_on_aheal = FALSE
|
||||
locked = TRUE //Species specific, keep out of actual gene pool
|
||||
warn_admins_on_inject = TRUE
|
||||
var/datum/species/original_species = /datum/species/human
|
||||
var/original_name
|
||||
|
||||
@@ -533,6 +534,7 @@
|
||||
difficulty = 12 //pretty good for traitors
|
||||
quality = NEGATIVE //holy shit no eyes or tongue or ears
|
||||
text_gain_indication = span_warning("Something feels off.")
|
||||
warn_admins_on_inject = TRUE
|
||||
|
||||
/datum/mutation/headless/on_acquiring()
|
||||
. = ..()
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
/datum/action/cooldown/spell/void/cursed/proc/on_life(mob/living/source, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isliving(source) || HAS_TRAIT(source, TRAIT_STASIS) || source.stat == DEAD || HAS_TRAIT(source, TRAIT_NO_TRANSFORM))
|
||||
if(HAS_TRAIT(source, TRAIT_STASIS) || source.stat == DEAD)
|
||||
return
|
||||
|
||||
if(!is_valid_target(source))
|
||||
|
||||
@@ -84,10 +84,7 @@
|
||||
/datum/quirk/item_quirk/asthma/proc/on_life(mob/living/source, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (quirk_holder.stat == DEAD)
|
||||
return
|
||||
|
||||
if (HAS_TRAIT(quirk_holder, TRAIT_STASIS) || HAS_TRAIT(quirk_holder, TRAIT_NO_TRANSFORM))
|
||||
if (quirk_holder.stat == DEAD || HAS_TRAIT(quirk_holder, TRAIT_STASIS))
|
||||
return
|
||||
|
||||
var/obj/item/organ/lungs/holder_lungs = quirk_holder.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
tick_interval = STATUS_EFFECT_NO_TICK
|
||||
duration = 1 MINUTES // set in on creation, this just needs to be any value to process
|
||||
alert_type = null
|
||||
/// Flags used to determine what all we're copying over
|
||||
VAR_PROTECTED/copy_dna_flags = COPY_DNA_SPECIES
|
||||
/// A reference to a COPY of the DNA that the mob will be transformed into.
|
||||
var/datum/dna/new_dna
|
||||
VAR_PRIVATE/datum/dna/new_dna
|
||||
/// A reference to a COPY of the DNA of the mob prior to transformation.
|
||||
var/datum/dna/old_dna
|
||||
VAR_PRIVATE/datum/dna/old_dna
|
||||
|
||||
/datum/status_effect/temporary_transformation/Destroy()
|
||||
. = ..() // parent must be called first, so we clear DNA refs AFTER transforming back... yeah i know
|
||||
@@ -16,10 +18,14 @@
|
||||
QDEL_NULL(old_dna)
|
||||
|
||||
/datum/status_effect/temporary_transformation/on_creation(mob/living/new_owner, new_duration = 1 MINUTES, datum/dna/dna_to_copy)
|
||||
if(!iscarbon(new_owner) || isnull(dna_to_copy))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
src.duration = new_duration
|
||||
src.new_dna = new()
|
||||
src.old_dna = new()
|
||||
dna_to_copy.copy_dna(new_dna)
|
||||
init_dna(new_owner, dna_to_copy)
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/temporary_transformation/on_apply()
|
||||
@@ -30,27 +36,39 @@
|
||||
if(!transforming.has_dna())
|
||||
return FALSE
|
||||
|
||||
// Save the old DNA
|
||||
transforming.dna.copy_dna(old_dna)
|
||||
// Makes them into the new DNA
|
||||
new_dna.copy_dna(transforming.dna, COPY_DNA_SPECIES)
|
||||
transforming.real_name = new_dna.real_name
|
||||
transforming.name = transforming.get_visible_name()
|
||||
transforming.updateappearance(mutcolor_update = TRUE)
|
||||
transforming.domutcheck()
|
||||
save_dna()
|
||||
apply_dna()
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/temporary_transformation/on_remove()
|
||||
var/mob/living/carbon/transforming = owner
|
||||
|
||||
if(!QDELING(owner)) // Don't really need to do appearance stuff if we're being deleted
|
||||
old_dna.copy_dna(transforming.dna, COPY_DNA_SPECIES)
|
||||
old_dna.copy_dna(transforming.dna, copy_dna_flags)
|
||||
transforming.updateappearance(mutcolor_update = TRUE)
|
||||
transforming.domutcheck()
|
||||
|
||||
transforming.real_name = old_dna.real_name // Name is fine though
|
||||
transforming.name = transforming.get_visible_name()
|
||||
|
||||
/// Called when initializing the DNA that the mob is transforming into
|
||||
/datum/status_effect/temporary_transformation/proc/init_dna(mob/living/carbon/new_owner, datum/dna/dna_to_copy)
|
||||
dna_to_copy.copy_dna(new_dna, copy_dna_flags)
|
||||
|
||||
/// Called when saving the mob's DNA before transformation
|
||||
/datum/status_effect/temporary_transformation/proc/save_dna()
|
||||
var/mob/living/carbon/transforming = owner
|
||||
transforming.dna.copy_dna(old_dna, copy_dna_flags)
|
||||
|
||||
/// Applies the DNA to the mob
|
||||
/datum/status_effect/temporary_transformation/proc/apply_dna()
|
||||
var/mob/living/carbon/transforming = owner
|
||||
new_dna.copy_dna(transforming.dna, copy_dna_flags)
|
||||
transforming.real_name = new_dna.real_name
|
||||
transforming.name = transforming.get_visible_name()
|
||||
transforming.updateappearance(mutcolor_update = TRUE)
|
||||
transforming.domutcheck()
|
||||
|
||||
/datum/status_effect/temporary_transformation/trans_sting
|
||||
/// Tracks the time left on the effect when the owner last died. Used to pause the effect.
|
||||
var/time_before_pause = -1
|
||||
@@ -89,3 +107,35 @@
|
||||
else if(time_before_pause != -1)
|
||||
duration = time_before_pause
|
||||
time_before_pause = -1
|
||||
|
||||
/datum/status_effect/temporary_transformation/dna_injector
|
||||
id = "temp_dna_injector_transformation"
|
||||
status_type = STATUS_EFFECT_MULTIPLE
|
||||
copy_dna_flags = NONE // no touching species or mutations
|
||||
|
||||
// when initting dna, any unset fields are copied from the mob's dna (so nothing changes effectively)
|
||||
/datum/status_effect/temporary_transformation/dna_injector/init_dna(mob/living/carbon/new_owner, datum/dna/dna_to_copy)
|
||||
. = ..()
|
||||
new_dna.real_name ||= new_owner.dna.real_name
|
||||
new_dna.unique_enzymes ||= new_owner.dna.unique_enzymes
|
||||
new_dna.unique_features ||= new_owner.dna.unique_features
|
||||
new_dna.unique_identity ||= new_owner.dna.unique_identity
|
||||
new_dna.blood_type ||= new_owner.dna.blood_type
|
||||
// just to put something there, it'll get updated if UF does anyways
|
||||
new_dna.features = new_owner.dna.features.Copy()
|
||||
|
||||
// ensure secondary transformation make a copy of the original dna (to prevent latter effects that expire earlier from returning to the wrong dna)
|
||||
/datum/status_effect/temporary_transformation/dna_injector/save_dna()
|
||||
for(var/datum/status_effect/temporary_transformation/dna_injector/other_effect in owner.status_effects)
|
||||
other_effect.old_dna.copy_dna(src.old_dna, copy_dna_flags)
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
// when the effect ends, see if there's any other active effects, and re-apply them if necessary
|
||||
/datum/status_effect/temporary_transformation/dna_injector/on_remove()
|
||||
. = ..()
|
||||
if(QDELING(owner))
|
||||
return
|
||||
for(var/datum/status_effect/temporary_transformation/dna_injector/other_effect in owner.status_effects)
|
||||
other_effect.apply_dna()
|
||||
|
||||
@@ -1303,93 +1303,19 @@
|
||||
// number later
|
||||
// params["type"] - Type of injector to create
|
||||
// Expected results:
|
||||
// "ue" - Unique Enzyme, changes name and blood type
|
||||
// "ue" - Unique Enzyme, changes name and blood type
|
||||
// "ui" - Unique Identity, changes looks
|
||||
// "uf" - Unique Features, changes mutant bodyparts and mutcolors
|
||||
// "mixed" - Combination of both ue and ui
|
||||
if("makeup_injector")
|
||||
if(!COOLDOWN_FINISHED(src, enzyme_copy_timer))
|
||||
return
|
||||
// Convert the index to a number and clamp within the array range, then
|
||||
// copy the data from the disk to that buffer
|
||||
var/buffer_index = text2num(params["index"])
|
||||
buffer_index = clamp(buffer_index, 1, NUMBER_OF_BUFFERS)
|
||||
var/list/buffer_slot = genetic_makeup_buffer[buffer_index]
|
||||
|
||||
// GUARD CHECK - This shouldn't be possible to execute this on a null
|
||||
// buffer. Unexpected resut
|
||||
if(!istype(buffer_slot))
|
||||
// Convert the index to a number and clamp within the array range, then copy the data from the disk to that buffer
|
||||
var/buffer_index = clamp(text2num(params["index"]), 1, NUMBER_OF_BUFFERS)
|
||||
if(!make_cosmetic_dna_injector(dna_injector_type_to_flag(params["type"]), genetic_makeup_buffer[buffer_index]))
|
||||
to_chat(usr, span_warning("Genetic data corrupted, unable to create injector."))
|
||||
return
|
||||
|
||||
var/type = params["type"]
|
||||
var/obj/item/dnainjector/timed/I
|
||||
|
||||
switch(type)
|
||||
if("ui")
|
||||
// GUARD CHECK - There's currently no way to save partial genetic data.
|
||||
// However, if this is the case, we can't make a complete injector and
|
||||
// this catches that edge case
|
||||
if(!buffer_slot["UI"])
|
||||
to_chat(usr,span_warning("Genetic data corrupted, unable to create injector."))
|
||||
return
|
||||
|
||||
I = new /obj/item/dnainjector/timed(loc)
|
||||
I.fields = list("UI"=buffer_slot["UI"])
|
||||
|
||||
// If there is a connected scanner, we can use its upgrades to reduce
|
||||
// the genetic damage generated by this injector
|
||||
if(scanner_operational())
|
||||
I.damage_coeff = connected_scanner.damage_coeff
|
||||
if("ue")
|
||||
// GUARD CHECK - There's currently no way to save partial genetic data.
|
||||
// However, if this is the case, we can't make a complete injector and
|
||||
// this catches that edge case
|
||||
if(!buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["blood_type"])
|
||||
to_chat(usr,span_warning("Genetic data corrupted, unable to create injector."))
|
||||
return
|
||||
|
||||
I = new /obj/item/dnainjector/timed(loc)
|
||||
I.fields = list("name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"])
|
||||
|
||||
// If there is a connected scanner, we can use its upgrades to reduce
|
||||
// the genetic damage generated by this injector
|
||||
if(scanner_operational())
|
||||
I.damage_coeff = connected_scanner.damage_coeff
|
||||
if("uf")
|
||||
// GUARD CHECK - There's currently no way to save partial genetic data.
|
||||
// However, if this is the case, we can't make a complete injector and
|
||||
// this catches that edge case
|
||||
if(!buffer_slot["name"] || !buffer_slot["UF"] || !buffer_slot["blood_type"])
|
||||
to_chat(usr,span_warning("Genetic data corrupted, unable to create injector."))
|
||||
return
|
||||
|
||||
I = new /obj/item/dnainjector/timed(loc)
|
||||
I.fields = list("name"=buffer_slot["name"], "UF"=buffer_slot["UF"])
|
||||
|
||||
// If there is a connected scanner, we can use its upgrades to reduce
|
||||
// the genetic damage generated by this injector
|
||||
if(scanner_operational())
|
||||
I.damage_coeff = connected_scanner.damage_coeff
|
||||
if("mixed")
|
||||
// GUARD CHECK - There's currently no way to save partial genetic data.
|
||||
// However, if this is the case, we can't make a complete injector and
|
||||
// this catches that edge case
|
||||
if(!buffer_slot["UI"] || !buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["UF"] || !buffer_slot["blood_type"])
|
||||
to_chat(usr,span_warning("Genetic data corrupted, unable to create injector."))
|
||||
return
|
||||
|
||||
I = new /obj/item/dnainjector/timed(loc)
|
||||
I.fields = list("UI"=buffer_slot["UI"],"name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "UF"=buffer_slot["UF"], "blood_type"=buffer_slot["blood_type"])
|
||||
|
||||
// If there is a connected scanner, we can use its upgrades to reduce
|
||||
// the genetic damage generated by this injector
|
||||
if(scanner_operational())
|
||||
I.damage_coeff = connected_scanner.damage_coeff
|
||||
|
||||
// If we successfully created an injector, don't forget to set the new
|
||||
// ready timer.
|
||||
if(I)
|
||||
injector_ready = world.time + MISC_INJECTOR_TIMEOUT
|
||||
injector_ready = world.time + MISC_INJECTOR_TIMEOUT
|
||||
if(connected_scanner)
|
||||
connected_scanner.use_energy(connected_scanner.active_power_usage)
|
||||
else
|
||||
@@ -1785,12 +1711,90 @@
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Checks if there is a connected DNA Scanner that is operational
|
||||
*/
|
||||
/obj/machinery/computer/dna_console/proc/scanner_operational()
|
||||
return connected_scanner?.is_operational
|
||||
|
||||
/**
|
||||
* Gets the damage coefficient of the connected DNA Scanner, or 1 if there isn't an operational one
|
||||
*/
|
||||
/obj/machinery/computer/dna_console/proc/get_injector_damage_coeff()
|
||||
if(scanner_operational())
|
||||
return connected_scanner.damage_coeff
|
||||
return 1
|
||||
|
||||
/// Copy UI to the dna injector
|
||||
#define DNA_INJECTOR_FLAG_UI (1<<0)
|
||||
/// Copy UE to the dna injector
|
||||
#define DNA_INJECTOR_FLAG_UE (1<<1)
|
||||
/// Copy UF to the dna injector
|
||||
#define DNA_INJECTOR_FLAG_UF (1<<2)
|
||||
/// Copy name to the dna injector
|
||||
#define DNA_INJECTOR_FLAG_NAME (1<<3)
|
||||
/// Copy blood type to the dna injector
|
||||
#define DNA_INJECTOR_FLAG_BLOOD (1<<4)
|
||||
|
||||
/**
|
||||
* Converts a string (from tgui) to a series of flags determine what we should put in a DNA Injector
|
||||
*/
|
||||
/obj/machinery/computer/dna_console/proc/dna_injector_type_to_flag(injector_type)
|
||||
switch(injector_type)
|
||||
if("ui")
|
||||
return DNA_INJECTOR_FLAG_UI
|
||||
if("ue")
|
||||
return DNA_INJECTOR_FLAG_UE | DNA_INJECTOR_FLAG_NAME | DNA_INJECTOR_FLAG_BLOOD
|
||||
if("uf")
|
||||
return DNA_INJECTOR_FLAG_UF | DNA_INJECTOR_FLAG_NAME
|
||||
if("mixed")
|
||||
return ALL
|
||||
return NONE
|
||||
|
||||
/**
|
||||
* Pass an injector flag and a genetic makeup buffer slot to create a DNA Injector
|
||||
*/
|
||||
/obj/machinery/computer/dna_console/proc/make_cosmetic_dna_injector(dna_flag, list/buffer_slot = list())
|
||||
if(!dna_flag || !length(buffer_slot))
|
||||
return FALSE
|
||||
|
||||
var/datum/dna/stored_dna = new()
|
||||
|
||||
if(dna_flag & DNA_INJECTOR_FLAG_NAME)
|
||||
if(!buffer_slot["name"])
|
||||
return FALSE
|
||||
stored_dna.real_name = buffer_slot["name"]
|
||||
|
||||
if(dna_flag & DNA_INJECTOR_FLAG_BLOOD)
|
||||
if(!buffer_slot["blood_type"])
|
||||
return FALSE
|
||||
stored_dna.blood_type = buffer_slot["blood_type"]
|
||||
|
||||
if(dna_flag & DNA_INJECTOR_FLAG_UI)
|
||||
if(!buffer_slot["UI"])
|
||||
return FALSE
|
||||
stored_dna.unique_identity = buffer_slot["UI"]
|
||||
|
||||
if(dna_flag & DNA_INJECTOR_FLAG_UE)
|
||||
if(!buffer_slot["UE"])
|
||||
return FALSE
|
||||
stored_dna.unique_enzymes = buffer_slot["UE"]
|
||||
|
||||
if(dna_flag & DNA_INJECTOR_FLAG_UF)
|
||||
if(!buffer_slot["UF"])
|
||||
return FALSE
|
||||
stored_dna.unique_features = buffer_slot["UF"]
|
||||
|
||||
new /obj/item/dnainjector/timed(loc, stored_dna, get_injector_damage_coeff())
|
||||
return TRUE
|
||||
|
||||
#undef DNA_INJECTOR_FLAG_UI
|
||||
#undef DNA_INJECTOR_FLAG_UE
|
||||
#undef DNA_INJECTOR_FLAG_UF
|
||||
#undef DNA_INJECTOR_FLAG_NAME
|
||||
#undef DNA_INJECTOR_FLAG_BLOOD
|
||||
|
||||
/**
|
||||
* Checks if there is a valid DNA Scanner occupant for genetic modification
|
||||
*
|
||||
|
||||
@@ -163,7 +163,7 @@ GLOBAL_VAR_INIT(experimental_cloner_fuckup_chance, 50)
|
||||
|
||||
if (prob(75))
|
||||
var/static/list/permitted_heights = list(HUMAN_HEIGHT_SHORTEST, HUMAN_HEIGHT_SHORT, HUMAN_HEIGHT_MEDIUM, HUMAN_HEIGHT_TALL, HUMAN_HEIGHT_TALLER, HUMAN_HEIGHT_TALLEST)
|
||||
new_clone.dna.remove_mutation(/datum/mutation/dwarfism, list(MUTATION_SOURCE_ACTIVATED, MUTATION_SOURCE_MUTATOR))
|
||||
new_clone.dna.remove_mutation(/datum/mutation/dwarfism, GLOB.standard_mutation_sources)
|
||||
new_clone.set_mob_height(pick(permitted_heights - loaded_record.height)) // To differentiate the clones
|
||||
|
||||
return new_clone
|
||||
|
||||
@@ -11,18 +11,34 @@
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
/// Modified to damage caused from injection, currently unused though
|
||||
var/damage_coeff = 1
|
||||
var/list/fields
|
||||
var/list/add_mutations = list()
|
||||
var/list/remove_mutations = list()
|
||||
/// Adds all mutations in this list to the injected mob, activating it rather than mutating it if possible.
|
||||
var/list/add_mutations
|
||||
/// If the injected mob has any mutations in this list activated or mutated, they will be removed.
|
||||
var/list/remove_mutations
|
||||
/// Tracks if it's been used
|
||||
VAR_FINAL/used = FALSE
|
||||
/// Duration of the mutations added/activated or DNA changes. Does not affect removed mutations.
|
||||
var/duration = INFINITY
|
||||
/// A DNA datum that has its fields copied to the target on injection.
|
||||
var/datum/dna/stored_dna
|
||||
|
||||
var/used = FALSE
|
||||
|
||||
/obj/item/dnainjector/Initialize(mapload)
|
||||
/obj/item/dnainjector/Initialize(mapload, datum/dna/stored_dna, damage_coeff = 1)
|
||||
. = ..()
|
||||
AddElement(/datum/element/update_icon_updates_onmob)
|
||||
if(used)
|
||||
update_appearance()
|
||||
src.stored_dna = stored_dna
|
||||
src.damage_coeff = damage_coeff
|
||||
|
||||
/obj/item/dnainjector/Destroy()
|
||||
if(stored_dna?.holder)
|
||||
stack_trace("DNA injector got owned DNA somehow")
|
||||
stored_dna = null
|
||||
else
|
||||
QDEL_NULL(stored_dna)
|
||||
return ..()
|
||||
|
||||
/obj/item/dnainjector/vv_edit_var(vname, vval)
|
||||
. = ..()
|
||||
@@ -43,27 +59,26 @@
|
||||
/obj/item/dnainjector/proc/inject(mob/living/carbon/target, mob/user)
|
||||
if(!target.can_mutate())
|
||||
return FALSE
|
||||
if(target.stat == DEAD) //prevents dead people from having their DNA changed
|
||||
to_chat(user, span_notice("You can't modify [target]'s DNA while [target.p_theyre()] dead."))
|
||||
return FALSE
|
||||
for(var/removed_mutation in remove_mutations)
|
||||
target.dna.remove_mutation(removed_mutation, list(MUTATION_SOURCE_ACTIVATED, MUTATION_SOURCE_MUTATOR))
|
||||
for(var/added_mutation in add_mutations)
|
||||
if(added_mutation == /datum/mutation/race)
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] injected [key_name_admin(target)] with \the [src] [span_danger("(MONKEY)")]")
|
||||
target.dna.remove_mutation(removed_mutation, GLOB.standard_mutation_sources)
|
||||
|
||||
for(var/datum/mutation/added_mutation as anything in add_mutations)
|
||||
if(added_mutation::warn_admins_on_inject && target != user && !ismonkey(target))
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] injected [key_name_admin(target)] with [src] containing [added_mutation::name].")
|
||||
if(target.dna.mutation_in_sequence(added_mutation))
|
||||
target.dna.activate_mutation(added_mutation)
|
||||
if(duration != INFINITY)
|
||||
addtimer(CALLBACK(target.dna, TYPE_PROC_REF(/datum/dna, remove_mutation), added_mutation, MUTATION_SOURCE_ACTIVATED), duration)
|
||||
else
|
||||
target.dna.add_mutation(added_mutation, MUTATION_SOURCE_MUTATOR)
|
||||
if(fields)
|
||||
if(fields["name"] && fields["UE"] && fields["blood_type"])
|
||||
target.real_name = fields["name"]
|
||||
target.dna.unique_enzymes = fields["UE"]
|
||||
target.name = target.real_name
|
||||
target.set_blood_type(fields["blood_type"])
|
||||
if(fields["UI"]) //UI+UE
|
||||
target.dna.unique_identity = merge_text(target.dna.unique_identity, fields["UI"])
|
||||
if(fields["UF"])
|
||||
target.dna.unique_features = merge_text(target.dna.unique_features, fields["UF"])
|
||||
if(fields["UI"] || fields["UF"])
|
||||
target.updateappearance(mutcolor_update = TRUE, mutations_overlay_update = TRUE)
|
||||
if(duration != INFINITY)
|
||||
addtimer(CALLBACK(target.dna, TYPE_PROC_REF(/datum/dna, remove_mutation), added_mutation, MUTATION_SOURCE_MUTATOR), duration)
|
||||
|
||||
if(stored_dna)
|
||||
target.apply_status_effect(/datum/status_effect/temporary_transformation/dna_injector, duration, stored_dna)
|
||||
return TRUE
|
||||
|
||||
/obj/item/dnainjector/attack(mob/target, mob/user)
|
||||
@@ -100,53 +115,7 @@
|
||||
update_appearance()
|
||||
|
||||
/obj/item/dnainjector/timed
|
||||
var/duration = 60 SECONDS
|
||||
|
||||
/obj/item/dnainjector/timed/inject(mob/living/carbon/target, mob/user)
|
||||
if(target.stat == DEAD) //prevents dead people from having their DNA changed
|
||||
to_chat(user, span_notice("You can't modify [target]'s DNA while [target.p_theyre()] dead."))
|
||||
return FALSE
|
||||
if(!target.can_mutate())
|
||||
return FALSE
|
||||
var/endtime = world.time + duration
|
||||
for(var/mutation in remove_mutations)
|
||||
target.dna.remove_mutation(mutation, list(MUTATION_SOURCE_ACTIVATED, MUTATION_SOURCE_MUTATOR))
|
||||
for(var/mutation in add_mutations)
|
||||
if(target.dna.get_mutation(mutation))
|
||||
continue //Skip permanent mutations we already have.
|
||||
if(mutation == /datum/mutation/race && !ismonkey(target))
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] injected [key_name_admin(target)] with \the [src] [span_danger("(MONKEY)")]")
|
||||
target.dna.add_mutation(mutation, MUTATION_SOURCE_TIMED_INJECTOR)
|
||||
addtimer(CALLBACK(target.dna, TYPE_PROC_REF(/datum/dna, remove_mutation), mutation, MUTATION_SOURCE_TIMED_INJECTOR), duration)
|
||||
if(fields)
|
||||
if(fields["name"] && fields["UE"] && fields["blood_type"])
|
||||
LAZYINITLIST(target.dna.previous)
|
||||
if(!target.dna.previous["name"])
|
||||
target.dna.previous["name"] = target.real_name
|
||||
if(!target.dna.previous["UE"])
|
||||
target.dna.previous["UE"] = target.dna.unique_enzymes
|
||||
if(!target.dna.previous["blood_type"])
|
||||
target.dna.previous["blood_type"] = target.get_bloodtype()
|
||||
target.real_name = fields["name"]
|
||||
target.dna.unique_enzymes = fields["UE"]
|
||||
target.name = target.real_name
|
||||
target.set_blood_type(fields["blood_type"])
|
||||
LAZYSET(target.dna.temporary_mutations, UE_CHANGED, endtime)
|
||||
if(fields["UI"]) //UI+UE
|
||||
LAZYINITLIST(target.dna.previous)
|
||||
if(!target.dna.previous["UI"])
|
||||
target.dna.previous["UI"] = target.dna.unique_identity
|
||||
target.dna.unique_identity = merge_text(target.dna.unique_identity, fields["UI"])
|
||||
LAZYSET(target.dna.temporary_mutations, UI_CHANGED, endtime)
|
||||
if(fields["UF"]) //UI+UE
|
||||
LAZYINITLIST(target.dna.previous)
|
||||
if(!target.dna.previous["UF"])
|
||||
target.dna.previous["UF"] = target.dna.unique_features
|
||||
target.dna.unique_features = merge_text(target.dna.unique_features, fields["UF"])
|
||||
LAZYSET(target.dna.temporary_mutations, UF_CHANGED, endtime)
|
||||
if(fields["UI"] || fields["UF"])
|
||||
target.updateappearance(mutcolor_update = TRUE, mutations_overlay_update = TRUE)
|
||||
return TRUE
|
||||
duration = 60 SECONDS
|
||||
|
||||
/obj/item/dnainjector/timed/hulk
|
||||
name = "\improper DNA injector (Hulk)"
|
||||
|
||||
@@ -263,12 +263,10 @@
|
||||
/mob/living/basic/soulscythe/Initialize(mapload)
|
||||
. = ..()
|
||||
add_traits(list(TRAIT_ASHSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE, TRAIT_LAVA_IMMUNE), INNATE_TRAIT)
|
||||
RegisterSignal(src, COMSIG_LIVING_LIFE, PROC_REF(on_life))
|
||||
|
||||
/mob/living/basic/soulscythe/proc/on_life(datum/source, seconds_per_tick) // done like this because there's no need to go through all of life since the item does the work anyways
|
||||
/mob/living/basic/soulscythe/Life(seconds_per_tick)
|
||||
if(stat == CONSCIOUS)
|
||||
adjust_blood_volume(round(1 * seconds_per_tick), maximum = MAX_BLOOD_LEVEL)
|
||||
return COMPONENT_LIVING_CANCEL_LIFE_PROCESSING
|
||||
|
||||
/// Special projectile for the soulscythe.
|
||||
/obj/projectile/soulscythe
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
|
||||
/// Updates effects that rely on blood volume or status, like blood HUDs.
|
||||
/mob/living/proc/update_blood_effects()
|
||||
living_flags &= ~BLOOD_UPDATE_QUEUED
|
||||
blood_hud_set_status()
|
||||
|
||||
/// Updates effects that rely on whether the mob can have blood.
|
||||
|
||||
@@ -542,11 +542,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
|
||||
return new_features
|
||||
|
||||
/datum/species/proc/spec_life(mob/living/carbon/human/H, seconds_per_tick)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(HAS_TRAIT(H, TRAIT_NOBREATH) && (H.health < H.crit_threshold) && !HAS_TRAIT(H, TRAIT_NOCRITDAMAGE))
|
||||
H.adjust_brute_loss(0.5 * seconds_per_tick)
|
||||
|
||||
/datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE)
|
||||
if(no_equip_flags & slot)
|
||||
if(!I.species_exception || !is_type_in_list(src, I.species_exception))
|
||||
|
||||
@@ -696,7 +696,7 @@
|
||||
if(heal_flags & HEAL_NEGATIVE_MUTATIONS)
|
||||
for(var/datum/mutation/existing_mutation in dna.mutations)
|
||||
if(existing_mutation.quality != POSITIVE && existing_mutation.remove_on_aheal)
|
||||
dna.remove_mutation(existing_mutation, list(MUTATION_SOURCE_ACTIVATED, MUTATION_SOURCE_MUTATOR, MUTATION_SOURCE_TIMED_INJECTOR))
|
||||
dna.remove_mutation(existing_mutation, GLOB.standard_mutation_sources)
|
||||
|
||||
if(heal_flags & HEAL_TEMP)
|
||||
set_coretemperature(get_body_temp_normal(apply_change = FALSE))
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
return
|
||||
|
||||
. = ..()
|
||||
|
||||
if(QDELETED(src))
|
||||
return FALSE
|
||||
|
||||
@@ -45,8 +44,9 @@
|
||||
handle_heart(seconds_per_tick)
|
||||
// Handles liver failure effects, if we lack a liver
|
||||
handle_liver(seconds_per_tick)
|
||||
// For special species interactions
|
||||
dna.species.spec_life(src, seconds_per_tick)
|
||||
// Crit damage but specifically for people who don't get suffocate while in crit so they can actually die eventually
|
||||
if(HAS_TRAIT(src, TRAIT_NOBREATH) && (health < crit_threshold) && !HAS_TRAIT(src, TRAIT_NOCRITDAMAGE))
|
||||
adjust_brute_loss(0.5 * seconds_per_tick)
|
||||
return stat != DEAD
|
||||
|
||||
/mob/living/carbon/human/calculate_affecting_pressure(pressure)
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
RegisterSignal(human_who_gained_species, COMSIG_CARBON_DEFIB_HEART_CHECK, PROC_REF(defib_check))
|
||||
RegisterSignal(human_who_gained_species, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(rebuild_check))
|
||||
RegisterSignal(human_who_gained_species, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
|
||||
RegisterSignal(human_who_gained_species, COMSIG_LIVING_LIFE, PROC_REF(on_life))
|
||||
// nutrition = health, so give people a head start
|
||||
human_who_gained_species.set_nutrition(NUTRITION_LEVEL_WELL_FED)
|
||||
|
||||
@@ -81,14 +82,16 @@
|
||||
COMSIG_CARBON_DEFIB_HEART_CHECK,
|
||||
COMSIG_ATOM_ITEM_INTERACTION,
|
||||
COMSIG_ATOM_EXAMINE,
|
||||
COMSIG_LIVING_LIFE,
|
||||
))
|
||||
|
||||
human_who_lost_species.physiology.stamina_mod /= 0.6
|
||||
human_who_lost_species.physiology.stun_mod /= 0.6
|
||||
human_who_lost_species.physiology.knockdown_mod /= 1.2
|
||||
|
||||
/datum/species/golem/spec_life(mob/living/carbon/human/source, seconds_per_tick)
|
||||
. = ..()
|
||||
/datum/species/golem/proc/on_life(mob/living/carbon/human/source, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(source.nutrition <= 20)
|
||||
// this is "hard crit" for golems
|
||||
source.Unconscious(1.5 SECONDS * seconds_per_tick)
|
||||
|
||||
@@ -215,7 +215,10 @@
|
||||
// so if someone mindswapped into them, they'd still be shared.
|
||||
bodies = null
|
||||
C.set_blood_volume(C.get_blood_volume(), maximum = BLOOD_VOLUME_NORMAL)
|
||||
UnregisterSignal(C, COMSIG_LIVING_DEATH)
|
||||
UnregisterSignal(C, list(
|
||||
COMSIG_LIVING_DEATH,
|
||||
COMSIG_LIVING_LIFE,
|
||||
))
|
||||
..()
|
||||
|
||||
/datum/species/jelly/slime/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load, regenerate_icons)
|
||||
@@ -232,6 +235,7 @@
|
||||
bodies |= C
|
||||
|
||||
RegisterSignal(C, COMSIG_LIVING_DEATH, PROC_REF(on_death_move_body))
|
||||
RegisterSignal(C, COMSIG_LIVING_LIFE, PROC_REF(on_life))
|
||||
|
||||
/datum/species/jelly/slime/proc/on_death_move_body(mob/living/carbon/human/source, gibbed)
|
||||
SIGNAL_HANDLER
|
||||
@@ -255,16 +259,16 @@
|
||||
/datum/species/jelly/slime/copy_properties_from(datum/species/jelly/slime/old_species)
|
||||
bodies = old_species.bodies
|
||||
|
||||
/datum/species/jelly/slime/spec_life(mob/living/carbon/human/H, seconds_per_tick)
|
||||
. = ..()
|
||||
if(H.get_blood_volume() >= BLOOD_VOLUME_SLIME_SPLIT)
|
||||
/datum/species/jelly/slime/proc/on_life(mob/living/carbon/human/source, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
if(source.get_blood_volume() >= BLOOD_VOLUME_SLIME_SPLIT)
|
||||
if(SPT_PROB(2.5, seconds_per_tick))
|
||||
to_chat(H, span_notice("You feel very bloated!"))
|
||||
to_chat(source, span_notice("You feel very bloated!"))
|
||||
|
||||
else if(H.nutrition >= NUTRITION_LEVEL_WELL_FED)
|
||||
H.adjust_blood_volume(1.5 * seconds_per_tick)
|
||||
if(H.get_blood_volume() <= BLOOD_VOLUME_LOSE_NUTRITION)
|
||||
H.adjust_nutrition(-1.25 * seconds_per_tick)
|
||||
else if(source.nutrition >= NUTRITION_LEVEL_WELL_FED)
|
||||
source.adjust_blood_volume(1.5 * seconds_per_tick)
|
||||
if(source.get_blood_volume() <= BLOOD_VOLUME_LOSE_NUTRITION)
|
||||
source.adjust_nutrition(-1.25 * seconds_per_tick)
|
||||
|
||||
/datum/action/innate/split_body
|
||||
name = "Split Body"
|
||||
|
||||
@@ -33,16 +33,21 @@
|
||||
new_vampire.skin_tone = "albino"
|
||||
RegisterSignal(new_vampire, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
|
||||
RegisterSignal(new_vampire, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created))
|
||||
RegisterSignal(new_vampire, COMSIG_LIVING_LIFE, PROC_REF(on_life))
|
||||
if(new_vampire.hud_used)
|
||||
on_hud_created(new_vampire)
|
||||
|
||||
/datum/species/human/vampire/on_species_loss(mob/living/carbon/human/old_vampire, datum/species/new_species, pref_load)
|
||||
. = ..()
|
||||
UnregisterSignal(old_vampire, COMSIG_ATOM_ATTACKBY)
|
||||
UnregisterSignal(old_vampire, list(
|
||||
COMSIG_ATOM_ATTACKBY,
|
||||
COMSIG_MOB_HUD_CREATED,
|
||||
COMSIG_LIVING_LIFE,
|
||||
))
|
||||
old_vampire.hud_used?.remove_screen_object(HUD_MOB_BLOOD_LEVEL)
|
||||
|
||||
/datum/species/human/vampire/spec_life(mob/living/carbon/human/vampire, seconds_per_tick)
|
||||
. = ..()
|
||||
/datum/species/human/vampire/proc/on_life(mob/living/carbon/human/vampire, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
if(istype(vampire.loc, /obj/structure/closet/crate/coffin))
|
||||
var/need_mob_update = FALSE
|
||||
need_mob_update += vampire.heal_overall_damage(brute = 2 * seconds_per_tick, burn = 2 * seconds_per_tick, updating_health = FALSE, required_bodytype = BODYTYPE_ORGANIC)
|
||||
|
||||
@@ -47,15 +47,6 @@
|
||||
BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/zombie
|
||||
)
|
||||
|
||||
/// Spooky growls we sometimes play while alive
|
||||
var/static/list/spooks = list(
|
||||
'sound/effects/hallucinations/growl1.ogg',
|
||||
'sound/effects/hallucinations/growl2.ogg',
|
||||
'sound/effects/hallucinations/growl3.ogg',
|
||||
'sound/effects/hallucinations/veryfar_noise.ogg',
|
||||
'sound/effects/hallucinations/wail.ogg',
|
||||
)
|
||||
|
||||
/// Zombies do not stabilize body temperature they are the walking dead and are cold blooded
|
||||
/datum/species/zombie/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick)
|
||||
return
|
||||
@@ -178,11 +169,6 @@
|
||||
/datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount)
|
||||
return min(2 SECONDS, amount)
|
||||
|
||||
/datum/species/zombie/infectious/spec_life(mob/living/carbon/carbon_mob, seconds_per_tick)
|
||||
. = ..()
|
||||
if(!HAS_TRAIT(carbon_mob, TRAIT_CRITICAL_CONDITION) && SPT_PROB(2, seconds_per_tick))
|
||||
playsound(carbon_mob, pick(spooks), 50, TRUE, 10)
|
||||
|
||||
// Weaker subtype - less healing, weaker attacks, etc
|
||||
/datum/species/zombie/infectious/mindless
|
||||
name = "Mindless Infectious Zombie"
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_STASIS))
|
||||
. = ..()
|
||||
if(QDELETED(src))
|
||||
return
|
||||
|
||||
reagents?.handle_stasis_chems(src, seconds_per_tick)
|
||||
else
|
||||
//Reagent processing needs to come before breathing, to prevent edge cases.
|
||||
@@ -31,9 +34,6 @@
|
||||
GLOB.addictions[key].process_addiction(src, seconds_per_tick)
|
||||
handle_brain_damage(seconds_per_tick)
|
||||
|
||||
if(stat != DEAD)
|
||||
handle_bodyparts(seconds_per_tick)
|
||||
|
||||
if(stat != DEAD)
|
||||
return TRUE
|
||||
|
||||
@@ -501,10 +501,6 @@
|
||||
|
||||
return COMPONENT_NO_EXPOSE_REAGENTS
|
||||
|
||||
/mob/living/carbon/proc/handle_bodyparts(seconds_per_tick)
|
||||
for(var/obj/item/bodypart/limb as anything in get_bodyparts(include_stumps = TRUE))
|
||||
. |= limb.on_life(seconds_per_tick)
|
||||
|
||||
/mob/living/carbon/proc/handle_organs(seconds_per_tick)
|
||||
if(stat == DEAD)
|
||||
if(reagents && (reagents.has_reagent(/datum/reagent/toxin/formaldehyde, 1) || reagents.has_reagent(/datum/reagent/cryostylane))) // No organ decay if the body contains formaldehyde.
|
||||
@@ -526,49 +522,6 @@
|
||||
if(organ?.owner) // This exist mostly because reagent metabolization can cause organ reshuffling
|
||||
organ.on_life(seconds_per_tick)
|
||||
|
||||
/mob/living/carbon/handle_diseases(seconds_per_tick)
|
||||
for(var/datum/disease/disease as anything in diseases)
|
||||
if(QDELETED(disease)) //Got cured/deleted while the loop was still going.
|
||||
continue
|
||||
if(stat != DEAD || disease.process_dead)
|
||||
disease.stage_act(seconds_per_tick)
|
||||
|
||||
/mob/living/carbon/handle_mutations(time_since_irradiated, seconds_per_tick)
|
||||
if(!LAZYLEN(dna?.temporary_mutations))
|
||||
return
|
||||
|
||||
for(var/mut, mut_data in dna.temporary_mutations)
|
||||
if(mut_data < world.time)
|
||||
if(!LAZYLEN(dna.previous))
|
||||
continue
|
||||
if(mut == UI_CHANGED)
|
||||
if(dna.previous["UI"])
|
||||
dna.unique_identity = merge_text(dna.unique_identity,dna.previous["UI"])
|
||||
updateappearance(mutations_overlay_update=1)
|
||||
dna.previous.Remove("UI")
|
||||
LAZYREMOVE(dna.temporary_mutations, mut)
|
||||
continue
|
||||
if(mut == UF_CHANGED)
|
||||
if(dna.previous["UF"])
|
||||
dna.unique_features = merge_text(dna.unique_features,dna.previous["UF"])
|
||||
updateappearance(mutcolor_update=1, mutations_overlay_update=1)
|
||||
dna.previous.Remove("UF")
|
||||
LAZYREMOVE(dna.temporary_mutations, mut)
|
||||
continue
|
||||
if(mut == UE_CHANGED)
|
||||
if(dna.previous["name"])
|
||||
real_name = dna.previous["name"]
|
||||
name = real_name
|
||||
dna.previous.Remove("name")
|
||||
if(dna.previous["UE"])
|
||||
dna.unique_enzymes = dna.previous["UE"]
|
||||
dna.previous.Remove("UE")
|
||||
if(dna.previous["blood_type"])
|
||||
set_blood_type(dna.previous["blood_type"])
|
||||
dna.previous.Remove("blood_type")
|
||||
LAZYREMOVE(dna.temporary_mutations, mut)
|
||||
continue
|
||||
|
||||
/**
|
||||
* Returns a multiplier representing how effectively this mob can regenerate blood
|
||||
*
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
set waitfor = FALSE
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
var/signal_result = SEND_SIGNAL(src, COMSIG_LIVING_LIFE, seconds_per_tick)
|
||||
var/signal_result = SEND_SIGNAL(src, COMSIG_LIVING_PRE_LIFE, seconds_per_tick)
|
||||
|
||||
if(signal_result & COMPONENT_LIVING_CANCEL_LIFE_PROCESSING) // mmm less work
|
||||
return
|
||||
@@ -41,18 +41,15 @@
|
||||
if(isnull(loc) || HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
||||
return
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_LIFE, seconds_per_tick)
|
||||
if(QDELETED(src)) // signal handlers such as diseases could delete the mob
|
||||
return
|
||||
|
||||
if(!HAS_TRAIT(src, TRAIT_STASIS))
|
||||
if(stat != DEAD)
|
||||
//Mutations and radiation
|
||||
handle_mutations(seconds_per_tick)
|
||||
//Breathing, if applicable
|
||||
handle_breathing(seconds_per_tick)
|
||||
|
||||
handle_diseases(seconds_per_tick) // DEAD check is in the proc itself; we want it to spread even if the mob is dead, but to handle its disease-y properties only if you're not.
|
||||
|
||||
if (QDELETED(src)) // Diseases can qdel the mob via transformations
|
||||
return
|
||||
|
||||
// Handle temperature/pressure differences between body and environment
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
if(environment)
|
||||
@@ -64,21 +61,15 @@
|
||||
update_nutrition()
|
||||
living_flags &= ~QUEUE_NUTRITION_UPDATE
|
||||
|
||||
if (living_flags & BLOOD_UPDATE_QUEUED)
|
||||
if(living_flags & BLOOD_UPDATE_QUEUED)
|
||||
update_blood_effects()
|
||||
living_flags &= ~BLOOD_UPDATE_QUEUED
|
||||
|
||||
if(stat != DEAD)
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/handle_breathing(seconds_per_tick)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_HANDLE_BREATHING, seconds_per_tick)
|
||||
return
|
||||
|
||||
/mob/living/proc/handle_mutations(seconds_per_tick)
|
||||
return
|
||||
|
||||
/mob/living/proc/handle_diseases(seconds_per_tick)
|
||||
return
|
||||
|
||||
// Base mob environment handler for body temperature
|
||||
/mob/living/proc/handle_environment(datum/gas_mixture/environment, seconds_per_tick)
|
||||
|
||||
@@ -1309,7 +1309,7 @@
|
||||
if (ismonkey(human_mob))
|
||||
if (!HAS_TRAIT(human_mob, TRAIT_BORN_MONKEY))
|
||||
//This is the only time mutadone should remove monkeyism
|
||||
human_mob.dna.remove_mutation(/datum/mutation/race, list(MUTATION_SOURCE_ACTIVATED, MUTATION_SOURCE_MUTATOR))
|
||||
human_mob.dna.remove_mutation(/datum/mutation/race, GLOB.standard_mutation_sources)
|
||||
else if (HAS_TRAIT(human_mob, TRAIT_BORN_MONKEY))
|
||||
human_mob.monkeyize()
|
||||
|
||||
|
||||
@@ -661,10 +661,6 @@
|
||||
|
||||
update_icon_dropped()
|
||||
|
||||
//Return TRUE to get whatever mob this is in to update health.
|
||||
/obj/item/bodypart/proc/on_life(seconds_per_tick)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
|
||||
/**
|
||||
* #receive_damage
|
||||
*
|
||||
|
||||
@@ -420,6 +420,14 @@
|
||||
disliked_foodtypes = NONE
|
||||
// List of english words that translate to zombie phrases
|
||||
var/static/list/english_to_zombie = list()
|
||||
/// Spooky growls we sometimes play while alive
|
||||
var/static/list/spooks = list(
|
||||
'sound/effects/hallucinations/growl1.ogg',
|
||||
'sound/effects/hallucinations/growl2.ogg',
|
||||
'sound/effects/hallucinations/growl3.ogg',
|
||||
'sound/effects/hallucinations/veryfar_noise.ogg',
|
||||
'sound/effects/hallucinations/wail.ogg',
|
||||
)
|
||||
|
||||
/obj/item/organ/tongue/zombie/proc/add_word_to_translations(english_word, zombie_word)
|
||||
english_to_zombie[english_word] = zombie_word
|
||||
@@ -475,6 +483,11 @@
|
||||
message = capitalize(message)
|
||||
speech_args[SPEECH_MESSAGE] = message
|
||||
|
||||
/obj/item/organ/tongue/zombie/on_life(seconds_per_tick)
|
||||
. = ..()
|
||||
if(owner.stat == CONSCIOUS && SPT_PROB(2, seconds_per_tick))
|
||||
playsound(owner, pick(spooks), 50, TRUE, 10)
|
||||
|
||||
/obj/item/organ/tongue/alien
|
||||
name = "alien tongue"
|
||||
desc = "According to leading xenobiologists the evolutionary benefit of having a second mouth in your mouth is \"that it looks badass\"."
|
||||
|
||||
Reference in New Issue
Block a user