ports hyper's genetics

This commit is contained in:
Seris02
2019-12-28 21:33:15 +08:00
parent d562a5ba27
commit 862acf2f06
63 changed files with 1931 additions and 483 deletions

View File

@@ -277,7 +277,6 @@
L.fields["sex"] = H.gender
L.fields["blood_type"] = H.dna.blood_type
L.fields["b_dna"] = H.dna.unique_enzymes
L.fields["enzymes"] = H.dna.struc_enzymes
L.fields["identity"] = H.dna.uni_identity
L.fields["species"] = H.dna.species.type
L.fields["features"] = H.dna.features

View File

@@ -58,12 +58,12 @@ Bonus
symptom_delay_max = 60
if(A.properties["resistance"] >= 8) //mutate twice
power = 2
possible_mutations = (GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.mutations_list[RACEMUT]
possible_mutations = (GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.all_mutations[RACEMUT]
var/mob/living/carbon/M = A.affected_mob
if(M)
if(!M.has_dna())
return
archived_dna = M.dna.struc_enzymes
archived_dna = M.dna.mutation_index
// Give them back their old DNA when cured.
/datum/symptom/genetic_mutation/End(datum/disease/advance/A)
@@ -74,5 +74,5 @@ Bonus
if(M && archived_dna)
if(!M.has_dna())
return
M.dna.struc_enzymes = archived_dna
M.dna.mutation_index = archived_dna
M.domutcheck()

View File

@@ -2,7 +2,6 @@
/////////////////////////// DNA DATUM
/datum/dna
var/unique_enzymes
var/struc_enzymes
var/uni_identity
var/blood_type
var/datum/species/species = new /datum/species/human //The type of mutant race the player is if applicable (i.e. potato-man)
@@ -11,10 +10,13 @@
var/nameless = FALSE
var/custom_species //siiiiigh I guess this is important
var/list/mutations = list() //All mutations are from now on here
var/list/temporary_mutations = list() //Timers for temporary mutations
var/list/temporary_mutations = list() //Temporary changes to the UE
var/list/previous = list() //For temporary name/ui/ue/blood_type modifications
var/mob/living/holder
var/delete_species = TRUE //Set to FALSE when a body is scanned by a cloner to fix #38875
var/mutation_index[DNA_MUTATION_BLOCKS] //List of which mutations this carbon has and its assigned block
var/stability = 100
var/scrambled = FALSE //Did we take something like mutagen? In that case we cant get our genes scanned to instantly cheese all the powers.
/datum/dna/New(mob/living/new_holder)
if(istype(new_holder))
@@ -42,8 +44,8 @@
destination.dna.unique_enzymes = unique_enzymes
destination.dna.uni_identity = uni_identity
destination.dna.blood_type = blood_type
destination.dna.features = features.Copy()
destination.set_species(species.type, icon_update=0)
destination.dna.features = features.Copy()
destination.dna.real_name = real_name
destination.dna.nameless = nameless
destination.dna.custom_species = custom_species
@@ -53,11 +55,11 @@
H.give_genitals(TRUE)//This gives the body the genitals of this DNA. Used for any transformations based on DNA
destination.flavor_text = destination.dna.features["flavor_text"] //Update the flavor_text to use new dna text
if(transfer_SE)
destination.dna.struc_enzymes = struc_enzymes
destination.dna.mutation_index = mutation_index
/datum/dna/proc/copy_dna(datum/dna/new_dna)
new_dna.unique_enzymes = unique_enzymes
new_dna.struc_enzymes = struc_enzymes
new_dna.mutation_index = mutation_index
new_dna.uni_identity = uni_identity
new_dna.blood_type = blood_type
new_dna.features = features.Copy()
@@ -67,26 +69,32 @@
new_dna.custom_species = custom_species
new_dna.mutations = mutations.Copy()
/datum/dna/proc/add_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_acquiring(holder)
//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
return force_give(new mutation_type (class, time, copymut = mutation))
/datum/dna/proc/remove_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_losing(holder)
/datum/dna/proc/remove_mutation(mutation_type)
return force_lose(get_mutation(mutation_type))
/datum/dna/proc/check_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
return mutations.Find(HM)
/datum/dna/proc/check_mutation(mutation_type)
return get_mutation(mutation_type)
/datum/dna/proc/remove_all_mutations()
remove_mutation_group(mutations)
/datum/dna/proc/remove_all_mutations(list/classes = list(MUT_NORMAL, MUT_EXTRA, MUT_OTHER), mutadone = FALSE)
remove_mutation_group(mutations, classes, mutadone)
scrambled = FALSE
/datum/dna/proc/remove_mutation_group(list/group)
/datum/dna/proc/remove_mutation_group(list/group, list/classes = list(MUT_NORMAL, MUT_EXTRA, MUT_OTHER), mutadone = FALSE)
if(!group)
return
for(var/datum/mutation/human/HM in group)
HM.force_lose(holder)
if((HM.class in classes) && !(HM.mutadone_proof && mutadone))
force_lose(HM)
/datum/dna/proc/generate_uni_identity()
. = ""
@@ -128,19 +136,49 @@
. += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
return .
/datum/dna/proc/generate_struc_enzymes()
var/list/sorting = new /list(DNA_STRUC_ENZYMES_BLOCKS)
var/result = ""
for(var/datum/mutation/human/A in GLOB.good_mutations + GLOB.bad_mutations + GLOB.not_good_mutations)
if(A.name == RACEMUT && ismonkey(holder))
sorting[A.dna_block] = num2hex(A.lowest_value + rand(0, 256 * 6), DNA_BLOCK_SIZE)
mutations |= A
else
sorting[A.dna_block] = random_string(DNA_BLOCK_SIZE, list("0","1","2","3","4","5","6"))
/datum/dna/proc/generate_dna_blocks()
var/bonus
if(species && species.inert_mutation)
bonus = GET_INITIALIZED_MUTATION(species.inert_mutation)
var/list/mutations_temp = GLOB.good_mutations + GLOB.bad_mutations + GLOB.not_good_mutations + bonus
if(!LAZYLEN(mutations_temp))
return
mutation_index.Cut()
shuffle_inplace(mutations_temp)
if(ismonkey(holder))
mutations |= new RACEMUT(MUT_NORMAL)
mutation_index[RACEMUT] = GET_SEQUENCE(RACEMUT)
else
mutation_index[RACEMUT] = create_sequence(RACEMUT, FALSE)
for(var/i in 2 to DNA_MUTATION_BLOCKS)
var/datum/mutation/human/M = mutations_temp[i]
mutation_index[M.type] = create_sequence(M.type, FALSE,M.difficulty)
shuffle_inplace(mutation_index)
for(var/B in sorting)
result += B
return result
//Used to generate original gene sequences for every mutation
/proc/generate_gene_sequence(length=4)
var/static/list/active_sequences = list("AT","TA","GC","CG")
var/sequence
for(var/i in 1 to length*DNA_SEQUENCE_LENGTH)
sequence += pick(active_sequences)
return sequence
//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
if(!A)
return
difficulty = A.difficulty
difficulty += rand(-2,4)
var/sequence = GET_SEQUENCE(mutation)
if(active)
return sequence
while(difficulty)
var/randnum = rand(1, length(sequence))
sequence = copytext(sequence, 1, randnum) + "X" + copytext(sequence, randnum+1, length(sequence)+1)
difficulty--
return sequence
/datum/dna/proc/generate_unique_enzymes()
. = ""
@@ -185,12 +223,57 @@
if(DNA_TAUR_BLOCK)
construct_block(GLOB.taur_list.Find(features["taur"]), GLOB.taur_list.len)
//Please use add_mutation or activate_mutation instead
/datum/dna/proc/force_give(datum/mutation/human/HM)
if(holder && HM)
if(HM.class == MUT_NORMAL)
set_se(1, HM)
. = HM.on_acquiring(holder)
if(.)
qdel(HM)
update_instability()
//Use remove_mutation instead
/datum/dna/proc/force_lose(datum/mutation/human/HM)
if(holder && (HM in mutations))
set_se(0, HM)
. = HM.on_losing(holder)
update_instability(FALSE)
return
/datum/dna/proc/is_same_as(datum/dna/D)
if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name && nameless == D.nameless && custom_species == D.custom_species)
if(uni_identity == D.uni_identity && mutation_index == D.mutation_index && real_name == D.real_name && nameless == D.nameless && custom_species == D.custom_species)
if(species.type == D.species.type && features == D.features && blood_type == D.blood_type)
return 1
return 0
/datum/dna/proc/update_instability(alert=TRUE)
stability = 100
for(var/datum/mutation/human/M in mutations)
if(M.class == MUT_EXTRA)
stability -= M.instability * GET_MUTATION_STABILIZER(M)
if(holder)
var/message
if(alert)
switch(stability)
if(70 to 90)
message = "<span class='warning'>You shiver.</span>"
if(60 to 69)
message = "<span class='warning'>You feel cold.</span>"
if(40 to 59)
message = "<span class='warning'>You feel sick.</span>"
if(20 to 39)
message = "<span class='warning'>It feels like your skin is moving.</span>"
if(1 to 19)
message = "<span class='warning'>You can feel your cells burning.</span>"
if(-INFINITY to 0)
message = "<span class='boldwarning'>You can feel your DNA exploding, we need to do something fast!</span>"
if(stability <= 0)
holder.apply_status_effect(STATUS_EFFECT_DNA_MELT)
if(message)
to_chat(holder, message)
//used to update dna UI, UE, and dna.real_name.
/datum/dna/proc/update_dna_identity()
uni_identity = generate_uni_identity()
@@ -201,7 +284,7 @@
blood_type = newblood_type
unique_enzymes = generate_unique_enzymes()
uni_identity = generate_uni_identity()
struc_enzymes = generate_struc_enzymes()
generate_dna_blocks()
features = random_features()
@@ -254,6 +337,7 @@
if(icon_update)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()// no lizard with human hulk overlay please.
@@ -264,7 +348,7 @@
return dna
/mob/living/carbon/human/proc/hardset_dna(ui, se, newreal_name, newblood_type, datum/species/mrace, newfeatures)
/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, newreal_name, newblood_type, datum/species/mrace, newfeatures)
if(newfeatures)
dna.features = newfeatures
@@ -286,8 +370,8 @@
dna.uni_identity = ui
updateappearance(icon_update=0)
if(se)
dna.struc_enzymes = se
if(LAZYLEN(mutation_index))
dna.mutation_index = mutation_index.Copy()
domutcheck()
if(mrace || newfeatures || ui)
@@ -330,19 +414,63 @@
/mob/proc/domutcheck()
return
/mob/living/carbon/domutcheck(force_powers=0) //Set force_powers to 1 to bypass the power chance
/mob/living/carbon/domutcheck()
if(!has_dna())
return
for(var/datum/mutation/human/A in GLOB.good_mutations | GLOB.bad_mutations | GLOB.not_good_mutations)
if(ismob(A.check_block(src, force_powers)))
for(var/mutation in dna.mutation_index)
if(ismob(dna.check_block(mutation)))
return //we got monkeyized/humanized, this mob will be deleted, no need to continue.
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)
return
return force_lose(HM)
//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(HM.type == A)
return HM
/datum/dna/proc/check_block_string(mutation)
if((LAZYLEN(mutation_index) > DNA_MUTATION_BLOCKS) || !(mutation in mutation_index))
return 0
return is_gene_active(mutation)
/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)
if(!HM || !(HM.type in mutation_index) || (LAZYLEN(mutation_index) < DNA_MUTATION_BLOCKS))
return
. = TRUE
if(on)
mutation_index[HM.type] = GET_SEQUENCE(HM.type)
else if(GET_SEQUENCE(HM.type) == mutation_index[HM.type])
mutation_index[HM.type] = create_sequence(HM.type, FALSE, HM.difficulty)
/datum/dna/proc/activate_mutation(mutation) //note that this returns a boolean and not a new mob
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(!mutation_in_sequence(mutation_type)) //cant activate what we dont have, use add_mutation
return FALSE
add_mutation(mutation, MUT_NORMAL)
return TRUE
/////////////////////////// DNA HELPER-PROCS //////////////////////////////
/proc/getleftblocks(input,blocknumber,blocksize)
if(blocknumber > 1)
return copytext(input,1,((blocksize*blocknumber)-(blocksize-1)))
@@ -359,29 +487,47 @@
return 0
return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize)
/datum/dna/proc/mutation_in_sequence(mutation)
if(!mutation)
return
if(istype(mutation, /datum/mutation/human))
var/datum/mutation/human/HM = mutation
if(HM.type in mutation_index)
return TRUE
else if(mutation in mutation_index)
return TRUE
/mob/living/carbon/proc/randmut(list/candidates, difficulty = 2)
if(!has_dna())
return
var/datum/mutation/human/num = pick(candidates)
. = num.force_give(src)
var/mutation = pick(candidates)
. = dna.add_mutation(mutation)
/mob/living/carbon/proc/randmutb()
/mob/living/carbon/proc/easy_randmut(quality = POSITIVE + NEGATIVE + MINOR_NEGATIVE, scrambled = TRUE, sequence = TRUE, exclude_monkey = TRUE)
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.mutations_list[RACEMUT])
. = HM.force_give(src)
var/list/mutations = list()
if(quality & POSITIVE)
mutations += GLOB.good_mutations
if(quality & NEGATIVE)
mutations += GLOB.bad_mutations
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(RACEMUT)
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
return TRUE
/mob/living/carbon/proc/randmutg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick(GLOB.good_mutations)
. = HM.force_give(src)
/mob/living/carbon/proc/randmutvg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.good_mutations) - GLOB.mutations_list[HULK] - GLOB.mutations_list[DWARFISM])
. = HM.force_give(src)
/mob/living/carbon/proc/randmuti()
if(!has_dna())
@@ -404,9 +550,9 @@
if(!M.has_dna())
return 0
if(se)
for(var/i=1, i<=DNA_STRUC_ENZYMES_BLOCKS, i++)
for(var/i=1, i<=DNA_MUTATION_BLOCKS, i++)
if(prob(probability))
M.dna.struc_enzymes = setblock(M.dna.struc_enzymes, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
M.dna.generate_dna_blocks()
M.domutcheck()
if(ui)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
@@ -433,3 +579,41 @@
return value
/////////////////////////// DNA HELPER-PROCS
/mob/living/carbon/human/proc/something_horrible()
if(!has_dna()) //shouldn't ever happen anyway so it's just in really weird cases
return
if(dna.stability > 0)
return
var/instability = -dna.stability
dna.remove_all_mutations()
dna.stability = 100
if(prob(max(70-instability,0)))
switch(rand(0,3)) //not complete and utter death
if(0)
monkeyize()
if(1)
gain_trauma(/datum/brain_trauma/severe/paralysis)
if(2)
corgize()
if(3)
to_chat(src, "<span class='notice'>Oh, we actually feel quite alright!</span>")
else
switch(rand(0,3))
if(0)
gib()
if(1)
dust()
if(2)
death()
petrify(INFINITY)
if(3)
if(prob(90))
var/obj/item/bodypart/BP = get_bodypart(pick(BODY_ZONE_CHEST,BODY_ZONE_HEAD))
if(BP)
BP.dismember()
else
gib()
else
set_species(/datum/species/dullahan)

View File

@@ -1,58 +1,55 @@
GLOBAL_LIST_EMPTY(mutations_list)
/datum/mutation
var/name
/datum/mutation/New()
GLOB.mutations_list[name] = src
/datum/mutation/human
var/dna_block
name = "mutation"
var/desc = "A mutation."
var/locked
var/quality
var/get_chance = 100
var/lowest_value = 256 * 8
var/text_gain_indication = ""
var/text_lose_indication = ""
var/list/mutable_appearance/visual_indicators = list()
var/obj/effect/proc_holder/spell/power
var/layer_used = MUTATIONS_LAYER //which mutation layer to use
var/list/species_allowed = list() //to restrict mutation to only certain species
var/health_req //minimum health required to acquire the mutation
var/limb_req //required limbs to acquire this mutation
var/time_coeff = 1 //coefficient for timed mutations
var/datum/dna/dna
var/mob/living/carbon/human/owner
var/instability = 0 //instability the holder gets when the mutation is not native
var/blocks = 4 //Amount of those big blocks with gene sequences
var/difficulty = 8 //Amount of missing sequences. Sometimes it removes an entire pair for 2 points
var/timed = FALSE //Boolean to easily check if we're going to self destruct
var/alias //'Mutation #49', decided every round to get some form of distinction between undiscovered mutations
var/scrambled = FALSE //Wheter we can read it if it's active. To avoid cheesing with mutagen
var/class //Decides player accesibility, sorta
//MUT_NORMAL - A mutation that can be activated and deactived by completing a sequence
//MUT_EXTRA - A mutation that is in the mutations tab, and can be given and taken away through though the DNA console. Has a 0 before it's name in the mutation section of the dna console
//MUT_OTHER Cannot be interacted with by players through normal means. I.E. wizards mutate
/datum/mutation/human/proc/force_give(mob/living/carbon/human/owner)
set_block(owner)
. = on_acquiring(owner)
var/can_chromosome = CHROMOSOME_NONE //can we take chromosomes? 0: CHROMOSOME_NEVER never, 1:CHROMOSOME_NONE yeah, 2: CHROMOSOME_USED no, already have one
var/chromosome_name //purely cosmetic
var/modified = FALSE //ugly but we really don't want chromosomes and on_acquiring to overlap and apply double the powers
var/mutadone_proof = FALSE
/datum/mutation/human/proc/force_lose(mob/living/carbon/human/owner)
set_block(owner, 0)
. = on_losing(owner)
//Chromosome stuff - set to -1 to prevent people from changing it. Example: It'd be a waste to decrease cooldown on mutism
var/stabilizer_coeff = 1 //genetic stability coeff
var/synchronizer_coeff = -1 //makes the mutation hurt the user less
var/power_coeff = -1 //boosts mutation strength
var/energy_coeff = -1 //lowers mutation cooldown
/datum/mutation/human/proc/set_se(se_string, on = 1)
if(!se_string || length(se_string) < DNA_STRUC_ENZYMES_BLOCKS * DNA_BLOCK_SIZE)
return
var/before = copytext(se_string, 1, ((dna_block - 1) * DNA_BLOCK_SIZE) + 1)
var/injection = num2hex(on ? rand(lowest_value, (256 * 16) - 1) : rand(0, lowest_value - 1), DNA_BLOCK_SIZE)
var/after = copytext(se_string, (dna_block * DNA_BLOCK_SIZE) + 1, 0)
return before + injection + after
/datum/mutation/human/proc/set_block(mob/living/carbon/owner, on = 1)
if(owner && owner.has_dna())
owner.dna.struc_enzymes = set_se(owner.dna.struc_enzymes, on)
/datum/mutation/human/proc/check_block_string(se_string)
if(!se_string || length(se_string) < DNA_STRUC_ENZYMES_BLOCKS * DNA_BLOCK_SIZE)
return 0
if(hex2num(getblock(se_string, dna_block)) >= lowest_value)
return 1
/datum/mutation/human/proc/check_block(mob/living/carbon/human/owner, force_powers=0)
if(check_block_string(owner.dna.struc_enzymes))
if(prob(get_chance)||force_powers)
. = on_acquiring(owner)
else
. = on_losing(owner)
/datum/mutation/human/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
. = ..()
class = class_
if(timer)
addtimer(CALLBACK(src, .proc/remove), timer)
timed = TRUE
if(copymut && istype(copymut, /datum/mutation/human))
copy_mutation(copymut)
/datum/mutation/human/proc/on_acquiring(mob/living/carbon/human/owner)
if(!owner || !istype(owner) || owner.stat == DEAD || (src in owner.dna.mutations))
@@ -63,7 +60,8 @@ GLOBAL_LIST_EMPTY(mutations_list)
return TRUE
if(limb_req && !owner.get_bodypart(limb_req))
return TRUE
owner.dna.mutations.Add(src)
dna = owner.dna
dna.mutations += src
if(text_gain_indication)
to_chat(owner, text_gain_indication)
if(visual_indicators.len)
@@ -75,6 +73,10 @@ GLOBAL_LIST_EMPTY(mutations_list)
owner.overlays_standing[layer_used] = mut_overlay
owner.apply_overlay(layer_used)
grant_spell(owner)
if(!modified)
addtimer(CALLBACK(src, .proc/modify, 5)) //gonna want children calling ..() to run first
/datum/mutation/human/proc/get_visual_indicator(mob/living/carbon/human/owner)
return
@@ -102,26 +104,80 @@ GLOBAL_LIST_EMPTY(mutations_list)
mut_overlay.Remove(get_visual_indicator(owner))
owner.overlays_standing[layer_used] = mut_overlay
owner.apply_overlay(layer_used)
if(power)
owner.RemoveSpell(power)
qdel(src)
return 0
return 1
/datum/mutation/human/proc/say_mod(message)
if(message)
return message
/datum/mutation/human/proc/get_spans()
return list()
/mob/living/carbon/proc/update_mutations_overlay()
return
/mob/living/carbon/human/update_mutations_overlay()
for(var/datum/mutation/human/CM in dna.mutations)
if(CM.species_allowed.len && !CM.species_allowed.Find(dna.species.id))
CM.force_lose(src) //shouldn't have that mutation at all
dna.force_lose(CM) //shouldn't have that mutation at all
continue
if(CM.visual_indicators.len)
var/list/mut_overlay = list()
if(overlays_standing[CM.layer_used])
mut_overlay = overlays_standing[CM.layer_used]
var/mutable_appearance/V = CM.get_visual_indicator(src)
var/mutable_appearance/V = CM.get_visual_indicator()
if(!mut_overlay.Find(V)) //either we lack the visual indicator or we have the wrong one
remove_overlay(CM.layer_used)
for(var/mutable_appearance/MA in CM.visual_indicators)
for(var/mutable_appearance/MA in CM.visual_indicators[CM.type])
mut_overlay.Remove(MA)
mut_overlay |= V
overlays_standing[CM.layer_used] = mut_overlay
apply_overlay(CM.layer_used)
/datum/mutation/human/proc/modify() //called when a genome is applied so we can properly update some stats without having to remove and reapply the mutation from someone
if(modified || !power || !owner)
return
power.charge_max *= GET_MUTATION_ENERGY(src)
power.charge_counter *= GET_MUTATION_ENERGY(src)
modified = TRUE
/datum/mutation/human/proc/copy_mutation(datum/mutation/human/HM)
if(!HM)
return
chromosome_name = HM.chromosome_name
stabilizer_coeff = HM.stabilizer_coeff
synchronizer_coeff = HM.synchronizer_coeff
power_coeff = HM.power_coeff
energy_coeff = HM.energy_coeff
mutadone_proof = HM.mutadone_proof
can_chromosome = HM.can_chromosome
/datum/mutation/human/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_spell(mob/living/carbon/human/owner)
if(!ispath(power) || !owner)
return FALSE
power = new power()
power.action_background_icon_state = "bg_tech_blue_on"
power.panel = "Genetic"
owner.AddSpell(power)
return TRUE

View File

@@ -0,0 +1,169 @@
/datum/mutation/human/telepathy
name = "Telepathy"
desc = "A rare mutation that allows the user to telepathically communicate to others."
quality = POSITIVE
text_gain_indication = "<span class='notice'>You can hear your own voice echoing in your mind!</span>"
text_lose_indication = "<span class='notice'>You don't hear your mind echo anymore.</span>"
difficulty = 12
power = /obj/effect/proc_holder/spell/targeted/telepathy/genetic
instability = 10
energy_coeff = 1
/datum/mutation/human/telepathy/on_acquiring(mob/living/carbon/human/owner)
. = ..()
/datum/mutation/human/telepathy/on_losing(mob/living/carbon/human/owner)
. = ..()
/obj/effect/proc_holder/spell/targeted/telepathy/genetic
magic_check = FALSE
/datum/mutation/human/firebreath
name = "Fire Breath"
desc = "An ancient mutation that gives lizards breath of fire."
quality = POSITIVE
difficulty = 12
locked = TRUE
text_gain_indication = "<span class='notice'>Your throat is burning!</span>"
text_lose_indication = "<span class='notice'>Your throat is cooling down.</span>"
power = /obj/effect/proc_holder/spell/aimed/firebreath
instability = 30
energy_coeff = 1
power_coeff = 1
/datum/mutation/human/firebreath/modify()
if(power)
var/obj/effect/proc_holder/spell/aimed/firebreath/S = power
S.strength = GET_MUTATION_POWER(src)
/obj/effect/proc_holder/spell/aimed/firebreath
name = "Fire Breath"
desc = "You can breathe fire at a target."
school = "evocation"
charge_max = 1200
clothes_req = FALSE
range = 20
projectile_type = /obj/item/projectile/magic/aoe/fireball/firebreath
base_icon_state = "fireball"
action_icon_state = "fireball0"
sound = 'sound/magic/demon_dies.ogg' //horrifying lizard noises
active_msg = "You built up heat in your mouth."
deactive_msg = "You swallow the flame."
var/strength = 1
/obj/effect/proc_holder/spell/aimed/firebreath/before_cast(list/targets)
. = ..()
if(iscarbon(usr))
var/mob/living/carbon/C = usr
if(C.is_mouth_covered())
C.adjust_fire_stacks(2)
C.IgniteMob()
to_chat(C,"<span class='warning'>Something in front of your mouth caught fire!</span>")
return FALSE
/obj/effect/proc_holder/spell/aimed/firebreath/ready_projectile(obj/item/projectile/P, atom/target, mob/user, iteration)
if(!istype(P, /obj/item/projectile/magic/aoe/fireball))
return
var/obj/item/projectile/magic/aoe/fireball/F = P
switch(strength)
if(1 to 3)
F.exp_light = strength-1
if(4 to INFINITY)
F.exp_heavy = strength-3
F.exp_fire += strength
/obj/item/projectile/magic/aoe/fireball/firebreath
name = "fire breath"
exp_heavy = 0
exp_light = 0
exp_flash = 0
exp_fire= 4
/datum/mutation/human/void
name = "Void Magnet"
desc = "A rare genome that attracts odd forces not usually observed."
quality = MINOR_NEGATIVE //upsides and downsides
text_gain_indication = "<span class='notice'>You feel a heavy, dull force just beyond the walls watching you.</span>"
instability = 30
power = /obj/effect/proc_holder/spell/self/void
energy_coeff = 1
synchronizer_coeff = 1
/datum/mutation/human/void/on_life(mob/living/carbon/human/owner)
if(!isturf(owner.loc))
return
if(prob((0.5+((100-dna.stability)/20))) * GET_MUTATION_SYNCHRONIZER(src)) //very rare, but enough to annoy you hopefully. +0.5 probability for every 10 points lost in stability
new /obj/effect/immortality_talisman/void(get_turf(owner), owner)
/obj/effect/proc_holder/spell/self/void
name = "Convoke Void" //magic the gathering joke here
desc = "A rare genome that attracts odd forces not usually observed. May sometimes pull you in randomly."
school = "evocation"
clothes_req = FALSE
charge_max = 600
invocation = "DOOOOOOOOOOOOOOOOOOOOM!!!"
invocation_type = "shout"
action_icon_state = "void_magnet"
var/in_use = FALSE //so it doesnt cast while you are already deep innit
/obj/effect/proc_holder/spell/self/void/can_cast(mob/user = usr)
. = ..()
if(!isturf(user.loc))
return FALSE
/obj/effect/proc_holder/spell/self/void/cast(mob/user = usr)
. = ..()
new /obj/effect/immortality_talisman/void(get_turf(user), user)
/datum/mutation/human/shock
name = "Shock Touch"
desc = "The affected can channel excess electricity through their hands without shocking themselves, allowing them to shock others."
quality = POSITIVE
locked = TRUE
difficulty = 16
text_gain_indication = "<span class='notice'>You feel power flow through your hands.</span>"
text_lose_indication = "<span class='notice'>The energy in your hands subsides.</span>"
power = /obj/effect/proc_holder/spell/targeted/touch/shock
instability = 30
/obj/effect/proc_holder/spell/targeted/touch/shock
name = "Shock Touch"
desc = "Channel electricity to your hand to shock people with."
drawmessage = "You channel electricity into your hand."
dropmessage = "You let the electricity from your hand dissipate."
hand_path = /obj/item/melee/touch_attack/shock
charge_max = 400
clothes_req = FALSE
action_icon_state = "zap"
/obj/item/melee/touch_attack/shock
name = "\improper shock touch"
desc = "This is kind of like when you rub your feet on a shag rug so you can zap your friends, only a lot less safe."
catchphrase = null
on_use_sound = 'sound/weapons/zapbang.ogg'
icon_state = "zapper"
item_state = "zapper"
/obj/item/melee/touch_attack/shock/afterattack(atom/target, mob/living/carbon/user, proximity)
if(!proximity || !isliving(target))
return
if(iscarbon(target))
var/mob/living/carbon/C = target
if(C.electrocute_act(15, user, 1, stun = 0))//doesnt stun. never let this stun
C.dropItemToGround(C.get_active_held_item())
C.dropItemToGround(C.get_inactive_held_item())
C.confused += 10
C.visible_message("<span class='danger'>[user] electrocutes [target]!</span>","<span class='userdanger'>[user] electrocutes you!</span>")
return ..()
else
user.visible_message("<span class='warning'>[user] fails to electrocute [target]!</span>")
return ..()
else if(isliving(target))
var/mob/living/L = target
L.electrocute_act(15, user, 1, stun = 0)
L.visible_message("<span class='danger'>[user] electrocutes [target]!</span>","<span class='userdanger'>[user] electrocutes you!</span>")
return ..()
else
to_chat(user,"<span class='warning'>The electricity doesn't seem to affect [target]...</span>")
return ..()

View File

@@ -0,0 +1,107 @@
/datum/mutation/human/antenna
name = "Antenna"
desc = "The affected person sprouts an antenna. This is known to allow them to access common radio channels passively."
quality = POSITIVE
text_gain_indication = "<span class='notice'>You feel an antenna sprout from your forehead.</span>"
text_lose_indication = "<span class='notice'>Your antenna shrinks back down.</span>"
instability = 5
difficulty = 8
var/obj/item/implant/radio/antenna/linked_radio
/obj/item/implant/radio/antenna
name = "internal antenna organ"
desc = "The internal organ part of the antenna. Science has not yet given it a good name."
icon = 'icons/obj/radio.dmi'//maybe make a unique sprite later. not important
icon_state = "walkietalkie"
/obj/item/implant/radio/antenna/Initialize(mapload)
..()
radio.name = "internal antenna"
/datum/mutation/human/antenna/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
linked_radio = new(owner)
linked_radio.implant(owner, null, TRUE, TRUE)
/datum/mutation/human/antenna/on_losing(mob/living/carbon/human/owner)
if(..())
return
if(linked_radio)
linked_radio.Destroy()
/datum/mutation/human/antenna/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "antenna", -FRONT_MUTATIONS_LAYER+1))//-MUTATIONS_LAYER+1
/datum/mutation/human/antenna/get_visual_indicator(mob/living/carbon/human/owner)
return visual_indicators[type][1]
/datum/mutation/human/mindreader
name = "Mind Reader"
desc = "The affected person can look into the recent memories of others."
quality = POSITIVE
text_gain_indication = "<span class='notice'>You hear distant voices at the corners of your mind.</span>"
text_lose_indication = "<span class='notice'>The distant voices fade.</span>"
power = /obj/effect/proc_holder/spell/targeted/mindread
instability = 40
difficulty = 8
locked = TRUE
/obj/effect/proc_holder/spell/targeted/mindread
name = "Mindread"
desc = "Read the target's mind."
charge_max = 300
range = 7
clothes_req = FALSE
action_icon_state = "mindread"
/obj/effect/proc_holder/spell/targeted/mindread/cast(list/targets, mob/living/carbon/human/user = usr)
for(var/mob/living/M in targets)
if(usr.anti_magic_check(FALSE, FALSE, TRUE, 0) || M.anti_magic_check(FALSE, FALSE, TRUE, 0))
to_chat(usr, "<span class='warning'>As you reach out with your mind, you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.</span>")
return
if(M.stat == DEAD)
to_chat(user, "<span class='boldnotice'>[M] is dead!</span>")
return
if(M.mind)
to_chat(user, "<span class='boldnotice'>You plunge into [M]'s mind...</span>")
if(prob(20))
to_chat(M, "<span class='danger'>You feel something foreign enter your mind.</span>")//chance to alert the read-ee
var/list/recent_speech = list()
var/list/say_log = list()
var/log_source = M.logging
for(var/log_type in log_source)//this whole loop puts the read-ee's say logs into say_log in an easy to access way
var/nlog_type = text2num(log_type)
if(nlog_type & LOG_SAY)
var/list/reversed = log_source[log_type]
if(islist(reversed))
say_log = reverseRange(reversed.Copy())
break
if(LAZYLEN(say_log))
for(var/spoken_memory in say_log)
if(recent_speech.len >= 3)//up to 3 random lines of speech, favoring more recent speech
break
if(prob(50))
recent_speech[spoken_memory] = say_log[spoken_memory]
if(recent_speech.len)
to_chat(user, "<span class='boldnotice'>You catch some drifting memories of their past conversations...</span>")
for(var/spoken_memory in recent_speech)
to_chat(user, "<span class='notice'>[recent_speech[spoken_memory]]</span>")
if(iscarbon(M))
var/mob/living/carbon/human/H = M
to_chat(user, "<span class='boldnotice'>You find that their intent is to [H.a_intent]...</span>")
var/datum/dna/the_dna = H.has_dna()
if(the_dna)
to_chat(user, "<span class='boldnotice'>You uncover that [H.p_their()] true identity is [the_dna.real_name].</span>")
else
to_chat(user, "<span class='warning'>You can't find a mind to read inside of [M]!</span>")
/datum/mutation/human/mindreader/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "antenna", -FRONT_MUTATIONS_LAYER+1))
/datum/mutation/human/mindreader/get_visual_indicator(mob/living/carbon/human/owner)
return visual_indicators[type][1]

