mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-16 17:43:35 +01:00
Merge remote-tracking branch 'upstream/master' into lungsss
# Conflicts: # code/modules/mob/living/carbon/alien/humanoid/humanoid.dm # code/modules/mob/living/carbon/carbon_defines.dm
This commit is contained in:
@@ -21,6 +21,13 @@ var/global/nologevent = 0
|
||||
var/msg = rendered
|
||||
to_chat(C, msg)
|
||||
|
||||
/proc/message_adminTicket(var/msg)
|
||||
msg = "<span class='adminticket'><span class='prefix'>ADMIN TICKET:</span> [msg]</span>"
|
||||
for(var/client/C in admins)
|
||||
if(R_ADMIN & C.holder.rights)
|
||||
if(C.prefs && !(C.prefs.toggles & CHAT_NO_TICKETLOGS))
|
||||
to_chat(C, msg)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////Panels
|
||||
|
||||
|
||||
@@ -108,6 +108,8 @@ var/list/admin_verbs_event = list(
|
||||
/client/proc/toggle_random_events,
|
||||
/client/proc/toggle_ert_calling,
|
||||
/client/proc/cmd_admin_change_custom_event,
|
||||
/client/proc/cmd_admin_custom_event_info,
|
||||
/client/proc/cmd_view_custom_event_info,
|
||||
/datum/admins/proc/access_news_network, /*allows access of newscasters*/
|
||||
/client/proc/cmd_admin_direct_narrate, /*send text directly to a player with no padding. Useful for narratives and fluff-text*/
|
||||
/client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/
|
||||
@@ -171,7 +173,8 @@ var/list/admin_verbs_debug = list(
|
||||
/client/proc/admin_serialize,
|
||||
/client/proc/admin_deserialize,
|
||||
/client/proc/jump_to_ruin,
|
||||
/client/proc/toggle_medal_disable
|
||||
/client/proc/toggle_medal_disable,
|
||||
/client/proc/startadmintickets,
|
||||
)
|
||||
var/list/admin_verbs_possess = list(
|
||||
/proc/possess,
|
||||
@@ -218,6 +221,12 @@ var/list/admin_verbs_snpc = list(
|
||||
/client/proc/customiseSNPC,
|
||||
/client/proc/hide_snpc_verbs
|
||||
)
|
||||
var/list/admin_verbs_ticket = list(
|
||||
/client/proc/openTicketUI,
|
||||
/client/proc/toggleticketlogs,
|
||||
/client/proc/resolveAllTickets,
|
||||
/client/proc/openUserUI
|
||||
)
|
||||
|
||||
/client/proc/on_holder_add()
|
||||
if(chatOutput && chatOutput.loaded)
|
||||
@@ -230,6 +239,7 @@ var/list/admin_verbs_snpc = list(
|
||||
verbs += /client/proc/togglebuildmodeself
|
||||
if(holder.rights & R_ADMIN)
|
||||
verbs += admin_verbs_admin
|
||||
verbs += admin_verbs_ticket
|
||||
spawn(1)
|
||||
control_freak = 0
|
||||
if(holder.rights & R_BAN)
|
||||
@@ -280,7 +290,8 @@ var/list/admin_verbs_snpc = list(
|
||||
admin_verbs_show_debug_verbs,
|
||||
/client/proc/readmin,
|
||||
admin_verbs_snpc,
|
||||
/client/proc/hide_snpc_verbs
|
||||
/client/proc/hide_snpc_verbs,
|
||||
admin_verbs_ticket
|
||||
)
|
||||
|
||||
/client/proc/hide_verbs()
|
||||
@@ -917,6 +928,20 @@ var/list/admin_verbs_snpc = list(
|
||||
else
|
||||
to_chat(usr, "You now will get admin log messages.")
|
||||
|
||||
/client/proc/toggleticketlogs()
|
||||
set name = "Toggle Admin Ticket Messgaes"
|
||||
set category = "Preferences"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
prefs.toggles ^= CHAT_NO_TICKETLOGS
|
||||
prefs.save_preferences(src)
|
||||
if(prefs.toggles & CHAT_NO_TICKETLOGS)
|
||||
to_chat(usr, "You now won't get admin ticket messages.")
|
||||
else
|
||||
to_chat(usr, "You now will get admin ticket messages.")
|
||||
|
||||
/client/proc/toggledrones()
|
||||
set name = "Toggle Maintenance Drones"
|
||||
set category = "Server"
|
||||
|
||||
@@ -100,3 +100,9 @@ you will have to do something like if(client.holder.rights & R_ADMIN) yourself.
|
||||
return 0
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/admins/vv_edit_var(var_name, var_value)
|
||||
return FALSE // no admin abuse
|
||||
|
||||
/datum/admins/can_vv_delete()
|
||||
return FALSE // don't break shit either
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
Admin ticket system by Birdtalon
|
||||
*/
|
||||
//Global holder
|
||||
|
||||
var/global/datum/adminTicketHolder/globAdminTicketHolder = new /datum/adminTicketHolder
|
||||
|
||||
//Defines
|
||||
//Deciseconds until ticket becomes stale if unanswered. Alerts admins.
|
||||
#define ADMIN_TICKET_TIMEOUT 6000 // 10 minutes
|
||||
//Decisecions before the user is allowed to open another ticket while their existing one is open.
|
||||
#define ADMIN_TICKET_DUPLICATE_COOLDOWN 3000 // 5 minutes
|
||||
|
||||
//Status defines
|
||||
#define ADMIN_TICKET_OPEN 1
|
||||
#define ADMIN_TICKET_CLOSED 2
|
||||
#define ADMIN_TICKET_RESOLVED 3
|
||||
#define ADMIN_TICKET_STALE 4
|
||||
|
||||
//Datum holding all tickets
|
||||
/datum/adminTicketHolder
|
||||
var/ticketCounter = 1 // Counts the tickets and used to assign the id number
|
||||
var/list/allTickets = list()
|
||||
|
||||
//Return the current ticket number ready to be called off.
|
||||
/datum/adminTicketHolder/proc/getTicketCounter()
|
||||
return ticketCounter
|
||||
|
||||
//Return the ticket counter and increment
|
||||
/datum/adminTicketHolder/proc/getTicketCounterAndInc()
|
||||
. = ticketCounter
|
||||
ticketCounter++
|
||||
return
|
||||
|
||||
/datum/adminTicketHolder/proc/resolveAllOpenTickets() // Resolve all open tickets
|
||||
for(var/i in allTickets)
|
||||
var/datum/admin_ticket/T = i
|
||||
resolveTicket(T.ticketNum)
|
||||
|
||||
//Open a new ticket and populate details then add to the list of open tickets
|
||||
/datum/adminTicketHolder/proc/newTicket(var/client/C, var/passedContent, var/title)
|
||||
if(!C || !passedContent)
|
||||
return
|
||||
|
||||
//Check if the user has an open ticket already within the cooldown period, if so we don't create a new one and re-set the cooldown period
|
||||
var/datum/admin_ticket/existingTicket = checkForOpenTicket(C)
|
||||
if(existingTicket)
|
||||
existingTicket.setCooldownPeriod()
|
||||
to_chat(C, "<span class='adminticket'>Your ticket #[existingTicket.ticketNum] remains open! Visit \"My tickets\" under the Admin Tab to view it.</span>")
|
||||
return
|
||||
|
||||
if(!title)
|
||||
title = passedContent
|
||||
|
||||
var/datum/admin_ticket/T = new /datum/admin_ticket
|
||||
T.clientName = C
|
||||
T.timeOpened = worldtime2text()
|
||||
T.title = title
|
||||
T.content += passedContent
|
||||
T.locationSent = C.mob.loc.loc.name
|
||||
T.mobControlled = C.mob
|
||||
T.ticketState = ADMIN_TICKET_OPEN
|
||||
T.timeUntilStale = world.time + ADMIN_TICKET_TIMEOUT
|
||||
T.setCooldownPeriod()
|
||||
T.ticketNum = getTicketCounterAndInc()
|
||||
allTickets += T
|
||||
|
||||
//Inform the user that they have opened a ticket
|
||||
to_chat(C, "<span class='adminticket'>You have opened admin ticket number #[(globAdminTicketHolder.getTicketCounter() - 1)]! Please be patient and we will help you soon!</span>")
|
||||
|
||||
//Begin the stale count for this ticket.
|
||||
spawn(0)
|
||||
T.beginStaleCount()
|
||||
|
||||
//Set ticket state with key N to open
|
||||
/datum/adminTicketHolder/proc/openTicket(var/N)
|
||||
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[N]
|
||||
if(T.ticketState != ADMIN_TICKET_OPEN)
|
||||
T.ticketState = ADMIN_TICKET_OPEN
|
||||
return TRUE
|
||||
|
||||
//Set ticket state with key N to resolved
|
||||
/datum/adminTicketHolder/proc/resolveTicket(var/N)
|
||||
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[N]
|
||||
if(T.ticketState != ADMIN_TICKET_RESOLVED)
|
||||
T.ticketState = ADMIN_TICKET_RESOLVED
|
||||
return TRUE
|
||||
|
||||
//Set ticket state with key N to closed
|
||||
/datum/adminTicketHolder/proc/closeTicket(var/N)
|
||||
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[N]
|
||||
if(T.ticketState != ADMIN_TICKET_CLOSED)
|
||||
T.ticketState = ADMIN_TICKET_CLOSED
|
||||
return TRUE
|
||||
|
||||
//Check if the user already has a ticket open and within the cooldown period.
|
||||
/datum/adminTicketHolder/proc/checkForOpenTicket(var/client/C)
|
||||
for(var/datum/admin_ticket/T in allTickets)
|
||||
if(T.clientName == C && T.ticketState == ADMIN_TICKET_OPEN && (T.ticketCooldown > world.time))
|
||||
return T
|
||||
return FALSE
|
||||
|
||||
//Check if the user has ANY ticket not resolved or closed.
|
||||
/datum/adminTicketHolder/proc/checkForTicket(var/client/C)
|
||||
var/list/tickets = list()
|
||||
for(var/datum/admin_ticket/T in allTickets)
|
||||
if(T.clientName == C && T.ticketState == ADMIN_TICKET_OPEN || T.ticketState == ADMIN_TICKET_STALE)
|
||||
tickets += T
|
||||
if(tickets.len)
|
||||
return tickets
|
||||
return FALSE
|
||||
|
||||
//return the client of a ticket number
|
||||
/datum/adminTicketHolder/proc/returnClient(var/N)
|
||||
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[N]
|
||||
return T.clientName
|
||||
|
||||
/datum/adminTicketHolder/proc/assignAdminToTicket(var/client/C, var/N)
|
||||
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[N]
|
||||
T.assignAdmin(C)
|
||||
return TRUE
|
||||
|
||||
//Single admin ticket
|
||||
|
||||
/datum/admin_ticket
|
||||
var/ticketNum // Ticket number
|
||||
var/clientName // Client which opened the ticket
|
||||
var/timeOpened // Time the ticket was opened
|
||||
var/title //The initial message with links
|
||||
var/list/content = list() // content of the admin help
|
||||
var/lastAdminResponse // Last admin who responded
|
||||
var/lastResponseTime // When the admin last responded
|
||||
var/locationSent // Location the player was when they send the ticket
|
||||
var/mobControlled // Mob they were controlling
|
||||
var/ticketState // State of the ticket, open, closed, resolved etc
|
||||
var/timeUntilStale // When the ticket goes stale
|
||||
var/ticketCooldown // Cooldown before allowing the user to open another ticket.
|
||||
var/adminAssigned // Admin who has assigned themselves to this ticket
|
||||
|
||||
//Ticker called when a ticket is created, checks for stale-ness.
|
||||
/datum/admin_ticket/proc/beginStaleCount()
|
||||
while(world.time < timeUntilStale || !lastAdminResponse || !adminAssigned) // While within the stale period OR no admin responded OR no admin assigned.
|
||||
|
||||
if(!src)
|
||||
return
|
||||
|
||||
sleep(200) // Check every 20 seconds.
|
||||
if(ticketState == ADMIN_TICKET_OPEN && world.time > timeUntilStale)
|
||||
message_adminTicket("<span class='adminticket'>Ticket #[ticketNum] has been open for [ADMIN_TICKET_TIMEOUT * 0.1] seconds. Changing status to stale.</span>")
|
||||
ticketState = ADMIN_TICKET_STALE
|
||||
break
|
||||
|
||||
//Set the cooldown period for the ticket. The time when it's created plus the defined cooldown time.
|
||||
/datum/admin_ticket/proc/setCooldownPeriod()
|
||||
ticketCooldown = world.time + ADMIN_TICKET_DUPLICATE_COOLDOWN
|
||||
|
||||
//Set the last admin who responded as the client passed as an arguement.
|
||||
/datum/admin_ticket/proc/setLastAdminResponse(var/client/C)
|
||||
lastAdminResponse = C
|
||||
lastResponseTime = worldtime2text()
|
||||
|
||||
//Return the ticket state as a colour coded text string.
|
||||
/datum/admin_ticket/proc/state2text()
|
||||
switch(ticketState)
|
||||
if(ADMIN_TICKET_OPEN)
|
||||
return "<font color='green'>OPEN</font>"
|
||||
if(ADMIN_TICKET_RESOLVED)
|
||||
return "<font color='blue'>RESOLVED</font>"
|
||||
if(ADMIN_TICKET_CLOSED)
|
||||
return "<font color='red'>CLOSED</font>"
|
||||
if(ADMIN_TICKET_STALE)
|
||||
return "<font color='orange'>STALE</font>"
|
||||
|
||||
//Assign the client passed to var/adminAsssigned
|
||||
/datum/admin_ticket/proc/assignAdmin(var/client/C, var/N)
|
||||
if(!C)
|
||||
return
|
||||
adminAssigned = C
|
||||
return TRUE
|
||||
|
||||
/datum/admin_ticket/proc/addResponse(var/client/C, var/M as text)
|
||||
if(C.holder)
|
||||
setLastAdminResponse(C)
|
||||
M = "[C]: [M]"
|
||||
content += M
|
||||
@@ -0,0 +1,172 @@
|
||||
/datum/adminTicketHolder/proc/returnUI(var/tab = ADMIN_TICKET_OPEN)
|
||||
set name = "Open Ticket Interface"
|
||||
set category = "Tickets"
|
||||
|
||||
//dat
|
||||
var/trStyle = "border-top:2px solid; border-bottom:2px solid; padding-top: 5px; padding-bottom: 5px;"
|
||||
var/tdStyleleft = "border-top:2px solid; border-bottom:2px solid; width:150px; text-align:center;"
|
||||
var/tdStyle = "border-top:2px solid; border-bottom:2px solid;"
|
||||
var/datum/admin_ticket/ticket
|
||||
var/dat
|
||||
dat += "<head><style>.adminticket{border:2px solid}</style></head>"
|
||||
dat += "<body><h1>Admin Tickets</h1>"
|
||||
|
||||
dat +="<a href='?src=[UID()];refresh=1'>Refresh</a><br /><a href='?src=[UID()];showopen=1'>Open Tickets</a><a href='?src=[UID()];showresolved=1'>Resolved Tickets</a><a href='?src=[UID()];showclosed=1'>Closed Tickets</a>"
|
||||
if(tab == ADMIN_TICKET_OPEN)
|
||||
dat += "<h2>Open Tickets</h2>"
|
||||
dat += "<table style='width:1300px; border: 3px solid;'>"
|
||||
dat +="<tr style='[trStyle]'><th style='[tdStyleleft]'>Control</th><th style='[tdStyle]'>Ticket</th></tr>"
|
||||
if(tab == ADMIN_TICKET_OPEN)
|
||||
for(var/T in allTickets)
|
||||
ticket = T
|
||||
if(ticket.ticketState == ADMIN_TICKET_OPEN || ticket.ticketState == ADMIN_TICKET_STALE)
|
||||
dat += "<tr style='[trStyle]'><td style ='[tdStyleleft]'><a href='?src=[UID()];resolve=[ticket.ticketNum]'>Resolve</a><a href='?src=[UID()];details=[ticket.ticketNum]'>Details</a> <br /> #[ticket.ticketNum] ([ticket.timeOpened]) [ticket.ticketState == ADMIN_TICKET_STALE ? "<font color='red'><b>STALE</font>" : ""] </td><td style='[tdStyle]'><b>[ticket.title]</td></tr>"
|
||||
else
|
||||
continue
|
||||
else if(tab == ADMIN_TICKET_RESOLVED)
|
||||
dat += "<h2>Resolved Tickets</h2>"
|
||||
for(var/T in allTickets)
|
||||
ticket = T
|
||||
if(ticket.ticketState == ADMIN_TICKET_RESOLVED)
|
||||
dat += "<tr style='[trStyle]'><td style ='[tdStyleleft]'><a href='?src=[UID()];resolve=[ticket.ticketNum]'>Resolve</a><a href='?src=[UID()];details=[ticket.ticketNum]'>Details</a> <br /> #[ticket.ticketNum] ([ticket.timeOpened]) </td><td style='[tdStyle]'><b>[ticket.title]</td></tr>"
|
||||
else
|
||||
continue
|
||||
else if(tab == ADMIN_TICKET_CLOSED)
|
||||
dat += "<h2>Closed Tickets</h2>"
|
||||
for(var/T in allTickets)
|
||||
ticket = T
|
||||
if(ticket.ticketState == ADMIN_TICKET_CLOSED)
|
||||
dat += "<tr style='[trStyle]'><td style ='[tdStyleleft]'><a href='?src=[UID()];resolve=[ticket.ticketNum]'>Resolve</a><a href='?src=[UID()];details=[ticket.ticketNum]'>Details</a> <br /> #[ticket.ticketNum] ([ticket.timeOpened]) </td><td style='[tdStyle]'><b>[ticket.title]</td></tr>"
|
||||
else
|
||||
continue
|
||||
|
||||
dat += "</table></body>"
|
||||
|
||||
return dat
|
||||
|
||||
/datum/adminTicketHolder/proc/showUI(var/client/user, var/tab)
|
||||
var/dat = null
|
||||
dat = returnUI(tab)
|
||||
var/datum/browser/popup = new(user, "admintickets", "Admin Tickets", 1400, 600)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/datum/adminTicketHolder/proc/showDetailUI(var/client/user, var/ticketID)
|
||||
var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[ticketID]
|
||||
var/status = "[T.state2text()]"
|
||||
|
||||
var/dat = "<h1>Admin Tickets</h1>"
|
||||
|
||||
dat +="<a href='?src=[UID()];refresh=1'>Show All</a><a href='?src=[UID()];refreshdetail=[T.ticketNum]'>Refresh</a>"
|
||||
|
||||
dat += "<h2>Ticket #[T.ticketNum]</h2>"
|
||||
|
||||
dat += "<h3>[T.clientName] / [T.mobControlled] opened this ticket at [T.timeOpened] at location [T.locationSent]</h3>"
|
||||
dat += "<h4>Ticket Status: <font color='red'>[status]</font>"
|
||||
dat += "<table style='width:950px; border: 3px solid;'>"
|
||||
dat += "<tr><td>[T.title]</td></tr>"
|
||||
|
||||
if(T.content.len > 1)
|
||||
for(var/i = 2, i <= T.content.len, i++)
|
||||
dat += "<tr><td>[T.content[i]]</td></tr>"
|
||||
|
||||
dat += "</table><br /><br />"
|
||||
dat += "<a href='?src=[UID()];detailreopen=[T.ticketNum]'>Re-Open</a><a href='?src=[UID()];detailresolve=[T.ticketNum]'>Resolve</a><br /><br />"
|
||||
|
||||
if(!T.adminAssigned)
|
||||
dat += "No admin assigned to this ticket - <a href='?src=[UID()];assignadmin=[T.ticketNum]'>Take Ticket</a><br />"
|
||||
else
|
||||
dat += "[T.adminAssigned] is assigned to this Ticket. - <a href='?src=[UID()];assignadmin=[T.ticketNum]'>Take Ticket</a><br />"
|
||||
|
||||
if(T.lastAdminResponse)
|
||||
dat += "<b>Last Admin Response:</b> [T.lastAdminResponse] at [T.lastResponseTime]"
|
||||
else
|
||||
dat +="<font color='red'>No Admin Response</font>"
|
||||
|
||||
dat += "<br /><br />"
|
||||
|
||||
dat += "<a href='?src=[UID()];detailclose=[T.ticketNum]'>Close Ticket</a>"
|
||||
|
||||
var/datum/browser/popup = new(user, "adminticketsdetail", "Admin Ticket #[T.ticketNum]", 1000, 600)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/datum/adminTicketHolder/proc/userDetailUI(var/client/user)
|
||||
//dat
|
||||
var/tickets = checkForTicket(user)
|
||||
var/dat
|
||||
dat += "<h1>Your open tickets</h1>"
|
||||
dat += "<table>"
|
||||
for(var/datum/admin_ticket/T in tickets)
|
||||
dat += "<tr><td><h2>Ticket #[T.ticketNum]</h2></td></tr>"
|
||||
for(var/i = 1, i <= T.content.len, i++)
|
||||
dat += "<tr><td>[T.content[i]]</td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
var/datum/browser/popup = new(user, "userticketsdetail", "Tickets", 1000, 600)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/datum/adminTicketHolder/Topic(href, href_list)
|
||||
|
||||
if(href_list["refresh"])
|
||||
showUI(usr)
|
||||
return
|
||||
|
||||
if(href_list["refreshdetail"])
|
||||
var/indexNum = text2num(href_list["refreshdetail"])
|
||||
showDetailUI(usr, indexNum)
|
||||
return
|
||||
|
||||
if(href_list["showopen"])
|
||||
showUI(usr, ADMIN_TICKET_OPEN)
|
||||
return
|
||||
if(href_list["showresolved"])
|
||||
showUI(usr, ADMIN_TICKET_RESOLVED)
|
||||
return
|
||||
if(href_list["showclosed"])
|
||||
showUI(usr, ADMIN_TICKET_CLOSED)
|
||||
return
|
||||
|
||||
if(href_list["details"])
|
||||
var/indexNum = text2num(href_list["details"])
|
||||
showDetailUI(usr.client, indexNum)
|
||||
return
|
||||
|
||||
if(href_list["resolve"])
|
||||
var/indexNum = text2num(href_list["resolve"])
|
||||
if(globAdminTicketHolder.resolveTicket(indexNum))
|
||||
message_adminTicket("[usr.client] / ([usr]) resolved admin ticket number [indexNum]")
|
||||
to_chat(returnClient(indexNum), "<span class='adminticket'>Your admin ticket has now been resolved.</span>")
|
||||
showUI(usr)
|
||||
|
||||
if(href_list["detailresolve"])
|
||||
var/indexNum = text2num(href_list["detailresolve"])
|
||||
if(globAdminTicketHolder.resolveTicket(indexNum))
|
||||
message_adminTicket("[usr.client] / ([usr]) resolved admin ticket number [indexNum]")
|
||||
to_chat(returnClient(indexNum), "<span class='adminticket'>Your admin ticket has now been resolved.</span>")
|
||||
showDetailUI(usr, indexNum)
|
||||
|
||||
if(href_list["detailclose"])
|
||||
var/indexNum = text2num(href_list["detailclose"])
|
||||
if(alert("Are you sure? This will send a negative message.",,"Yes","No") != "Yes")
|
||||
return
|
||||
if(globAdminTicketHolder.closeTicket(indexNum))
|
||||
message_adminTicket("[usr.client] / ([usr]) closed admin ticket number [indexNum]")
|
||||
to_chat(returnClient(indexNum), "<font color='red' size='4'><b>- AdminHelp Rejected! -</b></font>")
|
||||
to_chat(returnClient(indexNum), "<span class='boldmessage'>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. If you asked a question, please ensure it was clear what you were asking.</span>")
|
||||
to_chat(returnClient(indexNum), "<span class='adminticket'>Your ticket has now been closed.</span>")
|
||||
showDetailUI(usr, indexNum)
|
||||
|
||||
if(href_list["detailreopen"])
|
||||
var/indexNum = text2num(href_list["detailreopen"])
|
||||
if(globAdminTicketHolder.openTicket(indexNum))
|
||||
message_adminTicket("[usr.client] / ([usr]) re-opened admin ticket number [indexNum]")
|
||||
showDetailUI(usr, indexNum)
|
||||
|
||||
if(href_list["assignadmin"])
|
||||
var/indexNum = text2num(href_list["assignadmin"])
|
||||
if(globAdminTicketHolder.assignAdminToTicket(usr.client, indexNum))
|
||||
message_adminTicket("[usr.client] / ([usr]) has taken ticket number [indexNum]")
|
||||
to_chat(returnClient(indexNum), "<span class='adminticket'>Your ticket is being handled by [usr.client].")
|
||||
showDetailUI(usr, indexNum)
|
||||
@@ -0,0 +1,51 @@
|
||||
//Verbs
|
||||
|
||||
/client/proc/startadmintickets()
|
||||
set name = "Restart Admin Ticket System"
|
||||
set category = "Debug"
|
||||
|
||||
if(!holder && !check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
if(!globAdminTicketHolder)
|
||||
var/global/datum/adminTicketHolder/globAdminTicketHolder = new /datum/adminTicketHolder
|
||||
else
|
||||
if(alert("Are you sure you want to reboot the admin ticket system?","Reboot Admin Tickets?","Yes","No") != "Yes")
|
||||
return
|
||||
message_admins("<span class='admintickets'>Restarting Admin Ticket System!</span>")
|
||||
globAdminTicketHolder = new /datum/adminTicketHolder
|
||||
message_admins("<span class='admintickets'>Admin Ticket System Restarted!</span>")
|
||||
|
||||
/client/proc/openTicketUI()
|
||||
|
||||
set name = "Open Ticket Interface"
|
||||
set category = "Admin"
|
||||
|
||||
if(!holder && !check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
globAdminTicketHolder.showUI(usr)
|
||||
|
||||
/client/proc/resolveAllTickets()
|
||||
set name = "Resolve All Open Tickets"
|
||||
set category = "Admin"
|
||||
|
||||
if(!holder && !check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(alert("Are you sure you want to resolve ALL open tickets?","Resolve all open tickets?","Yes","No") != "Yes")
|
||||
return
|
||||
|
||||
globAdminTicketHolder.resolveAllOpenTickets()
|
||||
|
||||
|
||||
|
||||
/client/proc/openUserUI()
|
||||
|
||||
set name = "My Tickets"
|
||||
set category = "Admin"
|
||||
|
||||
if(!holder && !check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
globAdminTicketHolder.userDetailUI(usr.client)
|
||||
@@ -26,6 +26,12 @@
|
||||
message_admins("[key_name_admin(usr)] rejected [key_name_admin(C.mob)]'s admin help")
|
||||
log_admin("[key_name(usr)] rejected [key_name(C.mob)]'s admin help")
|
||||
|
||||
if(href_list["openadminticket"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/ticketID = text2num(href_list["openadminticket"])
|
||||
globAdminTicketHolder.showDetailUI(usr, ticketID)
|
||||
|
||||
if(href_list["stickyban"])
|
||||
stickyban(href_list["stickyban"],href_list)
|
||||
|
||||
@@ -242,16 +248,23 @@
|
||||
|
||||
else if(task == "permissions")
|
||||
if(!D) return
|
||||
var/list/permissionlist = list()
|
||||
for(var/i=1, i<=R_MAXPERMISSION, i<<=1) //that <<= is shorthand for i = i << 1. Which is a left bitshift
|
||||
permissionlist[rights2text(i)] = i
|
||||
var/new_permission = input("Select a permission to turn on/off", "Permission toggle", null, null) as null|anything in permissionlist
|
||||
if(!new_permission) return
|
||||
D.rights ^= permissionlist[new_permission]
|
||||
while(TRUE)
|
||||
var/list/permissionlist = list()
|
||||
for(var/i=1, i<=R_MAXPERMISSION, i<<=1) //that <<= is shorthand for i = i << 1. Which is a left bitshift
|
||||
permissionlist[rights2text(i)] = i
|
||||
var/new_permission = input("Select a permission to turn on/off", adm_ckey + "'s Permissions", null, null) as null|anything in permissionlist
|
||||
if(!new_permission)
|
||||
return
|
||||
var/oldrights = D.rights
|
||||
var/toggleresult = "ON"
|
||||
D.rights ^= permissionlist[new_permission]
|
||||
if(oldrights > D.rights)
|
||||
toggleresult = "OFF"
|
||||
|
||||
message_admins("[key_name_admin(usr)] toggled the [new_permission] permission of [adm_ckey] to [toggleresult]")
|
||||
log_admin("[key_name(usr)] toggled the [new_permission] permission of [adm_ckey] to [toggleresult]")
|
||||
log_admin_permission_modification(adm_ckey, permissionlist[new_permission])
|
||||
|
||||
message_admins("[key_name_admin(usr)] toggled the [new_permission] permission of [adm_ckey]")
|
||||
log_admin("[key_name(usr)] toggled the [new_permission] permission of [adm_ckey]")
|
||||
log_admin_permission_modification(adm_ckey, permissionlist[new_permission])
|
||||
|
||||
edit_admin_permissions()
|
||||
|
||||
|
||||
@@ -89,8 +89,12 @@
|
||||
|
||||
if("delete")
|
||||
for(var/d in objs)
|
||||
if(!datum_is_forbidden(d))
|
||||
qdel(d)
|
||||
if(istype(d, /datum))
|
||||
var/datum/D = d
|
||||
if(!D.can_vv_delete())
|
||||
to_chat(usr, "[D] rejected your deletion")
|
||||
continue
|
||||
qdel(d)
|
||||
|
||||
if("select")
|
||||
var/text = ""
|
||||
@@ -118,9 +122,6 @@
|
||||
if("set" in query_tree)
|
||||
var/list/set_list = query_tree["set"]
|
||||
for(var/d in objs)
|
||||
// Forbid explicitly modifying an admin datum's vars
|
||||
if(datum_is_forbidden(d))
|
||||
return
|
||||
for(var/list/sets in set_list)
|
||||
var/datum/temp = d
|
||||
var/i = 0
|
||||
@@ -128,11 +129,10 @@
|
||||
if(++i == sets.len)
|
||||
if(istype(temp, /turf) && (v == "x" || v == "y" || v == "z"))
|
||||
continue
|
||||
if(!datum_is_forbidden(temp.vars[v]))
|
||||
return
|
||||
temp.vars[v] = SDQL_expression(d, set_list[sets])
|
||||
if(!temp.vv_edit_var(v, SDQL_expression(d, set_list[sets])))
|
||||
to_chat(usr, "[temp] rejected your varedit.")
|
||||
break
|
||||
if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client)) && !datum_is_forbidden(temp.vars[v]))
|
||||
if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client)))
|
||||
temp = temp.vars[v]
|
||||
else
|
||||
break
|
||||
@@ -440,11 +440,6 @@
|
||||
for(var/arg in arguments)
|
||||
new_args[++new_args.len] = SDQL_expression(source, arg)
|
||||
|
||||
for(var/p in forbidden_varedit_object_types)
|
||||
if(istype(object, p))
|
||||
to_chat(usr, "<span class='warning'>It is forbidden to run this object's procs.</span>")
|
||||
return
|
||||
|
||||
if(object == world) // Global proc.
|
||||
procname = "/proc/[procname]"
|
||||
return call(procname)(arglist(new_args))
|
||||
|
||||
@@ -115,7 +115,17 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
|
||||
X << 'sound/effects/adminhelp.ogg'
|
||||
to_chat(X, msg)
|
||||
if("Adminhelp")
|
||||
msg = "<span class='adminhelp'>[selected_type]: </span><span class='boldnotice'>[key_name(src, 1, 1, selected_type)] (<A HREF='?_src_=holder;adminmoreinfo=[ref_mob]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A>) (<A HREF='?_src_=vars;Vars=[mob.UID()]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>) ([admin_jump_link(mob)]) (<A HREF='?_src_=holder;check_antagonist=1'>CA</A>) (<A HREF='?_src_=holder;rejectadminhelp=[ref_client]'>REJT</A>) [ai_found ? " (<A HREF='?_src_=holder;adminchecklaws=[ref_mob]'>CL</A>)" : ""] (<A HREF='?_src_=holder;take_question=[mob.UID()]'>TAKE</A>) :</span> <span class='adminhelp'>[msg]</span>"
|
||||
var/ticketNum // Holder for the ticket number
|
||||
var/prunedmsg ="[usr.client]: [msg]" // Message without links
|
||||
if(globAdminTicketHolder.checkForOpenTicket(usr.client)) // If user already has an open ticket
|
||||
var/datum/admin_ticket/T = globAdminTicketHolder.checkForOpenTicket(usr.client) // Make T equal to the ticket they have open
|
||||
ticketNum = T.ticketNum // ticketNum is the number of their ticket.
|
||||
T.addResponse(usr.client, msg)
|
||||
else
|
||||
ticketNum = globAdminTicketHolder.getTicketCounter() // ticketNum is the ticket ready to be assigned.
|
||||
msg = "<span class='adminhelp'>[selected_type]: </span><span class='boldnotice'>[key_name(src, 1, 1, selected_type)] (<A HREF='?_src_=holder;adminmoreinfo=[ref_mob]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A>) (<A HREF='?_src_=vars;Vars=[mob.UID()]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>) ([admin_jump_link(mob)]) (<A HREF='?_src_=holder;check_antagonist=1'>CA</A>) (<A HREF='?_src_=holder;openadminticket=[ticketNum]'>TICKET</A>) [ai_found ? " (<A HREF='?_src_=holder;adminchecklaws=[ref_mob]'>CL</A>)" : ""] :</span> <span class='adminhelp'>[msg]</span>"
|
||||
//Open a new adminticket and inform the user.
|
||||
globAdminTicketHolder.newTicket(src, prunedmsg, msg)
|
||||
for(var/client/X in modholders + adminholders)
|
||||
if(X.prefs.sound & SOUND_ADMINHELP)
|
||||
X << 'sound/effects/adminhelp.ogg'
|
||||
|
||||
@@ -183,6 +183,23 @@
|
||||
if(check_rights(R_ADMIN|R_MOD, 0, X.mob))
|
||||
to_chat(X, "<span class='boldnotice'>[type]: [key_name(src, X, 0, type)]->[key_name(C, X, 0, type)]: [emoji_msg]</span>")
|
||||
|
||||
//Check if the mob being PM'd has any open admin tickets.
|
||||
var/tickets = list()
|
||||
tickets = globAdminTicketHolder.checkForTicket(C)
|
||||
if(tickets)
|
||||
for(var/datum/admin_ticket/i in tickets)
|
||||
i.addResponse(src, msg) // Add this response to their open tickets.
|
||||
return
|
||||
|
||||
tickets = globAdminTicketHolder.checkForTicket(src)
|
||||
if(check_rights(R_ADMIN|R_MOD, 0, C.mob)) //Is the person being pm'd an admin? If so we check if the pm'er has open tickets
|
||||
tickets = globAdminTicketHolder.checkForTicket(src)
|
||||
if(tickets)
|
||||
for(var/datum/admin_ticket/i in tickets)
|
||||
i.addResponse(src, msg)
|
||||
return
|
||||
|
||||
|
||||
/client/proc/cmd_admin_irc_pm()
|
||||
if(prefs.muted & MUTE_ADMINHELP)
|
||||
to_chat(src, "<font color='red'>Error: Private-Message: You are unable to use PM-s (muted).</font>")
|
||||
|
||||
@@ -38,3 +38,49 @@
|
||||
to_chat(src, "<h2 class='alert'>A custom event is taking place. OOC Info:</h2>")
|
||||
to_chat(src, "<span class='alert'>[html_encode(custom_event_msg)]</span>")
|
||||
to_chat(src, "<br>")
|
||||
|
||||
//admin event info to be view by admins
|
||||
|
||||
/client/proc/cmd_admin_custom_event_info()
|
||||
set category = "Event"
|
||||
set name = "Change Custom Admin Event Info"
|
||||
|
||||
if(!check_rights(R_EVENT))
|
||||
to_chat(src, "Only administrators may use this command.")
|
||||
return
|
||||
|
||||
var/input = input(usr, "Enter the description of the custom event. This is informations for admins only. Use it to notify other admins of event info but not players.", "Custom Event Info", custom_event_msg) as message|null
|
||||
if(!input || input == "")
|
||||
custom_event_admin_msg = null
|
||||
log_admin("[key_name(usr)] has cleared the custom admin event info text.")
|
||||
message_admins("[key_name_admin(usr)] has cleared the custom admin event text.")
|
||||
return
|
||||
|
||||
log_admin("[key_name(usr)] has changed the custom admin event info text.")
|
||||
message_admins("[key_name_admin(usr)] has changed the custom admin event info text.")
|
||||
|
||||
custom_event_admin_msg = input
|
||||
|
||||
for(var/client/X in admins)
|
||||
if(check_rights(R_EVENT,0,X.mob))
|
||||
to_chat(X, "<h1 class='alert'>Custom Admin Event Info</h1>")
|
||||
to_chat(X, "<h2 class='alert'>A custom event is starting. OOC Admin Info:</h2>")
|
||||
to_chat(X, "<span class='alert'>[html_encode(custom_event_admin_msg)]</span>")
|
||||
to_chat(X,"<br>")
|
||||
|
||||
/client/proc/cmd_view_custom_event_info()
|
||||
set category = "Event"
|
||||
set name = "Custom Event Admin Info"
|
||||
|
||||
if(!check_rights(R_EVENT))
|
||||
to_chat(src, "Only administrators may use this command.")
|
||||
return
|
||||
|
||||
if(!custom_event_admin_msg || custom_event_admin_msg == "")
|
||||
to_chat(src, "There currently is no known custom admin event taking place.")
|
||||
return
|
||||
|
||||
to_chat(src, "<h1 class='alert'>Custom Event Info</h1>")
|
||||
to_chat(src, "<h2 class='alert'>A custom event is taking place. OOC Info:</h2>")
|
||||
to_chat(src, "<span class='alert'>[html_encode(custom_event_admin_msg)]</span>")
|
||||
to_chat(src, "<br>")
|
||||
|
||||
@@ -22,360 +22,251 @@
|
||||
src.massmodify_variables(A, var_name, method)
|
||||
feedback_add_details("admin_verb","MEV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/client/proc/massmodify_variables(var/atom/O, var/var_name = "", var/method = 0)
|
||||
if(!check_rights(R_VAREDIT)) return
|
||||
|
||||
var/list/locked = list("vars", "key", "ckey", "client")
|
||||
|
||||
for(var/p in forbidden_varedit_object_types)
|
||||
if( istype(O,p) )
|
||||
to_chat(usr, "<span class='danger'>It is forbidden to edit this object's variables.</span>")
|
||||
return
|
||||
|
||||
var/list/names = list()
|
||||
for(var/V in O.vars)
|
||||
names += V
|
||||
|
||||
names = sortList(names)
|
||||
/client/proc/massmodify_variables(datum/O, var_name = "", method = 0)
|
||||
if(!check_rights(R_VAREDIT))
|
||||
return
|
||||
if(!istype(O))
|
||||
return
|
||||
|
||||
var/variable = ""
|
||||
|
||||
if(!var_name)
|
||||
variable = input("Which var?","Var") as null|anything in names
|
||||
var/list/names = list()
|
||||
for(var/V in O.vars)
|
||||
names += V
|
||||
|
||||
names = sortList(names)
|
||||
|
||||
variable = input("Which var?", "Var") as null|anything in names
|
||||
else
|
||||
variable = var_name
|
||||
|
||||
if(!variable) return
|
||||
if(!variable || !O.can_vv_get(variable))
|
||||
return
|
||||
var/default
|
||||
var/var_value = O.vars[variable]
|
||||
var/dir
|
||||
|
||||
if(variable == "holder" || (variable in locked))
|
||||
if(!check_rights(R_DEBUG)) return
|
||||
if(variable in VVckey_edit)
|
||||
to_chat(src, "It's forbidden to mass-modify ckeys. It'll crash everyone's client you dummy.")
|
||||
return
|
||||
if(variable in VVlocked)
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
if(variable in VVicon_edit_lock)
|
||||
if(!check_rights(R_EVENT | R_DEBUG))
|
||||
return
|
||||
if(variable in VVpixelmovement)
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
var/prompt = alert(src, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", "ABORT ", "Continue", " ABORT")
|
||||
if(prompt != "Continue")
|
||||
return
|
||||
|
||||
if(isnull(var_value))
|
||||
to_chat(usr, "Unable to determine variable type.")
|
||||
|
||||
else if(isnum(var_value))
|
||||
to_chat(usr, "Variable appears to be <b>NUM</b>.")
|
||||
default = "num"
|
||||
dir = 1
|
||||
|
||||
else if(istext(var_value))
|
||||
to_chat(usr, "Variable appears to be <b>TEXT</b>.")
|
||||
default = "text"
|
||||
|
||||
else if(isloc(var_value))
|
||||
to_chat(usr, "Variable appears to be <b>REFERENCE</b>.")
|
||||
default = "reference"
|
||||
|
||||
else if(isicon(var_value))
|
||||
to_chat(usr, "Variable appears to be <b>ICON</b>.")
|
||||
var_value = "[bicon(var_value)]"
|
||||
default = "icon"
|
||||
|
||||
else if(istype(var_value,/atom) || istype(var_value,/datum))
|
||||
to_chat(usr, "Variable appears to be <b>TYPE</b>.")
|
||||
default = "type"
|
||||
|
||||
else if(istype(var_value,/list))
|
||||
to_chat(usr, "Variable appears to be <b>LIST</b>.")
|
||||
default = "list"
|
||||
|
||||
else if(istype(var_value,/client))
|
||||
to_chat(usr, "Variable appears to be <b>CLIENT</b>.")
|
||||
default = "cancel"
|
||||
default = vv_get_class(var_value)
|
||||
|
||||
if(isnull(default))
|
||||
to_chat(src, "Unable to determine variable type.")
|
||||
else
|
||||
to_chat(usr, "Variable appears to be <b>FILE</b>.")
|
||||
default = "file"
|
||||
to_chat(src, "Variable appears to be <b>[uppertext(default)]</b>.")
|
||||
|
||||
to_chat(usr, "Variable contains: [var_value]")
|
||||
if(dir)
|
||||
switch(var_value)
|
||||
if(1)
|
||||
dir = "NORTH"
|
||||
if(2)
|
||||
dir = "SOUTH"
|
||||
if(4)
|
||||
dir = "EAST"
|
||||
if(8)
|
||||
dir = "WEST"
|
||||
if(5)
|
||||
dir = "NORTHEAST"
|
||||
if(6)
|
||||
dir = "SOUTHEAST"
|
||||
if(9)
|
||||
dir = "NORTHWEST"
|
||||
if(10)
|
||||
dir = "SOUTHWEST"
|
||||
else
|
||||
dir = null
|
||||
if(dir)
|
||||
to_chat(usr, "If a direction, direction is: [dir]")
|
||||
to_chat(src, "Variable contains: [var_value]")
|
||||
|
||||
var/class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
|
||||
"num","type","icon","file","edit referenced object","restore to default")
|
||||
if(default == VV_NUM)
|
||||
var/dir_text = ""
|
||||
if(dir < 0 && dir < 16)
|
||||
if(dir & 1)
|
||||
dir_text += "NORTH"
|
||||
if(dir & 2)
|
||||
dir_text += "SOUTH"
|
||||
if(dir & 4)
|
||||
dir_text += "EAST"
|
||||
if(dir & 8)
|
||||
dir_text += "WEST"
|
||||
|
||||
if(!class)
|
||||
if(dir_text)
|
||||
to_chat(src, "If a direction, direction is: [dir_text]")
|
||||
|
||||
var/value = vv_get_value(default_class = default)
|
||||
var/new_value = value["value"]
|
||||
var/class = value["class"]
|
||||
|
||||
if(!class || !new_value == null && class != VV_NULL)
|
||||
return
|
||||
|
||||
var/original_name
|
||||
if(class == VV_MESSAGE)
|
||||
class = VV_TEXT
|
||||
|
||||
if(!istype(O, /atom))
|
||||
original_name = "\ref[O] ([O])"
|
||||
else
|
||||
original_name = O:name
|
||||
if(value["type"])
|
||||
class = VV_NEW_TYPE
|
||||
|
||||
var/original_name = "[O]"
|
||||
|
||||
var/rejected = 0
|
||||
var/accepted = 0
|
||||
|
||||
switch(class)
|
||||
if(VV_RESTORE_DEFAULT)
|
||||
to_chat(src, "Finding items...")
|
||||
var/list/items = get_all_of_type(O.type, method)
|
||||
to_chat(src, "Changing [items.len] items...")
|
||||
for(var/thing in items)
|
||||
if(!thing)
|
||||
continue
|
||||
var/datum/D = thing
|
||||
if(D.vv_edit_var(variable, initial(D.vars[variable])) != FALSE)
|
||||
accepted++
|
||||
else
|
||||
rejected++
|
||||
CHECK_TICK
|
||||
|
||||
if("restore to default")
|
||||
O.vars[variable] = initial(O.vars[variable])
|
||||
if(method)
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if( istype(M , O.type) )
|
||||
M.vars[variable] = O.vars[variable]
|
||||
M.on_varedit(variable)
|
||||
if(VV_TEXT)
|
||||
var/list/varsvars = vv_parse_text(O, new_value)
|
||||
var/pre_processing = new_value
|
||||
var/unique
|
||||
if(varsvars && varsvars.len)
|
||||
unique = alert(usr, "Process vars unique to each instance, or same for all?", "Variable Association", "Unique", "Same")
|
||||
if(unique == "Unique")
|
||||
unique = TRUE
|
||||
else
|
||||
unique = FALSE
|
||||
for(var/V in varsvars)
|
||||
new_value = replacetext(new_value,"\[[V]]","[O.vars[V]]")
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
A.on_varedit(variable)
|
||||
to_chat(src, "Finding items...")
|
||||
var/list/items = get_all_of_type(O.type, method)
|
||||
to_chat(src, "Changing [items.len] items...")
|
||||
for(var/thing in items)
|
||||
if(!thing)
|
||||
continue
|
||||
var/datum/D = thing
|
||||
if(unique)
|
||||
new_value = pre_processing
|
||||
for(var/V in varsvars)
|
||||
new_value = replacetext(new_value,"\[[V]]","[D.vars[V]]")
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
A.on_varedit(variable)
|
||||
if(D.vv_edit_var(variable, new_value) != FALSE)
|
||||
accepted++
|
||||
else
|
||||
rejected++
|
||||
CHECK_TICK
|
||||
|
||||
if(VV_NEW_TYPE)
|
||||
var/many = alert(src, "Create only one [value["type"]] and assign each or a new one for each thing", "How Many", "One", "Many", "Cancel")
|
||||
if(many == "Cancel")
|
||||
return
|
||||
if(many == "Many")
|
||||
many = TRUE
|
||||
else
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.type == O.type)
|
||||
M.vars[variable] = O.vars[variable]
|
||||
M.on_varedit(variable)
|
||||
many = FALSE
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
A.on_varedit(variable)
|
||||
var/type = value["type"]
|
||||
to_chat(src, "Finding items...")
|
||||
var/list/items = get_all_of_type(O.type, method)
|
||||
to_chat(src, "Changing [items.len] items...")
|
||||
for(var/thing in items)
|
||||
if(!thing)
|
||||
continue
|
||||
var/datum/D = thing
|
||||
if(many && !new_value)
|
||||
new_value = new type()
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
A.on_varedit(variable)
|
||||
if(D.vv_edit_var(variable, new_value) != FALSE)
|
||||
accepted++
|
||||
else
|
||||
rejected++
|
||||
new_value = null
|
||||
CHECK_TICK
|
||||
|
||||
if("edit referenced object")
|
||||
return .(O.vars[variable])
|
||||
else
|
||||
to_chat(src, "Finding items...")
|
||||
var/list/items = get_all_of_type(O.type, method)
|
||||
to_chat(src, "Changing [items.len] items...")
|
||||
for(var/thing in items)
|
||||
if(!thing)
|
||||
continue
|
||||
var/datum/D = thing
|
||||
if(D.vv_edit_var(variable, new_value) != FALSE)
|
||||
accepted++
|
||||
else
|
||||
rejected++
|
||||
CHECK_TICK
|
||||
|
||||
if("text")
|
||||
var/new_value = input("Enter new text:","Text",O.vars[variable]) as message|null
|
||||
if(new_value == null) return
|
||||
O.vars[variable] = new_value
|
||||
|
||||
if(method)
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if( istype(M , O.type) )
|
||||
M.vars[variable] = O.vars[variable]
|
||||
var/count = rejected+accepted
|
||||
if(!count)
|
||||
to_chat(src, "No objects found")
|
||||
return
|
||||
if(!accepted)
|
||||
to_chat(src, "Every object rejected your edit")
|
||||
return
|
||||
if(rejected)
|
||||
to_chat(src, "[rejected] out of [count] objects rejected your edit")
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
log_to_dd("### MassVarEdit by [src]: [O.type] (A/R [accepted]/[rejected]) [variable]=[html_encode("[O.vars[variable]]")]([list2params(value)])")
|
||||
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
|
||||
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
else
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.type == O.type)
|
||||
M.vars[variable] = O.vars[variable]
|
||||
/proc/get_all_of_type(var/T, subtypes = TRUE)
|
||||
var/list/typecache = list()
|
||||
typecache[T] = 1
|
||||
if(subtypes)
|
||||
typecache = typecacheof(typecache)
|
||||
. = list()
|
||||
if(ispath(T, /mob))
|
||||
for(var/mob/thing in mob_list)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
else if(ispath(T, /obj/machinery/door))
|
||||
for(var/obj/machinery/door/thing in airlocks)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
else if(ispath(T, /obj/machinery))
|
||||
for(var/obj/machinery/thing in machines)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
if("num")
|
||||
var/new_value = input("Enter new number:","Num",\
|
||||
O.vars[variable]) as num|null
|
||||
if(new_value == null) return
|
||||
else if(ispath(T, /obj))
|
||||
for(var/obj/thing in world)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
if(variable=="light_range")
|
||||
O.set_light(new_value)
|
||||
else
|
||||
O.vars[variable] = new_value
|
||||
else if(ispath(T, /atom/movable))
|
||||
for(var/atom/movable/thing in world)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
if(method)
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if( istype(M , O.type) )
|
||||
if(variable=="light_range")
|
||||
M.set_light(new_value)
|
||||
else
|
||||
M.vars[variable] = O.vars[variable]
|
||||
else if(ispath(T, /turf))
|
||||
for(var/turf/thing in world)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if( istype(A , O.type) )
|
||||
if(variable=="light_range")
|
||||
A.set_light(new_value)
|
||||
else
|
||||
A.vars[variable] = O.vars[variable]
|
||||
else if(ispath(T, /atom))
|
||||
for(var/atom/thing in world)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if( istype(A , O.type) )
|
||||
if(variable=="light_range")
|
||||
A.set_light(new_value)
|
||||
else
|
||||
A.vars[variable] = O.vars[variable]
|
||||
else if(ispath(T, /client))
|
||||
for(var/client/thing in clients)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.type == O.type)
|
||||
if(variable=="light_range")
|
||||
M.set_light(new_value)
|
||||
else
|
||||
M.vars[variable] = O.vars[variable]
|
||||
else if(ispath(T, /datum))
|
||||
for(var/datum/thing)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if(A.type == O.type)
|
||||
if(variable=="light_range")
|
||||
A.set_light(new_value)
|
||||
else
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if(A.type == O.type)
|
||||
if(variable=="light_range")
|
||||
A.set_light(new_value)
|
||||
else
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
if("type")
|
||||
var/new_value
|
||||
new_value = input("Enter type:","Type",O.vars[variable]) as null|anything in typesof(/obj,/mob,/area,/turf)
|
||||
if(new_value == null) return
|
||||
O.vars[variable] = new_value
|
||||
if(method)
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if( istype(M , O.type) )
|
||||
M.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
else
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.type == O.type)
|
||||
M.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
if("file")
|
||||
var/new_value = input("Pick file:","File",O.vars[variable]) as null|file
|
||||
if(new_value == null) return
|
||||
O.vars[variable] = new_value
|
||||
|
||||
if(method)
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if( istype(M , O.type) )
|
||||
M.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O.type, /obj))
|
||||
for(var/obj/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O.type, /turf))
|
||||
for(var/turf/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
else
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.type == O.type)
|
||||
M.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O.type, /obj))
|
||||
for(var/obj/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O.type, /turf))
|
||||
for(var/turf/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
if("icon")
|
||||
var/new_value = input("Pick icon:","Icon",O.vars[variable]) as null|icon
|
||||
if(new_value == null) return
|
||||
O.vars[variable] = new_value
|
||||
if(method)
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if( istype(M , O.type) )
|
||||
M.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if( istype(A , O.type) )
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
else
|
||||
if(istype(O, /mob))
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.type == O.type)
|
||||
M.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O, /obj))
|
||||
for(var/obj/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
else if(istype(O, /turf))
|
||||
for(var/turf/A in world)
|
||||
if(A.type == O.type)
|
||||
A.vars[variable] = O.vars[variable]
|
||||
|
||||
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]")
|
||||
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]", 1)
|
||||
else
|
||||
for(var/datum/thing in world)
|
||||
if(typecache[thing.type])
|
||||
. += thing
|
||||
CHECK_TICK
|
||||
File diff suppressed because it is too large
Load Diff
@@ -61,7 +61,7 @@
|
||||
if(usr)
|
||||
if(usr.client)
|
||||
if(usr.client.holder)
|
||||
to_chat(M, "<b>old You hear a voice in your head... <i>[msg]</i></b>")
|
||||
to_chat(M, "<b>You hear a voice in your head... <i>[msg]</i></b>")
|
||||
|
||||
log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]")
|
||||
message_admins("<span class='boldnotice'>SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] : [msg]</span>", 1)
|
||||
@@ -588,22 +588,30 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
feedback_add_details("admin_verb","CCR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/client/proc/cmd_admin_delete(atom/O as obj|mob|turf in view())
|
||||
/client/proc/cmd_admin_delete(atom/A as obj|mob|turf in view())
|
||||
set category = "Admin"
|
||||
set name = "Delete"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(alert(src, "Are you sure you want to delete:\n[O]\nat ([O.x], [O.y], [O.z])?", "Confirmation", "Yes", "No") == "Yes")
|
||||
log_admin("[key_name(usr)] deleted [O] at ([O.x],[O.y],[O.z])")
|
||||
message_admins("[key_name_admin(usr)] deleted [O] at ([O.x],[O.y],[O.z])", 1)
|
||||
admin_delete(A)
|
||||
|
||||
/client/proc/admin_delete(datum/D)
|
||||
if(istype(D) && !D.can_vv_delete())
|
||||
to_chat(src, "[D] rejected your deletion")
|
||||
return
|
||||
var/atom/A = D
|
||||
var/coords = istype(A) ? "at ([A.x], [A.y], [A.z])" : ""
|
||||
if(alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", "Yes", "No") == "Yes")
|
||||
log_admin("[key_name(usr)] deleted [D][coords]")
|
||||
message_admins("[key_name_admin(usr)] deleted [D][coords]", 1)
|
||||
feedback_add_details("admin_verb","DEL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
if(istype(O, /turf))
|
||||
var/turf/T = O
|
||||
if(isturf(D))
|
||||
var/turf/T = D
|
||||
T.ChangeTurf(/turf/space)
|
||||
return
|
||||
qdel(O)
|
||||
else
|
||||
qdel(D)
|
||||
|
||||
/client/proc/cmd_admin_list_open_jobs()
|
||||
set category = "Admin"
|
||||
|
||||
Reference in New Issue
Block a user