[MIRROR] Fixes being able to spam ghost role notifications. (#7904)

* Fixes being able to spam ghost role notifications. (#61085)

There are methods that let players spam the everloving shit out of ghosts with BONG BONG BONG BONG BONG BONG BONG etc. through being able to constantly poll ghosts for roles with no restriction or cooldown.

Examples are laughter and slaughter demon antag_spawners.

It makes no sense to be able to concurrently poll for the same mob. As a result, I've now added a guard against this. The proc has been given a static list of mobs it's polling for ghost roles for. If it's already polling for ghost roles for a given mob, then it just early returns with an empty list, otherwise it adds the mob to the static list when the poll starts and removes it when the poll ends.

I've also done a little cleanup in var names and the proc name, with a find-and-replace done. There weren't many things calling it and none used named keywords in the args so should be fine.

There is also poll_candidates_for_mobs (also included in my cleanup) - This proc is basically only called by admins via sentience balloons and they have their own guards against spamming (the balloon pops and thus can only be used once)

Also fixes an issue in /mob/living/silicon/robot/proc/replace_banned_cyborg() where incorrect args were used in the proc call to poll for candidates.

* Fixes being able to spam ghost role notifications.

* a

Co-authored-by: Timberpoes <silent_insomnia_pp@hotmail.co.uk>
Co-authored-by: Gandalf <jzo123@hotmail.com>
This commit is contained in:
SkyratBot
2021-09-01 18:00:32 +02:00
committed by GitHub
parent 06b6977fbd
commit b267e1922b
21 changed files with 73 additions and 40 deletions
+48 -15
View File
@@ -438,22 +438,55 @@
return result
/proc/pollCandidatesForMob(Question, jobbanType, be_special_flag = 0, poll_time = 300, mob/M, ignore_category = null)
var/list/L = pollGhostCandidates(Question, jobbanType, be_special_flag, poll_time, ignore_category)
if(!M || QDELETED(M) || !M.loc)
return list()
return L
/**
* Returns a list of ghosts that are eligible to take over and wish to be considered for a mob.
*
* Arguments:
* * question - Question to show players as part of poll
* * jobban_type - Type of jobban to use to filter out potential candidates.
* * be_special_flag - Unknown/needs further documentation.
* * poll_time - Length of time in deciseconds that the poll input box exists before closing.
* * target_mob - The mob that is being polled for.
* * ignore_category - Unknown/needs further documentation.
*/
/proc/poll_candidates_for_mob(question, jobban_type, be_special_flag = 0, poll_time = 30 SECONDS, mob/target_mob, ignore_category = null)
var/static/list/mob/currently_polling_mobs = list()
/proc/pollCandidatesForMobs(Question, jobbanType, be_special_flag = 0, poll_time = 300, list/mobs, ignore_category = null)
var/list/L = pollGhostCandidates(Question, jobbanType, be_special_flag, poll_time, ignore_category)
var/i=1
for(var/v in mobs)
var/atom/A = v
if(!A || QDELETED(A) || !A.loc)
mobs.Cut(i,i+1)
else
++i
return L
if(currently_polling_mobs.Find(target_mob))
return list()
currently_polling_mobs += target_mob
var/list/possible_candidates = pollGhostCandidates(question, jobban_type, be_special_flag, poll_time, ignore_category)
currently_polling_mobs -= target_mob
if(!target_mob || QDELETED(target_mob) || !target_mob.loc)
return list()
return possible_candidates
/**
* Returns a list of ghosts that are eligible to take over and wish to be considered for a mob.
*
* Arguments:
* * question - Question to show players as part of poll
* * jobban_type - Type of jobban to use to filter out potential candidates.
* * be_special_flag - Unknown/needs further documentation.
* * poll_time - Length of time in deciseconds that the poll input box exists before closing.
* * mobs - The list of mobs being polled for. This list is mutated and invalid mobs are removed from it before the proc returns.
* * ignore_category - Unknown/needs further documentation.
*/
/proc/poll_candidates_for_mobs(question, jobban_type, be_special_flag = 0, poll_time = 30 SECONDS, list/mobs, ignore_category = null)
var/list/candidate_list = pollGhostCandidates(question, jobban_type, be_special_flag, poll_time, ignore_category)
for(var/mob/potential_mob as anything in mobs)
if(QDELETED(potential_mob) || !potential_mob.loc)
mobs -= potential_mob
if(!length(mobs))
return list()
return candidate_list
/proc/makeBody(mob/dead/observer/G_found) // Uses stripped down and bastardized code from respawn character
if(!G_found || !G_found.key)
+1 -1
View File
@@ -47,7 +47,7 @@
/datum/brain_trauma/special/imaginary_friend/proc/get_ghost()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner.real_name]'s imaginary friend?", ROLE_PAI, null, 75, friend, POLL_IGNORE_IMAGINARYFRIEND)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as [owner.real_name]'s imaginary friend?", ROLE_PAI, null, 7.5 SECONDS, friend, POLL_IGNORE_IMAGINARYFRIEND)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
friend.key = C.key
@@ -33,7 +33,7 @@
/datum/brain_trauma/severe/split_personality/proc/get_ghost()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner.real_name]'s split personality?", ROLE_PAI, null, 75, stranger_backseat, POLL_IGNORE_SPLITPERSONALITY)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as [owner.real_name]'s split personality?", ROLE_PAI, null, 7.5 SECONDS, stranger_backseat, POLL_IGNORE_SPLITPERSONALITY)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
stranger_backseat.key = C.key
@@ -206,7 +206,7 @@
/datum/brain_trauma/severe/split_personality/brainwashing/get_ghost()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner.real_name]'s brainwashed mind?", null, null, 75, stranger_backseat)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as [owner.real_name]'s brainwashed mind?", null, null, 7.5 SECONDS, stranger_backseat)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
stranger_backseat.key = C.key
+1 -1
View File
@@ -83,7 +83,7 @@
/datum/disease/transformation/proc/replace_banned_player(mob/living/new_mob) // This can run well after the mob has been transferred, so need a handle on the new mob to kill it if needed.
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [affected_mob.real_name]?", bantype, bantype, 50, affected_mob)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as [affected_mob.real_name]?", bantype, bantype, 5 SECONDS, affected_mob)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
to_chat(affected_mob, span_userdanger("Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!"))
+1 -1
View File
@@ -322,7 +322,7 @@
var/datum/action/innate/slime/reproduce/A = new
A.Grant(S)
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a pyroclastic anomaly slime?", ROLE_SENTIENCE, null, 100, S, POLL_IGNORE_PYROSLIME)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as a pyroclastic anomaly slime?", ROLE_SENTIENCE, null, 10 SECONDS, S, POLL_IGNORE_PYROSLIME)
if(LAZYLEN(candidates))
var/mob/dead/observer/chosen = pick(candidates)
S.key = chosen.key
+1 -1
View File
@@ -88,7 +88,7 @@
bodies += possessable
var/question = "Would you like to be [group_name]?"
var/list/candidates = pollCandidatesForMobs(question, ROLE_PAI, FALSE, 100, bodies)
var/list/candidates = poll_candidates_for_mobs(question, ROLE_PAI, FALSE, 10 SECONDS, bodies)
while(LAZYLEN(candidates) && LAZYLEN(bodies))
var/mob/dead/observer/C = pick_n_take(candidates)
var/mob/living/body = pick_n_take(bodies)
@@ -187,7 +187,7 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/replace_banned_player()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [name]?", "[name]", job_rank, 50, owner.current)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as a [name]?", "[name]", job_rank, 5 SECONDS, owner.current)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
@@ -56,7 +56,7 @@
if(used)
to_chat(H, span_warning("You already used this contract!"))
return
var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, ROLE_WIZARD, 150, src)
var/list/candidates = poll_candidates_for_mob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, ROLE_WIZARD, 15 SECONDS, src)
if(LAZYLEN(candidates))
if(QDELETED(src))
return
@@ -244,7 +244,7 @@
return
if(used)
return
var/list/candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, ROLE_ALIEN, 50, src)
var/list/candidates = poll_candidates_for_mob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, ROLE_ALIEN, 5 SECONDS, src)
if(LAZYLEN(candidates))
if(used || QDELETED(src))
return
+1 -1
View File
@@ -579,7 +579,7 @@ structure_check() searches for nearby cultist structures required for the invoca
mob_to_revive.grab_ghost()
if(!mob_to_revive.client || mob_to_revive.client.is_afk())
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.real_name], an inactive blood cultist?", ROLE_CULTIST, ROLE_CULTIST, 50, mob_to_revive)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as a [mob_to_revive.real_name], an inactive blood cultist?", ROLE_CULTIST, ROLE_CULTIST, 5 SECONDS, mob_to_revive)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
@@ -182,10 +182,10 @@
var/mob/living/mob_to_summon
/datum/eldritch_knowledge/summon/on_finished_recipe(mob/living/user, list/atoms, loc)
//we need to spawn the mob first so that we can use it in pollCandidatesForMob, we will move it from nullspace down the code
//we need to spawn the mob first so that we can use it in poll_candidates_for_mob, we will move it from nullspace down the code
var/mob/living/summoned = new mob_to_summon(loc)
message_admins("[summoned.name] is being summoned by [user.real_name] in [loc]")
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [summoned.real_name]", ROLE_HERETIC, FALSE, 100, summoned)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as [summoned.real_name]", ROLE_HERETIC, FALSE, 10 SECONDS, summoned)
if(!LAZYLEN(candidates))
to_chat(user,span_warning("No ghost could be found..."))
qdel(summoned)
@@ -46,7 +46,7 @@
humie.grab_ghost()
if(!humie.mind || !humie.client)
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [humie.real_name], a voiceless dead", ROLE_HERETIC, ROLE_HERETIC, 50,humie)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as a [humie.real_name], a voiceless dead", ROLE_HERETIC, ROLE_HERETIC, 5 SECONDS, humie)
if(!LAZYLEN(candidates))
return
var/mob/dead/observer/chosen_candidate = pick(candidates)
@@ -448,7 +448,7 @@
break
if(!key_of_revenant)
message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...")
var/list/candidates = pollCandidatesForMob("Do you want to be [revenant.name] (reforming)?", ROLE_REVENANT, ROLE_REVENANT, 50, revenant)
var/list/candidates = poll_candidates_for_mob("Do you want to be [revenant.name] (reforming)?", ROLE_REVENANT, ROLE_REVENANT, 5 SECONDS, revenant)
if(!LAZYLEN(candidates))
qdel(revenant)
message_admins("No candidates were found for the new revenant. Oh well!")
@@ -126,7 +126,7 @@
if(!current_wizard)
return
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as Wizard Academy Defender?", ROLE_WIZARD, ROLE_WIZARD, 50, current_wizard, POLL_IGNORE_ACADEMY_WIZARD)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as Wizard Academy Defender?", ROLE_WIZARD, ROLE_WIZARD, 5 SECONDS, current_wizard, POLL_IGNORE_ACADEMY_WIZARD)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
@@ -325,7 +325,7 @@
A.setup_master(user)
servant_mind.transfer_to(H)
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [user.real_name] Servant?", ROLE_WIZARD, ROLE_WIZARD, 50, H)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as [user.real_name] Servant?", ROLE_WIZARD, ROLE_WIZARD, 5 SECONDS, H)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
message_admins("[ADMIN_LOOKUPFLW(C)] was spawned as Dice Servant")
+1 -1
View File
@@ -461,7 +461,7 @@
playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
RegisterSignal(magnification, COMSIG_SPECIES_LOSS, .proc/make_fall_off)
polling = TRUE
var/list/candidates = pollCandidatesForMob("Do you want to play as a mind magnified monkey?", ROLE_SENTIENCE, ROLE_SENTIENCE, 50, magnification, POLL_IGNORE_SENTIENCE_POTION)
var/list/candidates = poll_candidates_for_mob("Do you want to play as a mind magnified monkey?", ROLE_SENTIENCE, ROLE_SENTIENCE, 5 SECONDS, magnification, POLL_IGNORE_SENTIENCE_POTION)
polling = FALSE
if(!magnification)
return
@@ -155,7 +155,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
addtimer(CALLBACK(src, .proc/spawn_elite), 30)
return
visible_message(span_boldwarning("Something within [src] stirs..."))
var/list/candidates = pollCandidatesForMob("Do you want to play as a lavaland elite?", ROLE_SENTIENCE, ROLE_SENTIENCE, 50, src, POLL_IGNORE_SENTIENCE_POTION)
var/list/candidates = poll_candidates_for_mob("Do you want to play as a lavaland elite?", ROLE_SENTIENCE, ROLE_SENTIENCE, 5 SECONDS, src, POLL_IGNORE_SENTIENCE_POTION)
if(candidates.len)
audible_message(span_boldwarning("The stirring sounds increase in volume!"))
elitemind = pick(candidates)
+2 -2
View File
@@ -407,7 +407,7 @@
/**
* Offer control of the passed in mob to dead player
*
* Automatic logging and uses pollCandidatesForMob, how convenient
* Automatic logging and uses poll_candidates_for_mob, how convenient
*/
/proc/offer_control(mob/M)
to_chat(M, "Control of your mob has been offered to dead players.")
@@ -423,7 +423,7 @@
var/datum/antagonist/A = M.mind.has_antag_datum(/datum/antagonist/)
if(A)
poll_message = "[poll_message] Status: [A.name]."
var/list/mob/dead/observer/candidates = pollCandidatesForMob(poll_message, ROLE_PAI, FALSE, 100, M)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob(poll_message, ROLE_PAI, FALSE, 10 SECONDS, M)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
+1 -1
View File
@@ -165,7 +165,7 @@
to_chat(src, "<b>You are job banned from cyborg! Appeal your job ban if you want to avoid this in the future!</b>")
ghostize(FALSE)
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [src]?", "[src]", null, "Cyborg", 50, src)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob("Do you want to play as [src]?", "Cyborg", null, 5 SECONDS, src)
if(LAZYLEN(candidates))
var/mob/dead/observer/chosen_candidate = pick(candidates)
message_admins("[key_name_admin(chosen_candidate)] has taken control of ([key_name_admin(src)]) to replace a jobbanned player.")
+1 -1
View File
@@ -437,7 +437,7 @@
var/datum/antagonist/A = M.mind.has_antag_datum(/datum/antagonist/)
if(A)
poll_message = "[poll_message] Status:[A.name]."
var/list/mob/dead/observer/candidates = pollCandidatesForMob(poll_message, ROLE_PAI, FALSE, 100, M)
var/list/mob/dead/observer/candidates = poll_candidates_for_mob(poll_message, ROLE_PAI, FALSE, 10 SECONDS, M)
if(M.stat == DEAD)//boo.
return
if(LAZYLEN(candidates))
@@ -703,7 +703,7 @@
to_chat(user, span_notice("You offer [src] to [SM]..."))
being_used = TRUE
var/list/candidates = pollCandidatesForMob("Do you want to play as [SM.name]?", ROLE_SENTIENCE, ROLE_SENTIENCE, 50, SM, POLL_IGNORE_SENTIENCE_POTION) // see poll_ignore.dm
var/list/candidates = poll_candidates_for_mob("Do you want to play as [SM.name]?", ROLE_SENTIENCE, ROLE_SENTIENCE, 5 SECONDS, SM, POLL_IGNORE_SENTIENCE_POTION) // see poll_ignore.dm
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
SM.key = C.key
@@ -50,7 +50,7 @@
/obj/item/clothing/head/helmet/monkey_sentience/proc/connect(mob/user)
polling = TRUE
var/list/candidates = pollCandidatesForMob("Do you want to play as a mind magnified monkey?", ROLE_SENTIENCE, M = magnification, ignore_category = POLL_IGNORE_SENTIENCE_POTION)
var/list/candidates = poll_candidates_for_mob("Do you want to play as a mind magnified monkey?", ROLE_SENTIENCE, M = magnification, ignore_category = POLL_IGNORE_SENTIENCE_POTION)
polling = FALSE
if(!magnification)
return
@@ -136,7 +136,7 @@ GLOBAL_LIST_EMPTY(mutant_infection_list) // A list of all mutant_infection organ
/datum/component/mutant_infection/proc/regenerate()
if(!host.mind)
var/list/candidates = pollCandidatesForMob("Do you want to play as a mutant([host.name])?", M = host)
var/list/candidates = poll_candidates_for_mob("Do you want to play as a mutant([host.name])?", M = host)
if(!candidates.len)
return
var/client/C = pick_n_take(candidates)