[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"
+ temp_html += "
Adv. Injector"
+ 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(..())
@@ -350,13 +594,15 @@
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(/datum/reagent/medicine/potass_iodide)
- var/can_add = max(min(REJUVENATORS_MAX - potassiodide_amount, REJUVENATORS_INJECT), 0)
- viable_occupant.reagents.add_reagent(/datum/reagent/medicine/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]
@@ -368,7 +614,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
@@ -382,8 +627,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")
@@ -397,28 +640,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)
@@ -457,7 +678,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)
@@ -469,7 +690,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
@@ -478,7 +699,7 @@
var/len = length_char(viable_occupant.dna.uni_identity)
num = WRAP(num, 1, len+1)
num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len) //Each manipulator level above 1 makes randomization as accurate as selected time + manipulator lvl^2
- //Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low
+ //Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low
var/block = round((num-1)/DNA_BLOCK_SIZE)+1
var/subblock = num - block*DNA_BLOCK_SIZE
last_change = "UI #[block]-[subblock]; "
@@ -490,35 +711,229 @@
viable_occupant.dna.uni_identity = copytext_char(viable_occupant.dna.uni_identity, 1, num) + hex + copytext_char(viable_occupant.dna.uni_identity, num + 1)
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_char(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_char(viable_occupant.dna.struc_enzymes, 1, num) + hex + copytext_char(viable_occupant.dna.struc_enzymes, num + 1)
- 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("advinjector")
+ var/selection = href_list["injector"]
+ if(injectorready < world.time)
+ if(injector_selection.Find(selection))
+ var/list/true_selection = injector_selection[selection]
+ if(LAZYLEN(injector_selection))
+ var/obj/item/dnainjector/activator/I = new /obj/item/dnainjector/activator(loc)
+ for(var/A in true_selection)
+ var/datum/mutation/human/HM = A
+ I.add_mutations += new HM.type (copymut = HM)
+ I.doitanyway = TRUE
+ I.name = "Advanced [selection] injector"
+ if(connected)
+ I.damage_coeff = connected.damage_coeff
+ injectorready = world.time + INJECTOR_TIMEOUT * 8 * (1 - 0.1 * connected.precision_coeff)
+ else
+ injectorready = world.time + INJECTOR_TIMEOUT * 8
+ 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)
+ if("expand_advinjector")
+ var/mutation = text2path(href_list["path"])
+ var/datum/mutation/human/HM = get_valid_mutation(mutation)
+ if(HM && LAZYLEN(injector_selection))
+ var/which_injector = input(usr, "Select Adv. Injector", "Advanced Injectors") as null|anything in injector_selection
+ if(injector_selection.Find(which_injector))
+ var/list/true_selection = injector_selection[which_injector]
+ var/total_instability
+ for(var/B in true_selection)
+ var/datum/mutation/human/mootacion = B
+ total_instability += mootacion.instability
+ total_instability += HM.instability
+ if((total_instability > max_injector_instability) || (true_selection.len + 1) > max_injector_mutations)
+ to_chat(usr, "Adding more mutations would make the advanced injector too unstable!")
+ else
+ true_selection += HM //reminder that this works. because I keep forgetting this works
+ if("remove_from_advinjector")
+ var/mutation = text2path(href_list["path"])
+ var/selection = href_list["injector"]
+ if(injector_selection.Find(selection))
+ var/list/true_selection = injector_selection[selection]
+ for(var/B in true_selection)
+ var/datum/mutation/human/HM = B
+ if(HM.type == mutation)
+ true_selection -= HM
+ break
+
+ if("remove_advinjector")
+ var/selection = href_list["injector"]
+ for(selection in injector_selection)
+ if(selection == selection)
+ injector_selection.Remove(selection)
+
+ if("add_advinjector")
+ if(LAZYLEN(injector_selection) < max_injector_selections)
+ var/new_selection = input(usr, "Enter Adv. Injector name", "Advanced Injectors") as text|null
+ if(new_selection && !(new_selection in injector_selection))
+ injector_selection[new_selection] = list()
+
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
@@ -547,10 +962,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"]
@@ -572,15 +983,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/dna_scanner.dm b/code/game/machinery/dna_scanner.dm
index ed61e13596..4b2ba85d11 100644
--- a/code/game/machinery/dna_scanner.dm
+++ b/code/game/machinery/dna_scanner.dm
@@ -22,7 +22,7 @@
precision_coeff = 0
for(var/obj/item/stock_parts/scanning_module/P in component_parts)
scan_level += P.rating
- for(var/obj/item/stock_parts/manipulator/P in component_parts)
+ for(var/obj/item/stock_parts/matter_bin/P in component_parts)
precision_coeff = P.rating
for(var/obj/item/stock_parts/micro_laser/P in component_parts)
damage_coeff = P.rating
diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm
index 25e5948b51..a88cba851f 100644
--- a/code/game/machinery/exp_cloner.dm
+++ b/code/game/machinery/exp_cloner.dm
@@ -9,7 +9,7 @@
internal_radio = FALSE
//Start growing a human clone in the pod!
-/obj/machinery/clonepod/experimental/growclone(ckey, clonename, ui, se, datum/species/mrace, list/features, factions)
+/obj/machinery/clonepod/experimental/growclone(clonename, ui, mutation_index, mindref, last_death, blood_type, datum/species/mrace, list/features, factions, list/quirks)
if(panel_open)
return FALSE
if(mess || attempting)
@@ -20,15 +20,15 @@
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
- H.hardset_dna(ui, se, H.real_name, null, mrace, features)
+ H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
if(efficiency > 2)
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
@@ -42,18 +42,17 @@
icon_state = "pod_1"
//Get the clone body ready
maim_clone(H)
- ADD_TRAIT(H, TRAIT_STABLEHEART, CLONING_POD_TRAIT)
- ADD_TRAIT(H, TRAIT_STABLELIVER, CLONING_POD_TRAIT)
- ADD_TRAIT(H, TRAIT_EMOTEMUTE, CLONING_POD_TRAIT)
- ADD_TRAIT(H, TRAIT_MUTE, CLONING_POD_TRAIT)
- ADD_TRAIT(H, TRAIT_NOBREATH, CLONING_POD_TRAIT)
- ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT)
+ ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning")
+ ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning")
+ ADD_TRAIT(H, TRAIT_MUTE, "cloning")
+ ADD_TRAIT(H, TRAIT_NOBREATH, "cloning")
+ ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
- var/list/candidates = pollCandidatesForMob("Do you want and agree to play as a [clonename]'s defective clone, respect their character and not engage in ERP without permission from the original?", null, null, null, 100, H, POLL_IGNORE_CLONE)
+ var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
- C.transfer_ckey(H)
+ H.key = C.key
if(grab_ghost_when == CLONER_FRESH_CLONE)
H.grab_ghost()
@@ -293,6 +292,7 @@
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(mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, null, dna.blood_type, 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/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm
index 8b6c2180d9..97c89c9168 100644
--- a/code/game/machinery/pipe/construction.dm
+++ b/code/game/machinery/pipe/construction.dm
@@ -63,7 +63,7 @@ Buildable meters
if(make_from.flipped)
do_a_flip()
-/obj/item/pipe/dropped()
+/obj/item/pipe/dropped(mob/user)
if(loc)
setPipingLayer(piping_layer)
return ..()
@@ -225,7 +225,7 @@ Buildable meters
to_chat(user, "You fasten the meter to the [loc.name].")
qdel(src)
-/obj/item/pipe_meter/dropped()
+/obj/item/pipe_meter/dropped(mob/user)
. = ..()
if(loc)
setAttachLayer(piping_layer)
diff --git a/code/game/machinery/toylathe.dm b/code/game/machinery/toylathe.dm
index 87ab3cadd8..c679f3f983 100644
--- a/code/game/machinery/toylathe.dm
+++ b/code/game/machinery/toylathe.dm
@@ -46,7 +46,12 @@
)
/obj/machinery/autoylathe/Initialize()
- AddComponent(/datum/component/material_container, list(/datum/material/iron, /datum/material/glass, /datum/material/plastic), 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
+ var/static/list/allowed_materials = list(
+ /datum/material/iron,
+ /datum/material/glass,
+ /datum/material/plastic
+ )
+ AddComponent(/datum/component/material_container, allowed_materials, 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
. = ..()
wires = new /datum/wires/autoylathe(src)
diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index 38ef518f49..4ddb5281ea 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -283,13 +283,13 @@
/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_charge()
if(equip_ready) //disabled
return
- var/area/A = get_base_area(chassis)
- var/pow_chan = get_power_channel(A)
+ var/area/A = get_area(chassis)
+ 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/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index f9b8f31bca..2ebb2f6ded 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -35,9 +35,19 @@
)
/obj/machinery/mecha_part_fabricator/Initialize()
- var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
- list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/plasma, /datum/material/uranium, /datum/material/bananium, /datum/material/titanium, /datum/material/bluespace), 0,
- TRUE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
+ var/static/list/allowed_types = list(
+ /datum/material/iron,
+ /datum/material/glass,
+ /datum/material/silver,
+ /datum/material/gold,
+ /datum/material/diamond,
+ /datum/material/plasma,
+ /datum/material/uranium,
+ /datum/material/bananium,
+ /datum/material/titanium,
+ /datum/material/bluespace
+ )
+ var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, allowed_types, 0, TRUE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.precise_insertion = TRUE
stored_research = new
return ..()
diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm
index 08843c9202..581283d339 100644
--- a/code/game/mecha/mecha_defense.dm
+++ b/code/game/mecha/mecha_defense.dm
@@ -320,11 +320,7 @@
clearInternalDamage(MECHA_INT_CONTROL_LOST)
/obj/mecha/narsie_act()
- if(occupant)
- var/mob/living/L = occupant
- go_out(TRUE)
- if(L)
- L.narsie_act()
+ emp_act(EMP_HEAVY)
/obj/mecha/ratvar_act()
if((GLOB.ratvar_awakens || GLOB.clockwork_gateway_activated) && occupant)
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index 20c85f37a1..48fba2687d 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -28,6 +28,7 @@
take_damage(5, BURN, 0, 0)
/obj/structure/spider/stickyweb
+ var/genetic = FALSE
icon_state = "stickyweb1"
/obj/structure/spider/stickyweb/Initialize()
@@ -36,6 +37,8 @@
. = ..()
/obj/structure/spider/stickyweb/CanPass(atom/movable/mover, turf/target)
+ if (genetic)
+ return
if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider))
return TRUE
else if(isliving(mover))
@@ -48,6 +51,27 @@
return prob(30)
return TRUE
+/obj/structure/spider/stickyweb/genetic //for the spider genes in genetics
+ genetic = TRUE
+ var/mob/living/allowed_mob
+
+/obj/structure/spider/stickyweb/genetic/Initialize(mapload, allowedmob)
+ allowed_mob = allowedmob
+ . = ..()
+
+/obj/structure/spider/stickyweb/genetic/CanPass(atom/movable/mover, turf/target)
+ . = ..() //this is the normal spider web return aka a spider would make this TRUE
+ if(mover == allowed_mob)
+ return TRUE
+ else if(isliving(mover)) //we change the spider to not be able to go through here
+ if(mover.pulledby == allowed_mob)
+ return TRUE
+ if(prob(50))
+ to_chat(mover, "You get stuck in \the [src] for a moment.")
+ return FALSE
+ else if(istype(mover, /obj/item/projectile))
+ return prob(30)
+
/obj/structure/spider/eggcluster
name = "egg cluster"
desc = "They seem to pulse slightly with an inner life."
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index fd6ae1bb43..5c2f151e38 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -850,3 +850,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if (HAS_TRAIT(src, TRAIT_NODROP))
return
return ..()
+
+/obj/item/proc/embedded(mob/living/carbon/human/embedded_mob)
+ return
+
+/obj/item/proc/unembedded()
+ return
\ No newline at end of file
diff --git a/code/game/objects/items/RCL.dm b/code/game/objects/items/RCL.dm
index 9513519fa9..72e6ccbbe2 100644
--- a/code/game/objects/items/RCL.dm
+++ b/code/game/objects/items/RCL.dm
@@ -117,7 +117,7 @@
. = ..()
if(!isinhands || !(loaded?.amount))
return
- var/mutable_appearance/cable_overlay = mutable_appearance(icon, "rcl-[CEILING(loaded.amount/(max_amount/3), 1)]")
+ var/mutable_appearance/cable_overlay = mutable_appearance(icon_file, "rcl-[CEILING(loaded.amount/(max_amount/3), 1)]")
cable_overlay.color = GLOB.cable_colors[colors[current_color_index]]
. += cable_overlay
diff --git a/code/game/objects/items/chromosome.dm b/code/game/objects/items/chromosome.dm
new file mode 100644
index 0000000000..1340e7f35b
--- /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/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index 7b8c53484a..6b3428698b 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -18,15 +18,11 @@
/obj/item/chrono_eraser/proc/pass_mind(datum/mind/M)
erased_minds += M
-/obj/item/chrono_eraser/dropped()
+/obj/item/chrono_eraser/dropped(mob/user)
..()
if(PA)
qdel(PA)
-/obj/item/chrono_eraser/Destroy()
- dropped()
- return ..()
-
/obj/item/chrono_eraser/ui_action_click(mob/user)
if(iscarbon(user))
var/mob/living/carbon/C = user
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index df0a4e6cf3..b13cfd9f64 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -74,7 +74,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/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm
index e87987600a..57443de973 100644
--- a/code/game/objects/items/devices/chameleonproj.dm
+++ b/code/game/objects/items/devices/chameleonproj.dm
@@ -21,7 +21,7 @@
var/obj/item/cigbutt/butt = /obj/item/cigbutt
saved_appearance = initial(butt.appearance)
-/obj/item/chameleon/dropped()
+/obj/item/chameleon/dropped(mob/user)
..()
disrupt()
diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm
index 9eb51ffaeb..5cab9e33de 100644
--- a/code/game/objects/items/devices/geiger_counter.dm
+++ b/code/game/objects/items/devices/geiger_counter.dm
@@ -218,7 +218,7 @@
/obj/item/geiger_counter/cyborg/proc/redirect_rad_act(datum/source, amount)
rad_act(amount)
-/obj/item/geiger_counter/cyborg/dropped()
+/obj/item/geiger_counter/cyborg/dropped(mob/user)
. = ..()
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_ATOM_RAD_ACT)
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 556080168f..8802698b5d 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -150,7 +150,10 @@ SLIME SCANNER
msg += "\n\tSubject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage."
if(advanced)
msg += "\n\tCellular Damage Level: [M.getCloneLoss()]."
-
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(advanced && H.has_dna())
+ msg += "\n\tGenetic Stability: [H.dna.stability]%."
to_chat(user, msg)
msg = ""
@@ -326,8 +329,8 @@ SLIME SCANNER
breathes = FALSE
if(NOBLOOD in C.dna.species.species_traits)
blooded = FALSE
- var/has_liver = (!(NOLIVER in C.dna.species.species_traits))
- var/has_stomach = (!(NOSTOMACH in C.dna.species.species_traits))
+ var/has_liver = C.dna && !(NOLIVER in C.dna.species.species_traits)
+ var/has_stomach = C.dna && !(NOSTOMACH in C.dna.species.species_traits)
if(!M.getorganslot(ORGAN_SLOT_EYES))
msg += "\tSubject does not have eyes.\n"
if(!M.getorganslot(ORGAN_SLOT_EARS))
@@ -776,3 +779,104 @@ 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 for analyzing someones gene sequence on the fly. Hold near a DNA console to update the internal 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
+ custom_materials = list(/datum/material/iron=200)
+ var/list/discovered = list() //hit a dna console to update the scanners database
+ var/list/buffer
+ var/ready = TRUE
+ var/cooldown = 200
+
+/obj/item/sequence_scanner/attack(mob/living/M, mob/living/carbon/human/user)
+ add_fingerprint(user)
+ if (!HAS_TRAIT(M, TRAIT_RADIMMUNE)) //no scanning if its a husk or DNA-less Species
+ user.visible_message("[user] analyzes [M]'s genetic sequence.", \
+ "You analyze [M]'s genetic sequence.")
+ gene_scan(M, user)
+
+ else
+ user.visible_message("[user] failed to analyse [M]'s genetic sequence.", "[M] has no readable genetic sequence!")
+
+/obj/item/sequence_scanner/attack_self(mob/user)
+ display_sequence(user)
+
+/obj/item/sequence_scanner/attack_self_tk(mob/user)
+ return
+
+/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] linked to central research database.")
+ discovered = C.stored_research.discovered_mutations
+ else
+ to_chat(user,"No database to update from.")
+
+/obj/item/sequence_scanner/proc/gene_scan(mob/living/carbon/C, mob/living/user)
+ if(!iscarbon(C) || !C.has_dna())
+ return
+ buffer = C.dna.mutation_index
+ to_chat(user, "Subject [C.name]'s DNA sequence has been saved to buffer.")
+ if(LAZYLEN(buffer))
+ for(var/A in buffer)
+ to_chat(user, "[get_display_name(A)]")
+
+
+/obj/item/sequence_scanner/proc/display_sequence(mob/living/user)
+ if(!LAZYLEN(buffer) || !ready)
+ return
+ var/list/options = list()
+ for(var/A in buffer)
+ options += get_display_name(A)
+
+ var/answer = input(user, "Analyze Potential", "Sequence Analyzer") as null|anything in sortList(options)
+ if(answer && ready && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+ var/sequence
+ for(var/A in buffer) //this physically hurts but i dont know what anything else short of an assoc list
+ if(get_display_name(A) == answer)
+ sequence = buffer[A]
+ break
+
+ if(sequence)
+ var/display
+ for(var/i in 0 to length_char(sequence) / DNA_MUTATION_BLOCKS-1)
+ if(i)
+ display += "-"
+ display += copytext_char(sequence, 1 + i*DNA_MUTATION_BLOCKS, DNA_MUTATION_BLOCKS*(1+i) + 1)
+
+ to_chat(user, "[display]
")
+
+ ready = FALSE
+ icon_state = "[icon_state]_recharging"
+ addtimer(CALLBACK(src, .proc/recharge), cooldown, TIMER_UNIQUE)
+
+/obj/item/sequence_scanner/proc/recharge()
+ icon_state = initial(icon_state)
+ ready = TRUE
+
+/obj/item/sequence_scanner/proc/get_display_name(mutation)
+ var/datum/mutation/human/HM = GET_INITIALIZED_MUTATION(mutation)
+ if(!HM)
+ return "ERROR"
+ if(mutation in discovered)
+ return "[HM.name] ([HM.alias])"
+ else
+ return HM.alias
\ No newline at end of file
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index 2c101b0ec5..b929642f33 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -63,10 +63,10 @@
if(attached_device)
attached_device.holder_movement()
-/obj/item/transfer_valve/dropped()
+/obj/item/transfer_valve/dropped(mob/user)
. = ..()
if(attached_device)
- attached_device.dropped()
+ attached_device.dropped(user)
/obj/item/transfer_valve/on_found(mob/finder)
if(attached_device)
diff --git a/code/game/objects/items/dna_injector.dm b/code/game/objects/items/dna_injector.dm
index a03447c0f0..60b1e81c94 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,258 @@
/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/void
+ name = "\improper DNA injector (Void)"
+ add_mutations = list(VOID)
+
+/obj/item/dnainjector/antivoid
+ name = "\improper DNA injector (Anti-Void)"
+ remove_mutations = list(VOID)
+
+/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/radioactive
+ name = "\improper DNA injector (Radioactive)"
+ add_mutations = list(RADIOACTIVE)
+
+/obj/item/dnainjector/antiradioactive
+ name = "\improper DNA injector (Anti-Radioactive)"
+ remove_mutations = list(RADIOACTIVE)
+/obj/item/dnainjector/olfaction
+ name = "\improper DNA injector (Olfaction)"
+ add_mutations = list(OLFACTION)
+
+/obj/item/dnainjector/antiolfaction
+ name = "\improper DNA injector (Anti-Olfaction)"
+ remove_mutations = list(OLFACTION)
+
+/obj/item/dnainjector/insulated
+ 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/shock
+ name = "\improper DNA injector (Shock Touch)"
+ add_mutations = list(SHOCKTOUCH)
+
+/obj/item/dnainjector/antishock
+ name = "\improper DNA injector (Anti-Shock Touch)"
+ remove_mutations = list(SHOCKTOUCH)
+
+/obj/item/dnainjector/spacialinstability
+ name = "\improper DNA injector (Spacial Instability)"
+ add_mutations = list(BADBLINK)
+
+/obj/item/dnainjector/antispacialinstability
+ name = "\improper DNA injector (Anti-Spacial Instability)"
+ remove_mutations = list(BADBLINK)
+
+/obj/item/dnainjector/acidflesh
+ name = "\improper DNA injector (Acid Flesh)"
+ add_mutations = list(ACIDFLESH)
+
+/obj/item/dnainjector/antiacidflesh
+ name = "\improper DNA injector (Acid Flesh)"
+ remove_mutations = list(ACIDFLESH)
+
+/obj/item/dnainjector/gigantism
+ name = "\improper DNA injector (Gigantism)"
+ add_mutations = list(GIGANTISM)
+
+/obj/item/dnainjector/antigigantism
+ name = "\improper DNA injector (Anti-Gigantism)"
+ remove_mutations = list(GIGANTISM)
+
+/obj/item/dnainjector/spastic
+ name = "\improper DNA injector (Spastic)"
+ add_mutations = list(SPASTIC)
+
+/obj/item/dnainjector/antispastic
+ name = "\improper DNA injector (Anti-Spastic)"
+ remove_mutations = list(SPASTIC)
+
+/obj/item/dnainjector/geladikinesis
+ name = "\improper DNA injector (Geladikinesis)"
+ add_mutations = list(GELADIKINESIS)
+
+/obj/item/dnainjector/antigeladikinesis
+ name = "\improper DNA injector (Anti-Geladikinesis)"
+ remove_mutations = list(GELADIKINESIS)
+
+/obj/item/dnainjector/cryokinesis
+ name = "\improper DNA injector (Cryokinesis)"
+ add_mutations = list(CRYOKINESIS)
+
+/obj/item/dnainjector/anticryokinesis
+ name = "\improper DNA injector (Anti-Cryokinesis)"
+ remove_mutations = list(CRYOKINESIS)
+
+/obj/item/dnainjector/thermal
+ 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/glow
+ name = "\improper DNA injector (Glowy)"
+ add_mutations = list(GLOWY)
+
+/obj/item/dnainjector/removeglow
+ name = "\improper DNA injector (Anti-Glowy)"
+ remove_mutations = list(GLOWY)
+
+/obj/item/dnainjector/antiglow
+ name = "\improper DNA injector (Antiglowy)"
+ add_mutations = list(ANTIGLOWY)
+
+/obj/item/dnainjector/removeantiglow
+ name = "\improper DNA injector (Anti-Antiglowy)"
+ remove_mutations = list(ANTIGLOWY)
+
+/obj/item/dnainjector/firebreath
+ 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/tonguespike
+ name = "\improper DNA injector (Tongue Spike)"
+ add_mutations = list(TONGUESPIKE)
+
+/obj/item/dnainjector/antitonguespike
+ name = "\improper DNA injector (Anti-Tongue Spike)"
+ remove_mutations = list(TONGUESPIKE)
+
+/obj/item/dnainjector/spiderweb
+ name = "\improper DNA injector (Spider Web)"
+ add_mutations = list(SPIDER_WEB)
+
+/obj/item/dnainjector/antispiderweb
+ name = "\improper DNA injector (Anti-Spider Web)"
+ remove_mutations = list(SPIDER_WEB)
/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 +467,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 +510,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/granters.dm b/code/game/objects/items/granters.dm
index 0907a18fdd..9749bae313 100644
--- a/code/game/objects/items/granters.dm
+++ b/code/game/objects/items/granters.dm
@@ -11,7 +11,7 @@
/obj/item/book/granter/proc/turn_page(mob/user)
playsound(user, pick('sound/effects/pageturn1.ogg','sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg'), 30, 1)
- if(do_after(user,50, user))
+ if(do_after(user,50, TRUE, user))
if(remarks.len)
to_chat(user, "[pick(remarks)]")
else
@@ -53,7 +53,7 @@
on_reading_stopped()
reading = FALSE
return
- if(do_after(user,50, user))
+ if(do_after(user,50, TRUE, user))
on_reading_finished(user)
reading = FALSE
return TRUE
@@ -402,10 +402,11 @@
martialname = "sleeping carp"
desc = "A scroll filled with strange markings. It seems to be drawings of some sort of martial art."
greet = "You have learned the ancient martial art of the Sleeping Carp! Your hand-to-hand combat has become much more effective, and you are now able to deflect any projectiles \
- directed toward you. However, you are also unable to use any ranged weaponry. You can learn more about your newfound art by using the Recall Teachings verb in the Sleeping Carp tab."
+ directed toward you while in Throw Mode. Your body is also honed to protect you from damage and punctures, and even briefly survive space. \
+ However, you are also unable to use any ranged weaponry, and some medical supplies will prove useless to you. You can learn more about your newfound art by using the Recall Teachings verb in the Sleeping Carp tab."
icon = 'icons/obj/wizard.dmi'
icon_state = "scroll2"
- remarks = list("I must prove myself worthy to the masters of the sleeping carp...", "Stance means everything...", "Focus... And you'll be able to incapacitate any foe in seconds...", "I must pierce armor for maximum damage...", "I don't think this would combine with other martial arts...", "Grab them first so they don't retaliate...", "I must prove myself worthy of this power...")
+ remarks = list("Wait, a high protein diet is really all it takes to become bulletproof...?", "Overwhelming force, immovable object...", "Focus... And you'll be able to incapacitate any foe in seconds...", "I must pierce armor for maximum damage...", "I don't think this would combine with other martial arts...", "Become one with the carp...", "Glub...")
/obj/item/book/granter/martial/carp/onlearned(mob/living/carbon/user)
..()
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index 32e07284ec..fe1f3ebd6c 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -357,7 +357,7 @@
/obj/item/borg/lollipop/equipped()
check_amount()
-/obj/item/borg/lollipop/dropped()
+/obj/item/borg/lollipop/dropped(mob/user)
check_amount()
/obj/item/borg/lollipop/proc/check_amount() //Doesn't even use processing ticks.
@@ -620,7 +620,7 @@
return host.loc
return null
-/obj/item/borg/projectile_dampen/dropped()
+/obj/item/borg/projectile_dampen/dropped(mob/user)
. = ..()
host = loc
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index 56af03139a..28a93a7a83 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -462,7 +462,7 @@
desc = "An upgrade to the Medical module's hypospray, containing \
stronger versions of existing chemicals."
additional_reagents = list(/datum/reagent/medicine/oxandrolone, /datum/reagent/medicine/sal_acid,
- /datum/reagent/medicine/rezadone, /datum/reagent/medicine/pen_acid)
+ /datum/reagent/medicine/rezadone, /datum/reagent/medicine/pen_acid, /datum/reagent/medicine/prussian_blue)
/obj/item/borg/upgrade/piercing_hypospray
name = "cyborg piercing hypospray"
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index 7a6e1e3db6..103dabdeec 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -132,7 +132,7 @@
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/Pickup_ores)
listeningTo = user
-/obj/item/storage/bag/ore/dropped()
+/obj/item/storage/bag/ore/dropped(mob/user)
. = ..()
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm
index 0ff20f16c5..c9c686414d 100644
--- a/code/game/objects/items/storage/firstaid.dm
+++ b/code/game/objects/items/storage/firstaid.dm
@@ -525,14 +525,6 @@
desc = "A kit containing a Deluxe hypospray and Vials."
icon_state = "tactical-mini"
-/obj/item/storage/hypospraykit/cmo/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.can_hold = typecacheof(list(
- /obj/item/hypospray/mkii,
- /obj/item/reagent_containers/glass/bottle/vial))
-
/obj/item/storage/hypospraykit/cmo/PopulateContents()
if(empty)
return
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index 3079c3cad9..78ba6d4f5f 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -25,7 +25,7 @@
/obj/item/melee/baton/examine(mob/user)
. = ..()
- . += "
Right click attack while in combat mode or attack while in disarm intent to disarm instead of stun."
+ . += "
Right click attack while in combat mode to disarm instead of stun."
/obj/item/melee/baton/get_cell()
. = cell
@@ -149,8 +149,6 @@
//return TRUE to interrupt attack chain.
/obj/item/melee/baton/proc/common_baton_melee(mob/M, mob/living/user, disarming = FALSE)
- if(user.a_intent == INTENT_DISARM)
- disarming = TRUE //override if they're in disarm intent.
if(iscyborg(M) || !isliving(M)) //can't baton cyborgs
return FALSE
if(status && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 11a06e149d..57fc99c663 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -246,11 +246,11 @@
user.visible_message("
[user] axes [user.p_them()]self from head to toe! It looks like [user.p_theyre()] trying to commit suicide!")
return (BRUTELOSS)
-/obj/item/twohanded/fireaxe/afterattack(atom/A, mob/user, proximity)
+/obj/item/twohanded/fireaxe/afterattack(atom/A, mob/living/user, proximity)
. = ..()
- if(!proximity)
+ if(!proximity || (user.getStaminaLoss() > STAMINA_SOFTCRIT))
return
- if(wielded) //destroys windows and grilles in one hit
+ if(wielded) //destroys windows and grilles in one hit (or more if it has a ton of health like plasmaglass)
if(istype(A, /obj/structure/window))
var/obj/structure/window/W = A
W.take_damage(200, BRUTE, "melee", 0)
@@ -1217,7 +1217,7 @@
target.lastattackerckey = user.ckey
target.visible_message("
[user] has shocked [target] with [src]!", \
"
[user] has shocked you with [src]!")
- log_combat(user, user, "stunned with an electrostaff")
+ log_combat(user, target, "stunned with an electrostaff")
playsound(src, 'sound/weapons/staff.ogg', 50, 1, -1)
target.apply_status_effect(stun_status_effect, stun_status_duration)
if(ishuman(user))
@@ -1242,9 +1242,9 @@
if(user)
target.lastattacker = user.real_name
target.lastattackerckey = user.ckey
- target.visible_message("
[user] has seared [user] with [src]!", \
+ target.visible_message("
[user] has seared [target] with [src]!", \
"
[user] has seared you with [src]!")
- log_combat(user, user, "burned with an electrostaff")
+ log_combat(user, target, "burned with an electrostaff")
playsound(src, 'sound/weapons/sear.ogg', 50, 1, -1)
return TRUE
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 3fc183edc6..c92bbdc996 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -127,11 +127,10 @@
if ((M.client && M.machine == src))
is_in_use = TRUE
ui_interact(M)
- if(isAI(usr) || iscyborg(usr) || IsAdminGhost(usr) || hasSiliconAccessInArea(usr))
- if (!(usr in nearby))
- if (usr.client && usr.machine==src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh.
- is_in_use = TRUE
- ui_interact(usr)
+ if(usr && hasSiliconAccessInArea(usr) && !(usr in nearby))
+ if (usr.client && usr.machine==src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh.
+ is_in_use = TRUE
+ ui_interact(usr)
// check for TK users
diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm
index 531367585e..04c3909696 100644
--- a/code/game/objects/structures/windoor_assembly.dm
+++ b/code/game/objects/structures/windoor_assembly.dm
@@ -315,13 +315,8 @@
/obj/structure/windoor_assembly/ComponentInitialize()
. = ..()
- AddComponent(
- /datum/component/simple_rotation,
- ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS,
- null,
- CALLBACK(src, .proc/can_be_rotated),
- CALLBACK(src,.proc/after_rotation)
- )
+ var/static/rotation_flags = ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS
+ AddComponent(/datum/component/simple_rotation, rotation_flags, can_be_rotated=CALLBACK(src, .proc/can_be_rotated), after_rotation=CALLBACK(src,.proc/after_rotation))
/obj/structure/windoor_assembly/proc/can_be_rotated(mob/user,rotation_type)
if(anchored)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 6abf2d3f1b..51c2ba4fc6 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1732,7 +1732,7 @@
var/mob/M = locate(href_list["makeeligible"])
if(!ismob(M))
to_chat(usr, "this can only be used on instances of type /mob.")
- var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(/datum/element/ghost_role_eligibility)
+ var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(list(/datum/element/ghost_role_eligibility))
if(M.ckey in eli.timeouts)
eli.timeouts -= M.ckey
diff --git a/code/modules/antagonists/blob/blob/blobs/shield.dm b/code/modules/antagonists/blob/blob/blobs/shield.dm
index 481c5e6c8d..bc4e517ced 100644
--- a/code/modules/antagonists/blob/blob/blobs/shield.dm
+++ b/code/modules/antagonists/blob/blob/blobs/shield.dm
@@ -47,7 +47,7 @@
icon_state = "blob_glow"
flags_1 = CHECK_RICOCHET_1
point_return = 8
- max_integrity = 50
+ max_integrity = 100
brute_resist = 1
explosion_block = 2
diff --git a/code/modules/antagonists/blob/blob/powers.dm b/code/modules/antagonists/blob/blob/powers.dm
index 641019ef33..73d0c97476 100644
--- a/code/modules/antagonists/blob/blob/powers.dm
+++ b/code/modules/antagonists/blob/blob/powers.dm
@@ -71,7 +71,7 @@
var/list/nodes = list()
for(var/i in 1 to GLOB.blob_nodes.len)
var/obj/structure/blob/node/B = GLOB.blob_nodes[i]
- nodes["Blob Node #[i] ([B.overmind ? "[B.overmind.blobstrain.name]":"No Strain"])"] = B
+ nodes["Blob Node #[i] ([get_area_name(B)])"] = B
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
var/obj/structure/blob/node/chosen_node = nodes[node_name]
if(chosen_node)
@@ -120,13 +120,13 @@
/mob/camera/blob/proc/create_shield(turf/T)
var/obj/structure/blob/shield/S = locate(/obj/structure/blob/shield) in T
if(S)
- if(!can_buy(15))
+ if(!can_buy(BLOB_REFLECTOR_COST))
return
if(S.obj_integrity < S.max_integrity * 0.5)
add_points(BLOB_REFLECTOR_COST)
to_chat(src, "
This shield blob is too damaged to be modified properly!")
return
- to_chat(src, "
You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced intregrity.")
+ to_chat(src, "
You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced integrity.")
S.change_to(/obj/structure/blob/shield/reflective, src)
else
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
@@ -247,8 +247,8 @@
/mob/camera/blob/verb/expand_blob_power()
set category = "Blob"
- set name = "Expand/Attack Blob (4)"
- set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects."
+ set name = "Expand/Attack Blob ([BLOB_SPREAD_COST])"
+ set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects and refunding [BLOB_ATTACK_REFUND] points."
var/turf/T = get_turf(src)
expand_blob(T)
@@ -261,7 +261,7 @@
if(!possibleblobs.len)
to_chat(src, "
There is no blob adjacent to the target tile!")
return
- if(can_buy(4))
+ if(can_buy(BLOB_SPREAD_COST))
var/attacksuccess = FALSE
for(var/mob/living/L in T)
if(ROLE_BLOB in L.faction) //no friendly/dead fire
@@ -271,11 +271,11 @@
blobstrain.attack_living(L)
var/obj/structure/blob/B = locate() in T
if(B)
- if(attacksuccess) //if we successfully attacked a turf with a blob on it, don't refund shit
+ if(attacksuccess) //if we successfully attacked a turf with a blob on it, only give an attack refund
B.blob_attack_animation(T, src)
else
to_chat(src, "
There is a blob there!")
- add_points(4) //otherwise, refund all of the cost
+ add_points(BLOB_SPREAD_COST) //otherwise, refund all of the cost
else
var/list/cardinalblobs = list()
var/list/diagonalblobs = list()
@@ -288,14 +288,15 @@
var/obj/structure/blob/OB
if(cardinalblobs.len)
OB = pick(cardinalblobs)
- OB.expand(T, src)
+ if(!OB.expand(T, src))
+ add_points(BLOB_ATTACK_REFUND) //assume it's attacked SOMETHING, possibly a structure
else
OB = pick(diagonalblobs)
if(attacksuccess)
OB.blob_attack_animation(T, src)
playsound(OB, 'sound/effects/splat.ogg', 50, 1)
else
- add_points(4) //if we're attacking diagonally and didn't hit anything, refund
+ add_points(BLOB_SPREAD_COST) //if we're attacking diagonally and didn't hit anything, refund
if(attacksuccess)
last_attack = world.time + CLICK_CD_MELEE
else
diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_objectives.dm b/code/modules/antagonists/bloodsucker/bloodsucker_objectives.dm
index a2a0238df1..0c80ce0dee 100644
--- a/code/modules/antagonists/bloodsucker/bloodsucker_objectives.dm
+++ b/code/modules/antagonists/bloodsucker/bloodsucker_objectives.dm
@@ -43,7 +43,7 @@
// EXPLANATION
/datum/objective/bloodsucker/lair/update_explanation_text()
- explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift"// Make sure to keep it safe!"
+ explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift."// Make sure to keep it safe!"
// WIN CONDITIONS?
/datum/objective/bloodsucker/lair/check_completion()
@@ -228,7 +228,7 @@
if (SC && SC.lastgen > 0 && SC.connected_panels.len > 0 && SC.connected_tracker)
return FALSE
return TRUE
-*/
+*/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -250,15 +250,15 @@
// WIN CONDITIONS?
/datum/objective/bloodsucker/heartthief/check_completion()
// -Must have a body.
- if (!owner.current)
+ if(!owner.current)
return FALSE
// Taken from /steal in objective.dm
var/list/all_items = owner.current.GetAllContents() // Includes items inside other items.
var/itemcount = FALSE
for(var/obj/I in all_items) //Check for items
- if(I == /obj/item/organ/heart)
- itemcount ++
- if (itemcount >= target_amount) // Got the right amount?
+ if(istype(I, /obj/item/organ/heart/))
+ itemcount++
+ if(itemcount >= target_amount) // Got the right amount?
return TRUE
return FALSE
diff --git a/code/modules/antagonists/bloodsucker/items/bloodsucker_stake.dm b/code/modules/antagonists/bloodsucker/items/bloodsucker_stake.dm
index b69b851990..4c377f4b82 100644
--- a/code/modules/antagonists/bloodsucker/items/bloodsucker_stake.dm
+++ b/code/modules/antagonists/bloodsucker/items/bloodsucker_stake.dm
@@ -90,6 +90,7 @@
user.dropItemToGround(src, TRUE) //user.drop_item() // "drop item" doesn't seem to exist anymore. New proc is user.dropItemToGround() but it doesn't seem like it's needed now?
var/obj/item/bodypart/B = C.get_bodypart("chest") // This was all taken from hitby() in human_defense.dm
B.embedded_objects |= src
+ embedded()
add_mob_blood(target)//Place blood on the stake
loc = C // Put INSIDE the character
B.receive_damage(w_class * embedding.embedded_impact_pain_multiplier)
diff --git a/code/modules/antagonists/changeling/powers/chameleon_skin.dm b/code/modules/antagonists/changeling/powers/chameleon_skin.dm
index b7545353b2..03f3aab473 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/swarmer/swarmer_event.dm b/code/modules/antagonists/swarmer/swarmer_event.dm
index 8e385f6674..6ef35fdbaa 100644
--- a/code/modules/antagonists/swarmer/swarmer_event.dm
+++ b/code/modules/antagonists/swarmer/swarmer_event.dm
@@ -5,6 +5,7 @@
max_occurrences = 0
earliest_start = 30 MINUTES
min_players = 15
+ gamemode_blacklist = list("dynamic")
/datum/round_event/spawn_swarmer
diff --git a/code/modules/antagonists/traitor/IAA/internal_affairs.dm b/code/modules/antagonists/traitor/IAA/internal_affairs.dm
index caf2f644df..19144d67c9 100644
--- a/code/modules/antagonists/traitor/IAA/internal_affairs.dm
+++ b/code/modules/antagonists/traitor/IAA/internal_affairs.dm
@@ -120,7 +120,7 @@
/datum/antagonist/traitor/internal_affairs/reinstate_escape_objective()
..()
- var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
+ var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
var/datum/objective/escape_objective = new objtype
escape_objective.owner = owner
add_objective(escape_objective)
@@ -215,20 +215,12 @@
kill_objective.target = target_mind
kill_objective.update_explanation_text()
add_objective(kill_objective)
-
- //Optional traitor objective
- if(prob(PROB_ACTUAL_TRAITOR))
- employer = "The Syndicate"
- owner.special_role = TRAITOR_AGENT_ROLE
- special_role = TRAITOR_AGENT_ROLE
- syndicate = TRUE
- forge_single_objective()
return
/datum/antagonist/traitor/internal_affairs/forge_traitor_objectives()
forge_iaa_objectives()
- var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
+ var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
var/datum/objective/escape_objective = new objtype
escape_objective.owner = owner
add_objective(escape_objective)
diff --git a/code/modules/antagonists/traitor/classes/ai.dm b/code/modules/antagonists/traitor/classes/ai.dm
new file mode 100644
index 0000000000..fac1efeb49
--- /dev/null
+++ b/code/modules/antagonists/traitor/classes/ai.dm
@@ -0,0 +1,68 @@
+/datum/traitor_class/ai // this one is special, so has no weight
+ name = "Malfunctioning AI"
+
+/datum/traitor_class/ai/forge_objectives(datum/antagonist/traitor/T)
+ var/objective_count = 0
+
+ if(prob(30))
+ objective_count += forge_single_objective()
+
+ for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
+ var/datum/objective/assassinate/kill_objective = new
+ kill_objective.owner = T.owner
+ kill_objective.find_target()
+ T.add_objective(kill_objective)
+
+ var/datum/objective/survive/exist/exist_objective = new
+ exist_objective.owner = T.owner
+ T.add_objective(exist_objective)
+
+/datum/traitor_class/ai/forge_single_objective(datum/antagonist/traitor/T)
+ .=1
+ var/special_pick = rand(1,4)
+ switch(special_pick)
+ if(1)
+ var/datum/objective/block/block_objective = new
+ block_objective.owner = T.owner
+ T.add_objective(block_objective)
+ if(2)
+ var/datum/objective/purge/purge_objective = new
+ purge_objective.owner = T.owner
+ T.add_objective(purge_objective)
+ if(3)
+ var/datum/objective/robot_army/robot_objective = new
+ robot_objective.owner = T.owner
+ T.add_objective(robot_objective)
+ if(4) //Protect and strand a target
+ var/datum/objective/protect/yandere_one = new
+ yandere_one.owner = T.owner
+ T.add_objective(yandere_one)
+ yandere_one.find_target()
+ var/datum/objective/maroon/yandere_two = new
+ yandere_two.owner = T.owner
+ yandere_two.target = yandere_one.target
+ yandere_two.update_explanation_text() // normally called in find_target()
+ T.add_objective(yandere_two)
+ .=2
+
+/datum/traitor_class/ai/on_removal(datum/antagonist/traitor/T)
+ var/mob/living/silicon/ai/A = T.owner.current
+ A.set_zeroth_law("")
+ A.verbs -= /mob/living/silicon/ai/proc/choose_modules
+ A.malf_picker.remove_malf_verbs(A)
+ qdel(A.malf_picker)
+
+
+/datum/traitor_class/ai/apply_innate_effects(mob/living/M)
+ var/mob/living/silicon/ai/A = M
+ A.hack_software = TRUE
+
+/datum/traitor_class/ai/remove_innate_effects(mob/living/M)
+ var/mob/living/silicon/ai/A = M
+ A.hack_software = FALSE
+
+/datum/traitor_class/ai/finalize_traitor(datum/antagonist/traitor/T)
+ T.add_law_zero()
+ T.owner.current.playsound_local(get_turf(T.owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
+ T.owner.current.grant_language(/datum/language/codespeak)
+ return FALSE
diff --git a/code/modules/antagonists/traitor/classes/assassin.dm b/code/modules/antagonists/traitor/classes/assassin.dm
new file mode 100644
index 0000000000..0c1d950f57
--- /dev/null
+++ b/code/modules/antagonists/traitor/classes/assassin.dm
@@ -0,0 +1,37 @@
+/datum/traitor_class/human/assassin
+ name = "Donk Co Operative"
+ employer = "Donk Corporation"
+ weight = 0
+ chaos = 1
+ cost = 2
+
+/datum/traitor_class/human/assassin/forge_single_objective(datum/antagonist/traitor/T)
+ .=1
+ var/permakill_prob = 20
+ var/is_dynamic = FALSE
+ var/datum/game_mode/dynamic/mode
+ if(istype(SSticker.mode,/datum/game_mode/dynamic))
+ mode = SSticker.mode
+ is_dynamic = TRUE
+ permakill_prob = max(0,mode.threat_level-50)
+ var/list/active_ais = active_ais()
+ if(active_ais.len && prob(100/GLOB.joined_player_list.len))
+ var/datum/objective/destroy/destroy_objective = new
+ destroy_objective.owner = T.owner
+ destroy_objective.find_target()
+ T.add_objective(destroy_objective)
+ else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
+ var/datum/objective/maroon/maroon_objective = new
+ maroon_objective.owner = T.owner
+ maroon_objective.find_target()
+ T.add_objective(maroon_objective)
+ else if(prob(permakill_prob))
+ var/datum/objective/assassinate/kill_objective = new
+ kill_objective.owner = T.owner
+ kill_objective.find_target()
+ T.add_objective(kill_objective)
+ else
+ var/datum/objective/assassinate/once/kill_objective = new
+ kill_objective.owner = T.owner
+ kill_objective.find_target()
+ T.add_objective(kill_objective)
diff --git a/code/modules/antagonists/traitor/classes/freeform.dm b/code/modules/antagonists/traitor/classes/freeform.dm
new file mode 100644
index 0000000000..f84eadb9f6
--- /dev/null
+++ b/code/modules/antagonists/traitor/classes/freeform.dm
@@ -0,0 +1,12 @@
+/datum/traitor_class/human/freeform
+ name = "Waffle Co Agent"
+ employer = "Waffle Company"
+ weight = 16
+ chaos = 0
+
+/datum/traitor_class/human/freeform/forge_objectives(datum/antagonist/traitor/T)
+ var/datum/objective/escape/O = new
+ O.explanation_text = "You have no goals! Whatever you can do do antagonize Nanotrasen, do it! The gimmickier, the better! Make sure to escape alive, though!"
+ O.owner = T.owner
+ T.add_objective(O)
+ return
diff --git a/code/modules/antagonists/traitor/classes/hijack.dm b/code/modules/antagonists/traitor/classes/hijack.dm
new file mode 100644
index 0000000000..e89eda1dcf
--- /dev/null
+++ b/code/modules/antagonists/traitor/classes/hijack.dm
@@ -0,0 +1,18 @@
+/datum/traitor_class/human/hijack
+ name = "Gorlex Marauder"
+ employer = "The Gorlex Marauders"
+ weight = 3
+ chaos = 5
+ cost = 5
+ uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit)
+
+/datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T)
+ var/datum/objective/hijack/O = new
+ O.explanation_text = "The Gorlex Marauders are letting you do what you want, with one condition: the shuttle must be hijacked by hacking its navigational protocols through the control console (alt click emergency shuttle console)."
+ O.owner = T.owner
+ T.add_objective(O)
+ return
+
+/datum/traitor_class/human/hijack/finalize_traitor(datum/antagonist/traitor/T)
+ T.hijack_speed=1
+ return TRUE
diff --git a/code/modules/antagonists/traitor/classes/human.dm b/code/modules/antagonists/traitor/classes/human.dm
new file mode 100644
index 0000000000..4e096390c0
--- /dev/null
+++ b/code/modules/antagonists/traitor/classes/human.dm
@@ -0,0 +1,82 @@
+/datum/traitor_class/human
+ name = "Syndicate Agent"
+ chaos = 0
+
+/datum/traitor_class/human/forge_objectives(datum/antagonist/traitor/T)
+ var/objective_count = 0 //Hijacking counts towards number of objectives
+ if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
+ if(!SSticker.mode.exchange_red)
+ SSticker.mode.exchange_red = T.owner
+ else
+ SSticker.mode.exchange_blue = T.owner
+ T.assign_exchange_role(SSticker.mode.exchange_red)
+ T.assign_exchange_role(SSticker.mode.exchange_blue)
+ objective_count += 1 //Exchange counts towards number of objectives
+ var/toa = CONFIG_GET(number/traitor_objectives_amount)
+ for(var/i = objective_count, i < toa, i++)
+ forge_single_objective(T)
+ if(!(locate(/datum/objective/escape) in T.objectives))
+ var/datum/objective/escape/escape_objective = new
+ escape_objective.owner = T.owner
+ T.add_objective(escape_objective)
+ return
+
+/datum/traitor_class/human/forge_single_objective(datum/antagonist/traitor/T)
+ .=1
+ var/assassin_prob = 50
+ var/is_dynamic = FALSE
+ var/datum/game_mode/dynamic/mode
+ if(istype(SSticker.mode,/datum/game_mode/dynamic))
+ mode = SSticker.mode
+ is_dynamic = TRUE
+ assassin_prob = max(0,mode.threat_level-20)
+ if(prob(assassin_prob))
+ if(is_dynamic)
+ var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
+ mode.spend_threat(threat_spent)
+ mode.log_threat("[T.owner.name] spent [threat_spent] on an assassination target.")
+ var/list/active_ais = active_ais()
+ if(active_ais.len && prob(100/GLOB.joined_player_list.len))
+ var/datum/objective/destroy/destroy_objective = new
+ destroy_objective.owner = T.owner
+ destroy_objective.find_target()
+ T.add_objective(destroy_objective)
+ else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
+ var/datum/objective/maroon/maroon_objective = new
+ maroon_objective.owner = T.owner
+ maroon_objective.find_target()
+ T.add_objective(maroon_objective)
+ else if(prob(max(0,assassin_prob-20)))
+ var/datum/objective/assassinate/kill_objective = new
+ kill_objective.owner = T.owner
+ kill_objective.find_target()
+ T.add_objective(kill_objective)
+ else
+ var/datum/objective/assassinate/once/kill_objective = new
+ kill_objective.owner = T.owner
+ kill_objective.find_target()
+ T.add_objective(kill_objective)
+ else
+ if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
+ var/datum/objective/download/download_objective = new
+ download_objective.owner = T.owner
+ download_objective.gen_amount_goal()
+ T.add_objective(download_objective)
+ else if(prob(40)) // cum. not counting download: 40%.
+ var/datum/objective/steal/steal_objective = new
+ steal_objective.owner = T.owner
+ steal_objective.find_target()
+ T.add_objective(steal_objective)
+ else if(prob(100/3)) // cum. not counting download: 20%.
+ var/datum/objective/sabotage/sabotage_objective = new
+ sabotage_objective.owner = T.owner
+ sabotage_objective.find_target()
+ T.add_objective(sabotage_objective)
+ else // cum. not counting download: 40%
+ var/datum/objective/flavor/traitor/flavor_objective = new
+ flavor_objective.owner = T.owner
+ flavor_objective.forge_objective()
+ T.add_objective(flavor_objective)
+
+/datum/traitor_class/human/greet(datum/antagonist/traitor/T)
+ to_chat(T.owner.current, "
You are under contract with [employer]. They have given you your objectives.")
diff --git a/code/modules/antagonists/traitor/classes/martyr.dm b/code/modules/antagonists/traitor/classes/martyr.dm
new file mode 100644
index 0000000000..78f8bf9b0c
--- /dev/null
+++ b/code/modules/antagonists/traitor/classes/martyr.dm
@@ -0,0 +1,14 @@
+/datum/traitor_class/human/martyr
+ name = "Tiger Cooperator"
+ employer = "The Tiger Cooperative"
+ weight = 2
+ chaos = 5
+ cost = 5
+ uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit)
+
+/datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T)
+ var/datum/objective/martyr/O = new
+ O.explanation_text = "The tiger cooperative have given you free reign. You may do as you wish, as long as you die a glorious death!"
+ O.owner = T.owner
+ T.add_objective(O)
+ return
diff --git a/code/modules/antagonists/traitor/classes/subterfuge.dm b/code/modules/antagonists/traitor/classes/subterfuge.dm
new file mode 100644
index 0000000000..ae43f11fe7
--- /dev/null
+++ b/code/modules/antagonists/traitor/classes/subterfuge.dm
@@ -0,0 +1,40 @@
+/datum/traitor_class/human/subterfuge
+ name = "MI13 Operative"
+ employer = "MI13"
+ weight = 20
+ chaos = -5
+
+/datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T)
+ .=1
+ var/assassin_prob = 30
+ var/datum/game_mode/dynamic/mode
+ if(istype(SSticker.mode,/datum/game_mode/dynamic))
+ mode = SSticker.mode
+ assassin_prob = max(0,mode.threat_level-40)
+ if(prob(assassin_prob))
+ if(prob(assassin_prob))
+ var/datum/objective/assassinate/once/kill_objective = new
+ kill_objective.owner = T.owner
+ kill_objective.find_target()
+ T.add_objective(kill_objective)
+ else
+ var/datum/objective/maroon/maroon_objective = new
+ maroon_objective.owner = T.owner
+ maroon_objective.find_target()
+ T.add_objective(maroon_objective)
+ else
+ if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
+ var/datum/objective/download/download_objective = new
+ download_objective.owner = T.owner
+ download_objective.gen_amount_goal()
+ T.add_objective(download_objective)
+ else if(prob(70)) // cum. not counting download: 40%.
+ var/datum/objective/steal/steal_objective = new
+ steal_objective.owner = T.owner
+ steal_objective.find_target()
+ T.add_objective(steal_objective)
+ else
+ var/datum/objective/sabotage/sabotage_objective = new
+ sabotage_objective.owner = T.owner
+ sabotage_objective.find_target()
+ T.add_objective(sabotage_objective)
diff --git a/code/modules/antagonists/traitor/classes/traitor_class.dm b/code/modules/antagonists/traitor/classes/traitor_class.dm
new file mode 100644
index 0000000000..3df9dec929
--- /dev/null
+++ b/code/modules/antagonists/traitor/classes/traitor_class.dm
@@ -0,0 +1,40 @@
+GLOBAL_LIST_EMPTY(traitor_classes)
+
+/datum/traitor_class
+ var/name = "Bad Coders Ltd."
+ var/employer = "The Syndicate"
+ var/weight = 0
+ var/chaos = 0
+ var/cost = 0
+ var/TC = 20
+ var/list/uplink_filters
+
+/datum/traitor_class/New()
+ ..()
+ if(src.type in GLOB.traitor_classes)
+ qdel(src)
+ else
+ GLOB.traitor_classes += src.type
+ GLOB.traitor_classes[src.type] = src
+
+/datum/traitor_class/proc/forge_objectives(datum/antagonist/traitor/T)
+ // Like the old forge_human_objectives. Makes all the objectives for this traitor class.
+
+/datum/traitor_class/proc/forge_single_objective(datum/antagonist/traitor/T)
+ // As forge_single_objective.
+
+/datum/traitor_class/proc/on_removal(datum/antagonist/traitor/T)
+ // What this does to the antag datum on removal. Called before proper removal, obviously.
+
+/datum/traitor_class/proc/apply_innate_effects(mob/living/M)
+ // What innate effects it should have. See: AI.
+
+/datum/traitor_class/proc/remove_innate_effects(mob/living/M)
+ // Cleaning up the innate effects.
+
+/datum/traitor_class/proc/greet(datum/antagonist/traitor/T)
+ // Message upon creation. Not necessary, but can be useful.
+
+/datum/traitor_class/proc/finalize_traitor(datum/antagonist/traitor/T)
+ // Finalization. Return TRUE if should play standard traitor sound/equip, return FALSE if both are special case
+ return TRUE
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index 0352272f70..a9dee81a6c 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -1,6 +1,3 @@
-#define TRAITOR_HUMAN "human"
-#define TRAITOR_AI "AI"
-
/datum/antagonist/traitor
name = "Traitor"
roundend_category = "traitors"
@@ -12,43 +9,52 @@
var/give_objectives = TRUE
var/should_give_codewords = TRUE
var/should_equip = TRUE
- var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
+ var/datum/traitor_class/traitor_kind
var/datum/contractor_hub/contractor_hub
hijack_speed = 0.5 //10 seconds per hijack stage by default
+/datum/antagonist/traitor/New()
+ ..()
+ if(!GLOB.traitor_classes.len)//Only need to fill the list when it's needed.
+ for(var/I in subtypesof(/datum/traitor_class))
+ new I
+
+/datum/antagonist/traitor/proc/set_traitor_kind(var/kind)
+ traitor_kind = GLOB.traitor_classes[kind]
+ if(istype(SSticker.mode, /datum/game_mode/dynamic))
+ var/datum/game_mode/dynamic/mode = SSticker.mode
+ if(traitor_kind.cost)
+ mode.spend_threat(traitor_kind.cost)
+ mode.log_threat("[traitor_kind.cost] was spent due to [owner.name] being a [traitor_kind.name].")
+
/datum/antagonist/traitor/on_gain()
if(owner.current && isAI(owner.current))
- traitor_kind = TRAITOR_AI
-
+ set_traitor_kind(TRAITOR_AI)
+ else
+ var/chaos_weight = 0
+ if(istype(SSticker.mode,/datum/game_mode/dynamic))
+ var/datum/game_mode/dynamic/mode = SSticker.mode
+ chaos_weight = (mode.threat - 50)/50
+ var/list/weights = list()
+ for(var/C in GLOB.traitor_classes)
+ var/datum/traitor_class/class = GLOB.traitor_classes[C]
+ var/weight = (1.5*class.weight)/(0.5+NUM_E**(-chaos_weight*class.chaos)) // just a logistic function
+ weights[C] = weight
+ var/choice = pickweightAllowZero(weights)
+ if(!choice)
+ choice = GLOB.traitor_classes[TRAITOR_HUMAN]
+ set_traitor_kind(pickweightAllowZero(weights))
+ traitor_kind.weight *= 0.8 // less likely this round
SSticker.mode.traitors += owner
owner.special_role = special_role
if(give_objectives)
- forge_traitor_objectives()
+ traitor_kind.forge_objectives(src)
finalize_traitor()
..()
-/datum/antagonist/traitor/apply_innate_effects()
- if(owner.assigned_role == "Clown")
- var/mob/living/carbon/human/traitor_mob = owner.current
- if(traitor_mob && istype(traitor_mob))
- if(!silent)
- to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
- traitor_mob.dna.remove_mutation(CLOWNMUT)
-
-/datum/antagonist/traitor/remove_innate_effects()
- if(owner.assigned_role == "Clown")
- var/mob/living/carbon/human/traitor_mob = owner.current
- if(traitor_mob && istype(traitor_mob))
- traitor_mob.dna.add_mutation(CLOWNMUT)
-
/datum/antagonist/traitor/on_removal()
//Remove malf powers.
- if(traitor_kind == TRAITOR_AI && owner.current && isAI(owner.current))
- var/mob/living/silicon/ai/A = owner.current
- A.set_zeroth_law("")
- A.verbs -= /mob/living/silicon/ai/proc/choose_modules
- A.malf_picker.remove_malf_verbs(A)
- qdel(A.malf_picker)
+ traitor_kind.on_removal(src)
SSticker.mode.traitors -= owner
if(!silent && owner.current)
to_chat(owner.current,"
You are no longer the [special_role]! ")
@@ -69,192 +75,11 @@
objectives -= O
/datum/antagonist/traitor/proc/forge_traitor_objectives()
- switch(traitor_kind)
- if(TRAITOR_AI)
- forge_ai_objectives()
- else
- forge_human_objectives()
-
-/datum/antagonist/traitor/proc/forge_human_objectives()
- var/is_hijacker = FALSE
- var/datum/game_mode/dynamic/mode
- var/is_dynamic = FALSE
- var/hijack_prob = 0
- if(istype(SSticker.mode,/datum/game_mode/dynamic))
- mode = SSticker.mode
- is_dynamic = TRUE
- if(mode.threat >= CONFIG_GET(number/dynamic_hijack_cost))
- hijack_prob = CLAMP(mode.threat_level-50,0,20)
- if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit)
- is_hijacker = (prob(hijack_prob) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement))
- else
- var/indice_pop = min(10,round(GLOB.joined_player_list.len/mode.pop_per_requirement)+1)
- is_hijacker = (prob(hijack_prob) && (mode.threat_level >= CONFIG_GET(number_list/dynamic_hijack_requirements)[indice_pop]))
- if(mode.storyteller.flags & NO_ASSASSIN)
- is_hijacker = FALSE
- else if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks
- hijack_prob = 10
- is_hijacker = prob(10)
- var/martyr_chance = prob(hijack_prob*2)
- var/objective_count = is_hijacker //Hijacking counts towards number of objectives
- if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
- if(!SSticker.mode.exchange_red)
- SSticker.mode.exchange_red = owner
- else
- SSticker.mode.exchange_blue = owner
- assign_exchange_role(SSticker.mode.exchange_red)
- assign_exchange_role(SSticker.mode.exchange_blue)
- objective_count += 1 //Exchange counts towards number of objectives
- var/toa = CONFIG_GET(number/traitor_objectives_amount)
- for(var/i = objective_count, i < toa, i++)
- forge_single_objective()
-
- if(is_hijacker && objective_count <= toa) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
- if (!(locate(/datum/objective/hijack) in objectives))
- var/datum/objective/hijack/hijack_objective = new
- hijack_objective.owner = owner
- add_objective(hijack_objective)
- if(is_dynamic)
- var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
- mode.spend_threat(threat_spent)
- mode.log_threat("[owner.name] spent [threat_spent] on hijack.")
- return
-
-
- var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead.
- for(var/datum/objective/O in objectives)
- if(!O.martyr_compatible)
- martyr_compatibility = 0
- break
-
- if(martyr_compatibility && martyr_chance)
- var/datum/objective/martyr/martyr_objective = new
- martyr_objective.owner = owner
- add_objective(martyr_objective)
- if(is_dynamic)
- var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
- mode.spend_threat(threat_spent)
- mode.log_threat("[owner.name] spent [threat_spent] on glorious death.")
- return
-
- else
- if(!(locate(/datum/objective/escape) in objectives))
- var/datum/objective/escape/escape_objective = new
- escape_objective.owner = owner
- add_objective(escape_objective)
- return
-
-/datum/antagonist/traitor/proc/forge_ai_objectives()
- var/objective_count = 0
-
- if(prob(30))
- objective_count += forge_single_objective()
-
- for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
- var/datum/objective/assassinate/kill_objective = new
- kill_objective.owner = owner
- kill_objective.find_target()
- add_objective(kill_objective)
-
- var/datum/objective/survive/exist/exist_objective = new
- exist_objective.owner = owner
- add_objective(exist_objective)
-
-
-/datum/antagonist/traitor/proc/forge_single_objective()
- switch(traitor_kind)
- if(TRAITOR_AI)
- return forge_single_AI_objective()
- else
- return forge_single_human_objective()
-
-/datum/antagonist/traitor/proc/forge_single_human_objective() //Returns how many objectives are added
- .=1
- var/assassin_prob = 50
- var/is_dynamic = FALSE
- var/datum/game_mode/dynamic/mode
- if(istype(SSticker.mode,/datum/game_mode/dynamic))
- mode = SSticker.mode
- is_dynamic = TRUE
- assassin_prob = max(0,mode.threat_level-20)
- if(prob(assassin_prob))
- if(is_dynamic)
- var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
- mode.spend_threat(threat_spent)
- mode.log_threat("[owner.name] spent [threat_spent] on an assassination target.")
- var/list/active_ais = active_ais()
- if(active_ais.len && prob(100/GLOB.joined_player_list.len))
- var/datum/objective/destroy/destroy_objective = new
- destroy_objective.owner = owner
- destroy_objective.find_target()
- add_objective(destroy_objective)
- else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
- var/datum/objective/maroon/maroon_objective = new
- maroon_objective.owner = owner
- maroon_objective.find_target()
- add_objective(maroon_objective)
- else if(prob(max(0,assassin_prob-20)))
- var/datum/objective/assassinate/kill_objective = new
- kill_objective.owner = owner
- kill_objective.find_target()
- add_objective(kill_objective)
- else
- var/datum/objective/assassinate/once/kill_objective = new
- kill_objective.owner = owner
- kill_objective.find_target()
- add_objective(kill_objective)
- else
- if(prob(15) && !(locate(/datum/objective/download) in objectives) && !(owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
- var/datum/objective/download/download_objective = new
- download_objective.owner = owner
- download_objective.gen_amount_goal()
- add_objective(download_objective)
- else if(prob(40)) // cum. not counting download: 40%.
- var/datum/objective/steal/steal_objective = new
- steal_objective.owner = owner
- steal_objective.find_target()
- add_objective(steal_objective)
- else if(prob(100/3)) // cum. not counting download: 20%.
- var/datum/objective/sabotage/sabotage_objective = new
- sabotage_objective.owner = owner
- sabotage_objective.find_target()
- add_objective(sabotage_objective)
- else // cum. not counting download: 40%
- var/datum/objective/flavor/traitor/flavor_objective = new
- flavor_objective.owner = owner
- flavor_objective.forge_objective()
- add_objective(flavor_objective)
-
-/datum/antagonist/traitor/proc/forge_single_AI_objective()
- .=1
- var/special_pick = rand(1,4)
- switch(special_pick)
- if(1)
- var/datum/objective/block/block_objective = new
- block_objective.owner = owner
- add_objective(block_objective)
- if(2)
- var/datum/objective/purge/purge_objective = new
- purge_objective.owner = owner
- add_objective(purge_objective)
- if(3)
- var/datum/objective/robot_army/robot_objective = new
- robot_objective.owner = owner
- add_objective(robot_objective)
- if(4) //Protect and strand a target
- var/datum/objective/protect/yandere_one = new
- yandere_one.owner = owner
- add_objective(yandere_one)
- yandere_one.find_target()
- var/datum/objective/maroon/yandere_two = new
- yandere_two.owner = owner
- yandere_two.target = yandere_one.target
- yandere_two.update_explanation_text() // normally called in find_target()
- add_objective(yandere_two)
- .=2
+ traitor_kind.forge_objectives(src)
/datum/antagonist/traitor/greet()
to_chat(owner.current, "
You are the [owner.special_role].")
+ traitor_kind.greet(src)
owner.announce_objectives()
if(should_give_codewords)
give_codewords()
@@ -270,32 +95,33 @@
set_antag_hud(owner.current, null)
/datum/antagonist/traitor/proc/finalize_traitor()
- switch(traitor_kind)
- if(TRAITOR_AI)
- add_law_zero()
- owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
- owner.current.grant_language(/datum/language/codespeak)
- if(TRAITOR_HUMAN)
- if(should_equip)
- equip(silent)
- owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
+ if(traitor_kind.finalize_traitor(src))
+ if(should_equip)
+ equip(silent)
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
/datum/antagonist/traitor/apply_innate_effects(mob/living/mob_override)
. = ..()
update_traitor_icons_added()
var/mob/M = mob_override || owner.current
- if(isAI(M) && traitor_kind == TRAITOR_AI)
- var/mob/living/silicon/ai/A = M
- A.hack_software = TRUE
+ traitor_kind.apply_innate_effects(M)
+ if(owner.assigned_role == "Clown")
+ var/mob/living/carbon/human/H = M
+ if(istype(H))
+ if(!silent)
+ to_chat(H, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
+ H.dna.remove_mutation(CLOWNMUT)
RegisterSignal(M, COMSIG_MOVABLE_HEAR, .proc/handle_hearing)
/datum/antagonist/traitor/remove_innate_effects(mob/living/mob_override)
. = ..()
update_traitor_icons_removed()
var/mob/M = mob_override || owner.current
- if(isAI(M) && traitor_kind == TRAITOR_AI)
- var/mob/living/silicon/ai/A = M
- A.hack_software = FALSE
+ traitor_kind.remove_innate_effects(M)
+ if(owner.assigned_role == "Clown")
+ var/mob/living/carbon/human/H = M
+ if(istype(H))
+ H.dna.add_mutation(CLOWNMUT)
UnregisterSignal(M, COMSIG_MOVABLE_HEAR)
/datum/antagonist/traitor/proc/give_codewords()
@@ -326,8 +152,7 @@
killer.add_malf_picker()
/datum/antagonist/traitor/proc/equip(var/silent = FALSE)
- if(traitor_kind == TRAITOR_HUMAN)
- owner.equip_traitor(employer, silent, src)
+ owner.equip_traitor(traitor_kind, silent, src)
/datum/antagonist/traitor/proc/assign_exchange_role()
//set faction
diff --git a/code/modules/antagonists/wishgranter/wishgranter.dm b/code/modules/antagonists/wishgranter/wishgranter.dm
index d22d1b5e39..15ec78692f 100644
--- a/code/modules/antagonists/wishgranter/wishgranter.dm
+++ b/code/modules/antagonists/wishgranter/wishgranter.dm
@@ -24,5 +24,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/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm
index da76356ebe..ecb861f93d 100644
--- a/code/modules/antagonists/wizard/equipment/spellbook.dm
+++ b/code/modules/antagonists/wizard/equipment/spellbook.dm
@@ -375,6 +375,8 @@
desc = "A collection of wands that allow for a wide variety of utility. Wands have a limited number of charges, so be conservative in use. Comes in a handy belt."
item_path = /obj/item/storage/belt/wands/full
category = "Defensive"
+ dynamic_requirement = 60
+ dynamic_cost = 10
/datum/spellbook_entry/item/armor
name = "Mastercrafted Armor Set"
diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm
index 3dfc0d859d..a40a4c1a42 100644
--- a/code/modules/assembly/bomb.dm
+++ b/code/modules/assembly/bomb.dm
@@ -103,10 +103,10 @@
bombassembly.setDir(dir)
bombassembly.Move()
-/obj/item/onetankbomb/dropped()
+/obj/item/onetankbomb/dropped(mob/user)
. = ..()
if(bombassembly)
- bombassembly.dropped()
+ bombassembly.dropped(user)
diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm
index d7c184de92..c960a7f039 100644
--- a/code/modules/assembly/holder.dm
+++ b/code/modules/assembly/holder.dm
@@ -83,9 +83,9 @@
/obj/item/assembly_holder/dropped(mob/user)
. = ..()
if(a_left)
- a_left.dropped()
+ a_left.dropped(user)
if(a_right)
- a_right.dropped()
+ a_right.dropped(user)
/obj/item/assembly_holder/attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess
. = ..()
diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm
index d19666077d..33c6d46045 100644
--- a/code/modules/assembly/infrared.dm
+++ b/code/modules/assembly/infrared.dm
@@ -20,13 +20,8 @@
/obj/item/assembly/infra/ComponentInitialize()
. = ..()
- AddComponent(
- /datum/component/simple_rotation,
- ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS,
- null,
- null,
- CALLBACK(src,.proc/after_rotation)
- )
+ var/static/rotation_flags = ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS
+ AddComponent(/datum/component/simple_rotation, rotation_flags, after_rotation=CALLBACK(src,.proc/after_rotation))
/obj/item/assembly/infra/proc/after_rotation()
refreshBeam()
@@ -74,7 +69,7 @@
holder.update_icon()
return
-/obj/item/assembly/infra/dropped()
+/obj/item/assembly/infra/dropped(mob/user)
. = ..()
if(holder)
holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder
diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm
index c4bb6e8cdd..594eae5d46 100644
--- a/code/modules/awaymissions/capture_the_flag.dm
+++ b/code/modules/awaymissions/capture_the_flag.dm
@@ -379,7 +379,7 @@
force = 75
mag_type = /obj/item/ammo_box/magazine/m50/ctf
-/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped()
+/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped(mob/user)
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
@@ -402,14 +402,14 @@
desc = "This looks like it could really hurt in melee."
force = 50
-/obj/item/gun/ballistic/automatic/laser/ctf/dropped()
+/obj/item/gun/ballistic/automatic/laser/ctf/dropped(mob/user)
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
/obj/item/ammo_box/magazine/recharge/ctf
ammo_type = /obj/item/ammo_casing/caseless/laser/ctf
-/obj/item/ammo_box/magazine/recharge/ctf/dropped()
+/obj/item/ammo_box/magazine/recharge/ctf/dropped(mob/user)
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
@@ -475,7 +475,7 @@
return TRUE
return ..()
-/obj/item/claymore/ctf/dropped()
+/obj/item/claymore/ctf/dropped(mob/user)
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm
index ac1a4077ec..505b9a1edc 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/misc.dm b/code/modules/cargo/packs/misc.dm
index d9c9794bd8..80d6f76910 100644
--- a/code/modules/cargo/packs/misc.dm
+++ b/code/modules/cargo/packs/misc.dm
@@ -89,32 +89,17 @@
/datum/supply_pack/misc/paper_work
name = "Freelance Paper work"
- desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (20) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
- cost = 700 // Net of 0 credits but makes (120 x 20 = 2400)
+ desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
+ cost = 700 // Net of 0 credits but makes (120 x 10 = 1200)
contains = list(/obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
/obj/item/pen/fountain
)
crate_name = "Paperwork"
+/datum/supply_pack/misc/paper_work/generate()
+ . = ..()
+ for(var/i in 1 to 9)
+ new /obj/item/folder/paperwork(.)
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////// Entertainment ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -123,16 +108,14 @@
name = "Bedsheet Crate (R)"
desc = "Snuggle up in some sweet sheets with this assorted bedsheet crate. Each set comes with eight random bedsheets for your slumbering pleasure!"
cost = 2000
- contains = list(/obj/item/bedsheet/random,
- /obj/item/bedsheet/random,
- /obj/item/bedsheet/random,
- /obj/item/bedsheet/random,
- /obj/item/bedsheet/random,
- /obj/item/bedsheet/random,
- /obj/item/bedsheet/random,
- /obj/item/bedsheet/random) //I'm lazy, and I copy paste stuff.
+ contains = list(/obj/item/bedsheet/random)
crate_name = "random bedsheet crate"
+/datum/supply_pack/misc/randombedsheets/generate()
+ . = ..()
+ for(var/i in 1 to 7)
+ new /obj/item/bedsheet/random(.)
+
/datum/supply_pack/misc/coloredsheets
name = "Bedsheet Crate (C)"
desc = "Give your night life a splash of color with this crate filled with bedsheets! Contains a total of nine different-colored sheets."
@@ -208,13 +191,14 @@
name = "Dueling Pistols"
desc = "Resolve all your quarrels with some nonlethal fun."
cost = 2000
- contains = list(/obj/item/storage/lockbox/dueling/hugbox/stamina,
- /obj/item/storage/lockbox/dueling/hugbox/stamina,
- /obj/item/storage/lockbox/dueling/hugbox/stamina,
- /obj/item/storage/lockbox/dueling/hugbox/stamina,
- /obj/item/storage/lockbox/dueling/hugbox/stamina)
+ contains = list(/obj/item/storage/lockbox/dueling/hugbox/stamina)
crate_name = "dueling pistols"
+/datum/supply_pack/misc/dueling_stam/generate()
+ . = ..()
+ for(var/i in 1 to 3)
+ new /obj/item/storage/lockbox/dueling/hugbox/stamina(.)
+
/datum/supply_pack/misc/dueling_lethal
name = "Lethal Dueling Pistols"
desc = "Settle your differences the true spaceman way."
@@ -240,12 +224,7 @@
cost = 12000
var/num_contained = 3
contains = list(/obj/item/ammo_box/a357,
- /obj/item/ammo_box/a357,
- /obj/item/ammo_box/a357,
/obj/item/ammo_box/magazine/pistolm9mm,
- /obj/item/ammo_box/magazine/pistolm9mm,
- /obj/item/ammo_box/magazine/pistolm9mm,
- /obj/item/ammo_box/magazine/m45/kitchengun,
/obj/item/ammo_box/magazine/m45/kitchengun)
crate_name = "crate"
diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm
index 902b442403..7bafefcf53 100644
--- a/code/modules/client/asset_cache.dm
+++ b/code/modules/client/asset_cache.dm
@@ -703,3 +703,10 @@ 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/client/verbs/minimap.dm b/code/modules/client/verbs/minimap.dm
new file mode 100644
index 0000000000..3d213dc210
--- /dev/null
+++ b/code/modules/client/verbs/minimap.dm
@@ -0,0 +1,10 @@
+/client/verb/show_station_minimap()
+ set category = "OOC"
+ set name = "Show Station Minimap"
+ set desc = "Shows a minimap of the currently loaded station map."
+
+ if(!CONFIG_GET(flag/minimaps_enabled))
+ to_chat(usr, "
Minimap generation is not enabled in the server's configuration.")
+ return
+
+ SSminimaps.station_minimap.show(src)
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index cb169f4f62..19ff6bc8b2 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -9,10 +9,10 @@
var/flipped = 0
-/obj/item/clothing/head/soft/dropped()
- src.icon_state = "[item_color]soft"
- src.flipped=0
- ..()
+/obj/item/clothing/head/soft/dropped(mob/user)
+ icon_state = "[item_color]soft"
+ flipped = FALSE
+ return ..()
/obj/item/clothing/head/soft/verb/flipcap()
set category = "Object"
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 84990f9660..c743f26363 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -247,6 +247,30 @@
/obj/item/clothing/mask/bandana/attack_self(mob/user)
adjustmask(user)
+/obj/item/clothing/mask/bandana/AltClick(mob/user)
+ . = ..()
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ if((C.get_item_by_slot(SLOT_HEAD == src)) || (C.get_item_by_slot(SLOT_WEAR_MASK) == src))
+ to_chat(user, "
You can't tie [src] while wearing it!")
+ return
+ if(slot_flags & ITEM_SLOT_HEAD)
+ to_chat(user, "
You must undo [src] before you can tie it into a neckerchief!")
+ else
+ if(user.is_holding(src))
+ var/obj/item/clothing/neck/neckerchief/nk = new(src)
+ nk.name = "[name] neckerchief"
+ nk.desc = "[desc] It's tied up like a neckerchief."
+ nk.icon_state = icon_state
+ nk.sourceBandanaType = src.type
+ var/currentHandIndex = user.get_held_index_of_item(src)
+ user.transferItemToLoc(src, null)
+ user.put_in_hand(nk, currentHandIndex)
+ user.visible_message("
You tie [src] up like a neckerchief.", "
[user] ties [src] up like a neckerchief.")
+ qdel(src)
+ else
+ to_chat(user, "
You must be holding [src] in order to tie it!")
+
/obj/item/clothing/mask/bandana/red
name = "red bandana"
desc = "A fine red bandana with nanotech lining."
diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm
index 2b43460257..530af7777d 100644
--- a/code/modules/clothing/neck/_neck.dm
+++ b/code/modules/clothing/neck/_neck.dm
@@ -291,3 +291,36 @@
icon = 'icons/obj/clothing/neck.dmi'
icon_state = "bling"
item_color = "bling"
+
+//////////////////////////////////
+//VERY SUPER BADASS NECKERCHIEFS//
+//////////////////////////////////
+
+obj/item/clothing/neck/neckerchief
+ icon = 'icons/obj/clothing/masks.dmi' //In order to reuse the bandana sprite
+ w_class = WEIGHT_CLASS_TINY
+ var/sourceBandanaType
+
+/obj/item/clothing/neck/neckerchief/worn_overlays(isinhands)
+ . = ..()
+ if(!isinhands)
+ var/mutable_appearance/realOverlay = mutable_appearance('icons/mob/mask.dmi', icon_state)
+ realOverlay.pixel_y = -3
+ . += realOverlay
+
+/obj/item/clothing/neck/neckerchief/AltClick(mob/user)
+ . = ..()
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ if(C.get_item_by_slot(SLOT_NECK) == src)
+ to_chat(user, "You can't untie [src] while wearing it!")
+ return
+ if(user.is_holding(src))
+ var/obj/item/clothing/mask/bandana/newBand = new sourceBandanaType(user)
+ var/currentHandIndex = user.get_held_index_of_item(src)
+ var/oldName = src.name
+ qdel(src)
+ user.put_in_hand(newBand, currentHandIndex)
+ user.visible_message("You untie [oldName] back into a [newBand.name]", "[user] unties [oldName] back into a [newBand.name]")
+ else
+ to_chat(user, "You must be holding [src] in order to untie it!")
diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm
index 81fedcf57c..4311aa5166 100644
--- a/code/modules/clothing/spacesuits/chronosuit.dm
+++ b/code/modules/clothing/spacesuits/chronosuit.dm
@@ -8,16 +8,11 @@
resistance_flags = FIRE_PROOF | ACID_PROOF
var/obj/item/clothing/suit/space/chronos/suit = null
-/obj/item/clothing/head/helmet/space/chronos/dropped()
+/obj/item/clothing/head/helmet/space/chronos/dropped(mob/user)
if(suit)
suit.deactivate(1, 1)
..()
-/obj/item/clothing/head/helmet/space/chronos/Destroy()
- dropped()
- return ..()
-
-
/obj/item/clothing/suit/space/chronos
name = "Chronosuit"
desc = "An advanced spacesuit equipped with time-bluespace teleportation and anti-compression technology."
@@ -57,15 +52,11 @@
else
deactivate()
-/obj/item/clothing/suit/space/chronos/dropped()
+/obj/item/clothing/suit/space/chronos/dropped(mob/user)
if(activated)
deactivate()
..()
-/obj/item/clothing/suit/space/chronos/Destroy()
- dropped()
- return ..()
-
/obj/item/clothing/suit/space/chronos/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
diff --git a/code/modules/clothing/spacesuits/flightsuit.dm b/code/modules/clothing/spacesuits/flightsuit.dm
index 2f9ded7848..89644667d0 100644
--- a/code/modules/clothing/spacesuits/flightsuit.dm
+++ b/code/modules/clothing/spacesuits/flightsuit.dm
@@ -805,7 +805,8 @@
. += "Its maintainence panel is [maint_panel ? "OPEN" : "CLOSED"]"
/obj/item/clothing/suit/space/hardsuit/flightsuit/Destroy()
- dropped()
+ if(ismob(loc))
+ dropped(loc)
QDEL_NULL(pack)
QDEL_NULL(shoes)
return ..()
@@ -834,7 +835,7 @@
return FALSE
return ..()
-/obj/item/clothing/suit/space/hardsuit/flightsuit/dropped()
+/obj/item/clothing/suit/space/hardsuit/flightsuit/dropped(mob/the_user)
if(deployedpack)
retract_flightpack(TRUE)
if(deployedshoes)
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index 4df7061991..1f23569a9c 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -707,7 +707,7 @@
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/on_mob_move)
listeningTo = user
-/obj/item/clothing/suit/space/hardsuit/ancient/dropped()
+/obj/item/clothing/suit/space/hardsuit/ancient/dropped(mob/user)
. = ..()
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm
index 79b221a807..cbbd64ebcc 100644
--- a/code/modules/clothing/suits/toggles.dm
+++ b/code/modules/clothing/suits/toggles.dm
@@ -45,7 +45,7 @@
var/datum/action/A = X
A.UpdateButtonIcon()
-/obj/item/clothing/suit/hooded/dropped()
+/obj/item/clothing/suit/hooded/dropped(mob/user)
..()
RemoveHood()
@@ -76,7 +76,7 @@
suit = null
return ..()
-/obj/item/clothing/head/hooded/dropped()
+/obj/item/clothing/head/hooded/dropped(mob/user)
..()
if(suit)
suit.RemoveHood()
@@ -174,7 +174,7 @@
else
helmet.forceMove(src)
-/obj/item/clothing/suit/space/hardsuit/dropped()
+/obj/item/clothing/suit/space/hardsuit/dropped(mob/user)
..()
RemoveHelmet()
diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm
index 68c5d8c5c8..490cd0ff21 100644
--- a/code/modules/events/disease_outbreak.dm
+++ b/code/modules/events/disease_outbreak.dm
@@ -59,7 +59,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/events/portal_storm.dm b/code/modules/events/portal_storm.dm
index 5ef30d0030..457b5bd4ec 100644
--- a/code/modules/events/portal_storm.dm
+++ b/code/modules/events/portal_storm.dm
@@ -4,6 +4,7 @@
weight = 2
min_players = 15
earliest_start = 30 MINUTES
+ gamemode_blacklist = list("dynamic")
/datum/round_event/portal_storm/syndicate_shocktroop
boss_types = list(/mob/living/simple_animal/hostile/syndicate/melee/space/stormtrooper = 2)
diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm
index 9dbe1443d1..b7f8b8f911 100644
--- a/code/modules/events/wormholes.dm
+++ b/code/modules/events/wormholes.dm
@@ -4,6 +4,7 @@
max_occurrences = 3
weight = 2
min_players = 2
+ gamemode_blacklist = list("dynamic")
/datum/round_event/wormholes
diff --git a/code/modules/fields/fields.dm b/code/modules/fields/fields.dm
index 5b0b4bc1f8..8710282021 100644
--- a/code/modules/fields/fields.dm
+++ b/code/modules/fields/fields.dm
@@ -312,7 +312,7 @@
else if(!operating)
QDEL_NULL(current)
-/obj/item/multitool/field_debug/dropped()
+/obj/item/multitool/field_debug/dropped(mob/user)
. = ..()
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm
index 7668d17ac1..0411a80443 100644
--- a/code/modules/hydroponics/grown/banana.dm
+++ b/code/modules/hydroponics/grown/banana.dm
@@ -151,7 +151,7 @@
spawn(30)
if(!QDELETED(src))
var/mob/living/simple_animal/banana_spider/S = new /mob/living/simple_animal/banana_spider(get_turf(src.loc))
- S.speed += round(10 / seed.potency)
+ S.speed += round(10 / max(seed.potency, 1), 1)
S.visible_message("The banana spider chitters as it stretches its legs.")
qdel(src)
diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm
index 3183a6d0e6..d1cd852651 100644
--- a/code/modules/integrated_electronics/subtypes/manipulation.dm
+++ b/code/modules/integrated_electronics/subtypes/manipulation.dm
@@ -402,11 +402,22 @@
power_draw_per_use = 40
ext_cooldown = 1
cooldown_per_use = 10
- var/list/mtypes = list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/uranium, /datum/material/plasma, /datum/material/bluespace, /datum/material/bananium, /datum/material/titanium, /datum/material/plastic)
+ var/static/list/mtypes = list(
+ /datum/material/iron,
+ /datum/material/glass,
+ /datum/material/silver,
+ /datum/material/gold,
+ /datum/material/diamond,
+ /datum/material/uranium,
+ /datum/material/plasma,
+ /datum/material/bluespace,
+ /datum/material/bananium,
+ /datum/material/titanium,
+ /datum/material/plastic
+ )
-/obj/item/integrated_circuit/manipulation/matman/Initialize()
- var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
- mtypes, 100000, FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
+/obj/item/integrated_circuit/manipulation/matman/ComponentInitialize()
+ var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, mtypes, 100000, FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.precise_insertion = TRUE
.=..()
diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm
index d7f59ff883..6efa95cd91 100644
--- a/code/modules/jobs/job_types/geneticist.dm
+++ b/code/modules/jobs/job_types/geneticist.dm
@@ -32,4 +32,5 @@
backpack = /obj/item/storage/backpack/genetics
satchel = /obj/item/storage/backpack/satchel/gen
duffelbag = /obj/item/storage/backpack/duffelbag/med
+ l_pocket = /obj/item/sequence_scanner
diff --git a/code/modules/mapping/mapping_helpers/_mapping_helpers.dm b/code/modules/mapping/mapping_helpers/_mapping_helpers.dm
index 99184b1c3e..4de16ba350 100644
--- a/code/modules/mapping/mapping_helpers/_mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers/_mapping_helpers.dm
@@ -97,7 +97,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
if(target_type && !istype(A,target_type))
continue
var/cargs = build_args()
- A.AddComponent(arglist(cargs))
+ A._AddComponent(cargs)
qdel(src)
return
diff --git a/code/modules/mapping/minimaps.dm b/code/modules/mapping/minimaps.dm
new file mode 100644
index 0000000000..c347a8d7a6
--- /dev/null
+++ b/code/modules/mapping/minimaps.dm
@@ -0,0 +1,155 @@
+/datum/minimap
+ var/name
+ var/icon/map_icon
+ var/icon/meta_icon
+ var/icon/overlay_icon
+ var/list/color_area_names = list()
+ var/minx
+ var/maxx
+ var/miny
+ var/maxy
+ var/z_level
+ var/id = 0
+ var/static/next_id = 0
+
+/datum/minimap/New(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy, name)
+ src.name = name
+ id = ++next_id
+ z_level = z
+
+ var/crop_x1 = x2
+ var/crop_x2 = x1
+ var/crop_y1 = y2
+ var/crop_y2 = y1
+
+ // do the generating
+ map_icon = new('html/blank.png')
+ meta_icon = new('html/blank.png')
+ map_icon.Scale(x2-x1+1, y2-y1+1) // arrays start at 1
+ meta_icon.Scale(x2-x1+1, y2-y1+1)
+ var/list/area_to_color = list()
+ for(var/turf/T in block(locate(x1,y1,z),locate(x2,y2,z)))
+ var/area/A = T.loc
+ var/img_x = T.x - x1 + 1 // arrays start at 1
+ var/img_y = T.y - y1 + 1
+ if(!istype(A, /area/space) || istype(T, /turf/closed/wall))
+ crop_x1 = min(crop_x1, T.x)
+ crop_x2 = max(crop_x2, T.x)
+ crop_y1 = min(crop_y1, T.y)
+ crop_y2 = max(crop_y2, T.y)
+ var/meta_color = area_to_color[A]
+ if(!meta_color)
+ meta_color = rgb(rand(0,255),rand(0,255),rand(0,255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens
+ area_to_color[A] = meta_color
+ color_area_names[meta_color] = A.name
+ meta_icon.DrawBox(meta_color, img_x, img_y)
+ if(istype(T, /turf/closed/wall))
+ map_icon.DrawBox("#000000", img_x, img_y)
+ else if(!istype(A, /area/space))
+ var/color = A.minimap_color || "#FF00FF"
+ if(locate(/obj/machinery/power/solar) in T)
+ color = "#02026a"
+ if((locate(/obj/effect/spawner/structure/window) in T) || (locate(/obj/structure/grille) in T))
+ color = BlendRGB(color, "#000000", 0.5)
+ map_icon.DrawBox(color, img_x, img_y)
+ map_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2)
+ meta_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2)
+ minx = crop_x1
+ maxx = crop_x2
+ miny = crop_y1
+ maxy = crop_y2
+ overlay_icon = new(map_icon)
+ overlay_icon.Scale(16, 16)
+
+/datum/minimap/proc/send(mob/user)
+ register_asset("minimap-[id].png", map_icon)
+ register_asset("minimap-[id]-meta.png", meta_icon)
+ send_asset_list(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon), verify=FALSE)
+
+/datum/minimap_group
+ var/list/minimaps
+ var/static/next_id = 0
+ var/id
+ var/name
+
+/datum/minimap_group/New(list/maps, name)
+ id = ++next_id
+ src.name = name
+ minimaps = maps || list()
+
+/datum/minimap_group/proc/show(mob/user)
+ if(!length(minimaps))
+ to_chat(user, "ERROR: Attempted to access an empty datum/minimap_group. This should probably not happen.")
+ return
+ var/list/datas = list()
+ var/list/info = list()
+ var/datum/minimap/first_map = minimaps[1]
+ for(var/i in 1 to length(minimaps))
+ var/datum/minimap/M = minimaps[i]
+ M.send(user)
+ info += "
"
+ datas += json_encode(M.color_area_names);
+ info = info.Join()
+
+ var/html = {"
+
+
+
+
+
+
+[name]
+
+[info]
+"}
+
+ user << browse(html, "window=minimap_[id];size=768x[round(768 / first_map.map_icon.Width() * first_map.map_icon.Height() + 50)]")
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 5faa465b8c..bf25bb9da8 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -463,30 +463,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
@@ -503,6 +518,9 @@
else
. = ..()
+/obj/effect/immortality_talisman/void
+ vanish_description = "is dragged into the void"
+
//Shared Bag
@@ -957,7 +975,7 @@
if(1)
new /obj/item/mayhem(src)
if(2)
- new /obj/item/blood_contract(src)
+ new /obj/item/gun/ballistic/revolver/doublebarrel/super(src)
if(3)
new /obj/item/gun/magic/staff/spellblade(src)
@@ -1028,6 +1046,17 @@
log_combat(user, L, "took out a blood contract on", src)
qdel(src)
+/obj/item/gun/ballistic/revolver/doublebarrel/super
+ name = "super combat shotgun"
+ desc = "From the belly of the beast - or rather, demon. Twice as lethal as a less-than-super shotgun, but a tad bulkier."
+ icon_state = "heckgun"
+ slot_flags = null
+ mag_type = /obj/item/ammo_box/magazine/internal/shot/dual/heck
+ burst_size = 2
+ burst_shot_delay = 0
+ unique_reskin = null
+ sawn_off = TRUE
+
//Colossus
/obj/structure/closet/crate/necropolis/colossus
name = "colossus chest"
diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm
index c0eba668f1..c0356dd1ab 100644
--- a/code/modules/mining/machine_silo.dm
+++ b/code/modules/mining/machine_silo.dm
@@ -15,14 +15,20 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
/obj/machinery/ore_silo/Initialize(mapload)
. = ..()
- AddComponent(/datum/component/material_container,
- list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/plasma, /datum/material/uranium, /datum/material/bananium, /datum/material/titanium, /datum/material/bluespace, /datum/material/plastic),
- INFINITY,
- FALSE,
- /obj/item/stack,
- null,
- null,
- TRUE)
+ var/static/list/materials_list = list(
+ /datum/material/iron,
+ /datum/material/glass,
+ /datum/material/silver,
+ /datum/material/gold,
+ /datum/material/diamond,
+ /datum/material/plasma,
+ /datum/material/uranium,
+ /datum/material/bananium,
+ /datum/material/titanium,
+ /datum/material/bluespace,
+ /datum/material/plastic,
+ )
+ AddComponent(/datum/component/material_container, materials_list, INFINITY, allowed_types=/obj/item/stack, _disable_attackby=TRUE)
if (!GLOB.ore_silo_default && mapload && is_station_level(z))
GLOB.ore_silo_default = src
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 87c8598541..c201f437e4 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -292,9 +292,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit)
penalty += roundstart_quit_limit - world.time
- var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
- if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
- penalty = CANT_REENTER_ROUND
+ if(SSautotransfer.can_fire && SSautotransfer.maxvotes)
+ var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
+ if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
+ penalty = CANT_REENTER_ROUND
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE, (stat == DEAD)? penalty : 0, (stat == DEAD)? TRUE : FALSE) & COMPONENT_BLOCK_GHOSTING)
return
@@ -327,9 +328,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit)
penalty += roundstart_quit_limit - world.time
- var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
- if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
- penalty = CANT_REENTER_ROUND
+ if(SSautotransfer.can_fire && SSautotransfer.maxvotes)
+ var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
+ if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
+ penalty = CANT_REENTER_ROUND
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty == CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
index e7b8250494..4bca3e7f62 100644
--- a/code/modules/mob/living/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -40,7 +40,7 @@
return ..()
/mob/living/brain/update_mobility()
- return ((mobility_flags = (in_contents_of(/obj/mecha)? MOBILITY_FLAGS_DEFAULT : NONE)))
+ return ((mobility_flags = (container?.in_contents_of(/obj/mecha)? MOBILITY_FLAGS_DEFAULT : NONE)))
/mob/living/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up.
return
diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm
index 224b5ad807..173b68fc3c 100644
--- a/code/modules/mob/living/brain/posibrain.dm
+++ b/code/modules/mob/living/brain/posibrain.dm
@@ -28,6 +28,34 @@ GLOBAL_VAR(posibrain_notify_cooldown)
var/list/possible_names //If you leave this blank, it will use the global posibrain names
var/picked_name
+/obj/item/mmi/posibrain/Initialize()
+ . = ..()
+ brainmob = new(src)
+ var/new_name
+ if(!LAZYLEN(possible_names))
+ new_name = pick(GLOB.posibrain_names)
+ else
+ new_name = pick(possible_names)
+ brainmob.name = "[new_name]-[rand(100, 999)]"
+ brainmob.real_name = brainmob.name
+ brainmob.forceMove(src)
+ brainmob.container = src
+ if(autoping)
+ ping_ghosts("created", TRUE)
+ GLOB.poi_list |= src
+ LAZYADD(GLOB.mob_spawners[name], src)
+
+/obj/item/mmi/posibrain/Destroy()
+ latejoin_remove()
+ return ..()
+
+/obj/item/mmi/posibrain/proc/latejoin_remove()
+ GLOB.poi_list -= src
+ var/init_name = initial(name)
+ LAZYREMOVE(GLOB.mob_spawners[init_name], src)
+ if(!LAZYLEN(GLOB.mob_spawners[init_name]))
+ GLOB.mob_spawners -= init_name
+
/obj/item/mmi/posibrain/Topic(href, href_list)
if(href_list["activate"])
var/mob/dead/observer/ghost = usr
@@ -97,15 +125,6 @@ GLOBAL_VAR(posibrain_notify_cooldown)
transfer_personality(user)
latejoin_remove()
-/obj/item/mmi/posibrain/Destroy()
- latejoin_remove()
- return ..()
-
-/obj/item/mmi/posibrain/proc/latejoin_remove()
- GLOB.poi_list -= src
- LAZYREMOVE(GLOB.mob_spawners[name], src)
- if(!LAZYLEN(GLOB.mob_spawners[name]))
- GLOB.mob_spawners -= name
/obj/item/mmi/posibrain/transfer_identity(mob/living/carbon/C)
name = "[initial(name)] ([C])"
@@ -163,23 +182,6 @@ GLOBAL_VAR(posibrain_notify_cooldown)
. += msg
-/obj/item/mmi/posibrain/Initialize()
- . = ..()
- brainmob = new(src)
- var/new_name
- if(!LAZYLEN(possible_names))
- new_name = pick(GLOB.posibrain_names)
- else
- new_name = pick(possible_names)
- brainmob.name = "[new_name]-[rand(100, 999)]"
- brainmob.real_name = brainmob.name
- brainmob.forceMove(src)
- brainmob.container = src
- if(autoping)
- ping_ghosts("created", TRUE)
- GLOB.poi_list |= src
- LAZYADD(GLOB.mob_spawners[name], src)
-
/obj/item/mmi/posibrain/attackby(obj/item/O, mob/user)
return
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index dfd409ef8f..5bb1e6d17d 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -632,6 +632,13 @@
if(M.name == XRAY)
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/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 1ea2fa1130..8bd1a35e07 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -71,6 +71,7 @@
L.embedded_objects |= I
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
I.forceMove(src)
+ I.embedded()
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
visible_message("[I] embeds itself in [src]'s [L.name]!","[I] embeds itself in your [L.name]!")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
@@ -104,7 +105,8 @@
var/basebloodychance = affecting.brute_dam + totitemdamage
if(prob(basebloodychance))
I.add_mob_blood(src)
- bleed(totitemdamage)
+ var/turf/location = get_turf(src)
+ add_splatter_floor(location)
if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
user.add_mob_blood(src)
@@ -262,11 +264,11 @@
jitteriness += 1000 //High numbers for violent convulsions
do_jitter_animation(jitteriness)
stuttering += 2
- if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && (flags & SHOCK_NOSTUN))
+ if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
Stun(40)
spawn(20)
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
- if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && (flags & SHOCK_NOSTUN))
+ if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
DefaultCombatKnockdown(60)
return shock_damage
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 4ef5a3ca04..1fc43f0d41 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -45,31 +45,11 @@
if(spec_return)
return spec_return
- if(mind)
- if (mind.martial_art && mind.martial_art.dodge_chance)
- if(!lying && dna && !dna.check_mutation(HULK))
- if(prob(mind.martial_art.dodge_chance))
- var/static/dodgemessages = list("dodges under",0,-4,"dodges to the right of",-4,0,"dodges to the left of",4,0,"jumps over",0,4)
- var/pick = pick(1,4,7,10)
- var/oldx = pixel_x
- var/oldy = pixel_y
- animate(src,pixel_x = pixel_x + dodgemessages[pick+1],pixel_y = pixel_y + dodgemessages[pick+2],time=3)
- animate(src,pixel_x = oldx,pixel_y = oldy,time=2)
- visible_message("[src] [dodgemessages[pick]] the projectile!", "You dodge the projectile!")
- return BULLET_ACT_FORCE_PIERCE
- if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
- if(prob(mind.martial_art.deflection_chance))
- if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
- if(mind.martial_art.deflection_chance >= 100) //if they can NEVER be hit, lets clue sec in ;)
- visible_message("[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!", "You deflect the projectile!")
- else
- visible_message("[src] deflects the projectile!", "You deflect the projectile!")
- playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
- if(mind.martial_art.reroute_deflection)
- P.firer = src
- P.setAngle(rand(0, 360))//SHING
- return BULLET_ACT_FORCE_PIERCE
-
+ if(mind) //martial art stuff
+ if(mind.martial_art && mind.martial_art.can_use(src)) //Some martial arts users can deflect projectiles!
+ var/martial_art_result = mind.martial_art.on_projectile_hit(src, P, def_zone)
+ if(!(martial_art_result == BULLET_ACT_HIT))
+ return martial_art_result
return ..()
/mob/living/carbon/human/check_reflect(def_zone)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 7507067597..9316a36e6b 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -316,6 +316,7 @@
BP.receive_damage(I.w_class*I.embedding.embedded_fall_pain_multiplier)
BP.embedded_objects -= I
I.forceMove(drop_location())
+ I.unembedded()
visible_message("[I] falls out of [name]'s [BP.name]!","[I] falls out of your [BP.name]!")
if(!has_embedded_objects())
clear_alert("embeddedobject")
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 1cb30a657b..b428f49578 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -69,6 +69,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
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
var/list/special_step_sounds //Sounds to override barefeet walkng
var/grab_sound //Special sound for grabbing
var/datum/outfit/outfit_important_for_life // A path to an outfit that is important for species life e.g. plasmaman outfit
@@ -356,6 +357,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
else
C.type_of_meat = initial(meat)
+ //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)
@@ -1394,7 +1403,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
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()
@@ -1710,7 +1719,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
bloody = 1
var/turf/location = H.loc
if(istype(location))
- H.bleed(totitemdamage)
+ H.add_splatter_floor(location)
if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood
user.add_mob_blood(H)
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 dfa1725026..6468bd1544 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -23,6 +23,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 d2d4c6c658..7ccccd588d 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -61,9 +61,9 @@
H.DefaultCombatKnockdown(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/inventory.dm b/code/modules/mob/living/carbon/inventory.dm
index 24acccdd2e..50801e1c0d 100644
--- a/code/modules/mob/living/carbon/inventory.dm
+++ b/code/modules/mob/living/carbon/inventory.dm
@@ -122,9 +122,9 @@
update_inv_wear_mask()
/mob/living/carbon/wear_mask_update(obj/item/clothing/C, toggle_off = 1)
- if(C.tint || initial(C.tint))
+ if(isclothing(C) && (C.tint || initial(C.tint)))
update_tint()
- update_inv_wear_mask()
+ return ..()
//handle stuff to update when a mob equips/unequips a headgear.
/mob/living/carbon/proc/head_update(obj/item/I, forced)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 639cfc40e2..4aae10c444 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -427,7 +427,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)
@@ -450,9 +449,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 ef2f4b80c7..3d567b0eff 100644
--- a/code/modules/mob/living/carbon/monkey/life.dm
+++ b/code/modules/mob/living/carbon/monkey/life.dm
@@ -42,7 +42,7 @@
if(radiation > RAD_MOB_MUTATE)
if(prob(1))
to_chat(src, "You mutate!")
- randmutb()
+ easy_randmut(NEGATIVE+MINOR_NEGATIVE)
emote("gasp")
domutcheck()
if(radiation > RAD_MOB_VOMIT && prob(RAD_MOB_VOMIT_PROB))
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index e48fc722cd..86b9826c12 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -43,7 +43,7 @@
/mob/living/carbon/monkey/ComponentInitialize()
. = ..()
- AddElement(/datum/element/mob_holder, "monkey", null, null, null, ITEM_SLOT_HEAD)
+ AddElement(/datum/element/mob_holder, worn_state = "monkey", inv_slots = ITEM_SLOT_HEAD)
/mob/living/carbon/monkey/Destroy()
diff --git a/code/modules/mob/living/silicon/pai/pai_shell.dm b/code/modules/mob/living/silicon/pai/pai_shell.dm
index c6710141f9..63fb82082f 100644
--- a/code/modules/mob/living/silicon/pai/pai_shell.dm
+++ b/code/modules/mob/living/silicon/pai/pai_shell.dm
@@ -97,8 +97,7 @@
resist_a_rest(FALSE, TRUE)
update_icon()
if(possible_chassis[old_chassis])
- var/datum/element/mob_holder/M = SSdcs.GetElement(/datum/element/mob_holder, old_chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
- M.Detach(src)
+ RemoveElement(/datum/element/mob_holder, old_chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
if(possible_chassis[chassis])
AddElement(/datum/element/mob_holder, chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
to_chat(src, "You switch your holochassis projection composite to [chassis]")
diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index 46cdc755db..4bf8aa5e23 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -363,10 +363,8 @@
icon_dead = "old_corgi_dead"
desc = "At a ripe old age of [record_age] Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP
turns_per_move = 20
- var/datum/element/mob_holder/ele = SSdcs.GetElement(/datum/element/mob_holder, held_icon)
- if(ele)
- ele.Detach(src)
- AddElement(/datum/element/mob_holder, "old_corgi")
+ RemoveElement(/datum/element/mob_holder, held_icon)
+ AddElement(/datum/element/mob_holder, "old_corgi")
/mob/living/simple_animal/pet/dog/corgi/Ian/Life()
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm
index dbcaed1ba2..9ae46f29e5 100644
--- a/code/modules/mob/living/simple_animal/friendly/lizard.dm
+++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm
@@ -26,7 +26,7 @@
/mob/living/simple_animal/hostile/lizard/ComponentInitialize()
. = ..()
- AddElement(/datum/element/mob_holder, "lizard", null, null, null, ITEM_SLOT_HEAD) //you can hold lizards now.
+ AddElement(/datum/element/mob_holder, worn_state = "lizard", inv_slots = ITEM_SLOT_HEAD) //you can hold lizards now.
/mob/living/simple_animal/hostile/lizard/CanAttack(atom/the_target)//Can we actually attack a possible target?
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index c5a4fa6e1e..370442d4c4 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -64,7 +64,7 @@
..()
/mob/living/simple_animal/mouse/handle_automated_action()
- if(isbelly(loc))
+ if(!isturf(loc))
return
if(prob(chew_probability))
@@ -76,7 +76,7 @@
visible_message("[src] chews through the [C]. It's toast!")
playsound(src, 'sound/effects/sparks2.ogg', 100, 1)
C.deconstruct()
- death(toast=1)
+ death(toast=TRUE)
else
C.deconstruct()
visible_message("[src] chews through the [C].")
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index 83abde2fca..b50ebfe160 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -17,7 +17,7 @@ From these blood pools Bubblegum may summon slaughterlings - weak, low-damage mi
When Bubblegum dies, it leaves behind a H.E.C.K. suit+helmet as well as a chest that can contain three things:
1. A spellblade that can slice off limbs at range
2. A bottle that, when activated, drives everyone nearby into a frenzy
- 3. A contract that marks for death the chosen target
+ 3. A super double-barrel shotgun that shoots both shells at the same time.
Difficulty: Hard
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 15937873e3..cc7744eee0 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -123,7 +123,7 @@ Difficulty: Very Hard
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.mind)
- if(H.mind.martial_art && prob(H.mind.martial_art.deflection_chance))
+ if(istype(H.mind.martial_art, /datum/martial_art/the_sleeping_carp) & istype(H.mind.martial_art, /datum/martial_art/the_rising_bass))
. = TRUE
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
index 56d112237e..d940305080 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
@@ -84,10 +84,12 @@
pass_flags = PASSTABLE | PASSMOB //they shouldn't get stuck behind hivelords.
density = FALSE
del_on_death = 1
+ var/swarming = FALSE
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/Initialize()
. = ..()
- AddComponent(/datum/component/swarming) //oh god not the bees
+ if(swarming)
+ AddComponent(/datum/component/swarming) //oh god not the bees
addtimer(CALLBACK(src, .proc/death), 100)
//Legion
@@ -184,6 +186,7 @@
del_on_death = TRUE
stat_attack = UNCONSCIOUS
robust_searching = 1
+ swarming = TRUE
var/can_infest_dead = FALSE
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/Life()
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 12379bce91..10abf460c6 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -19,9 +19,15 @@
/mob/proc/set_dizziness(amount)
dizziness = max(amount, 0)
-///Blind a mobs eyes by amount
+/**
+ * Sets a mob's blindness to an amount if it was not above it already, similar to how status effects work
+ */
/mob/proc/blind_eyes(amount)
- adjust_blindness(amount)
+ var/old_blind = eye_blind || HAS_TRAIT(src, TRAIT_BLIND)
+ eye_blind = max(eye_blind, amount)
+ var/new_blind = eye_blind || HAS_TRAIT(src, TRAIT_BLIND)
+ if(old_blind != new_blind)
+ update_blindness()
/**
* Adjust a mobs blindness by an amount
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 4b360df8c7..42aaa110c8 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -49,9 +49,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
@@ -208,9 +207,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/modular_computers/computers/item/tablet.dm b/code/modules/modular_computers/computers/item/tablet.dm
index bc9d62acbe..a371e97ec6 100644
--- a/code/modules/modular_computers/computers/item/tablet.dm
+++ b/code/modules/modular_computers/computers/item/tablet.dm
@@ -24,11 +24,11 @@
/obj/item/modular_computer/tablet/syndicate_contract_uplink
name = "contractor tablet"
icon = 'icons/obj/contractor_tablet.dmi'
- icon_state = "tablet-red"
+ icon_state = "tablet"
icon_state_unpowered = "tablet"
icon_state_powered = "tablet"
icon_state_menu = "assign"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
comp_light_luminosity = 6.3
- has_variants = FALSE
\ No newline at end of file
+ has_variants = FALSE
diff --git a/code/modules/projectiles/boxes_magazines/internal/shotgun.dm b/code/modules/projectiles/boxes_magazines/internal/shotgun.dm
index 09d056a5f2..eb2572187c 100644
--- a/code/modules/projectiles/boxes_magazines/internal/shotgun.dm
+++ b/code/modules/projectiles/boxes_magazines/internal/shotgun.dm
@@ -37,6 +37,10 @@
name = "double-barrel shotgun internal magazine"
max_ammo = 2
+/obj/item/ammo_box/magazine/internal/shot/dual/heck
+ name = "heckgun internal magazine"
+ ammo_type = /obj/item/ammo_casing/shotgun/buckshot
+
/obj/item/ammo_box/magazine/internal/shot/improvised
name = "improvised shotgun internal magazine"
ammo_type = /obj/item/ammo_casing/shotgun/improvised
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index 0ff0c79f1e..39428275c8 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -39,7 +39,6 @@
magazine = AM
if(oldmag)
to_chat(user, "You perform a tactical reload on \the [src], replacing the magazine.")
- oldmag.dropped()
oldmag.forceMove(get_turf(src.loc))
oldmag.update_icon()
else
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index 571525d8f0..7f01db466f 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -171,7 +171,7 @@
pump()
gun_type = type
-/obj/item/gun/ballistic/shotgun/boltaction/enchanted/dropped()
+/obj/item/gun/ballistic/shotgun/boltaction/enchanted/dropped(mob/user)
..()
guns_left = 0
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index 6cd567ce16..c5660624a2 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -34,7 +34,7 @@
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
ammo_type = list(/obj/item/ammo_casing/energy/kinetic/premium)
-/obj/item/gun/energy/kinetic_accelerator/premiumka/dropped()
+/obj/item/gun/energy/kinetic_accelerator/premiumka/dropped(mob/user)
. = ..()
if(!QDELING(src) && !holds_charge)
// Put it on a delay because moving item from slot to hand
@@ -137,7 +137,7 @@
if(!can_shoot())
attempt_reload()
-/obj/item/gun/energy/kinetic_accelerator/dropped()
+/obj/item/gun/energy/kinetic_accelerator/dropped(mob/user)
. = ..()
if(!QDELING(src) && !holds_charge)
// Put it on a delay because moving item from slot to hand
diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm
index 098395e0d4..c295adde60 100644
--- a/code/modules/projectiles/guns/misc/beam_rifle.dm
+++ b/code/modules/projectiles/guns/misc/beam_rifle.dm
@@ -47,7 +47,7 @@
var/mob/current_user = null
var/list/obj/effect/projectile/tracer/current_tracers
- var/structure_piercing = 1
+ var/structure_piercing = 0
var/structure_bleed_coeff = 0.7
var/wall_pierce_amount = 0
var/wall_devastate = 0
@@ -60,7 +60,7 @@
var/impact_structure_damage = 75
var/projectile_damage = 40
var/projectile_stun = 0
- var/projectile_setting_pierce = TRUE
+ var/projectile_setting_pierce = FALSE
var/delay = 30
var/lastfire = 0
@@ -160,6 +160,9 @@
add_overlay(drained_overlay)
/obj/item/gun/energy/beam_rifle/attack_self(mob/user)
+ if(!structure_piercing)
+ projectile_setting_pierce = FALSE
+ return
projectile_setting_pierce = !projectile_setting_pierce
to_chat(user, "You set \the [src] to [projectile_setting_pierce? "pierce":"impact"] mode.")
aiming_beam()
@@ -402,7 +405,7 @@
/obj/item/ammo_casing/energy/beam_rifle/hitscan
projectile_type = /obj/item/projectile/beam/beam_rifle/hitscan
select_name = "beam"
- e_cost = 5000
+ e_cost = 10000
fire_sound = 'sound/weapons/beam_sniper.ogg'
/obj/item/projectile/beam/beam_rifle
@@ -557,9 +560,4 @@
hitscan_light_color_override = "#99ff99"
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit(atom/target)
- qdel(src)
return FALSE
-
-/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
- qdel(src)
- return BULLET_ACT_HIT
diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm
index 3bb1b3794e..6ae6564671 100644
--- a/code/modules/projectiles/projectile/energy/stun.dm
+++ b/code/modules/projectiles/projectile/energy/stun.dm
@@ -27,7 +27,7 @@
C.IgniteMob()
if(C.dna && C.dna.check_mutation(HULK))
C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
- else if(tase_duration && (C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE))
+ else if(tase_duration && (C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE) && !HAS_TRAIT(C, TRAIT_TASED_RESISTANCE))
C.apply_status_effect(strong_tase? STATUS_EFFECT_TASED : STATUS_EFFECT_TASED_WEAK, tase_duration)
addtimer(CALLBACK(C, /mob/living/carbon.proc/do_jitter_animation, jitter), 5)
diff --git a/code/modules/projectiles/projectile/special/temperature.dm b/code/modules/projectiles/projectile/special/temperature.dm
index dae7d5f8b3..c17fd0a447 100644
--- a/code/modules/projectiles/projectile/special/temperature.dm
+++ b/code/modules/projectiles/projectile/special/temperature.dm
@@ -16,3 +16,8 @@
/obj/item/projectile/temp/hot
name = "heat beam"
temperature = 400
+
+/obj/item/projectile/temp/cryo
+ name = "cryo beam"
+ range = 3
+ temperature = -240 // Single slow shot reduces temp greatly
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
index 04e7c0a74e..0b634ba2d8 100644
--- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
@@ -171,9 +171,11 @@
/datum/reagent/drug/methamphetamine/on_mob_metabolize(mob/living/L)
..()
L.ignore_slowdown(type)
+ ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
/datum/reagent/drug/methamphetamine/on_mob_end_metabolize(mob/living/L)
L.unignore_slowdown(type)
+ REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
..()
/datum/reagent/drug/methamphetamine/on_mob_life(mob/living/carbon/M)
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index 4b2c1447c5..46002287dd 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -218,7 +218,8 @@
. = ..()
if(iscarbon(M))
var/mob/living/carbon/patient = M
- if(reac_volume >= 5 && HAS_TRAIT_FROM(patient, TRAIT_HUSK, "burn") && patient.getFireLoss() < THRESHOLD_UNHUSK) //One carp yields 12u rezadone.
+ var/vol = reac_volume + M.reagents.get_reagent_amount(/datum/reagent/medicine/rezadone)
+ if(vol >= 5 && HAS_TRAIT_FROM(patient, TRAIT_HUSK, "burn") && patient.getFireLoss() < THRESHOLD_UNHUSK) //One carp yields 12u rezadone.
patient.cure_husk("burn")
patient.visible_message("[patient]'s body rapidly absorbs moisture from the enviroment, taking on a more healthy appearance.")
@@ -425,7 +426,7 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
overdose_threshold = 40
value = 6
-/datum/reagent/medicine/synthflesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume,show_message = 1)
+/datum/reagent/medicine/synthflesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(iscarbon(M))
if (M.stat == DEAD)
show_message = 0
@@ -442,8 +443,9 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
if(show_message)
to_chat(M, "You feel your burns and bruises healing! It stings like hell!")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
+ var/vol = reac_volume + M.reagents.get_reagent_amount(/datum/reagent/medicine/synthflesh)
//Has to be at less than THRESHOLD_UNHUSK burn damage and have 100 synthflesh before unhusking. Corpses dont metabolize.
- if(HAS_TRAIT_FROM(M, TRAIT_HUSK, "burn") && M.getFireLoss() < THRESHOLD_UNHUSK && M.reagents.has_reagent(/datum/reagent/medicine/synthflesh, 100))
+ if(HAS_TRAIT_FROM(M, TRAIT_HUSK, "burn") && M.getFireLoss() < THRESHOLD_UNHUSK && (vol > 100))
M.cure_husk("burn")
M.visible_message("Most of [M]'s burnt off or charred flesh has been restored.")
..()
@@ -957,7 +959,7 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
/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
..()
@@ -992,9 +994,11 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
/datum/reagent/medicine/stimulants/on_mob_metabolize(mob/living/L)
..()
L.add_movespeed_modifier(type, update=TRUE, priority=100, multiplicative_slowdown=-0.5, blacklisted_movetypes=(FLYING|FLOATING))
+ ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
/datum/reagent/medicine/stimulants/on_mob_end_metabolize(mob/living/L)
L.remove_movespeed_modifier(type)
+ REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
..()
/datum/reagent/medicine/stimulants/on_mob_life(mob/living/carbon/M)
@@ -1299,6 +1303,14 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
color = "#918e53"
overdose_threshold = 30
+/datum/reagent/medicine/changelingadrenaline/on_mob_metabolize(mob/living/L)
+ ..()
+ ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
+
+/datum/reagent/medicine/changelingadrenaline/on_mob_end_metabolize(mob/living/L)
+ REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
+ ..()
+
/datum/reagent/medicine/changelingadrenaline/on_mob_life(mob/living/carbon/M as mob)
M.AdjustUnconscious(-20, 0)
M.AdjustAllImmobility(-20, 0)
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 025587bc2a..cfb0588f8f 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -40,9 +40,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 57748acb1a..ce1940994d 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -75,6 +75,28 @@
for(var/i = 1, i <= multiplier, i++)
new /obj/item/stack/sheet/mineral/gold(location)
+/datum/chemical_reaction/uraniumsolidification
+ name = "Solid Uranium"
+ id = "soliduranium"
+ required_reagents = list(/datum/reagent/consumable/frostoil = 5, /datum/reagent/uranium = 20, /datum/reagent/bromine = 1)
+ mob_react = FALSE
+
+/datum/chemical_reaction/uraniumsolidification/on_reaction(datum/reagents/holder, multiplier)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= multiplier, i++)
+ new /obj/item/stack/sheet/mineral/uranium(location)
+
+/datum/chemical_reaction/bluespacecrystalifaction
+ name = "Crystal Bluespace"
+ id = "crystalbluespace"
+ required_reagents = list(/datum/reagent/consumable/frostoil = 5, /datum/reagent/bluespace = 20, /datum/reagent/iron = 1)
+ mob_react = FALSE
+
+/datum/chemical_reaction/bluespacecrystalifaction/on_reaction(datum/reagents/holder, multiplier)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= multiplier, i++)
+ new /obj/item/stack/sheet/bluespace_crystal(location)
+
/datum/chemical_reaction/capsaicincondensation
name = "Capsaicincondensation"
id = /datum/reagent/consumable/condensedcapsaicin
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index 73d0c5eafa..170ff64138 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -28,7 +28,7 @@ Borg Hypospray
var/list/datum/reagents/reagent_list = list()
var/list/reagent_ids = list(/datum/reagent/medicine/dexalin, /datum/reagent/medicine/kelotane, /datum/reagent/medicine/bicaridine, /datum/reagent/medicine/antitoxin,
- /datum/reagent/medicine/epinephrine, /datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution, /datum/reagent/medicine/insulin)
+ /datum/reagent/medicine/epinephrine, /datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution, /datum/reagent/medicine/insulin, /datum/reagent/medicine/potass_iodide)
var/accepts_reagent_upgrades = TRUE //If upgrades can increase number of reagents dispensed.
var/list/modes = list() //Basically the inverse of reagent_ids. Instead of having numbers as "keys" and strings as values it has strings as keys and numbers as values.
//Used as list for input() in shakers.
@@ -164,7 +164,7 @@ Borg Hypospray
icon_state = "borghypo_s"
charge_cost = 20
recharge_time = 2
- reagent_ids = list(/datum/reagent/medicine/syndicate_nanites, /datum/reagent/medicine/potass_iodide, /datum/reagent/medicine/morphine, /datum/reagent/medicine/insulin)
+ reagent_ids = list(/datum/reagent/medicine/syndicate_nanites, /datum/reagent/medicine/prussian_blue, /datum/reagent/medicine/morphine, /datum/reagent/medicine/insulin)
bypass_protection = 1
accepts_reagent_upgrades = FALSE
@@ -261,5 +261,5 @@ Borg Shaker
/obj/item/reagent_containers/borghypo/epi
name = "Stabilizer injector"
desc = "An advanced chemical synthesizer and injection system, designed to stabilize patients."
- reagent_ids = list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/insulin)
+ reagent_ids = list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/insulin, /datum/reagent/medicine/potass_iodide)
accepts_reagent_upgrades = FALSE
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index c0d48301e1..6b3ba6fe28 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(/datum/material/iron = 1000, /datum/material/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/nanites/nanite_cloud_controller.dm b/code/modules/research/nanites/nanite_cloud_controller.dm
index 0731d3067c..439d0c5750 100644
--- a/code/modules/research/nanites/nanite_cloud_controller.dm
+++ b/code/modules/research/nanites/nanite_cloud_controller.dm
@@ -48,7 +48,7 @@
return
var/datum/nanite_cloud_backup/backup = new(src)
- var/datum/component/nanites/cloud_copy = new(backup)
+ var/datum/component/nanites/cloud_copy = backup.AddComponent(/datum/component/nanites)
backup.cloud_id = cloud_id
backup.nanites = cloud_copy
investigate_log("[key_name(user)] created a new nanite cloud backup with id #[cloud_id]", INVESTIGATE_NANITES)
@@ -213,7 +213,7 @@
var/datum/component/nanites/nanites = backup.nanites
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
var/datum/nanite_rule/rule = rule_template.make_rule(P)
-
+
investigate_log("[key_name(usr)] added rule [rule.display()] to program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
. = TRUE
if("remove_rule")
@@ -224,7 +224,7 @@
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
var/datum/nanite_rule/rule = P.rules[text2num(params["rule_id"])]
rule.remove()
-
+
investigate_log("[key_name(usr)] removed rule [rule.display()] from program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
. = TRUE
diff --git a/code/modules/research/nanites/nanite_programs/suppression.dm b/code/modules/research/nanites/nanite_programs/suppression.dm
index dcc9521798..3b0d6d0d06 100644
--- a/code/modules/research/nanites/nanite_programs/suppression.dm
+++ b/code/modules/research/nanites/nanite_programs/suppression.dm
@@ -107,7 +107,7 @@
/datum/nanite_program/fake_death/enable_passive_effect()
. = ..()
host_mob.emote("deathgasp")
- host_mob.fakedeath("nanites")
+ host_mob.fakedeath("nanites", TRUE)
/datum/nanite_program/fake_death/disable_passive_effect()
. = ..()
diff --git a/code/modules/research/techweb/_techweb.dm b/code/modules/research/techweb/_techweb.dm
index 9a55e53659..388fa3785c 100644
--- a/code/modules/research/techweb/_techweb.dm
+++ b/code/modules/research/techweb/_techweb.dm
@@ -20,6 +20,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, id = 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 5c7b6b57d1..b0d95a87d7 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -71,7 +71,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", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "bloodbankgen", "telescopiciv", "medspray")
+ design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "bloodbankgen", "telescopiciv", "medspray","genescanner")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/adv_biotech
diff --git a/code/modules/spells/spell_types/conjure.dm b/code/modules/spells/spell_types/conjure.dm
index b34d4d1258..b609655526 100644
--- a/code/modules/spells/spell_types/conjure.dm
+++ b/code/modules/spells/spell_types/conjure.dm
@@ -80,11 +80,11 @@
school = "conjuration"
charge_max = 150
cooldown_min = 10
+ var/delete_old = TRUE
/obj/effect/proc_holder/spell/targeted/conjure_item/cast(list/targets, mob/user = usr)
- if (item && !QDELETED(item))
- qdel(item)
- item = null
+ if (delete_old && item && !QDELETED(item))
+ QDEL_NULL(item)
else
for(var/mob/living/carbon/C in targets)
if(C.dropItemToGround(C.get_active_held_item()))
diff --git a/code/modules/spells/spell_types/mime.dm b/code/modules/spells/spell_types/mime.dm
index 2697bd3e1a..a3bb81ae55 100644
--- a/code/modules/spells/spell_types/mime.dm
+++ b/code/modules/spells/spell_types/mime.dm
@@ -128,6 +128,49 @@
invocation_type ="none"
..()
+/obj/effect/proc_holder/spell/targeted/touch/mimerope
+ name = "Invisible Rope"
+ desc = "Form an invisible rope to tie people or trip people with."
+ school = "mime"
+ panel = "Mime"
+ invocation_type = "emote"
+ invocation_emote_self = "You start fabricate an invisible rope."
+ charge_max = 700
+ sound = null
+ clothes_req = 0
+ range = -1
+ include_user = 1
+ action_icon_state = "mime"
+ action_background_icon_state = "bg_mime"
+ hand_path = /obj/item/melee/touch_attack/mimerope
+
+/obj/effect/proc_holder/spell/targeted/touch/mimerope/Click()
+ if(usr && usr.mind)
+ if(!usr.mind.miming)
+ to_chat(usr, "You must dedicate yourself to silence first.")
+ return
+ if (usr.get_active_held_item())
+ to_chat(usr, "Your hands must be free to create the invisible rope.")
+ return
+ invocation = "[usr.real_name] is twirling an invisible rope in [usr.p_their()] hands."
+ else
+ invocation_type ="none"
+
+/obj/effect/proc_holder/spell/targeted/touch/mimerope/cast(list/targets,mob/user = usr)
+
+ usr.put_in_hands()
+
+/obj/item/melee/touch_attack/mimerope
+ item_state = ""
+ icon_state = ""
+ name = "mime rope"
+ desc = "An invisible rope."
+
+/obj/item/restraints/handcuffs/cable/mime
+ name = "mime restraints"
+ desc = "An invisible rope."
+ item_state = ""
+ icon_state = ""
/obj/item/book/granter/spell/mimery_blockade
spell = /obj/effect/proc_holder/spell/targeted/forcewall/mime
diff --git a/code/modules/spells/spell_types/touch_attacks.dm b/code/modules/spells/spell_types/touch_attacks.dm
index b0d348751f..a23e16cf88 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/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index f97bc1d7c3..276d4893de 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -103,6 +103,7 @@
for(var/obj/item/I in embedded_objects)
embedded_objects -= I
I.forceMove(src)
+ I.unembedded()
if(!C.has_embedded_objects())
C.clear_alert("embeddedobject")
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "embedded")
@@ -112,7 +113,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/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index eed8f62e10..aaca33685b 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -161,6 +161,7 @@
for(var/obj/item/I in L.embedded_objects)
L.embedded_objects -= I
I.forceMove(T)
+ I.unembedded()
clear_alert("embeddedobject")
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")
diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm
index 0c3a3b55a5..7d7cd2df63 100644
--- a/code/modules/surgery/remove_embedded_object.dm
+++ b/code/modules/surgery/remove_embedded_object.dm
@@ -25,6 +25,7 @@
objects++
I.forceMove(get_turf(H))
L.embedded_objects -= I
+ I.unembedded()
if(!H.has_embedded_objects())
H.clear_alert("embeddedobject")
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "embedded")
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 52f6efd3df..bbfa186a48 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -1,4 +1,4 @@
-/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE)
+/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE, other_filter = list())
var/list/filtered_uplink_items = GLOB.uplink_categories.Copy() // list of uplink categories without associated values.
var/list/sale_items = list()
@@ -18,7 +18,8 @@
continue
if (I.restricted && !allow_restricted)
continue
-
+ if (I.type in other_filter)
+ continue
LAZYSET(filtered_uplink_items[I.category], I.name, I)
if(I.limited_stock < 0 && !I.cant_discount && I.item && I.cost > 1)
diff --git a/code/modules/uplink/uplink_items/uplink_stealth.dm b/code/modules/uplink/uplink_items/uplink_stealth.dm
index 0ad06e7418..80aba02e2e 100644
--- a/code/modules/uplink/uplink_items/uplink_stealth.dm
+++ b/code/modules/uplink/uplink_items/uplink_stealth.dm
@@ -48,7 +48,7 @@
/datum/uplink_item/stealthy_weapons/martialarts
name = "Sleeping Carp Scroll"
desc = "This scroll contains the secrets of an ancient martial arts technique. You will master unarmed combat, \
- deflecting all ranged weapon fire, but you also refuse to use dishonorable ranged weaponry."
+ gain skin as hard as steel and swat bullets from the air, but you also refuse to use dishonorable ranged weaponry."
item = /obj/item/book/granter/martial/carp
cost = 17
surplus = 0
diff --git a/config/config.txt b/config/config.txt
index 1d987070dd..306d1d9a6d 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -185,12 +185,15 @@ VOTE_DELAY 6000
VOTE_PERIOD 600
## autovote initial delay (deciseconds) before first automatic transfer vote call (default 120 minutes)
+## Set to 0 to disable the subsystem altogether.
VOTE_AUTOTRANSFER_INITIAL 72000
## autovote delay (deciseconds) before sequential automatic transfer votes are called (default 30 minutes)
VOTE_AUTOTRANSFER_INTERVAL 18000
-## autovote maximum votes until automatic transfer call (default 4)
+## autovote maximum votes until automatic transfer call. (default 4)
+## Set to 0 to force automatic crew transfer after the 'vote_autotransfer_initial' elapsed.
+## Set to -1 to disable the maximum votes cap.
VOTE_AUTOTRANSFER_MAXIMUM 4
## prevents dead players from voting or starting votes
diff --git a/html/blank.png b/html/blank.png
new file mode 100644
index 0000000000..86c9630485
Binary files /dev/null and b/html/blank.png differ
diff --git a/html/browser/scannernew.css b/html/browser/scannernew.css
index 0e809a6760..6746a61a0d 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/changelogs/AutoChangeLog-pr-10327.yml b/html/changelogs/AutoChangeLog-pr-10327.yml
new file mode 100644
index 0000000000..3e43dbe1fd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-10327.yml
@@ -0,0 +1,4 @@
+author: "Seris02"
+delete-after: True
+changes:
+ - rscadd: "tg genetics"
diff --git a/html/changelogs/AutoChangeLog-pr-11290.yml b/html/changelogs/AutoChangeLog-pr-11290.yml
new file mode 100644
index 0000000000..726a8ee797
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11290.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - rscadd: "Traitor classes for traitors: a new way for traitors to have objectives assigned."
diff --git a/html/changelogs/AutoChangeLog-pr-11307.yml b/html/changelogs/AutoChangeLog-pr-11307.yml
new file mode 100644
index 0000000000..5b70dd7b0c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11307.yml
@@ -0,0 +1,5 @@
+author: "kappa-sama"
+delete-after: True
+changes:
+ - balance: "removed (mostly aesthetic) requirement to become hulk"
+ - bugfix: "changed add to remove on crit"
diff --git a/html/changelogs/AutoChangeLog-pr-11373.yml b/html/changelogs/AutoChangeLog-pr-11373.yml
new file mode 100644
index 0000000000..f6b8401fce
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11373.yml
@@ -0,0 +1,5 @@
+author: "kappa-sama"
+delete-after: True
+changes:
+ - rscadd: "a super combat shotgun that loads and fires 2 shells at a time"
+ - balance: "replaces bubblegum's blood contract drop with the super shotgun"
diff --git a/html/changelogs/AutoChangeLog-pr-11406.yml b/html/changelogs/AutoChangeLog-pr-11406.yml
new file mode 100644
index 0000000000..b46e346378
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11406.yml
@@ -0,0 +1,4 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - rscadd: "Minimaps, accessible via a button on OOC."
diff --git a/html/changelogs/AutoChangeLog-pr-11408.yml b/html/changelogs/AutoChangeLog-pr-11408.yml
new file mode 100644
index 0000000000..d6cf71f643
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11408.yml
@@ -0,0 +1,5 @@
+author: "necromanceranne"
+delete-after: True
+changes:
+ - rscadd: "Ports New Sleeping Carp"
+ - refactor: "Ports the martial arts refactors, which includes things like moving martial into the martial subfolder and renaming it _martial, and cleans up human_defense rising bass/sleeping carp exclusive code."
diff --git a/html/changelogs/AutoChangeLog-pr-11409.yml b/html/changelogs/AutoChangeLog-pr-11409.yml
new file mode 100644
index 0000000000..6da52ae2fa
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11409.yml
@@ -0,0 +1,5 @@
+author: "necromanceranne"
+delete-after: True
+changes:
+ - balance: "Particle Defender is now a much more sane weapon."
+ - balance: "Tasers are no longer ignoring stimulants."
diff --git a/html/changelogs/AutoChangeLog-pr-11410.yml b/html/changelogs/AutoChangeLog-pr-11410.yml
new file mode 100644
index 0000000000..14a78979f4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11410.yml
@@ -0,0 +1,4 @@
+author: "necromanceranne"
+delete-after: True
+changes:
+ - bugfix: "Blood beam can't create harvesters out of mech pilots."
diff --git a/html/changelogs/AutoChangeLog-pr-11414.yml b/html/changelogs/AutoChangeLog-pr-11414.yml
new file mode 100644
index 0000000000..e323cf115e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11414.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Joining in as a positronic brain won't break the spawner menu anymore."
diff --git a/html/changelogs/AutoChangeLog-pr-11416.yml b/html/changelogs/AutoChangeLog-pr-11416.yml
new file mode 100644
index 0000000000..3a76a9b2f5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11416.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "Soidifaction of and uranium can be done as well as making new bluespace shards"
diff --git a/html/changelogs/AutoChangeLog-pr-11422.yml b/html/changelogs/AutoChangeLog-pr-11422.yml
new file mode 100644
index 0000000000..085d767bcd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11422.yml
@@ -0,0 +1,5 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - balance: "Xeno and Fountain Hall will no longer spawn more then once"
+ - tweak: "Makes the game want to spawn in more then one tumor maybe"
diff --git a/html/changelogs/AutoChangeLog-pr-11424.yml b/html/changelogs/AutoChangeLog-pr-11424.yml
new file mode 100644
index 0000000000..2ab88177a4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11424.yml
@@ -0,0 +1,4 @@
+author: "necromanceranne"
+delete-after: True
+changes:
+ - code_imp: "Some minor fixes to fakedeath and a tg fix port."
diff --git a/html/changelogs/AutoChangeLog-pr-11425.yml b/html/changelogs/AutoChangeLog-pr-11425.yml
new file mode 100644
index 0000000000..82cf14d567
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11425.yml
@@ -0,0 +1,4 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - bugfix: "synthflesh and rezadone now take total amounts of both applied and existing reagents rather than only existing and only applied respectively."
diff --git a/html/changelogs/AutoChangeLog-pr-11429.yml b/html/changelogs/AutoChangeLog-pr-11429.yml
new file mode 100644
index 0000000000..3562f3b130
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11429.yml
@@ -0,0 +1,12 @@
+author: "Putnam"
+delete-after: True
+changes:
+ - tweak: "Swarmers, portal storm, wormholes are now controlled by dynamic."
+ - tweak: "Dynamic-controlled events can now have a minimum start time."
+ - balance: "Threatening meteors are more common (though still have pretty strict requirements)"
+ - balance: "Different storytellers now balance around different expected players-per-antag; default was 5, now intrigue/story/random have 7 and calm has 10."
+ - rscadd: "Clown ops is now available as a roundstart antag in dynamic."
+ - balance: "Sentient disease and revenant are now in the event pool rather than the antag pool (with the logic that they're both completely useless and unfun to play if people are actually playing against them)."
+ - rscadd: "A new formulation of extended was added to the storytellers; no antags, but still spending threat on events."
+ - bugfix: "Fixed a runtime in dynamic due to my misunderstanding pickweightAllowZero"
+ - rscdel: "Made conversion storyteller 0-weight-by-default."
diff --git a/html/changelogs/AutoChangeLog-pr-11430.yml b/html/changelogs/AutoChangeLog-pr-11430.yml
new file mode 100644
index 0000000000..9afe29f3ca
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11430.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - tweak: "Autotransfer vote now requires actual transfer votes to transfer."
diff --git a/html/changelogs/AutoChangeLog-pr-11431.yml b/html/changelogs/AutoChangeLog-pr-11431.yml
new file mode 100644
index 0000000000..f80f8c8585
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11431.yml
@@ -0,0 +1,4 @@
+author: "Useroth"
+delete-after: True
+changes:
+ - bugfix: "contractor tablets spawned with invalid icon_state"
diff --git a/html/changelogs/AutoChangeLog-pr-11432.yml b/html/changelogs/AutoChangeLog-pr-11432.yml
new file mode 100644
index 0000000000..f0c0572ca3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11432.yml
@@ -0,0 +1,4 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - balance: "reverts bubblegum bloodling swarming."
diff --git a/html/changelogs/AutoChangeLog-pr-11436.yml b/html/changelogs/AutoChangeLog-pr-11436.yml
new file mode 100644
index 0000000000..26ddaa7f69
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11436.yml
@@ -0,0 +1,4 @@
+author: "MrJWhit"
+delete-after: True
+changes:
+ - tweak: "Removed egun in every head locker, replaces RPD with air pump in science, fixes a computer in sec, moves hand teleporter, and removes decals under lockers."
diff --git a/html/changelogs/AutoChangeLog-pr-11437.yml b/html/changelogs/AutoChangeLog-pr-11437.yml
new file mode 100644
index 0000000000..4bb865e6f9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11437.yml
@@ -0,0 +1,8 @@
+author: "keronshb"
+delete-after: True
+changes:
+ - balance: "blobs now receive a 50% cost refund on attacks that don't spread"
+ - balance: "reflector blobs are considerably tougher"
+ - bugfix: "fixed an integrity"
+ - bugfix: "attempting to turn a damaged strong blob into a reflector blob now refunds points"
+ - bugfix: "also fixes blob node camera jump (from another PR)"
diff --git a/html/changelogs/AutoChangeLog-pr-11447.yml b/html/changelogs/AutoChangeLog-pr-11447.yml
new file mode 100644
index 0000000000..4ada92210c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11447.yml
@@ -0,0 +1,4 @@
+author: "spookydonut"
+delete-after: True
+changes:
+ - code_imp: "adds selective duplicate component mode"
diff --git a/html/changelogs/AutoChangeLog-pr-11448.yml b/html/changelogs/AutoChangeLog-pr-11448.yml
new file mode 100644
index 0000000000..de94aa1e0d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11448.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "The autotransfer subsystem is slightly more modulable now."
diff --git a/html/changelogs/AutoChangeLog-pr-11450.yml b/html/changelogs/AutoChangeLog-pr-11450.yml
new file mode 100644
index 0000000000..748c1f94c2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11450.yml
@@ -0,0 +1,4 @@
+author: "zeroisthebiggay"
+delete-after: True
+changes:
+ - rscadd: "Space Fashion has discovered a new way to wear bandannas. With some simple minor adjustments and ties, bandannas can be made into fashionable neckerchiefs!"
diff --git a/html/changelogs/AutoChangeLog-pr-11451.yml b/html/changelogs/AutoChangeLog-pr-11451.yml
new file mode 100644
index 0000000000..bc3acb86ea
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11451.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - bugfix: "More dynamic fixes"
diff --git a/html/changelogs/AutoChangeLog-pr-11452.yml b/html/changelogs/AutoChangeLog-pr-11452.yml
new file mode 100644
index 0000000000..8ec140d5b0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11452.yml
@@ -0,0 +1,4 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - tweak: "cmo hypokit now holds the same amount of items as normal kits"
diff --git a/html/changelogs/AutoChangeLog-pr-11453.yml b/html/changelogs/AutoChangeLog-pr-11453.yml
new file mode 100644
index 0000000000..0113ea3dd6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11453.yml
@@ -0,0 +1,4 @@
+author: "necromanceranne"
+delete-after: True
+changes:
+ - bugfix: "Bleeding out all your blood from getting love tapped by a toolbox."
diff --git a/html/changelogs/AutoChangeLog-pr-11455.yml b/html/changelogs/AutoChangeLog-pr-11455.yml
new file mode 100644
index 0000000000..a54556673e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11455.yml
@@ -0,0 +1,5 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - tweak: "Number of paper work in the crate \"freelance paperwork\" is half"
+ - code_imp: "A few cases were something their is unneeded copy past replaced with many 1 in spawns"
diff --git a/html/changelogs/AutoChangeLog-pr-11456.yml b/html/changelogs/AutoChangeLog-pr-11456.yml
new file mode 100644
index 0000000000..b5a9353d33
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11456.yml
@@ -0,0 +1,4 @@
+author: "bunny232"
+delete-after: True
+changes:
+ - rscadd: "Box station captain office now has a standard issue renault"
diff --git a/html/changelogs/AutoChangeLog-pr-11458.yml b/html/changelogs/AutoChangeLog-pr-11458.yml
new file mode 100644
index 0000000000..14e8d7d650
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11458.yml
@@ -0,0 +1,5 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "Potass Iodide has been fitted into standered borgs as well as medical ones. Upgraded hypos now have Prussian Blue as well."
+ - tweak: "Syndi borgs Potass Iodide has been swapped for Prussian Blue"
diff --git a/html/changelogs/AutoChangeLog-pr-11460.yml b/html/changelogs/AutoChangeLog-pr-11460.yml
new file mode 100644
index 0000000000..1c8fb3e3fa
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11460.yml
@@ -0,0 +1,4 @@
+author: "Kraseo"
+delete-after: True
+changes:
+ - bugfix: "Mice don't chew on wires anymore while they're on your person."
diff --git a/html/changelogs/AutoChangeLog-pr-11461.yml b/html/changelogs/AutoChangeLog-pr-11461.yml
new file mode 100644
index 0000000000..547a2c58e1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11461.yml
@@ -0,0 +1,4 @@
+author: "Kraseo"
+delete-after: True
+changes:
+ - bugfix: "Bloodsucker heart theft objective now completes successfully."
diff --git a/html/changelogs/AutoChangeLog-pr-11464.yml b/html/changelogs/AutoChangeLog-pr-11464.yml
new file mode 100644
index 0000000000..cc59b44a30
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11464.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - bugfix: "Server-run votes aren't subject to vote cooldown"
diff --git a/html/changelogs/AutoChangeLog-pr-11466.yml b/html/changelogs/AutoChangeLog-pr-11466.yml
new file mode 100644
index 0000000000..c5d60c84c2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11466.yml
@@ -0,0 +1,4 @@
+author: "Seris02"
+delete-after: True
+changes:
+ - bugfix: "quirk blacklist fixing"
diff --git a/html/changelogs/AutoChangeLog-pr-11467.yml b/html/changelogs/AutoChangeLog-pr-11467.yml
new file mode 100644
index 0000000000..5b59fc2e7b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11467.yml
@@ -0,0 +1,4 @@
+author: "Kraseo"
+delete-after: True
+changes:
+ - tweak: "Blacklists turret protected areas, the toxins test range, asteroid ruins, and solars from being valid dropoff locations for contracts."
diff --git a/html/changelogs/AutoChangeLog-pr-11477.yml b/html/changelogs/AutoChangeLog-pr-11477.yml
new file mode 100644
index 0000000000..dcbb8368a9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11477.yml
@@ -0,0 +1,4 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - balance: "Beam rifles shot count 10 --> 5 and can no longer pierce. Also renders properly for reflections against blobs and some other things."
diff --git a/html/dna_discovered.gif b/html/dna_discovered.gif
new file mode 100644
index 0000000000..bc6b75f2f9
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 0000000000..c92218a661
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 0000000000..a3c182a4a1
Binary files /dev/null and b/html/dna_undiscovered.gif differ
diff --git a/icons/effects/genetics.dmi b/icons/effects/genetics.dmi
index a9f5f433d5..373a9de623 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 0000000000..1b1bf8dc23
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 072bfc8fe3..72e72ad6f3 100644
Binary files a/icons/mob/actions/actions_spells.dmi and b/icons/mob/actions/actions_spells.dmi differ
diff --git a/icons/obj/chromosomes.dmi b/icons/obj/chromosomes.dmi
new file mode 100644
index 0000000000..a8ff6186d8
Binary files /dev/null and b/icons/obj/chromosomes.dmi differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 28fc29cd71..c58fb5d940 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi
index f859e8b1e7..79045ac92b 100644
Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ
diff --git a/modular_citadel/code/game/machinery/wishgranter.dm b/modular_citadel/code/game/machinery/wishgranter.dm
index 48024a2228..7758c0d613 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/modular_citadel/code/modules/mob/living/carbon/human/human.dm b/modular_citadel/code/modules/mob/living/carbon/human/human.dm
index ee88fcb277..390cac3646 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/human.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/human.dm
@@ -19,6 +19,7 @@
L.embedded_objects -= I
L.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier*I.w_class*painmul)//It hurts to rip it out, get surgery you dingus. And if you're ripping it out quickly via resist, it's gonna hurt even more
I.forceMove(get_turf(src))
+ I.unembedded()
user.put_in_hands(I)
user.emote("scream")
user.visible_message("[user] rips [I] out of [user.p_their()] [L.name]!","You remove [I] from your [L.name].")
diff --git a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm
index f7c0b343c3..0850a95c47 100644
--- a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm
+++ b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm
@@ -185,10 +185,13 @@
name = "electron blast"
icon_state = "stunjectile"
color = null
- nodamage = 1
+ nodamage = TRUE
knockdown = 100
- stamina = 5
+ knockdown_stamoverride = 0
+ knockdown_stam_max = 0
+ stamina = 18
stutter = 5
jitter = 20
hitsound = 'sound/weapons/taserhit.ogg'
- range = 7
+ range = 3
+ strong_tase = FALSE
diff --git a/tgstation.dme b/tgstation.dme
old mode 100755
new mode 100644
index bd9b6284ed..a22e9ce28d
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -36,7 +36,6 @@
#include "code\__DEFINES\clockcult.dm"
#include "code\__DEFINES\colors.dm"
#include "code\__DEFINES\combat.dm"
-#include "code\__DEFINES\components.dm"
#include "code\__DEFINES\configuration.dm"
#include "code\__DEFINES\construction.dm"
#include "code\__DEFINES\contracts.dm"
@@ -118,6 +117,9 @@
#include "code\__DEFINES\vv.dm"
#include "code\__DEFINES\wall_dents.dm"
#include "code\__DEFINES\wires.dm"
+#include "code\__DEFINES\dcs\flags.dm"
+#include "code\__DEFINES\dcs\helpers.dm"
+#include "code\__DEFINES\dcs\signals.dm"
#include "code\__HELPERS\_cit_helpers.dm"
#include "code\__HELPERS\_lists.dm"
#include "code\__HELPERS\_logging.dm"
@@ -127,6 +129,7 @@
#include "code\__HELPERS\cmp.dm"
#include "code\__HELPERS\custom_holoforms.dm"
#include "code\__HELPERS\dates.dm"
+#include "code\__HELPERS\dna.dm"
#include "code\__HELPERS\donator_groupings.dm"
#include "code\__HELPERS\files.dm"
#include "code\__HELPERS\game.dm"
@@ -268,6 +271,7 @@
#include "code\controllers\subsystem\mapping.dm"
#include "code\controllers\subsystem\materials.dm"
#include "code\controllers\subsystem\medals.dm"
+#include "code\controllers\subsystem\minimaps.dm"
#include "code\controllers\subsystem\minor_mapping.dm"
#include "code\controllers\subsystem\mobs.dm"
#include "code\controllers\subsystem\moods.dm"
@@ -331,7 +335,6 @@
#include "code\datums\holocall.dm"
#include "code\datums\hud.dm"
#include "code\datums\map_config.dm"
-#include "code\datums\martial.dm"
#include "code\datums\mind.dm"
#include "code\datums\mutable_appearance.dm"
#include "code\datums\mutations.dm"
@@ -515,6 +518,7 @@
#include "code\datums\looping_sounds\item_sounds.dm"
#include "code\datums\looping_sounds\machinery_sounds.dm"
#include "code\datums\looping_sounds\weather.dm"
+#include "code\datums\martial\_martial.dm"
#include "code\datums\martial\boxing.dm"
#include "code\datums\martial\cqc.dm"
#include "code\datums\martial\krav_maga.dm"
@@ -533,11 +537,16 @@
#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\cold.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\space_adaptation.dm"
#include "code\datums\mutations\speech.dm"
#include "code\datums\mutations\telekinesis.dm"
#include "code\datums\ruins\lavaland.dm"
@@ -880,6 +889,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"
@@ -1490,6 +1500,14 @@
#include "code\modules\antagonists\swarmer\swarmer_event.dm"
#include "code\modules\antagonists\traitor\datum_traitor.dm"
#include "code\modules\antagonists\traitor\syndicate_contract.dm"
+#include "code\modules\antagonists\traitor\classes\ai.dm"
+#include "code\modules\antagonists\traitor\classes\assassin.dm"
+#include "code\modules\antagonists\traitor\classes\freeform.dm"
+#include "code\modules\antagonists\traitor\classes\hijack.dm"
+#include "code\modules\antagonists\traitor\classes\human.dm"
+#include "code\modules\antagonists\traitor\classes\martyr.dm"
+#include "code\modules\antagonists\traitor\classes\subterfuge.dm"
+#include "code\modules\antagonists\traitor\classes\traitor_class.dm"
#include "code\modules\antagonists\traitor\equipment\contractor.dm"
#include "code\modules\antagonists\traitor\equipment\Malf_Modules.dm"
#include "code\modules\antagonists\traitor\IAA\internal_affairs.dm"
@@ -1673,6 +1691,7 @@
#include "code\modules\client\verbs\aooc.dm"
#include "code\modules\client\verbs\etips.dm"
#include "code\modules\client\verbs\looc.dm"
+#include "code\modules\client\verbs\minimap.dm"
#include "code\modules\client\verbs\ooc.dm"
#include "code\modules\client\verbs\ping.dm"
#include "code\modules\client\verbs\suicide.dm"
@@ -2069,6 +2088,7 @@
#include "code\modules\lighting\lighting_turf.dm"
#include "code\modules\mapping\dmm_suite.dm"
#include "code\modules\mapping\map_template.dm"
+#include "code\modules\mapping\minimaps.dm"
#include "code\modules\mapping\preloader.dm"
#include "code\modules\mapping\reader.dm"
#include "code\modules\mapping\ruins.dm"
diff --git a/tgui/package-lock.json b/tgui/package-lock.json
index 470e5c2d23..d2567aba36 100644
--- a/tgui/package-lock.json
+++ b/tgui/package-lock.json
@@ -5480,9 +5480,9 @@
}
},
"minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.2.tgz",
+ "integrity": "sha512-rIqbOrKb8GJmx/5bc2M0QchhUouMXSpd1RTclXsB41JdL+VtnojfaJR+h7F9k18/4kHUsBFgk80Uk+q569vjPA=="
},
"mixin-deep": {
"version": "1.3.2",
diff --git a/tgui/package.json b/tgui/package.json
index dd81c3b318..85d47ecfe7 100644
--- a/tgui/package.json
+++ b/tgui/package.json
@@ -35,7 +35,7 @@
"html5shiv": "3.7.3",
"ie8": "0.8.1",
"lodash": "^4.17.15",
- "minimist": "1.2.0",
+ "minimist": "1.2.2",
"paths-js": "0.4.10",
"pleeease-filters": "2.0.0",
"postcss": "7.0.18",