diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm
index 0b4adc0f2cd..88dcc4cd074 100644
--- a/code/modules/antagonists/heretic/heretic_antag.dm
+++ b/code/modules/antagonists/heretic/heretic_antag.dm
@@ -42,7 +42,7 @@
/// A list of TOTAL how many high value sacrifices completed.
var/high_value_sacrifices = 0
/// Lazy assoc list of [weakrefs to humans] to [image previews of the human]. Humans that we have as sacrifice targets.
- var/list/datum/weakref/sac_targets
+ var/list/mob/living/carbon/human/sac_targets
/// Whether we're drawing a rune or not
var/drawing_rune = FALSE
/// A static typecache of all tools we can scribe with.
@@ -50,6 +50,10 @@
/// A blacklist of turfs we cannot scribe on.
var/static/list/blacklisted_rune_turfs = typecacheof(list(/turf/open/space, /turf/open/openspace, /turf/open/lava, /turf/open/chasm))
+/datum/antagonist/heretic/Destroy()
+ LAZYNULL(sac_targets)
+ return ..()
+
/datum/antagonist/heretic/ui_data(mob/user)
var/list/data = list()
@@ -356,7 +360,29 @@
var/image/target_image = image(icon = target.icon, icon_state = target.icon_state)
target_image.overlays = target.overlays
- LAZYSET(sac_targets, WEAKREF(target), target_image)
+ LAZYSET(sac_targets, target, target_image)
+ RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/on_target_deleted)
+
+/**
+ * Removes [target] from the heretic's sacrifice list.
+ * Returns FALSE if no one was removed, TRUE otherwise
+ */
+/datum/antagonist/heretic/proc/remove_sacrifice_target(mob/living/carbon/human/target)
+ if(!(target in sac_targets))
+ return FALSE
+
+ LAZYREMOVE(sac_targets, target)
+ UnregisterSignal(target, COMSIG_PARENT_QDELETING)
+ return TRUE
+
+/**
+ * Signal proc for [COMSIG_PARENT_QDELETING] registered on sac targets
+ * if sacrifice targets are deleted (gibbed, dusted, whatever), free their slot and reference
+ */
+/datum/antagonist/heretic/proc/on_target_deleted(mob/living/carbon/human/source)
+ SIGNAL_HANDLER
+
+ remove_sacrifice_target(source)
/**
* Increments knowledge by one.
@@ -462,10 +488,8 @@
return
var/list/removable = list()
- for(var/datum/weakref/ref as anything in sac_targets)
- var/mob/living/carbon/human/old_target = ref.resolve()
- if(!QDELETED(old_target))
- removable[old_target.name] = old_target
+ for(var/mob/living/carbon/human/old_target as anything in sac_targets)
+ removable[old_target.name] = old_target
var/name_of_removed = tgui_input_list(admin, "Choose a human to remove", "Who to Spare", removable)
if(QDELETED(src) || !admin.client?.holder || isnull(name_of_removed))
@@ -473,10 +497,10 @@
var/mob/living/carbon/human/chosen_target = removable[name_of_removed]
if(QDELETED(chosen_target) || !ishuman(chosen_target))
return
- if(!(WEAKREF(chosen_target) in sac_targets))
- return
- LAZYREMOVE(sac_targets, WEAKREF(chosen_target))
+ if(!remove_sacrifice_target(chosen_target))
+ to_chat(admin, span_warning("Failed to remove [name_of_removed] from [owner]'s sacrifice list. Perhaps they're no longer in the list anyways."))
+ return
if(tgui_alert(admin, "Let them know their targets have been updated?", "Whispers of the Mansus", list("Yes", "No")) == "Yes")
to_chat(owner.current, span_danger("The Mansus has modified your targets."))
@@ -513,11 +537,9 @@
. += "
"
. += "Current Targets:
"
if(LAZYLEN(sac_targets))
- for(var/datum/weakref/ref as anything in sac_targets)
- var/mob/living/carbon/human/actual_target = ref.resolve()
- if(QDELETED(actual_target))
- continue
- . += " - [actual_target.real_name], the [actual_target.mind?.assigned_role?.title || "human"].
"
+ for(var/mob/living/carbon/human/target as anything in sac_targets)
+ . += " - [target.real_name], the [target.mind?.assigned_role?.title || "human"].
"
+
else
. += "None!
"
. += "
"
diff --git a/code/modules/antagonists/heretic/heretic_living_heart.dm b/code/modules/antagonists/heretic/heretic_living_heart.dm
index 0019e276506..a619e242376 100644
--- a/code/modules/antagonists/heretic/heretic_living_heart.dm
+++ b/code/modules/antagonists/heretic/heretic_living_heart.dm
@@ -118,13 +118,9 @@
var/list/targets_to_choose = list()
var/list/mob/living/carbon/human/human_targets = list()
- for(var/datum/weakref/target_ref as anything in heretic_datum.sac_targets)
- var/mob/living/carbon/human/real_target = target_ref.resolve()
- if(QDELETED(real_target))
- continue
-
- human_targets[real_target.real_name] = real_target
- targets_to_choose[real_target.real_name] = heretic_datum.sac_targets[target_ref]
+ for(var/mob/living/carbon/human/sac_target as anything in heretic_datum.sac_targets)
+ human_targets[sac_target.real_name] = sac_target
+ targets_to_choose[sac_target.real_name] = heretic_datum.sac_targets[sac_target]
// If we don't have a last tracked name, open a radial to set one.
// If we DO have a last tracked name, we skip the radial if they right click the action.
diff --git a/code/modules/antagonists/heretic/knowledge/general_side.dm b/code/modules/antagonists/heretic/knowledge/general_side.dm
index e56af034337..fafaa3f77ba 100644
--- a/code/modules/antagonists/heretic/knowledge/general_side.dm
+++ b/code/modules/antagonists/heretic/knowledge/general_side.dm
@@ -27,7 +27,8 @@
/datum/heretic_knowledge/reroll_targets/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user)
- LAZYCLEARLIST(heretic_datum.sac_targets)
+ for(var/mob/living/carbon/human/target as anything in heretic_datum.sac_targets)
+ heretic_datum.remove_sacrifice_target(target)
var/datum/heretic_knowledge/hunt_and_sacrifice/target_finder = heretic_datum.get_knowledge(/datum/heretic_knowledge/hunt_and_sacrifice)
if(!target_finder)
diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
index 53db0c5a14f..7c04393f18f 100644
--- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
+++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
@@ -65,7 +65,7 @@
// Let's remove any humans in our atoms list that aren't a sac target
for(var/mob/living/carbon/human/sacrifice in atoms)
// If the mob's not in soft crit or worse, or isn't one of the sacrifices, remove it from the list
- if(sacrifice.stat < SOFT_CRIT || !(WEAKREF(sacrifice) in heretic_datum.sac_targets))
+ if(sacrifice.stat < SOFT_CRIT || !(sacrifice in heretic_datum.sac_targets))
atoms -= sacrifice
// Finally, return TRUE if we have a target in the list
@@ -179,12 +179,12 @@
var/mob/living/carbon/human/sacrifice = locate() in selected_atoms
if(!sacrifice)
CRASH("[type] sacrifice_process didn't have a human in the atoms list. How'd it make it so far?")
- if(!(WEAKREF(sacrifice) in heretic_datum.sac_targets))
+ if(!(sacrifice in heretic_datum.sac_targets))
CRASH("[type] sacrifice_process managed to get a non-target human. This is incorrect.")
if(sacrifice.mind)
LAZYADD(target_blacklist, sacrifice.mind)
- LAZYREMOVE(heretic_datum.sac_targets, WEAKREF(sacrifice))
+ heretic_datum.remove_sacrifice_target(sacrifice)
to_chat(user, span_hypnophrase("Your patrons accepts your offer."))