View File

@@ -3,16 +3,19 @@
//Epilepsy gives a very small chance to have a seizure every life tick, knocking you unconscious.
/datum/mutation/human/epilepsy
name = "Epilepsy"
desc = "A genetic defect that sporadically causes seizures."
quality = NEGATIVE
text_gain_indication = "<span class='danger'>You get a headache.</span>"
synchronizer_coeff = 1
power_coeff = 1
/datum/mutation/human/epilepsy/on_life(mob/living/carbon/human/owner)
if(prob(1) && owner.stat == CONSCIOUS)
if(prob(1 * GET_MUTATION_SYNCHRONIZER(src)) && owner.stat == CONSCIOUS)
owner.visible_message("<span class='danger'>[owner] starts having a seizure!</span>", "<span class='userdanger'>You have a seizure!</span>")
owner.Unconscious(200)
owner.Jitter(1000)
owner.Unconscious(200 * GET_MUTATION_POWER(src))
owner.Jitter(1000 * GET_MUTATION_POWER(src))
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "epilepsy", /datum/mood_event/epilepsy)
addtimer(CALLBACK(src, .proc/jitter_less, owner), 90)
addtimer(CALLBACK(src, .proc/jitter_less), 90)
/datum/mutation/human/epilepsy/proc/jitter_less(mob/living/carbon/human/owner)
if(owner)
@@ -22,19 +25,23 @@
//Unstable DNA induces random mutations!
/datum/mutation/human/bad_dna
name = "Unstable DNA"
desc = "Strange mutation that causes the holder to randomly mutate."
quality = NEGATIVE
text_gain_indication = "<span class='danger'>You feel strange.</span>"
locked = TRUE
/datum/mutation/human/bad_dna/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
to_chat(owner, text_gain_indication)
var/mob/new_mob
if(prob(95))
if(prob(50))
new_mob = owner.randmutb()
new_mob = owner.easy_randmut(NEGATIVE + MINOR_NEGATIVE)
else
new_mob = owner.randmuti()
else
new_mob = owner.randmutg()
new_mob = owner.easy_randmut(POSITIVE)
if(new_mob && ismob(new_mob))
owner = new_mob
. = owner
@@ -44,21 +51,31 @@
//Cough gives you a chronic cough that causes you to drop items.
/datum/mutation/human/cough
name = "Cough"
desc = "A chronic cough."
quality = MINOR_NEGATIVE
text_gain_indication = "<span class='danger'>You start coughing.</span>"
synchronizer_coeff = 1
power_coeff = 1
/datum/mutation/human/cough/on_life(mob/living/carbon/human/owner)
if(prob(5) && owner.stat == CONSCIOUS)
if(prob(5 * GET_MUTATION_SYNCHRONIZER(src)) && owner.stat == CONSCIOUS)
owner.drop_all_held_items()
owner.emote("cough")
if(GET_MUTATION_POWER(src) > 1)
var/cough_range = GET_MUTATION_POWER(src) * 4
var/turf/target = get_ranged_target_turf(owner, turn(owner.dir, 180), cough_range)
owner.throw_at(target, cough_range, GET_MUTATION_POWER(src))
//Dwarfism shrinks your body and lets you pass tables.
/datum/mutation/human/dwarfism
name = "Dwarfism"
desc = "A mutation believed to be the cause of dwarfism."
quality = POSITIVE
get_chance = 15
lowest_value = 256 * 12
difficulty = 16
instability = 5
locked = TRUE // Default intert species for now, so locked from regular pool.
/datum/mutation/human/dwarfism/on_acquiring(mob/living/carbon/human/owner)
if(..())
@@ -78,6 +95,7 @@
//Clumsiness has a very large amount of small drawbacks depending on item.
/datum/mutation/human/clumsy
name = "Clumsiness"
desc = "A genome that inhibits certain brain functions, causing the holder to appear clumsy. Honk"
quality = MINOR_NEGATIVE
text_gain_indication = "<span class='danger'>You feel lightheaded.</span>"
@@ -95,11 +113,13 @@
//Tourettes causes you to randomly stand in place and shout.
/datum/mutation/human/tourettes
name = "Tourette's Syndrome"
desc = "A chronic twitch that forces the user to use colorful language."
quality = NEGATIVE
text_gain_indication = "<span class='danger'>You twitch.</span>"
synchronizer_coeff = 1
/datum/mutation/human/tourettes/on_life(mob/living/carbon/human/owner)
if(prob(10) && owner.stat == CONSCIOUS && !owner.IsStun())
if(prob(10 * GET_MUTATION_SYNCHRONIZER(src)) && owner.stat == CONSCIOUS && !owner.IsStun())
owner.Stun(200)
switch(rand(1, 3))
if(1)
@@ -117,6 +137,7 @@
//Deafness makes you deaf.
/datum/mutation/human/deaf
name = "Deafness"
desc = "The holder of this genome is completely deaf."
quality = NEGATIVE
text_gain_indication = "<span class='danger'>You can't seem to hear anything.</span>"
@@ -134,8 +155,10 @@
//Monified turns you into a monkey.
/datum/mutation/human/race
name = "Monkified"
desc = "A strange genome, believing to be what differentiates monkeys from humans."
quality = NEGATIVE
time_coeff = 2
locked = TRUE //Species specific, keep out of actual gene pool
/datum/mutation/human/race/on_acquiring(mob/living/carbon/human/owner)
if(..())
@@ -145,3 +168,95 @@
/datum/mutation/human/race/on_losing(mob/living/carbon/monkey/owner)
if(owner && istype(owner) && owner.stat != DEAD && (owner.dna.mutations.Remove(src)))
. = owner.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
/datum/mutation/human/glow
name = "Glowy"
desc = "You permanently emit a light with a random color and intensity."
quality = POSITIVE
text_gain_indication = "<span class='notice'>Your skin begins to glow softly.</span>"
instability = 5
var/obj/effect/dummy/luminescent_glow/glowth //shamelessly copied from luminescents
var/glow = 1.5
power_coeff = 1
/datum/mutation/human/glow/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
glowth = new(owner)
glowth.set_light(glow, glow, dna.features["mcolor"])
/datum/mutation/human/glow/modify(mob/living/carbon/human/owner)
if(glowth)
glowth.set_light(glow + GET_MUTATION_POWER(src) , glow + GET_MUTATION_POWER(src), dna.features["mcolor"])
/datum/mutation/human/glow/on_losing(mob/living/carbon/human/owner)
if(..())
return
qdel(glowth)
/datum/mutation/human/strong
name = "Strength"
desc = "The user's muscles slightly expand."
quality = POSITIVE
text_gain_indication = "<span class='notice'>You feel strong.</span>"
difficulty = 16
/datum/mutation/human/fire
name = "Fiery Sweat"
desc = "The user's skin will randomly combust, but is generally alot more resilient to burning."
quality = NEGATIVE
text_gain_indication = "<span class='warning'>You feel hot.</span>"
text_lose_indication = "<span class'notice'>You feel a lot cooler.</span>"
difficulty = 14
synchronizer_coeff = 1
power_coeff = 1
/datum/mutation/human/fire/on_life(mob/living/carbon/human/owner)
if(prob((1+(100-dna.stability)/10)) * GET_MUTATION_SYNCHRONIZER(src))
owner.adjust_fire_stacks(2 * GET_MUTATION_POWER(src))
owner.IgniteMob()
/datum/mutation/human/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)
if(..())
return
owner.physiology.burn_mod *= 2
/datum/mutation/human/insulated
name = "Insulated"
desc = "The affected person does not conduct electricity."
quality = POSITIVE
text_gain_indication = "<span class='notice'>Your fingertips go numb.</span>"
text_lose_indication = "<span class='notice'>Your fingertips regain feeling.</span>"
difficulty = 16
instability = 25
/datum/mutation/human/insulated/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
ADD_TRAIT(owner, TRAIT_SHOCKIMMUNE, "genetics")
/datum/mutation/human/insulated/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_SHOCKIMMUNE, "genetics")
/datum/mutation/human/paranoia
name = "Paranoia"
desc = "Subject is easily terrified, and may suffer from hallucinations."
quality = NEGATIVE
text_gain_indication = "<span class='danger'>You feel screams echo through your mind...</span>"
text_lose_indication = "<span class'notice'>The screaming in your mind fades.</span>"
/datum/mutation/human/paranoia/on_life(mob/living/carbon/human/owner)
if(prob(5) && owner.stat == CONSCIOUS)
owner.emote("scream")
owner.jitteriness = min(max(0, owner.jitteriness + 5), 30)
if(prob(25))
to_chat(owner,"<span class='warning'>You feel someone creeping in on you...</span>")
owner.hallucination += 20

