mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 05:00:55 +01:00
CRISPR for Base Gene editing (#53173)
* New Fork, hopefully Actions is over * CRISPR Charge implementation (untested) * Fixed TGUI, tested - works as expected Still needs the CRISPR string, but I'm not sure how to implement the relationship otherwise at the moment. * Fixing CRISPR charge * Update code/game/machinery/computer/dna_console.dm Co-authored-by: Aleksej Komarov <stylemistake@gmail.com> * Update code/game/machinery/computer/dna_console.dm Co-authored-by: Aleksej Komarov <stylemistake@gmail.com> * Removing debug sections as requested * Fixed TGUI, refactor, comments, disease probability * Update code/game/machinery/computer/dna_console.dm Co-authored-by: Timberpoes <silent_insomnia_pp@hotmail.co.uk> * Update code/game/machinery/computer/dna_console.dm Co-authored-by: Timberpoes <silent_insomnia_pp@hotmail.co.uk> * Update code/game/machinery/computer/dna_console.dm Co-authored-by: Timberpoes <silent_insomnia_pp@hotmail.co.uk> * Prayer to Appveyor * Rebuild tgui Co-authored-by: Aleksej Komarov <stylemistake@gmail.com> Co-authored-by: Timberpoes <silent_insomnia_pp@hotmail.co.uk>
This commit is contained in:
co-authored by
Aleksej Komarov
Timberpoes
parent
c6ee012af5
commit
55191abc8d
@@ -96,6 +96,8 @@
|
||||
var/is_joker_ready = FALSE
|
||||
/// Used for setting tgui data - Whether injectors are ready to be printed
|
||||
var/is_injector_ready = FALSE
|
||||
/// Used for setting tgui data - Is CRISPR ready?
|
||||
var/is_crispr_ready = FALSE
|
||||
/// Used for setting tgui data - Wheher an enzyme pulse operation is ongoing
|
||||
var/is_pulsing_rads = FALSE
|
||||
/// Used for setting tgui data - Time until scramble is ready
|
||||
@@ -129,6 +131,9 @@
|
||||
/// State of tgui view, i.e. which tab is currently active, or which genome we're currently looking at.
|
||||
var/list/list/tgui_view_state = list()
|
||||
|
||||
///Counter for CRISPR charges
|
||||
var/crispr_charges = 0
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/process()
|
||||
. = ..()
|
||||
|
||||
@@ -174,6 +179,8 @@
|
||||
to_chat(user,"<span class='notice'>[capitalize(CM.name)] added to storage.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>There was not enough genetic data to extract a viable chromosome.</span>")
|
||||
if(A.crispr_charge)
|
||||
crispr_charges++
|
||||
qdel(I)
|
||||
return
|
||||
|
||||
@@ -246,6 +253,8 @@
|
||||
is_pulsing_rads = ((rad_pulse_index > 0) && (rad_pulse_timer > world.time))
|
||||
time_to_pulse = round((rad_pulse_timer - world.time)/10)
|
||||
|
||||
is_crispr_ready = (crispr_charges > 0)
|
||||
|
||||
// Attempt to update tgui ui, open and update if needed.
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
@@ -309,6 +318,8 @@
|
||||
data["isScrambleReady"] = is_scramble_ready
|
||||
data["isJokerReady"] = is_joker_ready
|
||||
data["isInjectorReady"] = is_injector_ready
|
||||
data["isCrisprReady"] = is_crispr_ready
|
||||
data["crisprCharges"] = crispr_charges
|
||||
data["scrambleSeconds"] = time_to_scramble
|
||||
data["jokerSeconds"] = time_to_joker
|
||||
data["injectorSeconds"] = time_to_injector
|
||||
@@ -549,6 +560,143 @@
|
||||
|
||||
return
|
||||
|
||||
// Attempt overwriting Base DNA : The pairs are instead the top row vs the top row of the new code.
|
||||
// So AA means the AT pair stays the same, AT means AT becomes TA. This requires both knowing the
|
||||
// solved full DNA of the subject mutation and the full DNA of the replacement genes. Applies probable disease
|
||||
// of probable strengths as well. If you mess it up, you might end up getting undesirable genes, including
|
||||
// unstable DNA. This could lead to permanent monkey. When you get it right, some will be swapped out, on a
|
||||
// probability scale.
|
||||
// ---------------------------------------------------------------------- //
|
||||
// params["mutref"] - ATOM Ref of specific mutation to swap out
|
||||
// params["source"] - The source the request came from.
|
||||
// Expected results:
|
||||
// "occupant" - From genetic sequencer
|
||||
// "console" - From DNA Console storage
|
||||
// "disk" - From inserted diskette
|
||||
if("crispr")
|
||||
// GUARD CHECK - Can we genetically modify the occupant? Includes scanner
|
||||
// operational guard checks.
|
||||
if(!can_modify_occupant())
|
||||
return
|
||||
|
||||
// GUARD CHECK - Have we somehow cheekily swapped occupants? This is
|
||||
// unexpected.
|
||||
if(scanner_occupant != connected_scanner.occupant)
|
||||
return
|
||||
|
||||
//GUARD CHECK
|
||||
//Make sure there's charges available.
|
||||
if(crispr_charges < 1)
|
||||
return
|
||||
var/search_flags = 0
|
||||
|
||||
// Only continue if applying to occupant - all replacements in-vitro.
|
||||
switch(params["source"])
|
||||
if("occupant")
|
||||
if(can_modify_occupant())
|
||||
search_flags |= SEARCH_OCCUPANT
|
||||
if("console")
|
||||
search_flags |= SEARCH_STORED
|
||||
return
|
||||
if("disk")
|
||||
search_flags |= SEARCH_DISKETTE
|
||||
return
|
||||
|
||||
//Currently selected mutation
|
||||
var/bref = params["mutref"]
|
||||
|
||||
//Valid gene-pairs
|
||||
var/at_str = "AT"
|
||||
var/cg_str = "CG"
|
||||
|
||||
// GUARD CHECK - Only search occupant for this specific ref, since you
|
||||
// can only CRISPR existing mutations in a target
|
||||
var/datum/mutation/human/target_mutation = get_mut_by_ref(bref, search_flags)
|
||||
|
||||
// Prompt for modifier string
|
||||
var/new_sequence_input = input(usr, "Enter replacement sequence (or nothing to cancel)", "Replace inherent gene","")
|
||||
// Drop out if the string is the wrong length
|
||||
if(length(new_sequence_input) != 32)
|
||||
return
|
||||
|
||||
//Generate the original and new gene sequences from the CRISPR string
|
||||
//vars to hold the 2 sequences
|
||||
var/old_sequence
|
||||
var/new_sequence
|
||||
|
||||
//Unzip the modification string
|
||||
for(var/i = 1 to length(new_sequence_input))
|
||||
var/char = new_sequence_input[i]
|
||||
var/pair_str
|
||||
var/new_pair
|
||||
//figure out which pair type the character belongs to
|
||||
pair_str = ((at_str[1] == char || at_str[2] == char) ? at_str : ((cg_str[1] == char || cg_str[2] == char) ? cg_str : null))
|
||||
//Valid pair from character
|
||||
new_pair = (pair_str ? char + (pair_str[1]==char?pair_str[2]:pair_str[1]) : null)
|
||||
// every second letter in the sequence represents a valid pair of the new sequence, otherwise it belongs to old
|
||||
if(new_pair)
|
||||
if(i%2==0)
|
||||
new_sequence+=new_pair
|
||||
else
|
||||
old_sequence+=new_pair
|
||||
else
|
||||
return //drop out, no pair
|
||||
|
||||
//decrement CRISPR charge
|
||||
crispr_charges--
|
||||
|
||||
//Apply sequence
|
||||
if(new_sequence)
|
||||
//to hold the found mutation, if found
|
||||
var/datum/mutation/human/matched_mutation = null
|
||||
//Go through all sequences for matching gene, and set the mutation
|
||||
for (var/M in subtypesof(/datum/mutation/human))
|
||||
var/true_sequence = GET_SEQUENCE(M)
|
||||
if (new_sequence == true_sequence)
|
||||
matched_mutation = M
|
||||
//First check is for the more-likely, weaker random virus. Second is for a tougher one. There's a chance both checks fail and you get nothing.
|
||||
//This change was to bring it more in line with what I originally imagined, that the virus risk was from the virus misbehaving somehow - it
|
||||
//should be a "sometimes" thing, not an "always" thing, but risky enough to force the need for precautions to isolate the subject
|
||||
if(prob(60))
|
||||
var/datum/disease/advance/random/random_disease = new /datum/disease/advance/random(2,2)
|
||||
random_disease.try_infect(scanner_occupant, FALSE)
|
||||
else if (prob(30))
|
||||
var/datum/disease/advance/random/random_disease = new /datum/disease/advance/random(3,4)
|
||||
random_disease.try_infect(scanner_occupant, FALSE)
|
||||
//Instantiate list to hold resulting mutation_index
|
||||
var/mutation_data[0]
|
||||
//Start with the bad mutation, overwrite with the desired mutation if it passes the check
|
||||
//assures BAD END is the natural state if things go wrong
|
||||
//I think this should be like with viruses, probability cascade or switch/case on random?
|
||||
var/result_mutation = ACIDFLESH
|
||||
//If we found the replacement mutation
|
||||
if(matched_mutation)
|
||||
//and the old sequence matches the real sequence of the old mutation
|
||||
if(old_sequence == GET_SEQUENCE(target_mutation.type))
|
||||
//Set the replacement mutation to the desired mutation
|
||||
result_mutation = matched_mutation
|
||||
//Remove the current active mutations - let's say doing this triggers DNA repair or something
|
||||
//This is admittedly because I couldn't figure out how to only remove the targeted mutation
|
||||
//Not touching MUT_EXTRA will hopefully leave the added mutations alone
|
||||
scanner_occupant.dna.remove_all_mutations(list(MUT_NORMAL))
|
||||
//Add the resulting mutation to the active mutations
|
||||
scanner_occupant.dna.add_mutation(result_mutation,MUT_NORMAL, 0)
|
||||
//Rebuild the mutation_index into mutation_data, replacing the sequence entry with the solved
|
||||
//entry for the result mutation
|
||||
for(var/mutation_type in scanner_occupant.dna.mutation_index)
|
||||
if(mutation_type == target_mutation.type)
|
||||
mutation_data[result_mutation] = new_sequence
|
||||
else
|
||||
mutation_data[mutation_type]=scanner_occupant.dna.mutation_index[mutation_type]
|
||||
//Overwrite the mutation_index list with the rebuild mutation_data
|
||||
scanner_occupant.dna.mutation_index = mutation_data
|
||||
//Not sure what this does but it seems to be a sanity check and this needs a sanity check
|
||||
scanner_occupant.domutcheck()
|
||||
|
||||
|
||||
return
|
||||
|
||||
|
||||
// Print any type of standard injector, limited right now to activators that
|
||||
// activate a dormant mutation and mutators that forcibly create a new
|
||||
// MUT_EXTRA mutation
|
||||
|
||||
@@ -500,12 +500,14 @@
|
||||
var/doitanyway = FALSE
|
||||
var/research = FALSE //Set to true to get expended and filled injectors for chromosomes
|
||||
var/filled = FALSE
|
||||
var/crispr_charge = FALSE // Look for viruses, look at symptoms, if research and Dormant DNA Activator or Viral Evolutionary Acceleration, set to true
|
||||
|
||||
/obj/item/dnainjector/activator/inject(mob/living/carbon/M, mob/user)
|
||||
if(M.has_dna() && !HAS_TRAIT(M, TRAIT_GENELESS) && !HAS_TRAIT(M, TRAIT_BADDNA))
|
||||
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/pref = ""
|
||||
var/suff = ""
|
||||
for(var/mutation in add_mutations)
|
||||
var/datum/mutation/human/HM = mutation
|
||||
if(istype(HM, /datum/mutation/human))
|
||||
@@ -521,8 +523,13 @@
|
||||
pref = "filled"
|
||||
else
|
||||
pref = "expended"
|
||||
for(var/datum/disease/advance/disease in M.diseases)
|
||||
for(var/datum/symptom/symp in disease.symptoms)
|
||||
if((symp.type == /datum/symptom/genetic_mutation)||(symp.type == /datum/symptom/viralevolution))
|
||||
crispr_charge = TRUE
|
||||
suff = (crispr_charge ? "with CRISPR charge" : "")
|
||||
log_msg += "([mutation])"
|
||||
name = "[pref] [name]"
|
||||
name = "[pref] [name] [suff]"
|
||||
log_attack("[log_msg] [loc_name(user)]")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -564,6 +564,8 @@ const MutationInfo = (props, context) => {
|
||||
diskReadOnly,
|
||||
hasDisk,
|
||||
isInjectorReady,
|
||||
isCrisprReady,
|
||||
crisprCharges,
|
||||
} = data;
|
||||
const diskMutations = data.storage.disk ?? [];
|
||||
const mutationStorage = data.storage.console ?? [];
|
||||
@@ -653,6 +655,14 @@ const MutationInfo = (props, context) => {
|
||||
is_activator: 0,
|
||||
source: mutation.Source,
|
||||
})} />
|
||||
<Button
|
||||
icon="syringe"
|
||||
disabled={!mutation.Active || !isCrisprReady}
|
||||
content={`CRISPR [${crisprCharges}]`}
|
||||
onClick={() => act('crispr', {
|
||||
mutref: mutation.ByondRef,
|
||||
source: mutation.Source,
|
||||
})} />
|
||||
</Fragment>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user