diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index d30f388df39..1f71b4cdd1c 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -522,6 +522,7 @@ so as to remain in compliance with the most up-to-date laws."
var/action = NOTIFY_JUMP
var/show_time_left = FALSE // If true you need to call START_PROCESSING manually
var/image/time_left_overlay // The last image showing the time left
+ var/image/signed_up_overlay // image showing that you're signed up
var/datum/candidate_poll/poll // If set, on Click() it'll register the player as a candidate
/obj/screen/alert/notify_action/process()
@@ -551,6 +552,9 @@ so as to remain in compliance with the most up-to-date laws."
/obj/screen/alert/notify_action/Destroy()
target = null
+ if(signed_up_overlay)
+ overlays -= signed_up_overlay
+ qdel(signed_up_overlay)
return ..()
/obj/screen/alert/notify_action/Click()
@@ -561,9 +565,14 @@ so as to remain in compliance with the most up-to-date laws."
return
if(poll)
- if(poll.sign_up(G))
+ var/success
+ if(G in poll.signed_up)
+ success = poll.remove_candidate(G)
+ else
+ success = poll.sign_up(G)
+ if(success)
// Add a small overlay to indicate we've signed up
- display_signed_up()
+ update_signed_up_alert()
else if(target)
switch(action)
if(NOTIFY_ATTACK)
@@ -576,14 +585,26 @@ so as to remain in compliance with the most up-to-date laws."
G.ManualFollow(target)
/obj/screen/alert/notify_action/Topic(href, href_list)
- if(href_list["signup"] && poll?.sign_up(usr))
- display_signed_up()
+ if(!href_list["signup"])
+ return
+ if(!poll)
+ return
+ var/mob/dead/observer/G = usr
+ if(G in poll.signed_up)
+ poll.remove_candidate(G)
+ else
+ poll.sign_up(G)
+ update_signed_up_alert()
-/obj/screen/alert/notify_action/proc/display_signed_up()
- var/image/I = image('icons/mob/screen_gen.dmi', icon_state = "selector")
- I.layer = FLOAT_LAYER
- I.plane = FLOAT_PLANE + 2
- overlays += I
+/obj/screen/alert/notify_action/proc/update_signed_up_alert()
+ if(!signed_up_overlay)
+ signed_up_overlay = image('icons/mob/screen_gen.dmi', icon_state = "selector")
+ signed_up_overlay.layer = FLOAT_LAYER
+ signed_up_overlay.plane = FLOAT_PLANE + 2
+ if(usr in poll.signed_up)
+ overlays += signed_up_overlay
+ else
+ overlays -= signed_up_overlay
/obj/screen/alert/notify_action/proc/display_stacks(stacks = 1)
if(stacks <= 1)
diff --git a/code/controllers/subsystem/ghost_spawns.dm b/code/controllers/subsystem/ghost_spawns.dm
index 0490e764685..e9b2c2a8809 100644
--- a/code/controllers/subsystem/ghost_spawns.dm
+++ b/code/controllers/subsystem/ghost_spawns.dm
@@ -96,7 +96,7 @@ SUBSYSTEM_DEF(ghost_spawns)
if(P != P2 && P.hash == P2.hash)
// If there's already a poll for an identical mob type ongoing and the client is signed up for it, sign them up for this one
if(!inherited_sign_up && (M in P2.signed_up) && P.sign_up(M, TRUE))
- A.display_signed_up()
+ A.update_signed_up_alert()
inherited_sign_up = TRUE
// This number is used to display the number of polls the alert regroups
num_stack++
@@ -243,6 +243,7 @@ SUBSYSTEM_DEF(ghost_spawns)
if(!silent)
to_chat(M, "You have already signed up for this!")
return
+
if(time_left() <= 0)
if(!silent)
to_chat(M, "Sorry, you were too late for the consideration!")
@@ -251,7 +252,7 @@ SUBSYSTEM_DEF(ghost_spawns)
signed_up += M
if(!silent)
- to_chat(M, "You have signed up for this role! A candidate will be picked randomly soon..")
+ to_chat(M, "You have signed up for this role! A candidate will be picked randomly soon.")
// Sign them up for any other polls with the same mob type
for(var/existing_poll in SSghost_spawns.currently_polling)
var/datum/candidate_poll/P = existing_poll
@@ -260,6 +261,40 @@ SUBSYSTEM_DEF(ghost_spawns)
return TRUE
+/**
+ * Attempts to remove a signed-up mob from a poll.
+ *
+ * Arguments:
+ * * M - The mob to remove from the poll, if present.
+ * * silent - If TRUE, no messages will be sent to M about their removal.
+ */
+/datum/candidate_poll/proc/remove_candidate(mob/dead/observer/M, silent = FALSE)
+ . = FALSE
+ if(!istype(M) || !M.key || !M.client)
+ return
+ if(!(M in signed_up))
+ if(!silent)
+ to_chat(M, "You aren't signed up for this!")
+ return
+
+ if(time_left() <= 0)
+ if(!silent)
+ to_chat(M, "It's too late to unregister yourself, selection has already begun!")
+ return
+
+ signed_up -= M
+ if(!silent)
+ to_chat(M, "You have been unregistered as a candidate for this role. You can freely sign up again before the poll ends.")
+
+ for(var/existing_poll in SSghost_spawns.currently_polling)
+ var/datum/candidate_poll/P = existing_poll
+ if(src != P && hash == P.hash && (M in P.signed_up))
+ P.remove_candidate(M, TRUE)
+ return TRUE
+
+
+
+
/**
* Deletes any candidates who may have disconnected from the list
*/