View File

@@ -1,12 +1,13 @@
//Chameleon causes the owner to slowly become transparent when not moving.
/datum/mutation/human/chameleon
name = "Chameleon"
desc = "A genome that causes the holder's skin to become transparent over time."
quality = POSITIVE
get_chance = 20
lowest_value = 256 * 12
difficulty = 16
text_gain_indication = "<span class='notice'>You feel one with your surroundings.</span>"
text_lose_indication = "<span class='notice'>You feel oddly exposed.</span>"
time_coeff = 5
instability = 25
/datum/mutation/human/chameleon/on_acquiring(mob/living/carbon/human/owner)
if(..())

View File

@@ -1,32 +1,29 @@
//Cold Resistance gives your entire body an orange halo, and makes you immune to the effects of vacuum and cold.
/datum/mutation/human/cold_resistance
name = "Cold Resistance"
/datum/mutation/human/space_adaptation
name = "Space Adaptation"
desc = "A strange mutation that renders the host immune to the vacuum if space. Will still need an oxygen supply."
quality = POSITIVE
get_chance = 25
lowest_value = 256 * 12
difficulty = 16
text_gain_indication = "<span class='notice'>Your body feels warm!</span>"
time_coeff = 5
instability = 30
/datum/mutation/human/cold_resistance/New()
/datum/mutation/human/space_adaptation/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
..()
visual_indicators |= mutable_appearance('icons/effects/genetics.dmi', "fire", -MUTATIONS_LAYER)
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "fire", -MUTATIONS_LAYER))
/datum/mutation/human/cold_resistance/get_visual_indicator(mob/living/carbon/human/owner)
return visual_indicators[1]
/datum/mutation/human/space_adaptation/get_visual_indicator(mob/living/carbon/human/owner)
return visual_indicators[type][1]
/datum/mutation/human/cold_resistance/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/human/space_adaptation/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
ADD_TRAIT(owner, TRAIT_RESISTCOLD, "cold_resistance")
// ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE
ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance")
/datum/mutation/human/cold_resistance/on_losing(mob/living/carbon/human/owner)
/datum/mutation/human/space_adaptation/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_RESISTCOLD, "cold_resistance")
// REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE
/datum/mutation/human/cold_resistance/on_life(mob/living/carbon/human/owner)
if(owner.getFireLoss())
if(prob(1))
owner.heal_bodypart_damage(0,1) //Is this really needed?
REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance")

