Mutation code cleanup, mutations now have sources to avoid concurrency problems. (#91346)

This PR aims to clean or bring up to date portions of code about dna,
the dna console and mutations. This includes taking care of or removing
some of the awful choices like the pratically useless
`datum/mutation/human` pathing, or the class variable, in favor of using
sources to avoid potential issues with extraneous sources of a mutation.

The files changed are over a hundred just because I removed the
`datum/mutation/human` path, but the actual bulk of the code is mainly
shared between the datum/dna.dm, _mutations.dm and dna_console.dm.

Mutation shitcode is hurting my future plans for infusions a little.
Also it's a much needed refactor. Drafted 'till I'm sure it works
without issues.

🆑
refactor: Refactored mutation code backend. Report any issue.
/🆑
This commit is contained in:
Ghom
2025-06-15 15:50:31 -04:00
committed by Roxy
parent c0dd4cadda
commit 75e7ef6def
111 changed files with 1020 additions and 1012 deletions
+20 -20
View File
@@ -6,23 +6,23 @@
/// Remember last heart we ate and reset bites_taken counter if we start eat new one
var/datum/weakref/last_heart_we_ate
/// List of all mutations allowed to get.
var/static/list/datum/mutation/human/mutations_list = list(
/datum/mutation/human/adaptation/cold,
/datum/mutation/human/adaptation/heat,
/datum/mutation/human/adaptation/pressure,
/datum/mutation/human/adaptation/thermal,
/datum/mutation/human/chameleon,
/datum/mutation/human/cryokinesis,
/datum/mutation/human/pyrokinesis,
/datum/mutation/human/dwarfism,
/datum/mutation/human/cindikinesis,
/datum/mutation/human/insulated,
/datum/mutation/human/telekinesis,
/datum/mutation/human/telepathy,
/datum/mutation/human/thermal,
/datum/mutation/human/tongue_spike,
/datum/mutation/human/webbing,
/datum/mutation/human/xray,
var/static/list/datum/mutation/mutations_list = list(
/datum/mutation/adaptation/cold,
/datum/mutation/adaptation/heat,
/datum/mutation/adaptation/pressure,
/datum/mutation/adaptation/thermal,
/datum/mutation/chameleon,
/datum/mutation/cryokinesis,
/datum/mutation/pyrokinesis,
/datum/mutation/dwarfism,
/datum/mutation/cindikinesis,
/datum/mutation/insulated,
/datum/mutation/telekinesis,
/datum/mutation/telepathy,
/datum/mutation/thermal,
/datum/mutation/tongue_spike,
/datum/mutation/webbing,
/datum/mutation/xray,
)
/datum/component/heart_eater/Initialize(...)
@@ -94,8 +94,8 @@
///Not Perfect heart give random mutation.
/datum/component/heart_eater/proc/not_perfect_heart(mob/living/carbon/human/eater)
var/datum/mutation/human/new_mutation
var/list/datum/mutation/human/shuffle_mutation_list = shuffle(mutations_list)
var/datum/mutation/new_mutation
var/list/datum/mutation/shuffle_mutation_list = shuffle(mutations_list)
for(var/mutation_in_list in shuffle_mutation_list)
if(is_type_in_list(mutation_in_list, eater.dna.mutations))
continue
@@ -104,7 +104,7 @@
if(isnull(new_mutation))
healing_heart(eater)
return
eater.dna.add_mutation(new_mutation)
eater.dna.add_mutation(new_mutation, MUTATION_SOURCE_HEART_EATER)
healing_heart(eater)
to_chat(eater, span_warning("This heart is not right for you. You now have [new_mutation.name] mutation."))
+2 -2
View File
@@ -18,7 +18,7 @@
var/datum/callback/should_modify_speech = null
/datum/component/speechmod/Initialize(replacements = list(), end_string = "", end_string_chance = 100, slots, uppercase = FALSE, should_modify_speech)
if (!ismob(parent) && !isitem(parent) && !istype(parent, /datum/mutation/human))
if (!ismob(parent) && !isitem(parent) && !istype(parent, /datum/mutation))
return COMPONENT_INCOMPATIBLE
src.replacements = replacements
@@ -28,7 +28,7 @@
src.uppercase = uppercase
src.should_modify_speech = should_modify_speech
if (istype(parent, /datum/mutation/human))
if (istype(parent, /datum/mutation))
RegisterSignal(parent, COMSIG_MUTATION_GAINED, PROC_REF(on_mutation_gained))
RegisterSignal(parent, COMSIG_MUTATION_LOST, PROC_REF(on_mutation_lost))
return
@@ -44,17 +44,20 @@
if(A.totalResistance() >= 14) //one does not simply escape Nurgle's grasp
no_reset = TRUE
/datum/symptom/genetic_mutation/Activate(datum/disease/advance/A)
/datum/symptom/genetic_mutation/Activate(datum/disease/advance/disease)
. = ..()
if(!.)
return
var/mob/living/carbon/C = A.affected_mob
if(!C.has_dna())
var/mob/living/carbon/carbon = disease.affected_mob
if(!carbon.has_dna())
return
switch(A.stage)
switch(disease.stage)
if(4, 5)
to_chat(C, span_warning("[pick("Your skin feels itchy.", "You feel light headed.")]"))
C.easy_random_mutate((NEGATIVE | MINOR_NEGATIVE | POSITIVE) - excludemuts, TRUE, TRUE, TRUE, mutadone_proof)
to_chat(carbon, span_warning("[pick("Your skin feels itchy.", "You feel light headed.")]"))
var/datum/mutation/mutation = carbon.get_random_mutation_path((NEGATIVE|MINOR_NEGATIVE|POSITIVE) & ~excludemuts)
if(!mutation)
return
carbon.dna.add_mutation((mutation.quality & mutadone_proof) ? MUTATION_SOURCE_GENE_SYMPTOM : MUTATION_SOURCE_ACTIVATED)
/datum/symptom/genetic_mutation/End(datum/disease/advance/A)
. = ..()
@@ -63,4 +66,4 @@
if(!no_reset)
var/mob/living/carbon/M = A.affected_mob
if(M.has_dna())
M.dna.remove_all_mutations(list(MUT_NORMAL, MUT_EXTRA), FALSE)
M.dna.remove_all_mutations(list(MUTATION_SOURCE_GENE_SYMPTOM, MUTATION_SOURCE_ACTIVATED))
+2 -2
View File
@@ -60,7 +60,7 @@
to_chat(affected_mob, span_danger("You don't feel like yourself.."))
var/datum/dna/transform_dna = strain_data["dna"]
transform_dna.transfer_identity(affected_mob, transfer_SE = 1)
transform_dna.copy_dna(affected_mob.dna, COPY_DNA_SE|COPY_DNA_SPECIES)
affected_mob.real_name = affected_mob.dna.real_name
affected_mob.updateappearance(mutcolor_update=1)
affected_mob.domutcheck()
@@ -71,7 +71,7 @@
/datum/disease/dnaspread/Destroy()
if (original_dna && transformed && affected_mob)
original_dna.transfer_identity(affected_mob, transfer_SE = 1)
original_dna.copy_dna(affected_mob.dna, COPY_DNA_SE|COPY_DNA_SPECIES)
affected_mob.real_name = affected_mob.dna.real_name
affected_mob.updateappearance(mutcolor_update=1)
affected_mob.domutcheck()
+138 -134
View File
@@ -49,6 +49,8 @@ GLOBAL_LIST_INIT(features_block_lengths, list(
*/
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))
/proc/populate_total_ui_len_by_block()
. = list()
var/total_block_len = 1
@@ -110,7 +112,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/datum/dna/Destroy()
if (iscarbon(holder))
var/mob/living/carbon/as_carbon = holder
remove_all_mutations() // mutations hold a reference to the dna
for(var/datum/mutation/mutation as anything in mutations)
remove_mutation(mutation, mutation.sources) // mutations hold a reference to the dna, we need to delete them.
if(as_carbon.dna == src)
as_carbon.dna = null
holder = null
@@ -123,35 +126,16 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
return ..()
/datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = FALSE, transfer_species = TRUE)
if(!istype(destination))
return
destination.dna.unique_enzymes = unique_enzymes
destination.dna.unique_identity = unique_identity
destination.set_blood_type(blood_type)
destination.dna.unique_features = unique_features
destination.dna.features = features.Copy()
destination.dna.real_name = real_name
destination.dna.temporary_mutations = temporary_mutations.Copy()
//SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION
destination.dna.mutant_bodyparts = mutant_bodyparts.Copy()
destination.dna.body_markings = body_markings.Copy()
destination.dna.update_body_size()
//SKYRAT EDIT ADDITION END
if(transfer_SE)
destination.dna.mutation_index = mutation_index
destination.dna.default_mutation_genes = default_mutation_genes
if(transfer_species)
//destination.set_species(species.type, icon_update=0) - ORIGINAL
destination.set_species(species.type, TRUE, FALSE, features.Copy(), mutant_bodyparts.Copy(), body_markings.Copy()) //SKYRAT EDIT CHANGE - CUSTOMIZATION
/datum/dna/proc/copy_dna(datum/dna/new_dna)
///Copies the variables of a dna datum onto another.
/datum/dna/proc/copy_dna(datum/dna/new_dna, transfer_flags = COPY_DNA_SE|COPY_DNA_SPECIES)
new_dna.unique_enzymes = unique_enzymes
new_dna.mutation_index = mutation_index
new_dna.default_mutation_genes = default_mutation_genes
new_dna.unique_identity = unique_identity
new_dna.unique_features = unique_features
new_dna.features = features.Copy()
new_dna.real_name = real_name
new_dna.temporary_mutations = temporary_mutations.Copy()
new_dna.mutation_index = mutation_index
new_dna.default_mutation_genes = default_mutation_genes
//SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION
new_dna.mutant_bodyparts = mutant_bodyparts.Copy()
new_dna.body_markings = body_markings.Copy()
@@ -162,54 +146,91 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if (iscarbon(new_dna.holder))
var/mob/living/carbon/as_carbon = new_dna.holder
as_carbon.set_blood_type(blood_type)
new_dna.holder.set_species(species.type, icon_update = 0)
if(transfer_flags & COPY_DNA_SPECIES)
new_dna.holder.set_species(species.type, icon_update = FALSE)
else
new_dna.blood_type = blood_type
new_dna.species = new species.type
new_dna.real_name = real_name
// Mutations aren't gc managed, but they still aren't templates
// Let's do a proper copy
for(var/datum/mutation/human/mutation in mutations)
new_dna.add_mutation(mutation, mutation.class, mutation.timeout)
if(transfer_flags & COPY_DNA_SPECIES)
new_dna.species = new species.type
if(transfer_flags & COPY_DNA_MUTATIONS && holder?.can_mutate())
// Mutations aren't gc managed, but they still aren't templates
// Let's do a proper copy
for(var/datum/mutation/mutation in mutations)
var/list/valid_sources = mutation.sources & GLOB.standard_mutation_sources
if(!length(valid_sources))
continue
new_dna.add_mutation(mutation, valid_sources)
//See mutation.dm for what 'class' does. 'time' is time till it removes itself in decimals. 0 for no timer
/datum/dna/proc/add_mutation(mutation, class = MUT_OTHER, time)
var/mutation_type = mutation
if(istype(mutation, /datum/mutation/human))
var/datum/mutation/human/HM = mutation
mutation_type = HM.type
if(get_mutation(mutation_type))
return
SEND_SIGNAL(holder, COMSIG_CARBON_GAIN_MUTATION, mutation_type, class)
return force_give(new mutation_type (class, time, copymut = mutation))
/datum/dna/proc/remove_mutation(datum/mutation/human/mutation_type, mutadone)
var/datum/mutation/human/actual_mutation = get_mutation(mutation_type)
///Adds a mutation to the dna if possible. See defines/dna.dm for all sources.
/datum/dna/proc/add_mutation(mutation_to_add, list/sources)
if(!islist(sources))
if(!sources)
CRASH("add_mutation() called without set source(s)")
sources = list(sources)
var/datum/mutation/actual_mutation = get_mutation(mutation_to_add)
var/list/sources_to_add = sources.Copy() //make sure not to modify the original if it's stored in a variable outside this proc
if(!actual_mutation)
return FALSE
if(istype(mutation_to_add, /datum/mutation))
var/datum/mutation/mutation_instance
actual_mutation = mutation_instance.make_copy()
else
actual_mutation = new mutation_to_add
SEND_SIGNAL(holder, COMSIG_CARBON_GAIN_MUTATION, actual_mutation.type, sources_to_add)
else
sources_to_add -= actual_mutation.sources
if(!length(sources_to_add)) //no new sources to add, don't do anything.
return
if(!length(actual_mutation.sources))
if(!actual_mutation.on_acquiring(holder))
qdel(actual_mutation)
return
actual_mutation.setup()
actual_mutation.sources |= sources
if(MUTATION_SOURCE_ACTIVATED in sources)
set_se(1, actual_mutation)
update_instability()
/datum/dna/proc/remove_mutation(mutation_to_remove, list/sources)
if(!islist(sources))
if(!sources)
CRASH("remove_mutation() called without set source(s)")
sources = list(sources)
var/datum/mutation/actual_mutation = get_mutation(mutation_to_remove)
if(!actual_mutation || !(sources & actual_mutation.sources))
return
actual_mutation.sources -= sources
if(MUTATION_SOURCE_ACTIVATED in sources)
set_se(0, actual_mutation)
// Check that it exists first before trying to remove it with mutadone
if(actual_mutation.mutadone_proof && mutadone)
return FALSE
if(!length(actual_mutation.sources))
SEND_SIGNAL(holder, COMSIG_CARBON_LOSE_MUTATION, actual_mutation.type)
actual_mutation.on_losing(holder)
qdel(actual_mutation)
SEND_SIGNAL(holder, COMSIG_CARBON_LOSE_MUTATION, mutation_type)
return force_lose(actual_mutation)
update_instability(FALSE)
/datum/dna/proc/check_mutation(mutation_type)
return get_mutation(mutation_type)
/datum/dna/proc/remove_all_mutations(list/classes = list(MUT_NORMAL, MUT_EXTRA, MUT_OTHER), mutadone = FALSE)
remove_mutation_group(mutations, classes, mutadone)
/datum/dna/proc/remove_all_mutations(sources = GLOB.standard_mutation_sources)
remove_mutation_group(mutations, sources)
scrambled = FALSE
/datum/dna/proc/remove_mutation_group(list/group, list/classes = list(MUT_NORMAL, MUT_EXTRA, MUT_OTHER), mutadone = FALSE)
/datum/dna/proc/remove_mutation_group(list/group, sources = GLOB.standard_mutation_sources)
if(!group)
return
for(var/datum/mutation/human/HM in group)
if((HM.class in classes) && !(HM.mutadone_proof && mutadone))
remove_mutation(HM)
for(var/datum/mutation/mutation in group)
remove_mutation(mutation, sources)
/datum/dna/proc/generate_unique_identity()
. = ""
@@ -299,10 +320,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
mutation_index.Cut()
default_mutation_genes.Cut()
shuffle_inplace(mutations_temp)
mutation_index[/datum/mutation/human/race] = create_sequence(/datum/mutation/human/race, FALSE)
default_mutation_genes[/datum/mutation/human/race] = mutation_index[/datum/mutation/human/race]
mutation_index[/datum/mutation/race] = create_sequence(/datum/mutation/race, FALSE)
default_mutation_genes[/datum/mutation/race] = mutation_index[/datum/mutation/race]
for(var/i in 2 to DNA_MUTATION_BLOCKS)
var/datum/mutation/human/M = mutations_temp[i]
var/datum/mutation/M = mutations_temp[i]
mutation_index[M.type] = create_sequence(M.type, FALSE, M.difficulty)
default_mutation_genes[M.type] = mutation_index[M.type]
shuffle_inplace(mutation_index)
@@ -318,7 +339,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
//Used to create a chipped gene sequence
/proc/create_sequence(mutation, active, difficulty)
if(!difficulty)
var/datum/mutation/human/A = GET_INITIALIZED_MUTATION(mutation) //leaves the possibility to change difficulty mid-round
var/datum/mutation/A = GET_INITIALIZED_MUTATION(mutation) //leaves the possibility to change difficulty mid-round
if(!A)
return
difficulty = A.difficulty
@@ -433,31 +454,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
set_uni_feature_block(blocknumber, construct_block(SSaccessories.pod_hair_list.Find(features["pod_hair"]), length(SSaccessories.pod_hair_list)))
if(DNA_FISH_TAIL_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_fish.Find(features["fish_tail"]), length(SSaccessories.tails_list_fish)))
*/
//SKYRAT EDIT REMOVAL END
//Please use add_mutation or activate_mutation instead
/datum/dna/proc/force_give(datum/mutation/human/human_mutation)
if(!holder || !human_mutation)
return
if(human_mutation.class == MUT_NORMAL)
set_se(1, human_mutation)
. = human_mutation.on_acquiring(holder)
if(!.)
qdel(human_mutation)
return
human_mutation.setup()
update_instability()
//Use remove_mutation instead
/datum/dna/proc/force_lose(datum/mutation/human/human_mutation)
if(!holder || !(human_mutation in mutations))
return
set_se(0, human_mutation)
. = human_mutation.on_losing(holder)
if(!(human_mutation in mutations))
qdel(human_mutation) // qdel mutations on removal
update_instability(FALSE)
/**
* Checks if two DNAs are practically the same by comparing their most defining features
@@ -479,10 +475,11 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
return FALSE
/datum/dna/proc/update_instability(alert=TRUE)
var/old_stability = stability
stability = 100
for(var/datum/mutation/human/M in mutations)
if(M.class == MUT_EXTRA || M.instability < 0)
stability -= M.instability * GET_MUTATION_STABILIZER(M)
for(var/datum/mutation/mutation in mutations)
if((MUTATION_SOURCE_MUTATOR in mutation.sources) || mutation.instability < 0)
stability -= mutation.instability * GET_MUTATION_STABILIZER(mutation)
if(holder)
var/message
if(alert)
@@ -501,7 +498,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
message = span_boldwarning("You can feel your DNA exploding, we need to do something fast!")
if(stability <= 0)
holder.apply_status_effect(/datum/status_effect/dna_melt)
if(message)
if(message && stability < old_stability)
to_chat(holder, message)
/// Updates the UI, UE, and UF of the DNA according to the features, appearance, name, etc. of the DNA / holder.
@@ -545,16 +542,16 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/datum/dna/stored //subtype used by brain mob's stored_dna and the crew manifest
/datum/dna/stored/add_mutation(mutation_name) //no mutation changes on stored dna.
/datum/dna/stored/add_mutation(mutation_name, list/sources) //no mutation changes on stored dna.
return
/datum/dna/stored/remove_mutation(mutation_name, mutadone)
/datum/dna/stored/remove_mutation(mutation_name, list/sources)
return
/datum/dna/stored/check_mutation(mutation_name)
return
/datum/dna/stored/remove_all_mutations(list/classes, mutadone = FALSE)
/datum/dna/stored/remove_all_mutations(list/classes, list/sources)
return
/datum/dna/stored/remove_mutation_group(list/group)
@@ -651,7 +648,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/// Sets the DNA of the mob to the given DNA.
/mob/living/carbon/human/proc/hardset_dna(unique_identity, list/mutation_index, list/default_mutation_genes, newreal_name, newblood_type, datum/species/mrace, newfeatures, list/mutations, force_transfer_mutations)
//Do not use force_transfer_mutations for stuff like cloners without some precautions, otherwise some conditional mutations could break (timers, drill hat etc)
if(newfeatures)
dna.features = newfeatures
dna.generate_unique_features()
@@ -684,9 +680,11 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
update_body(is_creating = TRUE)
update_mutations_overlay()
if(LAZYLEN(mutations) && force_transfer_mutations)
for(var/datum/mutation/human/mutation as anything in mutations)
dna.force_give(new mutation.type(mutation.class, copymut = mutation)) //using force_give since it may include exotic mutations that otherwise won't be handled properly
if(LAZYLEN(mutations) && force_transfer_mutations && can_mutate())
for(var/datum/mutation/mutation as anything in mutations)
var/list/allowed_sources = mutation.sources & GLOB.standard_mutation_sources
if(allowed_sources)
dna.add_mutation(mutation, allowed_sources)
/mob/living/carbon/proc/create_dna()
dna = new /datum/dna(src)
@@ -799,19 +797,24 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
update_mutations_overlay()
/datum/dna/proc/check_block(mutation)
var/datum/mutation/human/HM = get_mutation(mutation)
if(check_block_string(mutation))
if(!HM)
. = add_mutation(mutation, MUT_NORMAL)
/datum/dna/proc/check_block(mutation_path)
var/datum/mutation/mutation = get_mutation(mutation_path)
if(check_block_string(mutation_path))
if(!mutation)
. = add_mutation(mutation_path, MUTATION_SOURCE_ACTIVATED)
return
return force_lose(HM)
if(MUTATION_SOURCE_ACTIVATED in mutation?.sources)
remove_mutation(mutation, MUTATION_SOURCE_ACTIVATED)
//Return the active mutation of a type if there is one
/datum/dna/proc/get_mutation(A)
for(var/datum/mutation/human/HM in mutations)
if(istype(HM, A))
return HM
/datum/dna/proc/get_mutation(mutation_path)
if(istype(mutation_path, /datum/mutation))
var/datum/mutation/mutation = mutation_path
mutation_path = mutation.type
for(var/datum/mutation/mutation as anything in mutations)
if(mutation.type == mutation_path)
return mutation
return null
/datum/dna/proc/check_block_string(mutation)
if((LAZYLEN(mutation_index) > DNA_MUTATION_BLOCKS) || !(mutation in mutation_index))
@@ -821,7 +824,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/datum/dna/proc/is_gene_active(mutation)
return (mutation_index[mutation] == GET_SEQUENCE(mutation))
/datum/dna/proc/set_se(on=TRUE, datum/mutation/human/HM)
/datum/dna/proc/set_se(on=TRUE, datum/mutation/HM)
if(!HM || !(HM.type in mutation_index) || (LAZYLEN(mutation_index) < DNA_MUTATION_BLOCKS))
return
. = TRUE
@@ -837,12 +840,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(!mutation)
return FALSE
var/mutation_type = mutation
if(istype(mutation, /datum/mutation/human))
var/datum/mutation/human/M = mutation
mutation_type = M.type
if(istype(mutation, /datum/mutation))
var/datum/mutation/instance = mutation
mutation_type = instance.type
if(!mutation_in_sequence(mutation_type)) //can't activate what we don't have, use add_mutation
return FALSE
add_mutation(mutation, MUT_NORMAL)
add_mutation(mutation, MUTATION_SOURCE_ACTIVATED)
return TRUE
/////////////////////////// DNA HELPER-PROCS //////////////////////////////
@@ -850,23 +853,24 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/datum/dna/proc/mutation_in_sequence(mutation)
if(!mutation)
return
if(istype(mutation, /datum/mutation/human))
var/datum/mutation/human/HM = mutation
if(istype(mutation, /datum/mutation))
var/datum/mutation/HM = mutation
if(HM.type in mutation_index)
return TRUE
else if(mutation in mutation_index)
return TRUE
/mob/living/carbon/proc/random_mutate(list/candidates, difficulty = 2)
/mob/living/carbon/proc/random_mutate(list/candidates)
if(!has_dna())
CRASH("[src] does not have DNA")
var/mutation = pick(candidates)
. = dna.add_mutation(mutation)
. = dna.add_mutation(mutation, MUTATION_SOURCE_MUTATOR)
/mob/living/carbon/proc/easy_random_mutate(quality = POSITIVE + NEGATIVE + MINOR_NEGATIVE, scrambled = TRUE, sequence = TRUE, exclude_monkey = TRUE, resilient = NONE)
///Returns a random mutation typepath based on the given arguments. By default, all available mutations in the dna sequence but the monkey one.
/mob/living/carbon/proc/get_random_mutation_path(quality = POSITIVE|NEGATIVE|MINOR_NEGATIVE, scrambled = TRUE, sequence = TRUE, list/excluded_mutations = list(/datum/mutation/race))
if(!has_dna())
CRASH("[src] does not have DNA")
return null
var/list/mutations = list()
if(quality & POSITIVE)
mutations += GLOB.good_mutations
@@ -875,21 +879,21 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(quality & MINOR_NEGATIVE)
mutations += GLOB.not_good_mutations
var/list/possible = list()
for(var/datum/mutation/human/A in mutations)
if((!sequence || dna.mutation_in_sequence(A.type)) && !dna.get_mutation(A.type))
possible += A.type
if(exclude_monkey)
possible.Remove(/datum/mutation/human/race)
if(LAZYLEN(possible))
var/mutation = pick(possible)
. = dna.activate_mutation(mutation)
if(scrambled)
var/datum/mutation/human/HM = dna.get_mutation(mutation)
if(HM)
HM.scrambled = TRUE
if(HM.quality & resilient)
HM.mutadone_proof = TRUE
return TRUE
for(var/datum/mutation/mutation in mutations)
if((!sequence || dna.mutation_in_sequence(mutation.type)) && !dna.get_mutation(mutation.type))
possible += mutation.type
possible -= excluded_mutations
return pick(possible)
///Gives the mob a random mutation based on the given arguments.
/mob/living/carbon/proc/easy_random_mutate(quality = POSITIVE|NEGATIVE|MINOR_NEGATIVE, scrambled = TRUE, sequence = TRUE, list/excluded_mutations = list(/datum/mutation/race))
var/mutation_path = get_random_mutation_path(quality, scrambled, sequence, excluded_mutations)
dna.add_mutation(mutation_path, MUTATION_SOURCE_ACTIVATED)
if(!scrambled)
return
var/datum/mutation/mutation = dna.get_mutation(mutation_path)
if(mutation)
mutation.scrambled = TRUE
/mob/living/carbon/proc/random_mutate_unique_identity()
if(!has_dna())
+36 -36
View File
@@ -15,61 +15,61 @@
/* RECIPES */
/datum/generecipe/hulk
input_one = /datum/mutation/human/strong
input_two = /datum/mutation/human/radioactive
result = /datum/mutation/human/hulk
input_one = /datum/mutation/strong
input_two = /datum/mutation/radioactive
result = /datum/mutation/hulk
/datum/generecipe/mindread
input_one = /datum/mutation/human/antenna
input_two = /datum/mutation/human/paranoia
result = /datum/mutation/human/mindreader
input_one = /datum/mutation/antenna
input_two = /datum/mutation/paranoia
result = /datum/mutation/mindreader
/datum/generecipe/shock
input_one = /datum/mutation/human/insulated
input_two = /datum/mutation/human/radioactive
result = /datum/mutation/human/shock
input_one = /datum/mutation/insulated
input_two = /datum/mutation/radioactive
result = /datum/mutation/shock
/datum/generecipe/cindikinesis
input_one = /datum/mutation/human/geladikinesis
input_two = /datum/mutation/human/fire // fiery sweat NOT fiery breath
result = /datum/mutation/human/cindikinesis
input_one = /datum/mutation/geladikinesis
input_two = /datum/mutation/fire // fiery sweat NOT fiery breath
result = /datum/mutation/cindikinesis
/datum/generecipe/pyrokinesis
input_one = /datum/mutation/human/cryokinesis
input_two = /datum/mutation/human/fire // fiery sweat NOT fiery breath
result = /datum/mutation/human/pyrokinesis
input_one = /datum/mutation/cryokinesis
input_two = /datum/mutation/fire // fiery sweat NOT fiery breath
result = /datum/mutation/pyrokinesis
/datum/generecipe/thermal_adaptation
input_one = /datum/mutation/human/adaptation/cold
input_two = /datum/mutation/human/adaptation/heat
result = /datum/mutation/human/adaptation/thermal
input_one = /datum/mutation/adaptation/cold
input_two = /datum/mutation/adaptation/heat
result = /datum/mutation/adaptation/thermal
/datum/generecipe/antiglow
input_one = /datum/mutation/human/glow
input_two = /datum/mutation/human/void
result = /datum/mutation/human/glow/anti
input_one = /datum/mutation/glow
input_two = /datum/mutation/void
result = /datum/mutation/glow/anti
/datum/generecipe/tonguechem
input_one = /datum/mutation/human/tongue_spike
input_two = /datum/mutation/human/stimmed
result = /datum/mutation/human/tongue_spike/chem
input_one = /datum/mutation/tongue_spike
input_two = /datum/mutation/stimmed
result = /datum/mutation/tongue_spike/chem
/datum/generecipe/martyrdom
input_one = /datum/mutation/human/strong
input_two = /datum/mutation/human/stimmed
result = /datum/mutation/human/martyrdom
input_one = /datum/mutation/strong
input_two = /datum/mutation/stimmed
result = /datum/mutation/martyrdom
/datum/generecipe/heckacious
input_one = /datum/mutation/human/wacky
input_two = /datum/mutation/human/stoner
result = /datum/mutation/human/heckacious
input_one = /datum/mutation/wacky
input_two = /datum/mutation/stoner
result = /datum/mutation/heckacious
/datum/generecipe/ork
input_one = /datum/mutation/human/hulk
input_two = /datum/mutation/human/clumsy
result = /datum/mutation/human/hulk/ork
input_one = /datum/mutation/hulk
input_two = /datum/mutation/clumsy
result = /datum/mutation/hulk/ork
/datum/generecipe/rock_absorber
input_one = /datum/mutation/human/rock_eater
input_two = /datum/mutation/human/stoner
result = /datum/mutation/human/rock_absorber
input_one = /datum/mutation/rock_eater
input_two = /datum/mutation/stoner
result = /datum/mutation/rock_absorber
+30 -46
View File
@@ -21,7 +21,7 @@
/datum/mutation
var/name
/datum/mutation/human
/datum/mutation
name = "mutation"
/// Description of the mutation
var/desc = "A mutation."
@@ -55,14 +55,12 @@
var/blocks = 4
/// Amount of missing sequences. Sometimes it removes an entire pair for 2 points
var/difficulty = 8
/// Time between mutation creation and removal. If this exists, we have a timer
var/timeout
/// 'Mutation #49', decided every round to get some form of distinction between undiscovered mutations
var/alias
/// Whether we can read it if it's active. To avoid cheesing with mutagen
var/scrambled = FALSE
/// The class of mutation (MUT_NORMAL, MUT_EXTRA, MUT_OTHER)
var/class
/// The sources of the mutation (found in defines/dna.dm)
var/list/sources = list()
/**
* any mutations that might conflict.
* put mutation typepath defines in here.
@@ -80,8 +78,6 @@
var/can_chromosome = CHROMOSOME_NONE
/// Name of the chromosome
var/chromosome_name
/// Is this mutation mutadone proof
var/mutadone_proof = FALSE
//Chromosome stuff - set to -1 to prevent people from changing it. Example: It'd be a waste to decrease cooldown on mutism
/// genetic stability coeff
@@ -97,23 +93,30 @@
/// List of traits that are added or removed by the mutation with GENETIC_TRAIT source.
var/list/mutation_traits
/datum/mutation/human/New(class = MUT_OTHER, timer, datum/mutation/human/copymut)
/datum/mutation/New()
. = ..()
src.class = class
if(timer)
addtimer(CALLBACK(src, PROC_REF(remove)), timer)
timeout = timer
if(copymut && istype(copymut, /datum/mutation/human))
copy_mutation(copymut)
update_valid_chromosome_list()
/datum/mutation/human/Destroy()
/datum/mutation/Destroy()
power_path = null
dna = null
owner = null
return ..()
/datum/mutation/human/proc/on_acquiring(mob/living/carbon/human/acquirer)
/datum/mutation/proc/make_copy()
var/datum/mutation/copy = new type
copy.chromosome_name = chromosome_name
copy.stabilizer_coeff = stabilizer_coeff
copy.synchronizer_coeff = synchronizer_coeff
copy.power_coeff = power_coeff
copy.energy_coeff = energy_coeff
can_chromosome = can_chromosome
copy.valid_chrom_list = valid_chrom_list
update_valid_chromosome_list()
return copy
/datum/mutation/proc/on_acquiring(mob/living/carbon/human/acquirer)
if(!acquirer || !istype(acquirer) || acquirer.stat == DEAD || (src in acquirer.dna.mutations))
return FALSE
// SKYRAT EDIT ADDITION
@@ -126,7 +129,7 @@
return FALSE
if(limb_req && !acquirer.get_bodypart(limb_req))
return FALSE
for(var/datum/mutation/human/mewtayshun as anything in acquirer.dna.mutations) //check for conflicting powers
for(var/datum/mutation/mewtayshun as anything in acquirer.dna.mutations) //check for conflicting powers
if(!(mewtayshun.type in conflicts) && !(type in mewtayshun.conflicts))
continue
to_chat(acquirer, span_warning("You feel your genes resisting something."))
@@ -150,13 +153,13 @@
owner.add_traits(mutation_traits, GENETIC_MUTATION)
return TRUE
/datum/mutation/human/proc/get_visual_indicator()
/datum/mutation/proc/get_visual_indicator()
return
/datum/mutation/human/proc/on_life(seconds_per_tick, times_fired)
/datum/mutation/proc/on_life(seconds_per_tick, times_fired)
return
/datum/mutation/human/proc/on_losing(mob/living/carbon/human/owner)
/datum/mutation/proc/on_losing(mob/living/carbon/human/owner)
if(!istype(owner) || !(owner.dna.mutations.Remove(src)))
return TRUE
. = FALSE
@@ -179,9 +182,9 @@
return
/mob/living/carbon/human/update_mutations_overlay()
for(var/datum/mutation/human/mutation in dna.mutations)
for(var/datum/mutation/mutation as anything in dna.mutations)
if(mutation.species_allowed && !mutation.species_allowed.Find(dna.species.id))
dna.force_lose(mutation) //shouldn't have that mutation at all
dna.remove_mutation(mutation, mutation.sources) //shouldn't have that mutation at all
continue
if(mutation.visual_indicators.len == 0)
continue
@@ -201,7 +204,7 @@
* Called after on_aquiring, or when a chromosome is applied.
* returns the instance of 'power_path' for children calls to use without calling locate() again.
*/
/datum/mutation/human/proc/setup()
/datum/mutation/proc/setup()
if(!power_path || QDELETED(owner))
return
var/datum/action/cooldown/modified_power = locate(power_path) in owner.actions
@@ -210,34 +213,15 @@
modified_power.cooldown_time = initial(modified_power.cooldown_time) * GET_MUTATION_ENERGY(src)
return modified_power
/datum/mutation/human/proc/copy_mutation(datum/mutation/human/mutation_to_copy)
if(!mutation_to_copy)
return
chromosome_name = mutation_to_copy.chromosome_name
stabilizer_coeff = mutation_to_copy.stabilizer_coeff
synchronizer_coeff = mutation_to_copy.synchronizer_coeff
power_coeff = mutation_to_copy.power_coeff
energy_coeff = mutation_to_copy.energy_coeff
mutadone_proof = mutation_to_copy.mutadone_proof
can_chromosome = mutation_to_copy.can_chromosome
valid_chrom_list = mutation_to_copy.valid_chrom_list
/datum/mutation/human/proc/remove_chromosome()
/datum/mutation/proc/remove_chromosome()
stabilizer_coeff = initial(stabilizer_coeff)
synchronizer_coeff = initial(synchronizer_coeff)
power_coeff = initial(power_coeff)
energy_coeff = initial(energy_coeff)
mutadone_proof = initial(mutadone_proof)
can_chromosome = initial(can_chromosome)
chromosome_name = null
/datum/mutation/human/proc/remove()
if(dna)
dna.force_lose(src)
else
qdel(src)
/datum/mutation/human/proc/grant_power()
/datum/mutation/proc/grant_power()
if(!ispath(power_path) || !owner)
return FALSE
@@ -254,7 +238,7 @@
// Runs through all the coefficients and uses this to determine which chromosomes the
// mutation can take. Stores these as text strings in a list.
/datum/mutation/human/proc/update_valid_chromosome_list()
/datum/mutation/proc/update_valid_chromosome_list()
valid_chrom_list.Cut()
if(can_chromosome == CHROMOSOME_NEVER)
+2 -2
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/adrenaline_rush
/datum/mutation/adrenaline_rush
name = "Adrenaline Rush"
desc = "Allows the host to trigger their body's adrenaline response at will."
quality = POSITIVE
@@ -10,7 +10,7 @@
synchronizer_coeff = 1
power_coeff = 1
/datum/mutation/human/adrenaline_rush/setup()
/datum/mutation/adrenaline_rush/setup()
. = ..()
var/datum/action/cooldown/adrenaline/to_modify = .
if(!istype(to_modify)) // null or invalid
+9 -9
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/adaptation
/datum/mutation/adaptation
name = "Adaptation"
desc = "A strange mutation that renders the host immune to damage from extreme temperatures. Does not protect from vacuums."
quality = POSITIVE
@@ -6,21 +6,21 @@
text_gain_indication = span_notice("Your body feels normal!")
instability = NEGATIVE_STABILITY_MAJOR
locked = TRUE // fake parent
conflicts = list(/datum/mutation/human/adaptation)
conflicts = list(/datum/mutation/adaptation)
mutation_traits = list(TRAIT_WADDLING)
/// Icon used for the adaptation overlay
var/adapt_icon = "meow"
/datum/mutation/human/adaptation/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
/datum/mutation/adaptation/New(datum/mutation/copymut)
..()
conflicts = typesof(/datum/mutation/human/adaptation)
conflicts = typesof(/datum/mutation/adaptation)
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', adapt_icon, -MUTATIONS_LAYER))
/datum/mutation/human/adaptation/get_visual_indicator()
/datum/mutation/adaptation/get_visual_indicator()
return visual_indicators[type][1]
/datum/mutation/human/adaptation/cold
/datum/mutation/adaptation/cold
name = "Cold Adaptation"
desc = "A strange mutation that renders the host immune to damage from low temperature environments. It also prevents the host from slipping on ice."
text_gain_indication = span_notice("Your body feels refreshingly cold.")
@@ -29,7 +29,7 @@
adapt_icon = "cold"
locked = FALSE
/datum/mutation/human/adaptation/heat
/datum/mutation/adaptation/heat
name = "Heat Adaptation"
desc = "A strange mutation that renders the host immune to damage from high temperature, including being set alight, though the flame itself still burns clothing. It also seems to make the host resist ash storms."
text_gain_indication = span_notice("Your body feels invigoratingly warm.")
@@ -38,7 +38,7 @@
adapt_icon = "fire"
locked = FALSE
/datum/mutation/human/adaptation/thermal
/datum/mutation/adaptation/thermal
name = "Thermal Adaptation"
desc = "A strange mutation that renders the host immune to damage from both low and high temperature environments. Does not protect from high or low pressure environments."
difficulty = 32
@@ -48,7 +48,7 @@
adapt_icon = "thermal"
locked = TRUE // recipe
/datum/mutation/human/adaptation/pressure
/datum/mutation/adaptation/pressure
name = "Pressure Adaptation"
desc = "A strange mutation that renders the host immune to damage from both low and high pressure environments. Does not protect from temperature, including the cold of space."
text_gain_indication = span_notice("Your body feels impressively pressurized.")
+8 -8
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/antenna
/datum/mutation/antenna
name = "Antenna"
desc = "The affected person sprouts an antenna. This is known to allow them to access common radio channels passively."
quality = POSITIVE
@@ -18,7 +18,7 @@
. = ..()
radio.name = "internal antenna"
/datum/mutation/human/antenna/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/antenna/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -26,22 +26,22 @@
linked_radio.implant(owner, null, TRUE, TRUE)
radio_weakref = WEAKREF(linked_radio)
/datum/mutation/human/antenna/on_losing(mob/living/carbon/human/owner)
/datum/mutation/antenna/on_losing(mob/living/carbon/human/owner)
if(..())
return
var/obj/item/implant/radio/antenna/linked_radio = radio_weakref.resolve()
if(linked_radio)
QDEL_NULL(linked_radio)
/datum/mutation/human/antenna/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
/datum/mutation/antenna/New(datum/mutation/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "antenna", -FRONT_MUTATIONS_LAYER+1))//-MUTATIONS_LAYER+1
/datum/mutation/human/antenna/get_visual_indicator()
/datum/mutation/antenna/get_visual_indicator()
return visual_indicators[type][1]
/datum/mutation/human/mindreader
/datum/mutation/mindreader
name = "Mind Reader"
desc = "The affected person can look into the recent memories of others."
quality = POSITIVE
@@ -118,10 +118,10 @@
to_chat(owner, span_boldnotice("You find that their intent is to [carbon_cast_on.combat_mode ? "harm" : "help"]..."))
to_chat(owner, span_boldnotice("You uncover that [carbon_cast_on.p_their()] true identity is [carbon_cast_on.mind.name]."))
/datum/mutation/human/mindreader/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
/datum/mutation/mindreader/New(datum/mutation/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "antenna", -FRONT_MUTATIONS_LAYER+1))
/datum/mutation/human/mindreader/get_visual_indicator()
/datum/mutation/mindreader/get_visual_indicator()
return visual_indicators[type][1]
+1 -1
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/self_amputation
/datum/mutation/self_amputation
name = "Autotomy"
desc = "Allows a creature to voluntary discard a random appendage."
quality = POSITIVE
+83 -84
View File
@@ -1,7 +1,7 @@
//These mutations change your overall "form" somehow, like size
//Epilepsy gives a very small chance to have a seizure every life tick, knocking you unconscious.
/datum/mutation/human/epilepsy
/datum/mutation/epilepsy
name = "Epilepsy"
desc = "A genetic defect that sporadically causes seizures."
instability = NEGATIVE_STABILITY_MODERATE
@@ -10,11 +10,11 @@
synchronizer_coeff = 1
power_coeff = 1
/datum/mutation/human/epilepsy/on_life(seconds_per_tick, times_fired)
/datum/mutation/epilepsy/on_life(seconds_per_tick, times_fired)
if(SPT_PROB(0.5 * GET_MUTATION_SYNCHRONIZER(src), seconds_per_tick))
trigger_seizure()
/datum/mutation/human/epilepsy/proc/trigger_seizure()
/datum/mutation/epilepsy/proc/trigger_seizure()
if(owner.stat != CONSCIOUS)
return
owner.visible_message(span_danger("[owner] starts having a seizure!"), span_userdanger("You have a seizure!"))
@@ -23,24 +23,24 @@
owner.add_mood_event("epilepsy", /datum/mood_event/epilepsy)
addtimer(CALLBACK(src, PROC_REF(jitter_less)), 9 SECONDS)
/datum/mutation/human/epilepsy/proc/jitter_less()
/datum/mutation/epilepsy/proc/jitter_less()
if(QDELETED(owner))
return
owner.set_jitter(20 SECONDS)
/datum/mutation/human/epilepsy/on_acquiring(mob/living/carbon/human/acquirer)
/datum/mutation/epilepsy/on_acquiring(mob/living/carbon/human/acquirer)
. = ..()
if(!.)
return
RegisterSignal(owner, COMSIG_MOB_FLASHED, PROC_REF(get_flashed_nerd))
/datum/mutation/human/epilepsy/on_losing(mob/living/carbon/human/owner)
/datum/mutation/epilepsy/on_losing(mob/living/carbon/human/owner)
if(..())
return
UnregisterSignal(owner, COMSIG_MOB_FLASHED)
/datum/mutation/human/epilepsy/proc/get_flashed_nerd()
/datum/mutation/epilepsy/proc/get_flashed_nerd()
SIGNAL_HANDLER
if(!prob(30))
@@ -49,7 +49,7 @@
//Unstable DNA induces random mutations!
/datum/mutation/human/bad_dna
/datum/mutation/bad_dna
name = "Unstable DNA"
desc = "Strange mutation that causes the holder to randomly mutate."
instability = NEGATIVE_STABILITY_MAJOR
@@ -57,7 +57,7 @@
text_gain_indication = span_danger("You feel strange.")
locked = TRUE
/datum/mutation/human/bad_dna/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/bad_dna/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -80,7 +80,7 @@
//Cough gives you a chronic cough that causes you to drop items.
/datum/mutation/human/cough
/datum/mutation/cough
name = "Cough"
desc = "A chronic cough."
instability = NEGATIVE_STABILITY_MODERATE
@@ -89,7 +89,7 @@
synchronizer_coeff = 1
power_coeff = 1
/datum/mutation/human/cough/on_life(seconds_per_tick, times_fired)
/datum/mutation/cough/on_life(seconds_per_tick, times_fired)
if(SPT_PROB(2.5 * GET_MUTATION_SYNCHRONIZER(src), seconds_per_tick) && owner.stat == CONSCIOUS)
owner.drop_all_held_items()
owner.emote("cough")
@@ -98,7 +98,7 @@
var/turf/target = get_ranged_target_turf(owner, REVERSE_DIR(owner.dir), cough_range)
owner.throw_at(target, cough_range, GET_MUTATION_POWER(src))
/datum/mutation/human/paranoia
/datum/mutation/paranoia
name = "Paranoia"
desc = "Subject is easily terrified, and may suffer from hallucinations."
instability = NEGATIVE_STABILITY_MODERATE
@@ -106,23 +106,23 @@
text_gain_indication = span_danger("You feel screams echo through your mind...")
text_lose_indication = span_notice("The screaming in your mind fades.")
/datum/mutation/human/paranoia/on_life(seconds_per_tick, times_fired)
/datum/mutation/paranoia/on_life(seconds_per_tick, times_fired)
if(SPT_PROB(2.5, seconds_per_tick) && owner.stat == CONSCIOUS)
owner.emote("scream")
if(prob(25))
owner.adjust_hallucinations(40 SECONDS)
//Dwarfism shrinks your body and lets you pass tables.
/datum/mutation/human/dwarfism
/datum/mutation/dwarfism
name = "Dwarfism"
desc = "A mutation believed to be the cause of dwarfism."
quality = POSITIVE
difficulty = 16
instability = POSITIVE_INSTABILITY_MINOR
conflicts = list(/datum/mutation/human/gigantism, /datum/mutation/human/acromegaly)
conflicts = list(/datum/mutation/gigantism, /datum/mutation/acromegaly)
locked = TRUE // Default intert species for now, so locked from regular pool.
/datum/mutation/human/dwarfism/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/dwarfism/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -135,7 +135,7 @@
ADD_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
owner.visible_message(span_danger("[owner] suddenly shrinks!"), span_notice("Everything around you seems to grow.."))
/datum/mutation/human/dwarfism/on_losing(mob/living/carbon/human/owner)
/datum/mutation/dwarfism/on_losing(mob/living/carbon/human/owner)
if(..())
return
// SKYRAT EDIT BEGIN
@@ -147,16 +147,16 @@
REMOVE_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
owner.visible_message(span_danger("[owner] suddenly grows!"), span_notice("Everything around you seems to shrink.."))
/datum/mutation/human/acromegaly
/datum/mutation/acromegaly
name = "Acromegaly"
desc = "A mutation believed to be the cause of acromegaly, or 'being unusually tall'."
quality = MINOR_NEGATIVE
difficulty = 16
instability = NEGATIVE_STABILITY_MODERATE
synchronizer_coeff = 1
conflicts = list(/datum/mutation/human/dwarfism)
conflicts = list(/datum/mutation/dwarfism)
/datum/mutation/human/acromegaly/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/acromegaly/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -165,7 +165,7 @@
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(head_bonk))
owner.regenerate_icons()
/datum/mutation/human/acromegaly/on_losing(mob/living/carbon/human/owner)
/datum/mutation/acromegaly/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_TOO_TALL, GENETIC_MUTATION)
@@ -174,7 +174,7 @@
owner.regenerate_icons()
// This is specifically happening because they're not used to their new height and are stumbling around into machinery made for normal humans
/datum/mutation/human/acromegaly/proc/head_bonk(mob/living/parent)
/datum/mutation/acromegaly/proc/head_bonk(mob/living/parent)
SIGNAL_HANDLER
var/atom/movable/whacked_by = (locate(/obj/machinery/door/airlock) in parent.loc) || (locate(/obj/machinery/door/firedoor) in parent.loc) || (locate(/obj/structure/mineral_door) in parent.loc)
if(!whacked_by || prob(100 - (8 * GET_MUTATION_SYNCHRONIZER(src))))
@@ -186,14 +186,14 @@
playsound(whacked_by, 'sound/effects/bang.ogg', 10, TRUE)
parent.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS)
/datum/mutation/human/gigantism
/datum/mutation/gigantism
name = "Gigantism" //negative version of dwarfism
desc = "The cells within the subject spread out to cover more area, making the subject appear larger."
quality = MINOR_NEGATIVE
difficulty = 12
conflicts = list(/datum/mutation/human/dwarfism)
conflicts = list(/datum/mutation/dwarfism)
/datum/mutation/human/gigantism/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/gigantism/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -207,7 +207,7 @@
owner.update_transform(1.25)
owner.visible_message(span_danger("[owner] suddenly grows!"), span_notice("Everything around you seems to shrink.."))
/datum/mutation/human/gigantism/on_losing(mob/living/carbon/human/owner)
/datum/mutation/gigantism/on_losing(mob/living/carbon/human/owner)
if(..())
return
// SKYRAT EDIT BEGIN
@@ -220,7 +220,7 @@
owner.visible_message(span_danger("[owner] suddenly shrinks!"), span_notice("Everything around you seems to grow.."))
//Clumsiness has a very large amount of small drawbacks depending on item.
/datum/mutation/human/clumsy
/datum/mutation/clumsy
name = "Clumsiness"
desc = "A genome that inhibits certain brain functions, causing the holder to appear clumsy. Honk!"
instability = NEGATIVE_STABILITY_MAJOR
@@ -229,7 +229,7 @@
mutation_traits = list(TRAIT_CLUMSY)
//Tourettes causes you to randomly stand in place and shout.
/datum/mutation/human/tourettes
/datum/mutation/tourettes
name = "Tourette's Syndrome"
desc = "A chronic twitch that forces the user to scream bad words." //definitely needs rewriting
quality = NEGATIVE
@@ -237,7 +237,7 @@
text_gain_indication = span_danger("You twitch.")
synchronizer_coeff = 1
/datum/mutation/human/tourettes/on_life(seconds_per_tick, times_fired)
/datum/mutation/tourettes/on_life(seconds_per_tick, times_fired)
if(SPT_PROB(5 * GET_MUTATION_SYNCHRONIZER(src), seconds_per_tick) && owner.stat == CONSCIOUS && !owner.IsStun())
switch(rand(1, 3))
if(1)
@@ -251,7 +251,7 @@
//Deafness makes you deaf.
/datum/mutation/human/deaf
/datum/mutation/deaf
name = "Deafness"
desc = "The holder of this genome is completely deaf."
instability = NEGATIVE_STABILITY_MAJOR
@@ -260,7 +260,7 @@
mutation_traits = list(TRAIT_DEAF)
//Monified turns you into a monkey.
/datum/mutation/human/race
/datum/mutation/race
name = "Monkified"
desc = "A strange genome, believing to be what differentiates monkeys from humans."
text_gain_indication = span_green("You feel unusually monkey-like.")
@@ -269,11 +269,10 @@
instability = NEGATIVE_STABILITY_MAJOR // mmmonky
remove_on_aheal = FALSE
locked = TRUE //Species specific, keep out of actual gene pool
mutadone_proof = TRUE
var/datum/species/original_species = /datum/species/human
var/original_name
/datum/mutation/human/race/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/race/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -283,7 +282,7 @@
original_name = owner.real_name
owner.monkeyize()
/datum/mutation/human/race/on_losing(mob/living/carbon/human/owner)
/datum/mutation/race/on_losing(mob/living/carbon/human/owner)
if(owner.stat == DEAD)
return
. = ..()
@@ -295,20 +294,20 @@
owner.fully_replace_character_name(null, original_name)
owner.humanize(original_species)
/datum/mutation/human/glow
/datum/mutation/glow
name = "Glowy"
desc = "You permanently emit a light with a random color and intensity."
quality = POSITIVE
text_gain_indication = span_notice("Your skin begins to glow softly.")
instability = POSITIVE_INSTABILITY_MINI
power_coeff = 1
conflicts = list(/datum/mutation/human/glow/anti)
conflicts = list(/datum/mutation/glow/anti)
var/glow_power = 2
var/glow_range = 2.5
var/glow_color
var/obj/effect/dummy/lighting_obj/moblight/glow
/datum/mutation/human/glow/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/glow/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -316,35 +315,35 @@
glow = owner.mob_light()
// Override modify here without a parent call, because we don't actually give an action.
/datum/mutation/human/glow/setup()
/datum/mutation/glow/setup()
if(!glow)
return
glow.set_light_range_power_color(glow_range * GET_MUTATION_POWER(src), glow_power, glow_color)
/datum/mutation/human/glow/on_losing(mob/living/carbon/human/owner)
/datum/mutation/glow/on_losing(mob/living/carbon/human/owner)
. = ..()
if(.)
return
QDEL_NULL(glow)
/// Returns a color for the glow effect
/datum/mutation/human/glow/proc/get_glow_color()
/datum/mutation/glow/proc/get_glow_color()
return pick(COLOR_RED, COLOR_BLUE, COLOR_YELLOW, COLOR_GREEN, COLOR_PURPLE, COLOR_ORANGE)
/datum/mutation/human/glow/anti
/datum/mutation/glow/anti
name = "Anti-Glow"
desc = "Your skin seems to attract and absorb nearby light creating 'darkness' around you."
text_gain_indication = span_notice("The light around you seems to disappear.")
conflicts = list(/datum/mutation/human/glow)
conflicts = list(/datum/mutation/glow)
instability = POSITIVE_INSTABILITY_MINOR
locked = TRUE
glow_power = -1.5
/datum/mutation/human/glow/anti/get_glow_color()
/datum/mutation/glow/anti/get_glow_color()
return COLOR_BLACK
/datum/mutation/human/strong
/datum/mutation/strong
name = "Strength"
desc = "The user's muscles slightly expand. Commonly seen in top-ranking boxers."
quality = POSITIVE
@@ -353,7 +352,7 @@
difficulty = 16
mutation_traits = list(TRAIT_STRENGTH)
/datum/mutation/human/stimmed
/datum/mutation/stimmed
name = "Stimmed"
desc = "The user's chemical balance is more robust. This mutation is known to slightly improve workout efficiency."
quality = POSITIVE
@@ -362,7 +361,7 @@
difficulty = 16
mutation_traits = list(TRAIT_STIMMED)
/datum/mutation/human/insulated
/datum/mutation/insulated
name = "Insulated"
desc = "The affected person does not conduct electricity."
quality = POSITIVE
@@ -372,34 +371,34 @@
instability = POSITIVE_INSTABILITY_MODERATE
mutation_traits = list(TRAIT_SHOCKIMMUNE)
/datum/mutation/human/fire
/datum/mutation/fire
name = "Fiery Sweat"
desc = "The user's skin will randomly combust, but is generally a lot more resilient to burning."
quality = NEGATIVE
text_gain_indication = span_warning("You feel hot.")
text_lose_indication = span_notice("You feel a lot cooler.")
conflicts = list(/datum/mutation/human/adaptation/heat)
conflicts = list(/datum/mutation/adaptation/heat)
difficulty = 14
synchronizer_coeff = 1
power_coeff = 1
/datum/mutation/human/fire/on_life(seconds_per_tick, times_fired)
/datum/mutation/fire/on_life(seconds_per_tick, times_fired)
if(SPT_PROB((0.05+(100-dna.stability)/19.5) * GET_MUTATION_SYNCHRONIZER(src), seconds_per_tick))
owner.adjust_fire_stacks(2 * GET_MUTATION_POWER(src))
owner.ignite_mob()
/datum/mutation/human/fire/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/fire/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
owner.physiology.burn_mod *= 0.5
/datum/mutation/human/fire/on_losing(mob/living/carbon/human/owner)
/datum/mutation/fire/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.physiology.burn_mod *= 2
/datum/mutation/human/badblink
/datum/mutation/badblink
name = "Spatial Instability"
desc = "The victim of the mutation has a very weak link to spatial reality, and may be displaced. Often causes extreme nausea."
quality = NEGATIVE
@@ -412,7 +411,7 @@
power_coeff = 1
var/warpchance = 0
/datum/mutation/human/badblink/on_life(seconds_per_tick, times_fired)
/datum/mutation/badblink/on_life(seconds_per_tick, times_fired)
if(SPT_PROB(warpchance, seconds_per_tick))
var/warpmessage = pick(
span_warning("With a sickening 720-degree twist of [owner.p_their()] back, [owner] vanishes into thin air."),
@@ -429,7 +428,7 @@
else
warpchance += 0.0625 * seconds_per_tick / GET_MUTATION_ENERGY(src)
/datum/mutation/human/acidflesh
/datum/mutation/acidflesh
name = "Acidic Flesh"
desc = "Subject has acidic chemicals building up underneath the skin. This is often lethal."
instability = NEGATIVE_STABILITY_MAJOR
@@ -440,7 +439,7 @@
/// The cooldown for the warning message
COOLDOWN_DECLARE(msgcooldown)
/datum/mutation/human/acidflesh/on_life(seconds_per_tick, times_fired)
/datum/mutation/acidflesh/on_life(seconds_per_tick, times_fired)
if(SPT_PROB(13, seconds_per_tick))
if(COOLDOWN_FINISHED(src, msgcooldown))
to_chat(owner, span_danger("Your acid flesh bubbles..."))
@@ -450,7 +449,7 @@
owner.visible_message(span_warning("[owner]'s skin bubbles and pops."), span_userdanger("Your bubbling flesh pops! It burns!"))
playsound(owner,'sound/items/weapons/sear.ogg', 50, TRUE)
/datum/mutation/human/spastic
/datum/mutation/spastic
name = "Spastic"
desc = "Subject suffers from muscle spasms."
instability = NEGATIVE_STABILITY_MODERATE
@@ -459,18 +458,18 @@
text_lose_indication = span_notice("Your flinching subsides.")
difficulty = 16
/datum/mutation/human/spastic/on_acquiring()
/datum/mutation/spastic/on_acquiring()
. = ..()
if(!.)
return
owner.apply_status_effect(/datum/status_effect/spasms)
/datum/mutation/human/spastic/on_losing()
/datum/mutation/spastic/on_losing()
if(..())
return
owner.remove_status_effect(/datum/status_effect/spasms)
/datum/mutation/human/extrastun
/datum/mutation/extrastun
name = "Two Left Feet"
desc = "A mutation that replaces the right foot with another left foot. Symptoms include kissing the floor when taking a step."
instability = NEGATIVE_STABILITY_MODERATE
@@ -479,20 +478,20 @@
text_lose_indication = span_notice("Your right foot feels alright.")
difficulty = 16
/datum/mutation/human/extrastun/on_acquiring()
/datum/mutation/extrastun/on_acquiring()
. = ..()
if(!.)
return
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
/datum/mutation/human/extrastun/on_losing()
/datum/mutation/extrastun/on_losing()
. = ..()
if(.)
return
UnregisterSignal(owner, COMSIG_MOVABLE_MOVED)
///Triggers on moved(). Randomly makes the owner trip
/datum/mutation/human/extrastun/proc/on_move()
/datum/mutation/extrastun/proc/on_move()
SIGNAL_HANDLER
if(prob(99.5)) //The brawl mutation
@@ -502,7 +501,7 @@
to_chat(owner, span_danger("You trip over your own feet."))
owner.Knockdown(30)
/datum/mutation/human/martyrdom
/datum/mutation/martyrdom
name = "Internal Martyrdom"
desc = "A mutation that makes the body destruct when near death. Not damaging, but very, VERY disorienting."
instability = NEGATIVE_STABILITY_MAJOR // free stability >:)
@@ -511,19 +510,19 @@
text_gain_indication = span_warning("You get an intense feeling of heartburn.")
text_lose_indication = span_notice("Your internal organs feel at ease.")
/datum/mutation/human/martyrdom/on_acquiring()
/datum/mutation/martyrdom/on_acquiring()
. = ..()
if(!.)
return
RegisterSignal(owner, COMSIG_MOB_STATCHANGE, PROC_REF(bloody_shower))
/datum/mutation/human/martyrdom/on_losing()
/datum/mutation/martyrdom/on_losing()
. = ..()
if(.)
return TRUE
UnregisterSignal(owner, COMSIG_MOB_STATCHANGE)
/datum/mutation/human/martyrdom/proc/bloody_shower(datum/source, new_stat)
/datum/mutation/martyrdom/proc/bloody_shower(datum/source, new_stat)
SIGNAL_HANDLER
if(new_stat != HARD_CRIT)
@@ -550,7 +549,7 @@
owner.investigate_log("has been gibbed by the martyrdom mutation.", INVESTIGATE_DEATHS)
owner.gib(DROP_ALL_REMAINS)
/datum/mutation/human/headless
/datum/mutation/headless
name = "H.A.R.S."
desc = "A mutation that makes the body reject the head, the brain receding into the chest. Stands for Head Allergic Rejection Syndrome. Warning: Removing this mutation is very dangerous, though it will regenerate non-vital head organs."
instability = NEGATIVE_STABILITY_MAJOR
@@ -558,7 +557,7 @@
quality = NEGATIVE //holy shit no eyes or tongue or ears
text_gain_indication = span_warning("Something feels off.")
/datum/mutation/human/headless/on_acquiring()
/datum/mutation/headless/on_acquiring()
. = ..()
if(!.)
return
@@ -578,7 +577,7 @@
qdel(head)
RegisterSignal(owner, COMSIG_ATTEMPT_CARBON_ATTACH_LIMB, PROC_REF(abort_attachment))
/datum/mutation/human/headless/on_losing()
/datum/mutation/headless/on_losing()
. = ..()
if(.)
return TRUE
@@ -599,14 +598,14 @@
owner.visible_message(span_warning("[owner]'s head returns with a sickening crunch!"), span_warning("Your head regrows with a sickening crack! Ouch."))
new /obj/effect/gibspawner/generic(get_turf(owner), owner)
/datum/mutation/human/headless/proc/abort_attachment(datum/source, obj/item/bodypart/new_limb, special) //you aren't getting your head back
/datum/mutation/headless/proc/abort_attachment(datum/source, obj/item/bodypart/new_limb, special) //you aren't getting your head back
SIGNAL_HANDLER
if(istype(new_limb, /obj/item/bodypart/head))
return COMPONENT_NO_ATTACH
// You bleed faster but regenerate blood faster
/datum/mutation/human/bloodier
/datum/mutation/bloodier
name = "Hypermetabolic Blood"
desc = "The subject's blood is hypermetabolic, causing it to be produced at a much faster rate."
quality = POSITIVE
@@ -624,7 +623,7 @@
/// Tracks if we've modified the physiology of the owner
VAR_PRIVATE/physiology_modified = FALSE
/datum/mutation/human/bloodier/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/bloodier/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -633,7 +632,7 @@
owner.physiology.blood_regen_mod *= blood_regen_rate
physiology_modified = TRUE
/datum/mutation/human/bloodier/on_losing(mob/living/carbon/human/owner)
/datum/mutation/bloodier/on_losing(mob/living/carbon/human/owner)
. = ..()
if(.)
return
@@ -642,7 +641,7 @@
owner.physiology.blood_regen_mod /= blood_regen_rate
physiology_modified = FALSE // just in case
/datum/mutation/human/bloodier/setup()
/datum/mutation/bloodier/setup()
if(owner && physiology_modified)
owner.physiology.bleed_mod /= bleed_rate
owner.physiology.blood_regen_mod /= blood_regen_rate
@@ -658,7 +657,7 @@
return TRUE
// You eat rocks
/datum/mutation/human/rock_eater
/datum/mutation/rock_eater
name = "Rock Eater"
desc = "The subject's body is able to digest rocks and minerals."
quality = POSITIVE
@@ -667,10 +666,10 @@
text_lose_indication = span_notice("You could go for a normal meal.")
difficulty = 12
mutation_traits = list(TRAIT_ROCK_EATER)
conflicts = list(/datum/mutation/human/rock_absorber)
conflicts = list(/datum/mutation/rock_absorber)
// You eat rock but also get buffs from them
/datum/mutation/human/rock_absorber
/datum/mutation/rock_absorber
name = "Rock Absorber"
desc = "The subject's body is able to digest rocks and minerals, taking on their properties."
quality = POSITIVE
@@ -678,10 +677,10 @@
text_gain_indication = span_notice("You feel a supreme craving for rocks.")
text_lose_indication = span_notice("You could go for a normal meal.")
mutation_traits = list(TRAIT_ROCK_EATER, TRAIT_ROCK_METAMORPHIC)
conflicts = list(/datum/mutation/human/rock_eater)
conflicts = list(/datum/mutation/rock_eater)
locked = TRUE
/datum/mutation/human/rock_absorber/on_losing(mob/living/carbon/human/owner)
/datum/mutation/rock_absorber/on_losing(mob/living/carbon/human/owner)
. = ..()
if(. || QDELING(owner) || HAS_TRAIT(owner, TRAIT_ROCK_METAMORPHIC))
return
@@ -689,7 +688,7 @@
owner.remove_status_effect(/datum/status_effect/golem_lightbulb)
// Soft crit is disabed
/datum/mutation/human/inexorable
/datum/mutation/inexorable
name = "Inexorable"
desc = "Your body can push on beyond the limits of normal human endurance. \
However, pushing it too far can cause severe damage to your body."
@@ -701,28 +700,28 @@
synchronizer_coeff = 1
mutation_traits = list(TRAIT_NOSOFTCRIT, TRAIT_ANALGESIA)
/datum/mutation/human/inexorable/on_acquiring(mob/living/carbon/human/acquirer)
/datum/mutation/inexorable/on_acquiring(mob/living/carbon/human/acquirer)
. = ..()
if(!.)
return
RegisterSignal(acquirer, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(check_health))
check_health()
/datum/mutation/human/inexorable/on_losing(mob/living/carbon/human/owner)
/datum/mutation/inexorable/on_losing(mob/living/carbon/human/owner)
. = ..()
if(.)
return
UnregisterSignal(owner, COMSIG_LIVING_HEALTH_UPDATE)
REMOVE_TRAIT(owner, TRAIT_SOFTSPOKEN, REF(src))
/datum/mutation/human/inexorable/proc/check_health(...)
/datum/mutation/inexorable/proc/check_health(...)
SIGNAL_HANDLER
if(owner.health > owner.crit_threshold || owner.stat != CONSCIOUS)
REMOVE_TRAIT(owner, TRAIT_SOFTSPOKEN, REF(src))
else
ADD_TRAIT(owner, TRAIT_SOFTSPOKEN, REF(src))
/datum/mutation/human/inexorable/on_life(seconds_per_tick, times_fired)
/datum/mutation/inexorable/on_life(seconds_per_tick, times_fired)
if(owner.health > owner.crit_threshold || owner.stat != CONSCIOUS || HAS_TRAIT(owner, TRAIT_STASIS))
return
// Gives you 30 seconds of being in soft crit... give or take
+7 -7
View File
@@ -1,5 +1,5 @@
//Chameleon causes the owner to slowly become transparent when not moving.
/datum/mutation/human/chameleon
/datum/mutation/chameleon
name = "Chameleon"
desc = "A genome that causes the holder's skin to become transparent over time."
quality = POSITIVE
@@ -9,7 +9,7 @@
instability = POSITIVE_INSTABILITY_MAJOR
power_coeff = 1
/datum/mutation/human/chameleon/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/chameleon/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -22,14 +22,14 @@
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
RegisterSignal(owner, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_attack_hand))
/datum/mutation/human/chameleon/on_life(seconds_per_tick, times_fired)
/datum/mutation/chameleon/on_life(seconds_per_tick, times_fired)
/// SKYRAT EDIT BEGIN
if(HAS_TRAIT(owner, TRAIT_CHAMELEON_SKIN))
owner.alpha = max(owner.alpha - (12.5 * (GET_MUTATION_POWER(src)) * seconds_per_tick), 0)
/// SKYRAT EDIT END
//Upgraded mutation of the base variant, used for changelings. No instability and better power_coeff
/datum/mutation/human/chameleon/changeling
/datum/mutation/chameleon/changeling
instability = 0
power_coeff = 2.5
locked = TRUE
@@ -44,7 +44,7 @@
* - forced: Whether the movement was caused by a forceMove or moveToNullspace.
* - [old_locs][/list/atom]: The locations the host mob used to be in.
*/
/datum/mutation/human/chameleon/proc/on_move(atom/movable/source, atom/old_loc, move_dir, forced, list/atom/old_locs)
/datum/mutation/chameleon/proc/on_move(atom/movable/source, atom/old_loc, move_dir, forced, list/atom/old_locs)
SIGNAL_HANDLER
/// SKYRAT EDIT BEGIN
@@ -63,7 +63,7 @@
* - proximity: Whether the host mob can physically reach the thing that they clicked on.
* - [modifiers][/list]: The set of click modifiers associated with this attack chain call.
*/
/datum/mutation/human/chameleon/proc/on_attack_hand(mob/living/carbon/human/source, atom/target, proximity, list/modifiers)
/datum/mutation/chameleon/proc/on_attack_hand(mob/living/carbon/human/source, atom/target, proximity, list/modifiers)
SIGNAL_HANDLER
if(!proximity) //stops tk from breaking chameleon
@@ -76,7 +76,7 @@
owner.alpha = 255
/// SKYRAT EDIT END
/datum/mutation/human/chameleon/on_losing(mob/living/carbon/human/owner)
/datum/mutation/chameleon/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.alpha = 255
+2 -2
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/geladikinesis
/datum/mutation/geladikinesis
name = "Geladikinesis"
desc = "Allows the user to concentrate moisture and sub-zero forces into snow."
quality = POSITIVE
@@ -20,7 +20,7 @@
delete_old = FALSE
delete_on_failure = FALSE
/datum/mutation/human/cryokinesis
/datum/mutation/cryokinesis
name = "Cryokinesis"
desc = "Draws negative energy from the sub-zero void to freeze surrounding temperatures at subject's will."
quality = POSITIVE //upsides and downsides
+2 -2
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/farsight
/datum/mutation/farsight
name = "Farsight"
desc = "The subject's eyes are able to see further than normal."
quality = POSITIVE
@@ -9,7 +9,7 @@
power_coeff = 1
power_path = /datum/action/cooldown/spell/farsight
/datum/mutation/human/farsight/setup()
/datum/mutation/farsight/setup()
. = ..()
var/datum/action/cooldown/spell/farsight/to_modify = .
if(istype(to_modify))
+2 -2
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/firebreath
/datum/mutation/firebreath
name = "Fire Breath"
desc = "An ancient mutation that gives lizards breath of fire."
quality = POSITIVE
@@ -11,7 +11,7 @@
energy_coeff = 1
power_coeff = 1
/datum/mutation/human/firebreath/setup()
/datum/mutation/firebreath/setup()
. = ..()
var/datum/action/cooldown/spell/cone/staggered/fire_breath/to_modify = .
if(!istype(to_modify)) // null or invalid
+2 -2
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/cindikinesis
/datum/mutation/cindikinesis
name = "Cindikinesis"
desc = "Allows the user to concentrate nearby heat into a pile of ash. Wow. Very interesting."
quality = POSITIVE
@@ -21,7 +21,7 @@
delete_old = FALSE
delete_on_failure = FALSE
/datum/mutation/human/pyrokinesis
/datum/mutation/pyrokinesis
name = "Pyrokinesis"
desc = "Draws positive energy from the surroundings to heat surrounding temperatures at subject's will."
quality = POSITIVE
+20 -20
View File
@@ -1,5 +1,5 @@
//Hulk turns your skin green, makes you strong, and allows you to shrug off stun effect.
/datum/mutation/human/hulk
/datum/mutation/hulk
name = "Hulk"
desc = "A poorly understood genome that causes the holder's muscles to expand, inhibit speech and gives the person a bad skin condition."
quality = POSITIVE
@@ -9,7 +9,7 @@
species_allowed = list(SPECIES_HUMAN) //no skeleton/lizard hulk
health_req = 25
instability = POSITIVE_INSTABILITY_MAJOR
conflicts = list(/datum/mutation/human/hulk/ork)
conflicts = list(/datum/mutation/hulk/ork)
var/scream_delay = 50
var/last_scream = 0
var/bodypart_color = COLOR_DARK_LIME
@@ -21,14 +21,14 @@
TRAIT_STUNIMMUNE,
)
/datum/mutation/human/hulk/New(class, timer, datum/mutation/human/copymut)
/datum/mutation/hulk/New(datum/mutation/copymut)
. = ..()
add_speechmod()
/datum/mutation/human/hulk/proc/add_speechmod()
/datum/mutation/hulk/proc/add_speechmod()
AddComponent(/datum/component/speechmod, replacements = list("." = "!"), end_string = "!!", uppercase = TRUE)
/datum/mutation/human/hulk/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/hulk/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
@@ -40,7 +40,7 @@
RegisterSignal(owner, COMSIG_MOB_CLICKON, PROC_REF(check_swing))
owner.add_movespeed_mod_immunities("hulk", /datum/movespeed_modifier/damage_slowdown)
/datum/mutation/human/hulk/proc/on_attack_hand(mob/living/carbon/human/source, atom/target, proximity, modifiers)
/datum/mutation/hulk/proc/on_attack_hand(mob/living/carbon/human/source, atom/target, proximity, modifiers)
SIGNAL_HANDLER
if(!source.combat_mode || !proximity || LAZYACCESS(modifiers, RIGHT_CLICK))
@@ -58,7 +58,7 @@
source.changeNext_move(CLICK_CD_MELEE)
return COMPONENT_CANCEL_ATTACK_CHAIN
/datum/mutation/human/hulk/proc/scream_attack(mob/living/carbon/human/source)
/datum/mutation/hulk/proc/scream_attack(mob/living/carbon/human/source)
source.say("WAAAAAAAAAAAAAAGH!", forced="hulk")
/**
@@ -70,7 +70,7 @@
*Arguments:
*arg1 is the arm to evaluate damage of and possibly break.
*/
/datum/mutation/human/hulk/proc/break_an_arm(obj/item/bodypart/arm)
/datum/mutation/hulk/proc/break_an_arm(obj/item/bodypart/arm)
var/severity
switch(arm.brute_dam)
if(45 to 50)
@@ -85,13 +85,13 @@
owner.cause_wound_of_type_and_severity(WOUND_BLUNT, arm, severity, wound_source = "hulk smashing")
/datum/mutation/human/hulk/on_life(seconds_per_tick, times_fired)
/datum/mutation/hulk/on_life(seconds_per_tick, times_fired)
if(owner.health < owner.crit_threshold)
on_losing(owner)
to_chat(owner, span_danger("You suddenly feel very weak."))
qdel(src)
/datum/mutation/human/hulk/on_losing(mob/living/carbon/human/owner)
/datum/mutation/hulk/on_losing(mob/living/carbon/human/owner)
if(..())
return
for(var/obj/item/bodypart/part as anything in owner.bodyparts)
@@ -106,7 +106,7 @@
#define HULK_TAILTHROW_STEPS 28
/// Run a barrage of checks to see if any given click is actually able to swing
/datum/mutation/human/hulk/proc/check_swing(mob/living/carbon/human/user, atom/clicked_atom, list/modifiers)
/datum/mutation/hulk/proc/check_swing(mob/living/carbon/human/user, atom/clicked_atom, list/modifiers)
SIGNAL_HANDLER
/// Basically, we only proceed if we're in throw mode with a tailed carbon in our grasp with at least a neck grab and we're not restrained in some way
@@ -133,7 +133,7 @@
return(COMSIG_MOB_CANCEL_CLICKON)
/// Do a short 2 second do_after before starting the actual swing
/datum/mutation/human/hulk/proc/setup_swing(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person)
/datum/mutation/hulk/proc/setup_swing(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person)
var/original_dir = the_hulk.dir // so no matter if the hulk tries to mess up their direction, they always face where they started when they throw
yeeted_person.forceMove(the_hulk.loc)
@@ -167,7 +167,7 @@
* credit to: cogwerks, pistoleer, spyguy, angriestibm, marquesas, and stuntwaffle.
* For each step of the swinging, with the delay getting shorter along the way. Checks to see we still have them in our grasp at each step.
*/
/datum/mutation/human/hulk/proc/swing_loop(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person, step, original_dir)
/datum/mutation/hulk/proc/swing_loop(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person, step, original_dir)
if(!yeeted_person || !the_hulk || the_hulk.incapacitated)
return
if(get_dist(the_hulk, yeeted_person) > 1 || !isturf(the_hulk.loc) || !isturf(yeeted_person.loc))
@@ -238,7 +238,7 @@
addtimer(CALLBACK(src, PROC_REF(swing_loop), the_hulk, yeeted_person, step, original_dir), delay)
/// Time to toss the victim at high speed
/datum/mutation/human/hulk/proc/finish_swing(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person, original_dir)
/datum/mutation/hulk/proc/finish_swing(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person, original_dir)
if(!yeeted_person || !the_hulk || the_hulk.incapacitated)
return
if(get_dist(the_hulk, yeeted_person) > 1 || !isturf(the_hulk.loc) || !isturf(yeeted_person.loc))
@@ -259,7 +259,7 @@
yeeted_person.throw_at(T, 10, 6, the_hulk, TRUE, TRUE)
log_combat(the_hulk, yeeted_person, "has thrown by tail")
/datum/mutation/human/hulk/wizardly
/datum/mutation/hulk/wizardly
name = "Hulk (Magical)"
species_allowed = null //yes skeleton/lizard hulk - note that species that dont have skintone changing (like skellies) get custom handling
health_req = 0
@@ -272,7 +272,7 @@
TRAIT_STUNIMMUNE,
) // no chunk
/datum/mutation/human/hulk/superhuman
/datum/mutation/hulk/superhuman
name = "Hulk (Super)"
health_req = 0
instability = 0
@@ -287,17 +287,17 @@
TRAIT_ANALGESIA,
) // fight till your last breath
/datum/mutation/human/hulk/superhuman/on_life(seconds_per_tick, times_fired)
/datum/mutation/hulk/superhuman/on_life(seconds_per_tick, times_fired)
return
/datum/mutation/human/hulk/ork
/datum/mutation/hulk/ork
name = "Ork"
desc = "A mutation caused by a mixup of hulk genes which severely impacts speech centers in owners' brains."
text_gain_indication = span_notice("You feel significantly dumber!")
bodypart_color = COLOR_ASSISTANT_OLIVE
conflicts = list(/datum/mutation/human/hulk)
conflicts = list(/datum/mutation/hulk)
/datum/mutation/human/hulk/ork/add_speechmod()
/datum/mutation/hulk/ork/add_speechmod()
AddComponent(/datum/component/speechmod, replacements = strings("ork_replacement.json", "ork"), end_string = "!!", uppercase = TRUE)
#undef HULK_TAILTHROW_STEPS
+2 -2
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/olfaction
/datum/mutation/olfaction
name = "Transcendent Olfaction"
desc = "Your sense of smell is comparable to that of a canine."
quality = POSITIVE
@@ -9,7 +9,7 @@
instability = POSITIVE_INSTABILITY_MODERATE
synchronizer_coeff = 1
/datum/mutation/human/olfaction/setup()
/datum/mutation/olfaction/setup()
. = ..()
var/datum/action/cooldown/spell/olfaction/to_modify = .
if(!istype(to_modify)) // null or invalid
+6 -6
View File
@@ -1,20 +1,20 @@
/datum/mutation/human/biotechcompat
/datum/mutation/biotechcompat
name = "Biotech Compatibility"
desc = "Subject is more compatibile with biotechnology such as skillchips."
quality = POSITIVE
instability = POSITIVE_INSTABILITY_MINI
/datum/mutation/human/biotechcompat/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/biotechcompat/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
owner.adjust_skillchip_complexity_modifier(1)
/datum/mutation/human/biotechcompat/on_losing(mob/living/carbon/human/owner)
/datum/mutation/biotechcompat/on_losing(mob/living/carbon/human/owner)
owner.adjust_skillchip_complexity_modifier(-1)
return ..()
/datum/mutation/human/clever
/datum/mutation/clever
name = "Clever"
desc = "Causes the subject to feel just a little bit smarter. Most effective in specimens with low levels of intelligence."
quality = POSITIVE
@@ -22,13 +22,13 @@
text_gain_indication = span_danger("You feel a little bit smarter.")
text_lose_indication = span_danger("Your mind feels a little bit foggy.")
/datum/mutation/human/clever/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/clever/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
owner.add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_LITERATE), GENETIC_MUTATION)
/datum/mutation/human/clever/on_losing(mob/living/carbon/human/owner)
/datum/mutation/clever/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.remove_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_LITERATE), GENETIC_MUTATION)
+7 -7
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/radioactive
/datum/mutation/radioactive
name = "Radioactivity"
desc = "A volatile mutation that causes the host to sent out deadly beta radiation. This affects both the hosts and their surroundings."
quality = NEGATIVE
@@ -9,22 +9,22 @@
/// Weakref to our radiation emitter component
var/datum/weakref/radioactivity_source_ref
/datum/mutation/human/radioactive/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
/datum/mutation/radioactive/New(datum/mutation/copymut)
. = ..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "radiation", -MUTATIONS_LAYER))
/datum/mutation/human/radioactive/get_visual_indicator()
/datum/mutation/radioactive/get_visual_indicator()
return visual_indicators[type][1]
/datum/mutation/human/radioactive/on_acquiring(mob/living/carbon/human/acquirer)
/datum/mutation/radioactive/on_acquiring(mob/living/carbon/human/acquirer)
. = ..()
if(!.)
return
var/datum/component/radioactive_emitter/radioactivity_source = make_radioactive(acquirer)
radioactivity_source_ref = WEAKREF(radioactivity_source)
/datum/mutation/human/radioactive/setup()
/datum/mutation/radioactive/setup()
. = ..()
if(!QDELETED(owner))
make_radioactive(owner)
@@ -33,7 +33,7 @@
* Makes the passed mob radioactive, or if they're already radioactive,
* update their radioactivity to the newly set values
*/
/datum/mutation/human/radioactive/proc/make_radioactive(mob/living/carbon/human/who)
/datum/mutation/radioactive/proc/make_radioactive(mob/living/carbon/human/who)
return who.AddComponent(
/datum/component/radioactive_emitter, \
cooldown_time = 5 SECONDS, \
@@ -41,6 +41,6 @@
threshold = RAD_MEDIUM_INSULATION, \
)
/datum/mutation/human/radioactive/on_losing(mob/living/carbon/human/owner)
/datum/mutation/radioactive/on_losing(mob/living/carbon/human/owner)
QDEL_NULL(radioactivity_source_ref)
return ..()
+13 -12
View File
@@ -1,5 +1,5 @@
///Telekinesis lets you interact with objects from range, and gives you a light blue halo around your head.
/datum/mutation/human/telekinesis
/datum/mutation/telekinesis
name = "Telekinesis"
desc = "A strange mutation that allows the holder to interact with objects through thought."
quality = POSITIVE
@@ -10,27 +10,28 @@
///Typecache of atoms that TK shouldn't interact with
var/static/list/blacklisted_atoms = typecacheof(list(/atom/movable/screen))
/datum/mutation/human/telekinesis/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
/datum/mutation/telekinesis/New(datum/mutation/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('modular_skyrat/master_files/icons/effects/tele_effects.dmi', "telekinesishead", -MUTATIONS_LAYER)) // SKYRAT EDIT CHANGE - ORIGINAL: visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "telekinesishead", -MUTATIONS_LAYER))
/datum/mutation/human/telekinesis/on_acquiring(mob/living/carbon/human/homan)
/datum/mutation/telekinesis/on_acquiring(mob/living/carbon/human/homan)
. = ..()
if(!.)
return
RegisterSignal(homan, COMSIG_MOB_ATTACK_RANGED, PROC_REF(on_ranged_attack))
/datum/mutation/human/telekinesis/on_losing(mob/living/carbon/human/homan)
/datum/mutation/telekinesis/on_losing(mob/living/carbon/human/homan)
. = ..()
if(.)
return
UnregisterSignal(homan, COMSIG_MOB_ATTACK_RANGED)
/datum/mutation/human/telekinesis/get_visual_indicator()
/datum/mutation/telekinesis/get_visual_indicator()
return visual_indicators[type][1]
///Triggers on COMSIG_MOB_ATTACK_RANGED. Usually handles stuff like picking up items at range.
/datum/mutation/human/telekinesis/proc/on_ranged_attack(mob/source, atom/target)
/datum/mutation/telekinesis/proc/on_ranged_attack(mob/source, atom/target)
SIGNAL_HANDLER
if(is_type_in_typecache(target, blacklisted_atoms))
return
@@ -38,7 +39,7 @@
return
return target.attack_tk(source)
/datum/mutation/human/elastic_arms
/datum/mutation/elastic_arms
name = "Elastic Arms"
desc = "Subject's arms have become elastic, allowing them to stretch up to a meter away. However, this elasticity makes it difficult to wear gloves, handle complex tasks, or grab large objects."
quality = POSITIVE
@@ -48,7 +49,7 @@
difficulty = 32
mutation_traits = list(TRAIT_CHUNKYFINGERS, TRAIT_NO_TWOHANDING)
/datum/mutation/human/elastic_arms/on_acquiring(mob/living/carbon/human/homan)
/datum/mutation/elastic_arms/on_acquiring(mob/living/carbon/human/homan)
. = ..()
if(!.)
return
@@ -56,21 +57,21 @@
RegisterSignal(homan, COMSIG_LIVING_TRY_PUT_IN_HAND, PROC_REF(on_owner_equipping_item))
RegisterSignal(homan, COMSIG_LIVING_TRY_PULL, PROC_REF(on_owner_try_pull))
/datum/mutation/human/elastic_arms/on_losing(mob/living/carbon/human/homan)
/datum/mutation/elastic_arms/on_losing(mob/living/carbon/human/homan)
. = ..()
if(.)
return
UnregisterSignal(homan, list(COMSIG_ATOM_CANREACH, COMSIG_LIVING_TRY_PUT_IN_HAND, COMSIG_LIVING_TRY_PULL))
/// signal sent when prompting if an item can be equipped
/datum/mutation/human/elastic_arms/proc/on_owner_equipping_item(mob/living/carbon/human/owner, obj/item/pick_item)
/datum/mutation/elastic_arms/proc/on_owner_equipping_item(mob/living/carbon/human/owner, obj/item/pick_item)
SIGNAL_HANDLER
if((pick_item.w_class > WEIGHT_CLASS_BULKY) && !(pick_item.item_flags & ABSTRACT|HAND_ITEM)) // cant decide if i should limit to huge or bulky.
pick_item.balloon_alert(owner, "arms too floppy to wield!")
return COMPONENT_LIVING_CANT_PUT_IN_HAND
/// signal sent when owner tries to pull
/datum/mutation/human/elastic_arms/proc/on_owner_try_pull(mob/living/carbon/owner, atom/movable/target, force)
/datum/mutation/elastic_arms/proc/on_owner_try_pull(mob/living/carbon/owner, atom/movable/target, force)
SIGNAL_HANDLER
if(isliving(target))
var/mob/living/living_target = target
@@ -84,7 +85,7 @@
return COMSIG_LIVING_CANCEL_PULL
// probably buggy. let's enlist our players as bug testers
/datum/mutation/human/elastic_arms/proc/on_canreach(mob/source, atom/target)
/datum/mutation/elastic_arms/proc/on_canreach(mob/source, atom/target)
SIGNAL_HANDLER
var/distance = get_dist(target, source)
+21 -21
View File
@@ -1,43 +1,43 @@
//Nearsightedness restricts your vision by several tiles.
/datum/mutation/human/nearsight
/datum/mutation/nearsight
name = "Near Sightness"
desc = "The holder of this mutation has poor eyesight."
instability = NEGATIVE_STABILITY_MODERATE
quality = MINOR_NEGATIVE
text_gain_indication = span_danger("You can't see very well.")
/datum/mutation/human/nearsight/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/nearsight/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
owner.become_nearsighted(GENETIC_MUTATION)
/datum/mutation/human/nearsight/on_losing(mob/living/carbon/human/owner)
/datum/mutation/nearsight/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.cure_nearsighted(GENETIC_MUTATION)
///Blind makes you blind. Who knew?
/datum/mutation/human/blind
/datum/mutation/blind
name = "Blindness"
desc = "Renders the subject completely blind."
instability = NEGATIVE_STABILITY_MAJOR
quality = NEGATIVE
text_gain_indication = span_danger("You can't seem to see anything.")
/datum/mutation/human/blind/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/blind/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
owner.become_blind(GENETIC_MUTATION)
/datum/mutation/human/blind/on_losing(mob/living/carbon/human/owner)
/datum/mutation/blind/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.cure_blind(GENETIC_MUTATION)
///Thermal Vision lets you see mobs through walls
/datum/mutation/human/thermal
/datum/mutation/thermal
name = "Thermal Vision"
desc = "The user of this genome can visually perceive the unique human thermal signature."
quality = POSITIVE
@@ -50,7 +50,7 @@
energy_coeff = 1
power_path = /datum/action/cooldown/spell/thermal_vision
/datum/mutation/human/thermal/on_losing(mob/living/carbon/human/owner)
/datum/mutation/thermal/on_losing(mob/living/carbon/human/owner)
if(..())
return
@@ -59,7 +59,7 @@
REMOVE_TRAIT(owner, TRAIT_THERMAL_VISION, GENETIC_MUTATION)
owner.update_sight()
/datum/mutation/human/thermal/setup()
/datum/mutation/thermal/setup()
. = ..()
var/datum/action/cooldown/spell/thermal_vision/to_modify = .
if(!istype(to_modify)) // null or invalid
@@ -110,21 +110,21 @@
carbon_cast_on.adjustOrganLoss(ORGAN_SLOT_EYES, eye_damage)
///X-ray Vision lets you see through walls.
/datum/mutation/human/xray
/datum/mutation/xray
name = "X Ray Vision"
desc = "A strange genome that allows the user to see between the spaces of walls." //actual x-ray would mean you'd constantly be blasting rads, which might be fun for later //hmb
text_gain_indication = span_notice("The walls suddenly disappear!")
instability = POSITIVE_INSTABILITY_MAJOR
locked = TRUE
/datum/mutation/human/xray/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/xray/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_XRAY_VISION, GENETIC_MUTATION)
owner.update_sight()
/datum/mutation/human/xray/on_losing(mob/living/carbon/human/owner)
/datum/mutation/xray/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_XRAY_VISION, GENETIC_MUTATION)
@@ -132,7 +132,7 @@
///Laser Eyes lets you shoot lasers from your eyes!
/datum/mutation/human/laser_eyes
/datum/mutation/laser_eyes
name = "Laser Eyes"
desc = "Reflects concentrated light back from the eyes."
quality = POSITIVE
@@ -142,28 +142,28 @@
layer_used = FRONT_MUTATIONS_LAYER
limb_req = BODY_ZONE_HEAD
/datum/mutation/human/laser_eyes/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
/datum/mutation/laser_eyes/New(datum/mutation/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "lasereyes", -FRONT_MUTATIONS_LAYER))
/datum/mutation/human/laser_eyes/on_acquiring(mob/living/carbon/human/H)
/datum/mutation/laser_eyes/on_acquiring(mob/living/carbon/human/H)
. = ..()
if(!.)
return
RegisterSignal(H, COMSIG_MOB_ATTACK_RANGED, PROC_REF(on_ranged_attack))
/datum/mutation/human/laser_eyes/on_losing(mob/living/carbon/human/H)
/datum/mutation/laser_eyes/on_losing(mob/living/carbon/human/H)
. = ..()
if(.)
return
UnregisterSignal(H, COMSIG_MOB_ATTACK_RANGED)
/datum/mutation/human/laser_eyes/get_visual_indicator()
/datum/mutation/laser_eyes/get_visual_indicator()
return visual_indicators[type][1]
///Triggers on COMSIG_MOB_ATTACK_RANGED. Does the projectile shooting.
/datum/mutation/human/laser_eyes/proc/on_ranged_attack(mob/living/carbon/human/source, atom/target, modifiers)
/datum/mutation/laser_eyes/proc/on_ranged_attack(mob/living/carbon/human/source, atom/target, modifiers)
SIGNAL_HANDLER
if(!source.combat_mode)
@@ -184,7 +184,7 @@
icon = 'icons/mob/effects/genetics.dmi'
icon_state = "eyelasers"
/datum/mutation/human/illiterate
/datum/mutation/illiterate
name = "Illiterate"
desc = "Causes a severe case of Aphasia that prevents reading or writing."
instability = NEGATIVE_STABILITY_MAJOR
@@ -192,13 +192,13 @@
text_gain_indication = span_danger("You feel unable to read or write.")
text_lose_indication = span_danger("You feel able to read and write again.")
/datum/mutation/human/illiterate/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/illiterate/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_ILLITERATE, GENETIC_MUTATION)
/datum/mutation/human/illiterate/on_losing(mob/living/carbon/human/owner)
/datum/mutation/illiterate/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_ILLITERATE, GENETIC_MUTATION)
+35 -35
View File
@@ -3,18 +3,18 @@
// no they arent bro
/datum/mutation/human/nervousness
/datum/mutation/nervousness
name = "Nervousness"
desc = "Causes the holder to stutter."
instability = NEGATIVE_STABILITY_MINI
quality = MINOR_NEGATIVE
text_gain_indication = span_danger("You feel nervous.")
/datum/mutation/human/nervousness/on_life(seconds_per_tick, times_fired)
/datum/mutation/nervousness/on_life(seconds_per_tick, times_fired)
if(SPT_PROB(5, seconds_per_tick))
owner.set_stutter_if_lower(20 SECONDS)
/datum/mutation/human/wacky
/datum/mutation/wacky
name = "Wacky"
desc = "You are not a clown. You are the entire circus."
instability = NEGATIVE_STABILITY_MINI
@@ -22,23 +22,23 @@
text_gain_indication = span_sans(span_notice("You feel an off sensation in your voicebox."))
text_lose_indication = span_notice("The off sensation passes.")
/datum/mutation/human/wacky/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/wacky/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(handle_speech))
/datum/mutation/human/wacky/on_losing(mob/living/carbon/human/owner)
/datum/mutation/wacky/on_losing(mob/living/carbon/human/owner)
if(..())
return
UnregisterSignal(owner, COMSIG_MOB_SAY)
/datum/mutation/human/wacky/proc/handle_speech(datum/source, list/speech_args)
/datum/mutation/wacky/proc/handle_speech(datum/source, list/speech_args)
SIGNAL_HANDLER
speech_args[SPEECH_SPANS] |= SPAN_SANS
/datum/mutation/human/heckacious
/datum/mutation/heckacious
name = "heckacious larincks"
desc = "duge what is WISH your words man..........."
quality = MINOR_NEGATIVE
@@ -46,23 +46,23 @@
text_lose_indication = span_notice("The demonic entity possessing your larynx has finally released its grasp.")
locked = TRUE
/datum/mutation/human/heckacious/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/heckacious/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
RegisterSignal(owner, COMSIG_LIVING_TREAT_MESSAGE, PROC_REF(handle_caps))
RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(handle_speech))
/datum/mutation/human/heckacious/on_losing(mob/living/carbon/human/owner)
/datum/mutation/heckacious/on_losing(mob/living/carbon/human/owner)
if(..())
return
UnregisterSignal(owner, list(COMSIG_LIVING_TREAT_MESSAGE, COMSIG_MOB_SAY))
/datum/mutation/human/heckacious/proc/handle_caps(atom/movable/source, list/message_args)
/datum/mutation/heckacious/proc/handle_caps(atom/movable/source, list/message_args)
SIGNAL_HANDLER
message_args[TREAT_CAPITALIZE_MESSAGE] = FALSE
/datum/mutation/human/heckacious/proc/handle_speech(datum/source, list/speech_args)
/datum/mutation/heckacious/proc/handle_speech(datum/source, list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
if(!message)
@@ -133,7 +133,7 @@
speech_args[SPEECH_MESSAGE] = message
/datum/mutation/human/mute
/datum/mutation/mute
name = "Mute"
desc = "Completely inhibits the vocal section of the brain."
instability = NEGATIVE_STABILITY_MAJOR
@@ -141,18 +141,18 @@
text_gain_indication = span_danger("You feel unable to express yourself at all.")
text_lose_indication = span_danger("You feel able to speak freely again.")
/datum/mutation/human/mute/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/mute/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_MUTE, GENETIC_MUTATION)
/datum/mutation/human/mute/on_losing(mob/living/carbon/human/owner)
/datum/mutation/mute/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_MUTE, GENETIC_MUTATION)
/datum/mutation/human/unintelligible
/datum/mutation/unintelligible
name = "Unintelligible"
desc = "Partially inhibits the vocal center of the brain, severely distorting speech."
instability = NEGATIVE_STABILITY_MODERATE
@@ -160,18 +160,18 @@
text_gain_indication = span_danger("You can't seem to form any coherent thoughts!")
text_lose_indication = span_danger("Your mind feels more clear.")
/datum/mutation/human/unintelligible/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/unintelligible/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_UNINTELLIGIBLE_SPEECH, GENETIC_MUTATION)
/datum/mutation/human/unintelligible/on_losing(mob/living/carbon/human/owner)
/datum/mutation/unintelligible/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_UNINTELLIGIBLE_SPEECH, GENETIC_MUTATION)
/datum/mutation/human/swedish
/datum/mutation/swedish
name = "Swedish"
desc = "A horrible mutation originating from the distant past. Thought to be eradicated after the incident in 2037."
instability = NEGATIVE_STABILITY_MINI
@@ -180,11 +180,11 @@
text_lose_indication = span_notice("The feeling of Swedishness passes.")
var/static/list/language_mutilation = list("w" = "v", "j" = "y", "bo" = "bjo", "a" = list("å","ä","æ","a"), "o" = list("ö","ø","o"))
/datum/mutation/human/swedish/New(class, timer, datum/mutation/human/copymut)
/datum/mutation/swedish/New(datum/mutation/copymut)
. = ..()
AddComponent(/datum/component/speechmod, replacements = language_mutilation, end_string = list("",", bork",", bork, bork"), end_string_chance = 30)
/datum/mutation/human/chav
/datum/mutation/chav
name = "Chav"
desc = "Unknown"
instability = NEGATIVE_STABILITY_MINI
@@ -192,11 +192,11 @@
text_gain_indication = span_notice("Ye feel like a reet prat like, innit?")
text_lose_indication = span_notice("You no longer feel like being rude and sassy.")
/datum/mutation/human/chav/New(class, timer, datum/mutation/human/copymut)
/datum/mutation/chav/New(datum/mutation/copymut)
. = ..()
AddComponent(/datum/component/speechmod, replacements = strings("chav_replacement.json", "chav"), end_string = ", mate", end_string_chance = 30)
/datum/mutation/human/elvis
/datum/mutation/elvis
name = "Elvis"
desc = "A terrifying mutation named after its 'patient-zero'."
instability = NEGATIVE_STABILITY_MINI
@@ -204,11 +204,11 @@
text_gain_indication = span_notice("You feel pretty good, honeydoll.")
text_lose_indication = span_notice("You feel a little less conversation would be great.")
/datum/mutation/human/chav/New(class, timer, datum/mutation/human/copymut)
/datum/mutation/chav/New(datum/mutation/copymut)
. = ..()
AddComponent(/datum/component/speechmod, replacements = strings("elvis_replacement.json", "elvis"))
/datum/mutation/human/elvis/on_life(seconds_per_tick, times_fired)
/datum/mutation/elvis/on_life(seconds_per_tick, times_fired)
switch(pick(1,2))
if(1)
if(SPT_PROB(7.5, seconds_per_tick))
@@ -219,26 +219,26 @@
if(SPT_PROB(7.5, seconds_per_tick))
owner.visible_message("<b>[owner]</b> [pick("jiggles their hips", "rotates their hips", "gyrates their hips", "taps their foot", "dances to an imaginary song", "jiggles their legs", "snaps their fingers")]!")
/datum/mutation/human/stoner
/datum/mutation/stoner
name = "Stoner"
desc = "A common mutation that severely decreases intelligence."
quality = NEGATIVE
text_gain_indication = span_notice("You feel...totally chill, man!")
text_lose_indication = span_notice("You feel like you have a better sense of time.")
/datum/mutation/human/stoner/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/stoner/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
owner.grant_language(/datum/language/beachbum, source = LANGUAGE_STONER)
owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)
/datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner)
/datum/mutation/stoner/on_losing(mob/living/carbon/human/owner)
..()
owner.remove_language(/datum/language/beachbum, source = LANGUAGE_STONER)
owner.remove_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)
/datum/mutation/human/medieval
/datum/mutation/medieval
name = "Medieval"
desc = "A horrible mutation originating from the distant past, thought to have once been a common gene in all of old world Europe."
instability = NEGATIVE_STABILITY_MINI
@@ -246,18 +246,18 @@
text_gain_indication = span_notice("You feel like seeking the holy grail!")
text_lose_indication = span_notice("You no longer feel like seeking anything.")
/datum/mutation/human/medieval/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/medieval/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(handle_speech))
/datum/mutation/human/medieval/on_losing(mob/living/carbon/human/owner)
/datum/mutation/medieval/on_losing(mob/living/carbon/human/owner)
if(..())
return
UnregisterSignal(owner, COMSIG_MOB_SAY)
/datum/mutation/human/medieval/proc/handle_speech(datum/source, list/speech_args)
/datum/mutation/medieval/proc/handle_speech(datum/source, list/speech_args)
SIGNAL_HANDLER
var/message = speech_args[SPEECH_MESSAGE]
@@ -280,7 +280,7 @@
speech_args[SPEECH_MESSAGE] = message
/datum/mutation/human/piglatin
/datum/mutation/piglatin
name = "Pig Latin"
desc = "Historians say back in the 2020's humanity spoke entirely in this mystical language."
instability = NEGATIVE_STABILITY_MINI
@@ -288,18 +288,18 @@
text_gain_indication = span_notice("Omethingsay eelsfay offyay.")
text_lose_indication = span_notice("The off sensation passes.")
/datum/mutation/human/piglatin/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/piglatin/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(handle_speech))
/datum/mutation/human/piglatin/on_losing(mob/living/carbon/human/owner)
/datum/mutation/piglatin/on_losing(mob/living/carbon/human/owner)
if(..())
return
UnregisterSignal(owner, COMSIG_MOB_SAY)
/datum/mutation/human/piglatin/proc/handle_speech(datum/source, list/speech_args)
/datum/mutation/piglatin/proc/handle_speech(datum/source, list/speech_args)
SIGNAL_HANDLER
var/spoken_message = speech_args[SPEECH_MESSAGE]
+1 -1
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/telepathy
/datum/mutation/telepathy
name = "Telepathy"
desc = "A rare mutation that allows the user to telepathically communicate to others."
quality = POSITIVE
+2 -2
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/tongue_spike
/datum/mutation/tongue_spike
name = "Tongue Spike"
desc = "Allows a creature to voluntary shoot their tongue out as a deadly weapon."
quality = POSITIVE
@@ -87,7 +87,7 @@
if (!QDELETED(tongue_spike)) // This can cause a qdel loop
tongue_spike.morph_back()
/datum/mutation/human/tongue_spike/chem
/datum/mutation/tongue_spike/chem
name = "Chem Spike"
desc = "Allows a creature to voluntary shoot their tongue out as biomass, allowing a long range transfer of chemicals."
quality = POSITIVE
+4 -4
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/shock
/datum/mutation/shock
name = "Shock Touch"
desc = "The affected can channel excess electricity through their hands without shocking themselves, allowing them to shock others. Mostly harmless! Mostly... "
quality = POSITIVE
@@ -11,7 +11,7 @@
energy_coeff = 1
power_coeff = 1
/datum/mutation/human/shock/setup()
/datum/mutation/shock/setup()
. = ..()
var/datum/action/cooldown/spell/touch/shock/to_modify =.
@@ -82,7 +82,7 @@
icon_state = "zapper"
inhand_icon_state = "zapper"
/datum/mutation/human/lay_on_hands
/datum/mutation/lay_on_hands
name = "Mending Touch"
desc = "The affected can lay their hands on other people to transfer a small amount of their injuries to themselves."
quality = POSITIVE
@@ -96,7 +96,7 @@
power_coeff = 1
synchronizer_coeff = 1
/datum/mutation/human/lay_on_hands/setup()
/datum/mutation/lay_on_hands/setup()
. = ..()
var/datum/action/cooldown/spell/touch/lay_on_hands/to_modify =.
+2 -2
View File
@@ -1,4 +1,4 @@
/datum/mutation/human/void
/datum/mutation/void
name = "Void Magnet"
desc = "A rare genome that attracts odd forces not usually observed."
quality = MINOR_NEGATIVE //upsides and downsides
@@ -8,7 +8,7 @@
energy_coeff = 1
synchronizer_coeff = 1
/datum/mutation/human/void/setup()
/datum/mutation/void/setup()
. = ..()
var/datum/action/cooldown/spell/void/cursed/to_modify = .
if(!istype(to_modify)) // null or invalid
+4 -4
View File
@@ -1,5 +1,5 @@
//spider webs
/datum/mutation/human/webbing
/datum/mutation/webbing
name = "Webbing Production"
desc = "Allows the user to lay webbing, and travel through it."
quality = POSITIVE
@@ -8,7 +8,7 @@
power_path = /datum/action/cooldown/mob_cooldown/lay_web/genetic
energy_coeff = 1
/datum/mutation/human/webbing/setup()
/datum/mutation/webbing/setup()
. = ..()
var/datum/action/cooldown/mob_cooldown/lay_web/genetic/to_modify = .
@@ -20,13 +20,13 @@
return
to_modify.webbing_time = 2 SECONDS // Spin webs faster but not more often
/datum/mutation/human/webbing/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/webbing/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_WEB_WEAVER, GENETIC_MUTATION)
/datum/mutation/human/webbing/on_losing(mob/living/carbon/human/owner)
/datum/mutation/webbing/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_WEB_WEAVER, GENETIC_MUTATION)
@@ -34,7 +34,7 @@
transforming.dna.copy_dna(old_dna)
// Makes them into the new DNA
transforming.visual_only_organs = TRUE // SKYRAT EDIT ADDITION - Customization
new_dna.transfer_identity(transforming)
new_dna.copy_dna(transforming.dna, COPY_DNA_SPECIES)
transforming.visual_only_organs = initial(transforming.visual_only_organs) // SKYRAT EDIT ADDITION - Customization
transforming.real_name = new_dna.real_name
transforming.name = transforming.get_visible_name()
@@ -47,7 +47,7 @@
if(!QDELING(owner)) // Don't really need to do appearance stuff if we're being deleted
transforming.visual_only_organs = TRUE // SKYRAT EDIT ADDITION - Customization
old_dna.transfer_identity(transforming)
old_dna.copy_dna(transforming.dna, COPY_DNA_SPECIES)
transforming.visual_only_organs = initial(transforming.visual_only_organs) // SKYRAT EDIT ADDITION - Customization
transforming.updateappearance(mutcolor_update = TRUE)
transforming.domutcheck()