[alias]"
+ temp_html += "
[mut_desc]
"
+ if(active && !storage_slot)
+ if(HM?.can_chromosome && (HM in viable_occupant.dna.mutations))
+ var/i = viable_occupant.dna.mutations.Find(HM)
+ var/chromosome_name = "
----"
+ if(HM.chromosome_name)
+ chromosome_name = HM.chromosome_name
+ temp_html += "
Chromosome status: [chromosome_name]
"
+ temp_html += "
Sequence:
"
+ if(!scrambled)
+ for(var/block in 1 to A.blocks)
+ var/whole_sequence = get_valid_gene_string(mutation)
+ var/sequence = copytext(whole_sequence, 1+(block-1)*(DNA_SEQUENCE_LENGTH*2),(DNA_SEQUENCE_LENGTH*2*block+1))
+ temp_html += "
"
+ for(var/i in 1 to DNA_SEQUENCE_LENGTH)
+ var/num = 1+(i-1)*2
+ var/genenum = num+(DNA_SEQUENCE_LENGTH*2*(block-1))
+ temp_html += " | "
+ temp_html += "
"
+ for(var/i in 1 to DNA_SEQUENCE_LENGTH)
+ temp_html += "| | "
+ temp_html += "
"
+ for(var/i in 1 to DNA_SEQUENCE_LENGTH)
+ var/num = i*2
+ var/genenum = num+(DNA_SEQUENCE_LENGTH*2*(block-1))
+ temp_html += " | "
+ temp_html += "
"
+ temp_html += "
"
+ else
+ temp_html = "
Sequence unreadable due to unpredictable mutation.
"
+ if((active || storage_slot) && (injectorready < world.time) && !scrambled)
+ temp_html += "
Print Activator"
+ temp_html += "
Print Mutator"
+ else
+ temp_html += "
Print Activator"
+ temp_html += "
Print Mutator"
+ temp_html += "
"
+ if(storage_slot)
+ temp_html += "
Delete"
+ if((LAZYLEN(stored_mutations) < max_storage) && diskette && !diskette.read_only)
+ temp_html += "
Export"
+ else
+ temp_html += "
Export"
+ temp_html += "
Back"
+ else if(active && !scrambled)
+ temp_html += "
Store"
+ if(extra || scrambled)
+ temp_html += "
Nullify"
+ else
+ temp_html += "
Nullify"
+ temp_html += "
"
+ return temp_html
/obj/machinery/computer/scan_consolenew/Topic(href, href_list)
if(..())
@@ -340,13 +547,16 @@
radstrength = WRAP(num, 1, RADIATION_STRENGTH_MAX+1)
if("screen")
current_screen = href_list["text"]
- if("rejuv")
- if(viable_occupant && viable_occupant.reagents)
- var/potassiodide_amount = viable_occupant.reagents.get_reagent_amount("potass_iodide")
- var/can_add = max(min(REJUVENATORS_MAX - potassiodide_amount, REJUVENATORS_INJECT), 0)
- viable_occupant.reagents.add_reagent("potass_iodide", can_add)
+ if("scramble")
+ if(viable_occupant && (scrambleready < world.time))
+ viable_occupant.dna.remove_all_mutations(list(MUT_NORMAL, MUT_EXTRA))
+ viable_occupant.dna.generate_dna_blocks()
+ scrambleready = world.time + SCRAMBLE_TIMEOUT
+ to_chat(usr,"
DNA scrambled.")
+ viable_occupant.radiation += RADIATION_STRENGTH_MULTIPLIER*50/(connected.damage_coeff ** 2)
+
if("setbufferlabel")
- var/text = sanitize(input(usr, "Input a new label:", "Input an Text", null) as text|null)
+ var/text = sanitize(input(usr, "Input a new label:", "Input a Text", null) as text|null)
if(num && text)
num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
@@ -358,7 +568,6 @@
buffer[num] = list(
"label"="Buffer[num]:[viable_occupant.real_name]",
"UI"=viable_occupant.dna.uni_identity,
- "SE"=viable_occupant.dna.struc_enzymes,
"UE"=viable_occupant.dna.unique_enzymes,
"name"=viable_occupant.real_name,
"blood_type"=viable_occupant.dna.blood_type
@@ -372,8 +581,6 @@
if("transferbuffer")
if(num && viable_occupant)
switch(href_list["text"]) //Numbers are this high because other way upgrading laser is just not worth the hassle, and i cant think of anything better to inmrove
- if("se")
- apply_buffer(SCANNER_ACTION_SE,num)
if("ui")
apply_buffer(SCANNER_ACTION_UI,num)
if("ue")
@@ -387,28 +594,6 @@
if(istype(buffer_slot))
var/obj/item/dnainjector/timed/I
switch(href_list["text"])
- if("se")
- if(buffer_slot["SE"])
- I = new /obj/item/dnainjector/timed(loc)
- var/powers = 0
- for(var/datum/mutation/human/HM in GLOB.good_mutations + GLOB.bad_mutations + GLOB.not_good_mutations)
- if(HM.check_block_string(buffer_slot["SE"]))
- I.add_mutations.Add(HM)
- if(HM in GLOB.good_mutations)
- powers += 1
- if(HM in GLOB.bad_mutations + GLOB.not_good_mutations)
- powers -= 1 //To prevent just unlocking everything to get all powers to a syringe for max tech
- else
- I.remove_mutations.Add(HM)
- var/time_coeff
- for(var/datum/mutation/human/HM in I.add_mutations)
- if(!time_coeff)
- time_coeff = HM.time_coeff
- continue
- time_coeff = min(time_coeff,HM.time_coeff)
- if(connected)
- I.duration = I.duration * time_coeff * connected.damage_coeff
- I.damage_coeff = connected.damage_coeff
if("ui")
if(buffer_slot["UI"])
I = new /obj/item/dnainjector/timed(loc)
@@ -447,7 +632,7 @@
if("setdelayed")
if(num)
delayed_action = list("action"=text2num(href_list["delayaction"]),"buffer"=num)
- if("pulseui","pulsese")
+ if("pulseui")
if(num && viable_occupant && connected)
radduration = WRAP(radduration, 1, RADIATION_DURATION_MAX+1)
radstrength = WRAP(radstrength, 1, RADIATION_STRENGTH_MAX+1)
@@ -459,7 +644,7 @@
ui_interact(usr)
sleep(radduration*10)
- current_screen = "mainmenu"
+ current_screen = "ui"
if(viable_occupant && connected && connected.occupant==viable_occupant)
viable_occupant.radiation += (RADIATION_IRRADIATION_MULTIPLIER*radduration*radstrength)/(connected.damage_coeff ** 2) //Read comment in "transferbuffer" section above for explanation
@@ -480,35 +665,173 @@
viable_occupant.dna.uni_identity = copytext(viable_occupant.dna.uni_identity, 1, num) + hex + copytext(viable_occupant.dna.uni_identity, num+1, 0)
viable_occupant.updateappearance(mutations_overlay_update=1)
- if("pulsese")
- var/len = length(viable_occupant.dna.struc_enzymes)
- num = WRAP(num, 1, len+1)
- num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len)
-
- var/block = round((num-1)/DNA_BLOCK_SIZE)+1
- var/subblock = num - block*DNA_BLOCK_SIZE
- last_change = "SE #[block]-[subblock]; "
-
- var/hex = copytext(viable_occupant.dna.struc_enzymes, num, num+1)
- last_change += "[hex]"
- hex = scramble(hex, radstrength, radduration)
- last_change += "->[hex]"
-
- viable_occupant.dna.struc_enzymes = copytext(viable_occupant.dna.struc_enzymes, 1, num) + hex + copytext(viable_occupant.dna.struc_enzymes, num+1, 0)
- viable_occupant.domutcheck()
else
current_screen = "mainmenu"
if(connected)
connected.locked = locked_state
+ if("inspect")
+ if(viable_occupant)
+ var/list/mutations = get_mutation_list(TRUE)
+ if(current_mutation == mutations[num])
+ current_mutation = null
+ else
+ current_mutation = mutations[num]
+
+ if("inspectstorage")
+ current_storage = num
+ current_screen = "info"
+ if("savemut")
+ if(viable_occupant)
+ var/succes
+ if(LAZYLEN(stored_mutations) < max_storage)
+ var/mutation = text2path(href_list["path"])
+ if(ispath(mutation, /datum/mutation/human)) //sanity checks
+ var/datum/mutation/human/HM = viable_occupant.dna.get_mutation(mutation)
+ if(HM)
+ var/datum/mutation/human/A = new HM.type()
+ A.copy_mutation(HM)
+ succes = TRUE
+ stored_mutations += A
+ to_chat(usr,"
Mutation succesfully stored.")
+ if(!succes) //we can exactly return here
+ to_chat(usr,"
Mutation storage is full.")
+ if("deletemut")
+ var/datum/mutation/human/HM = stored_mutations[num]
+ if(HM)
+ stored_mutations.Remove(HM)
+ qdel(HM)
+ current_screen = "mutations"
+ if("activator")
+ if(injectorready < world.time)
+ var/mutation = text2path(href_list["path"])
+ if(ispath(mutation, /datum/mutation/human))
+ var/datum/mutation/human/HM = get_valid_mutation(mutation)
+ if(HM)
+ var/obj/item/dnainjector/activator/I = new /obj/item/dnainjector/activator(loc)
+ I.add_mutations += new HM.type (copymut = HM)
+ I.name = "[HM.name] activator"
+ I.research = TRUE
+ if(connected)
+ I.damage_coeff = connected.damage_coeff*4
+ injectorready = world.time + INJECTOR_TIMEOUT * (1 - 0.1 * connected.precision_coeff) //precision_coeff being the matter bin rating
+ else
+ injectorready = world.time + INJECTOR_TIMEOUT
+ if("mutator")
+ if(injectorready < world.time)
+ var/mutation = text2path(href_list["path"])
+ if(ispath(mutation, /datum/mutation/human))
+ var/datum/mutation/human/HM = get_valid_mutation(mutation)
+ if(HM)
+ var/obj/item/dnainjector/activator/I = new /obj/item/dnainjector/activator(loc)
+ I.add_mutations += new HM.type (copymut = HM)
+ I.doitanyway = TRUE
+ I.name = "[HM.name] injector"
+ if(connected)
+ I.damage_coeff = connected.damage_coeff
+ injectorready = world.time + INJECTOR_TIMEOUT * 5 * (1 - 0.1 * connected.precision_coeff)
+ else
+ injectorready = world.time + INJECTOR_TIMEOUT * 5
+ if("nullify")
+ if(viable_occupant)
+ var/datum/mutation/human/A = viable_occupant.dna.get_mutation(current_mutation)
+ if(A && (!viable_occupant.dna.mutation_in_sequence(current_mutation) || A.scrambled))
+ viable_occupant.dna.remove_mutation(current_mutation)
+ current_screen = "mainmenu"
+ current_mutation = null
+ if("pulsegene")
+ if(current_screen != "info")
+ var/path = text2path(href_list["path"])
+ if(viable_occupant && num && (path in viable_occupant.dna.mutation_index))
+ var/list/genes = list("A","T","G","C","X")
+ if(jokerready < world.time)
+ genes += "JOKER"
+ var/sequence = GET_GENE_STRING(path, viable_occupant.dna)
+ var/original = sequence[num]
+ var/new_gene = input("From [original] to-", "New block", original) as null|anything in genes
+ if(!new_gene)
+ new_gene = original
+ if(viable_occupant == get_viable_occupant()) //No cheesing
+ if((new_gene == "JOKER") && (jokerready < world.time))
+ var/true_genes = GET_SEQUENCE(current_mutation)
+ new_gene = true_genes[num]
+ jokerready = world.time + JOKER_TIMEOUT - (JOKER_UPGRADE * (connected.precision_coeff-1))
+ sequence = copytext(sequence, 1, num) + new_gene + copytext(sequence, num+1, length(sequence)+1)
+ viable_occupant.dna.mutation_index[path] = sequence
+ viable_occupant.radiation += RADIATION_STRENGTH_MULTIPLIER/connected.damage_coeff
+ viable_occupant.domutcheck()
+ if("exportdiskmut")
+ if(diskette && !diskette.read_only)
+ var/path = text2path(href_list["path"])
+ if(ispath(path, /datum/mutation/human))
+ var/datum/mutation/human/A = get_valid_mutation(path)
+ if(A && diskette && (LAZYLEN(diskette.mutations) < diskette.max_mutations))
+ var/datum/mutation/human/HM = new A.type()
+ diskette.mutations += HM
+ HM.copy_mutation(A)
+ to_chat(usr, "
Succesfully written [A.name] to [diskette.name].")
+ if("deletediskmut")
+ if(diskette && !diskette.read_only)
+ if(num && (LAZYLEN(diskette.mutations) >= num))
+ var/datum/mutation/human/A = diskette.mutations[num]
+ diskette.mutations.Remove(A)
+ qdel(A)
+ if("importdiskmut")
+ if(diskette && (LAZYLEN(diskette.mutations) >= num))
+ if(LAZYLEN(stored_mutations) < max_storage)
+ var/datum/mutation/human/A = diskette.mutations[num]
+ var/datum/mutation/human/HM = new A.type()
+ HM.copy_mutation(A)
+ stored_mutations += HM
+ to_chat(usr,"
Succesfully written [A.name] to storage.")
+ if("combine")
+ if(num && (LAZYLEN(stored_mutations) >= num))
+ if(LAZYLEN(stored_mutations) < max_storage)
+ var/datum/mutation/human/A = stored_mutations[num]
+ var/path = A.type
+ if(combine)
+ var/result_path = get_mixed_mutation(combine, path)
+ if(result_path)
+ stored_mutations += new result_path()
+ to_chat(usr, "Succes! New mutation has been added to storage")
+ discover(result_path)
+ combine = null
+ else
+ to_chat(usr, "Failed. No mutation could be created.")
+ combine = null
+ else
+ combine = path
+ to_chat(usr,"Selected [A.name] for combining")
+ else
+ to_chat(usr, "Not enough space to store potential mutation.")
+ if("ejectchromosome")
+ if(LAZYLEN(stored_chromosomes) <= num)
+ var/obj/item/chromosome/CM = stored_chromosomes[num]
+ CM.forceMove(drop_location())
+ adjust_item_drop_location(CM)
+ stored_chromosomes -= CM
+ if("applychromosome")
+ if(viable_occupant && (LAZYLEN(viable_occupant.dna.mutations) <= num))
+ var/datum/mutation/human/HM = viable_occupant.dna.mutations[num]
+ var/list/chromosomes = list()
+ for(var/obj/item/chromosome/CM in stored_chromosomes)
+ if(CM.can_apply(HM))
+ chromosomes += CM
+ if(chromosomes.len)
+ var/obj/item/chromosome/CM = input("Select a chromosome to apply", "Apply Chromosome") as null|anything in sortNames(chromosomes)
+ if(CM)
+ to_chat(usr, "You apply [CM] to [HM.name].")
+ stored_chromosomes -= CM
+ CM.apply(HM)
+
ui_interact(usr,last_change)
-/obj/machinery/computer/scan_consolenew/proc/scramble(input,rs,rd)
+/obj/machinery/computer/scan_consolenew/proc/scramble(input,rs,rd) //hexadecimal genetics. dont confuse with scramble button
var/length = length(input)
var/ran = gaussian(0, rs*RADIATION_STRENGTH_MULTIPLIER)
if(ran == 0)
- ran = pick(-1,1) //hacky, statistically should almost never happen. 0-change makes people mad though
+ ran = pick(-1,1) //hacky, statistically should almost never happen. 0-chance makes people mad though
else if(ran < 0)
ran = round(ran) //negative, so floor it
else
@@ -537,10 +860,6 @@
//Each laser level reduces damage by lvl^2, so no effect on 1 lvl, 4 times less damage on 2 and 9 times less damage on 3
//Numbers are this high because other way upgrading laser is just not worth the hassle, and i cant think of anything better to inmrove
switch(action)
- if(SCANNER_ACTION_SE)
- if(buffer_slot["SE"])
- viable_occupant.dna.struc_enzymes = buffer_slot["SE"]
- viable_occupant.domutcheck()
if(SCANNER_ACTION_UI)
if(buffer_slot["UI"])
viable_occupant.dna.uni_identity = buffer_slot["UI"]
@@ -562,15 +881,54 @@
viable_occupant.dna.blood_type = buffer_slot["blood_type"]
/obj/machinery/computer/scan_consolenew/proc/on_scanner_close()
- if(delayed_action && connected)
+ if(delayed_action && get_viable_occupant())
to_chat(connected.occupant, "[src] activates!")
apply_buffer(delayed_action["action"],delayed_action["buffer"])
delayed_action = null //or make it stick + reset button ?
+/obj/machinery/computer/scan_consolenew/proc/get_valid_mutation(mutation)
+ var/mob/living/carbon/C = get_viable_occupant()
+ if(C)
+ var/datum/mutation/human/HM = C.dna.get_mutation(mutation)
+ if(HM)
+ return HM
+ for(var/datum/mutation/human/A in stored_mutations)
+ if(A.type == mutation)
+ return A
+
+
+/obj/machinery/computer/scan_consolenew/proc/get_mutation_list(include_storage) //Returns a list of the mutation index types and any extra mutations
+ var/mob/living/carbon/viable_occupant = get_viable_occupant()
+ var/list/paths = list()
+ if(viable_occupant)
+ for(var/A in viable_occupant.dna.mutation_index)
+ paths += A
+ for(var/datum/mutation/human/A in viable_occupant.dna.mutations)
+ if(A.class == MUT_EXTRA)
+ paths += A.type
+ if(include_storage)
+ for(var/datum/mutation/human/A in stored_mutations)
+ paths += A.type
+ return paths
+
+/obj/machinery/computer/scan_consolenew/proc/get_valid_gene_string(mutation)
+ var/mob/living/carbon/C = get_viable_occupant()
+ if(C && (mutation in C.dna.mutation_index))
+ return GET_GENE_STRING(mutation, C.dna)
+ else if(C && (LAZYLEN(C.dna.mutations)))
+ for(var/datum/mutation/human/A in C.dna.mutations)
+ if(A.type == mutation)
+ return GET_SEQUENCE(mutation)
+ for(var/datum/mutation/human/A in stored_mutations)
+ if(A.type == mutation)
+ return GET_SEQUENCE(mutation)
+
+/obj/machinery/computer/scan_consolenew/proc/discover(mutation)
+ if(stored_research && !(mutation in stored_research.discovered_mutations))
+ stored_research.discovered_mutations += mutation
+ return TRUE
/////////////////////////// DNA MACHINES
#undef INJECTOR_TIMEOUT
-#undef REJUVENATORS_INJECT
-#undef REJUVENATORS_MAX
#undef NUMBER_OF_BUFFERS
#undef RADIATION_STRENGTH_MAX
diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm
index e8364d22..ffe66e68 100644
--- a/code/game/machinery/exp_cloner.dm
+++ b/code/game/machinery/exp_cloner.dm
@@ -26,9 +26,9 @@
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
H.dna.remove_mutation_group(unclean_mutations)
if(efficiency > 5 && prob(20))
- H.randmutvg()
+ H.easy_randmut(POSITIVE)
if(efficiency < 3 && prob(50))
- var/mob/M = H.randmutb()
+ var/mob/M = H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
if(ismob(M))
H = M
@@ -292,6 +292,6 @@
temp = "Cloning cycle already in progress."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
- pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.struc_enzymes, clone_species, dna.features, mob_occupant.faction)
+ pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.mutation_index, clone_species, dna.features, mob_occupant.faction)
temp = "[mob_occupant.real_name] => Cloning data sent to pod."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index a8ba9850..56bd36a0 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -284,12 +284,12 @@
if(equip_ready) //disabled
return
var/area/A = get_area(chassis)
- var/pow_chan = get_power_channel(A)
+ var/pow_chan = GET_MUTATION_POWER_channel(A)
if(pow_chan)
return 1000 //making magic
-/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_power_channel(var/area/A)
+/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/GET_MUTATION_POWER_channel(var/area/A)
var/pow_chan
if(A)
for(var/c in use_channels)
diff --git a/code/game/objects/items/chromosome.dm b/code/game/objects/items/chromosome.dm
new file mode 100644
index 00000000..01c22bb4
--- /dev/null
+++ b/code/game/objects/items/chromosome.dm
@@ -0,0 +1,92 @@
+/obj/item/chromosome
+ name = "blank chromosome"
+ icon = 'icons/obj/chromosomes.dmi'
+ icon_state = ""
+ desc = "A tube holding chromosomic data."
+ force = 0
+ w_class = WEIGHT_CLASS_SMALL
+
+ var/stabilizer_coeff = 1 //lower is better, affects genetic stability
+ var/synchronizer_coeff = 1 //lower is better, affects chance to backfire
+ var/power_coeff = 1 //higher is better, affects "strength"
+ var/energy_coeff = 1 //lower is better. affects recharge time
+
+ var/weight = 5
+
+/obj/item/chromosome/proc/can_apply(datum/mutation/human/HM)
+ if(!HM || !(HM.can_chromosome == CHROMOSOME_NONE))
+ return FALSE
+ if((stabilizer_coeff != 1) && (HM.stabilizer_coeff != -1)) //if the chromosome is 1, we dont change anything. If the mutation is -1, we cant change it. sorry
+ return TRUE
+ if((synchronizer_coeff != 1) && (HM.synchronizer_coeff != -1))
+ return TRUE
+ if((power_coeff != 1) && (HM.power_coeff != -1))
+ return TRUE
+ if((energy_coeff != 1) && (HM.energy_coeff != -1))
+ return TRUE
+
+/obj/item/chromosome/proc/apply(datum/mutation/human/HM)
+ if(HM.stabilizer_coeff != -1)
+ HM.stabilizer_coeff = stabilizer_coeff
+ if(HM.synchronizer_coeff != -1)
+ HM.synchronizer_coeff = synchronizer_coeff
+ if(HM.power_coeff != -1)
+ HM.power_coeff = power_coeff
+ if(HM.energy_coeff != -1)
+ HM.energy_coeff = energy_coeff
+ HM.can_chromosome = 2
+ HM.chromosome_name = name
+ HM.modify()
+ qdel(src)
+
+/proc/generate_chromosome()
+ var/static/list/chromosomes
+ if(!chromosomes)
+ chromosomes = list()
+ for(var/A in subtypesof(/obj/item/chromosome))
+ var/obj/item/chromosome/CM = A
+ if(!initial(CM.weight))
+ break
+ chromosomes[A] = initial(CM.weight)
+ return pickweight(chromosomes)
+
+
+/obj/item/chromosome/stabilizer
+ name = "stabilizer chromosome"
+ desc = "A chromosome that adjusts to the body to reduce genetic damage by 20%."
+ icon_state = "stabilizer"
+ stabilizer_coeff = 0.8
+ weight = 1
+
+/obj/item/chromosome/synchronizer
+ name = "synchronizer chromosome"
+ desc = "A chromosome that gives the mind more controle over the mutation, reducing knockback and downsides by 50%."
+ icon_state = "synchronizer"
+ synchronizer_coeff = 0.5
+
+/obj/item/chromosome/power
+ name = "power chromosome"
+ desc = "A power chromosome for boosting certain mutation's power by 50%."
+ icon_state = "power"
+ power_coeff = 1.5
+
+/obj/item/chromosome/energy
+ name = "energetic chromosome"
+ desc = "A chromosome that reduces cooldown on action based mutations by 50%."
+ icon_state = "energy"
+ energy_coeff = 0.5
+
+/obj/item/chromosome/reinforcer
+ name = "reinforcement chromosome"
+ desc = "Renders the mutation immune to mutadone."
+ icon_state = "reinforcer"
+ weight = 3
+
+/obj/item/chromosome/reinforcer/can_apply(datum/mutation/human/HM)
+ if(!HM || !(HM.can_chromosome == CHROMOSOME_NONE))
+ return FALSE
+ return !HM.mutadone_proof
+
+/obj/item/chromosome/reinforcer/apply(datum/mutation/human/HM)
+ HM.mutadone_proof = TRUE
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index 0496b282..dcf3cd12 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -65,7 +65,7 @@
build_path = /obj/machinery/dna_scannernew
req_components = list(
/obj/item/stock_parts/scanning_module = 1,
- /obj/item/stock_parts/manipulator = 1,
+ /obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/micro_laser = 1,
/obj/item/stack/sheet/glass = 1,
/obj/item/stack/cable_coil = 2)
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 5bc03ab5..fb6eda84 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -6,6 +6,8 @@ T-RAY
HEALTH ANALYZER
GAS ANALYZER
SLIME SCANNER
+NANITE SCANNER
+GENE SCANNER
*/
/obj/item/t_scanner
@@ -291,7 +293,8 @@ SLIME SCANNER
var/ldamage = H.return_liver_damage()
if(ldamage > 10)
msg += "\t[ldamage > 45 ? "Severe" : "Minor"] liver damage detected.\n"
-
+ if(advanced && H.has_dna())
+ to_chat(user, "\tGenetic Stability: [H.dna.stability]%.")
// Body part damage report
if(iscarbon(M) && mode == 1)
var/mob/living/carbon/C = M
@@ -757,3 +760,62 @@ SLIME SCANNER
var/response = SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, TRUE)
if(!response)
to_chat(user, "No nanites detected in the subject.")
+
+/obj/item/sequence_scanner
+ name = "genetic sequence scanner"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "gene"
+ item_state = "healthanalyzer"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ desc = "A hand-held scanner able to swiftly scan someone for potential mutations. Hold near a DNA console to update from their database."
+ flags_1 = CONDUCT_1
+ item_flags = NOBLUDGEON
+ slot_flags = ITEM_SLOT_BELT
+ throwforce = 3
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL=200)
+ var/list/discovered = list() //hit a dna console to update the scanners database
+
+/obj/item/sequence_scanner/attack(mob/living/M, mob/living/carbon/human/user)
+ user.visible_message("[user] has analyzed [M]'s genetic sequence.")
+
+ add_fingerprint(user)
+
+ gene_scan(M, user, src)
+
+/obj/item/sequence_scanner/afterattack(obj/O, mob/user, proximity)
+ . = ..()
+ if(!istype(O) || !proximity)
+ return
+
+ if(istype(O, /obj/machinery/computer/scan_consolenew))
+ var/obj/machinery/computer/scan_consolenew/C = O
+ if(C.stored_research)
+ to_chat(user, "[name] database updated.")
+ discovered = C.stored_research.discovered_mutations
+ else
+ to_chat(user,"No database to update from.")
+
+/proc/gene_scan(mob/living/carbon/C, mob/living/user, obj/item/sequence_scanner/G)
+ if(!iscarbon(C) || !C.has_dna())
+ return
+ to_chat(user, "[C.name]'s potential mutations.")
+ for(var/A in C.dna.mutation_index)
+ var/datum/mutation/human/HM = GET_INITIALIZED_MUTATION(A)
+ var/mut_name
+ if(G && (A in G.discovered))
+ mut_name = "[HM.name] ([HM.alias])"
+ else
+ mut_name = HM.alias
+ var/temp = GET_GENE_STRING(HM.type, C.dna)
+ var/display
+ for(var/i in 0 to length(temp) / DNA_MUTATION_BLOCKS-1)
+ if(i)
+ display += "-"
+ display += copytext(temp, 1 + i*DNA_MUTATION_BLOCKS, DNA_MUTATION_BLOCKS*(1+i) + 1)
+
+
+ to_chat(user, "- [mut_name] > [display]")
\ No newline at end of file
diff --git a/code/game/objects/items/dna_injector.dm b/code/game/objects/items/dna_injector.dm
index a03447c0..8849ac51 100644
--- a/code/game/objects/items/dna_injector.dm
+++ b/code/game/objects/items/dna_injector.dm
@@ -14,33 +14,25 @@
var/list/add_mutations = list()
var/list/remove_mutations = list()
- var/list/add_mutations_static = list()
- var/list/remove_mutations_static = list()
-
var/used = 0
/obj/item/dnainjector/attack_paw(mob/user)
return attack_hand(user)
-/obj/item/dnainjector/proc/prepare()
- for(var/mut_key in add_mutations_static)
- add_mutations.Add(GLOB.mutations_list[mut_key])
- for(var/mut_key in remove_mutations_static)
- remove_mutations.Add(GLOB.mutations_list[mut_key])
-
/obj/item/dnainjector/proc/inject(mob/living/carbon/M, mob/user)
- prepare()
-
if(M.has_dna() && !HAS_TRAIT(M, TRAIT_RADIMMUNE) && !HAS_TRAIT(M, TRAIT_NOCLONE))
M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
- for(var/datum/mutation/human/HM in remove_mutations)
- HM.force_lose(M)
- for(var/datum/mutation/human/HM in add_mutations)
- if(HM.name == RACEMUT)
+ for(var/HM in remove_mutations)
+ M.dna.remove_mutation(HM)
+ for(var/HM in add_mutations)
+ if(HM == RACEMUT)
message_admins("[ADMIN_LOOKUPFLW(user)] injected [key_name_admin(M)] with the [name] (MONKEY)")
log_msg += " (MONKEY)"
- HM.force_give(M)
+ if(M.dna.mutation_in_sequence(HM))
+ M.dna.activate_mutation(HM)
+ else
+ M.dna.add_mutation(HM, MUT_EXTRA)
if(fields)
if(fields["name"] && fields["UE"] && fields["blood_type"])
M.real_name = fields["name"]
@@ -90,123 +82,123 @@
/obj/item/dnainjector/antihulk
name = "\improper DNA injector (Anti-Hulk)"
desc = "Cures green skin."
- remove_mutations_static = list(HULK)
+ remove_mutations = list(HULK)
/obj/item/dnainjector/hulkmut
name = "\improper DNA injector (Hulk)"
desc = "This will make you big and strong, but give you a bad skin condition."
- add_mutations_static = list(HULK)
+ add_mutations = list(HULK)
/obj/item/dnainjector/xraymut
name = "\improper DNA injector (X-ray)"
desc = "Finally you can see what the Captain does."
- add_mutations_static = list(XRAY)
+ add_mutations = list(XRAY)
/obj/item/dnainjector/antixray
name = "\improper DNA injector (Anti-X-ray)"
desc = "It will make you see harder."
- remove_mutations_static = list(XRAY)
+ remove_mutations = list(XRAY)
/////////////////////////////////////
/obj/item/dnainjector/antiglasses
name = "\improper DNA injector (Anti-Glasses)"
desc = "Toss away those glasses!"
- remove_mutations_static = list(BADSIGHT)
+ remove_mutations = list(BADSIGHT)
/obj/item/dnainjector/glassesmut
name = "\improper DNA injector (Glasses)"
desc = "Will make you need dorkish glasses."
- add_mutations_static = list(BADSIGHT)
+ add_mutations = list(BADSIGHT)
/obj/item/dnainjector/epimut
name = "\improper DNA injector (Epi.)"
desc = "Shake shake shake the room!"
- add_mutations_static = list(EPILEPSY)
+ add_mutations = list(EPILEPSY)
/obj/item/dnainjector/antiepi
name = "\improper DNA injector (Anti-Epi.)"
desc = "Will fix you up from shaking the room."
- remove_mutations_static = list(EPILEPSY)
+ remove_mutations = list(EPILEPSY)
////////////////////////////////////
/obj/item/dnainjector/anticough
name = "\improper DNA injector (Anti-Cough)"
desc = "Will stop that awful noise."
- remove_mutations_static = list(COUGH)
+ remove_mutations = list(COUGH)
/obj/item/dnainjector/coughmut
name = "\improper DNA injector (Cough)"
desc = "Will bring forth a sound of horror from your throat."
- add_mutations_static = list(COUGH)
+ add_mutations = list(COUGH)
/obj/item/dnainjector/antidwarf
name = "\improper DNA injector (Anti-Dwarfism)"
desc = "Helps you grow big and strong."
- remove_mutations_static = list(DWARFISM)
+ remove_mutations = list(DWARFISM)
/obj/item/dnainjector/dwarf
name = "\improper DNA injector (Dwarfism)"
desc = "It's a small world after all."
- add_mutations_static = list(DWARFISM)
+ add_mutations = list(DWARFISM)
/obj/item/dnainjector/clumsymut
name = "\improper DNA injector (Clumsy)"
desc = "Makes clown minions."
- add_mutations_static = list(CLOWNMUT)
+ add_mutations = list(CLOWNMUT)
/obj/item/dnainjector/anticlumsy
name = "\improper DNA injector (Anti-Clumsy)"
desc = "Apply this for Security Clown."
- remove_mutations_static = list(CLOWNMUT)
+ remove_mutations = list(CLOWNMUT)
/obj/item/dnainjector/antitour
name = "\improper DNA injector (Anti-Tour.)"
desc = "Will cure Tourette's."
- remove_mutations_static = list(TOURETTES)
+ remove_mutations = list(TOURETTES)
/obj/item/dnainjector/tourmut
name = "\improper DNA injector (Tour.)"
desc = "Gives you a nasty case of Tourette's."
- add_mutations_static = list(TOURETTES)
+ add_mutations = list(TOURETTES)
/obj/item/dnainjector/stuttmut
name = "\improper DNA injector (Stutt.)"
desc = "Makes you s-s-stuttterrr."
- add_mutations_static = list(NERVOUS)
+ add_mutations = list(NERVOUS)
/obj/item/dnainjector/antistutt
name = "\improper DNA injector (Anti-Stutt.)"
desc = "Fixes that speaking impairment."
- remove_mutations_static = list(NERVOUS)
+ remove_mutations = list(NERVOUS)
/obj/item/dnainjector/antifire
name = "\improper DNA injector (Anti-Fire)"
desc = "Cures fire."
- remove_mutations_static = list(COLDRES)
+ remove_mutations = list(SPACEMUT)
/obj/item/dnainjector/firemut
name = "\improper DNA injector (Fire)"
desc = "Gives you fire."
- add_mutations_static = list(COLDRES)
+ add_mutations = list(SPACEMUT)
/obj/item/dnainjector/blindmut
name = "\improper DNA injector (Blind)"
desc = "Makes you not see anything."
- add_mutations_static = list(BLINDMUT)
+ add_mutations = list(BLINDMUT)
/obj/item/dnainjector/antiblind
name = "\improper DNA injector (Anti-Blind)"
desc = "IT'S A MIRACLE!!!"
- remove_mutations_static = list(BLINDMUT)
+ remove_mutations = list(BLINDMUT)
/obj/item/dnainjector/antitele
name = "\improper DNA injector (Anti-Tele.)"
desc = "Will make you not able to control your mind."
- remove_mutations_static = list(TK)
+ remove_mutations = list(TK)
/obj/item/dnainjector/telemut
name = "\improper DNA injector (Tele.)"
desc = "Super brain man!"
- add_mutations_static = list(TK)
+ add_mutations = list(TK)
/obj/item/dnainjector/telemut/darkbundle
name = "\improper DNA injector"
@@ -215,100 +207,171 @@
/obj/item/dnainjector/deafmut
name = "\improper DNA injector (Deaf)"
desc = "Sorry, what did you say?"
- add_mutations_static = list(DEAFMUT)
+ add_mutations = list(DEAFMUT)
/obj/item/dnainjector/antideaf
name = "\improper DNA injector (Anti-Deaf)"
desc = "Will make you hear once more."
- remove_mutations_static = list(DEAFMUT)
+ remove_mutations = list(DEAFMUT)
/obj/item/dnainjector/h2m
name = "\improper DNA injector (Human > Monkey)"
desc = "Will make you a flea bag."
- add_mutations_static = list(RACEMUT)
+ add_mutations = list(RACEMUT)
/obj/item/dnainjector/m2h
name = "\improper DNA injector (Monkey > Human)"
desc = "Will make you...less hairy."
- remove_mutations_static = list(RACEMUT)
+ remove_mutations = list(RACEMUT)
/obj/item/dnainjector/antichameleon
name = "\improper DNA injector (Anti-Chameleon)"
- remove_mutations_static = list(CHAMELEON)
+ remove_mutations = list(CHAMELEON)
/obj/item/dnainjector/chameleonmut
name = "\improper DNA injector (Chameleon)"
- add_mutations_static = list(CHAMELEON)
+ add_mutations = list(CHAMELEON)
/obj/item/dnainjector/antiwacky
name = "\improper DNA injector (Anti-Wacky)"
- remove_mutations_static = list(WACKY)
+ remove_mutations = list(WACKY)
/obj/item/dnainjector/wackymut
name = "\improper DNA injector (Wacky)"
- add_mutations_static = list(WACKY)
+ add_mutations = list(WACKY)
/obj/item/dnainjector/antimute
name = "\improper DNA injector (Anti-Mute)"
- remove_mutations_static = list(MUT_MUTE)
+ remove_mutations = list(MUT_MUTE)
/obj/item/dnainjector/mutemut
name = "\improper DNA injector (Mute)"
- add_mutations_static = list(MUT_MUTE)
+ add_mutations = list(MUT_MUTE)
/obj/item/dnainjector/antismile
name = "\improper DNA injector (Anti-Smile)"
- remove_mutations_static = list(SMILE)
+ remove_mutations = list(SMILE)
/obj/item/dnainjector/smilemut
name = "\improper DNA injector (Smile)"
- add_mutations_static = list(SMILE)
+ add_mutations = list(SMILE)
/obj/item/dnainjector/unintelligiblemut
name = "\improper DNA injector (Unintelligible)"
- add_mutations_static = list(UNINTELLIGIBLE)
+ add_mutations = list(UNINTELLIGIBLE)
/obj/item/dnainjector/antiunintelligible
name = "\improper DNA injector (Anti-Unintelligible)"
- remove_mutations_static = list(UNINTELLIGIBLE)
+ remove_mutations = list(UNINTELLIGIBLE)
/obj/item/dnainjector/swedishmut
name = "\improper DNA injector (Swedish)"
- add_mutations_static = list(SWEDISH)
+ add_mutations = list(SWEDISH)
/obj/item/dnainjector/antiswedish
name = "\improper DNA injector (Anti-Swedish)"
- remove_mutations_static = list(SWEDISH)
+ remove_mutations = list(SWEDISH)
/obj/item/dnainjector/chavmut
name = "\improper DNA injector (Chav)"
- add_mutations_static = list(CHAV)
+ add_mutations = list(CHAV)
/obj/item/dnainjector/antichav
name = "\improper DNA injector (Anti-Chav)"
- remove_mutations_static = list(CHAV)
+ remove_mutations = list(CHAV)
/obj/item/dnainjector/elvismut
name = "\improper DNA injector (Elvis)"
- add_mutations_static = list(ELVIS)
+ add_mutations = list(ELVIS)
/obj/item/dnainjector/antielvis
name = "\improper DNA injector (Anti-Elvis)"
- remove_mutations_static = list(ELVIS)
+ remove_mutations = list(ELVIS)
/obj/item/dnainjector/lasereyesmut
name = "\improper DNA injector (Laser Eyes)"
- add_mutations_static = list(LASEREYES)
+ add_mutations = list(LASEREYES)
/obj/item/dnainjector/antilasereyes
name = "\improper DNA injector (Anti-Laser Eyes)"
- remove_mutations_static = list(LASEREYES)
+ remove_mutations = list(LASEREYES)
+
+/obj/item/dnainjector/thermalmut
+ name = "\improper DNA injector (Thermal Vision)"
+ add_mutations = list(THERMAL)
+
+/obj/item/dnainjector/antithermal
+ name = "\improper DNA injector (Anti-Thermal Vision)"
+ remove_mutations = list(THERMAL)
+
+/obj/item/dnainjector/telepathymut
+ name = "\improper DNA injector (Telepathy)"
+ add_mutations = list(TELEPATHY)
+
+/obj/item/dnainjector/antitelepathy
+ name = "\improper DNA injector (Anti-Telepathy)"
+ remove_mutations = list(TELEPATHY)
+
+/obj/item/dnainjector/voidmut
+ name = "\improper DNA injector (Void Magnet)"
+ add_mutations = list(VOID)
+
+/obj/item/dnainjector/antivoid
+ name = "\improper DNA injector (Anti-Void Magnet)"
+ remove_mutations = list(VOID)
+
+/obj/item/dnainjector/firebreathmut
+ name = "\improper DNA injector (Firebreath)"
+ add_mutations = list(FIREBREATH)
+
+/obj/item/dnainjector/antifirebreath
+ name = "\improper DNA injector (Anti-Firebreath)"
+ remove_mutations = list(FIREBREATH)
+
+/obj/item/dnainjector/insulatedmut
+ name = "\improper DNA injector (Insulated)"
+ add_mutations = list(INSULATED)
+
+/obj/item/dnainjector/antiinsulated
+ name = "\improper DNA injector (Anti-Insulated)"
+ remove_mutations = list(INSULATED)
+
+/obj/item/dnainjector/shocktouchmut
+ name = "\improper DNA injector (Shock Touch)"
+ add_mutations = list(SHOCKTOUCH)
+
+/obj/item/dnainjector/antishocktouch
+ name = "\improper DNA injector (Anti-Shock Touch)"
+ remove_mutations = list(SHOCKTOUCH)
+
+/obj/item/dnainjector/antenna
+ name = "\improper DNA injector (Antenna)"
+ add_mutations = list(ANTENNA)
+
+/obj/item/dnainjector/antiantenna
+ name = "\improper DNA injector (Anti-Antenna)"
+ remove_mutations = list(ANTENNA)
+
+/obj/item/dnainjector/paranoia
+ name = "\improper DNA injector (Paranoia)"
+ add_mutations = list(PARANOIA)
+
+/obj/item/dnainjector/antiparanoia
+ name = "\improper DNA injector (Anti-Paranoia)"
+ remove_mutations = list(PARANOIA)
+
+/obj/item/dnainjector/mindread
+ name = "\improper DNA injector (Mindread)"
+ add_mutations = list(MINDREAD)
+
+/obj/item/dnainjector/antimindread
+ name = "\improper DNA injector (Anti-Mindread)"
+ remove_mutations = list(MINDREAD)
/obj/item/dnainjector/timed
var/duration = 600
/obj/item/dnainjector/timed/inject(mob/living/carbon/M, mob/user)
- prepare()
if(M.stat == DEAD) //prevents dead people from having their DNA changed
to_chat(user, "You can't modify [M]'s DNA while [M.p_theyre()] dead.")
return FALSE
@@ -317,23 +380,22 @@
M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
var/endtime = world.time+duration
- for(var/datum/mutation/human/HM in remove_mutations)
- if(HM.name == RACEMUT)
+ for(var/mutation in remove_mutations)
+ if(mutation == RACEMUT)
if(ishuman(M))
continue
- M = HM.force_lose(M)
+ M = M.dna.remove_mutation(mutation)
else
- HM.force_lose(M)
- for(var/datum/mutation/human/HM in add_mutations)
- if((HM in M.dna.mutations) && !(M.dna.temporary_mutations[HM.name]))
+ M.dna.remove_mutation(mutation)
+ for(var/mutation in add_mutations)
+ if(M.dna.get_mutation(mutation))
continue //Skip permanent mutations we already have.
- if(HM.name == RACEMUT && ishuman(M))
+ if(mutation == RACEMUT && ishuman(M))
message_admins("[ADMIN_LOOKUPFLW(user)] injected [key_name_admin(M)] with the [name] (MONKEY)")
log_msg += " (MONKEY)"
- M = HM.force_give(M)
+ M = M.dna.add_mutation(mutation, MUT_OTHER, endtime)
else
- HM.force_give(M)
- M.dna.temporary_mutations[HM.name] = endtime
+ M.dna.add_mutation(mutation, MUT_OTHER, endtime)
if(fields)
if(fields["name"] && fields["UE"] && fields["blood_type"])
if(!M.dna.previous["name"])
@@ -361,9 +423,41 @@
/obj/item/dnainjector/timed/hulk
name = "\improper DNA injector (Hulk)"
desc = "This will make you big and strong, but give you a bad skin condition."
- add_mutations_static = list(HULK)
+ add_mutations = list(HULK)
/obj/item/dnainjector/timed/h2m
name = "\improper DNA injector (Human > Monkey)"
desc = "Will make you a flea bag."
- add_mutations_static = list(RACEMUT)
+ add_mutations = list(RACEMUT)
+
+/obj/item/dnainjector/activator
+ name = "\improper DNA activator"
+ desc = "Activates the current mutation on injection, if the subject has it."
+ var/doitanyway = FALSE
+ var/research = FALSE //Set to true to get expended and filled injectors for chromosomes
+ var/filled = FALSE
+
+/obj/item/dnainjector/activator/inject(mob/living/carbon/M, mob/user)
+ if(M.has_dna() && !HAS_TRAIT(M, TRAIT_RADIMMUNE) && !HAS_TRAIT(M,TRAIT_NOCLONE))
+ M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
+ var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
+ for(var/mutation in add_mutations)
+ var/datum/mutation/human/HM = mutation
+ if(istype(HM, /datum/mutation/human))
+ mutation = HM.type
+ if(!M.dna.activate_mutation(HM))
+ if(!doitanyway)
+ log_msg += "(FAILED)"
+ else
+ M.dna.add_mutation(HM, MUT_EXTRA)
+ name = "expended [name]"
+ else if(research && M.client)
+ filled = TRUE
+ name = "filled [name]"
+ else
+ name = "expended [name]"
+ log_msg += "([mutation])"
+ log_attack("[log_msg] [loc_name(user)]")
+ return TRUE
+ return FALSE
+
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 44b39265..83b14a1a 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -25,6 +25,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
merge_type = /obj/item/stack/sheet/glass
grind_results = list("silicon" = 20)
point_value = 1
+ tableVariant = /obj/structure/table/glass
/obj/item/stack/sheet/glass/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins to slice [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 7df16546..46c0d473 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -232,6 +232,7 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \
grind_results = list("silver" = 20)
point_value = 20
merge_type = /obj/item/stack/sheet/mineral/silver
+ tableVariant = /obj/structure/table/optable
GLOBAL_LIST_INIT(silver_recipes, list ( \
new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, one_per_turf = 1, on_floor = 1), \
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 8c808d0e..c0853068 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -107,6 +107,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
merge_type = /obj/item/stack/sheet/metal
grind_results = list("iron" = 20)
point_value = 2
+ tableVariant = /obj/structure/table
/obj/item/stack/sheet/metal/ratvar_act()
new /obj/item/stack/tile/brass(loc, amount)
@@ -168,6 +169,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
merge_type = /obj/item/stack/sheet/plasteel
grind_results = list("iron" = 20, "plasma" = 20)
point_value = 23
+ tableVariant = /obj/structure/table/reinforced
/obj/item/stack/sheet/plasteel/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.plasteel_recipes
@@ -474,6 +476,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
novariants = FALSE
grind_results = list("iron" = 5, "teslium" = 15, "holyoil" = 1)
merge_type = /obj/item/stack/tile/brass
+ tableVariant = /obj/structure/table/reinforced/brass
/obj/item/stack/tile/brass/narsie_act()
new /obj/item/stack/sheet/runed_metal(loc, amount)
@@ -526,6 +529,7 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
novariants = FALSE
grind_results = list("iron" = 5, "copper" = 3) //we have no "tin" reagent so this is the closest thing
merge_type = /obj/item/stack/tile/bronze
+ tableVariant = /obj/structure/table/bronze
/obj/item/stack/tile/bronze/attack_self(mob/living/user)
if(is_servant_of_ratvar(user)) //still lets them build with it, just gives a message
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 4217a58f..155d1f16 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -22,6 +22,7 @@
var/full_w_class = WEIGHT_CLASS_NORMAL //The weight class the stack should have at amount > 2/3rds max_amount
var/novariants = TRUE //Determines whether the item should update it's sprites based on amount.
//NOTE: When adding grind_results, the amounts should be for an INDIVIDUAL ITEM - these amounts will be multiplied by the stack size in on_grind()
+ var/obj/structure/table/tableVariant // we tables now (stores table variant to be built from this stack)
/obj/item/stack/on_grind()
for(var/i in 1 to grind_results.len) //This should only call if it's ground, so no need to check if grind_results exists
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index 3b28c304..b98c4f79 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -99,34 +99,118 @@
icon_state = "tile-carpet"
turf_type = /turf/open/floor/carpet
resistance_flags = FLAMMABLE
-
-/obj/item/stack/tile/carpet/fifty
- amount = 50
+ tableVariant = /obj/structure/table/wood/fancy
/obj/item/stack/tile/carpet/black
name = "black carpet"
icon_state = "tile-carpet-black"
turf_type = /turf/open/floor/carpet/black
+ tableVariant = /obj/structure/table/wood/fancy/black
+
+/obj/item/stack/tile/carpet/blackred
+ name = "red carpet"
+ icon_state = "tile-carpet-blackred"
+ turf_type = /turf/open/floor/carpet/blackred
+ tableVariant = /obj/structure/table/wood/fancy/blackred
+
+/obj/item/stack/tile/carpet/monochrome
+ name = "monochrome carpet"
+ icon_state = "tile-carpet-monochrome"
+ turf_type = /turf/open/floor/carpet/monochrome
+ tableVariant = /obj/structure/table/wood/fancy/monochrome
+
+/obj/item/stack/tile/carpet/blue
+ name = "blue carpet"
+ icon_state = "tile-carpet-blue"
+ item_state = "tile-carpet-blue"
+ turf_type = /turf/open/floor/carpet/blue
+ tableVariant = /obj/structure/table/wood/fancy/blue
+
+/obj/item/stack/tile/carpet/cyan
+ name = "cyan carpet"
+ icon_state = "tile-carpet-cyan"
+ item_state = "tile-carpet-cyan"
+ turf_type = /turf/open/floor/carpet/cyan
+ tableVariant = /obj/structure/table/wood/fancy/cyan
+
+/obj/item/stack/tile/carpet/green
+ name = "green carpet"
+ icon_state = "tile-carpet-green"
+ item_state = "tile-carpet-green"
+ turf_type = /turf/open/floor/carpet/green
+ tableVariant = /obj/structure/table/wood/fancy/green
+
+/obj/item/stack/tile/carpet/orange
+ name = "orange carpet"
+ icon_state = "tile-carpet-orange"
+ item_state = "tile-carpet-orange"
+ turf_type = /turf/open/floor/carpet/orange
+ tableVariant = /obj/structure/table/wood/fancy/orange
+
+/obj/item/stack/tile/carpet/purple
+ name = "purple carpet"
+ icon_state = "tile-carpet-purple"
+ item_state = "tile-carpet-purple"
+ turf_type = /turf/open/floor/carpet/purple
+ tableVariant = /obj/structure/table/wood/fancy/purple
+
+/obj/item/stack/tile/carpet/red
+ name = "red carpet"
+ icon_state = "tile-carpet-red"
+ item_state = "tile-carpet-red"
+ turf_type = /turf/open/floor/carpet/red
+ tableVariant = /obj/structure/table/wood/fancy/red
+
+/obj/item/stack/tile/carpet/royalblack
+ name = "royal black carpet"
+ icon_state = "tile-carpet-royalblack"
+ item_state = "tile-carpet-royalblack"
+ turf_type = /turf/open/floor/carpet/royalblack
+ tableVariant = /obj/structure/table/wood/fancy/royalblack
+
+/obj/item/stack/tile/carpet/royalblue
+ name = "royal blue carpet"
+ icon_state = "tile-carpet-royalblue"
+ item_state = "tile-carpet-royalblue"
+ turf_type = /turf/open/floor/carpet/royalblue
+ tableVariant = /obj/structure/table/wood/fancy/royalblue
+
+/obj/item/stack/tile/carpet/fifty
+ amount = 50
/obj/item/stack/tile/carpet/black/fifty
amount = 50
-/obj/item/stack/tile/carpet/blackred
- name = "red carpet"
- icon_state = "tile-carpet-blackred"
- turf_type = /turf/open/floor/carpet/blackred
-
/obj/item/stack/tile/carpet/blackred/fifty
amount = 50
-/obj/item/stack/tile/carpet/monochrome
- name = "monochrome carpet"
- icon_state = "tile-carpet-monochrome"
- turf_type = /turf/open/floor/carpet/monochrome
-
/obj/item/stack/tile/carpet/monochrome/fifty
amount = 50
+/obj/item/stack/tile/carpet/blue/fifty
+ amount = 50
+
+/obj/item/stack/tile/carpet/cyan/fifty
+ amount = 50
+
+/obj/item/stack/tile/carpet/green/fifty
+ amount = 50
+
+/obj/item/stack/tile/carpet/orange/fifty
+ amount = 50
+
+/obj/item/stack/tile/carpet/purple/fifty
+ amount = 50
+
+/obj/item/stack/tile/carpet/red/fifty
+ amount = 50
+
+/obj/item/stack/tile/carpet/royalblack/fifty
+ amount = 50
+
+/obj/item/stack/tile/carpet/royalblue/fifty
+ amount = 50
+
/obj/item/stack/tile/fakespace
name = "astral carpet"
singular_name = "astral carpet"
diff --git a/code/game/objects/structures/table_frames.dm b/code/game/objects/structures/table_frames.dm
index e979d4f1..f62bed87 100644
--- a/code/game/objects/structures/table_frames.dm
+++ b/code/game/objects/structures/table_frames.dm
@@ -22,84 +22,22 @@
var/framestackamount = 2
/obj/structure/table_frame/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/wrench))
+ if(I.tool_behaviour == TOOL_WRENCH)
to_chat(user, "You start disassembling [src]...")
I.play_tool_sound(src)
if(I.use_tool(src, user, 30))
- playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
+ playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE)
deconstruct(TRUE)
- else if(istype(I, /obj/item/stack/sheet/plasteel))
- var/obj/item/stack/sheet/plasteel/P = I
- if(P.get_amount() < 1)
- to_chat(user, "You need one plasteel sheet to do this!")
+ return
+
+ var/obj/item/stack/material = I
+ if (istype(I, /obj/item/stack) && material?.tableVariant)
+ if(material.get_amount() < 1)
+ to_chat(user, "You need one [material.name] sheet to do this!")
return
- to_chat(user, "You start adding [P] to [src]...")
- if(do_after(user, 50, target = src) && P.use(1))
- make_new_table(/obj/structure/table/reinforced)
- else if(istype(I, /obj/item/stack/sheet/metal))
- var/obj/item/stack/sheet/metal/M = I
- if(M.get_amount() < 1)
- to_chat(user, "You need one metal sheet to do this!")
- return
- to_chat(user, "You start adding [M] to [src]...")
- if(do_after(user, 20, target = src) && M.use(1))
- make_new_table(/obj/structure/table)
- else if(istype(I, /obj/item/stack/sheet/glass))
- var/obj/item/stack/sheet/glass/G = I
- if(G.get_amount() < 1)
- to_chat(user, "You need one glass sheet to do this!")
- return
- to_chat(user, "You start adding [G] to [src]...")
- if(do_after(user, 20, target = src) && G.use(1))
- make_new_table(/obj/structure/table/glass)
- else if(istype(I, /obj/item/stack/sheet/mineral/silver))
- var/obj/item/stack/sheet/mineral/silver/S = I
- if(S.get_amount() < 1)
- to_chat(user, "You need one silver sheet to do this!")
- return
- to_chat(user, "You start adding [S] to [src]...")
- if(do_after(user, 20, target = src) && S.use(1))
- make_new_table(/obj/structure/table/optable)
- else if(istype(I, /obj/item/stack/tile/carpet/black))
- var/obj/item/stack/tile/carpet/black/C = I
- if(C.get_amount() < 1)
- to_chat(user, "You need one black carpet sheet to do this!")
- return
- to_chat(user, "You start adding [C] to [src]...")
- if(do_after(user, 20, target = src) && C.use(1))
- make_new_table(/obj/structure/table/wood/fancy/black)
- else if(istype(I, /obj/item/stack/tile/carpet/blackred))
- var/obj/item/stack/tile/carpet/blackred/C = I
- if(C.get_amount() < 1)
- to_chat(user, "You need one red carpet sheet to do this!")
- return
- to_chat(user, "You start adding [C] to [src]...")
- if(do_after(user, 20, target = src) && C.use(1))
- make_new_table(/obj/structure/table/wood/fancy/blackred)
- else if(istype(I, /obj/item/stack/tile/carpet/monochrome))
- var/obj/item/stack/tile/carpet/monochrome/C = I
- if(C.get_amount() < 1)
- to_chat(user, "You need one monochrome carpet sheet to do this!")
- return
- to_chat(user, "You start adding [C] to [src]...")
- if(do_after(user, 20, target = src) && C.use(1))
- make_new_table(/obj/structure/table/wood/fancy/monochrome)
- else if(istype(I, /obj/item/stack/tile/carpet))
- var/obj/item/stack/tile/carpet/C = I
- if(C.get_amount() < 1)
- to_chat(user, "You need one carpet sheet to do this!")
- return
- to_chat(user, "You start adding [C] to [src]...")
- if(do_after(user, 20, target = src) && C.use(1))
- make_new_table(/obj/structure/table/wood/fancy)
- else if(istype(I, /obj/item/stack/tile/bronze))
- var/obj/item/stack/tile/bronze/B = I
- if(B.get_amount() < 1)
- to_chat(user, "You need one bronze sheet to do this!")
- return
- to_chat(user, "You start adding [B] to [src]...")
- if(do_after(user, 20, target = src) && B.use(1))
- make_new_table(/obj/structure/table/bronze)
+ to_chat(user, "You start adding [material] to [src]...")
+ if(do_after(user, 20, target = src) && material.use(1))
+ make_new_table(material.tableVariant)
else
return ..()
@@ -135,23 +73,21 @@
resistance_flags = FLAMMABLE
/obj/structure/table_frame/wood/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/stack/sheet/mineral/wood))
- var/obj/item/stack/sheet/mineral/wood/W = I
- if(W.get_amount() < 1)
- to_chat(user, "You need one wood sheet to do this!")
- return
- to_chat(user, "You start adding [W] to [src]...")
- if(do_after(user, 20, target = src) && W.use(1))
- make_new_table(/obj/structure/table/wood)
- return
- else if(istype(I, /obj/item/stack/tile/carpet))
- var/obj/item/stack/tile/carpet/C = I
- if(C.get_amount() < 1)
- to_chat(user, "You need one carpet sheet to do this!")
- return
- to_chat(user, "You start adding [C] to [src]...")
- if(do_after(user, 20, target = src) && C.use(1))
- make_new_table(/obj/structure/table/wood/poker)
+ if (istype(I, /obj/item/stack))
+ var/obj/item/stack/material = I
+ var/toConstruct // stores the table variant
+ if(istype(I, /obj/item/stack/sheet/mineral/wood))
+ toConstruct = /obj/structure/table/wood
+ else if(istype(I, /obj/item/stack/tile/carpet))
+ toConstruct = /obj/structure/table/wood/poker
+
+ if (toConstruct)
+ if(material.get_amount() < 1)
+ to_chat(user, "You need one [material.name] sheet to do this!")
+ return
+ to_chat(user, "You start adding [material] to [src]...")
+ if(do_after(user, 20, target = src) && material.use(1))
+ make_new_table(toConstruct)
else
return ..()
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index e262c5cf..bec51dce 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -115,6 +115,9 @@
log_combat(user, pushed_mob, "placed")
/obj/structure/table/proc/tablepush(mob/living/user, mob/living/pushed_mob)
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ to_chat(user, "Throwing [pushed_mob] onto the table might hurt them!")
+ return
var/added_passtable = FALSE
if(!pushed_mob.pass_flags & PASSTABLE)
added_passtable = TRUE
@@ -125,14 +128,25 @@
if(pushed_mob.loc != loc) //Something prevented the tabling
return
pushed_mob.Knockdown(40)
- pushed_mob.visible_message("[user] pushes [pushed_mob] onto [src].", \
- "[user] pushes [pushed_mob] onto [src].")
- log_combat(user, pushed_mob, "pushed")
+ pushed_mob.visible_message("[user] slams [pushed_mob] onto [src]!", \
+ "[user] slams you onto [src]!")
+ log_combat(user, pushed_mob, "tabled", null, "onto [src]")
if(!ishuman(pushed_mob))
return
var/mob/living/carbon/human/H = pushed_mob
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "table", /datum/mood_event/table)
+/* You don't shove people onto a table frame.
+/obj/structure/table/shove_act(mob/living/target, mob/living/user)
+ if(!target.resting)
+ target.Knockdown(SHOVE_KNOCKDOWN_TABLE)
+ user.visible_message("[user.name] shoves [target.name] onto \the [src]!",
+ "You shove [target.name] onto \the [src]!", null, COMBAT_MESSAGE_RANGE)
+ target.forceMove(src.loc)
+ log_combat(user, target, "shoved", "onto [src] (table)")
+ return TRUE
+*/
+
/obj/structure/table/attackby(obj/item/I, mob/user, params)
if(!(flags_1 & NODECONSTRUCT_1))
if(istype(I, /obj/item/screwdriver) && deconstruction_ready)
@@ -258,6 +272,52 @@
for(var/obj/item/shard/S in debris)
S.color = NARSIE_WINDOW_COLOUR
+/*
+ * Plasmaglass tables
+ */
+/obj/structure/table/plasmaglass
+ name = "plasmaglass table"
+ desc = "A glasstable, but it's pink and more sturdy. What will Nanotrasen design next with plasma?"
+ icon = 'icons/obj/smooth_structures/plasmaglass_table.dmi'
+ icon_state = "plasmaglass_table"
+ climbable = TRUE
+ buildstack = /obj/item/stack/sheet/plasmaglass
+ canSmoothWith = null
+ max_integrity = 270
+ resistance_flags = ACID_PROOF
+ armor = list("melee" = 10, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100)
+ var/list/debris = list()
+
+/obj/structure/table/plasmaglass/New()
+ . = ..()
+ debris += new frame
+
+/obj/structure/table/plasmaglass/Destroy()
+ QDEL_LIST(debris)
+ . = ..()
+
+/obj/structure/table/plasmaglass/proc/check_break(mob/living/M)
+ return
+
+/obj/structure/table/plasmaglass/deconstruct(disassembled = TRUE, wrench_disassembly = 0)
+ if(!(flags_1 & NODECONSTRUCT_1))
+ if(disassembled)
+ ..()
+ return
+ else
+ var/turf/T = get_turf(src)
+ playsound(T, "shatter", 50, 1)
+ for(var/X in debris)
+ var/atom/movable/AM = X
+ AM.forceMove(T)
+ debris -= AM
+ qdel(src)
+
+/obj/structure/table/plasmaglass/narsie_act()
+ color = NARSIE_WINDOW_COLOUR
+ for(var/obj/item/shard/S in debris)
+ S.color = NARSIE_WINDOW_COLOUR
+
/*
* Wooden tables
*/
@@ -298,44 +358,83 @@
frame = /obj/structure/table_frame
framestack = /obj/item/stack/rods
buildstack = /obj/item/stack/tile/carpet
- canSmoothWith = list(/obj/structure/table/wood/fancy, /obj/structure/table/wood/fancy/black, /obj/structure/table/wood/fancy/blackred, /obj/structure/table/wood/fancy/monochrome)
+ canSmoothWith = list(/obj/structure/table/wood/fancy,
+ /obj/structure/table/wood/fancy/black,
+ /obj/structure/table/wood/fancy/blackred,
+ /obj/structure/table/wood/fancy/monochrome,
+ /obj/structure/table/wood/fancy/blue,
+ /obj/structure/table/wood/fancy/cyan,
+ /obj/structure/table/wood/fancy/green,
+ /obj/structure/table/wood/fancy/orange,
+ /obj/structure/table/wood/fancy/purple,
+ /obj/structure/table/wood/fancy/red,
+ /obj/structure/table/wood/fancy/royalblack,
+ /obj/structure/table/wood/fancy/royalblue)
+ var/smooth_icon = 'icons/obj/smooth_structures/fancy_table.dmi' // see Initialize()
-/obj/structure/table/wood/fancy/New()
- // New() is used so that the /black subtype can override `icon` easily and
- // the correct value will be used by the smoothing subsystem.
+/obj/structure/table/wood/fancy/Initialize()
. = ..()
// Needs to be set dynamically because table smooth sprites are 32x34,
// which the editor treats as a two-tile-tall object. The sprites are that
// size so that the north/south corners look nice - examine the detail on
// the sprites in the editor to see why.
- icon = 'icons/obj/smooth_structures/fancy_table.dmi'
+ icon = smooth_icon
/obj/structure/table/wood/fancy/black
icon_state = "fancy_table_black"
buildstack = /obj/item/stack/tile/carpet/black
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_black.dmi'
/obj/structure/table/wood/fancy/blackred
- icon = 'icons/obj/structures.dmi'
- icon_state = "fancy_table_blackred"
- buildstack = /obj/item/stack/tile/carpet/blackred
-
-/obj/structure/table/wood/fancy/blackred/New()
- . = ..()
- icon = 'icons/obj/smooth_structures/fancy_table_blackred.dmi'
+ icon_state = "fancy_table_blackred"
+ buildstack = /obj/item/stack/tile/carpet/blackred
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_blackred.dmi'
/obj/structure/table/wood/fancy/monochrome
- icon = 'icons/obj/structures.dmi'
- icon_state = "fancy_table_monochrome"
- buildstack = /obj/item/stack/tile/carpet/monochrome
+ icon_state = "fancy_table_monochrome"
+ buildstack = /obj/item/stack/tile/carpet/monochrome
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_monochrome.dmi'
-/obj/structure/table/wood/fancy/monochrome/New()
- . = ..()
- icon = 'icons/obj/smooth_structures/fancy_table_monochrome.dmi'
+/obj/structure/table/wood/fancy/blue
+ icon_state = "fancy_table_blue"
+ buildstack = /obj/item/stack/tile/carpet/blue
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_blue.dmi'
+
+/obj/structure/table/wood/fancy/cyan
+ icon_state = "fancy_table_cyan"
+ buildstack = /obj/item/stack/tile/carpet/cyan
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_cyan.dmi'
+
+/obj/structure/table/wood/fancy/green
+ icon_state = "fancy_table_green"
+ buildstack = /obj/item/stack/tile/carpet/green
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_green.dmi'
+
+/obj/structure/table/wood/fancy/orange
+ icon_state = "fancy_table_orange"
+ buildstack = /obj/item/stack/tile/carpet/orange
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_orange.dmi'
+
+/obj/structure/table/wood/fancy/purple
+ icon_state = "fancy_table_purple"
+ buildstack = /obj/item/stack/tile/carpet/purple
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_purple.dmi'
+
+/obj/structure/table/wood/fancy/red
+ icon_state = "fancy_table_red"
+ buildstack = /obj/item/stack/tile/carpet/red
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_red.dmi'
+
+/obj/structure/table/wood/fancy/royalblack
+ icon_state = "fancy_table_royalblack"
+ buildstack = /obj/item/stack/tile/carpet/royalblack
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_royalblack.dmi'
+
+/obj/structure/table/wood/fancy/royalblue
+ icon_state = "fancy_table_royalblue"
+ buildstack = /obj/item/stack/tile/carpet/royalblue
+ smooth_icon = 'icons/obj/smooth_structures/fancy_table_royalblue.dmi'
-/obj/structure/table/wood/fancy/black/New()
- . = ..()
- // Ditto above.
- icon = 'icons/obj/smooth_structures/fancy_table_black.dmi'
/*
* Reinforced tables
*/
diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm
index 7b45aa1f..ed6e2790 100644
--- a/code/game/turfs/simulated/floor/fancy_floor.dm
+++ b/code/game/turfs/simulated/floor/fancy_floor.dm
@@ -209,6 +209,46 @@
icon_state = "tile-carpet-monochrome"
canSmoothWith = list(/turf/open/floor/carpet/black, /turf/open/floor/carpet/blackred, /turf/open/floor/carpet/monochrome)
+/turf/open/floor/carpet/blue
+ icon = 'icons/turf/floors/carpet_blue.dmi'
+ floor_tile = /obj/item/stack/tile/carpet/blue
+ canSmoothWith = list(/turf/open/floor/carpet/blue)
+
+/turf/open/floor/carpet/cyan
+ icon = 'icons/turf/floors/carpet_cyan.dmi'
+ floor_tile = /obj/item/stack/tile/carpet/cyan
+ canSmoothWith = list(/turf/open/floor/carpet/cyan)
+
+/turf/open/floor/carpet/green
+ icon = 'icons/turf/floors/carpet_green.dmi'
+ floor_tile = /obj/item/stack/tile/carpet/green
+ canSmoothWith = list(/turf/open/floor/carpet/green)
+
+/turf/open/floor/carpet/orange
+ icon = 'icons/turf/floors/carpet_orange.dmi'
+ floor_tile = /obj/item/stack/tile/carpet/orange
+ canSmoothWith = list(/turf/open/floor/carpet/orange)
+
+/turf/open/floor/carpet/purple
+ icon = 'icons/turf/floors/carpet_purple.dmi'
+ floor_tile = /obj/item/stack/tile/carpet/purple
+ canSmoothWith = list(/turf/open/floor/carpet/purple)
+
+/turf/open/floor/carpet/red
+ icon = 'icons/turf/floors/carpet_red.dmi'
+ floor_tile = /obj/item/stack/tile/carpet/red
+ canSmoothWith = list(/turf/open/floor/carpet/red)
+
+/turf/open/floor/carpet/royalblack
+ icon = 'icons/turf/floors/carpet_royalblack.dmi'
+ floor_tile = /obj/item/stack/tile/carpet/royalblack
+ canSmoothWith = list(/turf/open/floor/carpet/royalblack)
+
+/turf/open/floor/carpet/royalblue
+ icon = 'icons/turf/floors/carpet_royalblue.dmi'
+ floor_tile = /obj/item/stack/tile/carpet/royalblue
+ canSmoothWith = list(/turf/open/floor/carpet/royalblue)
+
/turf/open/floor/carpet/narsie_act(force, ignore_mobs, probability = 20)
. = (prob(probability) || force)
for(var/I in src)
diff --git a/code/modules/antagonists/changeling/powers/chameleon_skin.dm b/code/modules/antagonists/changeling/powers/chameleon_skin.dm
index b7545353..03f3aab4 100644
--- a/code/modules/antagonists/changeling/powers/chameleon_skin.dm
+++ b/code/modules/antagonists/changeling/powers/chameleon_skin.dm
@@ -13,17 +13,14 @@
var/mob/living/carbon/human/H = user //SHOULD always be human, because req_human = 1
if(!istype(H)) // req_human could be done in can_sting stuff.
return
- var/datum/mutation/human/HM = GLOB.mutations_list[CHAMELEON]
- if(HM in H.dna.mutations)
- HM.force_lose(H)
+ if(H.dna.get_mutation(CHAMELEON))
+ H.dna.remove_mutation(CHAMELEON)
else
- HM.force_give(H)
+ H.dna.add_mutation(CHAMELEON)
return TRUE
/obj/effect/proc_holder/changeling/chameleon_skin/on_refund(mob/user)
action.Remove(user)
if(user.has_dna())
var/mob/living/carbon/C = user
- var/datum/mutation/human/HM = GLOB.mutations_list[CHAMELEON]
- if(HM in C.dna.mutations)
- HM.force_lose(C)
\ No newline at end of file
+ C.dna.remove_mutation(CHAMELEON)
\ No newline at end of file
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index 87794993..8da0546b 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -69,7 +69,7 @@
/mob/living/simple_animal/revenant/Initialize(mapload)
. = ..()
AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
- AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
+ AddSpell(new /obj/effect/proc_holder/spell/targeted/telepathy/revenant(null))
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/overload(null))
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/blight(null))
diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm
index 112a31f4..0cbe3102 100644
--- a/code/modules/antagonists/revenant/revenant_abilities.dm
+++ b/code/modules/antagonists/revenant/revenant_abilities.dm
@@ -104,35 +104,14 @@
action_background_icon_state = "bg_revenant"
//Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob
-/obj/effect/proc_holder/spell/targeted/revenant_transmit
- name = "Transmit"
- desc = "Telepathically transmits a message to the target."
+/obj/effect/proc_holder/spell/targeted/telepathy/revenant
+ name = "Revenant Transmit"
panel = "Revenant Abilities"
- charge_max = 0
- clothes_req = 0
- range = 7
- include_user = 0
action_icon = 'icons/mob/actions/actions_revenant.dmi'
action_icon_state = "r_transmit"
action_background_icon_state = "bg_revenant"
-
-/obj/effect/proc_holder/spell/targeted/revenant_transmit/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
- for(var/mob/living/M in targets)
- var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "")
- if(!msg)
- charge_counter = charge_max
- return
- log_directed_talk(user, M, msg, LOG_SAY, "revenant whisper")
- to_chat(user, "You transmit to [M]: [msg]")
- if(!M.anti_magic_check(FALSE, TRUE)) //hear no evil
- to_chat(M, "You hear something behind you talking... [msg]")
- for(var/ded in GLOB.dead_mob_list)
- if(!isobserver(ded))
- continue
- var/follow_rev = FOLLOW_LINK(ded, user)
- var/follow_whispee = FOLLOW_LINK(ded, M)
- to_chat(ded, "[follow_rev] [user] Revenant Transmit: \"[msg]\" to [follow_whispee] [M]")
-
+ notice = "revennotice"
+ boldnotice = "revenboldnotice"
/obj/effect/proc_holder/spell/aoe_turf/revenant
diff --git a/code/modules/antagonists/wishgranter/wishgranter.dm b/code/modules/antagonists/wishgranter/wishgranter.dm
index 318de51e..196ce955 100644
--- a/code/modules/antagonists/wishgranter/wishgranter.dm
+++ b/code/modules/antagonists/wishgranter/wishgranter.dm
@@ -26,5 +26,5 @@
return
H.dna.add_mutation(HULK)
H.dna.add_mutation(XRAY)
- H.dna.add_mutation(COLDRES)
+ H.dna.add_mutation(SPACEMUT)
H.dna.add_mutation(TK)
\ No newline at end of file
diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm
index ac1a4077..505b9a1e 100644
--- a/code/modules/awaymissions/mission_code/wildwest.dm
+++ b/code/modules/awaymissions/mission_code/wildwest.dm
@@ -94,7 +94,7 @@
to_chat(user, "Your wish is granted, but at a terrible cost...")
to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart.")
user.dna.add_mutation(LASEREYES)
- user.dna.add_mutation(COLDRES)
+ user.dna.add_mutation(SPACEMUT)
user.dna.add_mutation(XRAY)
user.set_species(/datum/species/shadow)
if("Wealth")
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 1087f1eb..fa28da74 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -1762,15 +1762,31 @@
/obj/item/stack/tile/carpet/black/fifty)
crate_name = "premium carpet crate"
-/datum/supply_pack/service/carpet2
- name = "Premium Carpet Crate #2"
- desc = "Plasteel floor tiles getting on your nerves? These stacks of extra soft carpet will tie any room together. Contains red, and monochrome"
- cost = 1000
- contains = list(/obj/item/stack/tile/carpet/blackred/fifty,
+/datum/supply_pack/service/carpet_exotic
+ name = "Exotic Carpet Crate"
+ desc = "Exotic carpets straight from Space Russia, for all your decorating needs. Contains 100 tiles each of 10 different flooring patterns."
+ cost = 4000
+ contains = list(/obj/item/stack/tile/carpet/blue/fifty,
+ /obj/item/stack/tile/carpet/blue/fifty,
+ /obj/item/stack/tile/carpet/cyan/fifty,
+ /obj/item/stack/tile/carpet/cyan/fifty,
+ /obj/item/stack/tile/carpet/green/fifty,
+ /obj/item/stack/tile/carpet/green/fifty,
+ /obj/item/stack/tile/carpet/orange/fifty,
+ /obj/item/stack/tile/carpet/orange/fifty,
+ /obj/item/stack/tile/carpet/purple/fifty,
+ /obj/item/stack/tile/carpet/purple/fifty,
+ /obj/item/stack/tile/carpet/red/fifty,
+ /obj/item/stack/tile/carpet/red/fifty,
+ /obj/item/stack/tile/carpet/royalblue/fifty,
+ /obj/item/stack/tile/carpet/royalblue/fifty,
+ /obj/item/stack/tile/carpet/royalblack/fifty,
+ /obj/item/stack/tile/carpet/royalblack/fifty,
+ /obj/item/stack/tile/carpet/blackred/fifty,
/obj/item/stack/tile/carpet/blackred/fifty,
/obj/item/stack/tile/carpet/monochrome/fifty,
/obj/item/stack/tile/carpet/monochrome/fifty)
- crate_name = "premium carpet crate #2"
+ crate_name = "exotic carpet crate"
/datum/supply_pack/service/lightbulbs
name = "Replacement Lights"
diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm
index 0ff87c03..0b83304f 100644
--- a/code/modules/client/asset_cache.dm
+++ b/code/modules/client/asset_cache.dm
@@ -677,3 +677,11 @@ GLOBAL_LIST_EMPTY(asset_datums)
Insert(initial(D.id), I)
return ..()
+
+
+/datum/asset/simple/genetics
+ assets = list(
+ "dna_discovered.gif" = 'html/dna_discovered.gif',
+ "dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
+ "dna_extra.gif" = 'html/dna_extra.gif'
+)
\ No newline at end of file
diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm
index 96b5c8e2..4800b61f 100644
--- a/code/modules/events/disease_outbreak.dm
+++ b/code/modules/events/disease_outbreak.dm
@@ -57,7 +57,7 @@
var/datum/disease/dnaspread/DS = D
DS.strain_data["name"] = H.real_name
DS.strain_data["UI"] = H.dna.uni_identity
- DS.strain_data["SE"] = H.dna.struc_enzymes
+ DS.strain_data["SE"] = H.dna.mutation_index
else
D = new virus_type()
else
diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm
index 9373b5ad..d57615d2 100644
--- a/code/modules/jobs/job_types/medical.dm
+++ b/code/modules/jobs/job_types/medical.dm
@@ -164,6 +164,7 @@ Geneticist
shoes = /obj/item/clothing/shoes/sneakers/white
suit = /obj/item/clothing/suit/toggle/labcoat/genetics
suit_store = /obj/item/flashlight/pen
+ l_pocket = /obj/item/sequence_scanner
backpack = /obj/item/storage/backpack/genetics
satchel = /obj/item/storage/backpack/satchel/gen
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index f12b6b7e..a25ce336 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -453,7 +453,7 @@
/obj/item/immortality_talisman/Initialize()
. = ..()
- AddComponent(/datum/component/anti_magic, TRUE, TRUE)
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, TRUE)
/datum/action/item_action/immortality
name = "Immortality"
@@ -462,30 +462,45 @@
if(cooldown < world.time)
SSblackbox.record_feedback("amount", "immortality_talisman_uses", 1)
cooldown = world.time + 600
- user.visible_message("[user] vanishes from reality, leaving a hole in [user.p_their()] place!")
- var/obj/effect/immortality_talisman/Z = new(get_turf(src.loc))
- Z.name = "hole in reality"
- Z.desc = "It's shaped an awful lot like [user.name]."
- Z.setDir(user.dir)
- user.forceMove(Z)
- user.notransform = 1
- user.status_flags |= GODMODE
- addtimer(CALLBACK(src, .proc/return_to_reality, user, Z), 100)
+ new /obj/effect/immortality_talisman(get_turf(user), user)
else
to_chat(user, "[src] is not ready yet!")
-/obj/item/immortality_talisman/proc/return_to_reality(mob/user, obj/effect/immortality_talisman/Z)
- user.status_flags &= ~GODMODE
- user.notransform = 0
- user.forceMove(get_turf(Z))
- user.visible_message("[user] pops back into reality!")
- Z.can_destroy = TRUE
- qdel(Z)
-
/obj/effect/immortality_talisman
+ name = "hole in reality"
+ desc = "It's shaped an awful lot like a person."
icon_state = "blank"
icon = 'icons/effects/effects.dmi'
- var/can_destroy = FALSE
+ var/vanish_description = "vanishes from reality"
+ var/can_destroy = TRUE
+
+/obj/effect/immortality_talisman/Initialize(mapload, mob/new_user)
+ . = ..()
+ if(new_user)
+ vanish(new_user)
+
+/obj/effect/immortality_talisman/proc/vanish(mob/user)
+ user.visible_message("[user] [vanish_description], leaving a hole in [user.p_their()] place!")
+
+ desc = "It's shaped an awful lot like [user.name]."
+ setDir(user.dir)
+
+ user.forceMove(src)
+ user.notransform = TRUE
+ user.status_flags |= GODMODE
+
+ can_destroy = FALSE
+
+ addtimer(CALLBACK(src, .proc/unvanish, user), 10 SECONDS)
+
+/obj/effect/immortality_talisman/proc/unvanish(mob/user)
+ user.status_flags &= ~GODMODE
+ user.notransform = FALSE
+ user.forceMove(get_turf(src))
+
+ user.visible_message("[user] pops back into reality!")
+ can_destroy = TRUE
+ qdel(src)
/obj/effect/immortality_talisman/attackby()
return
@@ -502,6 +517,10 @@
else
. = ..()
+/obj/effect/immortality_talisman/void
+ vanish_description = "is dragged into the void"
+
+
//Shared Bag
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index a118dc78..89a7ec25 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -603,6 +603,14 @@
sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
see_in_dark = max(see_in_dark, 8)
+ if(HAS_TRAIT(src, TRAIT_THERMAL_VISION))
+ sight |= (SEE_MOBS)
+ lighting_alpha = min(lighting_alpha, LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE)
+
+ if(HAS_TRAIT(src, TRAIT_XRAY_VISION))
+ sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
+ see_in_dark = max(see_in_dark, 8)
+
if(see_override)
see_invisible = see_override
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 33b419de..eb91858b 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -44,6 +44,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/siemens_coeff = 1 //base electrocution coefficient
var/damage_overlay_type = "human" //what kind of damage overlays (if any) appear on our species when wounded?
var/fixed_mut_color = "" //to use MUTCOLOR with a fixed color that's independent of dna.feature["mcolor"]
+ var/inert_mutation = DWARFISM //special mutation that can be found in the genepool. Dont leave empty or changing species will be a headache
var/list/special_step_sounds //Sounds to override barefeet walkng
var/grab_sound //Special sound for grabbing
@@ -317,6 +318,14 @@ GLOBAL_LIST_EMPTY(roundstart_races)
for(var/X in inherent_traits)
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
+ //If their inert mutation is not the same, swap it out
+ if((inert_mutation != new_species.inert_mutation) && LAZYLEN(C.dna.mutation_index) && (inert_mutation in C.dna.mutation_index))
+ C.dna.remove_mutation(inert_mutation)
+ //keep it at the right spot, so we can't have people taking shortcuts
+ var/location = C.dna.mutation_index.Find(inert_mutation)
+ C.dna.mutation_index[location] = new_species.inert_mutation
+ C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation)
+
SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
@@ -1270,7 +1279,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(radiation > RAD_MOB_MUTATE)
if(prob(1))
to_chat(H, "You mutate!")
- H.randmutb()
+ H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
H.emote("gasp")
H.domutcheck()
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 9b2e2ad5..8d448592 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -20,6 +20,7 @@
exotic_bloodtype = "L"
disliked_food = GRAIN | DAIRY
liked_food = GROSS | MEAT
+ inert_mutation = FIREBREATH
/datum/species/lizard/after_equip_job(datum/job/J, mob/living/carbon/human/H)
H.grant_language(/datum/language/draconic)
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index 0da4073f..fbe18a6c 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -60,9 +60,9 @@
H.Knockdown(100)
H.visible_message("[H] writhes in pain as [H.p_their()] vacuoles boil.", "You writhe in pain as your vacuoles boil!", "You hear the crunching of leaves.")
if(prob(80))
- H.randmutb()
+ H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
else
- H.randmutg()
+ H.easy_randmut(POSITIVE)
H.domutcheck()
else
H.adjustFireLoss(rand(5,15))
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index de542754..1c2234bb 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -419,7 +419,6 @@
/mob/living/carbon/handle_mutations_and_radiation()
if(dna && dna.temporary_mutations.len)
- var/datum/mutation/human/HM
for(var/mut in dna.temporary_mutations)
if(dna.temporary_mutations[mut] < world.time)
if(mut == UI_CHANGED)
@@ -442,9 +441,9 @@
dna.previous.Remove("blood_type")
dna.temporary_mutations.Remove(mut)
continue
- HM = GLOB.mutations_list[mut]
- HM.force_lose(src)
- dna.temporary_mutations.Remove(mut)
+ for(var/datum/mutation/human/HM in dna.mutations)
+ if(HM && HM.timed)
+ dna.remove_mutation(HM.type)
radiation -= min(radiation, RAD_LOSS_PER_TICK)
if(radiation > RAD_MOB_SAFE)
diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm
index e0386bcd..be7d90c1 100644
--- a/code/modules/mob/living/carbon/monkey/life.dm
+++ b/code/modules/mob/living/carbon/monkey/life.dm
@@ -38,7 +38,7 @@
if(radiation > RAD_MOB_MUTATE)
if(prob(1))
to_chat(src, "You mutate!")
- randmutb()
+ easy_randmut(NEGATIVE+MINOR_NEGATIVE)
emote("gasp")
domutcheck()
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index e6f79198..65947711 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -50,9 +50,8 @@
O.updateappearance(icon_update=0)
if(tr_flags & TR_KEEPSE)
- O.dna.struc_enzymes = dna.struc_enzymes
- var/datum/mutation/human/race/R = GLOB.mutations_list[RACEMUT]
- O.dna.struc_enzymes = R.set_se(O.dna.struc_enzymes, on=1)//we don't want to keep the race block inactive
+ O.dna.mutation_index = dna.mutation_index
+ O.dna.set_se(1, GET_INITIALIZED_MUTATION(RACEMUT))
if(suiciding)
O.suiciding = suiciding
@@ -210,9 +209,8 @@
O.name = O.real_name
if(tr_flags & TR_KEEPSE)
- O.dna.struc_enzymes = dna.struc_enzymes
- var/datum/mutation/human/race/R = GLOB.mutations_list[RACEMUT]
- O.dna.struc_enzymes = R.set_se(O.dna.struc_enzymes, on=0)//we don't want to keep the race block active
+ O.dna.mutation_index = dna.mutation_index
+ O.dna.set_se(0, GET_INITIALIZED_MUTATION(RACEMUT))
O.domutcheck()
if(suiciding)
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index 0ad83652..b85de2e7 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -913,7 +913,7 @@
/datum/reagent/medicine/mutadone/on_mob_life(mob/living/carbon/M)
M.jitteriness = 0
if(M.has_dna())
- M.dna.remove_all_mutations()
+ M.dna.remove_all_mutations(mutadone = TRUE)
if(!QDELETED(M)) //We were a monkey, now a human
..()
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index fe309b42..b97e0e62 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1537,20 +1537,6 @@
taste_description = "metal"
pH = 4.5
-/datum/reagent/carpet
- name = "Carpet"
- id = "carpet"
- description = "For those that need a more creative way to roll out a red carpet."
- reagent_state = LIQUID
- color = "#b51d05"
- taste_description = "carpet" // Your tounge feels furry.
-
-/datum/reagent/carpet/reaction_turf(turf/T, reac_volume)
- if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
- var/turf/open/floor/F = T
- F.PlaceOnTop(/turf/open/floor/carpet)
- ..()
-
/datum/reagent/bromine
name = "Bromine"
id = "bromine"
@@ -1704,6 +1690,142 @@
qdel(O)
new /obj/item/clothing/shoes/galoshes/dry(t_loc)
+// Liquid Carpets
+/datum/reagent/carpet
+ name = "Liquid Carpet"
+ id = "carpet"
+ description = "For those that need a more creative way to roll out a carpet."
+ reagent_state = LIQUID
+ color = "#b51d05"
+ taste_description = "carpet" // Your tounge feels furry.
+
+/datum/reagent/carpet/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet)
+ ..()
+
+/datum/reagent/carpet/black
+ name = "Liquid Black Carpet"
+ id = "blackcarpet"
+ color = "#363636"
+
+/datum/reagent/carpet/black/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/black)
+ ..()
+
+/datum/reagent/carpet/blackred
+ name = "Liquid Red Black Carpet"
+ id = "blackredcarpet"
+ color = "#342125"
+
+/datum/reagent/carpet/blackred/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/blackred)
+ ..()
+
+/datum/reagent/carpet/monochrome
+ name = "Liquid Monochrome Carpet"
+ id = "monochromecarpet"
+ color = "#b4b4b4"
+
+/datum/reagent/carpet/monochrome/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/monochrome)
+ ..()
+
+/datum/reagent/carpet/blue
+ name = "Liquid Blue Carpet"
+ id = "bluecarpet"
+ color = "#1256ff"
+
+/datum/reagent/carpet/blue/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/blue)
+ ..()
+
+/datum/reagent/carpet/cyan
+ name = "Liquid Cyan Carpet"
+ id = "cyancarpet"
+ color = "#3acfb9"
+
+/datum/reagent/carpet/cyan/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/cyan)
+ ..()
+
+/datum/reagent/carpet/green
+ name = "Liquid Green Carpet"
+ id = "greencarpet"
+ color = "#619b62"
+
+/datum/reagent/carpet/green/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/green)
+ ..()
+
+/datum/reagent/carpet/orange
+ name = "Liquid Orange Carpet"
+ id = "orangecarpet"
+ color = "#cc7900"
+
+/datum/reagent/carpet/orange/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/orange)
+ ..()
+
+/datum/reagent/carpet/purple
+ name = "Liquid Purple Carpet"
+ id = "purplecarpet"
+ color = "#6d3392"
+
+/datum/reagent/carpet/purple/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/purple)
+ ..()
+
+/datum/reagent/carpet/red
+ name = "Liquid Red Carpet"
+ id = "redcarpet"
+ color = "#871515"
+
+/datum/reagent/carpet/red/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/red)
+ ..()
+
+/datum/reagent/carpet/royalblack
+ name = "Liquid Royal Black Carpet"
+ id = "royalblackcarpet"
+ color = "#483d05"
+
+/datum/reagent/carpet/royalblack/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/royalblack)
+ ..()
+
+/datum/reagent/carpet/royalblue
+ name = "Liquid Royal Blue Carpet"
+ id = "royalbluecarpet"
+ color = "#24227e"
+
+/datum/reagent/carpet/royalblue/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/carpet/royalblue)
+ ..()
+
// Virology virus food chems.
/datum/reagent/toxin/mutagen/mutagenvirusfood
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 2b50ecc0..c38bbfed 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -43,9 +43,9 @@
if((method==VAPOR && prob(min(33, reac_volume))) || method==INGEST || method==PATCH || method==INJECT)
M.randmuti()
if(prob(98))
- M.randmutb()
+ M.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
else
- M.randmutg()
+ M.easy_randmut(POSITIVE)
M.updateappearance()
M.domutcheck()
..()
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index e34f3467..a1e17e51 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -488,12 +488,6 @@
results = list("acetone" = 3)
required_reagents = list("oil" = 1, "welding_fuel" = 1, "oxygen" = 1)
-/datum/chemical_reaction/carpet
- name = "carpet"
- id = "carpet"
- results = list("carpet" = 2)
- required_reagents = list("space_drugs" = 1, "blood" = 1)
-
/datum/chemical_reaction/oil
name = "Oil"
id = "oil"
@@ -635,3 +629,77 @@
results = list("shadowmutationtoxin" = 1)
required_reagents = list("liquid_dark_matter" = 5, "synaptizine" = 10, "oculine" = 10, "stablemutationtoxin" = 1)
required_temp = 600
+
+// Liquid Carpets
+
+/datum/chemical_reaction/carpet
+ name = "carpet"
+ id = "carpet"
+ results = list("carpet" = 2)
+ required_reagents = list("space_drugs" = 1, "blood" = 1)
+
+/datum/chemical_reaction/carpet/black
+ name = "liquid black carpet"
+ id = "blackcarpet"
+ results = list("blackcarpet" = 2)
+ required_reagents = list("carpet" = 1, "carbon" = 1)
+
+/datum/chemical_reaction/carpet/blackred
+ name = "liquid red black carpet"
+ id = "blackredcarpet"
+ results = list("blackredcarpet" = 2)
+ required_reagents = list("carpet" = 1, "charcoal" = 1)
+
+/datum/chemical_reaction/carpet/monochrome
+ name = "liquid monochrome carpet"
+ id = "monochromecarpet"
+ results = list("monochromecarpet" = 2)
+ required_reagents = list("carpet" = 1, "oil" = 1)
+
+/datum/chemical_reaction/carpet/blue
+ name = "liquid blue carpet"
+ id = "bluecarpet"
+ results = list("bluecarpet" = 2)
+ required_reagents = list("carpet" = 1, "tonic" = 1)
+
+/datum/chemical_reaction/carpet/cyan
+ name = "liquid cyan carpet"
+ id = "cyancarpet"
+ results = list("cyancarpet" = 2)
+ required_reagents = list("carpet" = 1, "ice" = 1)
+
+/datum/chemical_reaction/carpet/green
+ name = "liquid green carpet"
+ id = "greencarpet"
+ results = list("greencarpet" = 2)
+ required_reagents = list("carpet" = 1, "sacid" = 1)
+
+/datum/chemical_reaction/carpet/orange
+ name = "liquid orange carpet"
+ id = "orangecarpet"
+ results = list("orangecarpet" = 2)
+ required_reagents = list("carpet" = 1, "orangejuice" = 1)
+
+/datum/chemical_reaction/carpet/purple
+ name = "liquid purple carpet"
+ id = "purplecarpet"
+ results = list("purplecarpet" = 2)
+ required_reagents = list("carpet" = 1, "stable_plasma" = 1)
+
+/datum/chemical_reaction/carpet/red
+ name = "liquid red carpet"
+ id = "redcarpet"
+ results = list("redcarpet" = 2)
+ required_reagents = list("carpet" = 1, "welding_fuel" = 1)
+
+/datum/chemical_reaction/carpet/royalblack
+ name = "liquid royal black carpet"
+ id = "royalblackcarpet"
+ results = list("royalblackcarpet" = 2)
+ required_reagents = list("carpet" = 1, "blackpepper" = 1)
+
+/datum/chemical_reaction/carpet/royalblue
+ name = "liquid royal blue carpet"
+ id = "royalbluecarpet"
+ results = list("royalbluecarpet" = 2)
+ required_reagents = list("carpet" = 1, "clonexadone" = 1)
\ No newline at end of file
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 580f9c87..5a8fc03d 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -162,6 +162,16 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/datum/design/genescanner
+ name = "Genetic Sequence Analyzer"
+ desc = "A handy hand-held analyzers for quickly determining mutations and collecting the full sequence."
+ id = "genescanner"
+ build_path = /obj/item/sequence_scanner
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 1000, MAT_GLASS = 500)
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
/datum/design/healthanalyzer_advanced
name = "Advanced Health Analyzer"
desc = "A hand-held body scanner able to distinguish vital signs of the subject with high accuracy."
diff --git a/code/modules/research/techweb/_techweb.dm b/code/modules/research/techweb/_techweb.dm
index da3fec61..42cd5ff1 100644
--- a/code/modules/research/techweb/_techweb.dm
+++ b/code/modules/research/techweb/_techweb.dm
@@ -19,6 +19,7 @@
var/largest_bomb_value = 0
var/organization = "Third-Party" //Organization name, used for display.
var/list/last_bitcoins = list() //Current per-second production, used for display only.
+ var/list/discovered_mutations = list() //Mutations discovered by genetics, this way they are shared and cant be destroyed by destroying a single console
var/list/tiers = list() //Assoc list, datum = number, 1 is available, 2 is all reqs are 1, so on
/datum/techweb/New()
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 5f848ce8..1349fd23 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -60,7 +60,7 @@
display_name = "Biological Technology"
description = "What makes us tick." //the MC, silly!
prereq_ids = list("base")
- design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag")
+ design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag","genescanner")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
diff --git a/code/modules/spells/spell_types/genetic.dm b/code/modules/spells/spell_types/genetic.dm
index b670d93f..c3bdc74e 100644
--- a/code/modules/spells/spell_types/genetic.dm
+++ b/code/modules/spells/spell_types/genetic.dm
@@ -4,7 +4,7 @@
var/list/active_on = list()
var/list/traits = list() //disabilities
- var/list/mutations = list() //mutation strings
+ var/list/mutations = list() //mutation defines
var/duration = 100 //deciseconds
/*
Disabilities
diff --git a/code/modules/spells/spell_types/telepathy.dm b/code/modules/spells/spell_types/telepathy.dm
new file mode 100644
index 00000000..db7e284e
--- /dev/null
+++ b/code/modules/spells/spell_types/telepathy.dm
@@ -0,0 +1,30 @@
+/obj/effect/proc_holder/spell/targeted/telepathy
+ name = "Telepathy"
+ desc = "Telepathically transmits a message to the target."
+ charge_max = 0
+ clothes_req = 0
+ range = 7
+ include_user = 0
+ action_icon = 'icons/mob/actions/actions_revenant.dmi'
+ action_icon_state = "r_transmit"
+ action_background_icon_state = "bg_spell"
+ var/notice = "notice"
+ var/boldnotice = "boldnotice"
+ var/magic_check = TRUE
+
+/obj/effect/proc_holder/spell/targeted/telepathy/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
+ for(var/mob/living/M in targets)
+ var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "")
+ if(!msg)
+ charge_counter = charge_max
+ return
+ log_directed_talk(user, M, msg, LOG_SAY, "[name]")
+ to_chat(user, "You transmit to [M]: [msg]")
+ if(!magic_check || !M.anti_magic_check(FALSE, TRUE)) //hear no evil
+ to_chat(M, "You hear something behind you talking... [msg]")
+ for(var/ded in GLOB.dead_mob_list)
+ if(!isobserver(ded))
+ continue
+ var/follow_rev = FOLLOW_LINK(ded, user)
+ var/follow_whispee = FOLLOW_LINK(ded, M)
+ to_chat(ded, "[follow_rev] [user] [name]: \"[msg]\" to [follow_whispee] [M]")
\ No newline at end of file
diff --git a/code/modules/spells/spell_types/touch_attacks.dm b/code/modules/spells/spell_types/touch_attacks.dm
index 0ffe02ce..f0a9735c 100644
--- a/code/modules/spells/spell_types/touch_attacks.dm
+++ b/code/modules/spells/spell_types/touch_attacks.dm
@@ -1,6 +1,8 @@
/obj/effect/proc_holder/spell/targeted/touch
var/hand_path = /obj/item/melee/touch_attack
var/obj/item/melee/touch_attack/attached_hand = null
+ var/drawmessage = "You channel the power of the spell to your hand."
+ var/dropmessage = "You draw the power out of your hand."
invocation_type = "none" //you scream on connecting, not summoning
include_user = 1
range = -1
@@ -21,7 +23,7 @@
/obj/effect/proc_holder/spell/targeted/touch/cast(list/targets,mob/user = usr)
if(!QDELETED(attached_hand))
remove_hand(TRUE)
- to_chat(user, "You draw the power out of your hand.")
+ to_chat(user, "[dropmessage]")
return
for(var/mob/living/carbon/C in targets)
@@ -43,7 +45,7 @@
remove_hand(TRUE)
to_chat(user, "Your hands are full!")
return FALSE
- to_chat(user, "You channel the power of the spell to your hand.")
+ to_chat(user, "[drawmessage]")
return TRUE
diff --git a/code/modules/surgery/advanced/toxichealing.dm b/code/modules/surgery/advanced/toxichealing.dm
index 998ca47b..ae43b3d5 100644
--- a/code/modules/surgery/advanced/toxichealing.dm
+++ b/code/modules/surgery/advanced/toxichealing.dm
@@ -17,7 +17,7 @@
/datum/surgery_step/toxichealing
name = "rejuvenate body"
- implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
+ implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
repeatable = TRUE
time = 25
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 9341fb6c..4e2b81dc 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -108,7 +108,7 @@
for(var/X in C.dna.mutations) //some mutations require having specific limbs to be kept.
var/datum/mutation/human/MT = X
if(MT.limb_req && MT.limb_req == body_zone)
- MT.force_lose(C)
+ C.dna.force_lose(MT)
for(var/X in C.internal_organs) //internal organs inside the dismembered limb are dropped.
var/obj/item/organ/O = X
diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm
index 5aeeb322..a98f419a 100644
--- a/code/modules/surgery/coronary_bypass.dm
+++ b/code/modules/surgery/coronary_bypass.dm
@@ -15,7 +15,7 @@
//an incision but with greater bleed, and a 90% base success chance
/datum/surgery_step/incise_heart
name = "incise heart"
- implements = list(TOOL_SCALPEL = 90, /obj/item/melee/transforming/energy/sword = 45, /obj/item/kitchen/knife = 45,
+ implements = list(/obj/item/scalpel = 100, /obj/item/melee/transforming/energy/sword = 45, /obj/item/kitchen/knife = 45,
/obj/item/shard = 25)
time = 16
diff --git a/code/modules/surgery/embalming.dm b/code/modules/surgery/embalming.dm
index d65abc9d..45f02af5 100644
--- a/code/modules/surgery/embalming.dm
+++ b/code/modules/surgery/embalming.dm
@@ -11,9 +11,9 @@
/datum/surgery_step/embalming
name = "embalming body"
- implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30)
+ implements = list(/obj/item/hemostat = 100)
time = 10
- chems_needed = list("drying_agent", "sterilizine")
+ chems_needed = list("drying_agent","formaldehyde")
require_all_chems = FALSE
/datum/surgery_step/embalming/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/html/browser/scannernew.css b/html/browser/scannernew.css
index 0e809a67..6746a61a 100644
--- a/html/browser/scannernew.css
+++ b/html/browser/scannernew.css
@@ -16,3 +16,24 @@
float: left;
}
+img.selected
+{
+ border: 1px solid blue;
+}
+img.unselected
+{
+ border: 2px solid black;
+}
+div>table {
+ float: left;
+}
+td
+{
+ text-align: center;
+}
+a.clean
+{
+ background: none;
+ border: none;
+ marging: none;
+}
\ No newline at end of file
diff --git a/html/dna_discovered.gif b/html/dna_discovered.gif
new file mode 100644
index 00000000..bc6b75f2
Binary files /dev/null and b/html/dna_discovered.gif differ
diff --git a/html/dna_extra.gif b/html/dna_extra.gif
new file mode 100644
index 00000000..c92218a6
Binary files /dev/null and b/html/dna_extra.gif differ
diff --git a/html/dna_undiscovered.gif b/html/dna_undiscovered.gif
new file mode 100644
index 00000000..a3c182a4
Binary files /dev/null and b/html/dna_undiscovered.gif differ
diff --git a/icons/effects/genetics.dmi b/icons/effects/genetics.dmi
index a9f5f433..373a9de6 100644
Binary files a/icons/effects/genetics.dmi and b/icons/effects/genetics.dmi differ
diff --git a/icons/mob/actions/actions_genetic.dmi b/icons/mob/actions/actions_genetic.dmi
new file mode 100644
index 00000000..72bd87f9
Binary files /dev/null and b/icons/mob/actions/actions_genetic.dmi differ
diff --git a/icons/mob/actions/actions_spells.dmi b/icons/mob/actions/actions_spells.dmi
index 30927d36..5617e228 100644
Binary files a/icons/mob/actions/actions_spells.dmi and b/icons/mob/actions/actions_spells.dmi differ
diff --git a/icons/mob/inhands/misc/tiles_lefthand.dmi b/icons/mob/inhands/misc/tiles_lefthand.dmi
new file mode 100644
index 00000000..d7903fcd
Binary files /dev/null and b/icons/mob/inhands/misc/tiles_lefthand.dmi differ
diff --git a/icons/mob/inhands/misc/tiles_righthand.dmi b/icons/mob/inhands/misc/tiles_righthand.dmi
new file mode 100644
index 00000000..9295ac73
Binary files /dev/null and b/icons/mob/inhands/misc/tiles_righthand.dmi differ
diff --git a/icons/obj/chromosomes.dmi b/icons/obj/chromosomes.dmi
new file mode 100644
index 00000000..a8ff6186
Binary files /dev/null and b/icons/obj/chromosomes.dmi differ
diff --git a/icons/obj/smooth_structures/fancy_table_blue.dmi b/icons/obj/smooth_structures/fancy_table_blue.dmi
new file mode 100644
index 00000000..07e13e99
Binary files /dev/null and b/icons/obj/smooth_structures/fancy_table_blue.dmi differ
diff --git a/icons/obj/smooth_structures/fancy_table_cyan.dmi b/icons/obj/smooth_structures/fancy_table_cyan.dmi
new file mode 100644
index 00000000..4f1a90e3
Binary files /dev/null and b/icons/obj/smooth_structures/fancy_table_cyan.dmi differ
diff --git a/icons/obj/smooth_structures/fancy_table_green.dmi b/icons/obj/smooth_structures/fancy_table_green.dmi
new file mode 100644
index 00000000..ea7f8daa
Binary files /dev/null and b/icons/obj/smooth_structures/fancy_table_green.dmi differ
diff --git a/icons/obj/smooth_structures/fancy_table_orange.dmi b/icons/obj/smooth_structures/fancy_table_orange.dmi
new file mode 100644
index 00000000..fe0375dd
Binary files /dev/null and b/icons/obj/smooth_structures/fancy_table_orange.dmi differ
diff --git a/icons/obj/smooth_structures/fancy_table_purple.dmi b/icons/obj/smooth_structures/fancy_table_purple.dmi
new file mode 100644
index 00000000..c404a9eb
Binary files /dev/null and b/icons/obj/smooth_structures/fancy_table_purple.dmi differ
diff --git a/icons/obj/smooth_structures/fancy_table_red.dmi b/icons/obj/smooth_structures/fancy_table_red.dmi
new file mode 100644
index 00000000..8bca0ca8
Binary files /dev/null and b/icons/obj/smooth_structures/fancy_table_red.dmi differ
diff --git a/icons/obj/smooth_structures/fancy_table_royalblack.dmi b/icons/obj/smooth_structures/fancy_table_royalblack.dmi
new file mode 100644
index 00000000..064b7c19
Binary files /dev/null and b/icons/obj/smooth_structures/fancy_table_royalblack.dmi differ
diff --git a/icons/obj/smooth_structures/fancy_table_royalblue.dmi b/icons/obj/smooth_structures/fancy_table_royalblue.dmi
new file mode 100644
index 00000000..9d0eba72
Binary files /dev/null and b/icons/obj/smooth_structures/fancy_table_royalblue.dmi differ
diff --git a/icons/obj/smooth_structures/plasmaglass_table.dmi b/icons/obj/smooth_structures/plasmaglass_table.dmi
new file mode 100644
index 00000000..808e79aa
Binary files /dev/null and b/icons/obj/smooth_structures/plasmaglass_table.dmi differ
diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi
index 2e1fdfa7..8650e7be 100644
Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ
diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi
index 9305e4b7..3aa6912d 100644
Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ
diff --git a/icons/turf/floors/carpet_blue.dmi b/icons/turf/floors/carpet_blue.dmi
new file mode 100644
index 00000000..f797be97
Binary files /dev/null and b/icons/turf/floors/carpet_blue.dmi differ
diff --git a/icons/turf/floors/carpet_cyan.dmi b/icons/turf/floors/carpet_cyan.dmi
new file mode 100644
index 00000000..feca351c
Binary files /dev/null and b/icons/turf/floors/carpet_cyan.dmi differ
diff --git a/icons/turf/floors/carpet_green.dmi b/icons/turf/floors/carpet_green.dmi
new file mode 100644
index 00000000..fdd1f071
Binary files /dev/null and b/icons/turf/floors/carpet_green.dmi differ
diff --git a/icons/turf/floors/carpet_orange.dmi b/icons/turf/floors/carpet_orange.dmi
new file mode 100644
index 00000000..ddf239b6
Binary files /dev/null and b/icons/turf/floors/carpet_orange.dmi differ
diff --git a/icons/turf/floors/carpet_purple.dmi b/icons/turf/floors/carpet_purple.dmi
new file mode 100644
index 00000000..c1f40ec7
Binary files /dev/null and b/icons/turf/floors/carpet_purple.dmi differ
diff --git a/icons/turf/floors/carpet_red.dmi b/icons/turf/floors/carpet_red.dmi
new file mode 100644
index 00000000..92665568
Binary files /dev/null and b/icons/turf/floors/carpet_red.dmi differ
diff --git a/icons/turf/floors/carpet_royalblack.dmi b/icons/turf/floors/carpet_royalblack.dmi
new file mode 100644
index 00000000..bc5cef1c
Binary files /dev/null and b/icons/turf/floors/carpet_royalblack.dmi differ
diff --git a/icons/turf/floors/carpet_royalblue.dmi b/icons/turf/floors/carpet_royalblue.dmi
new file mode 100644
index 00000000..841e49e9
Binary files /dev/null and b/icons/turf/floors/carpet_royalblue.dmi differ
diff --git a/interface/menu.dm b/interface/menu.dm
index 0d1313b0..59371cd1 100644
--- a/interface/menu.dm
+++ b/interface/menu.dm
@@ -81,14 +81,16 @@ GLOBAL_LIST_EMPTY(menulist)
default = /datum/verbs/menu/Settings/FPS/verb/high
/datum/verbs/menu/Settings/FPS/verb/low()
- set name = "LowFPS"
+ set name = "Low-end FPS"
set desc = "&20 fps"
+ set category = "Preferences"
usr.client.prefs.clientfps = 20
usr.client.prefs.parent.fps = 20
/datum/verbs/menu/Settings/FPS/verb/high()
- set name = "HighFPS"
+ set name = "High-end FPS"
set desc = "&30 fps (High-end machines)"
+ set category = "Preferences"
usr.client.prefs.clientfps = 30
usr.client.prefs.parent.fps = 30
diff --git a/modular_citadel/code/game/machinery/wishgranter.dm b/modular_citadel/code/game/machinery/wishgranter.dm
index f24062a1..6121893c 100644
--- a/modular_citadel/code/game/machinery/wishgranter.dm
+++ b/modular_citadel/code/game/machinery/wishgranter.dm
@@ -17,7 +17,7 @@
to_chat(user, "Your head pounds for a moment, before your vision clears. The Wish Granter, sensing the darkness in your heart, has given you limitless power, and it's all yours!")
user.dna.add_mutation(HULK)
user.dna.add_mutation(XRAY)
- user.dna.add_mutation(COLDRES)
+ user.dna.add_mutation(SPACEMUT)
user.dna.add_mutation(TK)
user.next_move_modifier *= 0.5 //half the delay between attacks!
to_chat(user, "Things around you feel slower!")
diff --git a/tgstation.dme b/tgstation.dme
index 00a38b10..54144212 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -115,6 +115,7 @@
#include "code\__HELPERS\AStar.dm"
#include "code\__HELPERS\cmp.dm"
#include "code\__HELPERS\dates.dm"
+#include "code\__HELPERS\dna.dm"
#include "code\__HELPERS\files.dm"
#include "code\__HELPERS\game.dm"
#include "code\__HELPERS\global_lists.dm"
@@ -468,10 +469,14 @@
#include "code\datums\mood_events\generic_positive_events.dm"
#include "code\datums\mood_events\mood_event.dm"
#include "code\datums\mood_events\needs_events.dm"
+#include "code\datums\mutations\actions.dm"
+#include "code\datums\mutations\antenna.dm"
#include "code\datums\mutations\body.dm"
#include "code\datums\mutations\chameleon.dm"
#include "code\datums\mutations\cold_resistance.dm"
+#include "code\datums\mutations\combined.dm"
#include "code\datums\mutations\hulk.dm"
+#include "code\datums\mutations\radioactive.dm"
#include "code\datums\mutations\sight.dm"
#include "code\datums\mutations\speech.dm"
#include "code\datums\mutations\telekinesis.dm"
@@ -784,6 +789,7 @@
#include "code\game\objects\items\cardboard_cutouts.dm"
#include "code\game\objects\items\cards_ids.dm"
#include "code\game\objects\items\charter.dm"
+#include "code\game\objects\items\chromosome.dm"
#include "code\game\objects\items\chrono_eraser.dm"
#include "code\game\objects\items\cigs_lighters.dm"
#include "code\game\objects\items\clown_items.dm"
@@ -2696,6 +2702,7 @@
#include "code\modules\spells\spell_types\spacetime_distortion.dm"
#include "code\modules\spells\spell_types\summonitem.dm"
#include "code\modules\spells\spell_types\taeclowndo.dm"
+#include "code\modules\spells\spell_types\telepathy.dm"
#include "code\modules\spells\spell_types\the_traps.dm"
#include "code\modules\spells\spell_types\touch_attacks.dm"
#include "code\modules\spells\spell_types\trigger.dm"