View File

@@ -0,0 +1,24 @@
/datum/generecipe
var/required = "" //it hurts so bad but initial is not compatible with lists
var/result = null
/proc/get_mixed_mutation(mutation1, mutation2)
if(!mutation1 || !mutation2)
return FALSE
if(mutation1 == mutation2) //this could otherwise be bad
return FALSE
for(var/A in GLOB.mutation_recipes)
if(findtext(A, "[mutation1]") && findtext(A, "[mutation2]"))
return GLOB.mutation_recipes[A]
/datum/generecipe/x_ray
required = "/datum/mutation/human/thermal; /datum/mutation/human/radioactive"
result = /datum/mutation/human/thermal/x_ray
/datum/generecipe/shock
required = "/datum/mutation/human/insulated; /datum/mutation/human/radioactive"
result = SHOCKTOUCH
/datum/generecipe/mindread
required = "/datum/mutation/human/antenna; /datum/mutation/human/paranoia"
result = MINDREAD

View File

@@ -1,28 +1,30 @@
//Hulk turns your skin green, and allows you to punch through walls.
/datum/mutation/human/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
get_chance = 15
lowest_value = 256 * 12
locked = TRUE
difficulty = 16
text_gain_indication = "<span class='notice'>Your muscles hurt!</span>"
species_allowed = list("fly") //no skeleton/lizard hulk
species_allowed = list("human") //no skeleton/lizard hulk
health_req = 25
instability = 40
locked = TRUE
/datum/mutation/human/hulk/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
ADD_TRAIT(owner, TRAIT_STUNIMMUNE, TRAIT_HULK)
ADD_TRAIT(owner, TRAIT_PUSHIMMUNE, TRAIT_HULK)
ADD_TRAIT(owner, TRAIT_CHUNKYFINGERS, TRAIT_HULK)
owner.update_body_parts()
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "hulk", /datum/mood_event/hulk)
RegisterSignal(owner, COMSIG_MOB_SAY, .proc/handle_speech)
/datum/mutation/human/hulk/on_attack_hand(mob/living/carbon/human/owner, atom/target, proximity)
/datum/mutation/human/hulk/on_attack_hand(atom/target, proximity)
if(proximity) //no telekinetic hulk attack
return target.attack_hulk(owner)
/datum/mutation/human/hulk/on_life(mob/living/carbon/human/owner)
/datum/mutation/human/hulk/on_life()
if(owner.health < 0)
on_losing(owner)
to_chat(owner, "<span class='danger'>You suddenly feel very weak.</span>")
@@ -32,7 +34,6 @@
return
REMOVE_TRAIT(owner, TRAIT_STUNIMMUNE, TRAIT_HULK)
REMOVE_TRAIT(owner, TRAIT_PUSHIMMUNE, TRAIT_HULK)
ADD_TRAIT(owner, TRAIT_CHUNKYFINGERS, TRAIT_HULK)
owner.update_body_parts()
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "hulk")
UnregisterSignal(owner, COMSIG_MOB_SAY)

