diff --git a/check_regex.yaml b/check_regex.yaml index 396cf9a20961..86faec7e1091 100644 --- a/check_regex.yaml +++ b/check_regex.yaml @@ -38,7 +38,7 @@ standards: - exactly: [ - 292, + 291, "non-bitwise << uses", '(?" + message += "HEY! An admin is trying to talk to you!
Check your chat window, and click their name to respond!" + message += "" + + maptext = MAPTEXT(message) + last_update_time = world.time + +/// Tries to give the target an admin popup. +/// If it fails, will send the error to the passed admin. +/proc/give_admin_popup(client/target, client/admin, message) + log_admin("[key_name(admin)] sent an admin popup to [key_name(target)].") + + var/datum/admin_help/current_ticket = target.current_ticket + if (!current_ticket) + to_chat(admin, span_warning("[key_name(target)] had no active ahelp, aborting.")) + return + + admin.cmd_admin_pm(target, message) + target.AddComponent(/datum/component/admin_popup, current_ticket) diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm index 4f20564d8fe5..baa52e38c7da 100644 --- a/code/modules/admin/chat_commands.dm +++ b/code/modules/admin/chat_commands.dm @@ -66,7 +66,7 @@ all_params.Cut(1, 2) var/id = text2num(target) if(id != null) - var/datum/admin_help/AH = GLOB.ahelp_tickets.TicketByID(id) + var/datum/admin_help/AH = GLOB.ahelp_tickets.ticket_by_id(id) if(AH) target = AH.initiator_ckey else diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index b10a5a4feb03..bde0a7676fac 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -549,7 +549,7 @@ if(roles_to_ban[1] == "Server" && (!is_admin || (is_admin && applies_to_admins))) qdel(C) if(roles_to_ban[1] == "Server" && AH) - AH.Resolve() + AH.resolve() for(var/client/i in GLOB.clients - C) if(i.address == player_ip || i.computer_id == player_cid) build_ban_cache(i) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 056e5c168f03..012be5da1e51 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -29,12 +29,12 @@ var/ahelp_ref = href_list["ahelp"] var/datum/admin_help/AH = locate(ahelp_ref) if(AH) - AH.Action(href_list["ahelp_action"]) + AH.action(usr, href_list["ahelp_action"]) else to_chat(usr, "Ticket [ahelp_ref] has been deleted!", confidential = TRUE) else if(href_list["ahelp_tickets"]) - GLOB.ahelp_tickets.BrowseTickets(text2num(href_list["ahelp_tickets"])) + GLOB.ahelp_tickets.browse_tickets(text2num(href_list["ahelp_tickets"])) else if(href_list["stickyban"]) stickyban(href_list["stickyban"],href_list) @@ -1260,6 +1260,22 @@ message_admins("[key_name(H)] has their hands full, so they did not receive their [initial(cookiealt.name)], spawned by [key_name(src.owner)].") // WS - End + else if (href_list["adminpopup"]) + if (!check_rights(R_ADMIN)) + return + + var/message = input(owner, "As well as a popup, they'll also be sent a message to reply to. What do you want that to be?", "Message") as text|null + if (!message) + to_chat(owner, span_notice("Popup cancelled.")) + return + + var/client/target = locate(href_list["adminpopup"]) + if (!istype(target)) + to_chat(owner, span_notice("The mob doesn't exist anymore!")) + return + + give_admin_popup(target, owner, message) + else if(href_list["adminsmite"]) if(!check_rights(R_ADMIN|R_FUN)) return diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 267dde41ea9c..1b9b41d773b1 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -26,7 +26,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) QDEL_NULL(rstatclick) return ..() -/datum/admin_help_tickets/proc/TicketByID(id) +/datum/admin_help_tickets/proc/ticket_by_id(id) var/list/lists = list(active_tickets, closed_tickets, resolved_tickets) for(var/I in lists) for(var/J in I) @@ -34,7 +34,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(AH.id == id) return J -/datum/admin_help_tickets/proc/TicketsByCKey(ckey) +/datum/admin_help_tickets/proc/tickets_by_ckey(ckey) . = list() var/list/lists = list(active_tickets, closed_tickets, resolved_tickets) for(var/I in lists) @@ -44,7 +44,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) . += AH //private -/datum/admin_help_tickets/proc/ListInsert(datum/admin_help/new_ticket) +/datum/admin_help_tickets/proc/list_insert(datum/admin_help/new_ticket) var/list/ticket_list switch(new_ticket.state) if(AHELP_ACTIVE) @@ -65,7 +65,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) ticket_list += new_ticket //opens the ticket listings for one of the 3 states -/datum/admin_help_tickets/proc/BrowseTickets(state) +/datum/admin_help_tickets/proc/browse_tickets(state) var/list/l2b var/title switch(state) @@ -94,8 +94,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) SHOULD_NOT_SLEEP(TRUE) var/list/L = list() var/num_disconnected = 0 - L[++L.len] = list("Active Tickets:", "[astatclick.update("[active_tickets.len]")]", null, REF(astatclick)) - astatclick.update("[active_tickets.len]") + L[++L.len] = list("Active Tickets:", "[astatclick.update("[length(active_tickets)]")]", null, REF(astatclick)) + astatclick.update("[length(active_tickets)]") for(var/I in active_tickets) var/datum/admin_help/AH = I if(AH.initiator) @@ -107,34 +107,35 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) message_admins("Ticket #[AH.id] had a null statclick, this message will only be shown once.") AH.error_screamed = TRUE - L[++L.len] = list("#[AH.id]. [AH.initiator_key_name]:", "[AH.statclick.update()]", REF(AH)) + L[++L.len] = list("#[AH.id]. [AH.initiator_key_name] (Claimed by [AH.claimed_by || "nobody"]):", "[AH.statclick.update()]", REF(AH)) else ++num_disconnected + if(num_disconnected) L[++L.len] = list("Disconnected:", "[astatclick.update("[num_disconnected]")]", null, REF(astatclick)) - L[++L.len] = list("Closed Tickets:", "[cstatclick.update("[closed_tickets.len]")]", null, REF(cstatclick)) - L[++L.len] = list("Resolved Tickets:", "[rstatclick.update("[resolved_tickets.len]")]", null, REF(rstatclick)) + L[++L.len] = list("Closed Tickets:", "[cstatclick.update("[length(closed_tickets)]")]", null, REF(cstatclick)) + L[++L.len] = list("Resolved Tickets:", "[rstatclick.update("[length(resolved_tickets)]")]", null, REF(rstatclick)) L[++L.len] = list("Statclick Errors:", "[total_statclick_errors]", null, null) return L //Reassociate still open ticket if one exists -/datum/admin_help_tickets/proc/ClientLogin(client/C) - C.current_ticket = CKey2ActiveTicket(C.ckey) +/datum/admin_help_tickets/proc/client_login(client/C) + C.current_ticket = ckey2active_ticket(C.ckey) if(C.current_ticket) C.current_ticket.initiator = C - C.current_ticket.AddInteraction("Client reconnected.") - SSblackbox.LogAhelp(C.current_ticket.id, "Reconnected", "Client reconnected", C.ckey) + C.current_ticket.add_interaction("Client reconnected.") + SSblackbox.log_ahelp(C.current_ticket.id, "Reconnected", "Client reconnected", C.ckey) //Dissasociate ticket -/datum/admin_help_tickets/proc/ClientLogout(client/C) +/datum/admin_help_tickets/proc/client_logout(client/C) if(C.current_ticket) var/datum/admin_help/T = C.current_ticket - T.AddInteraction("Client disconnected.") - SSblackbox.LogAhelp(T.id, "Disconnected", "Client disconnected", C.ckey) + T.add_interaction("Client disconnected.") + SSblackbox.log_ahelp(T.id, "Disconnected", "Client disconnected", C.ckey) T.initiator = null //Get a ticket given a ckey -/datum/admin_help_tickets/proc/CKey2ActiveTicket(ckey) +/datum/admin_help_tickets/proc/ckey2active_ticket(ckey) for(var/I in active_tickets) var/datum/admin_help/AH = I if(AH.initiator_ckey == ckey) @@ -152,7 +153,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) ..() /obj/effect/statclick/ticket_list/Click() - GLOB.ahelp_tickets.BrowseTickets(current_state) + GLOB.ahelp_tickets.browse_tickets(current_state) //called by admin topic /obj/effect/statclick/ticket_list/proc/Action() @@ -173,9 +174,10 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) var/client/initiator //semi-misnomer, it's the person who ahelped/was bwoinked var/initiator_ckey var/initiator_key_name + var/claimed_by var/heard_by_no_admins = FALSE - var/list/_interactions //use AddInteraction() or, preferably, admin_ticket_log() + var/list/_interactions //use add_interaction() or, preferably, admin_ticket_log() var/obj/effect/statclick/ahelp/statclick var/error_screamed = FALSE @@ -202,20 +204,21 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) initiator_key_name = key_name(initiator, FALSE, TRUE) if(initiator.current_ticket) //This is a bug stack_trace("Multiple ahelp current_tickets") - initiator.current_ticket.AddInteraction("Ticket erroneously left open by code") - initiator.current_ticket.Close() + initiator.current_ticket.add_interaction("Ticket erroneously left open by code") + initiator.current_ticket.close() initiator.current_ticket = src - TimeoutVerb() + timeout_verb() statclick = new(null, src) _interactions = list() if(is_bwoink) - AddInteraction("[key_name_admin(usr)] PM'd [LinkedReplyName()]") - message_admins("Ticket [TicketHref("#[id]")] created") + add_interaction("[key_name_admin(usr)] PM'd [linked_reply_name()]") + message_admins("Ticket [ticket_href("#[id]")] created") + claimed_by = usr.key else - MessageNoRecipient(msg) + message_no_recipient(msg) SSredbot.send_discord_message("admin", "Ticket #[id] created by [usr.ckey] ([usr.real_name]): [name]", "ticket") @@ -228,60 +231,66 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) GLOB.ahelp_tickets.active_tickets += src /datum/admin_help/Destroy() - RemoveActive() + remove_active() + QDEL_NULL(statclick) GLOB.ahelp_tickets.closed_tickets -= src GLOB.ahelp_tickets.resolved_tickets -= src return ..() -/datum/admin_help/proc/AddInteraction(formatted_message) +/datum/admin_help/proc/add_interaction(formatted_message) if(heard_by_no_admins && usr && usr.ckey != initiator_ckey) heard_by_no_admins = FALSE send2tgs(initiator_ckey, "Ticket #[id]: Answered by [key_name(usr)]") _interactions += "[time_stamp()]: [formatted_message]" //Removes the ahelp verb and returns it after 2 minutes -/datum/admin_help/proc/TimeoutVerb() +/datum/admin_help/proc/timeout_verb() remove_verb(initiator, /client/verb/adminhelp) initiator.adminhelptimerid = addtimer(CALLBACK(initiator, /client/proc/giveadminhelpverb), 1200, TIMER_STOPPABLE) //2 minute cooldown of admin helps //private -/datum/admin_help/proc/FullMonty(ref_src) +/datum/admin_help/proc/full_monty(ref_src) if(!ref_src) ref_src = "[REF(src)]" . = ADMIN_FULLMONTY_NONAME(initiator.mob) if(state == AHELP_ACTIVE) - . += ClosureLinks(ref_src) + . += ticket_actions(ref_src) + + if (CONFIG_GET(flag/popup_admin_pm)) + . += " (POPUP)" //private -/datum/admin_help/proc/ClosureLinks(ref_src) +/datum/admin_help/proc/ticket_actions(ref_src) if(!ref_src) ref_src = "[REF(src)]" - . = " (REJT)" - . += " (IC)" - . += " (SKILL)" - . += " (CLOSE)" - . += " (RSLVE)" + . = "
" + . += " ([ticket_href("REJT", ref_src, "reject")])" + . += " ([ticket_href("IC", ref_src, "icissue")])" + . += " ([ticket_href("SKILL", ref_src, "skillissue")])" + . += " ([ticket_href("CLOSE", ref_src, "close")])" + . += " ([ticket_href("RSLVE", ref_src, "resolve")])" + . += " ([ticket_href("CLAIM", ref_src, "claim")])" //private -/datum/admin_help/proc/LinkedReplyName(ref_src) +/datum/admin_help/proc/linked_reply_name(ref_src) if(!ref_src) ref_src = "[REF(src)]" return "[initiator_key_name]" //private -/datum/admin_help/proc/TicketHref(msg, ref_src, action = "ticket") +/datum/admin_help/proc/ticket_href(msg, ref_src, action = "ticket") if(!ref_src) ref_src = "[REF(src)]" return "[msg]" //message from the initiator without a target, all admins will see this //won't bug irc/discord -/datum/admin_help/proc/MessageNoRecipient(msg) +/datum/admin_help/proc/message_no_recipient(msg) var/ref_src = "[REF(src)]" //Message to be sent to all admins - var/admin_msg = "Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]: [keywords_lookup(msg)]" + var/admin_msg = "Ticket [ticket_href("#[id]", ref_src)]: [linked_reply_name(ref_src)] [full_monty(ref_src)]: [keywords_lookup(msg)]" - AddInteraction("[LinkedReplyName(ref_src)]: [msg]") + add_interaction("[linked_reply_name(ref_src)]: [msg]") log_admin_private("Ticket #[id]: [key_name(initiator)]: [msg]") //send this msg to all admins @@ -299,19 +308,18 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) type = MESSAGE_TYPE_ADMINPM, html = "PM to-Admins: [msg]", confidential = TRUE) - SSblackbox.LogAhelp(id, "Ticket Opened", msg, null, initiator.ckey) + SSblackbox.log_ahelp(id, "Ticket Opened", msg, null, initiator.ckey) //Reopen a closed ticket -/datum/admin_help/proc/Reopen() +/datum/admin_help/proc/reopen() if(state == AHELP_ACTIVE) to_chat(usr, "This ticket is already open.", confidential = TRUE) return - if(GLOB.ahelp_tickets.CKey2ActiveTicket(initiator_ckey)) + if(GLOB.ahelp_tickets.ckey2active_ticket(initiator_ckey)) to_chat(usr, "This user already has an active ticket, cannot reopen this one.", confidential = TRUE) return - statclick = new(null, src) GLOB.ahelp_tickets.active_tickets += src GLOB.ahelp_tickets.closed_tickets -= src GLOB.ahelp_tickets.resolved_tickets -= src @@ -325,61 +333,91 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(initiator) initiator.current_ticket = src - AddInteraction("Reopened by [key_name_admin(usr)]") - var/msg = "Ticket [TicketHref("#[id]")] reopened by [key_name_admin(usr)]." + add_interaction("Reopened by [key_name_admin(usr)]") + var/msg = "Ticket [ticket_href("#[id]")] reopened by [key_name_admin(usr)]." message_admins(msg) log_admin_private(msg) - SSblackbox.LogAhelp(id, "Reopened", "Reopened by [usr.key]", usr.ckey) + SSblackbox.log_ahelp(id, "Reopened", "Reopened by [usr.key]", usr.ckey) SSblackbox.record_feedback("tally", "ahelp_stats", 1, "reopened") - TicketPanel() //can only be done from here, so refresh it + ticket_panel() //can only be done from here, so refresh it //private -/datum/admin_help/proc/RemoveActive() +/datum/admin_help/proc/remove_active() if(state != AHELP_ACTIVE) stack_trace("Attempt to remove non-active ticket") return closed_at = world.time - QDEL_NULL(statclick) GLOB.ahelp_tickets.active_tickets -= src if(initiator && initiator.current_ticket == src) initiator.current_ticket = null + SEND_SIGNAL(src, COMSIG_ADMIN_HELP_MADE_INACTIVE) + +/datum/admin_help/proc/claim(key_name = key_name_admin(usr)) + if(state != AHELP_ACTIVE) + return FALSE + if(claimed_by && claimed_by != usr.key && alert(usr, "Ticket #[id] already claimed by [claimed_by]. Override?", "Adminhelp", "Yes", "No") != "Yes") + return FALSE + if(claimed_by == usr.key) + return TRUE + add_interaction(span_grey("Claimed by [key_name].")) + to_chat(initiator, span_adminhelp("Your ticket has been claimed by an admin. Expect a response shortly."), confidential = TRUE) + claimed_by = usr.key + SSblackbox.record_feedback("tally", "ahelp_stats", 1, "claimed") + var/msg = "Ticket [ticket_href("#[id]")] claimed by [key_name]." + message_admins(msg) + SSblackbox.log_ahelp(id, "Claimed", "Claimed by [usr.key]", null, usr.ckey) + log_admin_private(msg) + return TRUE + +/datum/admin_help/proc/unclaim(key_name = key_name_admin(usr)) + if(state != AHELP_ACTIVE) + return + if(claimed_by != usr.key) + return + add_interaction(span_grey("Unclaimed by [key_name].")) + claimed_by = null + SSblackbox.record_feedback("tally", "ahelp_stats", 1, "unclaimed") + var/msg = "Ticket [ticket_href("#[id]")] unclaimed by [key_name]." + message_admins(msg) + SSblackbox.log_ahelp(id, "Unclaimed", "Unclaimed by [usr.key]", null, usr.ckey) + log_admin_private(msg) //Mark open ticket as closed/meme -/datum/admin_help/proc/Close(key_name = key_name_admin(usr), silent = FALSE) +/datum/admin_help/proc/close(key_name = key_name_admin(usr), silent = FALSE) if(state != AHELP_ACTIVE) return - RemoveActive() + remove_active() state = AHELP_CLOSED - GLOB.ahelp_tickets.ListInsert(src) - AddInteraction("Closed by [key_name].") + GLOB.ahelp_tickets.list_insert(src) + add_interaction("Closed by [key_name].") if(!silent) SSblackbox.record_feedback("tally", "ahelp_stats", 1, "closed") - var/msg = "Ticket [TicketHref("#[id]")] closed by [key_name]." + var/msg = "Ticket [ticket_href("#[id]")] closed by [key_name]." message_admins(msg) - SSblackbox.LogAhelp(id, "Closed", "Closed by [usr.key]", null, usr.ckey) + SSblackbox.log_ahelp(id, "Closed", "Closed by [usr.key]", null, usr.ckey) log_admin_private(msg) //Mark open ticket as resolved/legitimate, returns ahelp verb -/datum/admin_help/proc/Resolve(key_name = key_name_admin(usr), silent = FALSE) +/datum/admin_help/proc/resolve(key_name = key_name_admin(usr), silent = FALSE) if(state != AHELP_ACTIVE) return - RemoveActive() + remove_active() state = AHELP_RESOLVED - GLOB.ahelp_tickets.ListInsert(src) + GLOB.ahelp_tickets.list_insert(src) addtimer(CALLBACK(initiator, /client/proc/giveadminhelpverb), 50) - AddInteraction("Resolved by [key_name].") + add_interaction("Resolved by [key_name].") to_chat(initiator, "Your ticket has been resolved by an admin. The Adminhelp verb will be returned to you shortly.", confidential = TRUE) if(!silent) SSblackbox.record_feedback("tally", "ahelp_stats", 1, "resolved") - var/msg = "Ticket [TicketHref("#[id]")] resolved by [key_name]" + var/msg = "Ticket [ticket_href("#[id]")] resolved by [key_name]" message_admins(msg) - SSblackbox.LogAhelp(id, "Resolved", "Resolved by [usr.key]", null, usr.ckey) + SSblackbox.log_ahelp(id, "Resolved", "Resolved by [usr.key]", null, usr.ckey) log_admin_private(msg) //Close and return ahelp verb, use if ticket is incoherent -/datum/admin_help/proc/Reject(key_name = key_name_admin(usr)) +/datum/admin_help/proc/reject(key_name = key_name_admin(usr)) if(state != AHELP_ACTIVE) return @@ -393,15 +431,15 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) to_chat(initiator, "Please try to be calm, clear, and descriptive in admin helps, do not assume the admin has seen any related events, and clearly state the names of anybody you are reporting.", confidential = TRUE) SSblackbox.record_feedback("tally", "ahelp_stats", 1, "rejected") - var/msg = "Ticket [TicketHref("#[id]")] rejected by [key_name]" + var/msg = "Ticket [ticket_href("#[id]")] rejected by [key_name]" message_admins(msg) log_admin_private(msg) - AddInteraction("Rejected by [key_name].") - SSblackbox.LogAhelp(id, "Rejected", "Rejected by [usr.key]", null, usr.ckey) - Close(silent = TRUE) + add_interaction("Rejected by [key_name].") + SSblackbox.log_ahelp(id, "Rejected", "Rejected by [usr.key]", null, usr.ckey) + close(silent = TRUE) //Resolve ticket with IC Issue message -/datum/admin_help/proc/ICIssue(key_name = key_name_admin(usr)) +/datum/admin_help/proc/ic_issue(key_name = key_name_admin(usr)) if(state != AHELP_ACTIVE) return @@ -412,15 +450,15 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) to_chat(initiator, msg, confidential = TRUE) SSblackbox.record_feedback("tally", "ahelp_stats", 1, "IC") - msg = "Ticket [TicketHref("#[id]")] marked as IC by [key_name]" + msg = "Ticket [ticket_href("#[id]")] marked as IC by [key_name]" message_admins(msg) log_admin_private(msg) - AddInteraction("Marked as IC issue by [key_name]") - SSblackbox.LogAhelp(id, "IC Issue", "Marked as IC issue by [usr.key]", null, usr.ckey) - Resolve(silent = TRUE) + add_interaction("Marked as IC issue by [key_name]") + SSblackbox.log_ahelp(id, "IC Issue", "Marked as IC issue by [usr.key]", null, usr.ckey) + resolve(silent = TRUE) //Resolve ticket and inform user that they have a skill issue -/datum/admin_help/proc/SkillIssue(key_name = key_name_admin(usr)) +/datum/admin_help/proc/skill_issue(key_name = key_name_admin(usr)) if(state != AHELP_ACTIVE) return @@ -431,18 +469,18 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) to_chat(initiator, msg, confidential = TRUE) SSblackbox.record_feedback("tally", "ahelp_stats", 1, "Skill") - msg = "Ticket [TicketHref("#[id]")] marked as skill issue by [key_name]" + msg = "Ticket [ticket_href("#[id]")] marked as skill issue by [key_name]" message_admins(msg) log_admin_private(msg) - AddInteraction("Marked as skill issue by [key_name]") - SSblackbox.LogAhelp(id, "Skill Issue", "Marked as skill issue by [usr.key]", null, usr.ckey) - Resolve(silent = TRUE) + add_interaction("Marked as skill issue by [key_name]") + SSblackbox.log_ahelp(id, "Skill Issue", "Marked as skill issue by [usr.key]", null, usr.ckey) + resolve(silent = TRUE) //Show the ticket panel -/datum/admin_help/proc/TicketPanel() - var/list/dat = list("Ticket #[id]") +/datum/admin_help/proc/ticket_panel() + var/list/dat = list() var/ref_src = "[REF(src)]" - dat += "

