diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index d30a2d098f..433f44e095 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -1,3 +1,4 @@
-#define ANTAG_DATUM_CULT /datum/antagonist/cult
-#define ANTAG_DATUM_CLOCKCULT /datum/antagonist/clockcult
-#define ANTAG_DATUM_CLOCKCULT_SILENT /datum/antagonist/clockcult/silent
\ No newline at end of file
+#define ANTAG_DATUM_CULT /datum/antagonist/cult
+#define ANTAG_DATUM_CULT_MASTER /datum/antagonist/cult/master
+#define ANTAG_DATUM_CLOCKCULT /datum/antagonist/clockcult
+#define ANTAG_DATUM_CLOCKCULT_SILENT /datum/antagonist/clockcult/silent
\ No newline at end of file
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index ec78eb49b2..db405d2878 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -415,68 +415,83 @@
return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y)
-/proc/showCandidatePollWindow(mob/dead/observer/G, poll_time, Question, list/candidates, ignore_category, time_passed, flashwindow = TRUE)
+/proc/showCandidatePollWindow(mob/M, poll_time, Question, list/candidates, ignore_category, time_passed, flashwindow = TRUE)
set waitfor = 0
- G << 'sound/misc/notice2.ogg' //Alerting them to their consideration
+ M << 'sound/misc/notice2.ogg' //Alerting them to their consideration
if(flashwindow)
- window_flash(G.client)
- switch(ignore_category ? askuser(G,Question,"Please answer in [poll_time/10] seconds!","Yes","No","Never for this round", StealFocus=0, Timeout=poll_time) : askuser(G,Question,"Please answer in [poll_time/10] seconds!","Yes","No", StealFocus=0, Timeout=poll_time))
+ window_flash(M.client)
+ switch(ignore_category ? askuser(M,Question,"Please answer in [poll_time/10] seconds!","Yes","No","Never for this round", StealFocus=0, Timeout=poll_time) : askuser(M,Question,"Please answer in [poll_time/10] seconds!","Yes","No", StealFocus=0, Timeout=poll_time))
if(1)
- to_chat(G, "Choice registered: Yes.")
+ to_chat(M, "Choice registered: Yes.")
if((world.time-time_passed)>poll_time)
- to_chat(G, "Sorry, you were too late for the consideration!")
- G << 'sound/machines/buzz-sigh.ogg'
+ to_chat(M, "Sorry, you answered too late to be considered!")
+ M << 'sound/machines/buzz-sigh.ogg'
+ candidates -= M
else
- candidates += G
+ candidates += M
if(2)
- to_chat(G, "Choice registered: No.")
+ to_chat(M, "Choice registered: No.")
+ candidates -= M
if(3)
var/list/L = GLOB.poll_ignore[ignore_category]
if(!L)
GLOB.poll_ignore[ignore_category] = list()
- GLOB.poll_ignore[ignore_category] += G.ckey
- to_chat(G, "Choice registered: Never for this round.")
+ GLOB.poll_ignore[ignore_category] += M.ckey
+ to_chat(M, "Choice registered: Never for this round.")
+ candidates -= M
+ else
+ candidates -= M
-/proc/pollCandidates(var/Question, var/jobbanType, var/datum/game_mode/gametypeCheck, var/be_special_flag = 0, var/poll_time = 300, var/ignore_category = null, flashwindow = TRUE)
- var/list/mob/dead/observer/candidates = list()
+/proc/pollGhostCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE)
+ var/list/candidates = list()
+
+ for(var/mob/dead/observer/G in GLOB.player_list)
+ candidates += G
+
+ pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category, flashwindow, candidates)
+
+ return candidates
+
+/proc/pollCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE, list/group = null)
var/time_passed = world.time
if (!Question)
Question = "Would you like to be a special role?"
- for(var/mob/dead/observer/G in GLOB.player_list)
- if(!G.key || !G.client || (ignore_category && GLOB.poll_ignore[ignore_category] && G.ckey in GLOB.poll_ignore[ignore_category]))
+ for(var/m in group)
+ var/mob/M = m
+ if(!M.key || !M.client || (ignore_category && GLOB.poll_ignore[ignore_category] && M.ckey in GLOB.poll_ignore[ignore_category]))
continue
if(be_special_flag)
- if(!(G.client.prefs) || !(be_special_flag in G.client.prefs.be_special))
+ if(!(M.client.prefs) || !(be_special_flag in M.client.prefs.be_special))
continue
- if (gametypeCheck)
- if(!gametypeCheck.age_check(G.client))
+ if(gametypeCheck)
+ if(!gametypeCheck.age_check(M.client))
continue
- if (jobbanType)
- if(jobban_isbanned(G, jobbanType) || jobban_isbanned(G, "Syndicate"))
+ if(jobbanType)
+ if(jobban_isbanned(M, jobbanType) || jobban_isbanned(M, "Syndicate"))
continue
- showCandidatePollWindow(G, poll_time, Question, candidates, ignore_category, time_passed, flashwindow)
+ showCandidatePollWindow(M, poll_time, Question, group, ignore_category, time_passed, flashwindow)
sleep(poll_time)
- //Check all our candidates, to make sure they didn't log off during the wait period.
- for(var/mob/dead/observer/G in candidates)
- if(!G.key || !G.client)
- candidates.Remove(G)
+ //Check all our candidates, to make sure they didn't log off or get deleted during the wait period.
+ for(var/mob/M in group)
+ if(!M.key || !M.client)
+ group -= M
- listclearnulls(candidates)
+ listclearnulls(group)
- return candidates
+ return group
/proc/pollCandidatesForMob(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, mob/M, ignore_category = null)
- var/list/L = pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
+ var/list/L = pollGhostCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
if(!M || QDELETED(M) || !M.loc)
return list()
return L
/proc/pollCandidatesForMobs(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, list/mobs, ignore_category = null)
- var/list/L = pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
+ var/list/L = pollGhostCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
var/i=1
for(var/v in mobs)
var/atom/A = v
@@ -487,62 +502,51 @@
return L
/proc/pollCultists(var/mob/living/Nominee) // Cult Master Poll
- var/time_passed = world.time
- var/list/yes_voters = new
- var/list/cult_total = new
if(world.time < CULT_POLL_WAIT)
- Nominee << "It would be premature to select a leader while everyone is still settling in, try again in [round((CULT_POLL_WAIT-world.time)/10)] seconds"
+ to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [round((CULT_POLL_WAIT-world.time)/10)] seconds.")
return
for(var/datum/mind/B in SSticker.mode.cult)
- var/mob/living/M = B.current
- if(!M.incapacitated())
- M << 'sound/hallucinations/im_here1.ogg'
- M.verbs -= /mob/living/proc/cult_master
- to_chat(M, "Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.")
+ if(B.current)
+ B.current.verbs -= /mob/living/proc/cult_master
+ if(!B.current.incapacitated())
+ B.current << 'sound/hallucinations/im_here1.ogg'
+ to_chat(B.current, "Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.")
sleep(250)
+ var/list/asked_cultists = list()
for(var/datum/mind/B in SSticker.mode.cult)
- var/mob/living/M = B.current
- if(!M.incapacitated())
- M << 'sound/magic/exit_blood.ogg'
- switch(askuser(M,"[Nominee] seeks to lead your cult, do you support them?","Please answer in 20 seconds!","Yes","No","Abstain", StealFocus=0, Timeout=200))
- if(1)
- if((world.time-time_passed)>500)
- to_chat(M, "Sorry, your vote came too late!")
- M << 'sound/machines/buzz-sigh.ogg'
- else
- M << "Choice registered: Yes."
- yes_voters += M
- cult_total += M
- if(2)
- if((world.time-time_passed)>500)
- to_chat(M, "Sorry, your vote came too late!")
- M << 'sound/machines/buzz-sigh.ogg'
- else
- to_chat(M, "Choice registered: No.")
- cult_total += M
- if(3)
- to_chat(M, "Choice registered: Abstain.")
+ if(B.current && B.current != Nominee && !B.current.incapacitated())
+ B.current << 'sound/magic/exit_blood.ogg'
+ asked_cultists += B.current
+ var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 1200, group = asked_cultists)
sleep(300)
- if(yes_voters.len > (cult_total.len/2))
- var/datum/action/innate/cultmast/finalreck/FinalReckoning = new()
- var/datum/action/innate/cultmast/cultmark/Mark = new()
- FinalReckoning.Grant(Nominee)
- Mark.Grant(Nominee)
- Nominee.mind.special_role = "Cult Master"
- Nominee.update_action_buttons_icon()
- Nominee.apply_status_effect(/datum/status_effect/cult_master)
- SSticker.mode.set_antag_hud(Nominee,"cultmaster")
- GLOB.cult_mastered = TRUE
+ if(QDELETED(Nominee) || Nominee.incapacitated())
for(var/datum/mind/B in SSticker.mode.cult)
- if(!B.current.incapacitated())
- to_chat(B.current,"[Nominee] has the cult's support and is now their master. Follow their orders to the best of your ability!")
- return TRUE
- else
- for(var/datum/mind/B in SSticker.mode.cult)
- if(!B.current.incapacitated())
- to_chat(B.current, "[Nominee] could not win the cult's support and shall continue to serve as an acolyte.")
+ if(B.current)
B.current.verbs += /mob/living/proc/cult_master
+ if(!B.current.incapacitated())
+ to_chat(B.current,"[Nominee] has died in the process of attempting to win the cult's support!")
return FALSE
+ if(!Nominee.mind)
+ for(var/datum/mind/B in SSticker.mode.cult)
+ if(B.current)
+ B.current.verbs += /mob/living/proc/cult_master
+ if(!B.current.incapacitated())
+ to_chat(B.current,"[Nominee] has gone insane and catatonic in the process of attempting to win the cult's support!")
+ return FALSE
+ if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
+ for(var/datum/mind/B in SSticker.mode.cult)
+ if(B.current)
+ B.current.verbs += /mob/living/proc/cult_master
+ if(!B.current.incapacitated())
+ to_chat(B.current, "[Nominee] could not win the cult's support and shall continue to serve as an acolyte.")
+ return FALSE
+ SSticker.mode.remove_cultist(Nominee.mind, FALSE)
+ Nominee.mind.add_antag_datum(ANTAG_DATUM_CULT_MASTER)
+ GLOB.cult_mastered = TRUE
+ for(var/datum/mind/B in SSticker.mode.cult)
+ if(!B.current.incapacitated())
+ to_chat(B.current,"[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!")
+ return TRUE
/proc/poll_helper(var/mob/living/M)
diff --git a/code/_globalvars/game_modes.dm b/code/_globalvars/game_modes.dm
index 912ae78a04..299113795d 100644
--- a/code/_globalvars/game_modes.dm
+++ b/code/_globalvars/game_modes.dm
@@ -3,10 +3,12 @@ GLOBAL_VAR_INIT(secret_force_mode, "secret") // if this is anything but "secret"
GLOBAL_VAR_INIT(wavesecret, 0) // meteor mode, delays wave progression, terrible name
GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report
-
-// Cult, needs to be global so admin cultists are functional
-GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master
-GLOBAL_DATUM(sac_mind, /datum/mind)
-GLOBAL_VAR_INIT(sac_image, null)
-GLOBAL_VAR_INIT(cult_mastered, FALSE)
+
+// Cult, needs to be global so admin cultists are functional
+GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master
+GLOBAL_DATUM(blood_target_image, /image)
+GLOBAL_DATUM(sac_mind, /datum/mind)
+GLOBAL_VAR_INIT(sac_image, null)
+GLOBAL_VAR_INIT(cult_mastered, FALSE)
+GLOBAL_VAR_INIT(reckoning_complete, FALSE)
GLOBAL_VAR_INIT(sac_complete, FALSE)
\ No newline at end of file
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index b95750009f..7cbd997db6 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -265,20 +265,20 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
desc = "Allows you to sense blood that is manipulated by dark magicks."
icon_state = "cult_sense"
alerttooltipstyle = "cult"
- var/image/sacimage
+ var/static/image/narnar
var/angle = 0
var/mob/living/simple_animal/hostile/construct/Cviewer = null
/obj/screen/alert/bloodsense/Initialize()
- ..()
- sacimage = GLOB.sac_image
+ . = ..()
+ if(!narnar)
+ narnar = new('icons/mob/screen_alert.dmi', "mini_nar")
START_PROCESSING(SSprocessing, src)
/obj/screen/alert/bloodsense/Destroy()
- sacimage = null
- Cviewer = null
- STOP_PROCESSING(SSprocessing, src)
- return ..()
+ Cviewer = null
+ STOP_PROCESSING(SSprocessing, src)
+ return ..()
/obj/screen/alert/bloodsense/process()
var/atom/blood_target
@@ -298,7 +298,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
cut_overlays()
icon_state = "runed_sense0"
desc = "Nar-Sie demands that [GLOB.sac_mind] be sacrificed before the summoning ritual can begin."
- add_overlay(sacimage)
+ add_overlay(GLOB.sac_image)
return
if(!blood_target && GLOB.sac_complete)
if(icon_state == "runed_sense1")
@@ -307,7 +307,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
angle = 0
cut_overlays()
icon_state = "runed_sense1"
- var/image/narnar = new('icons/mob/screen_alert.dmi', "mini_nar")
desc = "The sacrifice is complete, prepare to summon Nar-Sie!"
add_overlay(narnar)
return
@@ -318,8 +317,8 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
var/area/A = get_area(P)
if(P.z != Q.z) //The target is on a different Z level, we cannot sense that far.
return
- desc = "You are currently tracking [blood_target] in [A.name]"
- var/target_angle = Get_Angle(mob_viewer, blood_target)
+ desc = "You are currently tracking [blood_target] in [A.name]."
+ var/target_angle = Get_Angle(Q, P)
var/target_dist = get_dist(P, Q)
cut_overlays()
switch(target_dist)
diff --git a/code/datums/antagonists/datum_cult.dm b/code/datums/antagonists/datum_cult.dm
index 59f165ff37..9016331440 100644
--- a/code/datums/antagonists/datum_cult.dm
+++ b/code/datums/antagonists/datum_cult.dm
@@ -2,20 +2,21 @@
var/datum/action/innate/cultcomm/communion = new
/datum/antagonist/cult/Destroy()
- qdel(communion)
+ QDEL_NULL(communion)
return ..()
/datum/antagonist/cult/proc/add_objectives()
var/list/target_candidates = list()
for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && !is_convertable_to_cult(player) && (player != owner) && isliving(player))
+ if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && (player != owner) && player.stat != DEAD)
target_candidates += player.mind
if(target_candidates.len == 0)
message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.mind && (player != owner) && isliving(player))
+ if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && (player != owner) && player.stat != DEAD)
target_candidates += player.mind
- if(target_candidates.len > 0)
+ listclearnulls(target_candidates)
+ if(LAZYLEN(target_candidates))
GLOB.sac_mind = pick(target_candidates)
if(!GLOB.sac_mind)
message_admins("Cult Sacrifice: ERROR - Null target chosen!")
@@ -33,7 +34,6 @@
GLOB.sac_complete = TRUE
SSticker.mode.cult_objectives += "sacrifice"
SSticker.mode.cult_objectives += "eldergod"
- on_gain()
/datum/antagonist/cult/proc/cult_memorization(datum/mind/cult_mind)
var/mob/living/current = cult_mind.current
@@ -47,7 +47,8 @@
explanation = "The veil has already been weakened here, proceed to the final objective."
if("eldergod")
explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie' with nine acolytes on it. You must do this after sacrificing your target."
- to_chat(current, "Objective #[obj_count]: [explanation]")
+ if(!silent)
+ to_chat(current, "Objective #[obj_count]: [explanation]")
cult_mind.memory += "Objective #[obj_count]: [explanation]
"
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
@@ -58,16 +59,16 @@
/datum/antagonist/cult/on_gain()
. = ..()
var/mob/living/current = owner.current
- if(SSticker.mode.cult_objectives.len == 0)
+ if(!LAZYLEN(SSticker.mode.cult_objectives))
add_objectives()
- return
SSticker.mode.cult += owner // Only add after they've been given objectives
cult_memorization(owner)
if(jobban_isbanned(current, ROLE_CULTIST))
addtimer(CALLBACK(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, current, ROLE_CULTIST, ROLE_CULTIST), 0)
SSticker.mode.update_cult_icons_added(owner)
- current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
current.log_message("Has been converted to the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
+ if(GLOB.blood_target && GLOB.blood_target_image && current.client)
+ current.client.images += GLOB.blood_target_image
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
. = ..()
@@ -79,6 +80,7 @@
if(!GLOB.cult_mastered)
current.verbs += /mob/living/proc/cult_master
communion.Grant(current)
+ current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
/datum/antagonist/cult/remove_innate_effects(mob/living/mob_override)
. = ..()
@@ -97,8 +99,50 @@
owner.wipe_memory()
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
- to_chat(owner, "An unfamiliar white light flashes through your mind, cleansing the taint of the Dark One and all your memories as its servant.")
- owner.current.log_message("Has renounced the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
if(!silent)
- owner.current.visible_message("[owner] looks like [owner.current.p_they()] just reverted to their old faith!")
+ to_chat(owner.current, "An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.")
+ owner.current.log_message("Has renounced the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
+ owner.current.visible_message("[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!")
+ if(GLOB.blood_target && GLOB.blood_target_image && owner.current.client)
+ owner.current.client.images -= GLOB.blood_target_image
. = ..()
+
+/datum/antagonist/cult/master
+ var/datum/action/innate/cultmast/finalreck/reckoning = new
+ var/datum/action/innate/cultmast/cultmark/bloodmark = new
+
+/datum/antagonist/cult/master/Destroy()
+ QDEL_NULL(reckoning)
+ QDEL_NULL(bloodmark)
+ return ..()
+
+/datum/antagonist/cult/master/on_gain()
+ . = ..()
+ var/mob/living/current = owner.current
+ SSticker.mode.set_antag_hud(current, "cultmaster")
+
+/datum/antagonist/cult/master/greet()
+ to_chat(owner.current, "You are the cult's Master. As the cult's Master, you have a unique title and loud voice when communicating, are capable of marking \
+ targets, such as a location or a noncultist, to direct the cult to them, and, finally, you are capable of summoning the entire living cult to your location once.")
+ to_chat(owner.current, "Use these abilities to direct the cult to victory at any cost.")
+
+/datum/antagonist/cult/master/apply_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current = owner.current
+ if(mob_override)
+ current = mob_override
+ if(!GLOB.reckoning_complete)
+ reckoning.Grant(current)
+ bloodmark.Grant(current)
+ current.update_action_buttons_icon()
+ current.apply_status_effect(/datum/status_effect/cult_master)
+
+/datum/antagonist/cult/master/remove_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current = owner.current
+ if(mob_override)
+ current = mob_override
+ reckoning.Remove(current)
+ bloodmark.Remove(current)
+ current.update_action_buttons_icon()
+ current.remove_status_effect(/datum/status_effect/cult_master)
diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
index aa1a07ac2f..21da8fab00 100644
--- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
+++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
@@ -135,7 +135,7 @@
if(!check_special_requirements())
return FALSE
to_chat(invoker, "The tendril shivers slightly as it selects a marauder...")
- var/list/marauder_candidates = pollCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 50, POLL_IGNORE_CLOCKWORK_MARAUDER)
+ var/list/marauder_candidates = pollGhostCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 50, POLL_IGNORE_CLOCKWORK_MARAUDER)
if(!check_special_requirements())
return FALSE
if(!marauder_candidates.len)
diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm
index ff8ee97de7..ffaaf46b80 100644
--- a/code/game/gamemodes/cult/cult_comms.dm
+++ b/code/game/gamemodes/cult/cult_comms.dm
@@ -24,12 +24,19 @@
var/my_message
if(!message)
return
- user.whisper("O bidai nabora se[pick("'","`")]sma!")
+ user.whisper("O bidai nabora se[pick("'","`")]sma!", language = /datum/language/common)
user.whisper(html_decode(message))
- if (user.mind.special_role == "Cult Master")
- my_message = "[(ishuman(user) ? "Master" : "Lord")] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: [message]"
- else
- my_message = "[(ishuman(user) ? "Acolyte" : "Construct")] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: [message]"
+ var/title = "Acolyte"
+ var/span = "cultitalic"
+ if(user.mind && user.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
+ span = "cultlarge"
+ if(ishuman(user))
+ title = "Master"
+ else
+ title = "Lord"
+ else if(!ishuman(user))
+ title = "Construct"
+ my_message = "[title] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: [message]"
for(var/mob/M in GLOB.mob_list)
if(iscultist(M))
to_chat(M, my_message)
@@ -83,83 +90,88 @@
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS
/datum/action/innate/cultmast/IsAvailable()
- if(owner.mind.special_role != "Cult Master")
+ if(!owner.mind || !owner.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
return 0
return ..()
/datum/action/innate/cultmast/finalreck
name = "Final Reckoning"
- desc = "A single-use spell that brings the entire cult to the master's location"
+ desc = "A single-use spell that brings the entire cult to the master's location."
button_icon_state = "sintouch"
/datum/action/innate/cultmast/finalreck/Activate()
- var/list/destinations = list()
- for(var/turf/T in orange(1,owner))
- if(istype(T, /turf/open))
- destinations += T
for(var/i in 1 to 4)
- owner.chant(i)
+ chant(i)
+ var/list/destinations = list()
+ for(var/turf/T in orange(1, owner))
+ if(!is_blocked_turf(T, TRUE))
+ destinations += T
+ if(!LAZYLEN(destinations))
+ to_chat(owner, "You need more space to summon the cult!")
+ return
if(do_after(owner, 30, target = owner))
for(var/datum/mind/B in SSticker.mode.cult)
- var/mob/living/M = B.current
- if(isliving(M) && M.stat != DEAD)
- var/turf/mobloc = get_turf(M)
+ if(B.current && B.current.stat != DEAD)
+ var/turf/mobloc = get_turf(B.current)
switch(i)
- if (1)
- new /obj/effect/overlay/temp/cult/sparks(mobloc, M.dir)
+ if(1)
+ new /obj/effect/overlay/temp/cult/sparks(mobloc, B.current.dir)
playsound(mobloc, "sparks", 50, 1)
- if (2)
- new /obj/effect/overlay/temp/dir_setting/cult/phase/out(mobloc, M.dir)
+ if(2)
+ new /obj/effect/overlay/temp/dir_setting/cult/phase/out(mobloc, B.current.dir)
playsound(mobloc, "sparks", 75, 1)
- if (3)
- new /obj/effect/overlay/temp/dir_setting/cult/phase(mobloc, M.dir)
+ if(3)
+ new /obj/effect/overlay/temp/dir_setting/cult/phase(mobloc, B.current.dir)
playsound(mobloc, "sparks", 100, 1)
- if (4)
+ if(4)
playsound(mobloc, 'sound/magic/exit_blood.ogg', 100, 1)
- if(M != owner)
+ if(B.current != owner)
+ B.current.setDir(SOUTH)
var/turf/final = pick(destinations)
new /obj/effect/overlay/temp/cult/blood(final)
- addtimer(CALLBACK(M, /mob/.proc/reckon, final), 10)
- else
- for(var/datum/action/innate/cultmast/finalreck/H in owner.actions)
- qdel(H)
+ addtimer(CALLBACK(B.current, /mob/.proc/reckon, final), 10)
else
return
+ GLOB.reckoning_complete = TRUE
+ Remove(owner)
-/mob/proc/reckon(var/turf/final)
+/mob/proc/reckon(turf/final)
new /obj/effect/overlay/temp/cult/blood/out(get_turf(src))
forceMove(final)
-/mob/proc/chant(var/i)
- switch(i)
- if (1)
- say("C'arta Forbici!")
- if (2)
- say("Pleggh E'ntrath!")
- playsound(get_turf(src),'sound/magic/clockwork/narsie_attack.ogg', 50, 1)
- if (3)
- say("Barhah hra Zar'garis!")
- playsound(get_turf(src),'sound/magic/clockwork/narsie_attack.ogg', 75, 1)
- if (4)
- say("N'ath reth Sh'yro eth D'rekkathnor!!!")
- playsound(get_turf(src),'sound/magic/clockwork/narsie_attack.ogg', 100, 1)
+/datum/action/innate/cultmast/finalreck/proc/chant(chant_number)
+ switch(chant_number)
+ if(1)
+ owner.say("C'arta forbici!", language = /datum/language/common)
+ if(2)
+ owner.say("Pleggh e'ntrath!", language = /datum/language/common)
+ playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 50, 1)
+ if(3)
+ owner.say("Barhah hra zar'garis!", language = /datum/language/common)
+ playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 75, 1)
+ if(4)
+ owner.say("N'ath reth sh'yro eth d'rekkathnor!!!", language = /datum/language/common)
+ playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 100, 1)
/datum/action/innate/cultmast/cultmark
name = "Mark Target"
- desc = "Marks a target for the cult"
+ desc = "Marks a target for the cult."
button_icon_state = "cult_mark"
var/obj/effect/proc_holder/cultmark/CM
- var/time = 0
+ var/cooldown = 0
+ var/base_cooldown = 1200
/datum/action/innate/cultmast/cultmark/New()
- CM = new()
- ..()
+ CM = new()
+ CM.attached_action = src
+ ..()
/datum/action/innate/cultmast/cultmark/IsAvailable()
- if(owner.mind.special_role != "Cult Master")
+ if(!owner.mind || !owner.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
return 0
- if((world.time - time)<1200 && !CM.active)
- owner << "You need to wait [round((1200-(world.time-time))/10)] seconds before you can mark another target!"
+ if(cooldown > world.time)
+ if(!CM.active)
+ owner << "You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can mark another target!"
return 0
return ..()
@@ -169,22 +181,22 @@
/datum/action/innate/cultmast/cultmark/Activate()
CM.toggle(owner) //the important bit
- if(!active)
- time = world.time
- else
- time = 0
return TRUE
/obj/effect/proc_holder/cultmark
- active = FALSE
- ranged_mousepointer = 'icons/effects/cult_target.dmi'
+ active = FALSE
+ ranged_mousepointer = 'icons/effects/cult_target.dmi'
+ var/datum/action/innate/cultmast/cultmark/attached_action
+/obj/effect/proc_holder/cultmark/Destroy()
+ attached_action = null
+ return ..()
/obj/effect/proc_holder/cultmark/proc/toggle(mob/user)
- if(active)
- remove_ranged_ability("You cease the marking ritual...")
- else
- add_ranged_ability(user, "You prepare to mark a target for your cult...")
+ if(active)
+ remove_ranged_ability("You cease the marking ritual.")
+ else
+ add_ranged_ability(user, "You prepare to mark a target for your cult...")
/obj/effect/proc_holder/cultmark/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
@@ -196,24 +208,29 @@
if(!isturf(T))
return FALSE
if(target in view(7, get_turf(ranged_ability_user)))
- remove_ranged_ability(caller, "The marking rite is complete! It will last for 90 seconds.")
GLOB.blood_target = target
var/area/A = get_area(target)
+ attached_action.cooldown = world.time + attached_action.base_cooldown
+ addtimer(CALLBACK(attached_action.owner, /mob.proc/update_action_buttons_icon), attached_action.base_cooldown)
+ GLOB.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
+ GLOB.blood_target_image.appearance_flags = RESET_COLOR
+ GLOB.blood_target_image.pixel_x = -target.pixel_x
+ GLOB.blood_target_image.pixel_y = -target.pixel_y
for(var/datum/mind/B in SSticker.mode.cult)
- var/mob/living/M = B.current
- if(M.stat != DEAD)
- to_chat(M, "Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!")
- M << pick(sound('sound/hallucinations/over_here2.ogg',0,1,75), sound('sound/hallucinations/over_here3.ogg',0,1,75))
- var/image/cult_marker = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
- M.client.images |= cult_marker
- addtimer(CALLBACK(M, /mob/living/proc/reset_blood_image, cult_marker), 900, TIMER_OVERRIDE)
+ if(B.current && B.current.stat != DEAD && B.current.client)
+ to_chat(B.current, "Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!")
+ B.current << pick(sound('sound/hallucinations/over_here2.ogg',0,1,75), sound('sound/hallucinations/over_here3.ogg',0,1,75))
+ B.current.client.images += GLOB.blood_target_image
+ attached_action.owner.update_action_buttons_icon()
+ remove_ranged_ability("The marking rite is complete! It will last for 90 seconds.")
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target), 900, TIMER_OVERRIDE)
return TRUE
return FALSE
-/mob/living/proc/reset_blood_image(var/image/cult_marker)
- if(GLOB.blood_target && src.stat!=DEAD)
- to_chat(src,"The blood mark has expired!")
- if(client)
- client.images.Remove(cult_marker)
- QDEL_NULL(cult_marker)
- GLOB.blood_target = null
\ No newline at end of file
+/proc/reset_blood_target()
+ for(var/datum/mind/B in SSticker.mode.cult)
+ if(B.current && B.current.stat != DEAD && B.current.client)
+ if(GLOB.blood_target)
+ to_chat(B.current,"The blood mark has expired!")
+ B.current.client.images -= GLOB.blood_target_image
+ QDEL_NULL(GLOB.blood_target)
\ No newline at end of file
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index f393929463..069a422480 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -200,7 +200,7 @@ This file contains the arcane tome files.
if(!("eldergod" in SSticker.mode.cult_objectives))
to_chat(user, "Nar-Sie does not wish to be summoned!")
return
- if(GLOB.sac_complete)
+ if(!GLOB.sac_complete)
to_chat(user, "The sacrifice is not complete. The portal would lack the power to open if you tried!")
return
if(!SSticker.mode.eldergod)
@@ -209,7 +209,7 @@ This file contains the arcane tome files.
if((loc.z && loc.z != ZLEVEL_STATION) || !A.blob_allowed)
to_chat(user, "The Geometer is not interested in lesser locations; the station is the prize!")
return
- var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie, it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
+ var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
if(confirm_final == "No")
to_chat(user, "You decide to prepare further before scribing the rune.")
return
diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm
index b840b64c93..09412a79ac 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -253,7 +253,7 @@
break
if(!chosen_ghost) //Failing that, we grab a ghost
- var/list/consenting_candidates = pollCandidates("Would you like to play as a Shade?", "Cultist", null, ROLE_CULTIST, poll_time = 50)
+ var/list/consenting_candidates = pollGhostCandidates("Would you like to play as a Shade?", "Cultist", null, ROLE_CULTIST, poll_time = 50)
if(consenting_candidates.len)
chosen_ghost = pick(consenting_candidates)
if(!T)
diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm
index aa720f1979..4b5acd949d 100644
--- a/code/game/objects/items/weapons/holy_weapons.dm
+++ b/code/game/objects/items/weapons/holy_weapons.dm
@@ -214,7 +214,7 @@
possessed = TRUE
- var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_POSSESSED_BLADE)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_POSSESSED_BLADE)
var/mob/dead/observer/theghost = null
if(LAZYLEN(candidates))
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index d7b06ee9c8..87a9e5a040 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -132,7 +132,7 @@
/datum/admins/proc/makeWizard()
- var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for the position of a Wizard Foundation 'diplomat'?", "wizard", null)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for the position of a Wizard Foundation 'diplomat'?", "wizard", null)
var/mob/dead/observer/selected = pick_n_take(candidates)
@@ -215,7 +215,7 @@
/datum/admins/proc/makeNukeTeam()
var/datum/game_mode/nuclear/temp = new
- var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for a nuke team being sent in?", "operative", temp)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for a nuke team being sent in?", "operative", temp)
var/list/mob/dead/observer/chosen = list()
var/mob/dead/observer/theghost = null
@@ -288,7 +288,7 @@
// DEATH SQUADS
/datum/admins/proc/makeDeathsquad()
var/mission = input("Assign a mission to the deathsquad", "Assign Mission", "Leave no witnesses.")
- var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for an elite Nanotrasen Strike Team?", "deathsquad", null)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for an elite Nanotrasen Strike Team?", "deathsquad", null)
var/squadSpawned = 0
if(candidates.len >= 2) //Minimum 2 to be considered a squad
@@ -396,7 +396,7 @@
/datum/admins/proc/makeOfficial()
var/mission = input("Assign a task for the official", "Assign Task", "Conduct a routine preformance review of [station_name()] and its Captain.")
- var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered to be a Centcom Official?", "deathsquad")
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered to be a Centcom Official?", "deathsquad")
if(candidates.len)
var/mob/dead/observer/chosen_candidate = pick(candidates)
@@ -457,7 +457,7 @@
var/mission = input("Assign a mission to the Emergency Response Team", "Assign Mission", "Assist the station.") as null|text
if(!mission)
return
- var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for a Code [alert] Nanotrasen Emergency Response Team?", "deathsquad", null)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for a Code [alert] Nanotrasen Emergency Response Team?", "deathsquad", null)
var/teamSpawned = 0
if(candidates.len > 0)
diff --git a/code/modules/events/ghost_role.dm b/code/modules/events/ghost_role.dm
index 93eff54b27..2468ddb5c6 100644
--- a/code/modules/events/ghost_role.dm
+++ b/code/modules/events/ghost_role.dm
@@ -59,7 +59,7 @@
var/list/mob/dead/observer/regular_candidates
// don't get their hopes up
if(priority_candidates.len < minimum_required)
- regular_candidates = pollCandidates("Do you wish to be considered for the special role of '[role_name]'?", jobban, gametypecheck, be_special)
+ regular_candidates = pollGhostCandidates("Do you wish to be considered for the special role of '[role_name]'?", jobban, gametypecheck, be_special)
else
regular_candidates = list()
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 68d94b4c04..6e9bcc08cc 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -69,7 +69,7 @@
bursting = TRUE
- var/list/candidates = pollCandidates("Do you want to play as an alien larva that will burst out of [owner]?", ROLE_ALIEN, null, ROLE_ALIEN, 100, POLL_IGNORE_ALIEN_LARVA)
+ var/list/candidates = pollGhostCandidates("Do you want to play as an alien larva that will burst out of [owner]?", ROLE_ALIEN, null, ROLE_ALIEN, 100, POLL_IGNORE_ALIEN_LARVA)
if(QDELETED(src) || QDELETED(owner))
return
@@ -81,7 +81,7 @@
var/mob/dead/observer/ghost = pick(candidates)
- var/mutable_appearance/overlay = mutable_appearance('icons/mob/alien.dmi', "burst_lie")
+ var/mutable_appearance/overlay = mutable_appearance('icons/mob/alien.dmi', "burst_lie")
owner.add_overlay(overlay)
var/atom/xeno_loc = get_turf(owner)
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
index be889a4183..fe6e22bcab 100644
--- a/code/modules/mob/living/simple_animal/guardian/guardian.dm
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -414,7 +414,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
var/mob/living/simple_animal/hostile/guardian/G = input(src, "Pick the guardian you wish to reset", "Guardian Reset") as null|anything in guardians
if(G)
to_chat(src, "You attempt to reset [G.real_name]'s personality...")
- var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as [src.real_name]'s [G.real_name]?", "pAI", null, FALSE, 100)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as [src.real_name]'s [G.real_name]?", "pAI", null, FALSE, 100)
var/mob/dead/observer/new_stand = null
if(candidates.len)
new_stand = pick(candidates)
@@ -489,7 +489,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
return
used = TRUE
to_chat(user, "[use_message]")
- var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the [mob_name] of [user.real_name]?", ROLE_PAI, null, FALSE, 100)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the [mob_name] of [user.real_name]?", ROLE_PAI, null, FALSE, 100)
var/mob/dead/observer/theghost = null
if(candidates.len)