View File

@@ -0,0 +1,19 @@
/datum/mutation/human/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
text_gain_indication = "<span class='warning'>You can feel it in your bones!</span>"
time_coeff = 5
instability = 5
difficulty = 8
/datum/mutation/human/radioactive/on_life(mob/living/carbon/human/owner)
radiation_pulse(owner, 20)
/datum/mutation/human/radioactive/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "radiation", -MUTATIONS_LAYER))
/datum/mutation/human/radioactive/get_visual_indicator()
return visual_indicators[type][1]

View File

@@ -1,6 +1,7 @@
//Nearsightedness restricts your vision by several tiles.
/datum/mutation/human/nearsight
name = "Near Sightness"
desc = "The holder of this mutation has poor eyesight."
quality = MINOR_NEGATIVE
text_gain_indication = "<span class='danger'>You can't see very well.</span>"
@@ -18,6 +19,7 @@
//Blind makes you blind. Who knew?
/datum/mutation/human/blind
name = "Blindness"
desc = "Renders the subject completely blind."
quality = NEGATIVE
text_gain_indication = "<span class='danger'>You can't seem to see anything.</span>"
@@ -32,43 +34,58 @@
owner.cure_blind(GENETIC_MUTATION)
//X-ray Vision lets you see through walls.
/datum/mutation/human/x_ray
name = "X Ray Vision"
///Thermal Vision lets you see mobs through walls
/datum/mutation/human/thermal
name = "Thermal Vision"
desc = "The user of this genome can visually percieve the unique human thermal signature."
quality = POSITIVE
get_chance = 25
lowest_value = 256 * 12
text_gain_indication = "<span class='notice'>The walls suddenly disappear!</span>"
difficulty = 18
text_gain_indication = "<span class='notice'>You can see the heat rising off of your skin...</span>"
time_coeff = 2
instability = 25
var/visionflag = TRAIT_THERMAL_VISION
/datum/mutation/human/x_ray/on_acquiring(mob/living/carbon/human/owner)
/datum/mutation/human/thermal/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
ADD_TRAIT(owner, visionflag, GENETIC_MUTATION)
owner.update_sight()
/datum/mutation/human/x_ray/on_losing(mob/living/carbon/human/owner)
/datum/mutation/human/thermal/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, visionflag, GENETIC_MUTATION)
owner.update_sight()
///X-ray Vision lets you see through walls.
/datum/mutation/human/thermal/x_ray
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, wich might be fun for later //hmb
text_gain_indication = "<span class='notice'>The walls suddenly disappear!</span>"
instability = 35
locked = TRUE
visionflag = TRAIT_XRAY_VISION
//Laser Eyes lets you shoot lasers from your eyes!
/datum/mutation/human/laser_eyes
name = "Laser Eyes"
desc = "Reflects concentrated light back from the eyes."
quality = POSITIVE
dna_block = NON_SCANNABLE
locked = TRUE
difficulty = 16
text_gain_indication = "<span class='notice'>You feel pressure building up behind your eyes.</span>"
layer_used = FRONT_MUTATIONS_LAYER
limb_req = BODY_ZONE_HEAD
/datum/mutation/human/laser_eyes/New()
/datum/mutation/human/laser_eyes/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
..()
visual_indicators |= mutable_appearance('icons/effects/genetics.dmi', "lasereyes", -FRONT_MUTATIONS_LAYER)
/datum/mutation/human/laser_eyes/get_visual_indicator(mob/living/carbon/human/owner)
/datum/mutation/human/laser_eyes/get_visual_indicator()
return visual_indicators[1]
/datum/mutation/human/laser_eyes/on_ranged_attack(mob/living/carbon/human/owner, atom/target, mouseparams)
/datum/mutation/human/laser_eyes/on_ranged_attack(atom/target, mouseparams)
if(owner.a_intent == INTENT_HARM)
owner.LaserEyes(target, mouseparams)

