//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 SUBSYSTEM_DEF(tickets) name = "Tickets" init_order = INIT_ORDER_TICKETS wait = 300 priority = FIRE_PRIORITY_TICKETS flags = SS_BACKGROUND var/list/allTickets var/ticketCounter = 1 /datum/controller/subsystem/tickets/Initialize() LAZYINITLIST(allTickets) return ..() /datum/controller/subsystem/tickets/fire() var/stales = checkStaleness() if(LAZYLEN(stales)) var/report for(var/num in stales) report += "[num], " message_adminTicket("Tickets [report] have been open for over [ADMIN_TICKET_TIMEOUT / 600] minutes. Changing status to stale.") /datum/controller/subsystem/tickets/stat_entry() ..("Tickets: [LAZYLEN(allTickets)]") /datum/controller/subsystem/tickets/proc/checkStaleness() var/stales = list() for(var/T in allTickets) var/datum/admin_ticket/ticket = T if(!(ticket.ticketState == ADMIN_TICKET_OPEN)) continue if(world.time > ticket.timeUntilStale && (!ticket.lastAdminResponse || !ticket.adminAssigned)) var/id = ticket.makeStale() stales += id return stales //Return the current ticket number ready to be called off. /datum/controller/subsystem/tickets/proc/getTicketCounter() return ticketCounter //Return the ticket counter and increment /datum/controller/subsystem/tickets/proc/getTicketCounterAndInc() . = ticketCounter ticketCounter++ return /datum/controller/subsystem/tickets/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/controller/subsystem/tickets/proc/newTicket(client/C, passedContent, 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.mob, "Your ticket #[existingTicket.ticketNum] remains open! Visit \"My tickets\" under the Admin Tab to view it.") return if(!title) title = passedContent var/datum/admin_ticket/T = new(title, passedContent) T.clientName = C T.locationSent = C.mob.loc.name T.mobControlled = C.mob //Inform the user that they have opened a ticket to_chat(C, "You have opened admin ticket number #[(SStickets.getTicketCounter() - 1)]! Please be patient and we will help you soon!") //Set ticket state with key N to open /datum/controller/subsystem/tickets/proc/openTicket(N) var/datum/admin_ticket/T = SStickets.allTickets[N] if(T.ticketState != ADMIN_TICKET_OPEN) T.ticketState = ADMIN_TICKET_OPEN return TRUE //Set ticket state with key N to resolved /datum/controller/subsystem/tickets/proc/resolveTicket(N) var/datum/admin_ticket/T = SStickets.allTickets[N] if(T.ticketState != ADMIN_TICKET_RESOLVED) T.ticketState = ADMIN_TICKET_RESOLVED return TRUE //Set ticket state with key N to closed /datum/controller/subsystem/tickets/proc/closeTicket(N) var/datum/admin_ticket/T = SStickets.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/controller/subsystem/tickets/proc/checkForOpenTicket(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/controller/subsystem/tickets/proc/checkForTicket(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/controller/subsystem/tickets/proc/returnClient(N) var/datum/admin_ticket/T = SStickets.allTickets[N] return T.clientName /datum/controller/subsystem/tickets/proc/assignAdminToTicket(client/C, var/N) var/datum/admin_ticket/T = SStickets.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 // 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 /datum/admin_ticket/New(tit, cont) title = tit content = list() content += cont timeOpened = worldtime2text() timeUntilStale = world.time + ADMIN_TICKET_TIMEOUT setCooldownPeriod() ticketNum = SStickets.getTicketCounterAndInc() ticketState = ADMIN_TICKET_OPEN SStickets.allTickets += src //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(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 "OPEN" if(ADMIN_TICKET_RESOLVED) return "RESOLVED" if(ADMIN_TICKET_CLOSED) return "CLOSED" if(ADMIN_TICKET_STALE) return "STALE" //Assign the client passed to var/adminAsssigned /datum/admin_ticket/proc/assignAdmin(client/C) if(!C) return adminAssigned = C return TRUE /datum/admin_ticket/proc/addResponse(client/C, msg) if(C.holder) setLastAdminResponse(C) msg = "[C]: [msg]" content += msg /datum/admin_ticket/proc/makeStale() ticketState = ADMIN_TICKET_STALE return ticketNum /* UI STUFF */ /datum/controller/subsystem/tickets/proc/returnUI(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 += "
" dat += "| Control | Ticket |
|---|---|
| ResolveDetails #[ticket.ticketNum] ([ticket.timeOpened]) [ticket.ticketState == ADMIN_TICKET_STALE ? "STALE" : ""] | [ticket.title] |
| ResolveDetails #[ticket.ticketNum] ([ticket.timeOpened]) | [ticket.title] |
| ResolveDetails #[ticket.ticketNum] ([ticket.timeOpened]) | [ticket.title] |
| [T.title] |
| [T.content[i]] |
Ticket #[T.ticketNum] |
| [T.content[i]] |