Files
Paradise/code/modules/hydroponics/biogenerator.dm

379 lines
11 KiB
Plaintext

/// The base amount of plants that can be stored before taking our matter bin into account.
#define BASE_MAX_STORABLE_PLANTS 40
/obj/machinery/biogenerator
name = "biogenerator"
desc = "Converts plants into biomass, which can be used to construct useful items."
icon = 'icons/obj/biogenerator.dmi'
icon_state = "biogen-empty"
density = TRUE
anchored = TRUE
idle_power_consumption = 40
/// Is the biogenerator curretly grinding up plants?
var/processing = FALSE
/// The container that is used to store reagents from certain products.
var/obj/item/reagent_containers/glass/container
/// The amount of biomass stored in the machine.
var/biomass = 0
/// Used to modify the cost of producing items. A higher number means cheaper costs.
var/efficiency = 0
/// Used to modify how much biomass is produced by grinding plants. A higher number means more biomass.
var/productivity = 0
/// A list of plants currently stored plants in the biogenerator.
var/list/stored_plants = list()
/// The maximum amount of plants the biogenerator can store.
var/max_storable_plants = BASE_MAX_STORABLE_PLANTS
/// A reference to the biogenerator's research, which contains designs that it can build.
var/datum/research/files
/// A list which holds all categories and items the biogenator has available. Used with the UI to save having to rebuild this every time someone opens it.
var/list/product_list = list()
/// The [/datum/design]'s categories which can be produced by this machine and can be uploaded via a disk.
var/static/list/categories = list("Food", "Botany Chemicals", "Organic Materials", "Leather and Cloth")
var/static/list/acceptable_items = typecacheof(list(
/obj/item/seeds,
/obj/item/unsorted_seeds,
/obj/item/food/grown,
/obj/item/grown,
/obj/item/food/grown/ash_flora,
/obj/item/food/honeycomb))
/obj/machinery/biogenerator/Initialize(mapload)
. = ..()
files = new(src)
component_parts = list()
component_parts += new /obj/item/circuitboard/biogenerator(null)
component_parts += new /obj/item/stock_parts/matter_bin(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
component_parts += new /obj/item/stack/sheet/glass(null)
component_parts += new /obj/item/stack/cable_coil(null, 1)
RefreshParts()
/obj/machinery/biogenerator/Destroy()
QDEL_NULL(container)
QDEL_NULL(files)
QDEL_LIST_CONTENTS(stored_plants)
return ..()
/obj/machinery/biogenerator/ex_act(severity)
container?.ex_act(severity)
..()
/obj/machinery/biogenerator/handle_atom_del(atom/A)
..()
if(A != container)
return
container = null
update_icon(UPDATE_ICON_STATE)
SStgui.update_uis(src)
/obj/machinery/biogenerator/RefreshParts()
var/effeciency_prev = efficiency
efficiency = 0
productivity = 0
max_storable_plants = BASE_MAX_STORABLE_PLANTS
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
productivity += B.rating
max_storable_plants *= B.rating
for(var/obj/item/stock_parts/manipulator/M in component_parts)
efficiency += M.rating
if(effeciency_prev != efficiency)
update_ui_product_list() // We have have a higher `efficiency` now, and need to re-calc the product costs.
/obj/machinery/biogenerator/update_icon_state()
if(panel_open)
icon_state = "biogen-empty-o"
else if(!container)
icon_state = "biogen-empty"
else if(!processing)
icon_state = "biogen-stand"
else
icon_state = "biogen-work"
/obj/machinery/biogenerator/screwdriver_act(mob/living/user, obj/item/I)
if(!default_deconstruction_screwdriver(user, "biogen-empty-o", "biogen-empty", I))
return FALSE
if(container)
container.forceMove(loc)
container = null
return TRUE
/obj/machinery/biogenerator/crowbar_act(mob/living/user, obj/item/I)
return default_deconstruction_crowbar(user, I)
/obj/machinery/biogenerator/attackby(obj/item/O, mob/user, params)
if(user.a_intent == INTENT_HARM)
return ..()
if(istype(O, /obj/item/storage/part_replacer))
return ..()
if(processing)
to_chat(user, "<span class='warning'>[src] is currently processing.</span>")
return
if(istype(O, /obj/item/reagent_containers/glass))
if(panel_open)
to_chat(user, "<span class='warning'>Close the maintenance panel first.</span>")
return
if(container)
to_chat(user, "<span class='warning'>A container is already loaded into [src].</span>")
return
if(!user.drop_item())
return
O.forceMove(src)
container = O
to_chat(user, "<span class='notice'>You add the [container] to [src].</span>")
update_icon(UPDATE_ICON_STATE)
SStgui.update_uis(src)
return TRUE
if(istype(O, /obj/item/storage/bag/plants))
if(length(stored_plants) >= max_storable_plants)
to_chat(user, "<span class='warning'>[src] can't hold any more plants!</span>")
return
var/obj/item/storage/bag/plants/PB = O
for(var/obj/item/P in PB.contents)
// No need to filter here, because plant bags should have the same list of acceptable items we do.
if(length(stored_plants) >= max_storable_plants)
break
PB.remove_from_storage(P, src)
stored_plants += P
if(length(stored_plants) < max_storable_plants)
to_chat(user, "<span class='notice'>You empty [PB] into [src].</span>")
else
to_chat(user, "<span class='notice'>You fill [src] to its capacity.</span>")
SStgui.update_uis(src)
return TRUE
if(is_type_in_typecache(O, acceptable_items))
if(length(stored_plants) >= max_storable_plants)
to_chat(user, "<span class='warning'>[src] can't hold any more plants!</span>")
return
if(!user.unEquip(O))
return
O.forceMove(src)
stored_plants += O
to_chat(user, "<span class='notice'>You put [O] in [src].</span>")
SStgui.update_uis(src)
return TRUE
if(istype(O, /obj/item/disk/design_disk))
user.visible_message("[user] begins to load [O] in [src]...",
"You begin to load a design from [O]...",
"You hear the chatter of a floppy drive.")
processing = TRUE
SStgui.update_uis(src)
var/obj/item/disk/design_disk/D = O
if(do_after(user, 1 SECONDS, target = src))
files.AddDesign2Known(D.blueprint)
processing = FALSE
update_ui_product_list(user)
return TRUE
to_chat(user, "<span class='warning'>You cannot put [src] in [name]!</span>")
/**
* Builds/Updates the `product_list` used by the UI.
*/
/obj/machinery/biogenerator/proc/update_ui_product_list(mob/user)
product_list = list()
for(var/category in categories)
product_list[category] = list()
for(var/V in files.known_designs)
var/datum/design/D = files.known_designs[V]
for(var/category in categories)
if(!(category in D.category))
continue
product_list[category][D.name] = list(
"name" = D.name,
"id" = D.id,
"cost" = D.materials[MAT_BIOMASS] / efficiency
)
update_static_data(user)
SStgui.update_uis(src)
/obj/machinery/biogenerator/attack_hand(mob/user)
if(..())
return
ui_interact(user)
/obj/machinery/biogenerator/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/biogenerator/ui_state(mob/user)
return GLOB.default_state
/obj/machinery/biogenerator/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Biogenerator", "Biogenerator")
ui.set_autoupdate(FALSE)
ui.open()
/obj/machinery/biogenerator/ui_data(mob/user)
var/list/data = list(
"processing" = processing,
"biomass" = biomass,
"has_plants" = length(stored_plants) ? TRUE : FALSE
)
if(container)
data["container"] = TRUE
data["container_curr_reagents"] = container.reagents.total_volume
data["container_max_reagents"] = container.reagents.maximum_volume
else
data["container"] = FALSE
return data
/obj/machinery/biogenerator/ui_static_data(mob/user)
return list("product_list" = product_list)
/obj/machinery/biogenerator/ui_act(action, list/params)
if(..())
return
. = TRUE
switch(action)
if("activate")
process_plants(usr)
if("detach_container")
detach_container()
if("eject_plants")
eject_plants()
if("create")
var/datum/design/D = files.known_designs[params["id"]]
if(!D)
return
var/amount = clamp(text2num(params["amount"]), 1, 10)
create_product(D, amount)
/**
* Tells the biogenerator to grind up any stored plants, and produce an appropriate amount of biomass.
*
* Argumens:
* * mob/user - the mob who activated the biogenerator
*/
/obj/machinery/biogenerator/proc/process_plants(mob/user)
if(stat & (NOPOWER | BROKEN))
return
if(processing)
to_chat(user, "<span class='warning'>[src] is currently processing!</span>")
return
processing = TRUE
SStgui.update_uis(src)
update_icon(UPDATE_ICON_STATE)
var/plants_processed = length(stored_plants)
var/new_biomass = 0
for(var/obj/plant as anything in stored_plants)
var/plant_biomass = plant.reagents?.get_reagent_amount("nutriment") + plant.reagents?.get_reagent_amount("plantmatter")
new_biomass += max(plant_biomass, 0.1)
qdel(plant)
biomass += new_biomass * 10 * productivity
stored_plants.Cut()
playsound(loc, 'sound/machines/blender.ogg', 50, TRUE)
use_power(plants_processed * 150)
addtimer(CALLBACK(src, PROC_REF(end_processing)), min(20 SECONDS, new_biomass))
/obj/machinery/biogenerator/proc/end_processing()
processing = FALSE
SStgui.update_uis(src)
update_icon(UPDATE_ICON_STATE)
/**
* Ejects the biogenerator's stored plants
*/
/obj/machinery/biogenerator/proc/eject_plants()
for(var/obj/plant as anything in stored_plants)
plant.forceMove(get_turf(src))
stored_plants.Cut()
SStgui.update_uis(src)
/**
* Check if the biogenerator has enough biomass to create the passed in design `D`, times the `mutiplier`.
*
* Arguments:
* * datum/design/D - the design we want to create
* * multiplier - how many of this design should be built
*/
/obj/machinery/biogenerator/proc/check_cost(datum/design/D, multiplier = 1)
if(!D.materials[MAT_BIOMASS] || ((D.materials[MAT_BIOMASS] / efficiency) * multiplier) > biomass)
return FALSE
return TRUE
/**
* Check if the biogenerator's `container` can hold the reagents we're trying to give it.
*
* Arguments:
* * datum/design/D - the design we want to create reagents from
* * multiplier - how many of this design should be built
*/
/obj/machinery/biogenerator/proc/check_container_volume(datum/design/D, multiplier = 1)
var/sum_reagents = 0
for(var/R in D.make_reagents)
sum_reagents += D.make_reagents[R]
sum_reagents *= multiplier
if(container.reagents.total_volume + sum_reagents > container.reagents.maximum_volume)
return FALSE
return TRUE
/**
* Create biogenerator products and subtracts the appropriate biomass cost.
*
* Arguments:
* * datum/design/D - the design we want to create, or create reagents from
* * amount - how many of this design should be built
*/
/obj/machinery/biogenerator/proc/create_product(datum/design/D, amount)
// Creating stack-based items like cloth or cardboard.
if(ispath(D.build_path, /obj/item/stack))
if(!check_cost(D, amount))
return
new D.build_path(get_turf(src), amount)
// Filling the `container` with reagents.
else if(length(D.make_reagents))
if(!check_container_volume(D, amount))
return
for(var/R in D.make_reagents)
container.reagents.add_reagent(R, D.make_reagents[R] * amount)
// Creating all other items, such as monkey cubes or nutrient bottles.
else
if(!check_cost(D, amount))
return
for(var/i in 1 to amount)
new D.build_path(get_turf(src))
biomass -= (D.materials[MAT_BIOMASS] / efficiency) * amount
SStgui.update_uis(src)
update_icon(UPDATE_ICON_STATE)
/**
* Detach the `container` from the biogenerator.
*/
/obj/machinery/biogenerator/proc/detach_container()
if(!container)
return
container.forceMove(get_turf(src))
container = null
update_icon(UPDATE_ICON_STATE)
#undef BASE_MAX_STORABLE_PLANTS