diff --git a/code/__defines/_reagents.dm b/code/__defines/_reagents.dm index 25ea062068..602177c799 100644 --- a/code/__defines/_reagents.dm +++ b/code/__defines/_reagents.dm @@ -724,6 +724,10 @@ #define REAGENT_ID_GELATIN "gelatin" #define REAGENT_MUSTARDPODS "Mustard Pods" #define REAGENT_ID_MUSTARDPODS "mustardpods" +#define REAGENT_NUTRIPASTE "Nutriment Paste" +#define REAGENT_ID_NUTRIPASTE "nutripaste" +#define REAGENT_NUTRIPASTE_SOYLENT "Soylent Agent Green" +#define REAGENT_ID_NUTRIPASTE_SOYLENT "synthsoygreen" #define REAGENT_DRINK "Drink" #define REAGENT_ID_DRINK "drink" diff --git a/code/datums/wires/foodsynth.dm b/code/datums/wires/foodsynth.dm new file mode 100644 index 0000000000..4a757acc48 --- /dev/null +++ b/code/datums/wires/foodsynth.dm @@ -0,0 +1,69 @@ +//Totally not just a blatant copypasta. Nooooo... +/datum/wires/synthesizer + holder_type = /obj/machinery/synthesizer + wire_count = 6 + proper_name = "Food Synthesizer" + +/datum/wires/synthesizer/New(atom/_holder) + wires = list(WIRE_LATHE_HACK, WIRE_ELECTRIFY, WIRE_LATHE_DISABLE) + var/obj/machinery/synthesizer/A = _holder + if(A.hacked) + cut_wires += WIRE_LATHE_HACK + return ..() + +/datum/wires/synthesizer/get_status() + . = ..() + var/obj/machinery/synthesizer/A = holder + . += "The red light is [A.disabled ? "off" : "on"]." + . += "The green light is [A.shocked ? "off" : "on"]." + . += "The blue light is [A.hacked ? "off" : "on"]." + +/datum/wires/synthesizer/interactable(mob/user) + var/obj/machinery/synthesizer/A = holder + if(A.panel_open) + return TRUE + return FALSE + +/datum/wires/synthesizer/on_cut(wire, mend) + var/obj/machinery/synthesizer/A = holder + switch(wire) + if(WIRE_LATHE_HACK) + A.hacked = !mend + A.update_tgui_static_data(usr) + if(WIRE_ELECTRIFY) + A.shocked = !mend + if(WIRE_LATHE_DISABLE) + A.disabled = !mend + ..() + +/datum/wires/synthesizer/on_pulse(wire) + if(is_cut(wire)) + return + var/obj/machinery/synthesizer/A = holder + switch(wire) + if(WIRE_LATHE_HACK) + A.hacked = !A.hacked + A.update_tgui_static_data(usr) + addtimer(CALLBACK(src, PROC_REF(reset_hacked), WIRE_LATHE_HACK, usr), 5 SECONDS) + if(WIRE_ELECTRIFY) + A.shocked = !A.shocked + addtimer(CALLBACK(src, PROC_REF(reset_electrify), WIRE_ELECTRIFY), 5 SECONDS) + if(WIRE_LATHE_DISABLE) + A.disabled = !A.disabled + addtimer(CALLBACK(src, PROC_REF(reset_disable), WIRE_LATHE_DISABLE), 5 SECONDS) + +/datum/wires/synthesizer/proc/reset_hacked(wire, mob/user) + var/obj/machinery/synthesizer/A = holder + if(A && !is_cut(wire)) + A.hacked = FALSE + A.update_tgui_static_data(user) + +/datum/wires/synthesizer/proc/reset_electrify(wire) + var/obj/machinery/synthesizer/A = holder + if(A && !is_cut(wire)) + A.shocked = FALSE + +/datum/wires/synthesizer/proc/reset_disable(wire) + var/obj/machinery/synthesizer/A = holder + if(A && !is_cut(wire)) + A.disabled = FALSE diff --git a/code/game/machinery/frame.dm b/code/game/machinery/frame.dm index 610d5e1404..175f49ceac 100644 --- a/code/game/machinery/frame.dm +++ b/code/game/machinery/frame.dm @@ -24,6 +24,7 @@ GLOBAL_LIST(construction_frame_floor) var/frame_style = FRAME_STYLE_FLOOR // "floor" or "wall" var/x_offset // For wall frames: pixel_x var/y_offset // For wall frames: pixel_y + var/is_dense = TRUE // Lazy workaround for wall-mounted, upgradable machines // Get the icon state to use at a given state. Default implementation is based on the frame's name /datum/frame/frame_types/proc/get_icon_state(state) @@ -217,6 +218,22 @@ GLOBAL_LIST(construction_frame_floor) circuit = /obj/item/circuitboard/injector_maker frame_size = 3 +/datum/frame/frame_types/foodsynthesizer + name = "Food Synthesizer" + icon_override = 'icons/obj/machines/foodsynthesizer.dmi' + frame_class = FRAME_CLASS_MACHINE + frame_size = 5 + frame_style = FRAME_STYLE_WALL + x_offset = 24 + y_offset = 30 + is_dense = FALSE + +/datum/frame/frame_types/foodsynthesizer/mini + name = "Mini Food Synthesizer" + frame_class = FRAME_CLASS_MACHINE + frame_size = 3 // smaller, so slightly fewer sheets + frame_style = FRAME_STYLE_WALL + // Refinery machines /datum/frame/frame_types/industrial_reagent_grinder name = "Industrial Chemical Grinder" @@ -350,7 +367,7 @@ GLOBAL_LIST(construction_frame_floor) if(frame_type.name == "Computer") density = TRUE - if(frame_type.frame_class == FRAME_CLASS_MACHINE) + if(frame_type.frame_class == FRAME_CLASS_MACHINE && frame_type.is_dense) density = TRUE update_icon() diff --git a/code/modules/asset_cache/assets/spritesheets/foodsynth.dm b/code/modules/asset_cache/assets/spritesheets/foodsynth.dm new file mode 100644 index 0000000000..b6bbeb0379 --- /dev/null +++ b/code/modules/asset_cache/assets/spritesheets/foodsynth.dm @@ -0,0 +1,15 @@ +//Let's be optimal with our menu preview icons, shall we? +/datum/asset/spritesheet_batched/synthesizer + name = "synthesizer" + +/datum/asset/spritesheet_batched/synthesizer/create_spritesheets() + for(var/datum/category_item/synthesizer/path as anything in subtypesof(/datum/category_item/synthesizer)) + var/datum/universal_icon/icon = get_display_icon_for(path::build_path) + + if(!icon || !icon.icon_file) + continue + + icon.scale(128, 128) //enbiggen for the menu UI + + var/key = sanitize_css_class_name("[path::type]") + insert_icon(key, icon) diff --git a/code/modules/client/preference_setup/general/11_misc.dm b/code/modules/client/preference_setup/general/11_misc.dm index e2e78aeea5..c3aef661a5 100644 --- a/code/modules/client/preference_setup/general/11_misc.dm +++ b/code/modules/client/preference_setup/general/11_misc.dm @@ -1,10 +1,10 @@ // Define a place to save in character setup /datum/preferences - var/vantag_volunteer = 0 // What state I want to be in, in terms of being affected by antags. + var/vantag_volunteer = FALSE // What state I want to be in, in terms of being affected by antags. var/vantag_preference = VANTAG_NONE // Whether I'd like to volunteer to be an antag at some point. - var/resleeve_lock = 0 // Whether movs should have OOC reslieving protection. Default false. - var/resleeve_scan = 1 // Whether mob should start with a pre-spawn body scan. Default true. - var/mind_scan = 1 // Whether mob should start with a pre-spawn mind scan. Default true. + var/resleeve_lock = FALSE // Whether movs should have OOC reslieving protection. Default false. + var/resleeve_scan = TRUE // Whether mob should start with a pre-spawn body scan. Default true. + var/mind_scan = TRUE // Whether mob should start with a pre-spawn mind scan. Default true. var/custom_species // Custom species name, can't be changed due to it having been used in savefiles already. @@ -95,7 +95,7 @@ var/want_body_save = pref.resleeve_scan var/want_mind_save = pref.mind_scan - spawn(50) + spawn(5 SECONDS) if(QDELETED(character) || QDELETED(pref)) return // They might have been deleted during the wait if(!character.virtual_reality_mob && !(/mob/living/carbon/human/proc/perform_exit_vr in character.verbs)) //Janky fix to prevent resleeving VR avatars but beats refactoring transcore @@ -155,6 +155,7 @@ data["borg_petting"] = pref.borg_petting data["ignore_shoes"] = pref.read_preference(/datum/preference/toggle/human/ignore_shoes) + data["synth_cookie"] = pref.read_preference(/datum/preference/toggle/living/foodsynth_cookies) data["resleeve_lock"] = pref.resleeve_lock data["resleeve_scan"] = pref.resleeve_scan @@ -236,6 +237,9 @@ if("toggle_resleeve_scan") pref.resleeve_scan = pref.resleeve_scan ? 0 : 1; return TOPIC_REFRESH + if("toggle_synth_cookie") + pref.update_preference_by_type(/datum/preference/toggle/living/foodsynth_cookies, !pref.read_preference(/datum/preference/toggle/living/foodsynth_cookies)) + return TOPIC_REFRESH if("toggle_mind_scan") pref.mind_scan = pref.mind_scan ? 0 : 1; return TOPIC_REFRESH diff --git a/code/modules/client/preferences/types/character/general/11_misc.dm b/code/modules/client/preferences/types/character/general/11_misc.dm index 53e183b689..2984218213 100644 --- a/code/modules/client/preferences/types/character/general/11_misc.dm +++ b/code/modules/client/preferences/types/character/general/11_misc.dm @@ -7,3 +7,14 @@ /datum/preference/toggle/human/ignore_shoes/apply_to_human(mob/living/carbon/human/target, value) return + +// Whether mob can be printed as a snack. requires body scan. Default false. +/datum/preference/toggle/living/foodsynth_cookies + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "vore_fsynth_cookie" + default_value = FALSE + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + +/datum/preference/toggle/living/foodsynth_cookies/apply_to_living(mob/living/target, value) + return diff --git a/code/modules/food/kitchen/cooking_machines/foodsynthesizer.dm b/code/modules/food/kitchen/cooking_machines/foodsynthesizer.dm new file mode 100644 index 0000000000..92dd0e4879 --- /dev/null +++ b/code/modules/food/kitchen/cooking_machines/foodsynthesizer.dm @@ -0,0 +1,715 @@ +//Poojy's miracle 'I don't want generic pizza' / there's noone working kitchen machine +//Yes it's a generic food 3d printer. ~ +// in here because makes sense, if really it's just a refillable autolathe of food + +#define SYNTH_FOOD_COST 5 + +/obj/machinery/synthesizer + name = "Food Synthesizer" + desc = "Sabresnacks brand device able to produce an incredible array of conventional foods. Although only the most ascetic of users claim it produces truly good tasting products." + icon = 'icons/obj/machines/foodsynthesizer.dmi' + icon_state = "synthesizer" + density = FALSE + anchored = TRUE + use_power = USE_POWER_IDLE + idle_power_usage = 10 + active_power_usage = 2000 + clicksound = "keyboard" + clickvol = 30 + + var/hacked = FALSE + var/disabled = FALSE + var/shocked = FALSE + var/busy = FALSE + var/usage_amt = SYNTH_FOOD_COST + + light_system = STATIC_LIGHT + light_range = 3 + light_power = 1 + light_on = FALSE + + var/menu_grade //how tasty is it? + var/speed_grade //how fast can it be? + var/filtertext + + circuit = /obj/item/circuitboard/synthesizer + + //loaded cartridge + var/obj/item/reagent_containers/synthdispcart/cart = /obj/item/reagent_containers/synthdispcart + var/cart_type = ITEMSIZE_LARGE + + //all of our food + var/static/datum/category_collection/synthesizer/synthesizer_recipes + var/active_menu = "appasnacc" + var/activefood + + //Voice activation stuff + var/activator = "computer" + var/list/voicephrase + + //crew printing required stuff. + var/tgui_icons + var/icon/crewpicture + var/activecrew + var/refresh_delay = 10 SECONDS + +/obj/machinery/synthesizer/Initialize(mapload) + . = ..() + if(!synthesizer_recipes) + synthesizer_recipes = new() + cart = new cart(src) + wires = new/datum/wires/synthesizer(src) + default_apply_parts() + update_icon() + + if(!pixel_x && !pixel_y) + offset_synth() + +/obj/machinery/synthesizer/mini + name = "Mini Food Synthesizer" + icon_state = "portsynth" + cart_type = ITEMSIZE_NORMAL + circuit = /obj/item/circuitboard/synthesizer/mini + cart = /obj/item/reagent_containers/synthdispcart/small + +/obj/machinery/synthesizer/Destroy() + QDEL_NULL(wires) + + if(cart) + QDEL_NULL(cart) + + clear_tgui_icons() + return ..() + +/obj/machinery/synthesizer/examine(mob/user) + . = ..() + if(panel_open) + . += "A cartridge is [cart ? "installed" : "missing"]." + if(cart && (!(stat & (NOPOWER|BROKEN)))) + var/obj/item/reagent_containers/synthdispcart/C = cart + if(istype(C) && C.reagents && C.reagents.total_volume) + var/percent = round((C.reagents.total_volume / C.volume) * 100) + . += "The installed cartridge has [percent]% remaining." + +//offsets to make the machine squish to a wall. They're all south facing so it looks weird but every other direction is AWFUL +/obj/machinery/synthesizer/proc/offset_synth() + pixel_x = (dir & 3) ? 0 : (dir == 4 ? -24 : 24) + pixel_y = (dir & 3) ? (dir == 1 ? -22 : 30) : 0 + + +// TGUI +// Crew Cookie backend stuff... I can't even fuckin' believe this is Janicart stuff +/obj/machinery/synthesizer/proc/set_tgui_icon(mob/L) + if(!isliving(L)) + return + if(ishuman(L)) + crewpicture = getFlatIcon(L, defdir = SOUTH, no_anim = TRUE, force_south = TRUE) + tgui_icons = "'data:image/png;base64,[icon2base64(crewpicture)]'" + + else //Simple animals, Silicons, etc don't have records, so we'll just grab their current state. + var/icon/F = getFlatIcon(L, defdir = SOUTH, no_anim = TRUE, force_south = TRUE) + crewpicture = F + tgui_icons = "'data:image/png;base64,[icon2base64(F)]'" + SStgui.update_uis(src) + +/obj/machinery/synthesizer/proc/clear_tgui_icons() + tgui_icons = null + crewpicture = null + +// And literally this is all that's needed for conventional meals. lmao. +/obj/machinery/synthesizer/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet_batched/synthesizer), + ) + +/obj/machinery/synthesizer/tgui_interact(mob/user, datum/tgui/ui) + if(stat & (BROKEN|NOPOWER)) + return + + if(shocked) + shock(user, 100) + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "FoodSynthesizer") + ui.open() + +/obj/machinery/synthesizer/tgui_status(mob/user) + if(disabled) + return STATUS_CLOSE + return ..() + +/obj/machinery/synthesizer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = list( + "busy" = busy, + "isThereCart" = cart, + "active_menu" = active_menu, + "activefood" = activefood, + "activecrew" = activecrew, + "crewicon" = tgui_icons + ) + + if(cart) + var/percent = round((cart.reagents.total_volume / cart.reagents.maximum_volume) * 100) + data["cartFillStatus"] = percent + return data + +/obj/machinery/synthesizer/tgui_static_data(mob/user) + var/list/data = ..() + var/list/menucatagories = list() + for(var/datum/category_group/synthesizer/menulist in synthesizer_recipes.categories) + var/list/recipes = list() + for(var/datum/category_item/synthesizer/food in menulist.items) + UNTYPED_LIST_ADD(recipes, list( + "name" = food.name, + "type" = food.type, + "desc" = food.desc, + "hidden" = food.hidden, + "ref" = text_ref(food) + )) + UNTYPED_LIST_ADD(menucatagories, list( + "name" = menulist.name, + "id" = menulist.id, + "sortorder" = menulist.sortorder, + "ref" = text_ref(menulist), + "recipes" = recipes + )) + + data["menucatagories"] = menucatagories + + var/list/crew_cookies = list() + for(var/client/C in GLOB.clients) + // Check if the client allows crew cookies in their currently toggled prefs. Clients must be ingame to even be in GLOB.clients, so logged out players won't show up here. + if(!C.prefs?.read_preference(/datum/preference/toggle/living/foodsynth_cookies)) + continue + + var/name = null + var/species = null + + if(ishuman(C.mob)) + var/mob/living/carbon/human/H = C.mob + //Utilize the body records for humans to avoid metagaming problems (EX: using the cookie printer to check if someone is ghosting from the main menu) + var/datum/transcore_db/db = SStranscore.db_by_key() + if(db) + var/datum/transhuman/body_record/b_rec = db.body_scans[H.mind.name] + if(!b_rec) //extra check to make sure people have a body record, and no-one will immediately on start. + continue + name = H.real_name + species = "[H.custom_species ? H.custom_species : H.species.name]" + + if(issilicon(C.mob)) + if(isAI(C.mob)) + var/mob/living/silicon/ai/A = C.mob + name = A.name + species = "Artificial Intelligence" + + if(isrobot(C.mob)) + var/mob/living/silicon/robot/R = C.mob + if(R.scrambledcodes || (R.module && R.module.hide_on_manifest)) //Not sure if admeme events want valid cookie print outs + continue + name = R.name + species = "[R.modtype] [R.braintype]" + + if(isanimal(C.mob)) + var/mob/living/simple_mob/SM = C.mob + name = SM.name + species = initial(SM.name) //most mobs are simply named the species they are, so this ought to be useful for named critters. + + if(!name) + continue + + // our crew cookies are only applicable on the crew menu, and we're reusing our category sorting as much as possible! + crew_cookies.Add(list(list( + "category" = "crew", + "name" = name, + "species" = species + ))) + + data["crew_cookies"] = crew_cookies + return data + +/obj/machinery/synthesizer/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + if(stat & (BROKEN|NOPOWER)) + return FALSE + + if(ui.user.stat || ui.user.restrained()) + return FALSE + + add_fingerprint(ui.user) + + if(busy) + to_chat(ui.user, span_notice("The synthesizer is busy. Please wait for completion of previous operation.")) + return FALSE + + switch(action) + if("setactive_menu") + if(active_menu == params["setactive_menu"]) + return FALSE + active_menu = params["setactive_menu"] + activecrew = null + activefood = null + if(tgui_icons) + clear_tgui_icons() + return TRUE + + if("setactive_food") + if(activefood == params["setactive_food"]) + return FALSE + activefood = params["setactive_food"] + return TRUE + + if("setactive_crew") + if(activecrew == params["setactive_crew"]) + return FALSE + activecrew = params["setactive_crew"] + if(tgui_icons) + clear_tgui_icons() + + var/mob/found + for(var/mob/living/L in GLOB.player_list) + if(L.real_name == activecrew) + found = L + break + + if(!found) + return FALSE + + if(!get_mob_for_picture(ui.user, found)) + return FALSE + set_tgui_icon(found) + return TRUE + + if("make") + var/datum/category_item/synthesizer/making = locate(params["make"]) + if(!istype(making)) + return + if(making.hidden && !hacked) + return + + //Check if we still have the materials. + var/obj/item/reagent_containers/synthdispcart/C = cart + if(check_cart(C, ui.user)) + //Sanity check. + if(!making || !src) + return + busy = TRUE + update_use_power(USE_POWER_ACTIVE) + update_icon() // light up time + C.reagents.remove_reagent(REAGENT_ID_NUTRIPASTE_SOYLENT, SYNTH_FOOD_COST) //Drain our fuel + var/obj/item/reagent_containers/food/snacks/food_mimic = new making.build_path(src) //Let's get this on a tray + addtimer(CALLBACK(src, PROC_REF(finish_production), food_mimic, ui.user), speed_grade, TIMER_DELETE_ME) + return TRUE + + audible_message(span_notice("Error: Insufficent Materials. SabreSnacks recommends you have a genuine replacement cartridge available to install."), runemessage = "Error: Insufficent Materials!") + return FALSE + + if("refresh") + update_tgui_static_data(ui.user, ui) + return TRUE + + if("crewprint") + var/active_crew = params["crewprint"] + var/mob/found + for(var/mob/living/L in GLOB.player_list) + if(L.real_name == active_crew) + found = L + break + + if(found && !get_mob_for_picture(ui.user, found)) //verify that we can still print this person + to_chat(ui.user, "Warning: Invalid selection.") + return FALSE + + //Check if we still have the materials. + var/obj/item/reagent_containers/synthdispcart/C = cart + if(check_cart(C, ui.user)) + //Sanity check. + busy = TRUE + update_use_power(USE_POWER_ACTIVE) + update_icon() // light up time + C.reagents.remove_reagent(REAGENT_ID_NUTRIPASTE_SOYLENT, SYNTH_FOOD_COST) //Drain our fuel + sleep(speed_grade) //machine go brrr + + //Create the cookie base. + var/obj/item/reagent_containers/food/snacks/synthsized_meal/crewblock/meal = new /obj/item/reagent_containers/food/snacks/synthsized_meal/crewblock(loc) + + //Begin mimicking the micro + var/vore_flavor + if(found?.vore_taste) + vore_flavor = found.vore_taste + else + vore_flavor = "Something impalpable" + + meal.name = found.real_name + meal.desc = "A tiny replica of a crewmate!" + var/icon/F = crewpicture + F.Scale(16, 16) //Half size + meal.icon = F + meal.icon_state = null + + //flavor mixing, make the cookie taste somewhat like the real thing! + for(var/datum/reagent/foodpaste in meal.reagents.reagent_list) + if(foodpaste.id == REAGENT_ID_NUTRIPASTE) //This should be the only reagent, actually. + foodpaste.taste_description += " as well as [vore_flavor]" + foodpaste.data = list(foodpaste.taste_description = 1) + meal.nutriment_desc = list(foodpaste.taste_description = 1) + + if(menu_grade >= 2) //Is the machine upgraded? + meal.reagents.add_reagent(REAGENT_ID_NUTRIPASTE, ((1 + menu_grade) - 1)) //add the missing Nutriment bonus, subtracting the one we've already added in. + + audible_message(span_notice("Please take your miniature [meal.name]."), runemessage = "Minature [meal.name] is complete!") + if(Adjacent(ui.user)) + ui.user.put_in_any_hand_if_possible(meal) //Autoplace in hands to save a click + else + meal.forceMove(get_turf(src)) //otherwise we anti-clump layer onto the floor + meal.randpixel_xy() + busy = FALSE + update_icon() //turn off lights, please. + else + audible_message(span_notice("Error: Insufficent Materials. SabreSnacks recommends you have a genuine replacement cartridge available to install."), runemessage = "Error: Insufficent Materials!") + return FALSE + return TRUE + +/obj/machinery/synthesizer/proc/finish_production(obj/item/reagent_containers/food/snacks/food_mimic, mob/user) + //Create the desired item. + var/obj/item/reagent_containers/food/snacks/synthsized_meal/meal = new /obj/item/reagent_containers/food/snacks/synthsized_meal(loc) + + //Begin mimicking the food + meal.name = food_mimic.name + meal.desc = food_mimic.desc + meal.icon = food_mimic.icon + meal.icon_state = food_mimic.icon_state + meal.center_of_mass_x = food_mimic.center_of_mass_x + meal.center_of_mass_y = food_mimic.center_of_mass_y + + //flavor mixing + var/taste_output = food_mimic.reagents.generate_taste_message() + for(var/datum/reagent/F in meal.reagents.reagent_list) + if(F.id == REAGENT_ID_NUTRIPASTE) //This should be the only reagent, actually. + F.taste_description += " as well as [taste_output]" + F.data = list(F.taste_description = 1) + meal.nutriment_desc = list(F.taste_description = 1) + + if(menu_grade >= 2) //Is the machine upgraded? + meal.reagents.add_reagent(REAGENT_ID_NUTRIPASTE, ((1 + menu_grade) - 1)) //add the missing Nutriment bonus, subtracting the one we've already added in. + + meal.bitesize = food_mimic?.bitesize //suffer your aerogel like 1 Nutriment turkey, nerds. + meal.filling_color = food_mimic?.filling_color + meal.trash = food_mimic?.trash //If this can lead to exploits then we'll remove it, but I like the idea. + qdel(food_mimic) + audible_message(span_notice("Please take your [meal.name]."), runemessage = "[meal.name] is complete!") + if(Adjacent(user)) + user.put_in_any_hand_if_possible(meal) //Autoplace in hands to save a click + else + meal.forceMove(get_turf(src)) //otherwise we anti-clump layer onto the floor + meal.randpixel_xy() + busy = FALSE + update_icon() //turn off lights, please. + +/obj/machinery/synthesizer/update_icon() + cut_overlays() + set_light_on(FALSE) + icon_state = initial(icon_state) //we use this to reduce code bloat. It's nice. + if(panel_open) //add service panels just above our machine + if(!(stat & (NOPOWER|BROKEN))) + add_overlay("[initial(icon_state)]_ppanel") + else + add_overlay("[initial(icon_state)]_panel") + if(cart) + var/obj/item/reagent_containers/synthdispcart/C = cart + if(C.reagents && C.reagents.total_volume) + var/image/filling_overlay = image("[icon]", src, "[initial(icon_state)]fill_0") //Modular filling + var/percent = round((C.reagents.total_volume / C.volume) * 100) + switch(percent) + if(0 to 9) filling_overlay.icon_state = "[initial(icon_state)]fill_0" + if(10 to 35) filling_overlay.icon_state = "[initial(icon_state)]fill_25" + if(36 to 74) filling_overlay.icon_state = "[initial(icon_state)]fill_50" + if(75 to 90) filling_overlay.icon_state = "[initial(icon_state)]fill_75" + if(91 to INFINITY) filling_overlay.icon_state = "[initial(icon_state)]fill_100" + filling_overlay.color = C.reagents.get_color() + //Add our filling, if any. + add_overlay(filling_overlay) + //Then add our cart so the filling is inside of the canister. + add_overlay("[initial(icon_state)]_cart") + return //don't stack additional panel screen states, please. + + if((stat && BROKEN)) + icon_state = "[initial(icon_state)]x" + return + + if(stat & NOPOWER) + return + + if(!cart) + add_overlay("[initial(icon_state)]_error") + return + + if(cart && !busy) + var/obj/item/reagent_containers/synthdispcart/C = cart + if(C.reagents && C.reagents.total_volume) + add_overlay("[initial(icon_state)]_on") + else + add_overlay("[initial(icon_state)]_error") + return + + if(busy) + add_overlay("[initial(icon_state)]_busy") + set_light_color("#faebd7") // "antique white" + set_light_on(TRUE) + +//Cartridge Interactions in Machine +/obj/machinery/synthesizer/proc/add_cart(obj/item/C, mob/user) + if(!Adjacent(user)) + return //How did you even try? + if(!panel_open) //just in case + to_chat(user, "The hatch must be open to insert a [C].") + return + if(cart) // let's hot swap that bad boy. + remove_cart(user) + return + + user.drop_from_inventory(C) + cart = C + C.forceMove(src) + C.add_fingerprint(user) + to_chat(user, span_notice("You add [C] to \the [src].")) + update_icon() + SStgui.update_uis(src) + return + +/obj/machinery/synthesizer/proc/remove_cart(mob/user) + var/obj/item/reagent_containers/synthdispcart/C = cart + if(!C) + to_chat(user, span_notice("There's no cartridge here...")) //Sanity checks aren't ever a bad thing + return + if(!Adjacent(user)) //gotta, y'know, be in touch range to pull a physical canister out + return + C.forceMove(get_turf(loc)) + C.update_icon() + cart = null + to_chat(user, span_notice("You remove [C] from \the [src].")) + + if(Adjacent(user)) + user.put_in_hands(C) //pick up your trash, nerd. and don't hand it to the AI. They will be upset. + update_icon() + SStgui.update_uis(src) + +/obj/machinery/synthesizer/proc/check_cart(obj/item/reagent_containers/synthdispcart/C, mob/user) + if(!istype(C)) + to_chat(user, span_notice("The synthesizer cartridge is nonexistant.")) + return FALSE + if((!(C.reagents)) || (C.reagents.total_volume <= 0) || (!C.reagents.has_reagent(REAGENT_ID_NUTRIPASTE_SOYLENT))) + to_chat(user, span_notice("The synthesizer cartridge depleted, replace with a genuine Sabresnack Co cartridge.")) + return FALSE + if((C.reagents) && (C.reagents.total_volume <= 0) && (!C.reagents.has_reagent(REAGENT_ID_NUTRIPASTE_SOYLENT))) + to_chat(user, span_notice("Used or Counterfeit synthesizer cartridge detected.")) + return FALSE + else if(C.reagents && C.reagents.has_reagent(REAGENT_ID_NUTRIPASTE_SOYLENT) && (C.reagents.total_volume >= SYNTH_FOOD_COST)) + SStgui.update_uis(src) + return TRUE + +/obj/machinery/synthesizer/proc/get_mob_for_picture(mob/user, mob/living/LM) + if(!istype(LM)) + to_chat(user, span_warning("Warning: Invalid selection. Please refresh the database.")) + return FALSE + + if(LM.client?.prefs?.read_preference(/datum/preference/toggle/living/foodsynth_cookies)) + return TRUE + + to_chat(user, span_warning("Warning: Invalid selection. Please refresh the database.")) + return FALSE + +/obj/machinery/synthesizer/attackby(obj/item/W, mob/user) + if(busy) + audible_message(span_notice("\The [src] is busy. Please wait for completion of previous operation."), runemessage = "The Synthesizer is busy.") + return + if(default_part_replacement(user, W)) + return + if(stat) + update_icon() + return + if(W.is_screwdriver()) + panel_open = !panel_open + playsound(src, W.usesound, 50, 1) + user.visible_message(span_notice("[user] [panel_open ? "opens" : "closes"] the hatch on the [src]."), span_notice("You [panel_open ? "open" : "close"] the hatch on the [src].")) + update_icon() + return + if(panel_open) + if(istype(W, /obj/item/reagent_containers/synthdispcart)) + if(!anchored) + to_chat(user, span_warning("Anchor its bolts first.")) + return + if(W.w_class > cart_type) //since we confirmed it's a Cart, make sure it fits! + to_chat(user, span_warning("\The [src] only accepts smaller synthiziser cartridges.")) + return + if(cart) + var/choice = alert(user, "Replace the loaded cartridge?", "", "Yes", "Cancel") + switch(choice) + if("Cancel") + return FALSE + if("Yes") + add_cart(W, user) + else + add_cart(W, user) + + if(W.is_wrench()) + playsound(src, W.usesound, 50, 1) + to_chat(user, span_notice("You begin to [anchored ? "un" : ""]fasten \the [src].")) + if (do_after(user, 20 * W.toolspeed)) + user.visible_message( + span_notice("\The [user] [anchored ? "un" : ""]fastens \the [src]."), + span_notice("You have [anchored ? "un" : ""]fastened \the [src]."), + "You hear a ratchet.") + anchored = !anchored + update_icon() + else + to_chat(user, span_notice("You decide not to [anchored ? "un" : ""]fasten \the [src].")) + + if(default_deconstruction_crowbar(user, W)) + return + + return ..() + +/obj/machinery/synthesizer/attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + if(!panel_open) + tgui_interact(user) + else if(panel_open) + if(cart) + var/choice = alert(user, "Removing the Cartridge?", "", "Yes", "Cancel", "Wires Menu") + switch(choice) + if("Cancel") + return FALSE + if("Yes") + remove_cart(user) + if("Wires Menu") + wires.Interact(user) + else + wires.Interact(user) + +/obj/machinery/synthesizer/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/synthesizer/interact(mob/user) + if(panel_open) + return wires.Interact(user) + + if(disabled) + to_chat(user, span_danger("\The [src] is disabled!")) + return + + if(shocked) + shock(user, 50) + + tgui_interact(user) + +//Updates performance +/obj/machinery/synthesizer/RefreshParts() + ..() + menu_grade = 0 + speed_grade = 0 + + for(var/obj/item/stock_parts/manipulator/M in component_parts) + speed_grade = (10 SECONDS) / M.rating //let's try to make it worthwhile to upgrade 'em 10s, 5s, 3.3s, 2.5s + for(var/obj/item/stock_parts/scanning_module/S in component_parts) + menu_grade = S.rating //how much bonus Nutriment is added to the printed food. the regular wafer is only 5. + // Science parts will be of help if they bother. + +#undef SYNTH_FOOD_COST +//Cartridge Item handling +/obj/item/reagent_containers/synthdispcart + name = "Synthesizer cartridge" + desc = "Genuine replacement cartridge for SabreSnacks brand Food Synthesizers. It's too large for the Portable models." + icon = 'icons/obj/machines/foodsynthesizer.dmi' + icon_state = "bigcart" + + w_class = ITEMSIZE_LARGE + + volume = 250 //enough for feeding folk, but not so much it won't be needing replacment + //No way to refill or drain them. Like printer ink, it's only good in the machine! + amount_per_transfer_from_this = 0 + max_transfer_amount = 0 + min_transfer_amount = 0 + flags = NONE + +/obj/item/reagent_containers/synthdispcart/small + name = "Portable Synthesizer Cartridge" + desc = "Genuine replacement cartrifge SabreSnacks brand Portable Food Synthesizers. It can also fit within standard sized models." + icon_state = "Scart" + w_class = ITEMSIZE_NORMAL + volume = 100 + +/obj/item/reagent_containers/synthdispcart/Initialize(mapload) + . = ..() + reagents.add_reagent(REAGENT_ID_NUTRIPASTE_SOYLENT, volume) + update_icon() + +/obj/item/reagent_containers/synthdispcart/update_icon() + cut_overlays() + if(reagents.total_volume) + var/image/filling_overlay = image("[icon]", src, "[initial(icon_state)]fill_0", layer = layer - 0.1) + var/percent = round((reagents.total_volume / volume) * 100) + switch(percent) + if(0 to 9) filling_overlay.icon_state = "[initial(icon_state)]fill_0" + if(10 to 35) filling_overlay.icon_state = "[initial(icon_state)]fill_25" + if(36 to 74) filling_overlay.icon_state = "[initial(icon_state)]fill_50" + if(75 to 90) filling_overlay.icon_state = "[initial(icon_state)]fill_75" + if(91 to 100) filling_overlay.icon_state = "[initial(icon_state)]fill_100" + if(100 to INFINITY) filling_overlay.icon_state = "[initial(icon_state)]fill_100" + filling_overlay.color = reagents.get_color() + add_overlay(filling_overlay) + +/obj/item/reagent_containers/synthdispcart/examine(mob/user) + . = ..() + if(reagents && reagents.total_volume) + var/percent = round((reagents.total_volume / volume) * 100) + . += "The cartridge has [percent]% remaining." + +/obj/item/reagent_containers/synthdispcart/is_open_container() + return FALSE //sealed, proprietary container. aka preventing alternative beaker memes. + +//Circuits for contruction + +/datum/design_techweb/board/synthesizer + SET_CIRCUIT_DESIGN_NAMEDESC("food synthesizer") + id = "food_synthesizer" + // req_tech = list(TECH_DATA = 3, TECH_BLUESPACE = 3, TECH_ENGINEERING = 2) + build_path = /obj/item/circuitboard/synthesizer + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_KITCHEN + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_SCIENCE + +/datum/design_techweb/board/synthesizer/mini + SET_CIRCUIT_DESIGN_NAMEDESC("compact food synthesizer") + id = "compactfood_synthesizer" + // req_tech = list(TECH_DATA = 3, TECH_BLUESPACE = 3, TECH_ENGINEERING = 2) + build_path = /obj/item/circuitboard/synthesizer/mini + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_KITCHEN + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_SCIENCE + +// Physical Boards for Food Synthesizer Construction +/obj/item/circuitboard/synthesizer + name = T_BOARD("Food Synthesizer") + desc = "The circuitboard for a Food Synthesizer." + build_path = /obj/machinery/synthesizer + board_type = new /datum/frame/frame_types/foodsynthesizer + matter = list(MAT_STEEL = 50, MAT_GLASS = 50) + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/scanning_module = 1) + +/obj/item/circuitboard/synthesizer/mini + name = T_BOARD("Compact Food Synthesizer") + desc = "The circuitboard for a compact food synthesizer." + build_path = /obj/machinery/synthesizer/mini + board_type = new /datum/frame/frame_types/foodsynthesizer/mini + matter = list(MAT_STEEL = 50, MAT_GLASS = 50) + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/scanning_module = 1) diff --git a/code/modules/food/recipes_foodsynthesizer.dm b/code/modules/food/recipes_foodsynthesizer.dm new file mode 100644 index 0000000000..1e128477f9 --- /dev/null +++ b/code/modules/food/recipes_foodsynthesizer.dm @@ -0,0 +1,1150 @@ +#define VOICE_TEMP_COLD "cold" +#define VOICE_TEMP_HOT "hot" + +/datum/category_item/synthesizer/New() + ..() + var/obj/item/reagent_containers/food/snacks/snacc = build_path + if(!snacc) // Something has gone horribly wrong, or right. + log_game("[name] created an Synthesizer design without an assigned build_path.") + return + desc = initial(snacc.desc) //Let's get our description text + +/********************* +* Synthed Food Setup * +**********************/ +/obj/item/reagent_containers/food/snacks/synthsized_meal + name = "Nutrient paste wafer" + desc = "It's a synthisized edible wafer of nutrients. Everything you need and makes field rations a delicacy in comparison." + icon = 'icons/obj/machines/foodsynthesizer.dmi' + icon_state = "pasteblock" + filling_color = "#c5e384" + center_of_mass_x = 16 + center_of_mass_y = 6 + w_class = ITEMSIZE_SMALL + bitesize = 5 + +/obj/item/reagent_containers/food/snacks/synthsized_meal/Initialize(mapload) + . = ..() + reagents.add_reagent(REAGENT_ID_NUTRIPASTE, 5) + +/obj/item/reagent_containers/food/snacks/synthsized_meal/crewblock + name = "Crew paste block" + desc = "It's a synthisized edible wafer of nutrients. Everything you need and makes field rations a delicacy in comparison." + icon_state = "crewblock" + bitesize = 30 //one chomp. bitesize = amount taken per bite? I guess? weird. + eating_sound = 'sound/vore/sunesound/pred/swallow_01.ogg' //hehe + +/datum/reagent/nutriment/synthmealgoop + name = REAGENT_NUTRIPASTE + id = REAGENT_ID_NUTRIPASTE + description = "a revoltingly bland paste of nutrition." + taste_description = "undefinable blandness" //This gets updated with our printed food's taste descriptor + taste_mult = 1 + nutriment_factor = 6 // 2/3rds the power of real Nutriment (10). for balance. + reagent_state = SOLID + color = "#c5e384" + +//gotta make the fuel a thing, might as well make it horrid, amirite. Should only be a cargo import. Shouldn't be aquirable! +/datum/reagent/nutriment/synthsoylent + name = REAGENT_NUTRIPASTE_SOYLENT + id = REAGENT_ID_NUTRIPASTE_SOYLENT + description = "An thick, horridly rubbery fluid that somehow can be synthisized into 'edible' meals." + taste_description = "unrefined cloying oil" + taste_mult = 1.3 + nutriment_factor = 1 + reagent_state = LIQUID + color = "#4b0082" + +//Supply pack refills +/datum/supply_pack/vending_refills/synthesizer + contains = list(/obj/item/reagent_containers/synthdispcart) + name = "Food Synthesizer Cartridge (Standard)" + cost = 20 //pricy so chef value is ever better. + containername = "food synthesizer cartridge crate" + +/datum/supply_pack/vending_refills/synthesizer/smol + contains = list(/obj/item/reagent_containers/synthdispcart/small) + name = "Food Synthesizer Cartridge (Portable)" + cost = 10 + containername = "portable food synthesizer cartridge crate" + +/**************************** +* Category Collection Setup * +****************************/ + +/datum/category_collection/synthesizer + category_group_type = /datum/category_group/synthesizer + +/************* +* Categories * +*************/ +#define MENU_SNACC 0 +#define MENU_BREKKIE 1 +#define MENU_LONCH 2 +#define MENU_DINNAH 3 +#define MENU_DESLUT 4 +#define MENU_EROTIC 5 +#define MENU_RHAWH 6 +#define MENU_MEHARTY 7 + +/datum/category_group/synthesizer + var/id + var/sortorder + +/datum/category_group/synthesizer/New() + ..() + +/datum/category_group/synthesizer/appasnack + name = "Appetizers" + id = "appasnacc" + sortorder = MENU_SNACC + category_item_type = /datum/category_item/synthesizer/appasnack + +/datum/category_group/synthesizer/breakfastmenu + name = "Breakfasts" + id = "breakfast" + sortorder = MENU_BREKKIE + category_item_type = /datum/category_item/synthesizer/breakfastmenu + +/datum/category_group/synthesizer/lunchmenu + name = "Lunches" + id = "lunch" + sortorder = MENU_LONCH + category_item_type = /datum/category_item/synthesizer/lunchmenu + +/datum/category_group/synthesizer/dinnermenu + name = "Dinners" + id = "dinner" + sortorder = MENU_DINNAH + category_item_type = /datum/category_item/synthesizer/dinnermenu + +/datum/category_group/synthesizer/dessertmenu + name = "Desserts" + id = "dessert" + sortorder = MENU_DESLUT + category_item_type = /datum/category_item/synthesizer/dessert + +/datum/category_group/synthesizer/exoticmenu + name = "Exotics" + id = "exotic" + sortorder = MENU_EROTIC + category_item_type = /datum/category_item/synthesizer/exotic + +/datum/category_group/synthesizer/rawmenu + name = "Raw Offerings" + id = "raw" + sortorder = MENU_RHAWH + category_item_type = /datum/category_item/synthesizer/raw + +/datum/category_group/synthesizer/crewmenu + name = "Crew Cookies" + id = "crew" + sortorder = MENU_MEHARTY + category_item_type = /datum/category_item/synthesizer/crew + +#undef MENU_SNACC +#undef MENU_BREKKIE +#undef MENU_LONCH +#undef MENU_DINNAH +#undef MENU_DESLUT +#undef MENU_EROTIC +#undef MENU_RHAWH +#undef MENU_MEHARTY + +/******************* +* Category entries * +*******************/ + +/datum/category_item/synthesizer + var/desc //food description to be applied to the UI. + var/build_path //food item build_path + var/hidden = FALSE //is it illegal/nonstandard? + var/list/voice_order //what can we say to get this? Avoid exact same phrases. + var/voice_temp //mostly flavor but maybe also setting stuff that will warm/cool you off? idk + +/********* +* Snacks * +**********/ + +/datum/category_item/synthesizer/appasnack/popcorn + name = "Popcorn" + build_path = /obj/item/reagent_containers/food/snacks/popcorn + voice_order = list("popcorn", "corn of popping") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/appasnack/nuggies + name = "Chicken Nugget" + build_path = /obj/item/reagent_containers/food/snacks/nugget + voice_order = list("chimkin nuggy", "chicken nugget") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/appasnack/flatbread + name = "Flatbread" + build_path = /obj/item/reagent_containers/food/snacks/flatbread + voice_order = list("flatbread") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/appasnack/tortilla + name = "Flour Tortilla" + build_path = /obj/item/reagent_containers/food/snacks/tortilla + voice_order = list("tortilla", "flour tortilla") + voice_temp = VOICE_TEMP_HOT //imagine liking *cold* Tortillas. Ugh. It offends my Texan sensibilites. + +/datum/category_item/synthesizer/appasnack/bun + name = "Burger Bun" + build_path = /obj/item/reagent_containers/food/snacks/bun + voice_order = list("Burger bun", "plain bun") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/appasnack/eggroll + name = "Egg Roll" + build_path = /obj/item/reagent_containers/food/snacks/eggroll + voice_order = list("egg roll", "happy ending") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/appasnack/friedmushroom + name = "Fried Mushroom" + build_path = /obj/item/reagent_containers/food/snacks/friedmushroom + voice_order = list("fried mushroom","fried cap") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/appasnack/watermelonslice + name = "Watermelon Slice" + build_path = /obj/item/reagent_containers/food/snacks/watermelonslice + voice_order = list("watermelon slice") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/appasnack/truffle + name = "Candy (Truffle)" + build_path = /obj/item/reagent_containers/food/snacks/truffle + voice_order = list("chocolate truffle") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/appasnack/mint + name = "Candy (Mint)" + build_path = /obj/item/reagent_containers/food/snacks/mint + voice_order = list("candy mints", "mint candy") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/appasnack/candybar + name = "Candy (Bar)" + build_path = /obj/item/reagent_containers/food/snacks/candy + voice_order = list("candy bar", "chocolate bar") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/appasnack/proteinbar + name = "Candy (Protein)" + build_path = /obj/item/reagent_containers/food/snacks/candy/proteinbar + voice_order = list("protein candy bar", "protein bar") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/appasnack/cb10 + name = "Candy (Nutty)" + build_path = /obj/item/reagent_containers/food/snacks/cb10 + voice_order = list("shantak","shantak bar", "chocolate nut bar") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/appasnack/skrellsnacks + name = "Skrell Snacks" + build_path = /obj/item/reagent_containers/food/snacks/skrellsnacks + voice_order = list("skrell snacks", "skrell snacc", "skrell treats") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/appasnack/admints + name = "Admints" + build_path = /obj/item/reagent_containers/food/snacks/mint/admints + voice_order = list("admints", "admin mints") + voice_temp = VOICE_TEMP_COLD + +/********* +* Breakfast * +**********/ + +/datum/category_item/synthesizer/breakfastmenu/muffin + name = "Muffin (Plain)" + build_path = /obj/item/reagent_containers/food/snacks/muffin + voice_order = list("plain muffin", "bald cupcake") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/breakfastmenu/bagelplain + name = "Bagel (Plain)" + build_path = /obj/item/reagent_containers/food/snacks/bagelplain + voice_order = list("bagel", "plain bagel") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/breakfastmenu/bagelsunflower + name = "Bagel (Sunflower)" + build_path = /obj/item/reagent_containers/food/snacks/bagelsunflower + voice_order = list("sunflower bagel", "bagel sunflower", "bagel with sunflower") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/breakfastmenu/bagelcheese + name = "Bagel (Cheese)" + build_path = /obj/item/reagent_containers/food/snacks/bagelcheese + voice_order = list("cream cheese bagel","cheese bagel", "bagel with cheese") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/breakfastmenu/bagelraisin + name = "Bagel (Raisin)" + build_path = /obj/item/reagent_containers/food/snacks/bagelraisin + voice_order = list("raisin bagel", "raisen bagel", "bagel with raisins", "bagel with raisens") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/breakfastmenu/bagelpoppy + name = "Bagel (Poppyseed)" + build_path = /obj/item/reagent_containers/food/snacks/bagelpoppy + voice_order = list("poppyseed bagel", "bagel with poppyseeds") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/breakfastmenu/croissant + name = "Croissant" + build_path = /obj/item/reagent_containers/food/snacks/croissant + voice_order = list("croissant", "crossant") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/breakfastmenu/pancakes + name = "Pancakes" + build_path = /obj/item/reagent_containers/food/snacks/pancakes + voice_order = list("plain pancakes") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/berrypancake + name = "Berry Pancakes" + build_path = /obj/item/reagent_containers/food/snacks/pancakes/berry + voice_order = list("berry pancakes", "pancakes with berries") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/ntmuffin + name = "Dwarven Breakfast Muffin" + build_path = /obj/item/reagent_containers/food/snacks/nt_muffin + voice_order = list("breakfast muffin", "nt muffin") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/breakfastburrito + name = "Breakfast Burrito" + build_path = /obj/item/reagent_containers/food/snacks/breakfast_wrap + voice_order = list("Breakfast burrito") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/quicheslice + name = "Quiche Slice" + build_path = /obj/item/reagent_containers/food/snacks/quicheslice/filled + voice_order = list("quiche") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/poachedegg + name = "Egg (Poached)" + build_path = /obj/item/reagent_containers/food/snacks/poachedegg + voice_order = list("poached egg") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/boiledegg + name = "Egg (Boiled)" + build_path = /obj/item/reagent_containers/food/snacks/boiledegg + voice_order = list("boiled egg") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/friedegg + name = "Egg (Fried)" + build_path = /obj/item/reagent_containers/food/snacks/friedegg + voice_order = list("fried egg", "egg well") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/chiliedegg + name = "Egg (Chilied)" + build_path = /obj/item/reagent_containers/food/snacks/chilied_eggs + voice_order = list("redeemed eggs", "chili eggs") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/bacon + name = "Bacon wafer" + build_path = /obj/item/reagent_containers/food/snacks/bacon_stick + voice_order = list("bacon stick", "stick of bacon") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/ovenbacon + name = "Oven-baked bacon" + build_path = /obj/item/reagent_containers/food/snacks/bacon/oven + voice_order = list("oven bacon", "epic bacon") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/breakfastmenu/eggbacon + name = "Bacon and Eggs" + build_path = /obj/item/reagent_containers/food/snacks/bacon_and_eggs + voice_order = list("bacon and eggs", "eggs and bacon") + voice_temp = VOICE_TEMP_HOT + +/******** +* Lunch * +*********/ + +/datum/category_item/synthesizer/lunchmenu/blt + name = "BLT sandwich" + build_path = /obj/item/reagent_containers/food/snacks/blt + voice_order = list("blt sandwich", "sandwich blt") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/lunchmenu/genericsandwich + name = "Sandvich" + build_path = /obj/item/reagent_containers/food/snacks/sandwich + voice_order = list("lunchmenu sandwich", "sandwich") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/lunchmenu/meatbreadslice + name = "Meat bread (Slice)" + build_path = /obj/item/reagent_containers/food/snacks/slice/meatbread/filled + voice_order = list("meat bread slice", "slice of meat bread") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/tofubreadslice + name = "Tofu bread (Slice)" + build_path = /obj/item/reagent_containers/food/snacks/slice/tofubread/filled + voice_order = list("tofu bread slice", "slice of tofu bread") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/creamcheesebreadslice + name = "Cream cheese bread (slice)" + build_path = /obj/item/reagent_containers/food/snacks/slice/creamcheesebread/filled + voice_order = list("cream cheese bread slice", "slice of cream cheese bread") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/margheritaslice + name = "Margherita Pizza (Slice)" + build_path = /obj/item/reagent_containers/food/snacks/slice/margherita/filled + voice_order = list("margherita pizza", "neapolitan pizza") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/meatpizzaslice + name = "Meat Lovers Pizza (Slice)" + build_path = /obj/item/reagent_containers/food/snacks/slice/meatpizza/filled + voice_order = list("meat pizza", "meat lovers pizza", "pizza with meat") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/mushroompizzasilce + name = "Mushroom Pizza (Slice)" + build_path = /obj/item/reagent_containers/food/snacks/slice/mushroompizza/filled + voice_order = list("mushroom pizza", "pizza with mushroom") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/veggiepizzaslice + name = "Vegetable Pizza (Slice)" + build_path = /obj/item/reagent_containers/food/snacks/slice/vegetablepizza/filled + voice_order = list("veggie pizza", "vegetable pizza", "pizza with veggies", "pizza with vegetable") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/pineapplepizzaslice + name = "Pineapple Pizza (Slice)" + build_path = /obj/item/reagent_containers/food/snacks/pineappleslice/filled + voice_order = list("pineapple pizza", "pizza with pineapple", "abomination pizza", "best pizza") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/chickensandwich + name = "Chicken Fillet Sandwich" + build_path = /obj/item/reagent_containers/food/snacks/chickenfillet + voice_order = list("Chicken sandwich", "Chimkin sammich", "Chimkin sandwich") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/corndog + name = "County Fair Corndog" + build_path = /obj/item/reagent_containers/food/snacks/corn_dog + voice_order = list("corndog", "hotdog on a stick") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/ovenfries + name = "Oven baked fries" + build_path = /obj/item/reagent_containers/food/snacks/ovenfries + voice_order = list("oven fries") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/bread + name = "Bread Loaf" + build_path = /obj/item/reagent_containers/food/snacks/sliceable/bread + voice_order = list("bread loaf", "loaf of bread") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/lunchmenu/baguette + name = "Baguette" + build_path = /obj/item/reagent_containers/food/snacks/baguette + voice_order = list("baguette", "french bread") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/lunchmenu/tofubread + name = "Tofu Bread Loaf" + build_path = /obj/item/reagent_containers/food/snacks/sliceable/tofubread + voice_order = list("tofu bread loaf") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/lunchmenu/macncheese + name = "Mac and Cheese" + build_path = /obj/item/reagent_containers/food/snacks/macncheese + voice_order = list("Mac n cheese", "macaroni and cheese", "mac and cheese") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/chickenmomo + name = "Chicken MoMo" + build_path = /obj/item/reagent_containers/food/snacks/chickenmomo + voice_order = list("chicken momo", "chicken dumplings") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/veggiemomo + name = "Veggie MoMo" + build_path = /obj/item/reagent_containers/food/snacks/veggiemomo + voice_order = list("veggie momo", "veggie dumplings", "vegetarian dumplings") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/eggpancake + name = "Burger Omelette" + build_path = /obj/item/reagent_containers/food/snacks/egg_pancake + voice_order = list("egg pancake", "burger omelette") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/mysteryburrito + name = "Burrito (Mystery Meat)" + build_path = /obj/item/reagent_containers/food/snacks/burrito_mystery + voice_order = list("mystery burrito") + voice_temp = VOICE_TEMP_HOT + hidden = TRUE + +/datum/category_item/synthesizer/lunchmenu/fuegoburrito + name = "Burrito (Fuego Phoron)" + build_path = /obj/item/reagent_containers/food/snacks/fuegoburrito + voice_order = list("fire veggie burrito", "fuego phoron burrito") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/meatburrito + name = "Burrito (carne asada)" + build_path = /obj/item/reagent_containers/food/snacks/meatburrito + voice_order = list("steak burrito", "carne asada burrito") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/cheeseburrito + name = "Burrito (Cheese)" + build_path = /obj/item/reagent_containers/food/snacks/cheeseburrito + voice_order = list("cheese burrito", "burrito with cheese") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/burrito + name = "Burrito (Generic)" + build_path = /obj/item/reagent_containers/food/snacks/burrito + voice_order = list("plain burrito") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/spicyburrito + name = "Burrito (Spicy)" + build_path = /obj/item/reagent_containers/food/snacks/burrito_spicy + voice_order = list("spicy burrito") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/meatcheeseburrito + name = "Burrito (Carne Queso)" + build_path = /obj/item/reagent_containers/food/snacks/burrito_cheese + voice_order = list("meat and cheese burrito", "carne queso burrito") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/spicycheeseburrito + name = "Burrito (Spicy Cheese)" + build_path = /obj/item/reagent_containers/food/snacks/burrito_cheese_spicy + voice_order = list("spicy cheese burrito", "calente queso burrito") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/lunchmenu/veganburrito + name = "Burrito (Vegan)" + build_path = /obj/item/reagent_containers/food/snacks/burrito_vegan + voice_order = list("veggie burrito", "vegan burrito") + voice_temp = VOICE_TEMP_HOT + +/********* +* Dinner * +**********/ + +//American Continents +/datum/category_item/synthesizer/dinnermenu/ribplate + name = "Rib plate" + build_path = /obj/item/reagent_containers/food/snacks/ribplate + voice_order = list("plate of ribs", "rib plate") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/baconburger + name = "Burger (Bacon)" + build_path = /obj/item/reagent_containers/food/snacks/burger/bacon + voice_order = list("bacon burger", "burger with bacon") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/taco + name = "Taco" + build_path = /obj/item/reagent_containers/food/snacks/taco + voice_order = list("regular taco") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/fishtaco + name = "Fish Taco" + build_path = /obj/item/reagent_containers/food/snacks/fish_taco + voice_order = list("fish taco") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/enchiladas + name = "Enchiladas" + build_path = /obj/item/reagent_containers/food/snacks/enchiladas + voice_order = list("enchiladas") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/turkey + name = "Turkey (Whole)" + build_path = /obj/item/reagent_containers/food/snacks/sliceable/turkey + voice_order = list("turkey", "whole turkey") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/tofurkey + name = "Tofurkey (Whole)" + build_path = /obj/item/reagent_containers/food/snacks/tofurkey + voice_order = list("tofurkey", "tofu turkey", "whole tofurkey") + voice_temp = VOICE_TEMP_HOT + +//European + +/datum/category_item/synthesizer/dinnermenu/loadedpotato + name = "Loaded Baked Potato" + build_path = /obj/item/reagent_containers/food/snacks/loadedbakedpotato + voice_order = list("loaded potato", "baked loaded potato", "loaded baked potato") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/britishpotatos + name = "Bangers and Mash" + build_path = /obj/item/reagent_containers/food/snacks/bangersandmash + voice_order = list("bangers and mash", "sausage and potatoes") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/cheesemash + name = "Cheesy Mashed Potato" + build_path = /obj/item/reagent_containers/food/snacks/cheesymash + voice_order = list("cheese potatoes", "cheese mashed potatoes") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/zestfish + name = "Zesty Fish" + build_path = /obj/item/reagent_containers/food/snacks/zestfish + voice_order = list("zesty fish", "fish dinner") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/meatpie + name = "Pie (Meat)" + build_path = /obj/item/reagent_containers/food/snacks/meatpie + voice_order = list("meat pie", "pie of meat") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/tofupie + name = "Pie (Tofu)" + build_path = /obj/item/reagent_containers/food/snacks/tofupie + voice_order = list("tofu pie", "pie of tofu") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/plumppie + name = "Pie (Mushroom)" + build_path = /obj/item/reagent_containers/food/snacks/plump_pie + voice_order = list("mushroom pie", "plump hemlet pie") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/lasagna + name = "Lasagne" + build_path = /obj/item/reagent_containers/food/snacks/lasagna + voice_order = list("lasagne", "garfield special") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/baconflatbread + name = "Bacon Flatbread" + build_path = /obj/item/reagent_containers/food/snacks/bacon_flatbread + voice_order = list("bacon flatbread", "bacon with flatbread") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/meatpocket + name = "Meat and Cheese Flatbread" + build_path = /obj/item/reagent_containers/food/snacks/meat_pocket + voice_order = list("meat and cheese flatbread") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/risotto + name = "Risotto" + build_path = /obj/item/reagent_containers/food/snacks/risotto + voice_order = list("bowl of risotto", "regular risotto") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/risottoballs + name = "Risotto Balls" + build_path = /obj/item/reagent_containers/food/snacks/risottoballs + voice_order = list("risotto balls") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/stuffedmeatball + name = "Stuffed Meatball" + build_path = /obj/item/reagent_containers/food/snacks/stuffed_meatball + voice_order = list("stuffed meatball") + voice_temp = VOICE_TEMP_HOT + +//Asian + +/datum/category_item/synthesizer/dinnermenu/redcurry + name = "Red Curry" + build_path = /obj/item/reagent_containers/food/snacks/redcurry + voice_order = list("red curry", "curry red") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/greencurry + name = "Green Curry" + build_path = /obj/item/reagent_containers/food/snacks/greencurry + voice_order = list("green curry", "curry green") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/yellowcurry + name = "Yellow Curry" + build_path = /obj/item/reagent_containers/food/snacks/yellowcurry + voice_order = list("yellow curry", "curry yellow") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/bibimbap + name = "Bibimbap Bowl" //The best thing. Seriously. + build_path = /obj/item/reagent_containers/food/snacks/bibimbap + voice_order = list("bibimbap", "korean hot pot") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/lomein + name = "Lo Mein" + build_path = /obj/item/reagent_containers/food/snacks/lomein + voice_order = list("lo mein", "low main", "chinese noodles") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/friedrice + name = "Fried Rice (Plain)" + build_path = /obj/item/reagent_containers/food/snacks/friedrice + voice_order = list("egg fried rice", "plain fried rice") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/porkbowl + name = "Fried Rice (Pork)" + build_path = /obj/item/reagent_containers/food/snacks/porkbowl + voice_order = list("pork bowl", "pork fried rice") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/sweetnsour + name = "Sweet and Sour Pork" + build_path = /obj/item/reagent_containers/food/snacks/sweet_and_sour + voice_order = list("sweet and sour pork", "sweet sour pork") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/meatbun + name = "Meat and Leaf Bun" + build_path = /obj/item/reagent_containers/food/snacks/meatbun + voice_order = list("baozi", "meat and leaf dumpling", "meat and leaf bun") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/spicedmeatbun + name = "Spiced Meat Bun" + build_path = /obj/item/reagent_containers/food/snacks/spicedmeatbun + voice_order = list("spiced meat bun", "char sui", "char sui bun") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/eggrice + name = "Omelette Rice (regular)" + build_path = /obj/item/reagent_containers/food/snacks/omurice + voice_order = list("regular omelette rice", "regular omurice") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/eggriceheart + name = "Omelette Rice (heart)" + build_path = /obj/item/reagent_containers/food/snacks/omurice/heart + voice_order = list("omelette rice with heart", "omurice heart", "omurice with heart", "heart omurice") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dinnermenu/eggriceface + name = "Omelette Rice (face)" + build_path = /obj/item/reagent_containers/food/snacks/omurice/face + voice_order = list("omelette rice with face", "omurice face", "omurice with face", "face omurice") + voice_temp = VOICE_TEMP_HOT + +/********** +* Dessert * +***********/ + +/datum/category_item/synthesizer/dessert/donut + name = "Donut (Plain)" + build_path = /obj/item/reagent_containers/food/snacks/donut/plain + voice_order = list("plain donut", "donut with nothing") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/chocolate_donut + name = "Donut (Chocolate)" + build_path = /obj/item/reagent_containers/food/snacks/donut/choc + voice_order = list("chocolate donut", "donut with chocolate") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/pink_donut + name = "Donut (Pink Frosting)" + build_path = /obj/item/reagent_containers/food/snacks/donut/pink + voice_order = list("pink frosted donut", "donut with pink frosting") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/homer + name = "Donut (Sprinkles)" + build_path = /obj/item/reagent_containers/food/snacks/donut/homer + voice_order = list("homer donut", "donut with sprinkles") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/jelly_donut + name = "Donut (Jelly)" + build_path = /obj/item/reagent_containers/food/snacks/donut/plain/jelly + voice_order = list("jelly donut", "donut with jelly") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/meat_donut + name = "Donut (Meat)" + build_path = /obj/item/reagent_containers/food/snacks/donut/meat + voice_order = list("meat donut", "donut with meat") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/chaos_donut + name = "Donut (Chaos)" + build_path = /obj/item/reagent_containers/food/snacks/donut/plain + voice_order = list("chaos donut", "donut with chaos", "madness donut") + voice_temp = VOICE_TEMP_COLD + hidden = TRUE + +/datum/category_item/synthesizer/dessert/candyapple + name = "Candied Apple" + build_path = /obj/item/reagent_containers/food/snacks/candiedapple + voice_order = list("candy apple", "candied apple") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/applepie + name = "Pie (Apple)" + build_path = /obj/item/reagent_containers/food/snacks/applepie + voice_order = list("apple pie", "pie with apple", "American pie") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dessert/cherrypie + name = "Pie (Cherry)" + build_path = /obj/item/reagent_containers/food/snacks/cherrypie + voice_order = list("cherry pie", "pie with cherry") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dessert/appletart + name = "Apple Tart" + build_path = /obj/item/reagent_containers/food/snacks/appletart + voice_order = list("apple tart") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dessert/cinnamonbun + name = "cinnamon bun" + build_path = /obj/item/reagent_containers/food/snacks/cinnamonbun + voice_order = list("Cinnamon bun","sweetroll", "cinnabun") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dessert/tastybread + name = "Tubular Sweet Bread" + build_path = /obj/item/reagent_containers/food/snacks/tastybread + voice_order = list("bread tube") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/carrotcake + name = "Carrot Cake" + build_path = /obj/item/reagent_containers/food/snacks/slice/carrotcake/filled + voice_order = list("carrot cake") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/cheesecake + name = "Cheesecake" + build_path = /obj/item/reagent_containers/food/snacks/slice/cheesecake/filled + voice_order = list("cheese cake") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/plaincake + name = "Plain Cake" + build_path = /obj/item/reagent_containers/food/snacks/slice/plaincake/filled + voice_order = list("plain cake") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/orangecake + name = "Orange Cake" + build_path = /obj/item/reagent_containers/food/snacks/slice/orangecake/filled + voice_order = list("orange cake") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/limecake + name = "Lime Cake" + build_path = /obj/item/reagent_containers/food/snacks/slice/limecake/filled + voice_order = list("lime cake") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/lemoncake + name = "Lemon Cake" + build_path = /obj/item/reagent_containers/food/snacks/slice/lemoncake/filled + voice_order = list("lemon cake") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/chocolatecake + name = "Chocolate Cake" + build_path = /obj/item/reagent_containers/food/snacks/slice/chocolatecake/filled + voice_order = list("chocolate cake", "mudpie") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/birthdaycake + name = "Birthday Cake" + build_path = /obj/item/reagent_containers/food/snacks/slice/birthdaycake/filled + voice_order = list("Birthday cake") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/applecake + name = "Apple Cake" + build_path = /obj/item/reagent_containers/food/snacks/slice/applecake/filled + voice_order = list("apple cake") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/pumpkinpie + name = "Pumpkin Pie" + build_path = /obj/item/reagent_containers/food/snacks/slice/pumpkinpie/filled + voice_order = list("pumpkin pie") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dessert/keylimepieslice + name = "Key Lime Pie" + build_path = /obj/item/reagent_containers/food/snacks/keylimepieslice/filled + voice_order = list("key lime pie") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/browniesslice + name = "Brownie" + build_path = /obj/item/reagent_containers/food/snacks/browniesslice/filled + voice_order = list("brownie") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dessert/sugarcookie + name = "Sugar Cookie" + build_path = /obj/item/reagent_containers/food/snacks/sugarcookie + voice_order = list("sugar cookie") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/custardbun + name = "Custard Bun" + build_path = /obj/item/reagent_containers/food/snacks/custardbun + voice_order = list("custard bun") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/honeybun + name = "Honey Bun" + build_path = /obj/item/reagent_containers/food/snacks/honeybun + voice_order = list("honey bun") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/cookie + name = "Cookie" + build_path = /obj/item/reagent_containers/food/snacks/cookie + voice_order = list("plain cookie", "chocolate chip cookie") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dessert/fruitbar + name = "Fruit Bar" + build_path = /obj/item/reagent_containers/food/snacks/fruitbar + voice_order = list("fruit bar") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/pie + name = "Plain Pie" + build_path = /obj/item/reagent_containers/food/snacks/pie + voice_order = list("plain pie", "nothing pie") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dessert/amanita_pie + name = "Amanita Pie" + build_path = /obj/item/reagent_containers/food/snacks/amanita_pie + voice_order = list("amanita pie", "weed pie") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/funnelcake + name = "Funnel Cake" + build_path = /obj/item/reagent_containers/food/snacks/funnelcake + voice_order = list("funnel cake", "fair cake") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dessert/icecreamsandwich + name = "Ice Cream Sandwich" + build_path = /obj/item/reagent_containers/food/snacks/icecreamsandwich + voice_order = list("icecream sandwich", "ice cream sandwich", "sandwich with ice cream") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/dessert/pisanggoreng + name = "Pisang Goreng" + build_path = /obj/item/reagent_containers/food/snacks/pisanggoreng + voice_order = list("pisang goreng", "banana fritter") + voice_temp = VOICE_TEMP_HOT + +/********* +* Exotic * +**********/ + +/datum/category_item/synthesizer/exotic/hatchling_suprise + name = "Hatchling Suprise" + build_path = /obj/item/reagent_containers/food/snacks/hatchling_suprise + voice_order = list("hatchling surpise") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/exotic/red_sun_special + name = "Red Sun Special" + build_path = /obj/item/reagent_containers/food/snacks/red_sun_special + voice_order = list() + voice_temp = "" + +/datum/category_item/synthesizer/exotic/riztizkzi_sea + name = "Moghesian Sea Delight" + build_path = /obj/item/reagent_containers/food/snacks/riztizkzi_sea + voice_order = list() + voice_temp = "" + +/datum/category_item/synthesizer/exotic/father_breakfast + name = "Fatherly Breakfast" + build_path = /obj/item/reagent_containers/food/snacks/father_breakfast + voice_order = list() + voice_temp = "" + +/datum/category_item/synthesizer/exotic/bearburger + name = "Bear Burger" + build_path = /obj/item/reagent_containers/food/snacks/bearburger + voice_order = list() + voice_temp = "" + +/datum/category_item/synthesizer/exotic/namagashi + name = "Ryo-kucha Namagashi" + build_path = /obj/item/reagent_containers/food/snacks/namagashi + voice_order = list() + voice_temp = "" + +/datum/category_item/synthesizer/exotic/dionaroast + name = "Diona Roast" + build_path = /obj/item/reagent_containers/food/snacks/dionaroast + voice_order = list("diona roast", "plant roast") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/exotic/burnedmess + name = "Dubious Food" + build_path = /obj/item/reagent_containers/food/snacks/badrecipe + voice_order = list("right proper fuckup", "Whatever", "my college existance", "chef's disappointment", "Ramsey's nightmare") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/exotic/monkeydelight + name = "Monkey's Delight" + build_path = /obj/item/reagent_containers/food/snacks/monkeysdelight + voice_order = list("fancy banana", "monkey delight") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/exotic/xenopie + name = "Pie (Xeno)" + build_path = /obj/item/reagent_containers/food/snacks/xemeatpie + voice_order = list("xeno pie", "pie of xeno") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/exotic/xenobreadslice + name = "Xeno Bread (Slice)" + build_path = /obj/item/reagent_containers/food/snacks/sliceable/xenomeatbread + voice_order = list("meat bread slice", "slice of meat bread") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/exotic/liquidfood + name = "Liquid Ration (Generic)" + build_path = /obj/item/reagent_containers/food/snacks/liquidfood + voice_order = list("Liquid ration", "food drink", "Liquidfood") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/exotic/liquidprotein + name = "Liquid Ration (Protein)" + build_path = /obj/item/reagent_containers/food/snacks/liquidprotein + voice_order = list("protein liquid ration", "protein ration") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/exotic/liquidvitamin + name = "Liquid Ration (Vitamin)" + build_path = /obj/item/reagent_containers/food/snacks/liquidvitamin + voice_order = list("vitamin liquid ration", "vitamin ration") + voice_temp = VOICE_TEMP_COLD + +/***************** + * FOOKIN RAAAWH * + *****************/ + +/datum/category_item/synthesizer/raw/meat + name = "Meat Steak (raw)" + build_path = /obj/item/reagent_containers/food/snacks/meat + voice_order = list("meat slab","slab of meat","raw steak", "raw meat steak") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/raw/bacon + name = "Bacon (raw)" + build_path = /obj/item/reagent_containers/food/snacks/rawbacon + voice_order = list("raw bacon") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/raw/mushroom + name = "Mushroom Slice" + build_path = /obj/item/reagent_containers/food/snacks/mushroomslice + voice_order = list("mushroom slice", "raw mushroom") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/raw/tomato + name = "Tomato Steak (raw)" + build_path = /obj/item/reagent_containers/food/snacks/tomatomeat + voice_order = list("tomato slice") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/raw/bear + name = "Bear Steak (raw)" + build_path = /obj/item/reagent_containers/food/snacks/bearmeat + voice_order = list("raw bear steak", "slice of bear") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/raw/xeno + name = "Xeno Steak (raw)" + build_path = /obj/item/reagent_containers/food/snacks/xenomeat + voice_order = list("raw xeno steak") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/raw/spider + name = "Spider Steak (raw)" + build_path = /obj/item/reagent_containers/food/snacks/xenomeat/spidermeat + voice_order = list("raw spider steak") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/raw/spahgetti + name = "Spaghetti (raw)" + build_path = /obj/item/reagent_containers/food/snacks/spagetti + voice_order = list("raw spaghetti", "uncooked spaghett") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/raw/corgi + name = "Corgi Steak (raw)" + build_path = /obj/item/reagent_containers/food/snacks/meat/corgi + voice_order = list("Dog steak", "Dog", "Canine steak") + voice_temp = VOICE_TEMP_COLD + hidden = TRUE + +/datum/category_item/synthesizer/raw/waferblock + name = "Nutrient paste wafer" + build_path = /obj/item/reagent_containers/food/snacks/synthsized_meal + voice_order = list("paste block") + voice_temp = VOICE_TEMP_COLD + +/datum/category_item/synthesizer/raw/wafercrewblock + name = "Generic Crew Cookie" + build_path = /obj/item/reagent_containers/food/snacks/synthsized_meal/crewblock + voice_order = list("crew block") + voice_temp = VOICE_TEMP_COLD + +/********* +* Crew Cookie * +**********/ +/datum/category_item/synthesizer/crew/crewcookie + name = "Generic Crew Cookie" + build_path = /obj/item/reagent_containers/food/snacks/synthsized_meal/crewblock + voice_order = list("crew cookie") + voice_temp = VOICE_TEMP_HOT + +/datum/category_item/synthesizer/dd_SortValue() + return name + +#undef VOICE_TEMP_COLD +#undef VOICE_TEMP_HOT diff --git a/code/modules/mob/living/carbon/taste.dm b/code/modules/mob/living/carbon/taste.dm index 205a875d7e..bf044d1960 100644 --- a/code/modules/mob/living/carbon/taste.dm +++ b/code/modules/mob/living/carbon/taste.dm @@ -38,7 +38,7 @@ calculate text size per text. for(var/datum/reagent/R in reagent_list) if(!R.taste_mult) continue - if(R.id == REAGENT_ID_NUTRIMENT) //this is ugly but apparently only nutriment (not subtypes) has taste data TODO figure out why + if(R.id == REAGENT_ID_NUTRIMENT || R.id == REAGENT_ID_NUTRIPASTE) //this is ugly but apparently only nutriment (not subtypes) has taste data TODO figure out why var/list/taste_data = R.get_data() for(var/taste in taste_data) if(taste in tastes) diff --git a/code/modules/resleeving/infocore_records.dm b/code/modules/resleeving/infocore_records.dm index 6e16b5e554..7b2f1c07a0 100644 --- a/code/modules/resleeving/infocore_records.dm +++ b/code/modules/resleeving/infocore_records.dm @@ -101,7 +101,7 @@ var/aflags var/breath_type = GAS_O2 -/datum/transhuman/body_record/New(copyfrom, add_to_db = 0, ckeylock = 0) +/datum/transhuman/body_record/New(copyfrom, add_to_db = FALSE, ckeylock = FALSE) ..() if(istype(copyfrom, /datum/transhuman/body_record)) init_from_br(copyfrom) @@ -118,7 +118,7 @@ ..() return QDEL_HINT_HARDDEL // For now at least there is no easy way to clear references to this in GLOB.machines etc. -/datum/transhuman/body_record/proc/init_from_mob(mob/living/carbon/human/M, add_to_db = 0, ckeylock = 0, database_key) +/datum/transhuman/body_record/proc/init_from_mob(mob/living/carbon/human/M, add_to_db = FALSE, ckeylock = FALSE, database_key) ASSERT(!QDELETED(M)) ASSERT(istype(M)) @@ -212,7 +212,6 @@ for(var/datum/modifier/mod as anything in M.modifiers) if(mod.flags & MODIFIER_GENETIC) genetic_modifiers.Add(mod.type) - if(add_to_db) SStranscore.add_body(src, database_key = database_key) diff --git a/icons/obj/machines/foodsynthesizer.dmi b/icons/obj/machines/foodsynthesizer.dmi new file mode 100644 index 0000000000..e70eb13b2b Binary files /dev/null and b/icons/obj/machines/foodsynthesizer.dmi differ diff --git a/tgui/bun.lock b/tgui/bun.lock index 731e55e201..c809ff4c71 100644 --- a/tgui/bun.lock +++ b/tgui/bun.lock @@ -6,8 +6,8 @@ "name": "tgui-workspace", "devDependencies": { "@happy-dom/global-registrator": "^20.10.6", - "@rspack/cli": "^2.1.1", - "@rspack/core": "^2.1.1", + "@rspack/cli": "^2.1.2", + "@rspack/core": "^2.1.2", "@testing-library/react": "^16.3.2", "@types/bun": "^1.3.14", "@types/react": "^19.2.17", @@ -33,7 +33,7 @@ "version": "2.0.0", "dependencies": { "svgo": "^4.0.1", - "svgtofont": "^6.5.2", + "svgtofont": "^6.5.3", }, }, "packages/tgui": { @@ -46,14 +46,14 @@ "es-toolkit": "^1.49.0", "highlight.js": "^11.11.1", "jotai": "^2.20.1", - "js-yaml": "^5.2.0", + "js-yaml": "^5.2.1", "marked": "^18.0.5", "marked-base-url": "^1.1.9", "marked-smartypants": "^1.1.12", "react": "^19.2.7", "react-dom": "^19.2.7", "react-json-tree": "^0.20.0", - "tgui-core": "^6.1.0", + "tgui-core": "^6.1.1", "tgui-dev-server": "workspace:*", }, }, @@ -77,7 +77,7 @@ "react": "^19.2.7", "react-dom": "^19.2.7", "tgui": "workspace:*", - "tgui-core": "^6.1.0", + "tgui-core": "^6.1.1", "tgui-dev-server": "workspace:*", "zod": "^4.4.3", }, @@ -90,7 +90,7 @@ "react": "^19.2.7", "react-dom": "^19.2.7", "tgui": "workspace:*", - "tgui-core": "^6.1.0", + "tgui-core": "^6.1.1", }, }, "packages/tgui-setup": { @@ -143,7 +143,7 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.2" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg=="], "@nozbe/microfuzz": ["@nozbe/microfuzz@1.0.0", "", {}, "sha512-XKIg/guk+s1tkPTkHch9hfGOWgsKojT7BqSQddXTppOfVr3SWQhhTCqbgQaPTbppf9gc2kFeG0gpBZZ612UXHA=="], @@ -181,35 +181,35 @@ "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], - "@rspack/binding": ["@rspack/binding@2.1.1", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "2.1.1", "@rspack/binding-darwin-x64": "2.1.1", "@rspack/binding-linux-arm64-gnu": "2.1.1", "@rspack/binding-linux-arm64-musl": "2.1.1", "@rspack/binding-linux-riscv64-gnu": "2.1.1", "@rspack/binding-linux-riscv64-musl": "2.1.1", "@rspack/binding-linux-x64-gnu": "2.1.1", "@rspack/binding-linux-x64-musl": "2.1.1", "@rspack/binding-wasm32-wasi": "2.1.1", "@rspack/binding-win32-arm64-msvc": "2.1.1", "@rspack/binding-win32-ia32-msvc": "2.1.1", "@rspack/binding-win32-x64-msvc": "2.1.1" } }, "sha512-6062hZP33fn1w51ClpQnum19GGXl/3eS754xrRYbQ7wwBNZk94HVwfSyiqcNCtY/pB1lsFjnaTKiW/Q+jv0axQ=="], + "@rspack/binding": ["@rspack/binding@2.1.2", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "2.1.2", "@rspack/binding-darwin-x64": "2.1.2", "@rspack/binding-linux-arm64-gnu": "2.1.2", "@rspack/binding-linux-arm64-musl": "2.1.2", "@rspack/binding-linux-riscv64-gnu": "2.1.2", "@rspack/binding-linux-riscv64-musl": "2.1.2", "@rspack/binding-linux-x64-gnu": "2.1.2", "@rspack/binding-linux-x64-musl": "2.1.2", "@rspack/binding-wasm32-wasi": "2.1.2", "@rspack/binding-win32-arm64-msvc": "2.1.2", "@rspack/binding-win32-ia32-msvc": "2.1.2", "@rspack/binding-win32-x64-msvc": "2.1.2" } }, "sha512-/mFcRSUW7Pl19KeaBIujJvZYNJQu0wD5D3aa5h+Qcph26v7nmLYlX7eajIHGi8tt2qTZX1lXifw2KLIXKwYaRQ=="], - "@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@2.1.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6K8jA3pZphBwLt5DU78wl0IzY1myHrqNSvFVCd9CHa+szlOwv2iMQpZdYdpupIBxwiZ39rrDyQKtoZw7lsAG8w=="], + "@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@2.1.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-IYcxareUOYJZz+uNMSIwn+iDRiVyjZNOjoxO/zL4OFaPK8Ncrw0ka/9DqL9Gd7OpnAXN1zK3uS8yD0O1yIYI3Q=="], - "@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@2.1.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-RdqtEfIbSe5ucLNVvMac1k88UwmL4Gil8uXqlEFcSZ3VC2jTOkecadd+B0RYqJ+PirSInrRmKm1cr0740zppOA=="], + "@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@2.1.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-aoifkILvx/XEHyvg8yW57xu95nx7f9f/3ah1+RguHSNKcJMcoCep9VX1Ct1N0ftqg8MC0JUObc7xWL5W14hmjA=="], - "@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@2.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-ROKtqXoLpbZO1vYEcNxQg6COvRhdlJcoib1Z4pzG1nIyctEAUuFmnD7pIvJiVe6M7YuJNXW+1p0BhpptT2XEUQ=="], + "@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@2.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-My4m40tyJSgiCEf3bB2KIEX710q3nZg99LIjy+8Zxgi3oZTkg1bFmFRusFU5U4eN5408zfSqDDGvjDE3Yv7o4w=="], - "@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@2.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-QdQpG9dK0GfPASjBd/8rUwDNW0ShfFfYJfcoGLNTM6A8EqmgvWwklXDiCVF5dXALbZIksAuRznIKnLDsUoXi9Q=="], + "@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@2.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-yt+GGWUH7WPE8K97cRc8OpZhH7Pbj1vU+lkvKbDtF/rR8X9a/bJsA/nBqyUV2oBKOVbrp5I8rFZlnDskMqgvKw=="], - "@rspack/binding-linux-riscv64-gnu": ["@rspack/binding-linux-riscv64-gnu@2.1.1", "", { "os": "linux", "cpu": "none" }, "sha512-LGdYCAvblZp2qtHk9UseYftIRyaBzSWqEzd1toaS08sYESXERm+YBbrYKKiyq1yXiU1L7BkhMUxiWc3GCYmKcA=="], + "@rspack/binding-linux-riscv64-gnu": ["@rspack/binding-linux-riscv64-gnu@2.1.2", "", { "os": "linux", "cpu": "none" }, "sha512-uys8Jyw8Z3ralvICbN/L/nZfy5qELIwpOY72rhIqhoDYwFcL4fmMaY7WsvUcJOjCB2rqOcWPaWKuF2oPvo9iDQ=="], - "@rspack/binding-linux-riscv64-musl": ["@rspack/binding-linux-riscv64-musl@2.1.1", "", { "os": "linux", "cpu": "none" }, "sha512-87phiiPGFT1p4gy3Oz6YdNijCPXdjJy43LFdE8AFiZsV4ChFXQPqnVCF2aMRLybYa51A+9wGYlTvxt09yUQUww=="], + "@rspack/binding-linux-riscv64-musl": ["@rspack/binding-linux-riscv64-musl@2.1.2", "", { "os": "linux", "cpu": "none" }, "sha512-JYNVQwqCaRGQWvjHQYzZkIzQiwllMaJwh4Rdu3ww6W2OJcJUqT08sL1pkOtU0iCxT4VUYiRRcp93VGTGpHr8fg=="], - "@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@2.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-om0/PvZzxISsnyz3hdmI3xBi3Qsn6faRGrfp6WJpGHa5JYYaRVWz1MJ9fe+/cQE9ON9r32HpMOeuataCLv+Owg=="], + "@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@2.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-KDoPy0Msf/JLhxgPPrJQzZeB4Qpqd32em8AP5lSW2s6jR5I35dHgAe9xc2A++EQtnSrU4GTn6DBvFC7q84SihQ=="], - "@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@2.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-YgAyTOM5ZWvWT0Exwcg7QkGUv9PsHT4yIsEyJbH+a99uAKliGMwkHIOP/aJgrCF8G+lTfigY2wyl9cWo4TA4aw=="], + "@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@2.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-66hWmIGvn4zCKAYXJE9Bp5SNSLYnLFq2Ke/efE+ZtWy43Dd5vk9AAOmThVGBwdwmIxmGtHGCp+cAuS4G0wu0TA=="], - "@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@2.1.1", "", { "dependencies": { "@emnapi/core": "1.11.1", "@emnapi/runtime": "1.11.1", "@napi-rs/wasm-runtime": "1.1.5" }, "cpu": "none" }, "sha512-OicgaB3Dcd+KXsH/I3DkJG7XQyREJScg/jLkCtycFn9BhT0IVJvgi37F8QNJKl8Bp9YZIGehsqK9HpQWav6SLw=="], + "@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@2.1.2", "", { "dependencies": { "@emnapi/core": "1.11.1", "@emnapi/runtime": "1.11.1", "@napi-rs/wasm-runtime": "1.1.6" }, "cpu": "none" }, "sha512-EB4SqH8DW/E/OmqssNQvnIVGQiVUyYNlA/pcc6Ia4MlTNwu6eNDppcNLrToH+kSZpL4CpHSFfSM3eIsSuar2Rw=="], - "@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@2.1.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-fwL4P3SsC0r/vVGgnmexnc4vkvf+9vWMcGw5fdlPBJNR/zWlZRSXR5V6eXcHrpYVLhBsLYvZYE3NZa9paIUGxw=="], + "@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@2.1.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-T6Fs/g32MRja/UpCq4AdyPRj8tA0cOkcEa4PrAcn/ztUgK8b/qMVxj5mhMI+n7k+kHZQnpeB1Q4HqdSJi6OocA=="], - "@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@2.1.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-j3BISXbjPyI57HeHxW9Jx+UP7RebNQ4t62uCbRP29caf9aghYJP+ZA5nJ2X7pol7N5Je2/V6WNahuNd0zQFDOA=="], + "@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@2.1.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-OtxkFVz14mVL4QK8QriSELn9B6PaYGHw1jGJwVDEzpu2ZxSHCTQPz9dVE1ekYtREEqZUkRU7Fp7VfhJSmjTt2Q=="], - "@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@2.1.1", "", { "os": "win32", "cpu": "x64" }, "sha512-aPNNFuZT5iBM8+S9J4P5ywJbf3tUvZN3Ppe6mXJ8/jTVDUDhe0YVj3AgD/AuxnUvl+yHrLfQkN1nNwUfIcomfA=="], + "@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@2.1.2", "", { "os": "win32", "cpu": "x64" }, "sha512-Am+nx9fLF3nzgD/K05Bs1Bb+WO8SFLWAYRbXkymaL1r+RQxjRj7jd5ap2PhGOCcfaNA4yVWkAFvmFP92eRu7bQ=="], - "@rspack/cli": ["@rspack/cli@2.1.1", "", { "peerDependencies": { "@rspack/core": "^2.0.0-0", "@rspack/dev-server": "^2.0.0-0" }, "optionalPeers": ["@rspack/dev-server"], "bin": { "rspack": "./bin/rspack.js" } }, "sha512-zsJFurwCDesy0dud7cejObagbbXsvKcQ6j485nmnytBsXV17Uf6XfedQMxnOXBZeGIel+I7Jl/Jp3Sn08TsZuw=="], + "@rspack/cli": ["@rspack/cli@2.1.2", "", { "peerDependencies": { "@rspack/core": "^2.0.0-0", "@rspack/dev-server": "^2.0.0-0" }, "optionalPeers": ["@rspack/dev-server"], "bin": { "rspack": "./bin/rspack.js" } }, "sha512-GTBsKuaeqDii6NaGPkQwvycMSjqMUMMRGiAwH0sXsFIn8X7sFa4xpoL7pIhbebVBDGzYhUBqWzNQFuL5u2FeoQ=="], - "@rspack/core": ["@rspack/core@2.1.1", "", { "dependencies": { "@rspack/binding": "2.1.1" }, "peerDependencies": { "@module-federation/runtime-tools": "^0.24.1 || ^2.0.0", "@swc/helpers": "^0.5.23" }, "optionalPeers": ["@module-federation/runtime-tools", "@swc/helpers"] }, "sha512-Rgz6xZcD0rm7ejZhYNi13qvW2dSnIQQt/7D3xbYoT5hOU838JbkF0P3SAMFGKE+FyLZswnyRpxGfnYHZQqDmJA=="], + "@rspack/core": ["@rspack/core@2.1.2", "", { "dependencies": { "@rspack/binding": "2.1.2" }, "peerDependencies": { "@module-federation/runtime-tools": "^0.24.1 || ^2.0.0", "@swc/helpers": "^0.5.23" }, "optionalPeers": ["@module-federation/runtime-tools", "@swc/helpers"] }, "sha512-crpNQKhHfnzrIl4Sa4fjH30Ho5aAPgyqpmJZ41SkUFOzyKHdZKYfE5LF3CMh7MiFQFPPxiiKf5BcpxmtZZx4MQ=="], "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="], @@ -507,7 +507,7 @@ "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "js-yaml": ["js-yaml@5.2.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.mjs" } }, "sha512-YeLUMlvR4Ou1B119LIaM0r65JvbOBooJDc9yEu0dClb/uSC5P4FrLU8OCCz/HXWvtPoIrR0dRzABTjo1sTN9Bw=="], + "js-yaml": ["js-yaml@5.2.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.mjs" } }, "sha512-zfLtNfQqxVqq3uaTqSkh4x4hZw3KHobGUA0fJUj4wawW8bsQLTVqpHdXSIzidh7o+4lEW36tANuAGdaFx6Zgnw=="], "jsonc-eslint-parser": ["jsonc-eslint-parser@2.4.2", "", { "dependencies": { "acorn": "^8.5.0", "eslint-visitor-keys": "^3.0.0", "espree": "^9.0.0", "semver": "^7.3.5" } }, "sha512-1e4qoRgnn448pRuMvKGsFFymUCquZV0mpGgOyIKNgD3JVDTsVJyRBGH/Fm0tBb8WsWGgmB1mDe6/yJMQM37DUA=="], @@ -609,7 +609,7 @@ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], @@ -757,7 +757,7 @@ "svgpath": ["svgpath@2.6.0", "", {}, "sha512-OIWR6bKzXvdXYyO4DK/UWa1VA1JeKq8E+0ug2DG98Y/vOmMpfZNj+TIG988HjfYSqtcy/hFOtZq/n/j5GSESNg=="], - "svgtofont": ["svgtofont@6.5.2", "", { "dependencies": { "auto-config-loader": "^2.0.0", "cheerio": "~1.0.0", "colors-cli": "~1.0.28", "fs-extra": "~11.2.0", "image2uri": "^2.1.2", "nunjucks": "^3.2.4", "svg2ttf": "~6.1.0", "svgicons2svgfont": "~15.0.0", "svgo": "~3.3.0", "ttf2eot": "~3.1.0", "ttf2woff": "~3.0.0", "ttf2woff2": "~8.0.0", "yargs": "^17.7.2" }, "peerDependencies": { "@types/svg2ttf": "~5.0.1" }, "optionalPeers": ["@types/svg2ttf"], "bin": { "svgtofont": "lib/cli.js" } }, "sha512-D9aqybvt3yXIi4RLPbPDXwX9fvoTKN8HeiBeRA7Yb+5TtfdF9Bz9/TGZHEu+hlRtAmlZ3YBBluElfy9BMitcoA=="], + "svgtofont": ["svgtofont@6.5.3", "", { "dependencies": { "auto-config-loader": "^2.0.0", "cheerio": "~1.0.0", "colors-cli": "~1.0.28", "fs-extra": "~11.2.0", "image2uri": "^2.1.2", "nunjucks": "^3.2.4", "svg2ttf": "~6.1.0", "svgicons2svgfont": "~15.0.0", "svgo": "~3.3.0", "ttf2eot": "~3.1.0", "ttf2woff": "~3.0.0", "ttf2woff2": "~8.0.0", "yargs": "^17.7.2" }, "peerDependencies": { "@types/svg2ttf": "~5.0.1" }, "optionalPeers": ["@types/svg2ttf"], "bin": { "svgtofont": "lib/cli.js" } }, "sha512-koKMwoA+olMx7qY2LzdVF1+5/y0c1Tu1iZinTCClF4c5UVrSpExayMoyHqLB/58aTe5EUuE6htg5S2Y/MN4Azw=="], "sync-child-process": ["sync-child-process@1.0.2", "", { "dependencies": { "sync-message-port": "^1.0.0" } }, "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA=="], @@ -773,7 +773,7 @@ "tgui": ["tgui@workspace:packages/tgui"], - "tgui-core": ["tgui-core@6.1.0", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@nozbe/microfuzz": "^1.0.0" }, "peerDependencies": { "react": "^19.1.0", "react-dom": "^19.1.0" } }, "sha512-j512gHwvK8aPILIxS26LLHMRpO/EXn5pIiIdGphpqbDIe6ir3SpXDK+wfuEZ/5LxXlP6UQCxSSduR3JI8frIIg=="], + "tgui-core": ["tgui-core@6.1.1", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@nozbe/microfuzz": "^1.0.0" }, "peerDependencies": { "react": "^19.1.0", "react-dom": "^19.1.0" } }, "sha512-RiINJPsKLvaC4qkKtPdwoe9t08bTuUW8bpHDEIv3P6eZYJZfNSJwPy/hvdiVSeBA1V4ZtDTd+XADWsUzUVlMZA=="], "tgui-dev-server": ["tgui-dev-server@workspace:packages/tgui-dev-server"], @@ -861,7 +861,7 @@ "@npmcli/agent/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "@parcel/watcher/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], "cacache/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], @@ -893,6 +893,8 @@ "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "readdirp/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + "sass/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], "socks-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], @@ -909,8 +911,6 @@ "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - "tinyglobby/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], - "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], diff --git a/tgui/package.json b/tgui/package.json index 472e8963b4..05b3f08d73 100644 --- a/tgui/package.json +++ b/tgui/package.json @@ -4,8 +4,8 @@ "type": "module", "devDependencies": { "@happy-dom/global-registrator": "^20.10.6", - "@rspack/cli": "^2.1.1", - "@rspack/core": "^2.1.1", + "@rspack/cli": "^2.1.2", + "@rspack/core": "^2.1.2", "@testing-library/react": "^16.3.2", "@types/bun": "^1.3.14", "@types/react": "^19.2.17", diff --git a/tgui/packages/tgfont/package.json b/tgui/packages/tgfont/package.json index 6734261534..5b8cd2ee5c 100644 --- a/tgui/packages/tgfont/package.json +++ b/tgui/packages/tgfont/package.json @@ -8,6 +8,6 @@ }, "dependencies": { "svgo": "^4.0.1", - "svgtofont": "^6.5.2" + "svgtofont": "^6.5.3" } } diff --git a/tgui/packages/tgui-panel/package.json b/tgui/packages/tgui-panel/package.json index d7e19a918c..7b6e1964ed 100644 --- a/tgui/packages/tgui-panel/package.json +++ b/tgui/packages/tgui-panel/package.json @@ -9,7 +9,7 @@ "react": "^19.2.7", "react-dom": "^19.2.7", "tgui": "workspace:*", - "tgui-core": "^6.1.0", + "tgui-core": "^6.1.1", "tgui-dev-server": "workspace:*", "zod": "^4.4.3" }, diff --git a/tgui/packages/tgui-say/package.json b/tgui/packages/tgui-say/package.json index af0f719675..4db11b002e 100644 --- a/tgui/packages/tgui-say/package.json +++ b/tgui/packages/tgui-say/package.json @@ -6,7 +6,7 @@ "react": "^19.2.7", "react-dom": "^19.2.7", "tgui": "workspace:*", - "tgui-core": "^6.1.0" + "tgui-core": "^6.1.1" }, "private": true } diff --git a/tgui/packages/tgui/interfaces/FoodSynthesizer/CrewCookieIcon.tsx b/tgui/packages/tgui/interfaces/FoodSynthesizer/CrewCookieIcon.tsx new file mode 100644 index 0000000000..fe425d790a --- /dev/null +++ b/tgui/packages/tgui/interfaces/FoodSynthesizer/CrewCookieIcon.tsx @@ -0,0 +1,22 @@ +import { useBackend } from 'tgui/backend'; +import { Icon, Image } from 'tgui-core/components'; +import type { Data } from './types'; + +export const CrewCookieIcon = (props) => { + const { act, data } = useBackend(); + const { crewicon } = data; + + return ( + <> + {crewicon ? ( + + ) : ( + + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/FoodSynthesizer/SubTabs/FoodMenuTabs.tsx b/tgui/packages/tgui/interfaces/FoodSynthesizer/SubTabs/FoodMenuTabs.tsx new file mode 100644 index 0000000000..422c467027 --- /dev/null +++ b/tgui/packages/tgui/interfaces/FoodSynthesizer/SubTabs/FoodMenuTabs.tsx @@ -0,0 +1,31 @@ +import { useBackend } from 'tgui/backend'; +import { Stack, Tabs } from 'tgui-core/components'; +import type { Data } from '../types'; + +export const FoodMenuTabs = (props) => { + const { act, data } = useBackend(); + const { active_menu, menucatagories } = data; + + const menusToShow = [...menucatagories].sort( + (a, b) => a.sortorder - b.sortorder, + ); + + return ( + + + + {menusToShow.map((menu) => ( + act('setactive_menu', { setactive_menu: menu.id })} + > + {menu.name} + + ))} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/FoodSynthesizer/SubTabs/FoodSelectionMenu.tsx b/tgui/packages/tgui/interfaces/FoodSynthesizer/SubTabs/FoodSelectionMenu.tsx new file mode 100644 index 0000000000..801dfbbf12 --- /dev/null +++ b/tgui/packages/tgui/interfaces/FoodSynthesizer/SubTabs/FoodSelectionMenu.tsx @@ -0,0 +1,182 @@ +import { sanitizeCssClassName } from 'common/css_sanity'; +import { useEffect } from 'react'; +import { useBackend } from 'tgui/backend'; +import { + Box, + Button, + LabeledList, + Section, + Stack, + Tabs, +} from 'tgui-core/components'; +import { classes } from 'tgui-core/react'; +import { CrewCookieIcon } from '../CrewCookieIcon'; +import type { Data } from '../types'; + +export const FoodSelectionMenu = (props) => { + const { act, data } = useBackend(); + const { + busy, + menucatagories, + active_menu, + activefood, + crew_cookies, + activecrew, + } = data; + crew_cookies; + + const recipesToShow = menucatagories + .find((category) => category.id === active_menu) + ?.recipes.filter((recipe) => !recipe.hidden) + .sort((a, b) => a.name.localeCompare(b.name)); + + const selectedFood = recipesToShow?.find((c) => c.type === activefood); + const selectedCrew = crew_cookies.find((c) => c.name === activecrew); + + useEffect(() => { + if (active_menu !== 'crew' && !selectedFood && recipesToShow?.length) { + act('setactive_food', { setactive_food: recipesToShow[0].type }); + } + }, [active_menu]); + + if (!recipesToShow) { + return No recipes found!; + } + + const cookiesToShow = crew_cookies + .filter((cookie) => cookie.category === active_menu) + .sort((a, b) => a.name.localeCompare(b.name)); + + return ( +
+ + +
act('refresh')} + tooltip="Refresh" + icon="arrows-rotate" + /> + ) + } + > + + {active_menu === 'crew' + ? cookiesToShow.map((cookie) => ( + + + + )) + : recipesToShow.map((recipe) => ( + + + + ))} + +
+
+ + {active_menu === 'crew' ? ( + selectedCrew ? ( +
+ + + + + {selectedCrew.name} + + + {selectedCrew.species} + + + + + + + +
+ ) : ( + Please select an offering. + ) + ) : selectedFood ? ( +
+ + + + + {selectedFood.name} + + + + {selectedFood.desc || 'No description available.'} + + + + + + + + +
+ ) : ( + Please select an offering. + )} +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/FoodSynthesizer/SubTabs/SynthCartGuage.tsx b/tgui/packages/tgui/interfaces/FoodSynthesizer/SubTabs/SynthCartGuage.tsx new file mode 100644 index 0000000000..6c712e6650 --- /dev/null +++ b/tgui/packages/tgui/interfaces/FoodSynthesizer/SubTabs/SynthCartGuage.tsx @@ -0,0 +1,33 @@ +import { useBackend } from 'tgui/backend'; +import { Box, LabeledList, ProgressBar, Section } from 'tgui-core/components'; +import type { Data } from '../types'; + +/** Displays the current Cartridge status. */ +export const SynthCartGuage = (props) => { + const { data } = useBackend(); + const { isThereCart, cartFillStatus = 0 } = data; + const adjustedCartChange = cartFillStatus / 100; + + return ( +
+ {isThereCart ? ( + + + + ) : ( + + + One or more cartridges are missing or damaged.
+
+ Sabresnacks Co. recommends ordering a genuine Sabresnacks + replacement cartridge through your local logistical cargo service. +
+
+ )} +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/FoodSynthesizer/index.tsx b/tgui/packages/tgui/interfaces/FoodSynthesizer/index.tsx new file mode 100644 index 0000000000..0f972c507e --- /dev/null +++ b/tgui/packages/tgui/interfaces/FoodSynthesizer/index.tsx @@ -0,0 +1,29 @@ +import { Window } from 'tgui/layouts'; +import { Section, Stack } from 'tgui-core/components'; +import { FoodMenuTabs } from './SubTabs/FoodMenuTabs'; +import { FoodSelectionMenu } from './SubTabs/FoodSelectionMenu'; +import { SynthCartGuage } from './SubTabs/SynthCartGuage'; + +export const FoodSynthesizer = (props) => { + return ( + + + + +
+ +
+
+ +
+ +
+
+ + + +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/FoodSynthesizer/types.ts b/tgui/packages/tgui/interfaces/FoodSynthesizer/types.ts new file mode 100644 index 0000000000..3fe7dff377 --- /dev/null +++ b/tgui/packages/tgui/interfaces/FoodSynthesizer/types.ts @@ -0,0 +1,35 @@ +import type { BooleanLike } from 'tgui-core/react'; + +type MenuCategory = { + id: string; + name: string; + ref: string; + recipes: Recipe[]; + sortorder: number; +}; + +type Recipe = { + type: string; + name: string; + ref: string; + desc?: string; + hidden?: BooleanLike; +}; + +type CrewCookie = { + name: string; + species: string; + category: string; +}; + +export type Data = { + busy: BooleanLike; + isThereCart: BooleanLike; + cartFillStatus?: number; + active_menu: string; + menucatagories: MenuCategory[]; + activefood: string | null; + crew_cookies: CrewCookie[]; + activecrew: string | null; + crewicon?: string; +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/general/SubtabSettings.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/general/SubtabSettings.tsx index 36ed06f6ca..4139cd219c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/general/SubtabSettings.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/general/SubtabSettings.tsx @@ -66,6 +66,7 @@ export const SubtabSettings = (props: { borg_petting, resleeve_lock, resleeve_scan, + synth_cookie, mind_scan, vantag_volunteer, vantag_preference, @@ -239,6 +240,15 @@ export const SubtabSettings = (props: { {resleeve_scan ? 'Yes' : 'No'} + + +