Files
Batrachophreno cb2718db78 Xenobotany device NanoUI conversions (#21856)
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."
<img width="949" height="532" alt="image"
src="https://github.com/user-attachments/assets/91930b83-1a2d-4ecb-801d-153b1ae52ed1"
/>
2026-02-22 12:22:31 +00:00

356 lines
9.3 KiB
Plaintext

/obj/item/disk/botany
name = "flora data disk"
desc = "A small disk used for carrying data on plant genetics."
icon = 'icons/obj/hydroponics_machines.dmi'
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()
..()
pixel_x = rand(-5,5)
pixel_y = rand(-5,5)
/obj/item/disk/botany/attack_self(var/mob/user as mob)
if(genes.len)
var/choice = alert(user, "Are you sure you want to wipe the disk?", "Xenobotany Data", "No", "Yes")
if(src && user && genes && choice && choice == "Yes" && user.Adjacent(get_turf(src)))
to_chat(user, "You wipe the disk data.")
name = initial(name)
desc = initial(name)
genes = list()
genesource = "unknown"
/obj/item/storage/box/botanydisk
name = "flora disk box"
desc = "A box of flora data disks, apparently."
/obj/item/storage/box/botanydisk/fill()
..()
for(var/i = 0;i<7;i++)
new /obj/item/disk/botany(src)
/obj/machinery/botany
icon = 'icons/obj/hydroponics_machines.dmi'
icon_state = "hydrotray3"
density = TRUE
anchored = TRUE
/// 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
/// 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
if(world.time > last_action + action_time)
finished_task()
/obj/machinery/botany/attack_ai(mob/user as mob)
if(!ai_can_interact(user))
return
return attack_hand(user)
/obj/machinery/botany/attack_hand(mob/user as mob)
ui_interact(user)
/obj/machinery/botany/proc/finished_task()
active = 0
if(failed_task)
failed_task = 0
visible_message("[icon2html(src, viewers(get_turf(src)))] [src] pings unhappily, flashing a red warning light.")
else
visible_message("[icon2html(src, viewers(get_turf(src)))] [src] pings happily.")
if(eject_disk)
eject_disk = 0
if(loaded_disk)
loaded_disk.forceMove(get_turf(src))
visible_message("[icon2html(src, viewers(get_turf(src)))] [src] beeps and spits out [loaded_disk].")
loaded_disk = null
/obj/machinery/botany/attackby(obj/item/attacking_item, mob/user)
if(istype(attacking_item, /obj/item/seeds))
if(seed)
to_chat(user, "There is already a seed loaded.")
return
var/obj/item/seeds/S = attacking_item
if(S.seed && S.GET_SEED_TRAIT(seed, TRAIT_IMMUTABLE) > 0)
to_chat(user, "That seed is not compatible with our genetics technology.")
else
user.drop_from_inventory(attacking_item,src)
seed = attacking_item
to_chat(user, "You load [attacking_item] into [src].")
return
if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER)
panel_open = !panel_open
to_chat(user, SPAN_NOTICE("You [panel_open ? "open" : "close"] the maintenance panel."))
return
if(panel_open)
if(attacking_item.tool_behaviour == TOOL_CROWBAR)
dismantle()
return
if(istype(attacking_item,/obj/item/disk/botany))
if(loaded_disk)
to_chat(user, "There is already a data disk loaded.")
return
else
var/obj/item/disk/botany/B = attacking_item
if(B.genes && B.genes.len)
if(!disk_needs_genes)
to_chat(user, "That disk already has gene data loaded.")
return
else
if(disk_needs_genes)
to_chat(user, "That disk does not have any gene data loaded.")
return
user.drop_from_inventory(attacking_item,src)
loaded_disk = attacking_item
to_chat(user, "You load [attacking_item] into [src].")
return
..()
/// 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"
component_types = list(
/obj/item/circuitboard/botany_extractor,
/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
/obj/machinery/botany/extractor/ui_interact(mob/user, datum/tgui/ui)
if(!user)
return
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "BotanyIsolator", "Lysis-Isolation Centrifuge")
ui.open()
/obj/machinery/botany/extractor/ui_data(mob/user)
var/list/data = ..()
data["degradation"] = degradation
data["geneMasks"] = SSplants.gene_masked_list
if(genetics)
data["hasGeneticsData"] = TRUE
data["sourceName"] = genetics.display_name
if(!genetics.roundstart)
data["sourceName"] += " (variety #[genetics.uid])"
data["loadedseed"] = seed ? "[seed.name]" : "Unknown"
data["disk"] = loaded_disk ? TRUE : FALSE
return data
/obj/machinery/botany/extractor/ui_act(action, params)
switch(action)
if("scan_genome")
if(!seed)
return FALSE
last_action = world.time
active = TRUE
if(seed && seed.seed)
genetics = seed.seed
degradation = 0
qdel(seed)
seed = null
return TRUE
if("get_gene")
if(!genetics || !loaded_disk)
return TRUE
var/gene_tag = params["gene"]
if(!gene_tag)
return TRUE
last_action = world.time
active = TRUE
var/datum/plantgene/P = genetics.get_gene(gene_tag)
if(!P)
return TRUE
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[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
degradation += rand(20,60)
if(degradation >= 100)
failed_task = TRUE
genetics = null
degradation = 0
return TRUE
if("clear_buffer")
if(!genetics)
return
genetics = null
degradation = 0
return TRUE
return ..()
/// 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 = 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, datum/tgui/ui)
if(!user)
return
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "BotanyEditor", "Bioballistic Delivery System")
ui.open()
/obj/machinery/botany/editor/ui_data(mob/user)
var/list/data = ..()
data["degradation"] = seed ? seed.modified : 0
data["disk"] = !!loaded_disk
if(loaded_disk && loaded_disk.genes.len)
data["sourceName"] = loaded_disk.genesource
data["locus"] = ""
for(var/datum/plantgene/P in loaded_disk.genes)
if(data["locus"] != "")
data["locus"] += ", "
data["locus"] += "[SSplants.gene_tag_masks[P.genetype]]"
data["loadedseed"] = seed ? "[seed.name]" : null
return data
/obj/machinery/botany/editor/ui_act(action, params)
if(action == "apply_gene")
if(!loaded_disk || !seed)
return TRUE
last_action = world.time
active = TRUE
if(!isnull(SSplants.seeds[seed.seed.name]))
seed.seed = seed.seed.diverge(1)
seed.seed_type = seed.seed.name
seed.update_seed()
if(prob(seed.modified))
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)
return TRUE
return ..()
/obj/item/circuitboard/botany_extractor
name = T_BOARD("lysis-isolation centrifuge")
build_path = /obj/machinery/botany/extractor
origin_tech = list(TECH_DATA = 3)
/obj/item/circuitboard/botany_editor
name = T_BOARD("bioballistic delivery system")
build_path = /obj/machinery/botany/editor
origin_tech = list(TECH_DATA = 3)