From af03de1da8aebb2a8e193d074124ad74c6e825f9 Mon Sep 17 00:00:00 2001
From: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Date: Sun, 20 Mar 2022 04:36:47 -0500
Subject: [PATCH] Gibbed / dusted / otherwise deleted heretic sacrifice targets
will clear themselves from heretic target lists (#65566)
Swaps the weakref list of targets heretics use to a list of hard references, due to handling them on deletion
Uses a proc for removing sacrifice targets
Sacrifice targets which are deleted for some reason in game will automatically remove themselves from the heretic's sacrifice list, allowing them to reroll easier
Apparently, having one of your targets gibbed as a heretic is pretty unfortunate.
As I was holding weakrefs to targets, they persisted despite deletion (which I did not expect to be a problem)
So, now, when a body is completely gone (and you can no longer sacrifice them), the slot is freed for you.
---
.../antagonists/heretic/heretic_antag.dm | 50 +++++++++++++------
.../heretic/heretic_living_heart.dm | 10 ++--
.../heretic/knowledge/general_side.dm | 3 +-
.../sacrifice_knowledge.dm | 6 +--
4 files changed, 44 insertions(+), 25 deletions(-)
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."))