mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-16 03:56:20 +00:00
About The Pull Request Ports and improves my interview system that has been previously used in the summer ball and toolbox tournament events. Allows for a 'softer' panic bunker, wherein players who fall below the required living time limit can still join the server and be restricted to filling out a questionnaire. Upon completing the questionnaire, the player may be allowed into the server by an administrator. If the application is approved, they get a notification that they will be reconnected and upon reconnecting will have all verbs as they usually would. If the application is denied the user is put on a cooldown after which they may submit a new questionnaire. Players who are being interviewed (herein interviewees) have no verbs other than those required for the stat panel to function, as well as a verb to pull up the interview panel. Interviews do not persist through restarts, and the ability to join that is granted by an accepted interview is only valid for the duration of that round. Open interviews are listed under a new 'interviews' tab for admins, which is VERY similar to the existing tickets tab. Below is what a player who is flagged as an interviewee will see when they join the server. They can do nothing but respond to the questionnaire or leave. image This is what an administrator sees after an interview is submitted, they will also see a corresponding message within their chatbox, and an age-old BWOINK when an interview is submitted. image The interviews tab, which is similar to the tickets menu. You can open the interview manager panel to view all active (including non-submitted) interviews, queued (submitted) interviews, and closed interviews. image FAQ: What happens if someone submits an interview when no admins are on? It's treated like adminhelps are, the message gets sent to TGS to be dispatched off to configured end-points (like Discord or IRC), and the user is notified that their interview was handled this way. Can you configure the questions? Yes, in config/ there is now a interviews.txt file in which the welcome message and the individual questions can be set and modified. Can this be turned on and off during a round? Yes, it can be toggled like the panic bunker. It requires the panic bunker to be raised in order to function. Can interviewees have further questions asked to them? Yes, if you admin-pm them, which is possible using regular means or a conveniently placed button on the interview UI, they will be able to respond to the message. Technical details To use the interview system you must have the panic bunker enabled, this is an additional setting for the panic bunker. It can be set through the PANIC_BUNKER_INTERVIEW setting in config.txt, or alternatively enabled in-game as prompted during the panic bunker toggling process. It also can be toggled on its own using a verb added for this purpose, Toggle PB Interviews found under the server tab. These new actions are included in the logging for the panic bunker. I have also added a reporting stat to the world topic status keyword, which now reports if the interview system is on using the keyword interviews. As mentioned above, for server operators, configure the questions and welcome message in config/interviews.txt. Note to maintainers and those with big brains I had to add a call to init_verbs on the stat panel window being ready because seemingly a race condition exists wherein the add_verb of the 'view my interview' verb doesn't cause a refresh of the tabs (and therefore doesn't show the 'Interview' tab) when running in dream daemon but running it directly from visual studio code properly shows the tab. Adding a init_verbs call directly after adding the verb didn't seem to help. A note for downstreams If you don't use the HTML stat panel (which may not be a bad thing) then you will have to do some conversion from the HTML stat panel stuff used here to the old style stat panels. It's pretty trivial, but just be aware of that. You can see how I used to use the old stat panels in my PR from the summer ball, here, which should be helpful. Why It's Good For The Game This allows for a softer version of the panic bunker which impedes the flow of malicious players while allowing genuine players a chance to enter a round to gain enough time to not be affected by the panic bunker's restrictions. Changelog 🆑 bobbahbrown add: Added the interview system, a 'soft' panic bunker which lets players who would normally be blocked from joining be interviewed by admins to be selectively allowed to play. /🆑
434 lines
16 KiB
Plaintext
434 lines
16 KiB
Plaintext
#define EXTERNALREPLYCOUNT 2
|
|
|
|
//allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm
|
|
/client/proc/cmd_admin_pm_context(mob/M in GLOB.mob_list)
|
|
set category = null
|
|
set name = "Admin PM Mob"
|
|
if(!holder)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM-Context: Only administrators may use this command.</span>",
|
|
confidential = TRUE)
|
|
return
|
|
if(!ismob(M) || !M.client)
|
|
return
|
|
cmd_admin_pm(M.client,null)
|
|
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin PM Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
|
|
|
//shows a list of clients we could send PMs to, then forwards our choice to cmd_admin_pm
|
|
/client/proc/cmd_admin_pm_panel()
|
|
set category = "Admin"
|
|
set name = "Admin PM"
|
|
if(!holder)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM-Panel: Only administrators may use this command.</span>",
|
|
confidential = TRUE)
|
|
return
|
|
var/list/client/targets[0]
|
|
for(var/client/T)
|
|
if(T.mob)
|
|
if(isnewplayer(T.mob))
|
|
targets["(New Player) - [T]"] = T
|
|
else if(isobserver(T.mob))
|
|
targets["[T.mob.name](Ghost) - [T]"] = T
|
|
else
|
|
targets["[T.mob.real_name](as [T.mob.name]) - [T]"] = T
|
|
else
|
|
targets["(No Mob) - [T]"] = T
|
|
var/target = input(src,"To whom shall we send a message?","Admin PM",null) as null|anything in sortList(targets)
|
|
cmd_admin_pm(targets[target],null)
|
|
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin PM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
|
|
|
/client/proc/cmd_ahelp_reply(whom)
|
|
if(prefs.muted & MUTE_ADMINHELP)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>",
|
|
confidential = TRUE)
|
|
return
|
|
var/client/C
|
|
if(istext(whom))
|
|
if(whom[1] == "@")
|
|
whom = findStealthKey(whom)
|
|
C = GLOB.directory[whom]
|
|
else if(istype(whom, /client))
|
|
C = whom
|
|
if(!C)
|
|
if(holder)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM: Client not found.</span>",
|
|
confidential = TRUE)
|
|
return
|
|
|
|
var/datum/admin_help/AH = C.current_ticket
|
|
|
|
if(AH)
|
|
message_admins("[key_name_admin(src)] has started replying to [key_name_admin(C, 0, 0)]'s admin help.")
|
|
var/msg = input(src,"Message:", "Private message to [C.holder?.fakekey ? "an Administrator" : key_name(C, 0, 0)].") as message|null
|
|
if (!msg)
|
|
message_admins("[key_name_admin(src)] has cancelled their reply to [key_name_admin(C, 0, 0)]'s admin help.")
|
|
return
|
|
if(!C) //We lost the client during input, disconnected or relogged.
|
|
if(GLOB.directory[AH.initiator_ckey]) // Client has reconnected, lets try to recover
|
|
whom = GLOB.directory[AH.initiator_ckey]
|
|
else
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM: Client not found.</span>",
|
|
confidential = TRUE)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'><b>Message not sent:</b></span><br>[msg]",
|
|
confidential = TRUE)
|
|
AH.AddInteraction("<b>No client found, message not sent:</b><br>[msg]")
|
|
return
|
|
cmd_admin_pm(whom, msg)
|
|
|
|
//takes input from cmd_admin_pm_context, cmd_admin_pm_panel or /client/Topic and sends them a PM.
|
|
//Fetching a message if needed. src is the sender and C is the target client
|
|
/client/proc/cmd_admin_pm(whom, msg)
|
|
if(prefs.muted & MUTE_ADMINHELP)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>",
|
|
confidential = TRUE)
|
|
return
|
|
|
|
if(!holder && !current_ticket) //no ticket? https://www.youtube.com/watch?v=iHSPf6x1Fdo
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>You can no longer reply to this ticket, please open another one by using the Adminhelp verb if need be.</span>",
|
|
confidential = TRUE)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='notice'>Message: [msg]</span>",
|
|
confidential = TRUE)
|
|
return
|
|
|
|
var/client/recipient
|
|
var/recipient_ckey // Stored in case client is deleted between this and after the message is input
|
|
var/datum/admin_help/recipient_ticket // Stored in case client is deleted between this and after the message is input
|
|
var/external = 0
|
|
if(istext(whom))
|
|
if(whom[1] == "@")
|
|
whom = findStealthKey(whom)
|
|
if(whom == "IRCKEY")
|
|
external = 1
|
|
else
|
|
recipient = GLOB.directory[whom]
|
|
else if(istype(whom, /client))
|
|
recipient = whom
|
|
|
|
if(!recipient)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM: Client not found.</span>",
|
|
confidential = TRUE)
|
|
return
|
|
|
|
recipient_ckey = recipient.ckey
|
|
recipient_ticket = recipient.current_ticket
|
|
|
|
if(external)
|
|
if(!externalreplyamount) //to prevent people from spamming irc/discord
|
|
return
|
|
if(!msg)
|
|
msg = input(src,"Message:", "Private message to Administrator") as message|null
|
|
|
|
if(!msg)
|
|
return
|
|
if(holder)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Use the admin IRC/Discord channel, nerd.</span>",
|
|
confidential = TRUE)
|
|
return
|
|
|
|
|
|
else
|
|
//get message text, limit it's length.and clean/escape html
|
|
if(!msg)
|
|
msg = input(src,"Message:", "Private message to [recipient.holder?.fakekey ? "an Administrator" : key_name(recipient, 0, 0)].") as message|null
|
|
msg = trim(msg)
|
|
if(!msg)
|
|
return
|
|
|
|
if(!recipient)
|
|
if(GLOB.directory[recipient_ckey]) // Client has reconnected, lets try to recover
|
|
recipient = GLOB.directory[recipient_ckey]
|
|
else
|
|
if(holder)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM: Client not found.</span>",
|
|
confidential = TRUE)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'><b>Message not sent:</b></span><br>[msg]",
|
|
confidential = TRUE)
|
|
if(recipient_ticket)
|
|
recipient_ticket.AddInteraction("<b>No client found, message not sent:</b><br>[msg]")
|
|
return
|
|
else
|
|
current_ticket.MessageNoRecipient(msg)
|
|
return
|
|
|
|
|
|
if(prefs.muted & MUTE_ADMINHELP)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>",
|
|
confidential = TRUE)
|
|
return
|
|
|
|
if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
|
|
return
|
|
|
|
//clean the message if it's not sent by a high-rank admin
|
|
if(!check_rights(R_SERVER|R_DEBUG,0)||external)//no sending html to the poor bots
|
|
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
|
|
if(!msg)
|
|
return
|
|
|
|
var/rawmsg = msg
|
|
|
|
if(holder)
|
|
msg = emoji_parse(msg)
|
|
|
|
var/keywordparsedmsg = keywords_lookup(msg)
|
|
|
|
if(external)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='notice'>PM to-<b>Admins</b>: <span class='linkify'>[rawmsg]</span></span>",
|
|
confidential = TRUE)
|
|
var/datum/admin_help/AH = admin_ticket_log(src, "<font color='red'>Reply PM from-<b>[key_name(src, TRUE, TRUE)]</b> to <i>External</i>: [keywordparsedmsg]</font>")
|
|
externalreplyamount--
|
|
send2adminchat("[AH ? "#[AH.id] " : ""]Reply: [ckey]", rawmsg)
|
|
else
|
|
var/badmin = FALSE //Lets figure out if an admin is getting bwoinked.
|
|
if(holder && recipient.holder && !current_ticket) //Both are admins, and this is not a reply to our own ticket.
|
|
badmin = TRUE
|
|
if(recipient.holder && !badmin)
|
|
if(holder)
|
|
to_chat(recipient,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Admin PM from-<b>[key_name(src, recipient, 1)]</b>: <span class='linkify'>[keywordparsedmsg]</span></span>",
|
|
confidential = TRUE)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='notice'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: <span class='linkify'>[keywordparsedmsg]</span></span>",
|
|
confidential = TRUE)
|
|
//omg this is dumb, just fill in both their tickets
|
|
var/interaction_message = "<font color='purple'>PM from-<b>[key_name(src, recipient, 1)]</b> to-<b>[key_name(recipient, src, 1)]</b>: [keywordparsedmsg]</font>"
|
|
admin_ticket_log(src, interaction_message)
|
|
if(recipient != src) //reeee
|
|
admin_ticket_log(recipient, interaction_message)
|
|
SSblackbox.LogAhelp(current_ticket.id, "Reply", msg, recipient.ckey, src.ckey)
|
|
else //recipient is an admin but sender is not
|
|
var/replymsg = "Reply PM from-<b>[key_name(src, recipient, 1)]</b>: <span class='linkify'>[keywordparsedmsg]</span>"
|
|
admin_ticket_log(src, "<font color='red'>[replymsg]</font>")
|
|
to_chat(recipient,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>[replymsg]</span>",
|
|
confidential = TRUE)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='notice'>PM to-<b>Admins</b>: <span class='linkify'>[msg]</span></span>",
|
|
confidential = TRUE)
|
|
SSblackbox.LogAhelp(current_ticket.id, "Reply", msg, recipient.ckey, src.ckey)
|
|
|
|
//play the receiving admin the adminhelp sound (if they have them enabled)
|
|
if(recipient.prefs.toggles & SOUND_ADMINHELP)
|
|
SEND_SOUND(recipient, sound('sound/effects/adminhelp.ogg'))
|
|
|
|
else
|
|
if(holder) //sender is an admin but recipient is not. Do BIG RED TEXT
|
|
var/already_logged = FALSE
|
|
if(!recipient.current_ticket)
|
|
new /datum/admin_help(msg, recipient, TRUE)
|
|
already_logged = TRUE
|
|
SSblackbox.LogAhelp(recipient.current_ticket.id, "Ticket Opened", msg, recipient.ckey, src.ckey)
|
|
|
|
to_chat(recipient,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<font color='red' size='4'><b>-- Administrator private message --</b></font>",
|
|
confidential = TRUE)
|
|
to_chat(recipient,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='adminsay'>Admin PM from-<b>[key_name(src, recipient, 0)]</b>: <span class='linkify'>[msg]</span></span>",
|
|
confidential = TRUE)
|
|
to_chat(recipient,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='adminsay'><i>Click on the administrator's name to reply.</i></span>",
|
|
confidential = TRUE)
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='notice'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: <span class='linkify'>[msg]</span></span>",
|
|
confidential = TRUE)
|
|
|
|
admin_ticket_log(recipient, "<font color='purple'>PM From [key_name_admin(src)]: [keywordparsedmsg]</font>")
|
|
|
|
if(!already_logged) //Reply to an existing ticket
|
|
SSblackbox.LogAhelp(recipient.current_ticket.id, "Reply", msg, recipient.ckey, src.ckey)
|
|
|
|
//always play non-admin recipients the adminhelp sound
|
|
SEND_SOUND(recipient, sound('sound/effects/adminhelp.ogg'))
|
|
|
|
//AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn
|
|
if(CONFIG_GET(flag/popup_admin_pm))
|
|
INVOKE_ASYNC(src, .proc/popup_admin_pm, recipient, msg)
|
|
|
|
else //neither are admins
|
|
to_chat(src,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='danger'>Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.</span>",
|
|
confidential = TRUE)
|
|
return
|
|
|
|
if(external)
|
|
log_admin_private("PM: [key_name(src)]->External: [rawmsg]")
|
|
for(var/client/X in GLOB.admins)
|
|
to_chat(X,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='notice'><B>PM: [key_name(src, X, 0)]->External:</B> [keywordparsedmsg]</span>",
|
|
confidential = TRUE)
|
|
else
|
|
window_flash(recipient, ignorepref = TRUE)
|
|
log_admin_private("PM: [key_name(src)]->[key_name(recipient)]: [rawmsg]")
|
|
//we don't use message_admins here because the sender/receiver might get it too
|
|
for(var/client/X in GLOB.admins)
|
|
if(X.key!=key && X.key!=recipient.key) //check client/X is an admin and isn't the sender or recipient
|
|
to_chat(X,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='notice'><B>PM: [key_name(src, X, 0)]->[key_name(recipient, X, 0)]:</B> [keywordparsedmsg]</span>" ,
|
|
confidential = TRUE)
|
|
|
|
/client/proc/popup_admin_pm(client/recipient, msg)
|
|
var/sender = src
|
|
var/sendername = key
|
|
var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as message|null //show message and await a reply
|
|
if(recipient && reply)
|
|
if(sender)
|
|
recipient.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them
|
|
else
|
|
adminhelp(reply) //sender has left, adminhelp instead
|
|
|
|
#define TGS_AHELP_USAGE "Usage: ticket <close|resolve|icissue|reject|reopen \[ticket #\]|list>"
|
|
/proc/TgsPm(target,msg,sender)
|
|
target = ckey(target)
|
|
var/client/C = GLOB.directory[target]
|
|
|
|
var/datum/admin_help/ticket = C ? C.current_ticket : GLOB.ahelp_tickets.CKey2ActiveTicket(target)
|
|
var/compliant_msg = trim(lowertext(msg))
|
|
var/tgs_tagged = "[sender](TGS/External)"
|
|
var/list/splits = splittext(compliant_msg, " ")
|
|
if(splits.len && splits[1] == "ticket")
|
|
if(splits.len < 2)
|
|
return TGS_AHELP_USAGE
|
|
switch(splits[2])
|
|
if("close")
|
|
if(ticket)
|
|
ticket.Close(tgs_tagged)
|
|
return "Ticket #[ticket.id] successfully closed"
|
|
if("resolve")
|
|
if(ticket)
|
|
ticket.Resolve(tgs_tagged)
|
|
return "Ticket #[ticket.id] successfully resolved"
|
|
if("icissue")
|
|
if(ticket)
|
|
ticket.ICIssue(tgs_tagged)
|
|
return "Ticket #[ticket.id] successfully marked as IC issue"
|
|
if("reject")
|
|
if(ticket)
|
|
ticket.Reject(tgs_tagged)
|
|
return "Ticket #[ticket.id] successfully rejected"
|
|
if("reopen")
|
|
if(ticket)
|
|
return "Error: [target] already has ticket #[ticket.id] open"
|
|
var/fail = splits.len < 3 ? null : -1
|
|
if(!isnull(fail))
|
|
fail = text2num(splits[3])
|
|
if(isnull(fail))
|
|
return "Error: No/Invalid ticket id specified. [TGS_AHELP_USAGE]"
|
|
var/datum/admin_help/AH = GLOB.ahelp_tickets.TicketByID(fail)
|
|
if(!AH)
|
|
return "Error: Ticket #[fail] not found"
|
|
if(AH.initiator_ckey != target)
|
|
return "Error: Ticket #[fail] belongs to [AH.initiator_ckey]"
|
|
AH.Reopen()
|
|
return "Ticket #[ticket.id] successfully reopened"
|
|
if("list")
|
|
var/list/tickets = GLOB.ahelp_tickets.TicketsByCKey(target)
|
|
if(!tickets.len)
|
|
return "None"
|
|
. = ""
|
|
for(var/I in tickets)
|
|
var/datum/admin_help/AH = I
|
|
if(.)
|
|
. += ", "
|
|
if(AH == ticket)
|
|
. += "Active: "
|
|
. += "#[AH.id]"
|
|
return
|
|
else
|
|
return TGS_AHELP_USAGE
|
|
return "Error: Ticket could not be found"
|
|
|
|
var/static/stealthkey
|
|
var/adminname = CONFIG_GET(flag/show_irc_name) ? tgs_tagged : "Administrator"
|
|
|
|
if(!C)
|
|
return "Error: No client"
|
|
|
|
if(!stealthkey)
|
|
stealthkey = GenTgsStealthKey()
|
|
|
|
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
|
|
if(!msg)
|
|
return "Error: No message"
|
|
|
|
message_admins("External message from [sender] to [key_name_admin(C)] : [msg]")
|
|
log_admin_private("External PM: [sender] -> [key_name(C)] : [msg]")
|
|
msg = emoji_parse(msg)
|
|
|
|
to_chat(C,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<font color='red' size='4'><b>-- Administrator private message --</b></font>",
|
|
confidential = TRUE)
|
|
to_chat(C,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='adminsay'>Admin PM from-<b><a href='?priv_msg=[stealthkey]'>[adminname]</A></b>: [msg]</span>",
|
|
confidential = TRUE)
|
|
to_chat(C,
|
|
type = MESSAGE_TYPE_ADMINPM,
|
|
html = "<span class='adminsay'><i>Click on the administrator's name to reply.</i></span>",
|
|
confidential = TRUE)
|
|
|
|
admin_ticket_log(C, "<font color='purple'>PM From [tgs_tagged]: [msg]</font>")
|
|
|
|
window_flash(C, ignorepref = TRUE)
|
|
//always play non-admin recipients the adminhelp sound
|
|
SEND_SOUND(C, 'sound/effects/adminhelp.ogg')
|
|
|
|
C.externalreplyamount = EXTERNALREPLYCOUNT
|
|
|
|
return "Message Successful"
|
|
|
|
/proc/GenTgsStealthKey()
|
|
var/num = (rand(0,1000))
|
|
var/i = 0
|
|
while(i == 0)
|
|
i = 1
|
|
for(var/P in GLOB.stealthminID)
|
|
if(num == GLOB.stealthminID[P])
|
|
num++
|
|
i = 0
|
|
var/stealth = "@[num2text(num)]"
|
|
GLOB.stealthminID["IRCKEY"] = stealth
|
|
return stealth
|
|
|
|
#undef EXTERNALREPLYCOUNT
|