TGUI Limbgrower + Limbgrower refactoring and design expansion (#57955)

Refactors the limbgrower to modernize the code. Now, the limbgrower can accept any type of reagent in limbgrower designs.

Adds simple plumbing demand to the limbgrower, so you can pipe synthflesh into it.

Adds monkey tails, felinid ears and tails, lizard digitigrade legs, lizard tongues, fake lizard tails (unusable in lizard-wine and similar recipes), plasmaman organs, and ethereal organs (minus the heart) to the limbgrower via limbgrower design disks. These disks can be printed from the medical lathe once the required technology has been researched.

Adds a technology node to unlock the limbgrower design disks after advanced biotech, xenoorgan biology. In the future, this could have an experiment requirement - maybe to scan multiple types of species.

Co-authored-by: Aleksej Komarov <stylemistake@gmail.com>
This commit is contained in:
MrMelbert
2021-04-02 11:01:40 +03:00
committed by GitHub
co-authored by Aleksej Komarov
parent 8c1d6118e5
commit b46b586d7b
7 changed files with 490 additions and 161 deletions
@@ -138,6 +138,7 @@
result = /obj/item/tailclub
reqs = list(/obj/item/organ/tail/lizard = 1,
/obj/item/stack/sheet/iron = 1)
blacklist = list(/obj/item/organ/tail/lizard/fake)
time = 40
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
@@ -147,6 +148,7 @@
result = /obj/item/melee/chainofcommand/tailwhip
reqs = list(/obj/item/organ/tail/lizard = 1,
/obj/item/stack/cable_coil = 1)
blacklist = list(/obj/item/organ/tail/lizard/fake)
time = 40
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
+194 -154
View File
@@ -1,9 +1,5 @@
#define LIMBGROWER_MAIN_MENU 1
#define LIMBGROWER_CATEGORY_MENU 2
#define LIMBGROWER_CHEMICAL_MENU 3
//use these for the menu system
/// The limbgrower. Makes organd and limbs with synthflesh and chems.
/// See [limbgrower_designs.dm] for everything we can make.
/obj/machinery/limbgrower
name = "limb grower"
desc = "It grows new limbs using Synthflesh."
@@ -15,135 +11,222 @@
active_power_usage = 100
circuit = /obj/item/circuitboard/machine/limbgrower
var/operating = FALSE
var/disabled = FALSE
/// The category of limbs we're browing in our UI.
var/selected_category = "human"
/// If we're currently printing something.
var/busy = FALSE
var/prod_coeff = 1
/// How efficient our machine is. Better parts = less chemicals used and less power used. Range of 1 to 0.25.
var/production_coefficient = 1
/// How long it takes for us to print a limb. Affected by production_coefficient.
var/production_speed = 3 SECONDS
/// The design we're printing currently.
var/datum/design/being_built
/// Our internal techweb for limbgrower designs.
var/datum/techweb/stored_research
var/selected_category
var/screen = 1
var/list/categories = list(
"human",
"lizard",
"moth",
"plasmaman",
"ethereal",
"other"
)
/// All the categories of organs we can print.
var/list/categories = list("human", "lizard", "moth", "plasmaman", "ethereal", "other")
/obj/machinery/limbgrower/Initialize()
create_reagents(100, OPENCONTAINER)
stored_research = new /datum/techweb/specialized/autounlocking/limbgrower
. = ..()
AddComponent(/datum/component/plumbing/simple_demand)
/obj/machinery/limbgrower/ui_interact(mob/user)
/obj/machinery/limbgrower/ui_interact(mob/user, datum/tgui/ui)
. = ..()
if(!is_operational)
return
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Limbgrower")
ui.open()
var/dat = main_win(user)
/obj/machinery/limbgrower/ui_state(mob/user)
return GLOB.physical_state
switch(screen)
if(LIMBGROWER_MAIN_MENU)
dat = main_win(user)
if(LIMBGROWER_CATEGORY_MENU)
dat = category_win(user,selected_category)
if(LIMBGROWER_CHEMICAL_MENU)
dat = chemical_win(user)
/obj/machinery/limbgrower/ui_data(mob/user)
var/list/data = list()
var/datum/browser/popup = new(user, "Limb Grower", name, 400, 500)
popup.set_content(dat)
popup.open()
for(var/datum/reagent/reagent_id in reagents.reagent_list)
var/list/reagent_data = list(
reagent_name = reagent_id.name,
reagent_amount = reagent_id.volume,
reagent_type = reagent_id.type
)
data["reagents"] += list(reagent_data)
data["total_reagents"] = reagents.total_volume
data["max_reagents"] = reagents.maximum_volume
data["busy"] = busy
return data
/obj/machinery/limbgrower/ui_static_data(mob/user)
var/list/data = list()
data["categories"] = list()
var/species_categories = categories.Copy()
for(var/species in species_categories)
species_categories[species] = list()
for(var/design_id in stored_research.researched_designs)
var/datum/design/limb_design = SSresearch.techweb_design_by_id(design_id)
for(var/found_category in species_categories)
if(found_category in limb_design.category)
species_categories[found_category] += limb_design
for(var/category in species_categories)
var/list/category_data = list(
name = category,
designs = list(),
)
for(var/datum/design/found_design in species_categories[category])
var/list/all_reagents = list()
for(var/reagent_typepath in found_design.reagents_list)
var/datum/reagent/reagent_id = find_reagent_object_from_type(reagent_typepath)
var/list/reagent_data = list(
name = reagent_id.name,
amount = (found_design.reagents_list[reagent_typepath] * production_coefficient),
)
all_reagents += list(reagent_data)
category_data["designs"] += list(list(
parent_category = category,
name = found_design.name,
id = found_design.id,
needed_reagents = all_reagents,
))
data["categories"] += list(category_data)
return data
/obj/machinery/limbgrower/on_deconstruction()
for(var/obj/item/reagent_containers/glass/G in component_parts)
reagents.trans_to(G, G.reagents.maximum_volume)
for(var/obj/item/reagent_containers/glass/our_beaker in component_parts)
reagents.trans_to(our_beaker, our_beaker.reagents.maximum_volume)
..()
/obj/machinery/limbgrower/attackby(obj/item/O, mob/living/user, params)
/obj/machinery/limbgrower/attackby(obj/item/user_item, mob/living/user, params)
if (busy)
to_chat(user, "<span class=\"alert\">The Limb Grower is busy. Please wait for completion of previous operation.</span>")
return
if(default_deconstruction_screwdriver(user, "limbgrower_panelopen", "limbgrower_idleoff", O))
updateUsrDialog()
if(istype(user_item, /obj/item/disk/design_disk/limbs))
user.visible_message("<span class='notice'>[user] begins to load \the [user_item] in \the [src]...</span>",
"<span class='notice'>You begin to load designs from \the [user_item]...</span>",
"<span class='hear'>You hear the clatter of a floppy drive.</span>")
busy = TRUE
var/obj/item/disk/design_disk/limbs/limb_design_disk = user_item
if(do_after(user, 2 SECONDS, target = src))
for(var/datum/design/found_design in limb_design_disk.blueprints)
stored_research.add_design(found_design)
update_static_data(user)
busy = FALSE
return
if(panel_open && default_deconstruction_crowbar(O))
if(default_deconstruction_screwdriver(user, "limbgrower_panelopen", "limbgrower_idleoff", user_item))
ui_close(user)
return
if(panel_open && default_deconstruction_crowbar(user_item))
return
if(user.combat_mode) //so we can hit the machine
return ..()
/obj/machinery/limbgrower/Topic(href, href_list)
if(..())
/obj/machinery/limbgrower/ui_act(action, list/params)
. = ..()
if(.)
return
if (!busy)
if(href_list["menu"])
screen = text2num(href_list["menu"])
if(href_list["category"] in categories) //Don't let people send invalid categories, selected_category is displayed to anyone who looks at the machine in several places
selected_category = href_list["category"]
if (busy)
to_chat(usr, "<span class='danger'>The limb grower is busy. Please wait for completion of previous operation.</span>")
return
if(href_list["disposeI"]) //Get rid of a reagent incase you add the wrong one by mistake
reagents.del_reagent(text2path(href_list["disposeI"]))
switch(action)
if(href_list["make"])
if("empty_reagent")
reagents.del_reagent(text2path(params["reagent_type"]))
. = TRUE
/////////////////
//href protection
being_built = stored_research.isDesignResearchedID(href_list["make"]) //check if it's a valid design
if("make_limb")
being_built = stored_research.isDesignResearchedID(params["design_id"])
if(!being_built)
return
CRASH("[src] was passed an invalid design id!")
/// All the reagents we're using to make our organ.
var/list/consumed_reagents_list = being_built.reagents_list.Copy()
/// The amount of power we're going to use, based on how much reagent we use.
var/power = 0
var/synth_cost = being_built.reagents_list[/datum/reagent/medicine/c2/synthflesh]*prod_coeff
var/power = max(2000, synth_cost/5)
for(var/reagent_id in consumed_reagents_list)
consumed_reagents_list[reagent_id] *= production_coefficient
if(!reagents.has_reagent(reagent_id, consumed_reagents_list[reagent_id]))
audible_message("<span class='notice'>The [src] buzzes.</span>")
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
return
if(reagents.has_reagent(/datum/reagent/medicine/c2/synthflesh, being_built.reagents_list[/datum/reagent/medicine/c2/synthflesh]*prod_coeff))
busy = TRUE
use_power(power)
flick("limbgrower_fill",src)
icon_state = "limbgrower_idleon"
addtimer(CALLBACK(src, .proc/build_item),32*prod_coeff)
power = max(2000, (power + consumed_reagents_list[reagent_id]))
else
to_chat(usr, "<span class=\"alert\">The limb grower is busy. Please wait for completion of previous operation.</span>")
busy = TRUE
use_power(power)
flick("limbgrower_fill",src)
icon_state = "limbgrower_idleon"
selected_category = params["active_tab"]
addtimer(CALLBACK(src, .proc/build_item, consumed_reagents_list), production_speed * production_coefficient)
. = TRUE
updateUsrDialog()
return
/obj/machinery/limbgrower/proc/build_item()
if(reagents.has_reagent(/datum/reagent/medicine/c2/synthflesh, being_built.reagents_list[/datum/reagent/medicine/c2/synthflesh]*prod_coeff)) //sanity check, if this happens we are in big trouble
reagents.remove_reagent(/datum/reagent/medicine/c2/synthflesh,being_built.reagents_list[/datum/reagent/medicine/c2/synthflesh]*prod_coeff)
var/buildpath = being_built.build_path
if(ispath(buildpath, /obj/item/bodypart)) //This feels like spatgheti code, but i need to initilise a limb somehow
build_limb(buildpath)
else
//Just build whatever it is
new buildpath(loc)
else
src.visible_message("<span class='warning'>Something went very wrong, there isn't enough synthflesh anymore!</span>")
busy = FALSE
flick("limbgrower_unfill",src)
icon_state = "limbgrower_idleoff"
updateUsrDialog()
/*
* The process of beginning to build a limb or organ.
* Goes through and sanity checks that we actually have enough reagent to build our item.
* Then, remove those reagents from our reagents datum.
*
* After the reagents are handled, we can proceede with making the limb or organ. (Limbs are handled in a separate proc)
*
* modified_consumed_reagents_list - the list of reagents we will consume on build, modified by the production coefficient.
*/
/obj/machinery/limbgrower/proc/build_item(list/modified_consumed_reagents_list)
for(var/reagent_id in modified_consumed_reagents_list)
if(!reagents.has_reagent(reagent_id, modified_consumed_reagents_list[reagent_id]))
audible_message("<span class='notice'>The [src] buzzes.</span>")
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
break
reagents.remove_reagent(reagent_id, modified_consumed_reagents_list[reagent_id])
var/built_typepath = being_built.build_path
// If we have a bodypart, we need to initialize the limb on its own. Otherwise we can build it here.
if(ispath(built_typepath, /obj/item/bodypart))
build_limb(built_typepath)
else
new built_typepath(loc)
busy = FALSE
flick("limbgrower_unfill", src)
icon_state = "limbgrower_idleoff"
/*
* The process of putting together a limb.
* This is called from after we remove the reagents, so this proc is just initializing the limb type.
*
* This proc handles skin / mutant color, greyscaling, names and descriptions, and various other limb creation steps.
*
* buildpath - the path of the bodypart we're building.
*/
/obj/machinery/limbgrower/proc/build_limb(buildpath)
//i need to create a body part manually using a set icon (otherwise it doesnt appear)
var/obj/item/bodypart/limb
limb = new buildpath(loc)
if(selected_category=="human" || selected_category=="lizard" || selected_category=="ethereal") //Species with greyscale parts should be included here
if(selected_category=="human") //humans don't use the full colour spectrum, they use random_skin_tone
/// The limb we're making with our buildpath, so we can edit it.
var/obj/item/bodypart/limb = new buildpath(loc)
/// Species with greyscale limbs.
var/list/greyscale_species = list("human", "lizard", "ethereal")
if(selected_category in greyscale_species) //Species with greyscale parts should be included here
if(selected_category == "human") //humans don't use the full colour spectrum, they use random_skin_tone
limb.skin_tone = random_skin_tone()
else
limb.species_color = random_short_color()
limb.icon = 'icons/mob/human_parts_greyscale.dmi'
limb.should_draw_greyscale = TRUE
else
limb.icon = 'icons/mob/human_parts.dmi'
// Set this limb up using the species name and body zone
limb.icon_state = "[selected_category]_[limb.body_zone]"
limb.name = "\improper biosynthetic [selected_category] [parse_zone(limb.body_zone)]"
@@ -154,83 +237,40 @@
/obj/machinery/limbgrower/RefreshParts()
reagents.maximum_volume = 0
for(var/obj/item/reagent_containers/glass/G in component_parts)
reagents.maximum_volume += G.volume
G.reagents.trans_to(src, G.reagents.total_volume)
var/T=1.2
for(var/obj/item/stock_parts/manipulator/M in component_parts)
T -= M.rating*0.2
prod_coeff = min(1,max(0,T)) // Coeff going 1 -> 0,8 -> 0,6 -> 0,4
for(var/obj/item/reagent_containers/glass/our_beaker in component_parts)
reagents.maximum_volume += our_beaker.volume
our_beaker.reagents.trans_to(src, our_beaker.reagents.total_volume)
production_coefficient = 1.25
for(var/obj/item/stock_parts/manipulator/our_manipulator in component_parts)
production_coefficient -= our_manipulator.rating * 0.25
production_coefficient = clamp(production_coefficient, 0, 1) // coefficient goes from 1 -> 0.75 -> 0.5 -> 0.25
/obj/machinery/limbgrower/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
. += "<span class='notice'>The status display reads: Storing up to <b>[reagents.maximum_volume]u</b> of synthflesh.<br>Synthflesh consumption at <b>[prod_coeff*100]%</b>.</span>"
. += "<span class='notice'>The status display reads: Storing up to <b>[reagents.maximum_volume]u</b> of reagents.<br>Reagent consumption rate at <b>[production_coefficient * 100]%</b>.</span>"
/obj/machinery/limbgrower/proc/main_win(mob/user)
var/dat = "<div class='statusDisplay'><h3>Limb Grower Menu:</h3><br>"
dat += "<A href='?src=[REF(src)];menu=[LIMBGROWER_CHEMICAL_MENU]'>Chemical Storage</A>"
dat += materials_printout()
dat += "<table style='width:100%' align='center'><tr>"
for(var/C in categories)
dat += "<td><A href='?src=[REF(src)];category=[C];menu=[LIMBGROWER_CATEGORY_MENU]'>[C]</A></td>"
dat += "</tr><tr>"
//one category per line
dat += "</tr></table></div>"
return dat
/obj/machinery/limbgrower/proc/category_win(mob/user,selected_category)
var/dat = "<A href='?src=[REF(src)];menu=[LIMBGROWER_MAIN_MENU]'>Return to main menu</A>"
dat += "<div class='statusDisplay'><h3>Browsing [selected_category]:</h3><br>"
dat += materials_printout()
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(selected_category in D.category))
continue
if(disabled || !can_build(D))
dat += "<span class='linkOff'>[D.name]</span>"
else
dat += "<a href='?src=[REF(src)];make=[D.id];multiplier=1'>[D.name]</a>"
dat += "[get_design_cost(D)]<br>"
dat += "</div>"
return dat
/obj/machinery/limbgrower/proc/chemical_win(mob/user)
var/dat = "<A href='?src=[REF(src)];menu=[LIMBGROWER_MAIN_MENU]'>Return to main menu</A>"
dat += "<div class='statusDisplay'><h3>Browsing Chemical Storage:</h3><br>"
dat += materials_printout()
for(var/datum/reagent/R in reagents.reagent_list)
dat += "[R.name]: [R.volume]"
dat += "<A href='?src=[REF(src)];disposeI=[R]'>Purge</A><BR>"
dat += "</div>"
return dat
/obj/machinery/limbgrower/proc/materials_printout()
var/dat = "<b>Total amount:></b> [reagents.total_volume] / [reagents.maximum_volume] cm<sup>3</sup><br>"
return dat
/obj/machinery/limbgrower/proc/can_build(datum/design/D)
return (reagents.has_reagent(/datum/reagent/medicine/c2/synthflesh, D.reagents_list[/datum/reagent/medicine/c2/synthflesh]*prod_coeff)) //Return whether the machine has enough synthflesh to produce the design
/obj/machinery/limbgrower/proc/get_design_cost(datum/design/D)
var/dat
if(D.reagents_list[/datum/reagent/medicine/c2/synthflesh])
dat += "[D.reagents_list[/datum/reagent/medicine/c2/synthflesh] * prod_coeff] SynthFlesh"
return dat
/*
* Checks our reagent list to see if a design can be built.
*
* limb_design - the design we're checking for buildability.
*
* returns TRUE if we have enough reagent to build it. Returns FALSE if we do not.
*/
/obj/machinery/limbgrower/proc/can_build(datum/design/limb_design)
for(var/datum/reagent/reagent_id in limb_design.reagents_list)
if(!reagents.has_reagent(reagent_id, limb_design.reagents_list[reagent_id] * production_coefficient))
return FALSE
return TRUE
/// Emagging a limbgrower allows you to build synthetic armblades.
/obj/machinery/limbgrower/emag_act(mob/user)
if(obj_flags & EMAGGED)
return
for(var/id in SSresearch.techweb_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(id)
if((D.build_type & LIMBGROWER) && ("emagged" in D.category))
stored_research.add_design(D)
for(var/design_id in SSresearch.techweb_designs)
var/datum/design/found_design = SSresearch.techweb_design_by_id(design_id)
if((found_design.build_type & LIMBGROWER) && ("emagged" in found_design.category))
stored_research.add_design(found_design)
to_chat(user, "<span class='warning'>A warning flashes onto the screen, stating that safety overrides have been deactivated!</span>")
obj_flags |= EMAGGED
update_static_data(user)
@@ -10,6 +10,7 @@
/obj/item/organ/tail/lizard = 1,
/datum/reagent/consumable/ethanol = 100
)
blacklist = list(/obj/item/organ/tail/lizard/fake)
result = /obj/item/reagent_containers/food/drinks/bottle/lizardwine
category = CAT_DRINK
@@ -34,6 +34,22 @@
build_path = /obj/item/bodypart/r_leg
category = list("initial","human","lizard","moth","plasmaman","ethereal")
/datum/design/digi_leftleg
name = "Digitigrade Left Leg"
id = "digi_leftleg"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 30)
build_path = /obj/item/bodypart/l_leg/digitigrade
category = list("lizard")
/datum/design/digi_rightleg
name = "Digitigrade Right Leg"
id = "digi_rightleg"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 30)
build_path = /obj/item/bodypart/r_leg/digitigrade
category = list("lizard")
//Non-limb limb designs
/datum/design/heart
@@ -42,7 +58,7 @@
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 30)
build_path = /obj/item/organ/heart
category = list("other","initial")
category = list("human","initial")
/datum/design/lungs
name = "Lungs"
@@ -50,7 +66,7 @@
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
build_path = /obj/item/organ/lungs
category = list("other","initial")
category = list("human","initial")
/datum/design/liver
name = "Liver"
@@ -58,7 +74,7 @@
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
build_path = /obj/item/organ/liver
category = list("other","initial")
category = list("human","initial")
/datum/design/stomach
name = "Stomach"
@@ -66,7 +82,7 @@
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 15)
build_path = /obj/item/organ/stomach
category = list("other","initial")
category = list("human","initial")
/datum/design/appendix
name = "Appendix"
@@ -74,7 +90,7 @@
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 5) //why would you need this
build_path = /obj/item/organ/appendix
category = list("other","initial")
category = list("human","initial")
/datum/design/eyes
name = "Eyes"
@@ -82,7 +98,7 @@
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
build_path = /obj/item/organ/eyes
category = list("other","initial")
category = list("human","initial")
/datum/design/ears
name = "Ears"
@@ -90,7 +106,7 @@
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
build_path = /obj/item/organ/ears
category = list("other","initial")
category = list("human","initial")
/datum/design/tongue
name = "Tongue"
@@ -98,8 +114,106 @@
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
build_path = /obj/item/organ/tongue
category = list("human","initial")
// Grows a fake lizard tail - not usable in lizard wine and other similar recipes.
/datum/design/lizard_tail
name = "Lizard Tail"
id = "liztail"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
build_path = /obj/item/organ/tail/lizard/fake
category = list("lizard")
/datum/design/lizard_tongue
name = "Forked Tongue"
id = "liztongue"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
build_path = /obj/item/organ/tongue/lizard
category = list("lizard")
/datum/design/monkey_tail
name = "Monkey Tail"
id = "monkeytail"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
build_path = /obj/item/organ/tail/monkey
category = list("other","initial")
/datum/design/cat_tail
name = "Cat Tail"
id = "cattail"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
build_path = /obj/item/organ/tail/cat
category = list("human")
/datum/design/cat_ears
name = "Cat Ears"
id = "catears"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
build_path = /obj/item/organ/ears/cat
category = list("human")
/datum/design/plasmaman_lungs
name = "Plasma Filter"
id = "plasmamanlungs"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/toxin/plasma = 20)
build_path = /obj/item/organ/lungs/plasmaman
category = list("plasmaman")
/datum/design/plasmaman_tongue
name = "Plasma Bone Tongue"
id = "plasmamantongue"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/toxin/plasma = 20)
build_path = /obj/item/organ/tongue/bone/plasmaman
category = list("plasmaman")
/datum/design/plasmaman_liver
name = "Reagent Processing Crystal"
id = "plasmamanliver"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/toxin/plasma = 20)
build_path = /obj/item/organ/liver/plasmaman
category = list("plasmaman")
/datum/design/plasmaman_stomach
name = "Digestive Crystal"
id = "plasmamanstomach"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/toxin/plasma = 20)
build_path = /obj/item/organ/stomach/bone/plasmaman
category = list("plasmaman")
/datum/design/ethereal_stomach
name = "Biological Battery"
id = "etherealstomach"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/consumable/liquidelectricity = 20)
build_path = /obj/item/organ/stomach/ethereal
category = list("ethereal")
/datum/design/ethereal_tongue
name = "Electrical Discharger"
id = "etherealtongue"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/consumable/liquidelectricity = 20)
build_path = /obj/item/organ/tongue/ethereal
category = list("ethereal")
// Intentionally not growable by normal means - for balance conerns.
/datum/design/ethereal_heart
name = "Crystal Core"
id = "etherealheart"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/consumable/liquidelectricity = 20)
build_path = /obj/item/organ/heart/ethereal
category = list("ethereal")
/datum/design/armblade
name = "Arm Blade"
id = "armblade"
@@ -107,3 +221,68 @@
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 75)
build_path = /obj/item/melee/synthetic_arm_blade
category = list("other","emagged")
/// Design disks and designs - for adding limbs and organs to the limbgrower.
/obj/item/disk/design_disk/limbs
name = "Limb Design Disk"
desc = "A disk containing limb and organ designs for a limbgrower."
icon_state = "datadisk1"
/// List of all limb designs this disk contains.
var/list/limb_designs = list()
/obj/item/disk/design_disk/limbs/Initialize()
. = ..()
max_blueprints = limb_designs.len
for(var/design in limb_designs)
var/datum/design/new_design = design
blueprints += new new_design
/datum/design/limb_disk
name = "Limb Design Disk"
desc = "Contains designs for various limbs."
id = "limbdesign_parent"
build_type = PROTOLATHE
materials = list(/datum/material/iron = 300, /datum/material/glass = 100)
build_path = /obj/item/disk/design_disk/limbs
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/obj/item/disk/design_disk/limbs/felinid
name = "Felinid Limb Design Disk"
limb_designs = list(/datum/design/cat_tail, /datum/design/cat_ears)
/datum/design/limb_disk/felinid
name = "Felinid Limb Design Disk"
desc = "Contains designs for felinid bodyparts for the limbgrower - Felinid ears and tail."
id = "limbdesign_felinid"
build_path = /obj/item/disk/design_disk/limbs/felinid
/obj/item/disk/design_disk/limbs/lizard
name = "Lizard Limb Design Disk"
limb_designs = list(/datum/design/lizard_tail, /datum/design/lizard_tongue, /datum/design/digi_leftleg, /datum/design/digi_rightleg)
/datum/design/limb_disk/lizard
name = "Lizard Limb Design Disk"
desc = "Contains designs for lizard bodyparts for the limbgrower - Lizard tongue, tail, and digitigrade legs."
id = "limbdesign_lizard"
build_path = /obj/item/disk/design_disk/limbs/lizard
/obj/item/disk/design_disk/limbs/plasmaman
name = "Plasmaman Limb Design Disk"
limb_designs = list(/datum/design/plasmaman_stomach, /datum/design/plasmaman_liver, /datum/design/plasmaman_lungs, /datum/design/plasmaman_tongue)
/datum/design/limb_disk/plasmaman
name = "Plasmaman Limb Design Disk"
desc = "Contains designs for plasmaman organs for the limbgrower - Plasmaman tongue, liver, stomach, and lungs."
id = "limbdesign_plasmaman"
build_path = /obj/item/disk/design_disk/limbs/plasmaman
/obj/item/disk/design_disk/limbs/ethereal
name = "Ethereal Limb Design Disk"
limb_designs = list(/datum/design/ethereal_stomach, /datum/design/ethereal_tongue)
/datum/design/limb_disk/ethereal
name = "Ethereal Limb Design Disk"
desc = "Contains designs for ethereal organs for the limbgrower - Ethereal tongue and stomach."
id = "limbdesign_ethereal"
build_path = /obj/item/disk/design_disk/limbs/ethereal
@@ -82,6 +82,15 @@
required_experiments = list(/datum/experiment/scanning/points/slime/easy)
discount_experiments = list(/datum/experiment/scanning/random/material/meat = 4000) //Big discount to reinforce doing it.
/datum/techweb_node/xenoorgan_biotech
id = "xenoorgan_bio"
display_name = "Xeno-organ Biology"
description = "Plasmaman, Ethereals, Lizardpeople... What makes our non-human crewmembers tick?"
prereq_ids = list("adv_biotech")
design_ids = list("limbdesign_felinid", "limbdesign_lizard", "limbdesign_plasmaman", "limbdesign_ethereal")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 6500)
discount_experiments = list(/datum/experiment/scanning/random/cytology/easy = 1000, /datum/experiment/scanning/points/slime/expert = 5000)
/datum/techweb_node/bio_process
id = "bio_process"
display_name = "Biological Processing"
+4
View File
@@ -81,6 +81,10 @@
new_tail.tail_type = tail_type
new_tail.spines = spines
/obj/item/organ/tail/lizard/fake
name = "fabricated lizard tail"
desc = "A fabricated severed lizard tail. This one's made of synthflesh. Probably not usable for lizard wine."
/obj/item/organ/tail/monkey
name = "monkey tail"
desc = "A severed monkey tail. Does not look like a banana."
@@ -0,0 +1,94 @@
import { useBackend, useSharedState } from '../backend';
import { Box, Button, Dimmer, Icon, LabeledList, Section, Tabs } from '../components';
import { Window } from '../layouts';
export const Limbgrower = (props, context) => {
const { act, data } = useBackend(context);
const {
reagents = [],
total_reagents,
max_reagents,
categories = [],
busy,
} = data;
const [tab, setTab] = useSharedState(
context, 'category', categories[0]?.name);
const designList = categories
.find(category => category.name === tab)
?.designs;
return (
<Window
title="Limb Grower"
width={400}
height={550}>
{!!busy && (
<Dimmer fontSize="32px">
<Icon name="cog" spin={1} />
{' Building...'}
</Dimmer>
)}
<Window.Content scrollable>
<Section title="Reagents">
<Box mb={1}>
{total_reagents} / {max_reagents} reagent capacity used.
</Box>
<LabeledList>
{reagents.map(reagent => (
<LabeledList.Item
key={reagent.reagent_name}
label={reagent.reagent_name}
buttons={(
<Button.Confirm
textAlign="center"
width="120px"
content="Remove Reagent"
color="bad"
onClick={() => act('empty_reagent', {
reagent_type: reagent.reagent_type,
})} />
)}>
{reagent.reagent_amount}u
</LabeledList.Item>
))}
</LabeledList>
</Section>
<Section title="Designs">
<Tabs>
{categories.map(category => (
<Tabs.Tab
fluid
key={category.name}
selected={tab === category.name}
onClick={() => setTab(category.name)}>
{category.name}
</Tabs.Tab>
))}
</Tabs>
<LabeledList>
{designList.map(design => (
<LabeledList.Item
key={design.name}
label={design.name}
buttons={(
<Button
content="Make"
color="good"
onClick={() => act('make_limb', {
design_id: design.id,
active_tab: design.parent_category,
})} />
)}>
{design.needed_reagents.map(reagent => (
<Box key={reagent.name}>
{reagent.name}: {reagent.amount}u
</Box>
))}
</LabeledList.Item>
))}
</LabeledList>
</Section>
</Window.Content>
</Window>
);
};