diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index 01129916d63..fdc3654d379 100644 --- a/code/datums/components/crafting/recipes.dm +++ b/code/datums/components/crafting/recipes.dm @@ -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 diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index a2916c1d390..46d86afccb5 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -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, "The Limb Grower is busy. Please wait for completion of previous operation.") 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("[user] begins to load \the [user_item] in \the [src]...", + "You begin to load designs from \the [user_item]...", + "You hear the clatter of a floppy drive.") + 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, "The limb grower is busy. Please wait for completion of previous operation.") + 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("The [src] buzzes.") + 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, "The limb grower is busy. Please wait for completion of previous operation.") + 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("Something went very wrong, there isn't enough synthflesh anymore!") - 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("The [src] buzzes.") + 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)) - . += "The status display reads: Storing up to [reagents.maximum_volume]u of synthflesh.
Synthflesh consumption at [prod_coeff*100]%.
" + . += "The status display reads: Storing up to [reagents.maximum_volume]u of reagents.
Reagent consumption rate at [production_coefficient * 100]%.
" -/obj/machinery/limbgrower/proc/main_win(mob/user) - var/dat = "

Limb Grower Menu:


" - dat += "Chemical Storage" - dat += materials_printout() - dat += "" - - for(var/C in categories) - dat += "" - dat += "" - //one category per line - - dat += "
[C]
" - return dat - -/obj/machinery/limbgrower/proc/category_win(mob/user,selected_category) - var/dat = "Return to main menu" - dat += "

Browsing [selected_category]:


" - 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 += "[D.name]" - else - dat += "[D.name]" - dat += "[get_design_cost(D)]
" - - dat += "
" - return dat - - -/obj/machinery/limbgrower/proc/chemical_win(mob/user) - var/dat = "Return to main menu" - dat += "

Browsing Chemical Storage:


" - dat += materials_printout() - - for(var/datum/reagent/R in reagents.reagent_list) - dat += "[R.name]: [R.volume]" - dat += "Purge
" - - dat += "
" - return dat - -/obj/machinery/limbgrower/proc/materials_printout() - var/dat = "Total amount:> [reagents.total_volume] / [reagents.maximum_volume] cm3
" - 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, "A warning flashes onto the screen, stating that safety overrides have been deactivated!") obj_flags |= EMAGGED + update_static_data(user) diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm index 813b8f63ebd..4e7c29ddaa7 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm @@ -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 diff --git a/code/modules/research/designs/limbgrower_designs.dm b/code/modules/research/designs/limbgrower_designs.dm index 97b1474e227..c7f62dfbc7c 100644 --- a/code/modules/research/designs/limbgrower_designs.dm +++ b/code/modules/research/designs/limbgrower_designs.dm @@ -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 diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 37168ebdca3..026af3cad8a 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -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" diff --git a/code/modules/surgery/organs/tails.dm b/code/modules/surgery/organs/tails.dm index 2ca70316d7a..4e7673e74c6 100644 --- a/code/modules/surgery/organs/tails.dm +++ b/code/modules/surgery/organs/tails.dm @@ -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." diff --git a/tgui/packages/tgui/interfaces/Limbgrower.js b/tgui/packages/tgui/interfaces/Limbgrower.js new file mode 100644 index 00000000000..71ed3f2cd0d --- /dev/null +++ b/tgui/packages/tgui/interfaces/Limbgrower.js @@ -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 ( + + {!!busy && ( + + + {' Building...'} + + )} + +
+ + {total_reagents} / {max_reagents} reagent capacity used. + + + {reagents.map(reagent => ( + act('empty_reagent', { + reagent_type: reagent.reagent_type, + })} /> + )}> + {reagent.reagent_amount}u + + ))} + +
+
+ + {categories.map(category => ( + setTab(category.name)}> + {category.name} + + ))} + + + {designList.map(design => ( + act('make_limb', { + design_id: design.id, + active_tab: design.parent_category, + })} /> + )}> + {design.needed_reagents.map(reagent => ( + + {reagent.name}: {reagent.amount}u + + ))} + + ))} + +
+
+
+ ); +};