diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm index 0dbf5d65af1..1d0269d8cb1 100644 --- a/_maps/map_files/debug/runtimestation.dmm +++ b/_maps/map_files/debug/runtimestation.dmm @@ -1222,6 +1222,11 @@ "kS" = ( /turf/closed/wall/r_wall, /area/station/medical/chemistry) +"kY" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/service/hydroponics) "lc" = ( /turf/open/floor/engine, /area/station/hallway/secondary/entry) @@ -1444,6 +1449,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/engineering/main) +"tj" = ( +/obj/structure/cable, +/obj/machinery/light/directional/east, +/obj/item/gun/energy/floragun, +/obj/item/geneshears, +/turf/open/floor/iron, +/area/station/service/hydroponics) "tn" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1559,6 +1571,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white/corner, /area/station/medical/medbay) +"vK" = ( +/obj/machinery/door/airlock, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/service/hydroponics) "vQ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -1638,6 +1656,12 @@ /obj/structure/transit_tube/station/dispenser/reverse/flipped, /turf/open/floor/iron, /area/station/engineering/gravity_generator) +"xv" = ( +/obj/machinery/vending/hydroseeds{ + all_products_free = 1 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "xD" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/effect/turf_decal/tile/blue/half/contrasted, @@ -1728,6 +1752,10 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron, /area/station/science) +"zU" = ( +/obj/machinery/hydroponics/constructable/fullupgrade, +/turf/open/floor/iron, +/area/station/service/hydroponics) "zY" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -1736,6 +1764,7 @@ /area/station/commons/storage/primary) "Aj" = ( /obj/structure/cable, +/obj/machinery/light/directional/east, /turf/open/floor/iron, /area/station/cargo/bitrunning/den) "An" = ( @@ -1792,6 +1821,11 @@ /obj/item/gun/ballistic/automatic/pistol, /turf/open/floor/iron, /area/station/command/bridge) +"BK" = ( +/obj/item/wrench, +/obj/item/plant_analyzer, +/turf/open/floor/iron, +/area/station/service/hydroponics) "BM" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, @@ -1841,6 +1875,17 @@ /obj/machinery/component_printer, /turf/open/floor/iron/dark, /area/station/science/explab) +"Dd" = ( +/obj/item/shovel/spade{ + pixel_y = 4; + pixel_x = 3 + }, +/obj/item/secateurs, +/obj/item/cultivator{ + pixel_x = -6 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "Df" = ( /obj/machinery/light/directional/east, /obj/item/integrated_circuit/loaded/hello_world, @@ -1984,7 +2029,7 @@ /area/station/engineering/atmos) "GN" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 + dir = 1 }, /obj/machinery/light/directional/south, /turf/open/floor/iron, @@ -2098,6 +2143,9 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/gravity_generator) +"Ju" = ( +/turf/closed/wall/r_wall, +/area/station/service/hydroponics) "JJ" = ( /obj/machinery/navbeacon{ codes_txt = "patrol;next_patrol=4-Southeast"; @@ -2133,6 +2181,12 @@ /obj/machinery/light/directional/south, /turf/open/floor/plating, /area/station/engineering/atmos) +"KW" = ( +/obj/structure/sink/directional/south, +/obj/item/storage/bag/plants, +/obj/item/reagent_containers/cup/watering_can/advanced, +/turf/open/floor/iron, +/area/station/service/hydroponics) "Lb" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -2193,11 +2247,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/primary/central) -"Ml" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/light/directional/south, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) "My" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -2210,6 +2259,12 @@ }, /turf/open/floor/iron, /area/station/cargo/miningoffice) +"MH" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "MM" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/stripes/line{ @@ -2222,6 +2277,12 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/gravity_generator) +"MT" = ( +/obj/machinery/vending/hydronutrients{ + all_products_free = 1 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "Nb" = ( /obj/machinery/bci_implanter, /turf/open/floor/iron/dark, @@ -2275,6 +2336,10 @@ /obj/item/stock_parts/power_store/cell/bluespace, /turf/open/floor/iron/dark, /area/station/science/explab) +"Oy" = ( +/obj/machinery/seed_extractor, +/turf/open/floor/iron, +/area/station/service/hydroponics) "OF" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -2483,7 +2548,6 @@ /area/station/medical/medbay) "SC" = ( /obj/structure/table/reinforced, -/obj/machinery/light/directional/south, /obj/item/bitrunning_debug, /turf/open/floor/iron, /area/station/cargo/bitrunning/den) @@ -2573,6 +2637,13 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/main) +"VF" = ( +/obj/machinery/hydroponics/constructable/fullupgrade, +/obj/machinery/power/apc/auto_name/directional/south, +/obj/structure/cable, +/obj/machinery/airalarm/directional/east, +/turf/open/floor/iron, +/area/station/service/hydroponics) "We" = ( /obj/machinery/newscaster/directional/west, /turf/open/floor/iron, @@ -2672,6 +2743,10 @@ "Yd" = ( /turf/open/floor/iron, /area/station/cargo/bitrunning/den) +"Yg" = ( +/obj/machinery/smartfridge/food, +/turf/open/floor/plating, +/area/station/service/hydroponics) "Ym" = ( /obj/structure/table, /obj/item/storage/toolbox/electrical, @@ -3356,12 +3431,12 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa +Ju +Ju +Ju +Ju +Ju +Ju aa aa aa @@ -3448,12 +3523,12 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa +Ju +MT +xv +BK +zU +Ju aa aa aa @@ -3540,12 +3615,12 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa +Ju +KW +MH +Dd +zU +Ju aa aa aa @@ -3632,12 +3707,12 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa +Ju +Oy +kY +tj +VF +Ju aa aa aa @@ -3724,12 +3799,12 @@ Tj Tj Tj Tj -dY -en -dY -dY -aa -aa +Ju +Yg +vK +Ju +Ju +Ju aa aa aa @@ -3818,7 +3893,7 @@ lc lc wB eh -eh +ax dY aa aa @@ -3910,7 +3985,7 @@ lc lc wB eh -eh +ax en aa aa @@ -4002,7 +4077,7 @@ lc lc wB eh -eh +ax en aa aa @@ -4094,7 +4169,7 @@ lc lc wB eh -eh +ax dY aa aa @@ -4186,7 +4261,7 @@ lc lc wB eh -eh +ax en aa aa @@ -4278,7 +4353,7 @@ lc lc wB eh -eh +ax en aa aa @@ -4369,8 +4444,8 @@ lc lc lc wB -eh -eh +ax +ax en aa aa @@ -4461,7 +4536,7 @@ lc lc lc wB -eh +ax eh dY aa @@ -4553,7 +4628,7 @@ lc lc lc wB -eh +ax eh en aa @@ -4645,7 +4720,7 @@ lc lc lc wB -eh +ax eh en aa @@ -4737,7 +4812,7 @@ lc lc lc wB -eh +ax gv dY aa @@ -4829,7 +4904,7 @@ lc lc lc wB -eh +ax eh en aa @@ -4921,7 +4996,7 @@ lc lc lc wB -eh +ax gF fj aa @@ -5013,7 +5088,7 @@ lc lc lc wB -eh +ax eh en aa @@ -5105,7 +5180,7 @@ lc lc lc wB -eh +ax GN dY aa @@ -5197,8 +5272,8 @@ lc lc lc wB +ax eh -BM en aa aa @@ -5289,8 +5364,8 @@ lc lc lc wB +ax eh -BM en aa aa @@ -5381,8 +5456,8 @@ lc lc lc wB +ax eh -BM en aa aa @@ -5473,8 +5548,8 @@ lc lc lc wB -eh -Ml +ax +gv dY aa aa @@ -5565,8 +5640,8 @@ lc lc lc wB +ax eh -BM en aa aa @@ -5657,8 +5732,8 @@ en en dY wB +ax eh -BM dY dY fn @@ -5749,8 +5824,8 @@ eh eh eV eh +ax eh -BM eh eV eh diff --git a/code/game/objects/items/devices/scanners/plant_analyzer.dm b/code/game/objects/items/devices/scanners/plant_analyzer.dm index 78bcd74ae6e..fcce33141df 100644 --- a/code/game/objects/items/devices/scanners/plant_analyzer.dm +++ b/code/game/objects/items/devices/scanners/plant_analyzer.dm @@ -1,3 +1,6 @@ +#define PLANT_ANALYZER_STAT_TAB 1 +#define PLANT_ANALYZER_CHEM_TAB 2 + /obj/item/plant_analyzer name = "plant analyzer" desc = "A scanner used to evaluate a plant's various areas of growth, genetic traits and chemicals." @@ -12,13 +15,21 @@ custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT*0.3, /datum/material/glass =SMALL_MATERIAL_AMOUNT*0.2) /// Cached data from ui_interact var/list/last_scan_data + /// Weakref to the last thing we scanned + var/datum/weakref/last_tray_scanned /// Cached data for the product grinder results var/static/list/product_grinder_results = list() + /// If TRUE the UI opens to the second tab / the chem tab + var/shown_tab = PLANT_ANALYZER_STAT_TAB /obj/item/plant_analyzer/Initialize(mapload) . = ..() register_item_context() +/obj/item/plant_analyzer/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + /obj/item/plant_analyzer/add_item_context( obj/item/source, list/context, @@ -63,6 +74,7 @@ return ITEM_INTERACT_SUCCESS return ITEM_INTERACT_BLOCKING + shown_tab = PLANT_ANALYZER_STAT_TAB return analyze(user, interacting_with) /// Same as above, but with right click. Right-clicking scans for chemicals. @@ -86,6 +98,7 @@ return ITEM_INTERACT_SUCCESS return ITEM_INTERACT_BLOCKING + shown_tab = PLANT_ANALYZER_CHEM_TAB return analyze(user, scan_target) /* @@ -123,8 +136,22 @@ ui = new(user, src, "PlantAnalyzer", "Plant Analyzer") ui.open() +/obj/item/plant_analyzer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + switch(action) + if("setTab") + var/tab = params["tab"] + if(tab == PLANT_ANALYZER_STAT_TAB || tab == PLANT_ANALYZER_CHEM_TAB) + shown_tab = tab + return TRUE + /obj/item/plant_analyzer/ui_data(mob/user) - return last_scan_data + var/list/data = list() + data["active_tab"] = shown_tab + data += last_scan_data + return data /obj/item/plant_analyzer/ui_static_data(mob/user) var/list/data = list() @@ -140,13 +167,22 @@ data["trait_db"] += trait_data return data +/obj/item/plant_analyzer/process(seconds_per_tick) + var/atom/real_last_tray_scanned = last_tray_scanned?.resolve() + if(QDELETED(real_last_tray_scanned)) + return PROCESS_KILL + + if(loc.Adjacent(real_last_tray_scanned)) + analyze(null, real_last_tray_scanned) + /// Called when our analyzer is used on something /obj/item/plant_analyzer/proc/analyze(mob/user, atom/target) var/obj/item/graft/graft var/obj/item/seeds/seed var/obj/machinery/hydroponics/tray - playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE) + if(user) + playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE) if (istype(target, /obj/machinery/hydroponics)) tray = target @@ -166,12 +202,16 @@ if (!seed && !tray && !graft) return NONE - if(!user.can_read(src)) - return ITEM_INTERACT_BLOCKING + if(user) + if(!user.can_read(src)) + return ITEM_INTERACT_BLOCKING + START_PROCESSING(SSobj, src) + last_tray_scanned = WEAKREF(tray) // sets it to null if no tray last_scan_data = list( "tray_data" = null, "seed_data" = null, + "plant_data" = null, "graft_data" = null, ) @@ -179,6 +219,7 @@ last_scan_data["tray_data"] = list( "plant_health" = tray.plant_health, "plant_age" = tray.age, + "is_dead" = tray.plant_status == HYDROTRAY_PLANT_DEAD, "name" = tray.name, "icon" = tray.icon, "icon_state" = tray.icon_state, @@ -198,15 +239,27 @@ "toxins_max" = MAX_TRAY_TOXINS, "reagents" = list(), ) - for(var/datum/reagent/reagent in tray.reagents.reagent_list) + for(var/datum/reagent/reagent as anything in tray.reagents.reagent_list) last_scan_data["tray_data"]["reagents"] += list(list( "name" = reagent.name, - "volume" = reagent.volume + "volume" = round(reagent.volume, CHEMICAL_QUANTISATION_LEVEL), + "color" = reagent.color, )) if(seed) last_scan_data["seed_data"] = make_seed_data(seed) + if(isitem(target) && target.reagents) + last_scan_data["plant_data"] = list( + "reagents" = list(), + ) + for(var/datum/reagent/reagent as anything in target.reagents.reagent_list) + last_scan_data["plant_data"]["reagents"] += list(list( + "name" = reagent.name, + "volume" = round(reagent.volume, CHEMICAL_QUANTISATION_LEVEL), + "color" = reagent.color, + )) + if(graft) last_scan_data["graft_data"] = list( "name" = graft.parent_name, @@ -218,10 +271,11 @@ "endurance" = graft.endurance, "weed_rate" = graft.weed_rate, "weed_chance" = graft.weed_chance, - "graft_gene" = graft.stored_trait.type + "graft_gene" = graft.stored_trait.type, ) - ui_interact(user) + if(user) + ui_interact(user) return ITEM_INTERACT_SUCCESS @@ -280,4 +334,15 @@ seed_data["juice_name"] = product_grinder_results[seed.product]["juice_name"] seed_data["grind_results"] = product_grinder_results[seed.product]["grind_results"] + seed_data["unique_labels"] = list() + seed_data["unique_collapsibles"] = list() + var/list/unique_data = seed.get_unique_analyzer_data() + for(var/label in unique_data) + seed_data[islist(unique_data[label]) ? "unique_collapsibles" : "unique_labels"] += list(list( + "label" = label, + "data" = unique_data[label], + )) return seed_data + +#undef PLANT_ANALYZER_STAT_TAB +#undef PLANT_ANALYZER_CHEM_TAB diff --git a/code/modules/events/space_vines/vine_mutations.dm b/code/modules/events/space_vines/vine_mutations.dm index 8a9d922ee82..9db702169dd 100644 --- a/code/modules/events/space_vines/vine_mutations.dm +++ b/code/modules/events/space_vines/vine_mutations.dm @@ -1,6 +1,8 @@ /datum/spacevine_mutation /// Displayed name of mutation var/name = "" + /// Description of mutation, shown in the plant analyzer + var/description = "" /// Severity of mutation in terms of gameplay, affects appearance chance and how many mutations can be on the same vine var/severity = 1 /// The mutation's contribution to a given vine's color @@ -64,6 +66,7 @@ /datum/spacevine_mutation/light name = "Light" + description = "Emits light." hue = "#B2EA70" quality = POSITIVE severity = SEVERITY_TRIVIAL @@ -74,6 +77,7 @@ /datum/spacevine_mutation/toxicity name = "Toxic" + description = "Releases toxins when touched or eaten." hue = "#9B3675" severity = SEVERITY_AVERAGE quality = NEGATIVE @@ -91,6 +95,7 @@ /datum/spacevine_mutation/explosive // JC IT'S A BOMB name = "Explosive" + description = "Causes an explosion when destroyed." hue = "#D83A56" quality = NEGATIVE severity = SEVERITY_MAJOR @@ -108,6 +113,7 @@ /datum/spacevine_mutation/fire_proof name = "Fire proof" + description = "Provides immunity to heat and burn damage." hue = "#FF616D" quality = MINOR_NEGATIVE severity = SEVERITY_ABOVE_AVERAGE @@ -123,6 +129,7 @@ /datum/spacevine_mutation/cold_proof name = "Cold proof" + description = "Provides immunity to cold damage." hue = "#0BD5D9" quality = MINOR_NEGATIVE severity = SEVERITY_AVERAGE @@ -133,6 +140,7 @@ /datum/spacevine_mutation/temp_stabilisation name = "Temperature stabilisation" + description = "Stabilizes the temperature of the surrounding area." hue = "#B09856" quality = POSITIVE severity = SEVERITY_MINOR @@ -156,6 +164,7 @@ /datum/spacevine_mutation/vine_eating name = "Vine eating" + description = "Destroys other Kudzu vines on spread." hue = "#F4A442" quality = MINOR_NEGATIVE severity = SEVERITY_MINOR @@ -167,6 +176,7 @@ /datum/spacevine_mutation/aggressive_spread //very OP, but im out of other ideas currently name = "Aggressive spreading" + description = "Heavily wounds mobs when spreading or tangling them." hue = "#316b2f" severity = SEVERITY_MAJOR quality = NEGATIVE @@ -222,6 +232,7 @@ /datum/spacevine_mutation/transparency name = "transparent" + description = "Allows light to pass through." hue = "" quality = POSITIVE severity = SEVERITY_TRIVIAL @@ -232,6 +243,7 @@ /datum/spacevine_mutation/oxy_eater name = "Oxygen consuming" + description = "Consumes Oxygen from the surrounding area." hue = "#28B5B5" severity = SEVERITY_AVERAGE quality = NEGATIVE @@ -247,6 +259,7 @@ /datum/spacevine_mutation/nitro_eater name = "Nitrogen consuming" + description = "Consumes Nitrogen from the surrounding area." hue = "#FF7B54" severity = SEVERITY_AVERAGE quality = NEGATIVE @@ -262,6 +275,7 @@ /datum/spacevine_mutation/carbondioxide_eater name = "CO2 consuming" + description = "Consumes Carbon Dioxide from the surrounding area." hue = "#798777" severity = SEVERITY_MINOR quality = POSITIVE @@ -277,6 +291,7 @@ /datum/spacevine_mutation/plasma_eater name = "Plasma consuming" + description = "Consumes Plasma from the surrounding area." hue = "#9074b6" severity = SEVERITY_AVERAGE quality = POSITIVE @@ -292,6 +307,7 @@ /datum/spacevine_mutation/thorns name = "Thorny" + description = "Causes damage when hitting or passing through the vines." hue = "#9ECCA4" severity = SEVERITY_AVERAGE quality = NEGATIVE @@ -324,6 +340,7 @@ /datum/spacevine_mutation/hardened name = "Hardened" + description = "Provides resistance to cutting attacks, makes vines hardier, and prevents light from passing through." hue = "#997700" quality = NEGATIVE severity = SEVERITY_ABOVE_AVERAGE @@ -340,6 +357,7 @@ /datum/spacevine_mutation/timid name = "Timid" + description = "Hides the vines under structures and prevents them from tangling mobs." hue = "#a4a9ac" quality = POSITIVE severity = SEVERITY_MINOR @@ -354,6 +372,7 @@ /datum/spacevine_mutation/flowering name = "Flowering" + description = "Causes the vine to grow flower buds which spawns man eating plants when fully grown." hue = "#66DE93" quality = NEGATIVE severity = SEVERITY_MAJOR diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm index 2b97110dafa..842c10a025e 100644 --- a/code/modules/hydroponics/grown/replicapod.dm +++ b/code/modules/hydroponics/grown/replicapod.dm @@ -106,11 +106,10 @@ sampleDNA = null contains_sample = FALSE -/obj/item/seeds/replicapod/get_unique_analyzer_text() +/obj/item/seeds/replicapod/get_unique_analyzer_data() if(contains_sample) - return "It contains a blood sample with blood DNA (UE) \"[sampleDNA]\"." //blood DNA (UE) shows in medical records and is readable by forensics scanners - else - return null + return list("Blood DNA" = sampleDNA) + return null /obj/item/seeds/replicapod/harvest(mob/user) //now that one is fun -- Urist var/obj/machinery/hydroponics/parent = loc diff --git a/code/modules/hydroponics/grown/weeds/kudzu.dm b/code/modules/hydroponics/grown/weeds/kudzu.dm index a0a3c940571..87241365cf4 100644 --- a/code/modules/hydroponics/grown/weeds/kudzu.dm +++ b/code/modules/hydroponics/grown/weeds/kudzu.dm @@ -50,13 +50,12 @@ plant(user) to_chat(user, span_notice("You plant the kudzu. You monster.")) -/obj/item/seeds/kudzu/get_unique_analyzer_text() - var/kudzu_mutations = "" - var/output_message = "" - for(var/datum/spacevine_mutation/SM in mutations) - kudzu_mutations += "[(kudzu_mutations == "") ? "" : ", "][SM.name]" - output_message += "Plant Mutations: [(kudzu_mutations == "") ? "None." : "[kudzu_mutations]."]" - return output_message +/obj/item/seeds/kudzu/get_unique_analyzer_data() + var/list/all_mutations = list() + for(var/datum/spacevine_mutation/vine_trait in mutations) + all_mutations[vine_trait.name] = vine_trait.description + + return list("Kudzu Traits" = all_mutations) /obj/item/seeds/kudzu/on_chem_reaction(datum/reagents/reagents) var/list/temp_mut_list = list() diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 5d110f8ef8e..ffa6f596711 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -111,16 +111,16 @@ if(HAS_SILICON_ACCESS(user)) return NONE + context[SCREENTIP_CONTEXT_RMB] = "Empty nutrients" + switch(plant_status) if(HYDROTRAY_PLANT_DEAD) context[SCREENTIP_CONTEXT_LMB] = "Remove dead plant" - return CONTEXTUAL_SCREENTIP_SET if(HYDROTRAY_PLANT_HARVESTABLE) context[SCREENTIP_CONTEXT_LMB] = "Harvest plant" - return CONTEXTUAL_SCREENTIP_SET - return NONE + return CONTEXTUAL_SCREENTIP_SET // If the plant is harvestable, we can graft it with secateurs or harvest it with a plant bag. if(plant_status == HYDROTRAY_PLANT_HARVESTABLE) diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index c2985aef15e..14def128976 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -452,9 +452,11 @@ /** * Override for seeds with unique text for their analyzer. (No newlines at the start or end of unique text!) - * Returns null if no unique text, or a string of text if there is. + * Returns null if no unique data + * Return an assoc list (label = text) to add a new line to the analyzer + * Return an assoc list (label = list(text = tooltip, text = tooltip)) to add a new collapsible section to the analyzer */ -/obj/item/seeds/proc/get_unique_analyzer_text() +/obj/item/seeds/proc/get_unique_analyzer_data() return null /** diff --git a/tgui/packages/tgui/interfaces/PlantAnalyzer/Graft.tsx b/tgui/packages/tgui/interfaces/PlantAnalyzer/Graft.tsx index 83f4e244779..87b14fe667b 100644 --- a/tgui/packages/tgui/interfaces/PlantAnalyzer/Graft.tsx +++ b/tgui/packages/tgui/interfaces/PlantAnalyzer/Graft.tsx @@ -16,6 +16,11 @@ export function PlantAnalyzerGraft(props) { const { data } = useBackend(); const { graft_data } = data; + if (!graft_data) { + // This shouldn't be rendered if graft_data is null + return null; + } + return (
(); - const { seed_data, tray_data } = data; + const { seed_data, tray_data, cycle_seconds, trait_db } = data; + + if (!seed_data) { + // This shouldn't be rendered if seed data is null + return null; + } + + const all_traits = [ + ...(seed_data.core_traits || []), + ...(seed_data.removable_traits || []), + ]; return ( -
} - > +
- - - {seed_data.product_icon && seed_data.product_icon_state && ( - - )} + + + + + + {seed_data.product_icon && seed_data.product_icon_state && ( + + + + )} + + + + {seed_data.mutatelist.length > 0 && ( + + + + {seed_data.mutatelist.map((mutation) => ( + + + + ))} + + + + )} + @@ -79,18 +138,25 @@ export function PlantAnalyzerSeed(props) { {tray_data && ( - - {tray_data.plant_age * data.cycle_seconds} /{' '} - {seed_data.lifespan * data.cycle_seconds} seconds - + {tray_data.is_dead ? ( + + + Dead + + ) : ( + + {tray_data.plant_age * cycle_seconds} /{' '} + {formatPerSecond(seed_data.lifespan, cycle_seconds, false)} + + )} )} @@ -98,30 +164,21 @@ export function PlantAnalyzerSeed(props) { label="Maturation" tooltip="The age at which the plant starts growing products." > - {seed_data.maturation * data.cycle_seconds} seconds + {formatPerSecond(seed_data.maturation, cycle_seconds)} - {seed_data.production * data.cycle_seconds} seconds + {formatPerSecond(seed_data.production, cycle_seconds)} - - {seed_data.lifespan} / 100 - + {formatPerSecond(seed_data.lifespan, cycle_seconds)} - - {seed_data.weed_chance && seed_data.weed_rate - ? seed_data.weed_chance + - '% chance to grow by ' + - seed_data.weed_rate - : 'No weed growth'} + + {`${seed_data.weed_chance}% chance to grow by + ${seed_data.weed_rate} every ${cycle_seconds} seconds`} + {seed_data.unique_labels.map((label) => ( + + {label.data} + + ))} + + + {all_traits.map((trait) => { + const traitInfo = getTraitInfo(trait, trait_db); + return ( + + + + ); + })} + + + {seed_data.unique_collapsibles.map((collapsible) => ( + + + {Object.entries(collapsible.data).map( + ([dataText, dataTooltip]) => ( + + + + ), + )} + + + ))}
); } -function SeedExtraData(props) { +export function PlantAnalyzerSeedChems(props) { const { data } = useBackend(); const { seed_data } = data; - return ( - <> - {!!seed_data.graft_gene && ( - - )} + if (!seed_data) { + // This shouldn't be rendered if seed data is null + return null; + } - {seed_data.removable_traits?.map((trait) => ( - - ))} - {seed_data.core_traits?.map((trait) => ( - - ))} - {!!seed_data.mutatelist.length && ( - - - - )} - {!!seed_data.juice_name && ( - - - - )} - {!!seed_data.distill_reagent && ( - - - - )} - {seed_data.reagents.length > 0 && ( - - } - > - - - )} - + const totalPercentage = seed_data.reagents.reduce( + (sum, reagent) => sum + reagent.rate * 100, + 0, + ); + + const totalVolume = + seed_data.reagents.reduce( + (sum, reagent) => sum + expectedReagentVolume(reagent, seed_data), + 0, + ) || 0; + + return ( +
+ + + {seed_data.reagents.length === 0 ? ( + + No reagent genes + + ) : ( + + + Reagent + Percentage + + + + Expected Volume + + + + + {seed_data.reagents.map((reagent) => ( + + + {reagent.name} + + {reagent.rate * 100}% + + ~{expectedReagentVolume(reagent, seed_data)}u + + + ))} + + + Total + + + {totalPercentage}% + {totalPercentage > 100 && ( + +
+ )} +
+
+
); } + +export function PlantAnalyzerPlantChems(props) { + const { data } = useBackend(); + const { seed_data, plant_data } = data; + + if (!seed_data || !plant_data) { + // This shouldn't be rendered if seed or plant data is null + return null; + } + + return ( +
+ + + {plant_data.reagents.length === 0 ? ( + + No reagent genes + + ) : ( + + + Reagent + Volume + + {plant_data.reagents.map((reagent) => ( + + + {reagent.name} + + {reagent.volume} + + ))} + + + Total + + + {plant_data.reagents.reduce( + (sum, reagent) => sum + reagent.volume, + 0, + )} + u + + +
+ )} +
+
+
+ ); +} + +function expectedReagentVolume( + reagent: ReagentData, + seed_data: SeedData, +): number { + const baseVolume = seed_data.volume_units * seed_data.volume_mod; + return Math.round(reagent.rate * baseVolume * (seed_data.potency / 100)) || 0; +} + +function formatPerSecond( + value: number, + cycle_seconds: number, + simplify: boolean = true, +) { + if (!simplify) { + return `${value * cycle_seconds} second${value * cycle_seconds > 1 ? 's' : ''}`; + } + const seconds = Math.round(value * cycle_seconds); + if (seconds < 60) { + return `${seconds} second${seconds > 1 ? 's' : ''}`; + } + const minutes = Math.floor(seconds / 60); + const remainingSeconds = seconds % 60; + return `${minutes} minute${minutes > 1 ? 's' : ''}${ + remainingSeconds > 0 + ? `, ${remainingSeconds} second${remainingSeconds > 1 ? 's' : ''}` + : '' + }`; +} + +function getTraitInfo(trait: string, trait_db: PlantAnalyzerData['trait_db']) { + const traitData = trait_db.find((t) => t.path === trait); + return traitData; +} diff --git a/tgui/packages/tgui/interfaces/PlantAnalyzer/Tray.tsx b/tgui/packages/tgui/interfaces/PlantAnalyzer/Tray.tsx index 88dcd4f54cf..6b1c144a3b4 100644 --- a/tgui/packages/tgui/interfaces/PlantAnalyzer/Tray.tsx +++ b/tgui/packages/tgui/interfaces/PlantAnalyzer/Tray.tsx @@ -1,12 +1,13 @@ import { + Box, + Button, DmIcon, - Icon, LabeledList, + NoticeBox, ProgressBar, Section, Stack, Table, - Tooltip, } from 'tgui-core/components'; import { capitalizeFirst } from 'tgui-core/string'; @@ -14,42 +15,70 @@ import { useBackend } from '../../backend'; import { Fallback } from './Fallback'; import type { PlantAnalyzerData } from './types'; -export function PlantAnalyzerTray(props) { +export function PlantAnalyzerTrayStats(props) { const { data } = useBackend(); const { tray_data } = data; + if (!tray_data) { + // This shouldn't be rendered if tray_data is null + return null; + } + return ( -
- {!!tray_data.self_sustaining && ( - - - - )} - {!!tray_data.being_pollinated && ( - - - - )} - {tray_data.yield_mod > 1 && ( - - - - )} - - } - > +
- + + + + + + + + + + + + + +
+ {active_tab === PlantAnalyzerTabs.STATS || graft_data ? ( + <> + {graft_data && } + {tray_data && } + {seed_data && } + + ) : ( + <> + {/* grafts don't have any chems */} + {tray_data && } + {seed_data && } + {plant_data && } + + )} ); diff --git a/tgui/packages/tgui/interfaces/PlantAnalyzer/types.ts b/tgui/packages/tgui/interfaces/PlantAnalyzer/types.ts index a2dde935d69..bd4e908f706 100644 --- a/tgui/packages/tgui/interfaces/PlantAnalyzer/types.ts +++ b/tgui/packages/tgui/interfaces/PlantAnalyzer/types.ts @@ -1,36 +1,46 @@ +import type { BooleanLike } from 'tgui-core/react'; + +export enum PlantAnalyzerTabs { + STATS = 1, + CHEM = 2, +} + export type PlantAnalyzerData = { - graft_data: GraftData; - seed_data: SeedData; - tray_data: TrayData; + graft_data: GraftData | null; + seed_data: SeedData | null; + plant_data: PlantData | null; + tray_data: TrayData | null; // Static cycle_seconds: number; trait_db: TraitData[]; + active_tab: PlantAnalyzerTabs; }; type TrayData = { - being_pollinated: boolean; - icon_state: string; + being_pollinated: BooleanLike; icon: string; + icon_state: string; + is_dead: BooleanLike; light_level: number; name: string; - nutri_max: number; nutri: number; - pests_max: number; + nutri_max: number; pests: number; + pests_max: number; plant_age: number; plant_health: number; reagents: ReagentVolume[]; - self_sustaining: boolean; - toxins_max: number; + self_sustaining: BooleanLike; toxins: number; - water_max: number; + toxins_max: number; water: number; - weeds_max: number; + water_max: number; weeds: number; + weeds_max: number; yield_mod: number; }; -type SeedData = { +export type SeedData = { core_traits: string[]; distill_reagent: string; endurance: number; @@ -56,6 +66,23 @@ type SeedData = { weed_chance: number; weed_rate: number; yield: number; + unique_labels: UniqueSeedLabel[]; + unique_collapsibles: UniqueSeedCollapsible[]; +}; + +type UniqueSeedLabel = { + label: string; + data: string; +}; + +type UniqueSeedCollapsible = { + label: string; + // key is shown text, value is tooltip text + data: Record; +}; + +export type PlantData = { + reagents: ReagentVolume[]; }; type GraftData = { @@ -73,10 +100,11 @@ type GraftData = { type ReagentVolume = { name: string; - volume: string; + volume: number; + color: string; }; -type ReagentData = { +export type ReagentData = { name: string; rate: number; };