diff --git a/code/modules/hydroponics/seed_machines.dm b/code/modules/hydroponics/seed_machines.dm index cb48dede9ef..11673255d24 100644 --- a/code/modules/hydroponics/seed_machines.dm +++ b/code/modules/hydroponics/seed_machines.dm @@ -5,7 +5,9 @@ icon_state = "disk" w_class = WEIGHT_CLASS_TINY + /// The current gene data on the disk. var/list/genes = list() + /// The player-facing name of the gene's source. var/genesource = "unknown" /obj/item/disk/botany/New() @@ -35,22 +37,28 @@ /obj/machinery/botany icon = 'icons/obj/hydroponics_machines.dmi' icon_state = "hydrotray3" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE - var/obj/item/seeds/seed // Currently loaded seed packet. - var/obj/item/disk/botany/loaded_disk //Currently loaded data disk. - - var/open = 0 - var/active = 0 + /// Currently loaded seed packet. + var/obj/item/seeds/seed + /// Currently loaded data disk. + var/obj/item/disk/botany/loaded_disk + /// Is the machine current performing a task? + var/active = FALSE + /// Duration the task requires for completion. var/action_time = 5 + /// World time when the last action was queued. var/last_action = 0 - var/eject_disk = 0 - var/failed_task = 0 - var/disk_needs_genes = 0 + /// Whether the currently queued task should eject the current disk, if present. + var/eject_disk = FALSE + /// Whether the task has failed or not. + var/failed_task = FALSE + /// Helps determine whether or not a given operation requires a disk to be loaded with genes or to be empty. + var/disk_needs_genes = FALSE +/// Gets run every process tick. /obj/machinery/botany/process() - ..() if(!active) return @@ -95,11 +103,11 @@ return if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER) - open = !open - to_chat(user, SPAN_NOTICE("You [open ? "open" : "close"] the maintenance panel.")) + panel_open = !panel_open + to_chat(user, SPAN_NOTICE("You [panel_open ? "open" : "close"] the maintenance panel.")) return - if(open) + if(panel_open) if(attacking_item.tool_behaviour == TOOL_CROWBAR) dismantle() return @@ -127,7 +135,52 @@ return ..() -// Allows for a trait to be extracted from a seed packet, destroying that seed. +/// UI data shared between both editor and extractor machinery. +/obj/machinery/botany/ui_data(mob/user) + var/list/data = list() + + data["activity"] = active + data["loadedSeed"] = seed ? "[seed.name]" : null + data["disk"] = loaded_disk ? TRUE : FALSE + + return data + +/// UI action behavior shared between both editor and extractor machinery. +/obj/machinery/botany/ui_act(action, params) + . = ..() + if(.) + return + + switch(action) + if("eject_packet") + if(!seed) + return FALSE + + seed.forceMove(get_turf(src)) + + if(seed.seed.name == "new line" || isnull(SSplants.seeds[seed.seed.name])) + seed.seed.uid = SSplants.seeds.len + 1 + seed.seed.name = "[seed.seed.uid]" + SSplants.seeds[seed.seed.name] = seed.seed + + seed.update_seed() + visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps and spits out [seed].") + seed = null + + if("eject_disk") + if(!loaded_disk) + return FALSE + + loaded_disk.forceMove(get_turf(src)) + visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps and spits out [loaded_disk].") + loaded_disk = null + + else + return FALSE + + return TRUE + +/// Allows for a trait to be extracted from a seed packet, destroying that seed. /obj/machinery/botany/extractor name = "lysis-isolation centrifuge" icon_state = "centrifuge" @@ -136,194 +189,142 @@ /obj/item/stock_parts/manipulator = 3, /obj/item/stock_parts/scanning_module = 1 ) + /// Currently scanned seed genetic structure. + var/datum/seed/genetics + /// Increments with each scan, stops allowing gene mods after a certain point. + var/degradation = 0 - var/datum/seed/genetics // Currently scanned seed genetic structure. - var/degradation = 0 // Increments with each scan, stops allowing gene mods after a certain point. - -/obj/machinery/botany/extractor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - +/obj/machinery/botany/extractor/ui_interact(mob/user, datum/tgui/ui) if(!user) return - var/list/data = list() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "BotanyIsolator", "Lysis-Isolation Centrifuge") + ui.open() - var/list/geneMasks = SSplants.gene_masked_list - data["geneMasks"] = geneMasks +/obj/machinery/botany/extractor/ui_data(mob/user) + var/list/data = ..() - data["activity"] = active data["degradation"] = degradation - - if(loaded_disk) - data["disk"] = 1 - else - data["disk"] = 0 - - if(seed) - data["loaded"] = "[seed.name]" - else - data["loaded"] = 0 + data["geneMasks"] = SSplants.gene_masked_list if(genetics) - data["hasGenetics"] = 1 + data["hasGeneticsData"] = TRUE data["sourceName"] = genetics.display_name if(!genetics.roundstart) data["sourceName"] += " (variety #[genetics.uid])" - else - data["hasGenetics"] = 0 - data["sourceName"] = 0 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "botany_isolator.tmpl", "Lysis-isolation Centrifuge UI", 470, 450) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["loadedseed"] = seed ? "[seed.name]" : "Unknown" + data["disk"] = loaded_disk ? TRUE : FALSE -/obj/machinery/botany/Topic(href, href_list) + return data - if(..()) - return 1 +/obj/machinery/botany/extractor/ui_act(action, params) + switch(action) + if("scan_genome") + if(!seed) + return FALSE - if(href_list["eject_packet"]) - if(!seed) return - seed.forceMove(get_turf(src)) + last_action = world.time + active = TRUE - if(seed.seed.name == "new line" || isnull(SSplants.seeds[seed.seed.name])) - seed.seed.uid = SSplants.seeds.len + 1 - seed.seed.name = "[seed.seed.uid]" - SSplants.seeds[seed.seed.name] = seed.seed + if(seed && seed.seed) + genetics = seed.seed + degradation = 0 - seed.update_seed() - visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps and spits out [seed].") + qdel(seed) + seed = null - seed = null + return TRUE - if(href_list["eject_disk"]) - if(!loaded_disk) return - loaded_disk.forceMove(get_turf(src)) - visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps and spits out [loaded_disk].") - loaded_disk = null + if("get_gene") + if(!genetics || !loaded_disk) + return TRUE - usr.set_machine(src) - src.add_fingerprint(usr) + var/gene_tag = params["gene"] + if(!gene_tag) + return TRUE -/obj/machinery/botany/extractor/Topic(href, href_list) + last_action = world.time + active = TRUE - if(..()) - return 1 + var/datum/plantgene/P = genetics.get_gene(gene_tag) + if(!P) + return TRUE - usr.set_machine(src) - src.add_fingerprint(usr) + loaded_disk.genes += P - if(href_list["scan_genome"]) + loaded_disk.genesource = "[genetics.display_name]" + if(!genetics.roundstart) + loaded_disk.genesource += " (variety #[genetics.uid])" - if(!seed) return + loaded_disk.name += " ([SSplants.gene_tag_masks[gene_tag]], #[genetics.uid])" + loaded_disk.desc += " The label reads 'gene [SSplants.gene_tag_masks[gene_tag]], sampled from [genetics.display_name]'." + eject_disk = TRUE - last_action = world.time - active = 1 + degradation += rand(20,60) + if(degradation >= 100) + failed_task = TRUE + genetics = null + degradation = 0 + return TRUE - if(seed && seed.seed) - genetics = seed.seed - degradation = 0 - - qdel(seed) - seed = null - - if(href_list["get_gene"]) - - if(!genetics || !loaded_disk) return - - last_action = world.time - active = 1 - - var/datum/plantgene/P = genetics.get_gene(href_list["get_gene"]) - if(!P) return - loaded_disk.genes += P - - loaded_disk.genesource = "[genetics.display_name]" - if(!genetics.roundstart) - loaded_disk.genesource += " (variety #[genetics.uid])" - - loaded_disk.name += " ([SSplants.gene_tag_masks[href_list["get_gene"]]], #[genetics.uid])" - loaded_disk.desc += " The label reads \'gene [SSplants.gene_tag_masks[href_list["get_gene"]]], sampled from [genetics.display_name]\'." - eject_disk = 1 - - degradation += rand(20,60) - if(degradation >= 100) - failed_task = 1 + if("clear_buffer") + if(!genetics) + return genetics = null degradation = 0 + return TRUE - if(href_list["clear_buffer"]) - if(!genetics) return - genetics = null - degradation = 0 + return ..() - src.updateUsrDialog() - return - -// Fires an extracted trait into another packet of seeds with a chance -// of destroying it based on the size/complexity of the plasmid. +/// Injects an extracted trait into another packet of seeds with a chance of destroying it based on the size/complexity of the plasmid. /obj/machinery/botany/editor name = "bioballistic delivery system" icon_state = "traitgun" - disk_needs_genes = 1 + disk_needs_genes = TRUE component_types = list( /obj/item/circuitboard/botany_editor, /obj/item/stock_parts/manipulator = 3, /obj/item/stock_parts/scanning_module = 1 ) -/obj/machinery/botany/editor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - +/obj/machinery/botany/editor/ui_interact(mob/user, datum/tgui/ui) if(!user) return - var/list/data = list() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "BotanyEditor", "Bioballistic Delivery System") + ui.open() - data["activity"] = active +/obj/machinery/botany/editor/ui_data(mob/user) + var/list/data = ..() - if(seed) - data["degradation"] = seed.modified - else - data["degradation"] = 0 + data["degradation"] = seed ? seed.modified : 0 + data["disk"] = !!loaded_disk if(loaded_disk && loaded_disk.genes.len) - data["disk"] = 1 data["sourceName"] = loaded_disk.genesource data["locus"] = "" for(var/datum/plantgene/P in loaded_disk.genes) - if(data["locus"] != "") data["locus"] += ", " + if(data["locus"] != "") + data["locus"] += ", " data["locus"] += "[SSplants.gene_tag_masks[P.genetype]]" - else - data["disk"] = 0 - data["sourceName"] = 0 - data["locus"] = 0 + data["loadedseed"] = seed ? "[seed.name]" : null - if(seed) - data["loaded"] = "[seed.name]" - else - data["loaded"] = 0 + return data - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "botany_editor.tmpl", "Bioballistic Delivery UI", 470, 450) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/botany/editor/Topic(href, href_list) - - if(..()) - return 1 - - if(href_list["apply_gene"]) - if(!loaded_disk || !seed) return +/obj/machinery/botany/editor/ui_act(action, params) + if(action == "apply_gene") + if(!loaded_disk || !seed) + return TRUE last_action = world.time - active = 1 + active = TRUE if(!isnull(SSplants.seeds[seed.seed.name])) seed.seed = seed.seed.diverge(1) @@ -331,15 +332,16 @@ seed.update_seed() if(prob(seed.modified)) - failed_task = 1 + failed_task = TRUE seed.modified = 101 for(var/datum/plantgene/gene in loaded_disk.genes) seed.seed.apply_gene(gene) seed.modified += rand(5,10) - usr.set_machine(src) - src.add_fingerprint(usr) + return TRUE + + return ..() /obj/item/circuitboard/botany_extractor name = T_BOARD("lysis-isolation centrifuge") diff --git a/html/changelogs/Bat-XenobotTgui.yml b/html/changelogs/Bat-XenobotTgui.yml new file mode 100644 index 00000000000..038419503c2 --- /dev/null +++ b/html/changelogs/Bat-XenobotTgui.yml @@ -0,0 +1,14 @@ +# Your name. +author: Batrachophrenoboocosmomachia + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Converts xenobotany's Bioballistic Delivery System interface from NanoUI to TGUI." + - refactor: "Converts xenobotany's Lysis-Isolation Centrifuge interface from NanoUI to TGUI." diff --git a/tgui/packages/tgui/interfaces/BotanyEditor.tsx b/tgui/packages/tgui/interfaces/BotanyEditor.tsx new file mode 100644 index 00000000000..b406dd01093 --- /dev/null +++ b/tgui/packages/tgui/interfaces/BotanyEditor.tsx @@ -0,0 +1,98 @@ +// botany_editor.tsx +import { Window } from '../layouts'; +import { BooleanLike } from '../../common/react'; +import { useBackend } from '../backend'; +import { Box, Button, LabeledList, NoticeBox, Section } from '../components'; + +type Data = { + activity: BooleanLike; + degradation: number; + disk: BooleanLike; + sourceName: string; + locus: string; + loadedseed: string; +}; + +export const BotanyEditor = (_props, context) => { + const { act, data } = useBackend(context); + const { activity, degradation, disk, sourceName, locus, loadedseed } = data; + + const hasLoadedSeed = !!loadedseed; + const viable = degradation <= 100; + + return ( + + + {activity ? ( + Bioballistics systems engaged... + ) : ( + +
+ {disk ? ( + + + + {String(sourceName)} + + + {viable ? ( + `${degradation}%` + ) : ( + + FURTHER AMENDMENTS NONVIABLE + + )} + + + {String(locus)} + + + +
+ +
+ {hasLoadedSeed ? ( + + + + {loadedseed} + + + + {viable && ( +
+
+ )} +
+
+ ); +}; + +export default BotanyEditor; diff --git a/tgui/packages/tgui/interfaces/BotanyIsolator.tsx b/tgui/packages/tgui/interfaces/BotanyIsolator.tsx new file mode 100644 index 00000000000..fc79f3cf038 --- /dev/null +++ b/tgui/packages/tgui/interfaces/BotanyIsolator.tsx @@ -0,0 +1,138 @@ +// botany_isolator.tsx +import { useBackend } from '../backend'; +import { Box, Button, LabeledList, NoticeBox, Section } from '../components'; +import { Window } from '../layouts'; +import { BooleanLike } from '../../common/react'; + +type GeneMask = { + mask: string; + tag: string; +}; + +type Data = { + activity: BooleanLike; + degradation: number; + disk: BooleanLike; + loadedSeed: string; + sourceName: string; + HasGeneticsData: BooleanLike; + geneMasks: GeneMask[] | null; +}; + +export const BotanyIsolator = (_props, context) => { + const { act, data } = useBackend(context); + const { activity, degradation, disk, loadedSeed, sourceName, geneMasks } = + data; + + const hasDisk = !!disk; + const hasLoadedSeed = !!loadedSeed; + const masks = Array.isArray(geneMasks) ? geneMasks : []; + + return ( + + + {activity ? ( + Scanning... + ) : ( + +
+ {hasLoadedSeed ? ( + + + + {String(sourceName)} + + + {degradation}% + + + + {hasDisk ? ( + + {masks.length > 0 ? ( + + {masks.map((entry) => ( + +
+ +
+ {hasLoadedSeed ? ( + + + + {loadedSeed} + + + +
+
+ )} +
+
+ ); +}; + +export default BotanyIsolator;