From cf4a194e86d53d57397f6de4febbea0de9c6ef57 Mon Sep 17 00:00:00 2001
From: SkyratBot <59378654+SkyratBot@users.noreply.github.com>
Date: Wed, 30 Nov 2022 01:38:41 +0100
Subject: [PATCH] [MIRROR] Biogen Refactor and Code Cleanup, Faster Biomass
Conversion and No More Biomass Cap! [MDB IGNORE] (#17828)
* Biogen Refactor and Code Cleanup, Faster Biomass Conversion and No More Biomass Cap! (#71563)
## About The Pull Request
So, I looked at the Biogenerator code and there was just, _so_ much old
and undocumented code, that I just spazzed out and started documenting
and refactoring everything. There's now a lot less usage of contents
lookups and for loops, and _almost_ everything is documented, now, too.
As for the changes, as you can see in the title, I made biomass
conversion faster. How much faster, you ask? 5 times faster with default
parts, up to 20 times faster with the best parts. It was painfully slow,
and that's not fun for anyone.
I also lifted the biomass cap. It wasn't useful, it wasn't fun, and
Melbert didn't really agree with it either. However, I enjoyed the look
of the biomass going up, so I gave it a max visual amount of 5000, so
you get to see it gradually filling up as you put your first 5000
biomass in. After that, you do you, chief. Watch the funny numbers go up
all you want.
I also improved the maths so that it wasn't just rounding stuff
constantly, and also gave a little bit more insight on how much biomass
everything would cost you, down to two decimals. If there's no decimals,
it won't show them, however.
Here's what that looks like now:
That's one screenshot per different decimal places, there's no trailing
zeros because I think we can all universally agree that those look bad
in this kind of setting.



There's now also more information displayed when you examine the biogen,
namely, how many items it has stored, and how many it can hold. I also
fixed the formatting a bit, so it looks ever so slightly cleaner.
Other than that, I just improved the code everywhere I saw it to be
fitting, there shouldn't be any single-letter variables in there
anymore, and the code should be more spaced out. Honestly, at this
point, I wrote most of this code six hours ago so I don't remember all
of it, and I'm too lazy to go through and check what I've changed again.
Diff and changelog are there for that.
## Why It's Good For The Game
So, I'll be honest, there were two big reasons that motivated me to do
this. First of all, the biomass cap. That was a little silly, anyone
that has spent more than one shift in Hydroponics knows that you usually
only put Watermelons in the biomass generator as they're usually the
thing that nets you the most biomass. Botanists will generally stock the
fridges first, and if they have a lot of excess, they'll put it in the
generator if they want, but that's rarely what was done. I've talked
with @ MrMelbert about it and he gave me the go-ahead, as can be seen
here:

The other reason was the excruciatingly slow processing speed, which
I've fixed. So we're good now. :)
## Changelog
:cl: GoldenAlpharex
refactor: Went through and refactored a lot of the old code of the
biogenerator, and made multiple improvements to its logic, which should
hopefully make it behave more consistently. Nearly all of it is now also
fully documented, so as to make it easier for anyone else that has to
sift through it in the future.
qol: The biogenerator now processes items five times faster, up to 20
times faster if properly upgraded!
qol: The biogenerator is no longer capped on biomass. Its visuals will
change up until 5000 biomass, but you're free to go as high as you'd
like with it! Sky's the limit!
fix: Fixed the logic of the biogenerator that would make it so the
amount of biomass used for recipes was wildly inconsistent. Now, there's
no more back-end rounding up, it's all on the front end when it needs to
be, so there's no loss or gain of biomass when there shouldn't be.
spellcheck: Fixed a capitalization issue with the seaweed sheets in the
biogenerator recipes.
spellcheck: Fixed multiple inconsistencies between the messages sent to
your chat by the biogenerator.
/:cl:
* Biogen Refactor and Code Cleanup, Faster Biomass Conversion and No More Biomass Cap!
Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
---
code/modules/hydroponics/biogenerator.dm | 390 ++++++++++++------
.../research/designs/biogenerator_designs.dm | 48 +--
.../packages/tgui/interfaces/Biogenerator.tsx | 14 +-
3 files changed, 298 insertions(+), 154 deletions(-)
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index bd77f0a6fbf..de834717ce2 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -1,3 +1,9 @@
+/// How many more items does `max_items` get increased by per rating point.
+#define MAX_ITEMS_PER_RATING 10
+/// How many items are converted per cycle, per rating point of the manipulator used.
+#define PROCESSED_ITEMS_PER_RATING 5
+
+
/obj/machinery/biogenerator
name = "biogenerator"
desc = "Converts plants into biomass, which can be used to construct useful items."
@@ -5,29 +11,53 @@
icon_state = "biogenerator"
density = TRUE
circuit = /obj/item/circuitboard/machine/biogenerator
+ processing_flags = START_PROCESSING_MANUALLY
+ /// Whether the biogenerator is currently processing biomass or not.
var/processing = FALSE
+ /// The reagent container that is currently inside of the biomass generator. Can be null.
var/obj/item/reagent_containers/cup/beaker = null
+ /// The amount of biomass that's currently stored in the biogenerator.
var/biomass = 0
- var/efficiency = 0
- var/productivity = 0
+ /// The amount by which the biomass consumption will be divided.
+ var/efficiency = 1
+ /// The conversion factor for nutrient to biomass, and the amount of additional items that will be processed at once per cycle.
+ var/productivity = 1
+ /// The amount of items that will be converted into biomass per processing cycle.
+ var/processed_items_per_cycle = 5
+ /// The maximum amount of items the biogenerator can hold for biomass conversion purposes.
var/max_items = 20
- var/max_biomass = 500
+ /// The current amount of items that can be converted into biomass that the biogenerator is holding.
+ var/current_item_count = 0
+ /// The maximum amount of biomass that will affect the visuals of the biogenerator.
+ var/max_visual_biomass = 5000
+ /// The maximum amount of reagents that the biogenerator can output to a container at once.
var/max_output = 50
+ /// The research that is stored within this biogenerator.
var/datum/techweb/stored_research
- var/list/show_categories = list(RND_CATEGORY_BIO_FOOD, RND_CATEGORY_BIO_CHEMICALS, RND_CATEGORY_BIO_MATERIALS)
+ /// The different visual categories for the biogenerator, for the tabs.
+ var/list/show_categories = list(
+ RND_CATEGORY_BIO_FOOD,
+ RND_CATEGORY_BIO_CHEMICALS,
+ RND_CATEGORY_BIO_MATERIALS,
+ )
+ /// The category that's currently selected in the UI.
var/selected_cat
+ /// The sound loop that can be heard when the generator is processing.
var/datum/looping_sound/generator/soundloop
+
/obj/machinery/biogenerator/Initialize(mapload)
. = ..()
stored_research = new /datum/techweb/specialized/autounlocking/biogenerator
soundloop = new(src, processing)
+
/obj/machinery/biogenerator/Destroy()
QDEL_NULL(beaker)
QDEL_NULL(soundloop)
return ..()
+
/obj/machinery/biogenerator/contents_explosion(severity, target)
. = ..()
if(!beaker)
@@ -41,214 +71,304 @@
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += beaker
-/obj/machinery/biogenerator/handle_atom_del(atom/A)
- ..()
- if(A == beaker)
+
+/obj/machinery/biogenerator/handle_atom_del(atom/deleting_atom)
+ . = ..()
+
+ if(deleting_atom == beaker)
beaker = null
update_appearance()
+
/obj/machinery/biogenerator/RefreshParts()
. = ..()
- var/E = 0
- var/P = 0
- var/I = 10
- var/V = 0
- for(var/obj/item/stock_parts/matter_bin/B in component_parts)
- I += 10 * B.rating
- V += 500 * B.rating
- for(var/obj/item/stock_parts/manipulator/M in component_parts)
- P += M.rating
- E += M.rating
- efficiency = E
- productivity = P
- max_items = I
- max_biomass = V
+
+ var/new_efficiency = 0
+ var/new_productivity = 0
+ var/new_max_items = 10
+ var/new_processed_items_per_cycle = 0
+
+ for(var/obj/item/stock_parts/matter_bin/bin in component_parts)
+ new_max_items += MAX_ITEMS_PER_RATING * bin.rating
+
+ for(var/obj/item/stock_parts/manipulator/manipulator in component_parts)
+ new_productivity += manipulator.rating
+ new_efficiency += manipulator.rating
+ new_processed_items_per_cycle += PROCESSED_ITEMS_PER_RATING * manipulator.rating
+
+ max_items = new_max_items
+ efficiency = new_efficiency
+ productivity = new_productivity
+ processed_items_per_cycle = new_processed_items_per_cycle
+
update_appearance()
+
/obj/machinery/biogenerator/examine(mob/user)
. = ..()
+
if(in_range(user, src) || isobserver(user))
- . += span_notice("The status display reads: Productivity at [productivity*100]%.
Matter consumption reduced by [(efficiency*25)-25]%.
Machine can hold up to [max_items] pieces of produce.
And up to [max_biomass] units of biomass.")
+ . += span_notice("The status display reads:")
+ . += span_notice(" - Productivity at [productivity * 100]%.")
+ . += span_notice(" - Converting [processed_items_per_cycle] pieces of food per cycle.")
+ . += span_notice(" - Matter consumption at [1 / efficiency * 100]%.")
+ . += span_notice(" - Internal biomass converter capacity at [max_items] pieces of food, and currently holding [current_item_count].")
+
/obj/machinery/biogenerator/update_appearance()
. = ..()
- var/power = machine_stat & (NOPOWER|BROKEN) ? 0 : 1 + biomass / max_biomass + (processing & 1)
+
+ var/power = machine_stat & (NOPOWER|BROKEN) ? 0 : 1 + min(biomass / max_visual_biomass, 1) + (processing & 1)
set_light(MINIMUM_USEFUL_LIGHT_RANGE, power, LIGHT_COLOR_CYAN)
+
/obj/machinery/biogenerator/update_overlays()
. = ..()
+
if(panel_open)
. += mutable_appearance(icon, "[icon_state]_o_panel")
+
if(beaker)
. += mutable_appearance(icon, "[icon_state]_o_container")
+
if(biomass > 0)
- var/biomass_level = min(ROUND_UP(7 * biomass / max_biomass), 7)
+ var/biomass_level = min(ROUND_UP(7 * biomass / max_visual_biomass), 7)
. += mutable_appearance(icon, "[icon_state]_o_biomass_[biomass_level]")
. += emissive_appearance(icon, "[icon_state]_o_biomass_[biomass_level]", src)
+
if(machine_stat & (NOPOWER|BROKEN))
return
+
if(processing)
. += mutable_appearance(icon, "[icon_state]_o_process")
. += emissive_appearance(icon, "[icon_state]_o_process", src)
+
. += mutable_appearance(icon, "[icon_state]_o_screen")
. += emissive_appearance(icon, "[icon_state]_o_screen", src)
-/obj/machinery/biogenerator/attackby(obj/item/O, mob/living/user, params)
+
+/obj/machinery/biogenerator/attackby(obj/item/attacking_item, mob/living/user, params)
if(user.combat_mode)
return ..()
- if(default_deconstruction_screwdriver(user, icon_state, icon_state, O))
+ if(default_deconstruction_screwdriver(user, icon_state, icon_state, attacking_item))
if(processing)
- processing = FALSE
- soundloop.stop()
+ stop_process(FALSE)
+
if(beaker)
- var/obj/item/reagent_containers/cup/B = beaker
- B.forceMove(drop_location())
+ beaker.forceMove(drop_location())
beaker = null
+
update_appearance(UPDATE_ICON)
return
var/turf/drop_location = drop_location()
- if(default_deconstruction_crowbar(O))
+ if(default_deconstruction_crowbar(attacking_item))
if(biomass > 0)
- drop_location.visible_message(span_warning("The biomass spills!"))
+ drop_location.visible_message(span_warning("Biomass spills from \the [src]'s biomass tank!"))
playsound(drop_location, 'sound/effects/slosh.ogg', 25, vary = TRUE)
new /obj/effect/decal/cleanable/greenglow(drop_location)
+
return
- if(istype(O, /obj/item/reagent_containers/cup))
+ if(istype(attacking_item, /obj/item/reagent_containers/cup))
if(panel_open)
to_chat(user, span_warning("Close the maintenance panel first."))
else
- insert_beaker(user, O)
+ insert_beaker(user, attacking_item)
+
return TRUE
- else if(istype(O, /obj/item/storage/bag))
- var/obj/item/storage/bag/bag = O
- var/i = 0
- for(var/obj/item/food/item in contents)
- i++
- if(i >= max_items)
- to_chat(user, span_warning("The biogenerator is already full! Activate it."))
+ else if(istype(attacking_item, /obj/item/storage/bag))
+ if(current_item_count >= max_items)
+ to_chat(user, span_warning("\The [src] is already full! Activate it to free up some space."))
+ return TRUE
+
+ var/obj/item/storage/bag/bag = attacking_item
+
+ for(var/obj/item/food/item in bag.contents)
+ if(current_item_count >= max_items)
+ break
+
+ if(bag.atom_storage.attempt_remove(item, src))
+ current_item_count++
+
+ if(bag.contents.len == 0)
+ to_chat(user, span_info("You empty \the [bag] into \the [src]."))
+
+ else if (current_item_count >= max_items)
+ to_chat(user, span_info("You fill \the [src] from \the [bag] to its capacity."))
+
else
- for(var/obj/item/food/item in bag.contents)
- if(i >= max_items)
- break
- if(bag.atom_storage.attempt_remove(item, src))
- i++
- if(bag.contents.len == 0)
- to_chat(user, span_info("You empty the bag into the biogenerator."))
- else if (i >= max_items)
- to_chat(user, span_info("You fill the biogenerator from the bag to its capacity."))
- else
- to_chat(user, span_info("You fill the biogenerator from the bag."))
+ to_chat(user, span_info("You fill \the [src] from \the [bag]."))
+
return TRUE //no afterattack
- else if(istype(O, /obj/item/food))
- var/i = 0
- for(var/obj/item/food/item in contents)
- i++
- if(i >= max_items)
- to_chat(user, span_warning("The biogenerator is full! Activate it."))
+ else if(istype(attacking_item, /obj/item/food))
+ if(current_item_count >= max_items)
+ to_chat(user, span_warning("\The [src] is full! Activate it."))
+
else
- if(user.transferItemToLoc(O, src))
- to_chat(user, span_info("You put [O.name] in [src.name]"))
+ if(user.transferItemToLoc(attacking_item, src))
+ current_item_count++
+ to_chat(user, span_info("You insert \the [attacking_item] in \the [src]"))
+
return TRUE //no afterattack
- else if (istype(O, /obj/item/disk/design_disk))
- user.visible_message(span_notice("[user] begins to load \the [O] in \the [src]..."),
- span_notice("You begin to load a design from \the [O]..."),
- span_hear("You hear the chatter of a floppy drive."))
+
+ else if (istype(attacking_item, /obj/item/disk/design_disk))
+ user.visible_message(
+ span_notice("[user] begins to load \the [attacking_item] in \the [src]..."),
+ span_notice("You begin to load a design from \the [attacking_item]..."),
+ span_hear("You hear the chatter of a floppy drive.")
+ )
processing = TRUE
- var/obj/item/disk/design_disk/D = O
- if(do_after(user, 10, target = src))
- for(var/B in D.blueprints)
- if(B)
- stored_research.add_design(B)
+ var/obj/item/disk/design_disk/design_disk = attacking_item
+
+ if(do_after(user, 1 SECONDS, target = src))
+ for(var/blueprint in design_disk.blueprints)
+ if(blueprint)
+ stored_research.add_design(blueprint)
+
processing = FALSE
return TRUE
+
else
- to_chat(user, span_warning("You cannot put this in [src.name]!"))
+ to_chat(user, span_warning("You cannot put \the [attacking_item] in \the [src]!"))
+
/obj/machinery/biogenerator/AltClick(mob/living/user)
. = ..()
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE) && can_interact(user))
eject_beaker(user)
+
/// Activates biomass processing and converts all inserted food products into biomass
/obj/machinery/biogenerator/proc/start_process()
if(machine_stat != NONE || panel_open)
return
+
if(processing)
say("Already working!")
return
- if(biomass >= max_biomass)
- say("Biomass tank is full!")
- return
+
if(!(locate(/obj/item/food) in contents))
say("No food items found!")
return
+
+ begin_processing()
processing = TRUE
soundloop.start()
update_appearance()
+
/obj/machinery/biogenerator/process(delta_time)
if(!processing)
return
+
if(machine_stat != NONE || panel_open)
stop_process()
return
- if(biomass >= max_biomass)
- say("Biomass tank is full!")
+
+ if(!current_item_count)
stop_process()
return
- var/obj/item/food/object = locate(/obj/item/food) in contents
- if(!object)
- stop_process()
- return
- var/nutriments = 0
- for(var/nutriment in typesof(/datum/reagent/consumable/nutriment))
- nutriments += object.reagents.get_reagent_amount(nutriment)
- qdel(object)
- biomass = min(biomass + max(1, nutriments) * productivity, max_biomass)
+
+ for(var/i in 1 to processed_items_per_cycle)
+ var/obj/item/food/food_to_convert = locate(/obj/item/food) in contents
+
+ if(!food_to_convert)
+ break
+
+ convert_to_biomass(food_to_convert)
+
use_power(active_power_usage * delta_time)
+
+ if(!current_item_count)
+ stop_process(FALSE)
+
update_appearance()
-/obj/machinery/biogenerator/proc/stop_process()
+
+
+/**
+ * Simple helper proc that converts the given food item into biomass for the generator,
+ * while also handling removing it and modifying the `current_item_count`.
+ *
+ * Arguments:
+ * * food_to_convert - The food item that will be converted into biomass and
+ * subsequently be deleted.
+ */
+/obj/machinery/biogenerator/proc/convert_to_biomass(obj/item/food/food_to_convert)
+ var/static/list/nutrient_subtypes = typesof(/datum/reagent/consumable/nutriment)
+ var/nutriments = 0
+
+ nutriments += ROUND_UP(food_to_convert.reagents.get_multiple_reagent_amounts(nutrient_subtypes))
+ qdel(food_to_convert)
+ current_item_count = max(current_item_count - 1, 0)
+ biomass += nutriments * productivity
+
+
+/**
+ * Simple helper to handle stopping the process of the biogenerator.
+ *
+ * Arguments:
+ * * update_appearance - Whether or not we call `update_appearance()` here.
+ * Defaults to `TRUE`.
+ */
+/obj/machinery/biogenerator/proc/stop_process(update_appearance = TRUE)
+ end_processing()
processing = FALSE
soundloop.stop()
- update_appearance()
+
+ if(update_appearance)
+ update_appearance()
+
/obj/machinery/biogenerator/proc/use_biomass(list/materials, amount = 1, remove_biomass = TRUE)
if(materials.len != 1 || materials[1] != GET_MATERIAL_REF(/datum/material/biomass))
return FALSE
- if (ROUND_UP(materials[GET_MATERIAL_REF(/datum/material/biomass)]*amount/efficiency) > biomass)
- return FALSE
- else
- if(remove_biomass)
- biomass -= ROUND_UP(materials[GET_MATERIAL_REF(/datum/material/biomass)]*amount/efficiency)
- update_appearance()
- return TRUE
-/obj/machinery/biogenerator/proc/create_product(datum/design/D, amount)
- if(D.make_reagents.len > 0)
+ var/cost = materials[GET_MATERIAL_REF(/datum/material/biomass)] * amount / efficiency
+ if (cost > biomass)
+ return FALSE
+
+
+ if(remove_biomass)
+ biomass -= cost
+
+ update_appearance()
+ return TRUE
+
+
+/obj/machinery/biogenerator/proc/create_product(datum/design/design, amount)
+ if(design.make_reagents.len > 0)
if(!beaker)
return FALSE
+
if(beaker.reagents.maximum_volume - beaker.reagents.total_volume < amount)
say("Warning: Attached container does not have enough free capacity!")
return FALSE
- if(!use_biomass(D.materials, amount))
+
+ if(!use_biomass(design.materials, amount))
return FALSE
- beaker.reagents.add_reagent(D.make_reagents[1], amount)
- if(D.build_path)
- if(!use_biomass(D.materials, amount))
+
+ beaker.reagents.add_reagent(design.make_reagents[1], amount)
+
+ if(design.build_path)
+ if(!use_biomass(design.materials, amount))
return FALSE
- if(istype(D.build_path, /obj/item/stack/sheet))
- new D.build_path(drop_location(), amount)
+
+ if(istype(design.build_path, /obj/item/stack/sheet))
+ new design.build_path(drop_location(), amount)
+
else
+ var/drop_location = drop_location()
for(var/i in 1 to amount)
- new D.build_path(drop_location())
+ new design.build_path(drop_location)
+
return TRUE
+
/*
* Insert a new beaker into the biogenerator, replacing/swapping our current beaker if there is one.
*
@@ -265,12 +385,14 @@
if(beaker)
to_chat(user, span_notice("You swap out [beaker] in [src] for [inserted_beaker]."))
eject_beaker(user, silent = TRUE)
+
else
to_chat(user, span_notice("You add [inserted_beaker] to [src]."))
beaker = inserted_beaker
update_appearance(UPDATE_ICON)
+
/*
* Eject the current stored beaker either into the user's hands or onto the ground.
*
@@ -287,77 +409,87 @@
if(user.put_in_hands(beaker))
if(!silent)
to_chat(user, span_notice("You eject [beaker] from [src]."))
+
else
if(!silent)
to_chat(user, span_notice("You eject [beaker] from [src] onto the ground."))
+
beaker.forceMove(drop_location())
beaker = null
update_appearance(UPDATE_ICON)
+
/obj/machinery/biogenerator/ui_status(mob/user)
if(machine_stat & BROKEN || panel_open)
return UI_CLOSE
+
return ..()
+
/obj/machinery/biogenerator/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet/research_designs),
)
+
/obj/machinery/biogenerator/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Biogenerator", name)
ui.open()
+
/obj/machinery/biogenerator/ui_data(mob/user)
var/list/data = list()
data["beaker"] = beaker ? TRUE : FALSE
data["biomass"] = biomass
- data["max_biomass"] = max_biomass
data["processing"] = processing
data["max_output"] = max_output
data["efficiency"] = efficiency
- if((locate(/obj/item/food) in contents) && biomass < max_biomass)
- data["can_process"] = TRUE
- else
- data["can_process"] = FALSE
+ data["can_process"] = !!current_item_count
+
if(beaker)
data["beakerCurrentVolume"] = round(beaker.reagents.total_volume, 0.01)
data["beakerMaxVolume"] = beaker.volume
data["reagent_color"] = mix_color_from_reagents(beaker.reagents.reagent_list)
+
return data
+
/obj/machinery/biogenerator/ui_static_data(mob/user)
var/list/data = list()
data["categories"] = list()
+ data["max_visual_biomass"] = max_visual_biomass
var/categories = show_categories.Copy()
- for(var/V in categories)
- categories[V] = list()
- for(var/V in stored_research.researched_designs)
- var/datum/design/D = SSresearch.techweb_design_by_id(V)
- for(var/C in categories)
- if(C in D.category)
- categories[C] += D
+ for(var/category in categories)
+ categories[category] = list()
+
+ for(var/design_id in stored_research.researched_designs)
+ var/datum/design/design = SSresearch.techweb_design_by_id(design_id)
+ for(var/category in categories)
+ if(category in design.category)
+ categories[category] += design
for(var/category in categories)
var/list/cat = list(
"name" = category,
"items" = (category == selected_cat ? list() : null))
+
for(var/item in categories[category])
- var/datum/design/D = item
+ var/datum/design/design = item
cat["items"] += list(list(
- "id" = D.id,
- "name" = D.name,
- "is_reagent" = D.make_reagents.len > 0,
- "cost" = D.materials[GET_MATERIAL_REF(/datum/material/biomass)]/efficiency,
+ "id" = design.id,
+ "name" = design.name,
+ "is_reagent" = design.make_reagents.len > 0,
+ "cost" = design.materials[GET_MATERIAL_REF(/datum/material/biomass)] / efficiency,
))
data["categories"] += list(cat)
return data
+
/obj/machinery/biogenerator/ui_act(action, list/params)
. = ..()
if(.)
@@ -367,25 +499,37 @@
if("activate")
start_process()
return TRUE
+
if("eject")
eject_beaker(usr)
return TRUE
+
if("create")
var/amount = text2num(params["amount"])
if(!amount)
return
+
var/id = params["id"]
if(!stored_research.researched_designs.Find(id))
stack_trace("ID did not map to a researched datum [id]")
return
- var/datum/design/D = SSresearch.techweb_design_by_id(id)
- amount = clamp(amount, 1, (D.make_reagents.len > 0 && beaker ? beaker.reagents.maximum_volume - beaker.reagents.total_volume : max_output))
- if(D && !istype(D, /datum/design/error_design))
- create_product(D, amount)
+
+ var/datum/design/design = SSresearch.techweb_design_by_id(id)
+ amount = clamp(amount, 1, (design.make_reagents.len > 0 && beaker ? beaker.reagents.maximum_volume - beaker.reagents.total_volume : max_output))
+
+ if(design && !istype(design, /datum/design/error_design))
+ create_product(design, amount)
+
else
stack_trace("ID could not be turned into a valid techweb design datum [id]")
return
+
return TRUE
+
if("select")
selected_cat = params["category"]
return TRUE
+
+
+#undef MAX_ITEMS_PER_RATING
+#undef PROCESSED_ITEMS_PER_RATING
diff --git a/code/modules/research/designs/biogenerator_designs.dm b/code/modules/research/designs/biogenerator_designs.dm
index a6902e32f61..6984ad751a2 100644
--- a/code/modules/research/designs/biogenerator_designs.dm
+++ b/code/modules/research/designs/biogenerator_designs.dm
@@ -6,7 +6,7 @@
name = "Milk"
id = "milk"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.4)
+ materials = list(/datum/material/biomass = 0.4)
make_reagents = list(/datum/reagent/consumable/milk = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
@@ -14,7 +14,7 @@
name = "Soy Milk"
id = "soymilk"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.4)
+ materials = list(/datum/material/biomass = 0.4)
make_reagents = list(/datum/reagent/consumable/soymilk = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
@@ -22,7 +22,7 @@
name = "Ethanol"
id = "ethanol"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.6)
+ materials = list(/datum/material/biomass = 0.6)
make_reagents = list(/datum/reagent/consumable/ethanol = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
@@ -30,7 +30,7 @@
name = "Cream"
id = "cream"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.6)
+ materials = list(/datum/material/biomass = 0.6)
make_reagents = list(/datum/reagent/consumable/cream = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
@@ -38,7 +38,7 @@
name = "Black Pepper"
id = "black_pepper"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.6)
+ materials = list(/datum/material/biomass = 0.6)
make_reagents = list(/datum/reagent/consumable/blackpepper = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
@@ -46,7 +46,7 @@
name = "Universal Enzyme"
id = "enzyme"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.6)
+ materials = list(/datum/material/biomass = 0.6)
make_reagents = list(/datum/reagent/consumable/enzyme = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
@@ -54,7 +54,7 @@
name = "Flour"
id = "flour_sack"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.6)
+ materials = list(/datum/material/biomass = 0.6)
make_reagents = list(/datum/reagent/consumable/flour = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
@@ -62,7 +62,7 @@
name = "Sugar"
id = "sugar"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.6)
+ materials = list(/datum/material/biomass = 0.6)
make_reagents = list(/datum/reagent/consumable/sugar = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
@@ -70,15 +70,15 @@
name = "Monkey Cube"
id = "mcube"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 50)
+ materials = list(/datum/material/biomass = 50)
build_path = /obj/item/food/monkeycube
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
/datum/design/seaweed_sheet
- name = "Seaweed sheet"
+ name = "Seaweed Sheet"
id = "seaweedsheet"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 3)
+ materials = list(/datum/material/biomass = 3)
build_path = /obj/item/food/seaweedsheet
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_FOOD)
@@ -86,7 +86,7 @@
name = "E-Z Nutrient"
id = "ez_nut"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.1)
+ materials = list(/datum/material/biomass = 0.1)
make_reagents = list(/datum/reagent/plantnutriment/eznutriment = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_CHEMICALS)
@@ -94,7 +94,7 @@
name = "Left 4 Zed"
id = "l4z_nut"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.1)
+ materials = list(/datum/material/biomass = 0.1)
make_reagents = list(/datum/reagent/plantnutriment/left4zednutriment = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_CHEMICALS)
@@ -102,7 +102,7 @@
name = "Robust Harvest"
id = "rh_nut"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.2)
+ materials = list(/datum/material/biomass = 0.2)
make_reagents = list(/datum/reagent/plantnutriment/robustharvestnutriment = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_CHEMICALS)
@@ -110,7 +110,7 @@
name = "Enduro Grow"
id = "end_gro"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.3)
+ materials = list(/datum/material/biomass = 0.3)
make_reagents = list(/datum/reagent/plantnutriment/endurogrow = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_CHEMICALS)
@@ -118,7 +118,7 @@
name = "Liquid Earthquake"
id = "liq_earth"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.3)
+ materials = list(/datum/material/biomass = 0.3)
make_reagents = list(/datum/reagent/plantnutriment/liquidearthquake = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_CHEMICALS)
@@ -126,7 +126,7 @@
name = "Weed Killer"
id = "weed_killer"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.2)
+ materials = list(/datum/material/biomass = 0.2)
make_reagents = list(/datum/reagent/toxin/plantbgone/weedkiller = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_CHEMICALS)
@@ -134,7 +134,7 @@
name = "Pest Killer"
id = "pest_spray"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.4)
+ materials = list(/datum/material/biomass = 0.4)
make_reagents = list(/datum/reagent/toxin/pestkiller = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_CHEMICALS)
@@ -142,7 +142,7 @@
name = "Organic Pest Killer"
id = "org_pest_spray"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 0.6)
+ materials = list(/datum/material/biomass = 0.6)
make_reagents = list(/datum/reagent/toxin/pestkiller/organic = 1)
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_CHEMICALS)
@@ -150,7 +150,7 @@
name = "Sheet of Leather"
id = "leather"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 30)
+ materials = list(/datum/material/biomass = 30)
build_path = /obj/item/stack/sheet/leather
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_MATERIALS)
@@ -158,7 +158,7 @@
name = "Sheet of Cloth"
id = "cloth"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 10)
+ materials = list(/datum/material/biomass = 10)
build_path = /obj/item/stack/sheet/cloth
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_MATERIALS)
@@ -166,7 +166,7 @@
name = "Sheet of Cardboard"
id = "cardboard"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 5)
+ materials = list(/datum/material/biomass = 5)
build_path = /obj/item/stack/sheet/cardboard
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_MATERIALS)
@@ -174,7 +174,7 @@
name = "Sheet of Paper"
id = "paper"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 2)
+ materials = list(/datum/material/biomass = 2)
build_path = /obj/item/paper
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_MATERIALS)
@@ -182,6 +182,6 @@
name = "Sheet of Rolling Paper"
id = "rollingpaper"
build_type = BIOGENERATOR
- materials = list(/datum/material/biomass= 1)
+ materials = list(/datum/material/biomass = 1)
build_path = /obj/item/rollingpaper
category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_BIO_MATERIALS)
diff --git a/tgui/packages/tgui/interfaces/Biogenerator.tsx b/tgui/packages/tgui/interfaces/Biogenerator.tsx
index 168dc1c9ad7..02317560937 100644
--- a/tgui/packages/tgui/interfaces/Biogenerator.tsx
+++ b/tgui/packages/tgui/interfaces/Biogenerator.tsx
@@ -9,7 +9,7 @@ type BiogeneratorData = {
beaker: BooleanLike;
reagent_color: string;
biomass: number;
- max_biomass: number;
+ max_visual_biomass: number;
can_process: BooleanLike;
beakerCurrentVolume: number;
beakerMaxVolume: number;
@@ -39,7 +39,7 @@ export const Biogenerator = (props, context) => {
beaker,
reagent_color,
biomass,
- max_biomass,
+ max_visual_biomass,
can_process,
beakerCurrentVolume,
beakerMaxVolume,
@@ -79,14 +79,14 @@ export const Biogenerator = (props, context) => {
- {`${biomass} of ${max_biomass} units`}
+ {`${parseFloat(biomass.toFixed(2))} units`}
@@ -214,9 +214,9 @@ const ItemList = (props, context) => {
fluid
align="right"
content={
- Math.ceil((item.cost * item.amount) / props.efficiency) +
- ' ' +
- 'BIO'
+ parseFloat(
+ ((item.cost * item.amount) / props.efficiency).toFixed(2)
+ ) + ' BIO'
}
disabled={item.disabled}
onClick={() =>