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"