View File

@@ -3,6 +3,7 @@
/datum/mutation/human/nervousness
name = "Nervousness"
desc = "Causes the holder to stutter."
quality = MINOR_NEGATIVE
text_gain_indication = "<span class='danger'>You feel nervous.</span>"
@@ -13,6 +14,7 @@
/datum/mutation/human/wacky
name = "Wacky"
desc = "<span class='sans'>Unknown.</span>"
quality = MINOR_NEGATIVE
text_gain_indication = "<span class='sans'>You feel an off sensation in your voicebox.</span>"
text_lose_indication = "<span class='notice'>The off sensation passes.</span>"
@@ -34,6 +36,7 @@
/datum/mutation/human/mute
name = "Mute"
desc = "Completely inhibits the vocal section of the brain."
quality = NEGATIVE
text_gain_indication = "<span class='danger'>You feel unable to express yourself at all.</span>"
text_lose_indication = "<span class='danger'>You feel able to speak freely again.</span>"
@@ -53,8 +56,8 @@
/datum/mutation/human/smile
name = "Smile"
desc = "Causes the user to be in constant mania."
quality = MINOR_NEGATIVE
dna_block = NON_SCANNABLE
text_gain_indication = "<span class='notice'>You feel so happy. Nothing can be wrong with anything. :)</span>"
text_lose_indication = "<span class='notice'>Everything is terrible again. :(</span>"
@@ -95,7 +98,6 @@
message = replacetext(message," ugly "," beautiful ")
message = replacetext(message," douchbag "," nice guy ")
message = replacetext(message," whore "," lady ")
message = replacetext(message," gamer "," intellectual ")
message = replacetext(message," nerd "," smarty pants ")
message = replacetext(message," moron "," fun person ")
message = replacetext(message," IT'S LOOSE "," EVERYTHING IS FINE ")
@@ -121,8 +123,8 @@
/datum/mutation/human/unintelligible
name = "Unintelligible"
desc = "Partially inhibits the vocal center of the brain, severely distorting speech."
quality = NEGATIVE
dna_block = NON_SCANNABLE
text_gain_indication = "<span class='danger'>You can't seem to form any coherent thoughts!</span>"
text_lose_indication = "<span class='danger'>Your mind feels more clear.</span>"
@@ -141,8 +143,9 @@
/datum/mutation/human/swedish
name = "Swedish"
desc = "A horrible mutation originating from the distant past. Thought to be eradicated after the incident in 2037."
quality = MINOR_NEGATIVE
dna_block = NON_SCANNABLE
locked = TRUE
text_gain_indication = "<span class='notice'>You feel Swedish, however that works.</span>"
text_lose_indication = "<span class='notice'>The feeling of Swedishness passes.</span>"
@@ -173,8 +176,8 @@
/datum/mutation/human/chav
name = "Chav"
desc = "Unknown"
quality = MINOR_NEGATIVE
dna_block = NON_SCANNABLE
text_gain_indication = "<span class='notice'>Ye feel like a reet prat like, innit?</span>"
text_lose_indication = "<span class='notice'>You no longer feel like being rude and sassy.</span>"
@@ -220,12 +223,13 @@
/datum/mutation/human/elvis
name = "Elvis"
desc = "A terrifying mutation named after its 'patient-zero'."
quality = MINOR_NEGATIVE
dna_block = NON_SCANNABLE
locked = TRUE
text_gain_indication = "<span class='notice'>You feel pretty good, honeydoll.</span>"
text_lose_indication = "<span class='notice'>You feel a little less conversation would be great.</span>"
/datum/mutation/human/elvis/on_life(mob/living/carbon/human/owner)
/datum/mutation/human/elvis/on_life()
switch(pick(1,2))
if(1)
if(prob(15))
@@ -266,8 +270,9 @@
/datum/mutation/human/stoner
name = "Stoner"
desc = "A common mutation that severely decreases intelligence."
quality = NEGATIVE
dna_block = NON_SCANNABLE
locked = TRUE
text_gain_indication = "<span class='notice'>You feel...totally chill, man!</span>"
text_lose_indication = "<span class='notice'>You feel like you have a better sense of time.</span>"

