Improper forced qdel cleanup, some expanded del all verbs (#66595)

* Removes all supurfolus uses of QDEL_HINT_LETMELIVE

This define exists to allow abstract, sturucturally important things to
opt out of being qdeleted.
It does not exist to be a "Immune to everything" get out of jail free
card.
We have systems for this, and it's not appropriate here.

This change is inherently breaking, because things might be improperly
qdeling these things. Those issues will need to be resolved in future,
as they pop up

* Changes all needless uses of COMSIG_PARENT_PREQDELETED

It exists for things that want to block the qdel. If that's not you,
don't use it

* Adds force and hard del verbs, for chip and break glass cases
respectively

The harddel verb comes with two options before it's run, to let you
tailor it to your level of fucked

* Damn you nova

Adds proper parent returns instead of . = ..()

Co-authored-by: Seth Scherer <supernovaa41@gmx.com>

* Ensures immortality talismans cannot delete their human if something goes fuckey. Thanks ath/oro for pointing this out

Co-authored-by: Seth Scherer <supernovaa41@gmx.com>
This commit is contained in:
LemonInTheDark
2022-05-06 17:52:45 -07:00
committed by GitHub
parent d61fa9df81
commit 0504c0a2b4
20 changed files with 153 additions and 98 deletions
@@ -8,6 +8,8 @@
/// before a component is removed from a datum because of ClearFromParent: (/datum/component)
#define COMSIG_COMPONENT_REMOVING "component_removing"
/// before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation
/// you should only be using this if you want to block deletion
/// that's the only functional difference between it and COMSIG_PARENT_QDELETING, outside setting QDELETING to detect
#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted"
/// just before a datum's Destroy() is called: (force), at this point none of the other components chose to interrupt qdel and Destroy will be called
#define COMSIG_PARENT_QDELETING "parent_qdeleting"
-3
View File
@@ -92,9 +92,6 @@
///Call qdel on the atom after intialization
#define INITIALIZE_HINT_QDEL 2
///Call qdel with a force of TRUE after initialization
#define INITIALIZE_HINT_QDEL_FORCE 3
///type and all subtypes should always immediately call Initialize in New()
#define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\
..();\
-3
View File
@@ -136,9 +136,6 @@ SUBSYSTEM_DEF(atoms)
if(INITIALIZE_HINT_QDEL)
qdel(A)
qdeleted = TRUE
if(INITIALIZE_HINT_QDEL_FORCE)
qdel(A, force = TRUE)
qdeleted = TRUE
else
BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT
@@ -104,7 +104,7 @@ SUBSYSTEM_DEF(spatial_grid)
if(movable_turf)
enter_cell(movable, movable_turf)
UnregisterSignal(movable, COMSIG_PARENT_PREQDELETED)
UnregisterSignal(movable, COMSIG_PARENT_QDELETING)
waiting_to_add_by_type[channel_type] -= movable
pregenerate_more_oranges_ears(NUMBER_OF_PREGENERATED_ORANGES_EARS)
@@ -114,7 +114,7 @@ SUBSYSTEM_DEF(spatial_grid)
///add a movable to the pre init queue for whichever type is specified so that when the subsystem initializes they get added to the grid
/datum/controller/subsystem/spatial_grid/proc/enter_pre_init_queue(atom/movable/waiting_movable, type)
RegisterSignal(waiting_movable, COMSIG_PARENT_PREQDELETED, .proc/queued_item_deleted, override = TRUE)
RegisterSignal(waiting_movable, COMSIG_PARENT_QDELETING, .proc/queued_item_deleted, override = TRUE)
//override because something can enter the queue for two different types but that is done through unrelated procs that shouldnt know about eachother
waiting_to_add_by_type[type] += waiting_movable
@@ -129,11 +129,11 @@ SUBSYSTEM_DEF(spatial_grid)
waiting_movable_is_in_other_queues = TRUE
if(!waiting_movable_is_in_other_queues)
UnregisterSignal(movable_to_remove, COMSIG_PARENT_PREQDELETED)
UnregisterSignal(movable_to_remove, COMSIG_PARENT_QDELETING)
return
UnregisterSignal(movable_to_remove, COMSIG_PARENT_PREQDELETED)
UnregisterSignal(movable_to_remove, COMSIG_PARENT_QDELETING)
for(var/type in waiting_to_add_by_type)
waiting_to_add_by_type[type] -= movable_to_remove
+1 -1
View File
@@ -11,7 +11,7 @@
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/applyplate)
RegisterSignal(parent, COMSIG_PARENT_PREQDELETED, .proc/dropplates)
RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/dropplates)
if(istype(parent, /obj/vehicle/sealed/mecha/working/ripley))
RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_mech_overlays)
+2 -2
View File
@@ -58,7 +58,7 @@
if(usage_flags & SHOCK_REQUIREMENT_ITEM)
required_object = input_item
required_object.Move(parent_as_movable)
RegisterSignal(required_object, COMSIG_PARENT_PREQDELETED, .proc/delete_self)
RegisterSignal(required_object, COMSIG_PARENT_QDELETING, .proc/delete_self)
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER), .proc/move_required_object_from_contents)
if(usage_flags & SHOCK_REQUIREMENT_ON_SIGNAL_RECEIVED)
@@ -109,7 +109,7 @@
UnregisterSignal(parent, requested_signal_parent_emits)
if(required_object)
UnregisterSignal(required_object, list(COMSIG_PARENT_PREQDELETED, COMSIG_ASSEMBLY_PULSED))
UnregisterSignal(required_object, list(COMSIG_PARENT_QDELETING, COMSIG_ASSEMBLY_PULSED))
if(parent_as_movable && (required_object in parent_as_movable.contents))
required_object.Move(parent_as_movable.loc)
+2 -2
View File
@@ -63,7 +63,7 @@
if(!QDELETED(shooter))
RegisterSignal(shooter, COMSIG_MOB_LOGOUT, .proc/autofire_off)
UnregisterSignal(shooter, COMSIG_MOB_LOGIN)
RegisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_ITEM_DROPPED), .proc/autofire_off)
RegisterSignal(parent, list(COMSIG_PARENT_QDELETING, COMSIG_ITEM_DROPPED), .proc/autofire_off)
parent.RegisterSignal(src, COMSIG_AUTOFIRE_ONMOUSEDOWN, /obj/item/gun/.proc/autofire_bypass_check)
parent.RegisterSignal(parent, COMSIG_AUTOFIRE_SHOT, /obj/item/gun/.proc/do_autofire)
@@ -84,7 +84,7 @@
if(!QDELETED(shooter))
RegisterSignal(shooter, COMSIG_MOB_LOGIN, .proc/on_client_login)
UnregisterSignal(shooter, COMSIG_MOB_LOGOUT)
UnregisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_ITEM_DROPPED))
UnregisterSignal(parent, list(COMSIG_PARENT_QDELETING, COMSIG_ITEM_DROPPED))
shooter = null
parent.UnregisterSignal(parent, COMSIG_AUTOFIRE_SHOT)
parent.UnregisterSignal(src, COMSIG_AUTOFIRE_ONMOUSEDOWN)
+2 -2
View File
@@ -50,14 +50,14 @@
RegisterSignal(parent, list(COMSIG_COMPONENT_ADDED), .proc/enable)
/datum/component/plumbing/RegisterWithParent()
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED,COMSIG_PARENT_PREQDELETED), .proc/disable)
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING), .proc/disable)
RegisterSignal(parent, list(COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH), .proc/toggle_active)
RegisterSignal(parent, list(COMSIG_OBJ_HIDE), .proc/hide)
RegisterSignal(parent, list(COMSIG_ATOM_UPDATE_OVERLAYS), .proc/create_overlays) //called by lateinit on startup
RegisterSignal(parent, list(COMSIG_MOVABLE_CHANGE_DUCT_LAYER), .proc/change_ducting_layer)
/datum/component/plumbing/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED,COMSIG_PARENT_PREQDELETED, COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH,COMSIG_OBJ_HIDE, \
UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING, COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH, COMSIG_OBJ_HIDE, \
COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_MOVABLE_CHANGE_DUCT_LAYER, COMSIG_COMPONENT_ADDED))
/datum/component/plumbing/Destroy()
+2 -2
View File
@@ -95,7 +95,7 @@
holder = equipper
qdel(GetComponent(/datum/component/connect_loc_behalf))
AddComponent(/datum/component/connect_loc_behalf, holder, holder_connections)
RegisterSignal(holder, COMSIG_PARENT_PREQDELETED, .proc/holder_deleted)
RegisterSignal(holder, COMSIG_PARENT_QDELETING, .proc/holder_deleted)
/*
* Detects if the holder mob is deleted.
@@ -120,7 +120,7 @@
/datum/component/slippery/proc/on_drop(datum/source, mob/user)
SIGNAL_HANDLER
UnregisterSignal(user, COMSIG_PARENT_PREQDELETED)
UnregisterSignal(user, COMSIG_PARENT_QDELETING)
qdel(GetComponent(/datum/component/connect_loc_behalf))
add_connect_loc_behalf_to_parent()
+2 -2
View File
@@ -112,7 +112,7 @@
SIGNAL_HANDLER
holder = equipper
RegisterSignal(holder, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react, override=TRUE)
RegisterSignal(holder, COMSIG_PARENT_PREQDELETED, .proc/holder_deleted, override=TRUE)
RegisterSignal(holder, COMSIG_PARENT_QDELETING, .proc/holder_deleted, override=TRUE)
//override for the preqdeleted is necessary because putting parent in hands sends the signal that this proc is registered towards,
//so putting an object in hands and then equipping the item on a clothing slot (without dropping it first)
//will always runtime without override = TRUE
@@ -120,7 +120,7 @@
/datum/component/squeak/proc/on_drop(datum/source, mob/user)
SIGNAL_HANDLER
UnregisterSignal(user, COMSIG_MOVABLE_DISPOSING)
UnregisterSignal(user, COMSIG_PARENT_PREQDELETED)
UnregisterSignal(user, COMSIG_PARENT_QDELETING)
holder = null
///just gets rid of the reference to holder in the case that theyre qdeleted
@@ -174,7 +174,7 @@ DEFINE_BITFIELD(turret_flags, list(
turret_gun.forceMove(src)
stored_gun = turret_gun
RegisterSignal(stored_gun, COMSIG_PARENT_PREQDELETED, .proc/null_gun)
RegisterSignal(stored_gun, COMSIG_PARENT_QDELETING, .proc/null_gun)
var/list/gun_properties = stored_gun.get_turret_properties()
//required properties
-2
View File
@@ -26,8 +26,6 @@
return INITIALIZE_HINT_LATELOAD
/obj/structure/ladder/Destroy(force)
if ((resistance_flags & INDESTRUCTIBLE) && !force)
return QDEL_HINT_LETMELIVE
GLOB.ladders -= src
disconnect()
return ..()
+6
View File
@@ -126,6 +126,8 @@ GLOBAL_PROTECT(admin_verbs_server)
/datum/admins/proc/toggleAI,
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
/client/proc/cmd_debug_del_all,
/client/proc/cmd_debug_force_del_all,
/client/proc/cmd_debug_hard_del_all,
/client/proc/toggle_random_events,
/client/proc/forcerandomrotate,
/client/proc/adminchangemap,
@@ -146,6 +148,8 @@ GLOBAL_PROTECT(admin_verbs_debug)
/client/proc/cmd_debug_mob_lists,
/client/proc/cmd_admin_delete,
/client/proc/cmd_debug_del_all,
/client/proc/cmd_debug_force_del_all,
/client/proc/cmd_debug_hard_del_all,
/client/proc/restart_controller,
/client/proc/enable_mapping_verbs,
/client/proc/callproc,
@@ -257,6 +261,8 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
/client/proc/cmd_debug_make_powernets,
/client/proc/cmd_debug_mob_lists,
/client/proc/cmd_debug_del_all,
/client/proc/cmd_debug_force_del_all,
/client/proc/cmd_debug_hard_del_all,
/client/proc/enable_mapping_verbs,
/proc/possess,
/proc/release,
+88 -16
View File
@@ -69,30 +69,102 @@
SSpai.candidates.Remove(candidate)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Make pAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/poll_type_to_del(search_string)
var/list/types = get_fancy_list_of_atom_types()
if (!isnull(search_string) && search_string != "")
types = filter_fancy_list(types, search_string)
if(!length(types))
return
var/key = input(usr, "Choose an object to delete.", "Delete:") as null|anything in sort_list(types)
if(!key)
return
return types[key]
//TODO: merge the vievars version into this or something maybe mayhaps
/client/proc/cmd_debug_del_all(object as text)
set category = "Debug"
set name = "Del-All"
var/list/matches = get_fancy_list_of_atom_types()
if (!isnull(object) && object!="")
matches = filter_fancy_list(matches, object)
var/type_to_del = poll_type_to_del(object)
if(matches.len==0)
if(!type_to_del)
return
var/hsbitem = input(usr, "Choose an object to delete.", "Delete:") as null|anything in sort_list(matches)
if(hsbitem)
hsbitem = matches[hsbitem]
var/counter = 0
for(var/atom/O in world)
if(istype(O, hsbitem))
counter++
qdel(O)
CHECK_TICK
log_admin("[key_name(src)] has deleted all ([counter]) instances of [hsbitem].")
message_admins("[key_name_admin(src)] has deleted all ([counter]) instances of [hsbitem].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete All") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
var/counter = 0
for(var/atom/O in world)
if(istype(O, type_to_del))
counter++
qdel(O)
CHECK_TICK
log_admin("[key_name(src)] has deleted all ([counter]) instances of [type_to_del].")
message_admins("[key_name_admin(src)] has deleted all ([counter]) instances of [type_to_del].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete All") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_debug_force_del_all(object as text)
set category = "Debug"
set name = "Force-Del-All"
var/type_to_del = poll_type_to_del(object)
if(!type_to_del)
return
var/counter = 0
for(var/atom/O in world)
if(istype(O, type_to_del))
counter++
qdel(O, force = TRUE)
CHECK_TICK
log_admin("[key_name(src)] has force-deleted all ([counter]) instances of [type_to_del].")
message_admins("[key_name_admin(src)] has force-deleted all ([counter]) instances of [type_to_del].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Force-Delete All") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_debug_hard_del_all(object as text)
set category = "Debug"
set name = "Hard-Del-All"
var/type_to_del = poll_type_to_del(object)
if(!type_to_del)
return
var/choice = alert("ARE YOU SURE that you want to hard delete this type? It will cause MASSIVE lag.", "Hoooo lad what happen?", "Yes", "No")
if(choice != "Yes")
return
choice = alert("Do you want to pre qdelete the atom? This will speed things up significantly, but may break depending on your level of fuckup.", "How do you even get it that bad", "Yes", "No")
var/should_pre_qdel = TRUE
if(choice == "No")
should_pre_qdel = FALSE
choice = alert("Ok one last thing, do you want to yield to the game? or do it all at once. These are hard deletes remember.", "Jesus christ man", "Yield", "Ignore the server")
var/should_check_tick = TRUE
if(choice == "Ignore the server")
should_check_tick = FALSE
var/counter = 0
if(should_check_tick)
for(var/atom/O in world)
if(istype(O, type_to_del))
counter++
if(should_pre_qdel)
qdel(O)
del(O)
CHECK_TICK
else
for(var/atom/O in world)
if(istype(O, type_to_del))
counter++
if(should_pre_qdel)
qdel(O)
del(O)
CHECK_TICK
log_admin("[key_name(src)] has hard deleted all ([counter]) instances of [type_to_del].")
message_admins("[key_name_admin(src)] has hard deleted all ([counter]) instances of [type_to_del].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Hard Delete All") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_debug_make_powernets()
set category = "Debug"
+5 -5
View File
@@ -269,7 +269,7 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf
spawned -= holo_atom
continue
RegisterSignal(holo_atom, COMSIG_PARENT_PREQDELETED, .proc/remove_from_holo_lists)
RegisterSignal(holo_atom, COMSIG_PARENT_QDELETING, .proc/remove_from_holo_lists)
holo_atom.flags_1 |= HOLOGRAM_1
if(isholoeffect(holo_atom))//activates holo effects and transfers them from the spawned list into the effects list
@@ -279,10 +279,10 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf
var/atom/holo_effect_product = holo_effect.activate(src)//change name
if(istype(holo_effect_product))
spawned += holo_effect_product // we want mobs or objects spawned via holoeffects to be tracked as objects
RegisterSignal(holo_effect_product, COMSIG_PARENT_PREQDELETED, .proc/remove_from_holo_lists)
RegisterSignal(holo_effect_product, COMSIG_PARENT_QDELETING, .proc/remove_from_holo_lists)
if(islist(holo_effect_product))
for(var/atom/atom_product as anything in holo_effect_product)
RegisterSignal(atom_product, COMSIG_PARENT_PREQDELETED, .proc/remove_from_holo_lists)
RegisterSignal(atom_product, COMSIG_PARENT_QDELETING, .proc/remove_from_holo_lists)
continue
if(isobj(holo_atom))
@@ -309,7 +309,7 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf
spawned -= holo_atom
if(!holo_atom)
return
UnregisterSignal(holo_atom, COMSIG_PARENT_PREQDELETED)
UnregisterSignal(holo_atom, COMSIG_PARENT_QDELETING)
var/turf/target_turf = get_turf(holo_atom)
for(var/atom/movable/atom_contents as anything in holo_atom) //make sure that things inside of a holoitem are moved outside before destroying it
atom_contents.forceMove(target_turf)
@@ -328,7 +328,7 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf
/obj/machinery/computer/holodeck/proc/remove_from_holo_lists(datum/to_remove, _forced)
SIGNAL_HANDLER
spawned -= to_remove
UnregisterSignal(to_remove, COMSIG_PARENT_PREQDELETED)
UnregisterSignal(to_remove, COMSIG_PARENT_QDELETING)
/obj/machinery/computer/holodeck/process(delta_time)
if(damaged && DT_PROB(5, delta_time))
@@ -53,11 +53,8 @@
AddElement(/datum/element/connect_loc, loc_connections)
/obj/structure/necropolis_gate/Destroy(force)
if(force)
qdel(sight_blocker, TRUE)
. = ..()
else
return QDEL_HINT_LETMELIVE
qdel(sight_blocker)
return ..()
/obj/structure/necropolis_gate/singularity_pull()
return 0
@@ -92,13 +89,7 @@
anchored = TRUE
/obj/structure/opacity_blocker/singularity_pull()
return 0
/obj/structure/opacity_blocker/Destroy(force)
if(force)
. = ..()
else
return QDEL_HINT_LETMELIVE
return FALSE
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/structure/necropolis_gate/attack_hand(mob/user, list/modifiers)
@@ -162,12 +153,9 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate)
GLOB.necropolis_gate = src
/obj/structure/necropolis_gate/legion_gate/Destroy(force)
if(force)
if(GLOB.necropolis_gate == src)
GLOB.necropolis_gate = null
. = ..()
else
return QDEL_HINT_LETMELIVE
if(GLOB.necropolis_gate == src)
GLOB.necropolis_gate = null
return ..()
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/structure/necropolis_gate/legion_gate/attack_hand(mob/user, list/modifiers)
@@ -241,12 +229,6 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate)
/obj/structure/necropolis_arch/singularity_pull()
return 0
/obj/structure/necropolis_arch/Destroy(force)
if(force)
. = ..()
else
return QDEL_HINT_LETMELIVE
#define STABLE 0 //The tile is stable and won't collapse/sink when crossed.
#define COLLAPSE_ON_CROSS 1 //The tile is unstable and will temporary become unusable when crossed.
#define DESTROY_ON_CROSS 2 //The tile is nearly broken and will permanently become unusable when crossed.
@@ -273,12 +255,6 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate)
)
AddElement(/datum/element/connect_loc, loc_connections)
/obj/structure/stone_tile/Destroy(force)
if(force || fallen)
. = ..()
else
return QDEL_HINT_LETMELIVE
/obj/structure/stone_tile/singularity_pull()
return
+23 -16
View File
@@ -380,13 +380,32 @@
icon_state = "blank"
icon = 'icons/effects/effects.dmi'
var/vanish_description = "vanishes from reality"
var/can_destroy = TRUE
// Weakref to the user who we're "acting" on
var/datum/weakref/user_ref
/obj/effect/immortality_talisman/Initialize(mapload, mob/new_user)
. = ..()
if(new_user)
vanish(new_user)
/obj/effect/immortality_talisman/Destroy()
// If we have a mob, we need to free it before cleanup
// This is a safety to prevent nuking a human, not so much a good pattern in general
unvanish()
return ..()
/obj/effect/immortality_talisman/proc/unvanish()
var/mob/user = user_ref?.resolve()
user_ref = null
if(!user)
return
user.status_flags &= ~GODMODE
user.notransform = FALSE
user.forceMove(get_turf(src))
user.visible_message(span_danger("[user] pops back into reality!"))
/obj/effect/immortality_talisman/proc/vanish(mob/user)
user.visible_message(span_danger("[user] [vanish_description], leaving a hole in [user.p_their()] place!"))
@@ -397,17 +416,11 @@
user.notransform = TRUE
user.status_flags |= GODMODE
can_destroy = FALSE
user_ref = WEAKREF(user)
addtimer(CALLBACK(src, .proc/unvanish, user), 10 SECONDS)
addtimer(CALLBACK(src, .proc/dissipate), 10 SECONDS)
/obj/effect/immortality_talisman/proc/unvanish(mob/user)
user.status_flags &= ~GODMODE
user.notransform = FALSE
user.forceMove(get_turf(src))
user.visible_message(span_danger("[user] pops back into reality!"))
can_destroy = TRUE
/obj/effect/immortality_talisman/proc/dissipate()
qdel(src)
/obj/effect/immortality_talisman/attackby()
@@ -416,12 +429,6 @@
/obj/effect/immortality_talisman/singularity_pull()
return
/obj/effect/immortality_talisman/Destroy(force)
if(!can_destroy && !force)
return QDEL_HINT_LETMELIVE
else
. = ..()
/obj/effect/immortality_talisman/void
vanish_description = "is dragged into the void"
@@ -201,7 +201,7 @@
/datum/action/consume/New(Target)
. = ..()
RegisterSignal(owner, COMSIG_LIVING_DEATH, .proc/on_owner_death)
RegisterSignal(owner, COMSIG_PARENT_PREQDELETED, .proc/handle_mob_deletion)
RegisterSignal(owner, COMSIG_PARENT_QDELETING, .proc/handle_mob_deletion)
/datum/action/consume/proc/handle_mob_deletion()
SIGNAL_HANDLER
@@ -233,7 +233,7 @@
/datum/action/consume/proc/start_consuming(mob/living/target)
vored_mob = target
vored_mob.forceMove(owner) ///AAAAAAAAAAAAAAAAAAAAAAHHH!!!
RegisterSignal(vored_mob, COMSIG_PARENT_PREQDELETED, .proc/handle_mob_deletion)
RegisterSignal(vored_mob, COMSIG_PARENT_QDELETING, .proc/handle_mob_deletion)
playsound(owner,'sound/items/eatfood.ogg', rand(30,50), TRUE)
owner.visible_message(span_warning("[src] devours [target]!"), span_notice("You devour [target]."))
START_PROCESSING(SSprocessing, src)
@@ -244,7 +244,7 @@
vored_mob.forceMove(get_turf(owner))
playsound(get_turf(owner), 'sound/effects/splat.ogg', 50, TRUE)
owner.visible_message(span_warning("[owner] pukes out [vored_mob]!"), span_notice("You puke out [vored_mob]."))
UnregisterSignal(vored_mob, COMSIG_PARENT_PREQDELETED)
UnregisterSignal(vored_mob, COMSIG_PARENT_QDELETING)
vored_mob = null
///Gain health for the consumption and dump some clone loss on the target.
+2 -2
View File
@@ -53,13 +53,13 @@
if(ispath(device))
device = new device(src)
ADD_TRAIT(device, TRAIT_NODROP, MOD_TRAIT)
RegisterSignal(device, COMSIG_PARENT_PREQDELETED, .proc/on_device_deletion)
RegisterSignal(device, COMSIG_PARENT_QDELETING, .proc/on_device_deletion)
RegisterSignal(src, COMSIG_ATOM_EXITED, .proc/on_exit)
/obj/item/mod/module/Destroy()
mod?.uninstall(src)
if(device)
UnregisterSignal(device, COMSIG_PARENT_PREQDELETED)
UnregisterSignal(device, COMSIG_PARENT_QDELETING)
QDEL_NULL(device)
return ..()
+2 -2
View File
@@ -279,10 +279,10 @@
. = ..()
RegisterSignal(owner, COMSIG_MOB_STATCHANGE, .proc/on_stat_change)
RegisterSignal(owner, COMSIG_LIVING_POST_FULLY_HEAL, .proc/on_owner_fully_heal)
RegisterSignal(owner, COMSIG_PARENT_PREQDELETED, .proc/owner_deleted)
RegisterSignal(owner, COMSIG_PARENT_QDELETING, .proc/owner_deleted)
/obj/item/organ/heart/ethereal/Remove(mob/living/carbon/owner, special = 0)
UnregisterSignal(owner, list(COMSIG_MOB_STATCHANGE, COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_PARENT_PREQDELETED))
UnregisterSignal(owner, list(COMSIG_MOB_STATCHANGE, COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_PARENT_QDELETING))
REMOVE_TRAIT(owner, TRAIT_CORPSELOCKED, SPECIES_TRAIT)
stop_crystalization_process(owner)
QDEL_NULL(current_crystal)