diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index ad9c8edf8f..fffcd6dada 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -271,18 +271,7 @@
if(resin_cooldown)
to_chat(user, "Resin launcher is still recharging...")
return
- resin_cooldown = TRUE
- R.remove_any(100)
- var/obj/effect/resin_container/A = new (get_turf(src))
- log_game("[key_name(user)] used Resin Launcher at [AREACOORD(user)].")
- playsound(src,'sound/items/syringeproj.ogg',40,1)
- for(var/a=0, a<5, a++)
- step_towards(A, target)
- sleep(2)
- A.Smoke()
- spawn(100)
- if(src)
- resin_cooldown = FALSE
+ launch_resin(target, user)
return
if(nozzle_mode == RESIN_FOAM)
if(!Adj|| !isturf(target))
@@ -301,6 +290,21 @@
to_chat(user, "Resin foam mix is still being synthesized...")
return
+/obj/item/extinguisher/mini/nozzle/proc/launch_resin(atom/target, mob/user)
+ set waitfor = FALSE
+ resin_cooldown = TRUE
+ reagents.remove_any(100)
+ var/obj/effect/resin_container/A = new (get_turf(src))
+ log_game("[key_name(user)] used Resin Launcher at [AREACOORD(user)].")
+ playsound(src,'sound/items/syringeproj.ogg',40,1)
+ for(var/a=0, a<5, a++)
+ step_towards(A, target)
+ sleep(2)
+ A.Smoke()
+ spawn(100)
+ if(src)
+ resin_cooldown = FALSE
+
/obj/effect/resin_container
name = "resin container"
desc = "A compacted ball of expansive resin, used to repair the atmosphere in a room, or seal off breaches."
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index 9bd1030685..521c32fe3d 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -387,8 +387,7 @@
log_combat(user, M, "used a cult spell on", source.name, "")
M.set_last_attacker(user)
-/obj/item/melee/blood_magic/afterattack(atom/target, mob/living/carbon/user, proximity)
- . = ..()
+/obj/item/melee/blood_magic/proc/post_cast(atom/target, mob/living/carbon/user, proximity)
if(invocation)
user.whisper(invocation, language = /datum/language/common)
if(health_cost)
@@ -467,6 +466,7 @@
to_chat(user, "In an brilliant flash of red, [L] [is_servant_of_ratvar(L) ? "writhes in pain!" : "falls to the ground!"]")
uses--
..()
+ post_cast(target, user, proximity)
//Teleportation
/obj/item/melee/blood_magic/teleport
@@ -480,40 +480,45 @@
to_chat(user, "You can only teleport adjacent cultists with this spell!")
return
if(iscultist(user))
- var/list/potential_runes = list()
- var/list/teleportnames = list()
- for(var/R in GLOB.teleport_runes)
- var/obj/effect/rune/teleport/T = R
- potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T
-
- if(!potential_runes.len)
- to_chat(user, "There are no valid runes to teleport to!")
- log_game("Teleport talisman failed - no other teleport runes")
- return
-
- var/turf/T = get_turf(src)
- if(is_away_level(T.z))
- to_chat(user, "You are not in the right dimension!")
- log_game("Teleport spell failed - user in away mission")
- return
-
- var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked
- var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
- if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity)
- return
- var/turf/dest = get_turf(actual_selected_rune)
- if(is_blocked_turf(dest, TRUE))
- to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.")
- return
- uses--
- var/turf/origin = get_turf(user)
- var/mob/living/L = target
- if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
- origin.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \
- "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.")
- dest.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
+ try_teleport(target, user, proximity)
..()
+/obj/item/melee/blood_magic/teleport/proc/try_teleport(atom/target, mob/living/carbon/user, proximity)
+ set waitfor = FALSE
+ var/list/potential_runes = list()
+ var/list/teleportnames = list()
+ for(var/R in GLOB.teleport_runes)
+ var/obj/effect/rune/teleport/T = R
+ potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T
+
+ if(!potential_runes.len)
+ to_chat(user, "There are no valid runes to teleport to!")
+ log_game("Teleport talisman failed - no other teleport runes")
+ return
+
+ var/turf/T = get_turf(src)
+ if(is_away_level(T.z))
+ to_chat(user, "You are not in the right dimension!")
+ log_game("Teleport spell failed - user in away mission")
+ return
+
+ var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked
+ var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
+ if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity)
+ return
+ var/turf/dest = get_turf(actual_selected_rune)
+ if(is_blocked_turf(dest, TRUE))
+ to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.")
+ return
+ uses--
+ var/turf/origin = get_turf(user)
+ var/mob/living/L = target
+ if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
+ origin.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \
+ "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.")
+ dest.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
+ post_cast(target, user, proximity)
+
//Shackles
/obj/item/melee/blood_magic/shackles
name = "Binding Aura"
@@ -530,6 +535,7 @@
user.visible_message("This victim doesn't have enough arms to complete the restraint!")
return
..()
+ post_cast(target, user, proximity)
/obj/item/melee/blood_magic/shackles/proc/CuffAttack(mob/living/carbon/C, mob/living/user)
if(!C.handcuffed)
@@ -583,6 +589,7 @@
to_chat(user, "A dark cloud emanates from your hand and swirls around the metal, twisting it into a construct shell!")
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, proximity_flag, user)
else
to_chat(user, "You need 50 metal to produce a construct shell!")
else if(istype(target, /obj/item/stack/sheet/plasteel))
@@ -593,56 +600,73 @@
new /obj/item/stack/sheet/runed_metal(T,quantity)
to_chat(user, "A dark cloud emanates from you hand and swirls around the plasteel, transforming it into runed metal!")
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, user, proximity_flag)
if(istype(target, /obj/item/clothing/suit/hooded/wintercoat) && target.type != /obj/item/clothing/suit/hooded/wintercoat/narsie)
- if (do_after(user,30,target=target))
- new /obj/item/clothing/suit/hooded/wintercoat/narsie(T)
- qdel(target)
- to_chat(user, "A dark cloud emanates from you hand and swirls around [target], transforming it into a narsian winter coat!")
- SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ convert_coat(target, user, proximity_flag, T)
else if(istype(target,/mob/living/silicon/robot))
- var/mob/living/silicon/robot/candidate = target
- if(!iscultist(user, TRUE))
- to_chat(user, "You are not strongly connected enough to Nar'sie to use make constructs...")
- else if(candidate.mmi)
- user.visible_message("A dark cloud emanates from [user]'s hand and swirls around [candidate]!")
- playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
- var/prev_color = candidate.color
- candidate.color = "black"
- if(do_after(user, 90, target = candidate))
- candidate.emp_act(80)
- var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
- user.visible_message("The dark cloud receedes from what was formerly [candidate], revealing a\n [construct_class]!")
- switch(construct_class)
- if("Juggernaut")
- makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, candidate, user, 0, T)
- if("Wraith")
- makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, candidate, user, 0, T)
- if("Artificer")
- makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, candidate, user, 0, T)
- SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
- uses--
- candidate.mmi = null
- qdel(candidate)
- else
- candidate.color = prev_color
- else
- uses--
- to_chat(user, "A dark cloud emanates from you hand and swirls around [candidate] - twisting it into a construct shell!")
- new /obj/structure/constructshell(T)
- SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ convert_borg(target, user, proximity_flag, T)
else if(istype(target,/obj/machinery/door/airlock))
- playsound(T, 'sound/machines/airlockforced.ogg', 50, 1)
- do_sparks(5, TRUE, target)
- if(do_after(user, 50, target = user))
- target.narsie_act()
- uses--
- user.visible_message("Black ribbons suddenly emanate from [user]'s hand and cling to the airlock - twisting and corrupting it!")
- SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ convert_door(target, user, proximity_flag, T)
else
to_chat(user, "The spell will not work on [target]!")
return
..()
+/obj/item/melee/blood_magic/construction/proc/convert_coat(atom/target, mob/user, proximity_flag, turf/T)
+ set waitfor = FALSE
+ if(do_after(user,30,target=target))
+ new /obj/item/clothing/suit/hooded/wintercoat/narsie(T)
+ qdel(target)
+ to_chat(user, "A dark cloud emanates from you hand and swirls around [target], transforming it into a narsian winter coat!")
+ SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, user, proximity_flag)
+
+/obj/item/melee/blood_magic/construction/proc/convert_door(atom/target, mob/user, proximity_flag, turf/T)
+ set waitfor = FALSE
+ playsound(T, 'sound/machines/airlockforced.ogg', 50, 1)
+ do_sparks(5, TRUE, target)
+ if(do_after(user, 50, target = user))
+ target.narsie_act()
+ uses--
+ user.visible_message("Black ribbons suddenly emanate from [user]'s hand and cling to the airlock - twisting and corrupting it!")
+ SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, user, proximity_flag)
+
+/obj/item/melee/blood_magic/construction/proc/convert_borg(atom/target, mob/user, proximity_flag, turf/T)
+ set waitfor = FALSE
+ var/mob/living/silicon/robot/candidate = target
+ if(!iscultist(user, TRUE))
+ to_chat(user, "You are not strongly connected enough to Nar'sie to use make constructs...")
+ return
+ else if(candidate.mmi)
+ user.visible_message("A dark cloud emanates from [user]'s hand and swirls around [candidate]!")
+ playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
+ var/prev_color = candidate.color
+ candidate.color = "black"
+ if(do_after(user, 90, target = candidate))
+ candidate.emp_act(80)
+ var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
+ user.visible_message("The dark cloud receedes from what was formerly [candidate], revealing a\n [construct_class]!")
+ switch(construct_class)
+ if("Juggernaut")
+ makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, candidate, user, 0, T)
+ if("Wraith")
+ makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, candidate, user, 0, T)
+ if("Artificer")
+ makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, candidate, user, 0, T)
+ SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ uses--
+ candidate.mmi = null
+ qdel(candidate)
+ else
+ candidate.color = prev_color
+ else
+ uses--
+ to_chat(user, "A dark cloud emanates from you hand and swirls around [candidate] - twisting it into a construct shell!")
+ new /obj/structure/constructshell(T)
+ SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, user, proximity_flag)
+
//Armor: Gives the target a basic cultist combat loadout
/obj/item/melee/blood_magic/armor
name = "Bladed Aura"
@@ -665,6 +689,7 @@
C.put_in_hands(new /obj/item/melee/cultblade(user))
C.put_in_hands(new /obj/item/restraints/legcuffs/bola/cult(user))
..()
+ post_cast(target, user, proximity)
/obj/item/melee/blood_magic/manipulator
name = "Ritual Aura"
@@ -693,7 +718,9 @@
H.adjust_integration_blood(uses * 2)
to_chat(user,"You use the last of your blood rites to restore what blood you could!")
uses = 0
- return ..()
+ ..()
+ post_cast(target, user, proximity)
+ return
else
H.blood_volume = (BLOOD_VOLUME_SAFE*H.blood_ratio)
uses -= round(restore_blood/2)
@@ -758,6 +785,7 @@
if(istype(target, /obj/effect/decal/cleanable/blood))
blood_draw(target, user)
..()
+ post_cast()
/obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user)
var/temp = 0
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index 35151953a0..20e41828d4 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -660,40 +660,42 @@
return
if(istype(A, /obj/item))
-
- var/list/cultists = list()
- for(var/datum/mind/M in SSticker.mode.cult)
- if(M.current && M.current.stat != DEAD)
- cultists |= M.current
- var/mob/living/cultist_to_receive = input(user, "Who do you wish to call to [src]?", "Followers of the Geometer") as null|anything in (cultists - user)
- if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated())
- return
- if(!cultist_to_receive)
- to_chat(user, "You require a destination!")
- log_game("Void torch failed - no target")
- return
- if(cultist_to_receive.stat == DEAD)
- to_chat(user, "[cultist_to_receive] has died!")
- log_game("Void torch failed - target died")
- return
- if(!iscultist(cultist_to_receive))
- to_chat(user, "[cultist_to_receive] is not a follower of the Geometer!")
- log_game("Void torch failed - target was deconverted")
- return
- if(A in user.GetAllContents())
- to_chat(user, "[A] must be on a surface in order to teleport it!")
- return
- to_chat(user, "You ignite [A] with \the [src], turning it to ash, but through the torch's flames you see that [A] has reached [cultist_to_receive]!")
- cultist_to_receive.put_in_hands(A)
- charges--
- to_chat(user, "\The [src] now has [charges] charge\s.")
- if(charges == 0)
- qdel(src)
+ transmit_item(A, user, proximity)
else
..()
to_chat(user, "\The [src] can only transport items!")
+/obj/item/flashlight/flare/culttorch/proc/transmit_item(atom/movable/A, mob/user, proximity)
+ set waitfor = FALSE
+ var/list/cultists = list()
+ for(var/datum/mind/M in SSticker.mode.cult)
+ if(M.current && M.current.stat != DEAD)
+ cultists |= M.current
+ var/mob/living/cultist_to_receive = input(user, "Who do you wish to call to [src]?", "Followers of the Geometer") as null|anything in (cultists - user)
+ if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated())
+ return
+ if(!cultist_to_receive)
+ to_chat(user, "You require a destination!")
+ log_game("Void torch failed - no target")
+ return
+ if(cultist_to_receive.stat == DEAD)
+ to_chat(user, "[cultist_to_receive] has died!")
+ log_game("Void torch failed - target died")
+ return
+ if(!iscultist(cultist_to_receive))
+ to_chat(user, "[cultist_to_receive] is not a follower of the Geometer!")
+ log_game("Void torch failed - target was deconverted")
+ return
+ if(A in user.GetAllContents())
+ to_chat(user, "[A] must be on a surface in order to teleport it!")
+ return
+ to_chat(user, "You ignite [A] with \the [src], turning it to ash, but through the torch's flames you see that [A] has reached [cultist_to_receive]!")
+ cultist_to_receive.put_in_hands(A)
+ charges--
+ to_chat(user, "\The [src] now has [charges] charge\s.")
+ if(charges == 0)
+ qdel(src)
/obj/item/cult_spear
name = "blood halberd"
diff --git a/code/modules/mining/fulton.dm b/code/modules/mining/fulton.dm
index 5044a73c10..adee8b66ce 100644
--- a/code/modules/mining/fulton.dm
+++ b/code/modules/mining/fulton.dm
@@ -60,83 +60,86 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
return
if(A.anchored || (A.move_resist > max_force_fulton))
return
- to_chat(user, "You start attaching the pack to [A]...")
- if(do_after(user,50,target=A))
- to_chat(user, "You attach the pack to [A] and activate it.")
- if(loc == user && istype(user.back, /obj/item/storage/backpack))
- var/obj/item/storage/backpack/B = user.back
- SEND_SIGNAL(B, COMSIG_TRY_STORAGE_INSERT, src, user, FALSE, FALSE)
- uses_left--
- if(uses_left <= 0)
- user.transferItemToLoc(src, A, TRUE)
- var/mutable_appearance/balloon
- var/mutable_appearance/balloon2
- var/mutable_appearance/balloon3
- if(isliving(A))
- var/mob/living/M = A
- M.DefaultCombatKnockdown(320) // Keep them from moving during the duration of the extraction
- M.buckled = 0 // Unbuckle them to prevent anchoring problems
- else
- A.anchored = TRUE
- A.density = FALSE
- var/obj/effect/extraction_holder/holder_obj = new(A.loc)
- holder_obj.appearance = A.appearance
- A.forceMove(holder_obj)
- balloon2 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_expand")
- balloon2.pixel_y = 10
- balloon2.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
- holder_obj.add_overlay(balloon2)
- sleep(4)
- balloon = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_balloon")
- balloon.pixel_y = 10
- balloon.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
- holder_obj.cut_overlay(balloon2)
- holder_obj.add_overlay(balloon)
- playsound(holder_obj.loc, 'sound/items/fulext_deploy.wav', 50, 1, -3)
- animate(holder_obj, pixel_z = 10, time = 20)
- sleep(20)
- animate(holder_obj, pixel_z = 15, time = 10)
- sleep(10)
- animate(holder_obj, pixel_z = 10, time = 10)
- sleep(10)
- animate(holder_obj, pixel_z = 15, time = 10)
- sleep(10)
- animate(holder_obj, pixel_z = 10, time = 10)
- sleep(10)
- playsound(holder_obj.loc, 'sound/items/fultext_launch.wav', 50, 1, -3)
- animate(holder_obj, pixel_z = 1000, time = 30)
- if(ishuman(A))
- var/mob/living/carbon/human/L = A
- L.SetUnconscious(0)
- L.drowsyness = 0
- L.SetSleeping(0)
- sleep(30)
- var/list/flooring_near_beacon = list()
- for(var/turf/open/floor in orange(1, beacon))
- flooring_near_beacon += floor
- holder_obj.forceMove(pick(flooring_near_beacon))
- animate(holder_obj, pixel_z = 10, time = 50)
- sleep(50)
- animate(holder_obj, pixel_z = 15, time = 10)
- sleep(10)
- animate(holder_obj, pixel_z = 10, time = 10)
- sleep(10)
- balloon3 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_retract")
- balloon3.pixel_y = 10
- balloon3.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
- holder_obj.cut_overlay(balloon)
- holder_obj.add_overlay(balloon3)
- sleep(4)
- holder_obj.cut_overlay(balloon3)
- A.anchored = FALSE // An item has to be unanchored to be extracted in the first place.
- A.density = initial(A.density)
- animate(holder_obj, pixel_z = 0, time = 5)
- sleep(5)
- A.forceMove(holder_obj.loc)
- qdel(holder_obj)
- if(uses_left <= 0)
- qdel(src)
+ attach_fulton(A, user, flag, params)
+/obj/item/extraction_pack/proc/attach_fulton(atom/movable/A, mob/living/carbon/human/user, flag, params)
+ set waitfor = FALSE
+ to_chat(user, "You start attaching the pack to [A]...")
+ if(do_after(user,50,target=A))
+ to_chat(user, "You attach the pack to [A] and activate it.")
+ if(loc == user && istype(user.back, /obj/item/storage/backpack))
+ var/obj/item/storage/backpack/B = user.back
+ SEND_SIGNAL(B, COMSIG_TRY_STORAGE_INSERT, src, user, FALSE, FALSE)
+ uses_left--
+ if(uses_left <= 0)
+ user.transferItemToLoc(src, A, TRUE)
+ var/mutable_appearance/balloon
+ var/mutable_appearance/balloon2
+ var/mutable_appearance/balloon3
+ if(isliving(A))
+ var/mob/living/M = A
+ M.DefaultCombatKnockdown(320) // Keep them from moving during the duration of the extraction
+ M.buckled = 0 // Unbuckle them to prevent anchoring problems
+ else
+ A.anchored = TRUE
+ A.density = FALSE
+ var/obj/effect/extraction_holder/holder_obj = new(A.loc)
+ holder_obj.appearance = A.appearance
+ A.forceMove(holder_obj)
+ balloon2 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_expand")
+ balloon2.pixel_y = 10
+ balloon2.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
+ holder_obj.add_overlay(balloon2)
+ sleep(4)
+ balloon = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_balloon")
+ balloon.pixel_y = 10
+ balloon.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
+ holder_obj.cut_overlay(balloon2)
+ holder_obj.add_overlay(balloon)
+ playsound(holder_obj.loc, 'sound/items/fulext_deploy.wav', 50, 1, -3)
+ animate(holder_obj, pixel_z = 10, time = 20)
+ sleep(20)
+ animate(holder_obj, pixel_z = 15, time = 10)
+ sleep(10)
+ animate(holder_obj, pixel_z = 10, time = 10)
+ sleep(10)
+ animate(holder_obj, pixel_z = 15, time = 10)
+ sleep(10)
+ animate(holder_obj, pixel_z = 10, time = 10)
+ sleep(10)
+ playsound(holder_obj.loc, 'sound/items/fultext_launch.wav', 50, 1, -3)
+ animate(holder_obj, pixel_z = 1000, time = 30)
+ if(ishuman(A))
+ var/mob/living/carbon/human/L = A
+ L.SetUnconscious(0)
+ L.drowsyness = 0
+ L.SetSleeping(0)
+ sleep(30)
+ var/list/flooring_near_beacon = list()
+ for(var/turf/open/floor in orange(1, beacon))
+ flooring_near_beacon += floor
+ holder_obj.forceMove(pick(flooring_near_beacon))
+ animate(holder_obj, pixel_z = 10, time = 50)
+ sleep(50)
+ animate(holder_obj, pixel_z = 15, time = 10)
+ sleep(10)
+ animate(holder_obj, pixel_z = 10, time = 10)
+ sleep(10)
+ balloon3 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_retract")
+ balloon3.pixel_y = 10
+ balloon3.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
+ holder_obj.cut_overlay(balloon)
+ holder_obj.add_overlay(balloon3)
+ sleep(4)
+ holder_obj.cut_overlay(balloon3)
+ A.anchored = FALSE // An item has to be unanchored to be extracted in the first place.
+ A.density = initial(A.density)
+ animate(holder_obj, pixel_z = 0, time = 5)
+ sleep(5)
+ A.forceMove(holder_obj.loc)
+ qdel(holder_obj)
+ if(uses_left <= 0)
+ qdel(src)
/obj/item/fulton_core
name = "extraction beacon signaller"
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index b4f1acbed4..41e22de9e6 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -148,6 +148,10 @@
/obj/item/pen/afterattack(obj/O, mob/living/user, proximity)
. = ..()
//Changing name/description of items. Only works if they have the UNIQUE_RENAME object flag set
+ try_modify_object(O, user, proximity)
+
+/obj/item/pen/proc/try_modify_object(obj/O, mob/living/user, proximity)
+ set waitfor = FALSE
if(isobj(O) && proximity && (O.obj_flags & UNIQUE_RENAME))
var/penchoice = input(user, "What would you like to edit?", "Rename, change description or reset both?") as null|anything in list("Rename","Change description","Reset")
if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE))
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 70cd28718c..9bf794a0a2 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -735,7 +735,10 @@
if(jb)
to_chat(user, "Your mind goes blank as you attempt to use the potion.")
return
+ try_transfer_mind(SM, user)
+/obj/item/slimepotion/transference/proc/try_transfer_mind(mob/living/simple_animal/SM, mob/user)
+ set waitfor = FALSE
prompted = 1
if(alert("This will permanently transfer your consciousness to [SM]. Are you sure you want to do this?",,"Yes","No")=="No")
prompted = 0