mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-20 11:35:19 +01:00
Food Synthesizers (#19569)
* Food Synthesizers
Initial port, need to figure out what madness you people have done to tgui... and sprite sheets.
At this moment, it compiles but I haven't tested it yet. Too eepy
* iconforge spritesheet nonsense
* Cleaning up tgui menu
full disclosure, After six plus hours of trying to figure out how to do the spritesheets and the tgui stuff I just gave up on this particular bit and threw it into Gemini for a looksie over.
As it's originally my code I figure it's worth at least a reasonable proof read. The side-by-side comparison is pretty wild.
* Passes tgu-lint building
* Appease Gripe err Grep checks
* Oh these for the grep as well whoops
* Sorts out the backend
also piss off linter check, it's COMMENTED OUT aaaaaaaaaa.
* changes from will
* changes from will and some UI splitting, needs proper testing and final adjustments
* passadata
* .
* can be combined
* .
* ml={1}
* id
* Crew category
* id handling
* .
* more cleanup
* smaller cleanup
* why not
* deps up, minor tgui core fix
* timer
* .
* .
* missed to put that back
* order
* this
* Change preference category for foodsynth cookies
* Enforce south facement for cookie image
* Maurice I am no longer asking
* .
---------
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
+30
-30
@@ -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=="],
|
||||
|
||||
+2
-2
@@ -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",
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"svgo": "^4.0.1",
|
||||
"svgtofont": "^6.5.2"
|
||||
"svgtofont": "^6.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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<Data>();
|
||||
const { crewicon } = data;
|
||||
|
||||
return (
|
||||
<>
|
||||
{crewicon ? (
|
||||
<Image
|
||||
src={crewicon.substring(1, crewicon.length - 1)}
|
||||
width="128px"
|
||||
height="128px"
|
||||
/>
|
||||
) : (
|
||||
<Icon width="128px" height="128px" fontSize={4} name="camera" />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -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<Data>();
|
||||
const { active_menu, menucatagories } = data;
|
||||
|
||||
const menusToShow = [...menucatagories].sort(
|
||||
(a, b) => a.sortorder - b.sortorder,
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<Tabs fluid textAlign="center">
|
||||
{menusToShow.map((menu) => (
|
||||
<Tabs.Tab
|
||||
key={menu.ref}
|
||||
icon="list"
|
||||
selected={menu.id === active_menu}
|
||||
onClick={() => act('setactive_menu', { setactive_menu: menu.id })}
|
||||
>
|
||||
{menu.name}
|
||||
</Tabs.Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -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<Data>();
|
||||
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 <Box color="bad">No recipes found!</Box>;
|
||||
}
|
||||
|
||||
const cookiesToShow = crew_cookies
|
||||
.filter((cookie) => cookie.category === active_menu)
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
return (
|
||||
<Section fill>
|
||||
<Stack fill>
|
||||
<Stack.Item basis="30%">
|
||||
<Section
|
||||
title="Food Selection"
|
||||
scrollable
|
||||
fill
|
||||
buttons={
|
||||
active_menu === 'crew' && (
|
||||
<Button
|
||||
onClick={() => act('refresh')}
|
||||
tooltip="Refresh"
|
||||
icon="arrows-rotate"
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
<Tabs vertical>
|
||||
{active_menu === 'crew'
|
||||
? cookiesToShow.map((cookie) => (
|
||||
<Tabs.Tab key={cookie.name}>
|
||||
<Button
|
||||
fluid
|
||||
selected={
|
||||
selectedCrew && cookie.name === selectedCrew.name
|
||||
}
|
||||
onClick={() => {
|
||||
act('setactive_crew', {
|
||||
setactive_crew: cookie.name,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{cookie.name}
|
||||
</Button>
|
||||
</Tabs.Tab>
|
||||
))
|
||||
: recipesToShow.map((recipe) => (
|
||||
<Tabs.Tab key={recipe.ref}>
|
||||
<Button
|
||||
fluid
|
||||
selected={
|
||||
selectedFood && recipe.ref === selectedFood.ref
|
||||
}
|
||||
onClick={() =>
|
||||
act('setactive_food', {
|
||||
setactive_food: recipe.type,
|
||||
})
|
||||
}
|
||||
>
|
||||
{recipe.name}
|
||||
</Button>
|
||||
</Tabs.Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow ml={1}>
|
||||
{active_menu === 'crew' ? (
|
||||
selectedCrew ? (
|
||||
<Section title="Product Details" fill scrollable>
|
||||
<Stack vertical>
|
||||
<Stack.Item>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Name">
|
||||
{selectedCrew.name}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Species">
|
||||
{selectedCrew.species}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
disabled={busy}
|
||||
align="center"
|
||||
color="transparent"
|
||||
onClick={() =>
|
||||
act('crewprint', {
|
||||
crewprint: selectedCrew.name,
|
||||
})
|
||||
}
|
||||
>
|
||||
<CrewCookieIcon />
|
||||
<Box>Print this Cookie</Box>
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
) : (
|
||||
<Box color="label">Please select an offering.</Box>
|
||||
)
|
||||
) : selectedFood ? (
|
||||
<Section title="Product Details" fill scrollable>
|
||||
<Stack vertical>
|
||||
<Stack.Item>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Name">
|
||||
{selectedFood.name}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Divider />
|
||||
<LabeledList.Item label="Description">
|
||||
{selectedFood.desc || 'No description available.'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Divider />
|
||||
</LabeledList>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
disabled={busy}
|
||||
align="center"
|
||||
color="transparent"
|
||||
onClick={() => act('make', { make: selectedFood.ref })}
|
||||
>
|
||||
<Box
|
||||
className={classes([
|
||||
'synthesizer128x128',
|
||||
sanitizeCssClassName(selectedFood.type),
|
||||
])}
|
||||
/>
|
||||
<Box>Print this meal</Box>
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
) : (
|
||||
<Box color="label">Please select an offering.</Box>
|
||||
)}
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -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<Data>();
|
||||
const { isThereCart, cartFillStatus = 0 } = data;
|
||||
const adjustedCartChange = cartFillStatus / 100;
|
||||
|
||||
return (
|
||||
<Section title="Cartridge Status">
|
||||
{isThereCart ? (
|
||||
<LabeledList.Item label="Product Remaining">
|
||||
<ProgressBar
|
||||
color={cartFillStatus ? 'purple' : 'red'}
|
||||
value={adjustedCartChange}
|
||||
width={20}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
) : (
|
||||
<LabeledList.Item label="Cartridge Problem">
|
||||
<Box color="label">
|
||||
One or more cartridges are missing or damaged. <br />
|
||||
<br />
|
||||
Sabresnacks Co. recommends ordering a genuine Sabresnacks
|
||||
replacement cartridge through your local logistical cargo service.
|
||||
</Box>
|
||||
</LabeledList.Item>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<Window width={765} height={520}>
|
||||
<Window.Content>
|
||||
<Stack fill vertical>
|
||||
<Stack.Item>
|
||||
<Section>
|
||||
<SynthCartGuage />
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Section title="Menu Selection">
|
||||
<FoodMenuTabs />
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<FoodSelectionMenu />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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'}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Allow Synth cookie replicas">
|
||||
<Button
|
||||
onClick={() => act('toggle_synth_cookie')}
|
||||
selected={synth_cookie}
|
||||
tooltip="Opt-in to allow crewmembers to print minature replica cookies from food synthesizers of yourself."
|
||||
>
|
||||
{synth_cookie ? 'Yes' : 'No'}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Start With Mind Scan">
|
||||
<Button
|
||||
onClick={() => act('toggle_mind_scan')}
|
||||
|
||||
@@ -292,6 +292,7 @@ export type MiscData = {
|
||||
|
||||
resleeve_lock: BooleanLike;
|
||||
resleeve_scan: BooleanLike;
|
||||
synth_cookie: BooleanLike;
|
||||
mind_scan: BooleanLike;
|
||||
|
||||
vantag_volunteer: BooleanLike;
|
||||
|
||||
@@ -8,14 +8,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:*"
|
||||
},
|
||||
"private": true
|
||||
|
||||
@@ -1034,6 +1034,7 @@
|
||||
#include "code\datums\wires\circuit_imprinter.dm"
|
||||
#include "code\datums\wires\disposals.dm"
|
||||
#include "code\datums\wires\explosive.dm"
|
||||
#include "code\datums\wires\foodsynth.dm"
|
||||
#include "code\datums\wires\grid_checker.dm"
|
||||
#include "code\datums\wires\jukebox.dm"
|
||||
#include "code\datums\wires\mines.dm"
|
||||
@@ -2379,6 +2380,7 @@
|
||||
#include "code\modules\asset_cache\assets\vv.dm"
|
||||
#include "code\modules\asset_cache\assets\spritesheets\chat.dm"
|
||||
#include "code\modules\asset_cache\assets\spritesheets\chem_master.dm"
|
||||
#include "code\modules\asset_cache\assets\spritesheets\foodsynth.dm"
|
||||
#include "code\modules\asset_cache\assets\spritesheets\kitchen_recipes.dm"
|
||||
#include "code\modules\asset_cache\assets\spritesheets\pai_icons.dm"
|
||||
#include "code\modules\asset_cache\assets\spritesheets\pipes.dm"
|
||||
@@ -2931,6 +2933,7 @@
|
||||
#include "code\modules\food\food.dm"
|
||||
#include "code\modules\food\recipe.dm"
|
||||
#include "code\modules\food\recipe_dump.dm"
|
||||
#include "code\modules\food\recipes_foodsynthesizer.dm"
|
||||
#include "code\modules\food\recipes_fryer.dm"
|
||||
#include "code\modules\food\recipes_fryer_vr.dm"
|
||||
#include "code\modules\food\recipes_grill.dm"
|
||||
@@ -2977,6 +2980,7 @@
|
||||
#include "code\modules\food\kitchen\cooking_machines\candy.dm"
|
||||
#include "code\modules\food\kitchen\cooking_machines\cereal.dm"
|
||||
#include "code\modules\food\kitchen\cooking_machines\container.dm"
|
||||
#include "code\modules\food\kitchen\cooking_machines\foodsynthesizer.dm"
|
||||
#include "code\modules\food\kitchen\cooking_machines\fryer.dm"
|
||||
#include "code\modules\food\kitchen\cooking_machines\grill.dm"
|
||||
#include "code\modules\food\kitchen\cooking_machines\oven.dm"
|
||||
|
||||
Reference in New Issue
Block a user