View File

@@ -1,18 +1,20 @@
//Telekinesis lets you interact with objects from range, and gives you a light blue halo around your head.
/datum/mutation/human/telekinesis
name = "Telekinesis"
desc = "A strange mutation that allows the holder to interact with objects through thought."
quality = POSITIVE
get_chance = 20
lowest_value = 256 * 12
difficulty = 18
text_gain_indication = "<span class='notice'>You feel smarter!</span>"
limb_req = BODY_ZONE_HEAD
instability = 30
/datum/mutation/human/telekinesis/New()
/datum/mutation/human/telekinesis/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
..()
visual_indicators |= mutable_appearance('icons/effects/genetics.dmi', "telekinesishead", -MUTATIONS_LAYER)
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "telekinesishead", -MUTATIONS_LAYER))
/datum/mutation/human/telekinesis/get_visual_indicator(mob/living/carbon/human/owner)
return visual_indicators[1]
return visual_indicators[type][1]
/datum/mutation/human/telekinesis/on_ranged_attack(mob/living/carbon/human/owner, atom/target)
target.attack_tk(owner)
target.attack_tk(owner)

View File

@@ -737,3 +737,26 @@ datum/status_effect/pacify
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
owner.log_message("threw [I] due to a Muscle Spasm", LOG_ATTACK)
owner.throw_item(pick(targets))
/datum/status_effect/dna_melt
id = "dna_melt"
duration = 600
status_type = STATUS_EFFECT_REPLACE
alert_type = /obj/screen/alert/status_effect/dna_melt
var/kill_either_way = FALSE //no amount of removing mutations is gonna save you now
/datum/status_effect/dna_melt/on_creation(mob/living/new_owner, set_duration, updating_canmove)
. = ..()
to_chat(new_owner, "<span class='boldwarning'>My body can't handle the mutations! I need to get my mutations removed fast!</span>")
/datum/status_effect/dna_melt/on_remove()
if(!ishuman(owner))
owner.gib() //fuck you in particular
return
var/mob/living/carbon/human/H = owner
H.something_horrible(kill_either_way)
/obj/screen/alert/status_effect/dna_melt
name = "Genetic Breakdown"
desc = "I don't feel so good. Your body can't handle the mutations! You have one minute to remove your mutations, or you will be met with a horrible fate."
icon_state = "dna_melt"