diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index 4a50214bb7..7da895a593 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -10,11 +10,6 @@
#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
-// Signal return value flags
-// The other defines are under the signal they're used in
-
-#define COMPONENT_ACTIVATED 1 // call parent.ComponentActivated(comp) and component.AfterComponentActivated()
-
// All signals. Format:
// When the signal is called: (signal arguments)
@@ -28,7 +23,7 @@
// /atom signals
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
- #define COMPONENT_NO_AFTERATTACK 2 //Return this in response if you don't want afterattack to be called
+ #define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob)
#define COMSIG_ATOM_ENTERED "atom_entered" //from base of atom/Entered(): (/atom/movable, /atom)
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index e346f60bff..192aa96044 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -142,10 +142,6 @@
/datum/component/proc/OnTransfer(datum/new_parent)
return
-/datum/component/proc/AfterComponentActivated()
- set waitfor = FALSE
- return
-
/datum/component/proc/_GetInverseTypeList(our_type = type)
#if DM_VERSION >= 513
#warning 512 is definitely stable now, remove the old code
@@ -177,28 +173,16 @@
var/datum/callback/CB = C.signal_procs[sigtype]
if(!CB)
return NONE
- . = CB.InvokeAsync(arglist(arguments))
- if(. & COMPONENT_ACTIVATED)
- ComponentActivated(C)
- C.AfterComponentActivated()
- else
- . = NONE
- for(var/I in target)
- var/datum/component/C = I
- if(!C.enabled)
- continue
- var/datum/callback/CB = C.signal_procs[sigtype]
- if(!CB)
- continue
- var/retval = CB.InvokeAsync(arglist(arguments))
- . |= retval
- if(retval & COMPONENT_ACTIVATED)
- ComponentActivated(C)
- C.AfterComponentActivated()
-
-/datum/proc/ComponentActivated(datum/component/C)
- set waitfor = FALSE
- return
+ return CB.InvokeAsync(arglist(arguments))
+ . = NONE
+ for(var/I in target)
+ var/datum/component/C = I
+ if(!C.enabled)
+ continue
+ var/datum/callback/CB = C.signal_procs[sigtype]
+ if(!CB)
+ continue
+ . |= CB.InvokeAsync(arglist(arguments))
/datum/proc/GetComponent(c_type)
var/list/dc = datum_components
diff --git a/code/datums/components/archaeology.dm b/code/datums/components/archaeology.dm
index 05a56952b6..6fb2b67051 100644
--- a/code/datums/components/archaeology.dm
+++ b/code/datums/components/archaeology.dm
@@ -3,10 +3,12 @@
var/list/archdrops
var/prob2drop
var/dug
+ var/datum/callback/callback
-/datum/component/archaeology/Initialize(_prob2drop, list/_archdrops = list())
+/datum/component/archaeology/Initialize(_prob2drop, list/_archdrops = list(), datum/callback/_callback)
prob2drop = Clamp(_prob2drop, 0, 100)
archdrops = _archdrops
+ callback = _callback
RegisterSignal(COMSIG_PARENT_ATTACKBY,.proc/Dig)
RegisterSignal(COMSIG_ATOM_EX_ACT, .proc/BombDig)
RegisterSignal(COMSIG_ATOM_SING_PULL, .proc/SingDig)
@@ -67,6 +69,8 @@
if(OT.slowdown) //Things like snow slow you down until you dig them.
OT.slowdown = 0
dug = TRUE
+ if(callback)
+ callback.Invoke()
/datum/component/archaeology/proc/SingDig(S, current_size)
switch(current_size)
diff --git a/code/datums/components/infective.dm b/code/datums/components/infective.dm
index 5b2232b8a9..521d9ece2c 100644
--- a/code/datums/components/infective.dm
+++ b/code/datums/components/infective.dm
@@ -9,5 +9,4 @@
var/mob/living/carbon/victim = AM
if(istype(victim))
for(var/datum/disease/D in diseases)
- victim.ContactContractDisease(D, "feet")
- return COMPONENT_ACTIVATED
\ No newline at end of file
+ victim.ContactContractDisease(D, "feet")
\ No newline at end of file
diff --git a/code/datums/components/material_container.dm b/code/datums/components/material_container.dm
index ec9ac1d1e6..5e989005be 100644
--- a/code/datums/components/material_container.dm
+++ b/code/datums/components/material_container.dm
@@ -16,20 +16,19 @@
var/list/materials
var/show_on_examine
var/list/allowed_typecache
- var/last_inserted_type
var/last_inserted_id
- var/last_amount_inserted
- var/last_insert_success
var/precise_insertion = FALSE
var/datum/callback/precondition
+ var/datum/callback/after_insert
-/datum/component/material_container/Initialize(list/mat_list, max_amt = 0, _show_on_examine = FALSE, list/allowed_types, datum/callback/_precondition)
+/datum/component/material_container/Initialize(list/mat_list, max_amt = 0, _show_on_examine = FALSE, list/allowed_types, datum/callback/_precondition, datum/callback/_after_insert)
materials = list()
max_amount = max(0, max_amt)
show_on_examine = _show_on_examine
if(allowed_types)
allowed_typecache = typecacheof(allowed_types)
precondition = _precondition
+ after_insert = _after_insert
RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy)
RegisterSignal(COMSIG_PARENT_EXAMINE, .proc/OnExamine)
@@ -57,8 +56,7 @@
if((I.flags_2 & (HOLOGRAM_2 | NO_MAT_REDEMPTION_2)) || (tc && !is_type_in_typecache(I, tc)))
to_chat(user, "[parent] won't accept [I]!")
return
- . = COMPONENT_ACTIVATED | COMPONENT_NO_AFTERATTACK
- last_insert_success = FALSE
+ . = COMPONENT_NO_AFTERATTACK
var/datum/callback/pc = precondition
if(pc && !pc.Invoke())
return
@@ -69,11 +67,12 @@
if(!has_space(material_amount))
to_chat(user, "[parent] is full. Please remove metal or glass from [parent] in order to insert more.")
return
- INVOKE_ASYNC(src, .proc/user_insert, I, user)
+ user_insert(I, user)
/datum/component/material_container/proc/user_insert(obj/item/I, mob/living/user)
var/requested_amount
- if(istype(I, /obj/item/stack) && precise_insertion)
+ var/Itype = I.type
+ if(ispath(Itype, /obj/item/stack) && precise_insertion)
var/atom/current_parent = parent
requested_amount = input(user, "How much do you want to insert?", "Inserting sheets") as num|null
if(isnull(requested_amount) || (requested_amount <= 0))
@@ -85,7 +84,6 @@
return
var/inserted = insert_item(I, stack_amt = requested_amount)
if(inserted)
- last_insert_success = TRUE
if(istype(I, /obj/item/stack))
to_chat(user, "You insert [inserted] sheet[inserted>1 ? "s" : ""] into [parent].")
if(!QDELETED(I))
@@ -93,6 +91,8 @@
else
to_chat(user, "You insert a material total of [inserted] into [parent].")
qdel(I)
+ if(after_insert)
+ after_insert.Invoke(Itype, last_inserted_id, inserted)
else
user.put_in_active_hand(I)
@@ -132,9 +132,7 @@
return FALSE
last_inserted_id = insert_materials(S,amt)
- last_inserted_type = S.type
S.use(amt)
- last_amount_inserted = amt
return amt
/datum/component/material_container/proc/insert_item(obj/item/I, multiplier = 1, stack_amt)
@@ -148,8 +146,6 @@
return FALSE
last_inserted_id = insert_materials(I, multiplier)
- last_inserted_type = I.type
- last_amount_inserted = material_amount
return material_amount
/datum/component/material_container/proc/insert_materials(obj/item/I, multiplier = 1) //for internal usage only
diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm
index c174ba5ecb..24cb22020d 100644
--- a/code/datums/components/slippery.dm
+++ b/code/datums/components/slippery.dm
@@ -1,18 +1,15 @@
/datum/component/slippery
var/intensity
var/lube_flags
- var/mob/slip_victim
+ var/datum/callback/callback
-/datum/component/slippery/Initialize(_intensity, _lube_flags = NONE)
+/datum/component/slippery/Initialize(_intensity, _lube_flags = NONE, datum/callback/_callback)
intensity = max(_intensity, 0)
lube_flags = _lube_flags
+ callback = _callback
RegisterSignal(list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), .proc/Slip)
/datum/component/slippery/proc/Slip(atom/movable/AM)
var/mob/victim = AM
- if(istype(victim) && !victim.is_flying() && victim.slip(intensity, parent, lube_flags))
- slip_victim = victim
- return COMPONENT_ACTIVATED
-
-/datum/component/slippery/AfterComponentActivated()
- slip_victim = null
+ if(istype(victim) && !victim.is_flying() && victim.slip(intensity, parent, lube_flags) && callback)
+ callback.Invoke(victim)
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index d783be292e..9ce42f580c 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -46,7 +46,7 @@
)
/obj/machinery/autolathe/Initialize()
- AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS))
+ AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS), 0, FALSE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
. = ..()
wires = new /datum/wires/autolathe(src)
@@ -124,23 +124,17 @@
return ..()
-/obj/machinery/mecha_part_fabricator/ComponentActivated(datum/component/C)
- ..()
- if(istype(C, /datum/component/material_container))
- var/datum/component/material_container/M = C
- if(!M.last_insert_success)
- return
- var/lit = M.last_inserted_type
- if(ispath(lit, /obj/item/ore/bluespace_crystal))
- use_power(max(500,M.last_amount_inserted/10))
- else
- switch(M.last_inserted_id)
- if (MAT_METAL)
- flick("autolathe_o",src)//plays metal insertion animation
- if (MAT_GLASS)
- flick("autolathe_r",src)//plays glass insertion animation
- use_power(M.last_amount_inserted*100)
- updateUsrDialog()
+/obj/machinery/autolathe/proc/AfterMaterialInsert(type_inserted, id_inserted, amount_inserted)
+ if(ispath(type_inserted, /obj/item/ore/bluespace_crystal))
+ use_power(max(500, amount_inserted / 10))
+ else
+ switch(id_inserted)
+ if (MAT_METAL)
+ flick("autolathe_o",src)//plays metal insertion animation
+ if (MAT_GLASS)
+ flick("autolathe_r",src)//plays glass insertion animation
+ use_power(amount_inserted * 100)
+ updateUsrDialog()
/obj/machinery/autolathe/Topic(href, href_list)
if(..())
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index be0f596ced..f0b2915794 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -35,12 +35,21 @@
)
/obj/machinery/mecha_part_fabricator/Initialize()
+<<<<<<< HEAD
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE),
FALSE, list(/obj/item/stack, /obj/item/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready))
materials.precise_insertion = TRUE
. = ..()
files = new /datum/research(src) //Setup the research data holder.
+=======
+ var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
+ list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE),
+ FALSE, list(/obj/item/stack, /obj/item/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
+ materials.precise_insertion = TRUE
+ stored_research = new
+ return ..()
+>>>>>>> 3aba012... Removes ComponentActivated in favor of callbacks (#33274)
/obj/machinery/mecha_part_fabricator/RefreshParts()
var/T = 0
@@ -415,16 +424,11 @@
materials.retrieve_all()
..()
-/obj/machinery/mecha_part_fabricator/ComponentActivated(datum/component/C)
- ..()
- if(istype(C, /datum/component/material_container))
- var/datum/component/material_container/M = C
- if(!M.last_insert_success)
- return
- var/stack_name = material2name(M.last_inserted_id)
- add_overlay("fab-load-[stack_name]")
- addtimer(CALLBACK(src, /atom/proc/cut_overlay, "fab-load-[stack_name]"), 10)
- updateUsrDialog()
+/obj/machinery/mecha_part_fabricator/proc/AfterMaterialInsert(type_inserted, id_inserted, amount_inserted)
+ var/stack_name = material2name(id_inserted)
+ add_overlay("fab-load-[stack_name]")
+ addtimer(CALLBACK(src, /atom/proc/cut_overlay, "fab-load-[stack_name]"), 10)
+ updateUsrDialog()
/obj/machinery/mecha_part_fabricator/attackby(obj/item/W, mob/user, params)
if(default_deconstruction_screwdriver(user, "fab-o", "fab-idle", W))
diff --git a/code/game/objects/items/devices/PDA/PDA_types.dm b/code/game/objects/items/devices/PDA/PDA_types.dm
index 4f2db14fa6..90eff4b735 100644
--- a/code/game/objects/items/devices/PDA/PDA_types.dm
+++ b/code/game/objects/items/devices/PDA/PDA_types.dm
@@ -10,6 +10,7 @@
/obj/item/device/pda/clown/Initialize()
. = ..()
+<<<<<<< HEAD
AddComponent(/datum/component/slippery, 120, NO_SLIP_WHEN_WALKING)
/obj/item/device/pda/clown/ComponentActivated(datum/component/C)
@@ -20,6 +21,12 @@
var/mob/living/carbon/human/M = S.slip_victim
if (istype(M) && (M.real_name != src.owner))
slipvictims |= M
+=======
+ AddComponent(/datum/component/slippery, 120, NO_SLIP_WHEN_WALKING, CALLBACK(src, .proc/AfterSlip))
+
+/obj/item/device/pda/clown/proc/AfterSlip(mob/living/carbon/human/M)
+ if (istype(M) && (M.real_name != owner))
+>>>>>>> 3aba012... Removes ComponentActivated in favor of callbacks (#33274)
var/obj/item/cartridge/virus/clown/cart = cartridge
if(istype(cart) && cart.charges < 5)
cart.charges++
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index ae6aa0cb2d..5d83d677de 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -275,17 +275,12 @@
else
qdel(GetComponent(/datum/component/slippery))
return
- var/datum/component/slippery/S = LoadComponent(/datum/component/slippery)
+ var/datum/component/slippery/S = LoadComponent(/datum/component/slippery, NONE, CALLBACK(src, .proc/AfterSlip))
S.intensity = intensity
S.lube_flags = lube_flags
-/turf/open/ComponentActivated(datum/component/C)
- ..()
- var/datum/component/slippery/S = C
- if(!istype(S))
- return
+/turf/open/proc/AfterSlip(mob/living/L)
if(wet == TURF_WET_LUBE)
- var/mob/living/L = S.slip_victim
L.confused = max(L.confused, 8)
/turf/open/proc/MakeDry(wet_setting = TURF_WET_WATER)
diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm
index abbf83a164..b2ab28dcae 100644
--- a/code/game/turfs/simulated/floor/plating/asteroid.dm
+++ b/code/game/turfs/simulated/floor/plating/asteroid.dm
@@ -87,6 +87,9 @@
/turf/open/floor/plating/asteroid/basalt/Initialize()
. = ..()
set_basalt_light(src)
+ GET_COMPONENT(arch, /datum/component/archaeology)
+ ASSERT(isnull(arch.callback))
+ arch.callback = CALLBACK(src, /atom/proc/set_light, 0)
/proc/set_basalt_light(turf/open/floor/B)
switch(B.icon_state)
@@ -95,12 +98,6 @@
if("basalt5", "basalt9")
B.set_light(1.4, 0.6, LIGHT_COLOR_LAVA) //barely anything!
-/turf/open/floor/plating/asteroid/basalt/ComponentActivated(datum/component/C)
- ..()
- if(istype(C, /datum/component/archaeology))
- set_light(0)
-
-
///////Surface. The surface is warm, but survivable without a suit. Internals are required. The floors break to chasms, which drop you into the underground.
/turf/open/floor/plating/asteroid/basalt/lava_land_surface
diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm
index ebeb869d9c..c863ba8afa 100644
--- a/code/modules/research/circuitprinter.dm
+++ b/code/modules/research/circuitprinter.dm
@@ -27,9 +27,15 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis).
"Computer Parts"
)
+<<<<<<< HEAD
/obj/machinery/r_n_d/circuit_imprinter/Initialize()
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, list(MAT_GLASS, MAT_GOLD, MAT_DIAMOND, MAT_METAL, MAT_BLUESPACE),
FALSE, list(/obj/item/stack, /obj/item/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready))
+=======
+/obj/machinery/rnd/circuit_imprinter/Initialize()
+ materials = AddComponent(/datum/component/material_container, list(MAT_GLASS, MAT_GOLD, MAT_DIAMOND, MAT_METAL, MAT_BLUESPACE),
+ FALSE, list(/obj/item/stack, /obj/item/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
+>>>>>>> 3aba012... Removes ComponentActivated in favor of callbacks (#33274)
materials.precise_insertion = TRUE
create_reagents(0)
return ..()
@@ -77,6 +83,7 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis).
linked_console.linked_imprinter = null
..()
+<<<<<<< HEAD
/obj/machinery/r_n_d/circuit_imprinter/ComponentActivated(datum/component/C)
..()
if(istype(C, /datum/component/material_container))
@@ -94,3 +101,48 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis).
use_power(max(1000, (MINERAL_MATERIAL_AMOUNT * M.last_amount_inserted / 10)))
add_overlay("protolathe_[stack_name]")
addtimer(CALLBACK(src, /atom/proc/cut_overlay, "protolathe_[stack_name]"), 10)
+=======
+/obj/machinery/rnd/circuit_imprinter/proc/user_try_print_id(id)
+ if((!linked_console && requires_console) || !id)
+ return FALSE
+ var/datum/design/D = (linked_console || requires_console)? linked_console.stored_research.researched_designs[id] : get_techweb_design_by_id(id)
+ if(!istype(D))
+ return FALSE
+
+ var/power = 1000
+ for(var/M in D.materials)
+ power += round(D.materials[M] / 5)
+ power = max(4000, power)
+ use_power(power)
+
+ var/list/efficient_mats = list()
+ for(var/MAT in D.materials)
+ efficient_mats[MAT] = D.materials[MAT]/efficiency_coeff
+
+ if(!materials.has_materials(efficient_mats))
+ say("Not enough materials to complete prototype.")
+ return FALSE
+ for(var/R in D.reagents_list)
+ if(!reagents.has_reagent(R, D.reagents_list[R]/efficiency_coeff))
+ say("Not enough reagents to complete prototype.")
+ return FALSE
+
+ busy = TRUE
+ flick("circuit_imprinter_ani", src)
+ materials.use_amount(efficient_mats)
+ for(var/R in D.reagents_list)
+ reagents.remove_reagent(R, D.reagents_list[R]/efficiency_coeff)
+
+ var/P = D.build_path
+ addtimer(CALLBACK(src, .proc/reset_busy), 16)
+ addtimer(CALLBACK(src, .proc/do_print, P, efficient_mats, D.dangerous_construction), 16)
+ return TRUE
+
+/obj/machinery/rnd/circuit_imprinter/proc/do_print(path, list/matlist, notify_admins)
+ if(notify_admins && usr)
+ investigate_log("[key_name(usr)] built [path] at a circuit imprinter.", INVESTIGATE_RESEARCH)
+ message_admins("[ADMIN_LOOKUPFLW(usr)] has built [path] at a circuit imprinter.")
+ var/obj/item/I = new path(get_turf(src))
+ I.materials = matlist.Copy()
+ SSblackbox.record_feedback("nested_tally", "circuit_printed", 1, list("[type]", "[path]"))
+>>>>>>> 3aba012... Removes ComponentActivated in favor of callbacks (#33274)
diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm
index 9df4946ed2..1447e77dd6 100644
--- a/code/modules/research/protolathe.dm
+++ b/code/modules/research/protolathe.dm
@@ -35,7 +35,7 @@ Note: Must be placed west/left of and R&D console to function.
create_reagents(0)
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE),
- FALSE, list(/obj/item/stack, /obj/item/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready))
+ FALSE, list(/obj/item/stack, /obj/item/ore/bluespace_crystal), CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.precise_insertion = TRUE
return ..()
@@ -78,6 +78,7 @@ Note: Must be placed west/left of and R&D console to function.
linked_console.linked_lathe = null
..()
+<<<<<<< HEAD
/obj/machinery/r_n_d/protolathe/ComponentActivated(datum/component/C)
..()
if(istype(C, /datum/component/material_container))
@@ -95,3 +96,58 @@ Note: Must be placed west/left of and R&D console to function.
use_power(max(1000, (MINERAL_MATERIAL_AMOUNT * M.last_amount_inserted / 10)))
add_overlay("protolathe_[stack_name]")
addtimer(CALLBACK(src, /atom/proc/cut_overlay, "protolathe_[stack_name]"), 10)
+=======
+/obj/machinery/rnd/protolathe/proc/user_try_print_id(id, amount)
+ if((!istype(linked_console) && requires_console) || !id)
+ return FALSE
+ if(istext(amount))
+ amount = text2num(amount)
+ if(isnull(amount))
+ amount = 1
+ var/datum/design/D = (linked_console || requires_console)? linked_console.stored_research.researched_designs[id] : get_techweb_design_by_id(id)
+ if(!istype(D))
+ return FALSE
+ if(D.make_reagents.len)
+ return FALSE
+
+ var/power = 1000
+ amount = Clamp(amount, 1, 10)
+ for(var/M in D.materials)
+ power += round(D.materials[M] * amount / 5)
+ power = max(3000, power)
+ use_power(power)
+
+ var/list/efficient_mats = list()
+ for(var/MAT in D.materials)
+ efficient_mats[MAT] = D.materials[MAT]*efficiency_coeff
+
+ if(!materials.has_materials(efficient_mats, amount))
+ say("Not enough materials to complete prototype[amount > 1? "s" : ""].")
+ return FALSE
+ for(var/R in D.reagents_list)
+ if(!reagents.has_reagent(R, D.reagents_list[R]*efficiency_coeff))
+ say("Not enough reagents to complete prototype[amount > 1? "s" : ""].")
+ return FALSE
+
+ materials.use_amount(efficient_mats, amount)
+ for(var/R in D.reagents_list)
+ reagents.remove_reagent(R, D.reagents_list[R]*efficiency_coeff)
+
+ busy = TRUE
+ flick("protolathe_n", src)
+ var/timecoeff = efficiency_coeff * D.lathe_time_factor
+
+ addtimer(CALLBACK(src, .proc/reset_busy), (32 * timecoeff * amount) ** 0.8)
+ addtimer(CALLBACK(src, .proc/do_print, D.build_path, amount, efficient_mats, D.dangerous_construction), (32 * timecoeff * amount) ** 0.8)
+ return TRUE
+
+/obj/machinery/rnd/protolathe/proc/do_print(path, amount, list/matlist, notify_admins)
+ if(notify_admins && usr)
+ investigate_log("[key_name(usr)] built [amount] of [path] at a protolathe.", INVESTIGATE_RESEARCH)
+ message_admins("[ADMIN_LOOKUPFLW(usr)] has built [amount] of [path] at a protolathe")
+ for(var/i in 1 to amount)
+ var/obj/item/I = new path(get_turf(src))
+ if(!istype(I, /obj/item/stack/sheet) && !istype(I, /obj/item/ore/bluespace_crystal))
+ I.materials = matlist.Copy()
+ SSblackbox.record_feedback("nested_tally", "item_printed", amount, list("[type]", "[path]"))
+>>>>>>> 3aba012... Removes ComponentActivated in favor of callbacks (#33274)
diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm
index 973a496254..94ccfb4691 100644
--- a/code/modules/research/rdmachines.dm
+++ b/code/modules/research/rdmachines.dm
@@ -106,3 +106,15 @@
if(loaded_item)
loaded_item.forceMove(loc)
..()
+
+/obj/machinery/rnd/proc/AfterMaterialInsert(type_inserted, id_inserted, amount_inserted)
+ var/stack_name
+ if(ispath(type_inserted, /obj/item/ore/bluespace_crystal))
+ stack_name = "bluespace"
+ use_power(MINERAL_MATERIAL_AMOUNT / 10)
+ else
+ var/obj/item/stack/S = type_inserted
+ stack_name = initial(S.name)
+ use_power(max(1000, (MINERAL_MATERIAL_AMOUNT * amount_inserted / 10)))
+ add_overlay("protolathe_[stack_name]")
+ addtimer(CALLBACK(src, /atom/proc/cut_overlay, "protolathe_[stack_name]"), 10)