diff --git a/code/__DEFINES/dcs/signals/signals_antagonist.dm b/code/__DEFINES/dcs/signals/signals_mind.dm similarity index 72% rename from code/__DEFINES/dcs/signals/signals_antagonist.dm rename to code/__DEFINES/dcs/signals/signals_mind.dm index a209456f7dd..72f43f518eb 100644 --- a/code/__DEFINES/dcs/signals/signals_antagonist.dm +++ b/code/__DEFINES/dcs/signals/signals_mind.dm @@ -1,4 +1,6 @@ -// Antagonist signals +///from mind/transfer_to. Sent after the mind has been transferred: (mob/previous_body) +#define COMSIG_MIND_TRANSFERRED "mind_transferred" + /// Called on the mind when an antagonist is being gained, after the antagonist list has updated (datum/antagonist/antagonist) #define COMSIG_ANTAGONIST_GAINED "antagonist_gained" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index 63f0a82920d..15eb628df71 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -32,6 +32,9 @@ /// From base of /client/Move() #define COMSIG_MOB_CLIENT_MOVED "mob_client_moved" +///from mind/transfer_to. Sent to the receiving mob. +#define COMSIG_MOB_MIND_TRANSFERRED_INTO "mob_mind_transferred_into" + ///from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj #define COMSIG_MOB_ALLOWED "mob_allowed" ///from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index db3c211ad2a..2b260db4730 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -185,6 +185,8 @@ LAZYCLEARLIST(new_character.client.recent_examines) new_character.client.init_verbs() // re-initialize character specific verbs current.update_atom_languages() + SEND_SIGNAL(src, COMSIG_MIND_TRANSFERRED, old_current) + SEND_SIGNAL(current, COMSIG_MOB_MIND_TRANSFERRED_INTO) //I cannot trust you fucks to do this properly /datum/mind/proc/set_original_character(new_original_character) diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index 724e028512b..e2d2fe71611 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -326,7 +326,31 @@ reshape.Crop(-5,-3,26,30) sac_objective.sac_image = reshape +/datum/team/cult/proc/setup_objectives() + var/datum/objective/sacrifice/sacrifice_objective = new + sacrifice_objective.team = src + sacrifice_objective.find_target() + objectives += sacrifice_objective + + var/datum/objective/eldergod/summon_objective = new + summon_objective.team = src + objectives += summon_objective + +/datum/objective/sacrifice + var/sacced = FALSE + var/sac_image + +/// Unregister signals from the old target so it doesn't cause issues when sacrificed of when a new target is found. +/datum/objective/sacrifice/proc/clear_sacrifice() + if(!target) + return + UnregisterSignal(target, COMSIG_MIND_TRANSFERRED) + if(target.current) + UnregisterSignal(target.current, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_MIND_TRANSFERRED_INTO)) + target = null + /datum/objective/sacrifice/find_target(dupe_search_range) + clear_sacrifice() if(!istype(team, /datum/team/cult)) return var/datum/team/cult/cult = team @@ -343,27 +367,47 @@ if(LAZYLEN(target_candidates)) target = pick(target_candidates) update_explanation_text() + // Register a bunch of signals to both the target mind and its body + // to stop cult from softlocking everytime the target is deleted before being actually sacrificed. + RegisterSignal(target, COMSIG_MIND_TRANSFERRED, .proc/on_mind_transfer) + RegisterSignal(target.current, COMSIG_PARENT_QDELETING, .proc/on_target_body_del) + RegisterSignal(target.current, COMSIG_MOB_MIND_TRANSFERRED_INTO, .proc/on_possible_mindswap) else message_admins("Cult Sacrifice: Could not find unconvertible or convertible target. WELP!") - cult.make_image(src) + sacced = TRUE // Prevents another hypothetical softlock. This basically means every PC is a cultist. + if(!sacced) + cult.make_image(src) for(var/datum/mind/mind in cult.members) if(mind.current) mind.current.clear_alert("bloodsense") mind.current.throw_alert("bloodsense", /atom/movable/screen/alert/bloodsense) -/datum/team/cult/proc/setup_objectives() - var/datum/objective/sacrifice/sacrifice_objective = new - sacrifice_objective.team = src - sacrifice_objective.find_target() - objectives += sacrifice_objective +/datum/objective/sacrifice/proc/on_target_body_del() + SIGNAL_HANDLER + INVOKE_ASYNC(src, .proc/find_target) - var/datum/objective/eldergod/summon_objective = new - summon_objective.team = src - objectives += summon_objective +/datum/objective/sacrifice/proc/on_mind_transfer(datum/source, mob/previous_body) + SIGNAL_HANDLER + //If, for some reason, the mind was transferred to a ghost (better safe than sorry), find a new target. + if(!isliving(target.current)) + INVOKE_ASYNC(src, .proc/find_target) + return + UnregisterSignal(previous_body, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_MIND_TRANSFERRED_INTO)) + RegisterSignal(target.current, COMSIG_PARENT_QDELETING, .proc/on_target_body_del) + RegisterSignal(target.current, COMSIG_MOB_MIND_TRANSFERRED_INTO, .proc/on_possible_mindswap) -/datum/objective/sacrifice - var/sacced = FALSE - var/sac_image +/datum/objective/sacrifice/proc/on_possible_mindswap(mob/source) + SIGNAL_HANDLER + UnregisterSignal(target.current, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_MIND_TRANSFERRED_INTO)) + //we check if the mind is bodyless only after mindswap shenanigeans to avoid issues. + addtimer(CALLBACK(src, .proc/do_we_have_a_body), 0 SECONDS) + +/datum/objective/sacrifice/proc/do_we_have_a_body() + if(!target.current) //The player was ghosted and the mind isn't probably going to be transferred to another mob at this point. + find_target() + return + RegisterSignal(target.current, COMSIG_PARENT_QDELETING, .proc/on_target_body_del) + RegisterSignal(target.current, COMSIG_MOB_MIND_TRANSFERRED_INTO, .proc/on_possible_mindswap) /datum/objective/sacrifice/check_completion() return sacced || completed diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 56b6875b659..fad4ae745db 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -317,6 +317,7 @@ structure_check() searches for nearby cultist structures required for the invoca for(var/datum/objective/sacrifice/sac_objective in C.cult_team.objectives) if(sac_objective.target == sacrificial.mind) sac_objective.sacced = TRUE + sac_objective.clear_sacrifice() sac_objective.update_explanation_text() big_sac = TRUE else diff --git a/tgstation.dme b/tgstation.dme index 21df997d337..a672e813011 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -175,7 +175,6 @@ #include "code\__DEFINES\dcs\signals\signals_action.dm" #include "code\__DEFINES\dcs\signals\signals_admin.dm" #include "code\__DEFINES\dcs\signals\signals_adventure.dm" -#include "code\__DEFINES\dcs\signals\signals_antagonist.dm" #include "code\__DEFINES\dcs\signals\signals_area.dm" #include "code\__DEFINES\dcs\signals\signals_bot.dm" #include "code\__DEFINES\dcs\signals\signals_circuit.dm" @@ -191,6 +190,7 @@ #include "code\__DEFINES\dcs\signals\signals_hydroponic.dm" #include "code\__DEFINES\dcs\signals\signals_janitor.dm" #include "code\__DEFINES\dcs\signals\signals_light_eater.dm" +#include "code\__DEFINES\dcs\signals\signals_mind.dm" #include "code\__DEFINES\dcs\signals\signals_mood.dm" #include "code\__DEFINES\dcs\signals\signals_movetype.dm" #include "code\__DEFINES\dcs\signals\signals_music.dm"