Admin Help Ticket #[id]: [LinkedReplyName(ref_src)]

" + dat += "

Admin Help Ticket #[id]: [linked_reply_name(ref_src)] (Claimed by [claimed_by || "nobody"])

" dat += "State: " switch(state) if(AHELP_ACTIVE) @@ -453,55 +491,64 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) dat += "CLOSED" else dat += "UNKNOWN" - dat += "[FOURSPACES][TicketHref("Refresh", ref_src)][FOURSPACES][TicketHref("Re-Title", ref_src, "retitle")]" + dat += "[FOURSPACES][ticket_href("Refresh", ref_src)][FOURSPACES][ticket_href("Re-Title", ref_src, "retitle")]" if(state != AHELP_ACTIVE) - dat += "[FOURSPACES][TicketHref("Reopen", ref_src, "reopen")]" + dat += "[FOURSPACES][ticket_href("Reopen", ref_src, "reopen")]" dat += "

Opened at: [gameTimestamp(wtime = opened_at)] (Approx [DisplayTimeText(world.time - opened_at)] ago)" if(closed_at) dat += "
Closed at: [gameTimestamp(wtime = closed_at)] (Approx [DisplayTimeText(world.time - closed_at)] ago)" dat += "

" if(initiator) - dat += "Actions: [FullMonty(ref_src)]
" + dat += "Actions:
[full_monty(ref_src)]
" else - dat += "DISCONNECTED[FOURSPACES][ClosureLinks(ref_src)]
" + dat += "DISCONNECTED[ticket_actions(ref_src)]
" dat += "
Log:

" for(var/I in _interactions) dat += "[I]
" - usr << browse(dat.Join(), "window=ahelp[id];size=620x480") + var/datum/browser/popup = new(usr, "ahelp[id]", "Ticket #[id]", 620, 480) + popup.set_content(dat.Join()) + popup.open() -/datum/admin_help/proc/Retitle() +/datum/admin_help/proc/retitle() var/new_title = input(usr, "Enter a title for the ticket", "Rename Ticket", name) as text|null if(new_title) name = new_title //not saying the original name cause it could be a long ass message - var/msg = "Ticket [TicketHref("#[id]")] titled [name] by [key_name_admin(usr)]" + var/msg = "Ticket [ticket_href("#[id]")] titled [name] by [key_name_admin(usr)]" message_admins(msg) log_admin_private(msg) - TicketPanel() //we have to be here to do this + ticket_panel() //we have to be here to do this //Forwarded action from admin/Topic -/datum/admin_help/proc/Action(action) +/datum/admin_help/proc/action(mob/user, action) testing("Ahelp action: [action]") switch(action) + if("claim") + if(user.key == claimed_by) + unclaim() + return + claim() if("ticket") - TicketPanel() + ticket_panel() if("retitle") - Retitle() + retitle() if("reject") - Reject() + reject() if("reply") - usr.client.cmd_ahelp_reply(initiator) + if(!claim()) + return + user.client.cmd_ahelp_reply(initiator) if("icissue") - ICIssue() + ic_issue() if("skillissue") - SkillIssue() + skill_issue() if("close") - Close() + close() if("resolve") - Resolve() + resolve() if("reopen") - Reopen() + reopen() // // TICKET STATCLICK @@ -518,7 +565,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) return ..(ahelp_datum.name) /obj/effect/statclick/ahelp/Click() - ahelp_datum.TicketPanel() + ahelp_datum.ticket_panel() /obj/effect/statclick/ahelp/Destroy() ahelp_datum = null @@ -562,14 +609,14 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(current_ticket) if(alert(usr, "You already have a ticket open. Is this for the same issue?",,"Yes","No") != "No") if(current_ticket) - current_ticket.MessageNoRecipient(msg) - current_ticket.TimeoutVerb() + current_ticket.message_no_recipient(msg) + current_ticket.timeout_verb() return else to_chat(usr, "Ticket not found, creating new one...", confidential = TRUE) else - current_ticket.AddInteraction("[key_name_admin(usr)] opened a new ticket.") - current_ticket.Close() + current_ticket.add_interaction("[key_name_admin(usr)] opened a new ticket.") + current_ticket.close() //Extremely simple system of suggesting mentorhelp instead of adminhelp var/msg_lower = lowertext(msg) @@ -594,12 +641,12 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) else C = what if(istype(C) && C.current_ticket) - C.current_ticket.AddInteraction(message) + C.current_ticket.add_interaction(message) return C.current_ticket if(istext(what)) //ckey - var/datum/admin_help/AH = GLOB.ahelp_tickets.CKey2ActiveTicket(what) + var/datum/admin_help/AH = GLOB.ahelp_tickets.ckey2active_ticket(what) if(AH) - AH.AddInteraction(message) + AH.add_interaction(message) return AH // @@ -638,8 +685,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) /proc/send2tgs(msg,msg2) - msg = replacetext(replacetext(msg, "\proper", ""), "\improper", "") - msg2 = replacetext(replacetext(msg2, "\proper", ""), "\improper", "") + msg = format_text(msg) + msg2 = format_text(msg2) world.TgsTargetedChatBroadcast("[msg] | [msg2]", TRUE) /** @@ -823,7 +870,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) if(!possible_ticket_id) continue - var/datum/admin_help/ahelp_check = GLOB.ahelp_tickets?.TicketByID(possible_ticket_id) + var/datum/admin_help/ahelp_check = GLOB.ahelp_tickets?.ticket_by_id(possible_ticket_id) if(!ahelp_check) continue diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index b4e5653b0076..d227d44e18b0 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -82,7 +82,7 @@ type = MESSAGE_TYPE_ADMINPM, html = "Message not sent:
[msg]", confidential = TRUE) - AH.AddInteraction("No client found, message not sent:
[msg]") + AH.add_interaction("No client found, message not sent:
[msg]") return cmd_admin_pm(whom, msg) @@ -169,10 +169,10 @@ html = "Message not sent:
[msg]", confidential = TRUE) if(recipient_ticket) - recipient_ticket.AddInteraction("No client found, message not sent:
[msg]") + recipient_ticket.add_interaction("No client found, message not sent:
[msg]") return else - current_ticket.MessageNoRecipient(msg) + current_ticket.message_no_recipient(msg) return @@ -212,6 +212,8 @@ 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) + SEND_SIGNAL(current_ticket, COMSIG_ADMIN_HELP_REPLIED) + if(holder) to_chat(recipient, type = MESSAGE_TYPE_ADMINPM, @@ -226,7 +228,7 @@ 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) + SSblackbox.log_ahelp(current_ticket.id, "Reply", msg, recipient.ckey, src.ckey) else //recipient is an admin but sender is not var/replymsg = "Reply PM from-[key_name(src, recipient, 1)]: [keywordparsedmsg]" admin_ticket_log(src, "[replymsg]") @@ -238,19 +240,18 @@ type = MESSAGE_TYPE_ADMINPM, html = "PM to-Admins: [msg]", confidential = TRUE) - SSblackbox.LogAhelp(current_ticket.id, "Reply", msg, recipient.ckey, src.ckey) + SSblackbox.log_ahelp(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) + SSblackbox.log_ahelp(recipient.current_ticket.id, "Ticket Opened", msg, recipient.ckey, src.ckey) to_chat(recipient, type = MESSAGE_TYPE_ADMINPM, @@ -272,21 +273,23 @@ admin_ticket_log(recipient, "PM From [key_name_admin(src)]: [keywordparsedmsg]") if(!already_logged) //Reply to an existing ticket - SSblackbox.LogAhelp(recipient.current_ticket.id, "Reply", msg, recipient.ckey, src.ckey) + SSblackbox.log_ahelp(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 = "Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.", - confidential = TRUE) - return + else //neither are admins + if(!current_ticket) + to_chat(src, + type = MESSAGE_TYPE_ADMINPM, + html = span_danger("Error: Admin-PM: Non-admin to non-admin PM communication is forbidden."), + confidential = TRUE) + to_chat(src, + type = MESSAGE_TYPE_ADMINPM, + html = "[span_danger("Message not sent:")]
[msg]", + confidential = TRUE) + return + current_ticket.message_no_recipient(msg) if(external) log_admin_private("PM: [key_name(src)]->External: [rawmsg]") @@ -306,22 +309,12 @@ html = "PM: [key_name(src, X, 0)]->[key_name(recipient, X, 0)]: [keywordparsedmsg]" , 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 " /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/datum/admin_help/ticket = C ? C.current_ticket : GLOB.ahelp_tickets.ckey2active_ticket(target) var/compliant_msg = trim(lowertext(msg)) var/tgs_tagged = "[sender](TGS/External)" var/list/splits = splittext(compliant_msg, " ") @@ -331,23 +324,23 @@ switch(splits[2]) if("close") if(ticket) - ticket.Close(tgs_tagged) + ticket.close(tgs_tagged) return "Ticket #[ticket.id] successfully closed" if("resolve") if(ticket) - ticket.Resolve(tgs_tagged) + ticket.resolve(tgs_tagged) return "Ticket #[ticket.id] successfully resolved" if("icissue") if(ticket) - ticket.ICIssue(tgs_tagged) + ticket.ic_issue(tgs_tagged) return "Ticket #[ticket.id] successfully marked as IC issue" if("skill") if(ticket) - ticket.SkillIssue(tgs_tagged) + ticket.skill_issue(tgs_tagged) return "Ticket #[ticket.id] successfully marked as skill issue" if("reject") if(ticket) - ticket.Reject(tgs_tagged) + ticket.reject(tgs_tagged) return "Ticket #[ticket.id] successfully rejected" if("reopen") if(ticket) @@ -357,15 +350,15 @@ 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) + var/datum/admin_help/AH = GLOB.ahelp_tickets.ticket_by_id(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() + AH.reopen() return "Ticket #[ticket.id] successfully reopened" if("list") - var/list/tickets = GLOB.ahelp_tickets.TicketsByCKey(target) + var/list/tickets = GLOB.ahelp_tickets.tickets_by_ckey(target) if(!tickets.len) return "None" . = "" diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 6b5e62e9681f..5c5553df2755 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -220,7 +220,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( // Instantiate tgui panel tgui_panel = new(src) - GLOB.ahelp_tickets.ClientLogin(src) + GLOB.ahelp_tickets.client_login(src) GLOB.interviews.client_login(src) var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins. //Admin Authorisation @@ -489,7 +489,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( GLOB.clients -= src GLOB.directory -= ckey log_access("Logout: [key_name(src)]") - GLOB.ahelp_tickets.ClientLogout(src) + GLOB.ahelp_tickets.client_logout(src) GLOB.interviews.client_logout(src) SSserver_maint.UpdateHubStatus() if(credits) diff --git a/config/config.txt b/config/config.txt index 0fe49324ec07..89dd495066eb 100644 --- a/config/config.txt +++ b/config/config.txt @@ -309,9 +309,9 @@ CHECK_RANDOMIZER ## Uncomment this to forbid admins from possessing the singularity. #FORBID_SINGULO_POSSESSION -## Uncomment to show a popup 'reply to' window to every non-admin that receives an adminPM. -## The intention is to make adminPMs more visible. (although I fnd popups annoying so this defaults to off) -#POPUP_ADMIN_PM +## Uncomment to give admins the ability to send a maptext popup to players. +## Only fires when an admin requests it, not every ahelp. +POPUP_ADMIN_PM ## Uncomment to allow special 'Easter-egg' events on special holidays such as seasonal holidays and stuff like 'Talk Like a Pirate Day' :3 YAARRR ALLOW_HOLIDAYS diff --git a/shiptest.dme b/shiptest.dme index c7c663be5a99..dfeb323f63c6 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -438,6 +438,7 @@ #include "code\datums\brain_damage\special.dm" #include "code\datums\brain_damage\split_personality.dm" #include "code\datums\components\_component.dm" +#include "code\datums\components\admin_popup.dm" #include "code\datums\components\anti_magic.dm" #include "code\datums\components\armor_plate.dm" #include "code\datums\components\art.dm"