diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm index 687cebfb786..7c4135a2f91 100644 --- a/code/__DEFINES/genetics.dm +++ b/code/__DEFINES/genetics.dm @@ -26,6 +26,9 @@ #define CHAV "Chav" #define ELVIS "Elvis" +#define UI_CHANGED "ui changed" +#define UE_CHANGED "ue changed" + #define CHAMELEON_MUTATION_DEFAULT_TRANSPARENCY 204 // String identifiers for associative list lookup diff --git a/code/datums/mutations.dm b/code/datums/mutations.dm index 1572fd4cf97..c7e53d39b64 100644 --- a/code/datums/mutations.dm +++ b/code/datums/mutations.dm @@ -19,6 +19,7 @@ var/layer_used = MUTATIONS_LAYER //which mutation layer to use var/list/species_allowed = list() //to restrict mutation to only certain species var/health_req //minimum health required to acquire the mutation + var/time_coeff = 1 //coefficient for timed mutations /datum/mutation/human/proc/force_give(mob/living/carbon/human/owner) set_block(owner) @@ -177,6 +178,7 @@ get_chance = 25 lowest_value = 256 * 12 text_gain_indication = "Your body feels warm!" + time_coeff = 5 /datum/mutation/human/cold_resistance/New() ..() @@ -197,6 +199,7 @@ get_chance = 25 lowest_value = 256 * 12 text_gain_indication = "The walls suddenly disappear!" + time_coeff = 2 /datum/mutation/human/x_ray/on_acquiring(mob/living/carbon/human/owner) if(..()) @@ -378,6 +381,7 @@ name = "Monkified" quality = NEGATIVE + time_coeff = 2 /datum/mutation/human/race/on_acquiring(mob/living/carbon/human/owner) if(..()) @@ -396,6 +400,7 @@ lowest_value = 256 * 12 text_gain_indication = "You begin to fade into the shadows." text_lose_indication = "You become fully visible." + time_coeff = 5 /datum/mutation/human/stealth/on_life(mob/living/carbon/human/owner) @@ -420,6 +425,7 @@ lowest_value = 256 * 12 text_gain_indication = "You feel one with your surroundings." text_lose_indication = "You feel oddly exposed." + time_coeff = 5 /datum/mutation/human/chameleon/on_acquiring(mob/living/carbon/human/owner) if(..()) diff --git a/code/game/dna.dm b/code/game/dna.dm index 098f89c9dd2..b15fc10715a 100644 --- a/code/game/dna.dm +++ b/code/game/dna.dm @@ -9,6 +9,8 @@ var/list/features = list("FFF") //first value is mutant color var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings, var/list/mutations = list() //All mutations are from now on here + var/list/temporary_mutations = list() //Timers for temporary mutations + var/list/previous = list() //For temporary name/ui/ue/blood_type modifications var/mob/living/carbon/holder /datum/dna/New(mob/living/carbon/new_holder) @@ -22,6 +24,7 @@ destination.set_species(species.type, icon_update=0) destination.dna.features = features destination.dna.real_name = real_name + destination.dna.temporary_mutations = temporary_mutations if(transfer_SE) destination.dna.struc_enzymes = struc_enzymes diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index dd5332623e0..e3ead355f11 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -1,4 +1,4 @@ -#define INJECTOR_TIMEOUT 300 +#define INJECTOR_TIMEOUT 100 #define REJUVENATORS_INJECT 15 #define REJUVENATORS_MAX 90 #define NUMBER_OF_BUFFERS 3 @@ -11,6 +11,11 @@ #define RADIATION_IRRADIATION_MULTIPLIER 0.2 //multiplier for how much radiation a test subject recieves +#define SCANNER_ACTION_SE 1 +#define SCANNER_ACTION_UI 2 +#define SCANNER_ACTION_UE 3 +#define SCANNER_ACTION_MIXED 4 + /obj/machinery/computer/scan_consolenew name = "\improper DNA scanner access console" desc = "Scan DNA." @@ -27,6 +32,7 @@ var/current_screen = "mainmenu" var/obj/machinery/dna_scannernew/connected = null var/obj/item/weapon/disk/data/diskette = null + var/list/delayed_action = null anchored = 1 use_power = 1 idle_power_usage = 10 @@ -185,6 +191,7 @@ temp_html += "
\tUE: [ue] " if(viable_occupant) temp_html += "Occupant " else temp_html += "Occupant" + temp_html += "Occupant:Delayed " if(injectorready) temp_html += "Injector" else temp_html += "Injector" else @@ -194,14 +201,23 @@ temp_html += "
\tUI: [ui] " if(viable_occupant) temp_html += "Occupant " else temp_html += "Occupant" + temp_html += "Occupant:Delayed " if(injectorready) temp_html += "Injector" else temp_html += "Injector" else temp_html += "
\tUI: No Data" + if(ue && name && blood_type && ui) + temp_html += "
\tUI+UE: [ui]/[ue] " + if(viable_occupant) temp_html += "Occupant " + else temp_html += "Occupant" + temp_html += "Occupant:Delayed " + if(injectorready) temp_html += "UI+UE Injector" + else temp_html += "UI+UE Injector" if(se) temp_html += "
\tSE: [se] " if(viable_occupant) temp_html += "Occupant " else temp_html += "Occupant " + temp_html += "Occupant:Delayed " if(injectorready) temp_html += "Injector" else temp_html += "Injector" else @@ -269,11 +285,7 @@ add_fingerprint(usr) usr.set_machine(src) - var/mob/living/carbon/viable_occupant - if(connected) - viable_occupant = connected.occupant - if(!istype(viable_occupant) || !viable_occupant.dna || (viable_occupant.disabilities & NOCLONE)) - viable_occupant = null + var/mob/living/carbon/viable_occupant = get_viable_occupant() //Basic Tasks/////////////////////////////////////////// var/num = round(text2num(href_list["num"])) @@ -326,55 +338,57 @@ buffer_slot.Cut() if("transferbuffer") if(num && viable_occupant) - num = Clamp(num, 1, NUMBER_OF_BUFFERS) - var/list/buffer_slot = buffer[num] - if(istype(buffer_slot)) //15 and 40 are just magic numbers that were here before so i didnt touch them, they are initial boundaries of damage - viable_occupant.radiation += rand(15/(connected.damage_coeff ** 2),40/(connected.damage_coeff ** 2)) //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 - 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") - if(buffer_slot["SE"]) - viable_occupant.dna.struc_enzymes = buffer_slot["SE"] - viable_occupant.domutcheck() - if("ui") - if(buffer_slot["UI"]) - viable_occupant.dna.uni_identity = buffer_slot["UI"] - viable_occupant.updateappearance(mutations_overlay_update=1) - else - if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"]) - viable_occupant.real_name = buffer_slot["name"] - viable_occupant.name = buffer_slot["name"] - viable_occupant.dna.unique_enzymes = buffer_slot["UE"] - viable_occupant.dna.blood_type = buffer_slot["blood_type"] + 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") + apply_buffer(SCANNER_ACTION_UE,num) + if("mixed") + apply_buffer(SCANNER_ACTION_MIXED,num) if("injector") if(num && injectorready) num = Clamp(num, 1, NUMBER_OF_BUFFERS) var/list/buffer_slot = buffer[num] if(istype(buffer_slot)) - var/obj/item/weapon/dnainjector/I + var/obj/item/weapon/dnainjector/timed/I switch(href_list["text"]) if("se") if(buffer_slot["SE"]) - I = new /obj/item/weapon/dnainjector(loc) + I = new /obj/item/weapon/dnainjector/timed(loc) for(var/datum/mutation/human/HM in good_mutations + bad_mutations + not_good_mutations) if(HM.check_block_string(buffer_slot["SE"])) - if(prob(HM.get_chance)) - I.add_mutations.Add(HM) + I.add_mutations.Add(HM) 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/weapon/dnainjector(loc) + I = new /obj/item/weapon/dnainjector/timed(loc) I.fields = list("UI"=buffer_slot["UI"]) if(connected) I.damage_coeff = connected.damage_coeff - else + if("ue") if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"]) - I = new /obj/item/weapon/dnainjector(loc) + I = new /obj/item/weapon/dnainjector/timed(loc) I.fields = list("name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"]) if(connected) I.damage_coeff = connected.damage_coeff + if("mixed") + if(buffer_slot["UI"] && buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"]) + I = new /obj/item/weapon/dnainjector/timed(loc) + I.fields = list("UI"=buffer_slot["UI"],"name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"]) + if(connected) + I.damage_coeff = connected.damage_coeff if(I) injectorready = 0 spawn(INJECTOR_TIMEOUT) @@ -394,6 +408,9 @@ if(diskette) diskette.loc = get_turf(src) diskette = null + if("setdelayed") + if(num) + delayed_action = list("action"=text2num(href_list["delayaction"]),"buffer"=num) if("pulseui","pulsese") if(num && viable_occupant && connected) radduration = Wrap(radduration, 1, RADIATION_DURATION_MAX+1) @@ -462,7 +479,54 @@ /obj/machinery/computer/scan_consolenew/proc/randomize_radiation_accuracy(position_we_were_supposed_to_hit, radduration, number_of_blocks) return Wrap(round(position_we_were_supposed_to_hit + gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration), 1), 1, number_of_blocks+1) +/obj/machinery/computer/scan_consolenew/proc/get_viable_occupant() + var/mob/living/carbon/viable_occupant = null + if(connected) + viable_occupant = connected.occupant + if(!istype(viable_occupant) || !viable_occupant.dna || (viable_occupant.disabilities & NOCLONE)) + viable_occupant = null + return viable_occupant +/obj/machinery/computer/scan_consolenew/proc/apply_buffer(action,buffer_num) + buffer_num = Clamp(buffer_num, 1, NUMBER_OF_BUFFERS) + var/list/buffer_slot = buffer[buffer_num] + var/mob/living/carbon/viable_occupant = get_viable_occupant() + if(istype(buffer_slot)) + viable_occupant.radiation += rand(10/(connected.damage_coeff ** 2),25/(connected.damage_coeff ** 2)) + //15 and 40 are just magic numbers that were here before so i didnt touch them, they are initial boundaries of damage + //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"] + viable_occupant.updateappearance(mutations_overlay_update=1) + if(SCANNER_ACTION_UE) + if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"]) + viable_occupant.real_name = buffer_slot["name"] + viable_occupant.name = buffer_slot["name"] + viable_occupant.dna.unique_enzymes = buffer_slot["UE"] + viable_occupant.dna.blood_type = buffer_slot["blood_type"] + if(SCANNER_ACTION_MIXED) + if(buffer_slot["UI"]) + viable_occupant.dna.uni_identity = buffer_slot["UI"] + viable_occupant.updateappearance(mutations_overlay_update=1) + if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"]) + viable_occupant.real_name = buffer_slot["name"] + viable_occupant.name = buffer_slot["name"] + viable_occupant.dna.unique_enzymes = buffer_slot["UE"] + viable_occupant.dna.blood_type = buffer_slot["blood_type"] + +/obj/machinery/computer/scan_consolenew/proc/on_scanner_close() + connected.occupant << "[src] activates!" + if(delayed_action) + apply_buffer(delayed_action["action"],delayed_action["buffer"]) + delayed_action = null //or make it stick + reset button ? + return /////////////////////////// DNA MACHINES #undef INJECTOR_TIMEOUT @@ -478,6 +542,11 @@ #undef RADIATION_IRRADIATION_MULTIPLIER +#undef SCANNER_ACTION_SE +#undef SCANNER_ACTION_UI +#undef SCANNER_ACTION_UE +#undef SCANNER_ACTION_MIXED + //#undef BAD_MUTATION_DIFFICULTY //#undef GOOD_MUTATION_DIFFICULTY //#undef OP_MUTATION_DIFFICULTY \ No newline at end of file diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm index 8f5e8f6c8b1..e6e730428f6 100644 --- a/code/game/machinery/dna_scanner.dm +++ b/code/game/machinery/dna_scanner.dm @@ -110,6 +110,13 @@ || locate(/obj/machinery/computer/cloning, get_step(src, WEST))) occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src) + + var/obj/machinery/computer/scan_consolenew/console + for(dir in list(NORTH,EAST,SOUTH,WEST)) + console = locate(/obj/machinery/computer/scan_consolenew, get_step(src, dir)) + if(console) + console.on_scanner_close() + break return 1 /obj/machinery/dna_scannernew/open_machine() diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm index 094faaffb86..43f30818de7 100644 --- a/code/game/objects/items/weapons/dna_injector.dm +++ b/code/game/objects/items/weapons/dna_injector.dm @@ -11,6 +11,7 @@ var/list/fields var/list/add_mutations = list() var/list/remove_mutations = list() + var/used = 0 /obj/item/weapon/dnainjector/attack_paw(mob/user) return attack_hand(user) @@ -45,6 +46,9 @@ if(!user.IsAdvancedToolUser()) user << "You don't have the dexterity to do this!" return + if(used) + user << "This injector is used up!" + return if(ishuman(target)) var/mob/living/carbon/human/humantarget = target if (!humantarget.can_inject(user, 1)) @@ -63,7 +67,9 @@ add_logs(user, target, "injected", src) inject(target, user) //Now we actually do the heavy lifting. - qdel(src) + used = 1 + icon_state = "dnainjector0" + desc += " This one is used up." /obj/item/weapon/dnainjector/antihulk @@ -385,4 +391,70 @@ name = "\improper DNA injector (Anti-Laser Eyes)" New() ..() - remove_mutations.Add(mutations_list[LASEREYES]) \ No newline at end of file + remove_mutations.Add(mutations_list[LASEREYES]) + +/obj/item/weapon/dnainjector/timed + var/duration = 600 + +/obj/item/weapon/dnainjector/timed/inject(mob/living/carbon/M, mob/user) + if(M.has_dna() && !(M.disabilities & NOCLONE)) + if(M.stat == DEAD) //prevents dead people from having their DNA changed + user << "You can't modify [M]'s DNA while \he's dead." + return + 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) + if(ishuman(M)) + continue + M = HM.force_lose(M) + 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])) + continue //Skip permanent mutations we already have. + if(HM.name == RACEMUT && ishuman(M)) + message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] (MONKEY)") + log_msg += " (MONKEY)" + M = HM.force_give(M) + else + HM.force_give(M) + M.dna.temporary_mutations[HM.name] = endtime + if(fields) + if(fields["name"] && fields["UE"] && fields["blood_type"]) + if(!M.dna.previous["name"]) + M.dna.previous["name"] = M.real_name + if(!M.dna.previous["UE"]) + M.dna.previous["UE"] = M.dna.unique_enzymes + if(!M.dna.previous["blood_type"]) + M.dna.previous["blood_type"] = M.dna.blood_type + M.real_name = fields["name"] + M.dna.unique_enzymes = fields["UE"] + M.name = M.real_name + M.dna.blood_type = fields["blood_type"] + M.dna.temporary_mutations[UE_CHANGED] = endtime + if(fields["UI"]) //UI+UE + if(!M.dna.previous["UI"]) + M.dna.previous["UI"] = M.dna.uni_identity + M.dna.uni_identity = merge_text(M.dna.uni_identity, fields["UI"]) + M.updateappearance(mutations_overlay_update=1) + M.dna.temporary_mutations[UI_CHANGED] = endtime + log_attack(log_msg) + else + user << "It appears that [M] does not have compatible DNA." + return + +/obj/item/weapon/dnainjector/timed/hulk + name = "\improper DNA injector (Hulk)" + desc = "This will make you big and strong, but give you a bad skin condition." + New() + ..() + add_mutations.Add(mutations_list[HULK]) + +/obj/item/weapon/dnainjector/timed/h2m + name = "\improper DNA injector (Human > Monkey)" + desc = "Will make you a flea bag." + New() + ..() + add_mutations.Add(mutations_list[RACEMUT]) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 15ef338af86..27ea1b59382 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -207,6 +207,34 @@ /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) + if(dna.previous["UI"]) + dna.uni_identity = merge_text(dna.uni_identity,dna.previous["UI"]) + updateappearance(mutations_overlay_update=1) + dna.previous.Remove("UI") + dna.temporary_mutations.Remove(mut) + continue + if(mut == UE_CHANGED) + if(dna.previous["name"]) + real_name = dna.previous["name"] + name = real_name + dna.previous.Remove("name") + if(dna.previous["UE"]) + dna.unique_enzymes = dna.previous["UE"] + dna.previous.Remove("UE") + if(dna.previous["blood_type"]) + dna.blood_type = dna.previous["blood_type"] + dna.previous.Remove("blood_type") + dna.temporary_mutations.Remove(mut) + continue + HM = mutations_list[mut] + HM.force_lose(src) + dna.temporary_mutations.Remove(mut) + if(radiation) switch(radiation) diff --git a/html/changelogs/injectors.yml b/html/changelogs/injectors.yml new file mode 100644 index 00000000000..14e562d30ee --- /dev/null +++ b/html/changelogs/injectors.yml @@ -0,0 +1,9 @@ +author: AnturK + +delete-after: True + +changes: + - tweak: "DNA Injectors now grant temporary powers on every use. Duration dependent on activated powers and machine upgrades" + - rscadd: "Delayed Transfer added to DNA Scanner - It will activate on the next closing of scanner door " + - rscadd: "UI+UE injectors/buffer transfers added for convinience " + - tweak: "Injector creation timeout cut in half"