diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 61c61673d11a..4fac39157231 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -83,6 +83,10 @@
if(new_character.mind) //disassociate any mind currently in our new body's mind variable
new_character.mind.current = null
+ if(istype(current) && islist(current.antag_datums)) //wow apparently current isn't always living good fucking job SOMEONE
+ for(var/i in current.antag_datums)
+ var/datum/antag_datum/D = i
+ D.transfer_to_new_body(new_character)
var/datum/atom_hud/antag/hud_to_transfer = antag_hud//we need this because leave_hud() will clear this list
leave_all_huds() //leave all the huds in the old body, so it won't get huds if somebody else enters it
current = new_character //associate ourself with our new body
diff --git a/code/game/gamemodes/antag_datum.dm b/code/game/gamemodes/antag_datum.dm
new file mode 100644
index 000000000000..716db0fe8b7a
--- /dev/null
+++ b/code/game/gamemodes/antag_datum.dm
@@ -0,0 +1,197 @@
+/mob/living
+ var/list/antag_datums
+
+/mob/living/proc/gain_antag_datum(datum_type)
+ if(!islist(antag_datums))
+ antag_datums = list()
+ var/datum/antag_datum/D = new datum_type()
+ . = D.give_to_body(src)
+
+/mob/living/proc/has_antag_datum(type, check_subtypes)
+ if(!islist(antag_datums))
+ return FALSE
+ for(var/i in antag_datums)
+ var/datum/antag_datum/D = i
+ if(check_subtypes
+ if(istype(D, type))
+ return D
+ else
+ if(D.type == type)
+ return D
+ return FALSE
+
+/datum/antag_datum
+ var/mob/living/owner
+ var/some_flufftext = "yer an antag larry"
+
+/datum/antag_datum/Destroy()
+ owner = null
+ return ..()
+
+/datum/antag_datum/proc/can_be_owned(mob/living/new_body)
+ return new_body && !new_body.has_antag_datum(type, TRUE)
+
+/datum/antag_datum/proc/give_to_body(mob/living/new_body) //tries to give an antag datum to a mob. cancels out if it can't be owned by the new body
+ if(new_body && can_be_owned(new_body))
+ new_body.antag_datums += src
+ owner = new_body
+ on_gain()
+ . = src //return the datum if successful
+ else
+ qdel(src)
+ . = FALSE
+
+/datum/antag_datum/proc/on_gain() //on initial gain of antag datum, do this. should only be called once per datum
+ apply_innate_effects()
+ if(some_flufftext)
+ owner << some_flufftext
+
+/datum/antag_datum/proc/apply_innate_effects() //applies innate effects to the owner, may be called multiple times due to mind transferral
+ //antag huds would go here if antag huds were less completely unworkable as-is
+
+/datum/antag_datum/proc/remove_innate_effects() //removes innate effects from the owner, may be called multiple times due to mind transferral
+ //also antag huds but see above antag huds a shit
+
+/datum/antag_datum/proc/on_remove() //totally removes the antag datum from the owner; can only be called once per owner
+ remove_innate_effects()
+ owner.antag_datums -= src
+ qdel(src)
+
+/datum/antag_datum/proc/transfer_to_new_body(mob/living/new_body)
+ remove_innate_effects()
+ if(!islist(new_body.antag_datums))
+ new_body.antag_datums = list()
+ new_body.antag_datums += src
+ owner.antag_datums -= src
+ owner = new_body
+ apply_innate_effects()
+
+//CLOCKCULT PROOF OF CONCEPT
+
+/datum/antag_datum/clockcultist
+ var/silent_update = FALSE
+ some_flufftext = null
+
+/datum/antag_datum/clockcultist/silent
+ silent_update = TRUE
+
+/datum/antag_datum/clockcultist/can_be_owned(mob/living/new_body)
+ . = ..()
+ if(.)
+ . = is_eligible_servant(new_body)
+
+/datum/antag_datum/clockcultist/give_to_body(mob/living/new_body)
+ if(!silent_update)
+ if(iscarbon(new_body))
+ new_body << "Your mind is racing! Your body feels incredibly light! Your world glows a brilliant yellow! All at once it comes to you. Ratvar, the Clockwork \
+ Justiciar, lies in exile, derelict and forgotten in an unseen realm."
+ else if(issilicon(new_body))
+ new_body << "You are unable to compute this truth. Your vision glows a brilliant yellow, and all at once it comes to you. Ratvar, the Clockwork Justiciar, lies in \
+ exile, derelict and forgotten in an unseen realm."
+ else
+ new_body << "Your world glows a brilliant yellow! All at once it comes to you. Ratvar, the Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm."
+ . = ..()
+ if(!silent_update && new_body)
+ if(.)
+ new_body.visible_message("[new_body]'s eyes glow a blazing yellow!", \
+ "Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork Justiciar above all else. Perform his every \
+ whim without hesitation.")
+ else
+ new_body.visible_message("[new_body] seems to resist an unseen force!")
+ new_body << "And yet, you somehow push it all away."
+
+/datum/antag_datum/clockcultist/on_gain()
+ if(ticker && ticker.mode && owner.mind)
+ ticker.mode.servants_of_ratvar += owner.mind
+ ticker.mode.update_servant_icons_added(owner.mind)
+ if(owner.mind)
+ owner.mind.special_role = "Servant of Ratvar"
+ owner.attack_log += "\[[time_stamp()]\] Has been converted to the cult of Ratvar!"
+ if(issilicon(owner))
+ var/mob/living/silicon/S = owner
+ if(isrobot(S) && !silent_update)
+ S << "You have been desynced from your master AI. In addition, your onboard camera is no longer active and your safeties have been disabled."
+ S << "You can communicate with other servants by using the Hierophant Network action button in the upper left."
+ else if(isbrain(owner) || isclockmob(owner))
+ owner << "You can communicate with other servants by using the Hierophant Network action button in the upper left."
+ ..()
+
+/datum/antag_datum/clockcultist/apply_innate_effects()
+ all_clockwork_mobs += owner
+ owner.faction |= "ratvar"
+ owner.languages_spoken |= RATVAR
+ owner.languages_understood |= RATVAR
+ owner.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
+ if(issilicon(owner))
+ var/mob/living/silicon/S = owner
+ if(isrobot(S))
+ var/mob/living/silicon/robot/R = S
+ R.UnlinkSelf()
+ R.emagged = 1
+ else if(isAI(S))
+ var/mob/living/silicon/ai/A = S
+ for(var/C in A.connected_robots)
+ var/mob/living/silicon/robot/R = C
+ if(R.connected_ai == A)
+ R.visible_message("[R]'s eyes glow a blazing yellow!", \
+ "Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork Justiciar above all else. Perform his every \
+ whim without hesitation.")
+ R << "Your onboard camera is no longer active and your safeties have been disabled."
+ add_servant_of_ratvar(R, TRUE)
+ S.laws = new/datum/ai_laws/ratvar
+ S.laws.associate(S)
+ S.update_icons()
+ S.show_laws()
+ var/datum/action/innate/hierophant/H = new()
+ H.Grant(S)
+ H.title = "Silicon"
+ H.span_for_name = "nezbere"
+ else if(isbrain(owner))
+ var/datum/action/innate/hierophant/H = new()
+ H.Grant(owner)
+ H.title = "Vessel"
+ H.span_for_name = "nezbere"
+ H.span_for_message = "alloy"
+ else if(isclockmob(owner))
+ var/datum/action/innate/hierophant/H = new()
+ H.Grant(owner)
+ H.title = "Construct"
+ H.span_for_name = "nezbere"
+ owner.throw_alert("clockinfo", /obj/screen/alert/clockwork/infodump)
+ cache_check(owner)
+
+/datum/antag_datum/clockcultist/remove_innate_effects()
+ all_clockwork_mobs -= owner
+ owner.faction -= "ratvar"
+ owner.languages_spoken &= ~RATVAR
+ owner.languages_understood &= ~RATVAR
+ owner.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons
+ owner.clear_alert("clockinfo")
+ owner.clear_alert("nocache")
+ for(var/datum/action/innate/function_call/F in owner.actions) //Removes any bound Ratvarian spears
+ qdel(F)
+ for(var/datum/action/innate/hierophant/H in owner.actions) //Removes any communication actions
+ qdel(H)
+ if(issilicon(owner))
+ var/mob/living/silicon/S = owner
+ if(isrobot(S))
+ var/mob/living/silicon/robot/R = S
+ R.emagged = initial(R.emagged)
+ S.make_laws()
+ S.update_icons()
+ S.show_laws()
+
+/datum/antag_datum/clockcultist/on_remove()
+ if(!silent_update)
+ owner.visible_message("[owner] seems to have remembered their true allegiance!", \
+ "A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.")
+ if(ticker && ticker.mode && owner.mind)
+ ticker.mode.servants_of_ratvar -= owner.mind
+ ticker.mode.update_servant_icons_removed(owner.mind)
+ if(owner.mind)
+ owner.mind.memory = "" //Not sure if there's a better way to do this
+ owner.mind.special_role = null
+ owner.attack_log += "\[[time_stamp()]\] Has renounced the cult of Ratvar!"
+ if(isrobot(owner))
+ owner << "Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking."
+ ..()
diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm
index 81e00e6b877c..404c3851edc3 100644
--- a/code/game/gamemodes/clock_cult/clock_cult.dm
+++ b/code/game/gamemodes/clock_cult/clock_cult.dm
@@ -43,148 +43,41 @@ Credit where due:
///////////
/proc/is_servant_of_ratvar(mob/living/M)
- return M && istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.servants_of_ratvar)
+ return M && istype(M) && M.has_antag_datum(/datum/antag_datum/clockcultist, TRUE)
/proc/is_eligible_servant(mob/living/M)
if(!istype(M))
return 0
- if(!M.mind)
- return 0
- if(M.mind.enslaved_to && !is_servant_of_ratvar(M.mind.enslaved_to))
- return 0
+ if(M.mind)
+ if(M.mind.enslaved_to && !is_servant_of_ratvar(M.mind.enslaved_to))
+ return 0
+ if(ishuman(M))
+ if(M.mind.assigned_role in list("Captain", "Chaplain"))
+ return 0
if(iscultist(M) || isconstruct(M))
return 0
- if(isbrain(M))
- return 1
if(ishuman(M))
- if(isloyal(M) || (M.mind.assigned_role in list("Captain", "Chaplain")))
+ if(isloyal(M))
return 0
return 1
- if(isguardian(M))
- var/mob/living/simple_animal/hostile/guardian/G = M
- if(is_servant_of_ratvar(G.summoner))
- return 1 //can't convert it unless the owner is converted
- if(issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
+ if(isbrain(M) || isguardian(M) || issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
return 1
return 0
-/proc/add_servant_of_ratvar(mob/M, silent = FALSE)
- if(is_servant_of_ratvar(M) || !ticker || !ticker.mode)
- return 0
- if(iscarbon(M))
- if(!silent)
- M << "Your mind is racing! Your body feels incredibly light! Your world glows a brilliant yellow! All at once it comes to you. Ratvar, the Clockwork \
- Justiciar, lies in exile, derelict and forgotten in an unseen realm."
- else if(issilicon(M))
- if(!silent)
- M << "You are unable to compute this truth. Your vision glows a brilliant yellow, and all at once it comes to you. Ratvar, the Clockwork Justiciar, lies in \
- exile, derelict and forgotten in an unseen realm."
- if(!is_eligible_servant(M))
- if(!M.stat)
- M.visible_message("[M] whirs as it resists an outside influence!")
- M << "Corrupt data purged. Resetting cortex chip to factory defaults... complete." //silicons have a custom fail message
- return 0
- else if(!silent)
- M << "Your world glows a brilliant yellow! All at once it comes to you. Ratvar, the Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm."
+/proc/add_servant_of_ratvar(mob/living/L, silent = FALSE)
+ var/update_type = /datum/antag_datum/clockcultist
+ if(silent)
+ update_type = /datum/antag_datum/clockcultist/silent
+ . = L.gain_antag_datum(update_type)
- if(!is_eligible_servant(M))
- if(!silent && !M.stat)
- M.visible_message("[M] seems to resist an unseen force!")
- M << "And yet, you somehow push it all away."
- return 0
-
- if(!silent)
- M.visible_message("[M]'s eyes glow a blazing yellow!", \
- "Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork Justiciar above all else. Perform his every \
- whim without hesitation.")
- ticker.mode.servants_of_ratvar += M.mind
- ticker.mode.update_servant_icons_added(M.mind)
- all_clockwork_mobs += M
- M.faction |= "ratvar"
- M.mind.special_role = "Servant of Ratvar"
- M.languages_spoken |= RATVAR
- M.languages_understood |= RATVAR
- M.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
- M.attack_log += "\[[time_stamp()]\] Has been converted to the cult of Ratvar!"
- if(issilicon(M))
- var/mob/living/silicon/S = M
- if(isrobot(S))
- var/mob/living/silicon/robot/R = S
- R.UnlinkSelf()
- R.emagged = 1
- if(!silent)
- R << "You have been desynced from your master AI. In addition, your onboard camera is no longer active and your safeties have been disabled."
- else if(isAI(S))
- var/mob/living/silicon/ai/A = S
- for(var/C in A.connected_robots)
- var/mob/living/silicon/robot/R = C
- if(R.connected_ai == A)
- R.visible_message("[R]'s eyes glow a blazing yellow!", \
- "Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork Justiciar above all else. Perform his every \
- whim without hesitation.")
- R << "Your onboard camera is no longer active and your safeties have been disabled."
- add_servant_of_ratvar(R, TRUE)
- S.laws = new/datum/ai_laws/ratvar
- S.laws.associate(S)
- S.update_icons()
- S.show_laws()
- var/datum/action/innate/hierophant/H = new()
- H.Grant(S)
- H.title = "Silicon"
- H.span_for_name = "nezbere"
- S << "You can communicate with other servants by using the Hierophant Network action button in the upper left."
- else if(isbrain(M))
- var/datum/action/innate/hierophant/H = new()
- H.Grant(M)
- H.title = "Vessel"
- H.span_for_name = "nezbere"
- H.span_for_message = "alloy"
- M << "You can communicate with other servants by using the Hierophant Network action button in the upper left."
- else if(isclockmob(M))
- var/datum/action/innate/hierophant/H = new()
- H.Grant(M)
- H.title = "Construct"
- H.span_for_name = "nezbere"
- M << "You can communicate with other servants by using the Hierophant Network action button in the upper left."
- if(istype(ticker.mode, /datum/game_mode/clockwork_cult))
- var/datum/game_mode/clockwork_cult/C = ticker.mode
- C.present_tasks(M) //Memorize the objectives
- M.throw_alert("clockinfo", /obj/screen/alert/clockwork/infodump)
- cache_check(M)
- return 1
-
-/proc/remove_servant_of_ratvar(mob/living/M, silent = FALSE)
- if(!is_servant_of_ratvar(M)) //In this way, is_servant_of_ratvar() checks the existence of ticker and minds
- return 0
- if(!silent)
- M.visible_message("[M] seems to have remembered their true allegiance!", \
- "A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.")
- ticker.mode.servants_of_ratvar -= M.mind
- ticker.mode.update_servant_icons_removed(M.mind)
- all_clockwork_mobs -= M
- M.faction -= "ratvar"
- M.mind.memory = "" //Not sure if there's a better way to do this
- M.mind.special_role = null
- M.languages_spoken &= ~RATVAR
- M.languages_understood &= ~RATVAR
- M.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons
- M.attack_log += "\[[time_stamp()]\] Has renounced the cult of Ratvar!"
- M.clear_alert("clockinfo")
- M.clear_alert("nocache")
- for(var/datum/action/innate/function_call/F in M.actions) //Removes any bound Ratvarian spears
- qdel(F)
- for(var/datum/action/innate/hierophant/H in M.actions) //Removes any communication actions
- qdel(H)
- if(issilicon(M))
- var/mob/living/silicon/S = M
- if(isrobot(S))
- var/mob/living/silicon/robot/R = S
- R.emagged = initial(R.emagged)
- R << "Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking."
- S.make_laws()
- S.update_icons()
- S.show_laws()
- return 1
+/proc/remove_servant_of_ratvar(mob/living/L, silent = FALSE)
+ var/datum/antag_datum/clockcultist/clock_datum = L.has_antag_datum(/datum/antag_datum/clockcultist, TRUE)
+ if(!clock_datum)
+ world << "wait shit what"
+ return FALSE
+ clock_datum.silent_update = silent
+ clock_datum.on_remove()
+ return TRUE
///////////////
// GAME MODE //
diff --git a/code/game/gamemodes/clock_cult/clock_structures.dm b/code/game/gamemodes/clock_cult/clock_structures.dm
index a543a5d2d3b0..d92048a99428 100644
--- a/code/game/gamemodes/clock_cult/clock_structures.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures.dm
@@ -293,9 +293,7 @@
user.visible_message("[user] places [S] in [src], where it fuses to the shell.", "You place [S] in [src], fusing it to the shell.")
var/mob/living/simple_animal/A = new mobtype(get_turf(src))
A.visible_message("[src][spawn_message]")
- remove_servant_of_ratvar(S.brainmob, TRUE)
S.brainmob.mind.transfer_to(A)
- add_servant_of_ratvar(A, TRUE)
user.drop_item()
qdel(S)
qdel(src)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index eb15b771a5b6..a1cf737631b1 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -540,7 +540,6 @@
ticker.mode.remove_revolutionary(newborgie, 0)
ticker.mode.remove_gangster(newborgie, 0, remove_bosses=1)
ticker.mode.remove_hog_follower(newborgie, 0)
- remove_servant_of_ratvar(newborgie.current, TRUE)
/datum/game_mode/proc/generate_station_goals()
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 21aab1670c9e..f89954ad43a5 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -213,11 +213,10 @@
O.make_laws()
ticker.mode.remove_antag_for_borging(BM.mind)
+ if(!M.clockwork)
+ remove_servant_of_ratvar(BM, TRUE)
BM.mind.transfer_to(O)
- if(M.clockwork)
- add_servant_of_ratvar(O)
-
if(O.mind && O.mind.special_role)
O.mind.store_memory("As a cyborg, you must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.")
O << "You have been robotized!"
diff --git a/tgstation.dme b/tgstation.dme
index 45351474e52b..4d25b40e48ff 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -283,6 +283,7 @@
#include "code\game\area\ai_monitored.dm"
#include "code\game\area\areas.dm"
#include "code\game\area\Space_Station_13_areas.dm"
+#include "code\game\gamemodes\antag_datum.dm"
#include "code\game\gamemodes\antag_hud.dm"
#include "code\game\gamemodes\antag_spawner.dm"
#include "code\game\gamemodes\events.dm"