diff --git a/_maps/map_files/stations/boxstation.dmm b/_maps/map_files/stations/boxstation.dmm
index 50511c8af66..924e17cfcb3 100644
--- a/_maps/map_files/stations/boxstation.dmm
+++ b/_maps/map_files/stations/boxstation.dmm
@@ -68036,9 +68036,7 @@
/area/station/public/dorms)
"nXu" = (
/obj/structure/window/reinforced,
-/obj/structure/table/reinforced,
-/obj/item/hemostat,
-/obj/item/scalpel,
+/obj/machinery/smithing/scientific_assembler,
/turf/simulated/floor/plasteel{
icon_state = "whitepurple"
},
@@ -87485,6 +87483,8 @@
},
/obj/item/slime_scanner,
/obj/item/slime_scanner,
+/obj/item/hemostat,
+/obj/item/scalpel,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "whitepurple"
diff --git a/_maps/map_files/stations/cerestation.dmm b/_maps/map_files/stations/cerestation.dmm
index 7f7f5e4a3fa..d3e252ae669 100644
--- a/_maps/map_files/stations/cerestation.dmm
+++ b/_maps/map_files/stations/cerestation.dmm
@@ -59464,6 +59464,12 @@
},
/turf/simulated/floor/plasteel,
/area/station/engineering/atmos)
+"lCN" = (
+/obj/machinery/smithing/scientific_assembler,
+/turf/simulated/floor/plasteel{
+ icon_state = "whitepurple"
+ },
+/area/station/science/xenobiology)
"lCO" = (
/obj/structure/rack,
/obj/effect/spawner/random/tech_storage/engineering,
@@ -133877,7 +133883,7 @@ cGd
cGd
wNA
qKO
-yiP
+lCN
xIa
xIa
xIa
diff --git a/_maps/map_files/stations/deltastation.dmm b/_maps/map_files/stations/deltastation.dmm
index 64865129e61..e919db87503 100644
--- a/_maps/map_files/stations/deltastation.dmm
+++ b/_maps/map_files/stations/deltastation.dmm
@@ -85488,6 +85488,13 @@
/obj/effect/turf_decal/stripes/corner,
/turf/simulated/floor/plating/airless,
/area/station/engineering/control)
+"tgQ" = (
+/obj/machinery/smithing/scientific_assembler,
+/turf/simulated/floor/plasteel{
+ dir = 1;
+ icon_state = "whitepurple"
+ },
+/area/station/science/xenobiology)
"thl" = (
/obj/effect/turf_decal/delivery,
/obj/machinery/door/firedoor,
@@ -130127,7 +130134,7 @@ eGq
exC
mek
tjH
-cQP
+tgQ
cVf
cVf
cSc
diff --git a/_maps/map_files/stations/emeraldstation.dmm b/_maps/map_files/stations/emeraldstation.dmm
index 819f156c3a4..750f2d9aa87 100644
--- a/_maps/map_files/stations/emeraldstation.dmm
+++ b/_maps/map_files/stations/emeraldstation.dmm
@@ -23053,7 +23053,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
-/obj/structure/filingcabinet/chestdrawer,
+/obj/machinery/smithing/scientific_assembler,
/turf/simulated/floor/plasteel{
icon_state = "whitepurplecorner"
},
diff --git a/_maps/map_files/stations/metastation.dmm b/_maps/map_files/stations/metastation.dmm
index 536099d8cc6..cb1bdca4b82 100644
--- a/_maps/map_files/stations/metastation.dmm
+++ b/_maps/map_files/stations/metastation.dmm
@@ -42933,6 +42933,13 @@
},
/turf/simulated/floor/plasteel,
/area/station/engineering/break_room)
+"fbq" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/machinery/smithing/scientific_assembler,
+/turf/simulated/floor/plasteel{
+ icon_state = "white"
+ },
+/area/station/science/xenobiology)
"fbr" = (
/obj/machinery/ai_status_display{
pixel_y = 32
@@ -130284,7 +130291,7 @@ gZe
deu
sFX
pNz
-kjo
+fbq
fvN
aaa
aaa
diff --git a/code/game/machinery/machine_frame.dm b/code/game/machinery/machine_frame.dm
index 690f78f37ec..7b3c1ce0743 100644
--- a/code/game/machinery/machine_frame.dm
+++ b/code/game/machinery/machine_frame.dm
@@ -1097,6 +1097,17 @@ to destroy them and players will be able to make replacements.
/obj/item/stock_parts/manipulator = 3,
/obj/item/stack/sheet/glass = 1)
+/obj/item/circuitboard/scientific_assembler
+ board_name = "Scientific Assembler"
+ icon_state = "supply"
+ build_path = /obj/machinery/smithing/scientific_assembler
+ board_type = "machine"
+ origin_tech = "programming=1;engineering=4"
+ req_components = list(
+ /obj/item/stock_parts/micro_laser = 1,
+ /obj/item/stock_parts/manipulator = 3,
+ /obj/item/stack/sheet/glass = 1)
+
/obj/item/circuitboard/ore_redemption
board_name = "Ore Redemption"
icon_state = "supply"
diff --git a/code/game/machinery/vendors/departmental_vendors.dm b/code/game/machinery/vendors/departmental_vendors.dm
index 00cd0897362..01437bc26c5 100644
--- a/code/game/machinery/vendors/departmental_vendors.dm
+++ b/code/game/machinery/vendors/departmental_vendors.dm
@@ -367,6 +367,7 @@
/obj/item/smithing_cast/component/lens_focus = 3,
/obj/item/smithing_cast/component/lens_frame = 3,
/obj/item/smithing_cast/component/trim = 3,
+ /obj/item/smithing_cast/misc/egun_parts = 3,
/obj/item/storage/bag/smith = 2,
/obj/item/storage/box/crewvend = 1)
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index 20715cfbd5e..dd8950b2e81 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -582,6 +582,16 @@
build_path = /obj/item/circuitboard/kinetic_assembler
category = list ("Misc. Machinery")
+/datum/design/scientific_assembler
+ name = "Machine Design (Kinetic Assembler)"
+ desc = "The circuit board for a Kinetic Assembler."
+ id = "scientific_assembler"
+ req_tech = list("programming" = 2, "engineering" = 4, "plasmatech" = 3)
+ build_type = IMPRINTER
+ materials = list(MAT_GLASS = 1000)
+ build_path = /obj/item/circuitboard/scientific_assembler
+ category = list ("Misc. Machinery")
+
/datum/design/mining_equipment_vendor
name = "Machine Design (Mining Rewards Vendor Board)"
desc = "The circuit board for a Mining Rewards Vendor."
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index be67faed004..60a5b196fa8 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -17,6 +17,8 @@
var/Uses = 1
/// The mob who last injected the extract with plasma, water or blood. Used for logging.
var/mob/living/injector_mob
+ /// The gun type associated with the extract
+ var/obj/item/gun/energy/associated_gun_type
/obj/item/slime_extract/attackby__legacy__attackchain(obj/item/O, mob/user)
if(istype(O, /obj/item/slimepotion/enhancer))
@@ -41,86 +43,107 @@
/obj/item/slime_extract/gold
name = "gold slime extract"
icon_state = "gold slime extract"
+ associated_gun_type = /obj/item/gun/energy/gun/shotgun
/obj/item/slime_extract/silver
name = "silver slime extract"
icon_state = "silver slime extract"
+ associated_gun_type = /obj/item/gun/energy/disabler/smg
/obj/item/slime_extract/metal
name = "metal slime extract"
icon_state = "metal slime extract"
+ associated_gun_type = /obj/item/gun/energy/gun/mini
/obj/item/slime_extract/purple
name = "purple slime extract"
icon_state = "purple slime extract"
+ associated_gun_type = /obj/item/gun/energy/disabler
/obj/item/slime_extract/darkpurple
name = "dark purple slime extract"
icon_state = "dark purple slime extract"
+ associated_gun_type = /obj/item/gun/energy/laser
/obj/item/slime_extract/orange
name = "orange slime extract"
icon_state = "orange slime extract"
+ associated_gun_type = /obj/item/gun/energy/gun/mini
/obj/item/slime_extract/yellow
name = "yellow slime extract"
icon_state = "yellow slime extract"
+ associated_gun_type = /obj/item/gun/energy/ionrifle/carbine
/obj/item/slime_extract/red
name = "red slime extract"
icon_state = "red slime extract"
+ associated_gun_type = /obj/item/gun/energy/plasma_pistol
/obj/item/slime_extract/blue
name = "blue slime extract"
icon_state = "blue slime extract"
+ associated_gun_type = /obj/item/gun/energy/disabler
/obj/item/slime_extract/darkblue
name = "dark blue slime extract"
icon_state = "dark blue slime extract"
+ associated_gun_type = /obj/item/gun/energy/gun
/obj/item/slime_extract/pink
name = "pink slime extract"
icon_state = "pink slime extract"
+ associated_gun_type = /obj/item/gun/energy/gun/blueshield
/obj/item/slime_extract/green
name = "green slime extract"
icon_state = "green slime extract"
+ associated_gun_type = /obj/item/gun/projectile/automatic/laserrifle
/obj/item/slime_extract/lightpink
name = "light pink slime extract"
icon_state = "light pink slime extract"
+ associated_gun_type = /obj/item/gun/energy/arc_revolver
/obj/item/slime_extract/black
name = "black slime extract"
icon_state = "black slime extract"
+ associated_gun_type = /obj/item/gun/energy/lasercannon
/obj/item/slime_extract/oil
name = "oil slime extract"
icon_state = "oil slime extract"
+ associated_gun_type = /obj/item/gun/energy/immolator
/obj/item/slime_extract/adamantine
name = "adamantine slime extract"
icon_state = "adamantine slime extract"
+ associated_gun_type = /obj/item/gun/energy/gun/nuclear
/obj/item/slime_extract/bluespace
name = "bluespace slime extract"
icon_state = "bluespace slime extract"
+ associated_gun_type = /obj/item/gun/energy/sparker
/obj/item/slime_extract/pyrite
name = "pyrite slime extract"
icon_state = "pyrite slime extract"
+ associated_gun_type = /obj/item/gun/energy/gun/mini
/obj/item/slime_extract/cerulean
name = "cerulean slime extract"
icon_state = "cerulean slime extract"
+ associated_gun_type = /obj/item/gun/energy/gun/shotgun
/obj/item/slime_extract/sepia
name = "sepia slime extract"
icon_state = "sepia slime extract"
+ associated_gun_type = /obj/item/gun/energy/laser/retro
/obj/item/slime_extract/rainbow
name = "rainbow slime extract"
icon_state = "rainbow slime extract"
+ associated_gun_type = /obj/item/gun/energy/lwap
////Slime-derived potions///
diff --git a/code/modules/smithing/machinery/casting_basin.dm b/code/modules/smithing/machinery/casting_basin.dm
index 12e5708ece0..cf4fa0eeb3d 100644
--- a/code/modules/smithing/machinery/casting_basin.dm
+++ b/code/modules/smithing/machinery/casting_basin.dm
@@ -50,6 +50,16 @@
. += " - [MAT]: [ROUND_UP(((temp_product.materials[MAT] * quality.material_mult) * efficiency) / MINERAL_MATERIAL_AMOUNT)] sheets."
// Get rid of the temp product
qdel(temp_product)
+ else if(istype(cast, /obj/item/smithing_cast/misc) && !produced_item)
+ var/obj/item/temp_product = new cast.selected_product(src) // This is necessary due to selected_product being a type
+ var/obj/item/smithing_cast/component/comp_cast = cast
+ . += "Required Resources:"
+ var/MAT
+ // Get the materials the item needs and display
+ for(MAT in temp_product.materials)
+ . += " - [MAT]: [ROUND_UP((temp_product.materials[MAT] * efficiency) / MINERAL_MATERIAL_AMOUNT)] sheets."
+ // Get rid of the temp product
+ qdel(temp_product)
if(produced_item)
. += "There is a [produced_item] in the machine. You can pick it up with your hand."
@@ -86,6 +96,8 @@
. += "cast_lens"
else if(istype(cast, /obj/item/smithing_cast/component/trim))
. += "cast_trim"
+ else if(istype(cast, /obj/item/smithing_cast/misc/egun_parts))
+ . += "cast_egun_parts"
. += "casting_lip"
if(panel_open)
. += "casting_wires"
@@ -233,6 +245,32 @@
qdel(temp_product)
return FINISH_ATTACK
+ if(istype(cast, /obj/item/smithing_cast/misc))
+ var/list/used_mats = list()
+
+ // Check if there is enough materials to craft the item
+ for(MAT in temp_product.materials)
+ used_mats[MAT] = temp_product.materials[MAT] * efficiency
+
+ if(!materials.has_materials(used_mats, 1))
+ to_chat(user, "Not enough materials in the crucible to smelt [temp_product.name]!")
+ qdel(temp_product)
+ return FINISH_ATTACK
+
+ to_chat(user, "You begin to pour the liquid minerals into the [src]...")
+ // Use the materials and create the item.
+ materials.use_amount(used_mats)
+ linked_crucible.animate_pour(operation_time SECONDS)
+ operate(operation_time, user)
+ produced_item = new cast.selected_product(src)
+ produced_item.set_worktime()
+ produced_item.update_appearance(UPDATE_NAME)
+ produced_item.update_icon(UPDATE_ICON_STATE)
+ update_icon(UPDATE_OVERLAYS)
+ // Clean up temps
+ qdel(temp_product)
+ return FINISH_ATTACK
+
/obj/machinery/smithing/casting_basin/Destroy()
if(linked_crucible)
linked_crucible.linked_machines -= src
diff --git a/code/modules/smithing/machinery/kinetic_assembler.dm b/code/modules/smithing/machinery/kinetic_assembler.dm
index 00032834333..c2aefbc3cf1 100644
--- a/code/modules/smithing/machinery/kinetic_assembler.dm
+++ b/code/modules/smithing/machinery/kinetic_assembler.dm
@@ -231,3 +231,148 @@
extra_product.update_appearance(UPDATE_NAME)
extra_product.scatter_atom()
finished_product = null
+
+// MARK: Scientific Assembler
+
+/obj/machinery/smithing/scientific_assembler
+ name = "scientific assembler"
+ desc = "A smart assembler that takes slime cores, energy cells, and energy gun parts to produce energy guns."
+ icon = 'icons/obj/machines/smithing_machines.dmi'
+ icon_state = "assembler"
+ max_integrity = 100
+ pixel_x = 0 // 1x1
+ pixel_y = 0
+ bound_height = 32
+ bound_width = 32
+ bound_y = 0
+ operation_sound = 'sound/items/welder.ogg'
+ /// Slime extract for the egun
+ var/obj/item/slime_extract/slime_core
+ /// The gun frame
+ var/obj/item/smithed_item/component/egun_parts/parts
+ /// The battery
+ var/obj/item/stock_parts/cell/cell
+
+/obj/machinery/smithing/scientific_assembler/Initialize(mapload)
+ . = ..()
+ // Stock parts
+ component_parts = list()
+ component_parts += new /obj/item/circuitboard/kinetic_assembler(null)
+ component_parts += new /obj/item/stock_parts/manipulator(null)
+ component_parts += new /obj/item/stock_parts/manipulator(null)
+ component_parts += new /obj/item/stock_parts/manipulator(null)
+ component_parts += new /obj/item/stock_parts/micro_laser(null)
+ component_parts += new /obj/item/stack/sheet/glass(null)
+ RefreshParts()
+
+/obj/machinery/smithing/scientific_assembler/examine(mob/user)
+ . = ..()
+ if(slime_core || parts || cell)
+ . += "You can activate the machine with your hand, or remove a component by alt-clicking."
+ if(slime_core)
+ . += "There is a [slime_core] in the core slot."
+ if(parts)
+ . += "There is a [parts] in the gun frame slot."
+ if(cell)
+ . += "There is a [cell] in the power cell slot."
+
+/obj/machinery/smithing/scientific_assembler/RefreshParts()
+ var/operation_mult = 0
+ for(var/obj/item/stock_parts/component in component_parts)
+ operation_mult += OPERATION_SPEED_MULT_PER_RATING * component.rating
+ // Update our values
+ operation_time = operation_time = max(ROUND_UP(initial(operation_time) * (1.3 - operation_mult)), 2)
+
+/obj/machinery/smithing/scientific_assembler/update_icon_state()
+ . = ..()
+ if(panel_open)
+ icon_state = "assembler_wires"
+
+/obj/machinery/smithing/kinetic_assembler/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/I)
+ . = ..()
+ update_icon(UPDATE_ICON_STATE)
+
+/obj/machinery/smithing/scientific_assembler/update_overlays()
+ . = ..()
+ overlays.Cut()
+ if(panel_open)
+ icon_state = "assembler_wires"
+
+/obj/machinery/smithing/scientific_assembler/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(operating)
+ to_chat(user, "[src] is still operating!")
+ return ITEM_INTERACT_COMPLETE
+
+ if(istype(used, /obj/item/slime_extract))
+ var/obj/item/slime_extract/core = used
+ if(!core.associated_gun_type)
+ to_chat(user, "[core] is not capable of producing an energy gun!")
+ return ITEM_INTERACT_COMPLETE
+ if(slime_core)
+ to_chat(user, "You remove [slime_core] from the core component slot of [src].")
+ slime_core.forceMove(src.loc)
+ slime_core = null
+ if(used.flags & NODROP || !user.transfer_item_to(used, src))
+ to_chat(user, "[used] is stuck to your hand!")
+ return ITEM_INTERACT_COMPLETE
+ to_chat(user, "You insert [used] into the core component slot of [src].")
+ slime_core = used
+ return ITEM_INTERACT_COMPLETE
+
+ if(istype(used, /obj/item/smithed_item/component/egun_parts))
+ if(parts)
+ to_chat(user, "You remove [parts] from the gun parts component slot of [src].")
+ parts.forceMove(src.loc)
+ parts = null
+ if(used.flags & NODROP || !user.transfer_item_to(used, src))
+ to_chat(user, "[used] is stuck to your hand!")
+ return ITEM_INTERACT_COMPLETE
+ var/obj/item/smithed_item/component/egun_parts/new_parts = used
+ if(new_parts.hammer_time)
+ to_chat(user, "[new_parts] is not complete yet!")
+ return ITEM_INTERACT_COMPLETE
+ to_chat(user, "You insert [used] into the gun parts component slot of [src].")
+ parts = used
+ return ITEM_INTERACT_COMPLETE
+
+ if(istype(used, /obj/item/stock_parts/cell))
+ if(cell)
+ to_chat(user, "You remove [cell] from the power cell component slot of [src].")
+ cell.forceMove(src.loc)
+ cell = null
+ if(used.flags & NODROP || !user.transfer_item_to(used, src))
+ to_chat(user, "[used] is stuck to your hand!")
+ return ITEM_INTERACT_COMPLETE
+ to_chat(user, "You insert [used] into the power cell component slot of [src].")
+ cell = used
+ return ITEM_INTERACT_COMPLETE
+
+ to_chat(user, "You feel like there's no reason to process [used].")
+ return ITEM_INTERACT_COMPLETE
+
+/obj/machinery/smithing/scientific_assembler/attack_hand(mob/user)
+ if(!slime_core)
+ to_chat(user, "[src] lacks a slime core!")
+ return FINISH_ATTACK
+
+ if(!parts)
+ to_chat(user, "[src] lacks an energy gun frame!")
+ return FINISH_ATTACK
+
+ if(!cell)
+ to_chat(user, "[src] lacks a power cell!")
+ return FINISH_ATTACK
+
+ operate(operation_time, user)
+ return FINISH_ATTACK
+
+/obj/machinery/smithing/scientific_assembler/operate(loops, mob/living/user)
+ ..()
+ var/obj/item/gun/energy/finished_product = new slime_core.associated_gun_type(src)
+ finished_product.forceMove(src.loc)
+ qdel(slime_core)
+ qdel(parts)
+ qdel(cell)
+ slime_core = null
+ parts = null
+ cell = null
diff --git a/code/modules/smithing/machinery/power_hammer.dm b/code/modules/smithing/machinery/power_hammer.dm
index 7bc9e78e5f8..af463db6671 100644
--- a/code/modules/smithing/machinery/power_hammer.dm
+++ b/code/modules/smithing/machinery/power_hammer.dm
@@ -48,7 +48,7 @@
/obj/machinery/smithing/power_hammer/operate(loops, mob/living/user)
if(!working_component)
- to_chat(user, "There is no component in the machine.")
+ to_chat(user, "There is no component to hammer!")
return
if(!working_component.heat)
to_chat(user, "[working_component] is too cold to properly shape.")
diff --git a/code/modules/smithing/smithed_items/misc_smithed.dm b/code/modules/smithing/smithed_items/misc_smithed.dm
new file mode 100644
index 00000000000..e98d5c8af8a
--- /dev/null
+++ b/code/modules/smithing/smithed_items/misc_smithed.dm
@@ -0,0 +1,7 @@
+// MARK: Energy Gun Frame
+/obj/item/smithed_item/component/egun_parts
+ name = "energy gun parts"
+ desc = "Smithed component of an energy gun."
+ icon_state = "egun_parts"
+ materials = list(MAT_TITANIUM = 10000, MAT_PLASMA = 10000)
+ hammer_time = 6
diff --git a/code/modules/smithing/smithing_cast.dm b/code/modules/smithing/smithing_cast.dm
index 9a2140be5a0..d46507e7826 100644
--- a/code/modules/smithing/smithing_cast.dm
+++ b/code/modules/smithing/smithing_cast.dm
@@ -26,11 +26,15 @@
. = ..()
if(!possible_products)
return
+ if(!length(possible_products))
+ return
var/list/product_names = list()
var/product
for(product in possible_products)
var/obj/item/possible_product = product
product_names[possible_product.name] = possible_product
+ if(!length(product_names))
+ return
var/new_product = tgui_input_list(user, "Select a product", src, product_names)
if(!new_product)
selected_product = possible_products[1]
@@ -158,3 +162,20 @@
icon_state = "trim_cast"
desc = "A cast for creating trims."
product_type = /obj/item/smithed_item/component/trim
+
+/obj/item/smithing_cast/misc
+ name = "misc cast"
+ icon_state = "insert_frame_cast"
+ desc = "Debug cast. If you see this, notify the development team."
+
+/obj/item/smithing_cast/misc/AltClick(mob/user, modifiers)
+ return
+
+/obj/item/smithing_cast/misc/examine(mob/user)
+ . = desc
+
+/obj/item/smithing_cast/misc/egun_parts
+ name = "energy gun parts cast"
+ icon_state = "egun_parts_cast"
+ desc = "A cast for creating energy gun frames."
+ selected_product = /obj/item/smithed_item/component/egun_parts
diff --git a/icons/obj/machines/smithing_machines.dmi b/icons/obj/machines/smithing_machines.dmi
index cd2c5a5fb34..fbe6aa2c129 100644
Binary files a/icons/obj/machines/smithing_machines.dmi and b/icons/obj/machines/smithing_machines.dmi differ
diff --git a/icons/obj/smithing.dmi b/icons/obj/smithing.dmi
index 6ce76869a53..9ad42d26bf7 100644
Binary files a/icons/obj/smithing.dmi and b/icons/obj/smithing.dmi differ
diff --git a/paradise.dme b/paradise.dme
index c69c1fef5cd..6ebfb4fad68 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -2984,6 +2984,7 @@
#include "code\modules\smithing\machinery\smart_hopper.dm"
#include "code\modules\smithing\smithed_items\inserts.dm"
#include "code\modules\smithing\smithed_items\lens.dm"
+#include "code\modules\smithing\smithed_items\misc_smithed.dm"
#include "code\modules\smithing\smithed_items\tool_bits.dm"
#include "code\modules\space_management\level_check.dm"
#include "code\modules\space_management\level_traits.dm"