mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 02:09:41 +00:00
[MIRROR] [MAJOR CHANGE] Admin rank datum (#10316)
Co-authored-by: Selis <12716288+ItsSelis@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
86d5086018
commit
a57d38624d
@@ -1,22 +1,29 @@
|
||||
-- Table structure for table `erro_admin`
|
||||
CREATE TABLE `erro_admin` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
CREATE TABLE `admin` (
|
||||
`ckey` varchar(32) NOT NULL,
|
||||
`rank` varchar(32) NOT NULL DEFAULT 'Administrator',
|
||||
`level` int(2) NOT NULL DEFAULT '0',
|
||||
`flags` int(16) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
|
||||
`rank` varchar(32) NOT NULL,
|
||||
`feedback` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`ckey`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- Table structure for table `erro_admin_log`
|
||||
CREATE TABLE `erro_admin_log` (
|
||||
CREATE TABLE `admin_log` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`datetime` datetime NOT NULL,
|
||||
`round_id` int(11) unsigned NULL,
|
||||
`adminckey` varchar(32) NOT NULL,
|
||||
`adminip` varchar(18) NOT NULL,
|
||||
`log` text NOT NULL,
|
||||
`adminip` int(10) unsigned NOT NULL,
|
||||
`operation` enum('add admin','remove admin','change admin rank','add rank','remove rank','change rank flags') NOT NULL,
|
||||
`target` varchar(32) NOT NULL,
|
||||
`log` varchar(1000) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE `admin_ranks` (
|
||||
`rank` varchar(32) NOT NULL,
|
||||
`flags` mediumint(5) unsigned NOT NULL,
|
||||
`exclude_flags` mediumint(5) unsigned NOT NULL,
|
||||
`can_edit_flags` mediumint(5) unsigned NOT NULL,
|
||||
PRIMARY KEY (`rank`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- Table structure for table `erro_ban`
|
||||
CREATE TABLE `erro_ban` (
|
||||
|
||||
15
SQL/starter_admin_ranks.sql
Normal file
15
SQL/starter_admin_ranks.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
INSERT INTO admin_ranks
|
||||
(rank, flags, exclude_flags, can_edit_flags)
|
||||
VALUES
|
||||
('Host', 65535, 0, 65535),
|
||||
('Head Admin', 65535, 0, 65535),
|
||||
('Game Master', 65535, 0, 65535),
|
||||
('Moderator', 8192, 0, 0),
|
||||
('Game Admin', 8191, 0, 0),
|
||||
('Dev Mod', 13937, 0, 0),
|
||||
('Developer', 5745, 0, 0),
|
||||
('Badmin', 5727, 0, 0),
|
||||
('Trial Admin', 5638, 0, 0),
|
||||
('Admin Candidate', 2, 0, 0),
|
||||
('Retired Admin', 258, 0, 0),
|
||||
('Admin Observer', 0, 0, 0);
|
||||
4
code/__defines/_bitfields.dm
Normal file
4
code/__defines/_bitfields.dm
Normal file
@@ -0,0 +1,4 @@
|
||||
#define DEFINE_BITFIELD(_variable, _flags) /datum/bitfield/##_variable { \
|
||||
flags = ##_flags; \
|
||||
variable = #_variable; \
|
||||
}
|
||||
@@ -22,25 +22,29 @@
|
||||
|
||||
#define ROUNDSTART_LOGOUT_REPORT_TIME 6000 // Amount of time (in deciseconds) after the rounds starts, that the player disconnect report is issued.
|
||||
|
||||
// Admin permissions.
|
||||
#define R_BUILDMODE 0x1
|
||||
#define R_ADMIN 0x2
|
||||
#define R_BAN 0x4
|
||||
#define R_FUN 0x8
|
||||
#define R_SERVER 0x10
|
||||
#define R_DEBUG 0x20
|
||||
#define R_POSSESS 0x40
|
||||
#define R_PERMISSIONS 0x80
|
||||
#define R_STEALTH 0x100
|
||||
#define R_REJUVINATE 0x200
|
||||
#define R_VAREDIT 0x400
|
||||
#define R_SOUNDS 0x800
|
||||
#define R_SPAWN 0x1000
|
||||
#define R_MOD 0x2000
|
||||
#define R_EVENT 0x4000
|
||||
#define R_HOST 0x8000 //higher than this will overflow
|
||||
//Admin Permissions
|
||||
/// Used for signifying that all admins can use this regardless of actual permissions
|
||||
#define R_NONE NONE
|
||||
#define R_BUILDMODE (1<<0)
|
||||
#define R_ADMIN (1<<1)
|
||||
#define R_BAN (1<<2)
|
||||
#define R_FUN (1<<3)
|
||||
#define R_SERVER (1<<4)
|
||||
#define R_DEBUG (1<<5)
|
||||
#define R_POSSESS (1<<6)
|
||||
#define R_PERMISSIONS (1<<7)
|
||||
#define R_STEALTH (1<<8)
|
||||
#define R_REJUVINATE (1<<9)
|
||||
#define R_VAREDIT (1<<10)
|
||||
#define R_SOUNDS (1<<11)
|
||||
#define R_SPAWN (1<<12)
|
||||
#define R_MOD (1<<13)
|
||||
#define R_EVENT (1<<14)
|
||||
#define R_HOST (1<<15) //higher than this will overflow
|
||||
|
||||
#define R_MAXPERMISSION 0x8000 // This holds the maximum value for a permission. It is used in iteration, so keep it updated.
|
||||
#define R_DEFAULT R_NONE
|
||||
|
||||
#define R_EVERYTHING (1<<16)-1 //the sum of all other rank permissions, used for +EVERYTHING
|
||||
|
||||
#define SMITE_BREAKLEGS "Break Legs"
|
||||
#define SMITE_BLUESPACEARTILLERY "Bluespace Artillery"
|
||||
@@ -72,3 +76,6 @@
|
||||
#define AHELP_ACTIVE 1
|
||||
#define AHELP_CLOSED 2
|
||||
#define AHELP_RESOLVED 3
|
||||
|
||||
/// A value for /datum/admins/cached_feedback_link to indicate empty, rather than unobtained
|
||||
#define NO_FEEDBACK_LINK "no_feedback_link"
|
||||
|
||||
94
code/__defines/admin_verb.dm
Normal file
94
code/__defines/admin_verb.dm
Normal file
@@ -0,0 +1,94 @@
|
||||
/client/CanProcCall(procname)
|
||||
if(findtext(procname, "__avd_") == 1)
|
||||
message_admins("[key_name_admin(usr)] attempted to directly call admin verb '[procname]'.")
|
||||
log_admin("[key_name(usr)] attempted to directly call admin verb '[procname]'.")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* This is the only macro you should use to define admin verbs.
|
||||
* It will define the verb and the verb holder for you.
|
||||
* Using it is very simple:
|
||||
* ADMIN_VERB(verb_path, R_PERM, "Name", "Description", "Admin.Category", args...)
|
||||
* This sets up all of the above and also acts as syntatic sugar as a verb delcaration for the verb itself.
|
||||
* Note that the verb args have an injected `client/user` argument that is the user that called the verb.
|
||||
* Do not use usr in your verb; technically you can but I'll kill you.
|
||||
*/
|
||||
#define _ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, show_in_context_menu, verb_args...) \
|
||||
/datum/admin_verb/##verb_path_name \
|
||||
{ \
|
||||
name = ##verb_name; \
|
||||
description = ##verb_desc; \
|
||||
category = ##verb_category; \
|
||||
permissions = ##verb_permissions; \
|
||||
verb_path = /client/proc/__avd_##verb_path_name; \
|
||||
}; \
|
||||
/client/proc/__avd_##verb_path_name(##verb_args) \
|
||||
{ \
|
||||
set name = ##verb_name; \
|
||||
set desc = ##verb_desc; \
|
||||
set hidden = FALSE; /* this is explicitly needed as the proc begins with an underscore */ \
|
||||
set popup_menu = ##show_in_context_menu; \
|
||||
set category = ##verb_category; \
|
||||
var/list/_verb_args = list(usr, /datum/admin_verb/##verb_path_name); \
|
||||
_verb_args += args; \
|
||||
SSadmin_verbs.dynamic_invoke_verb(arglist(_verb_args)); \
|
||||
}; \
|
||||
/datum/admin_verb/##verb_path_name/__avd_do_verb(client/user, ##verb_args)
|
||||
|
||||
#define ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, verb_args...) \
|
||||
_ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, FALSE, ##verb_args)
|
||||
|
||||
#define ADMIN_VERB_ONLY_CONTEXT_MENU(verb_path_name, verb_permissions, verb_name, verb_args...) \
|
||||
_ADMIN_VERB(verb_path_name, verb_permissions, verb_name, ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, TRUE, ##verb_args)
|
||||
|
||||
#define ADMIN_VERB_AND_CONTEXT_MENU(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, verb_args...) \
|
||||
_ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, TRUE, ##verb_args)
|
||||
|
||||
/// Used to define a special check to determine if the admin verb should exist at all. Useful for verbs such as play sound which require configuration.
|
||||
#define ADMIN_VERB_CUSTOM_EXIST_CHECK(verb_path_name) \
|
||||
/datum/admin_verb/##verb_path_name/__avd_check_should_exist()
|
||||
|
||||
/// Used to define the visibility flag of the verb. If the admin does not have this flag enabled they will not see the verb.
|
||||
#define ADMIN_VERB_VISIBILITY(verb_path_name, verb_visibility) /datum/admin_verb/##verb_path_name/visibility_flag = ##verb_visibility
|
||||
|
||||
// These are put here to prevent the "procedure override precedes definition" error.
|
||||
/datum/admin_verb/proc/__avd_get_verb_path()
|
||||
CRASH("__avd_get_verb_path not defined. use the macro")
|
||||
/datum/admin_verb/proc/__avd_do_verb(...)
|
||||
CRASH("__avd_do_verb not defined. use the macro")
|
||||
/datum/admin_verb/proc/__avd_check_should_exist()
|
||||
return TRUE
|
||||
|
||||
/*
|
||||
* This is an example of how to use the above macro:
|
||||
* ```
|
||||
* ADMIN_VERB(name_of_verb, R_ADMIN, "Verb Name", "Verb Desc", "Verb Category", mob/target in world)
|
||||
* to_chat(user, "Hello!")
|
||||
* ```
|
||||
* Note the implied `client/user` argument that is injected into the verb.
|
||||
* Also note that byond is shit and you cannot multi-line the macro call.
|
||||
*/
|
||||
|
||||
/// Use this to mark your verb as not having a description. Should ONLY be used if you are also hiding the verb!
|
||||
#define ADMIN_VERB_NO_DESCRIPTION ""
|
||||
/// Used to verbs you do not want to show up in the master verb panel.
|
||||
#define ADMIN_CATEGORY_HIDDEN null
|
||||
|
||||
// Admin verb categories
|
||||
#define ADMIN_CATEGORY_MAIN "Admin"
|
||||
#define ADMIN_CATEGORY_EVENTS "Admin.Events"
|
||||
#define ADMIN_CATEGORY_FUN "Admin.Fun"
|
||||
#define ADMIN_CATEGORY_GAME "Admin.Game"
|
||||
#define ADMIN_CATEGORY_SHUTTLE "Admin.Shuttle"
|
||||
|
||||
// Special categories that are separated
|
||||
#define ADMIN_CATEGORY_DEBUG "Debug"
|
||||
#define ADMIN_CATEGORY_SERVER "Server"
|
||||
#define ADMIN_CATEGORY_OBJECT "Object"
|
||||
#define ADMIN_CATEGORY_MAPPING "Mapping"
|
||||
#define ADMIN_CATEGORY_PROFILE "Profile"
|
||||
#define ADMIN_CATEGORY_IPINTEL "Admin.IPIntel"
|
||||
|
||||
// Visibility flags
|
||||
#define ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG "Map-Debug"
|
||||
2
code/__defines/dcs/signals/signals_client.dm
Normal file
2
code/__defines/dcs/signals/signals_client.dm
Normal file
@@ -0,0 +1,2 @@
|
||||
/// Called after a client logs into a mob: (mob)
|
||||
#define COMSIG_CLIENT_MOB_LOGIN "client_mob_changed"
|
||||
@@ -118,6 +118,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
|
||||
// The numbers just define the ordering, they are meaningless otherwise.
|
||||
#define INIT_ORDER_TITLE 99 //CHOMPEdit
|
||||
#define INIT_ORDER_SERVER_MAINT 93
|
||||
#define INIT_ORDER_ADMIN_VERBS 84 // needs to be pretty high, admins can't do much without it
|
||||
#define INIT_ORDER_WEBHOOKS 50
|
||||
#define INIT_ORDER_SQLITE 41
|
||||
#define INIT_ORDER_GARBAGE 40
|
||||
|
||||
@@ -1,41 +1,77 @@
|
||||
GLOBAL_LIST_INIT(bitfields, list(
|
||||
"datum_flags" = list(
|
||||
"DF_VAR_EDITED" = DF_VAR_EDITED,
|
||||
"DF_ISPROCESSING" = DF_ISPROCESSING
|
||||
),
|
||||
"appearance_flags" = list(
|
||||
"KEEP_APART" = KEEP_APART,
|
||||
"KEEP_TOGETHER" = KEEP_TOGETHER,
|
||||
"LONG_GLIDE" = LONG_GLIDE,
|
||||
"NO_CLIENT_COLOR" = NO_CLIENT_COLOR,
|
||||
"PIXEL_SCALE" = PIXEL_SCALE,
|
||||
"PLANE_MASTER" = PLANE_MASTER,
|
||||
"RESET_ALPHA" = RESET_ALPHA,
|
||||
"RESET_COLOR" = RESET_COLOR,
|
||||
"RESET_TRANSFORM" = RESET_TRANSFORM,
|
||||
"TILE_BOUND" = TILE_BOUND,
|
||||
"PASS_MOUSE" = PASS_MOUSE,
|
||||
"TILE_MOVER" = TILE_MOVER
|
||||
),
|
||||
"vis_flags" = list(
|
||||
"VIS_HIDE" = VIS_HIDE,
|
||||
"VIS_INHERIT_DIR" = VIS_INHERIT_DIR,
|
||||
"VIS_INHERIT_ICON" = VIS_INHERIT_ICON,
|
||||
"VIS_INHERIT_ICON_STATE" = VIS_INHERIT_ICON_STATE,
|
||||
"VIS_INHERIT_ID" = VIS_INHERIT_ID,
|
||||
"VIS_INHERIT_LAYER" = VIS_INHERIT_LAYER,
|
||||
"VIS_INHERIT_PLANE" = VIS_INHERIT_PLANE,
|
||||
"VIS_UNDERLAY" = VIS_UNDERLAY,
|
||||
),
|
||||
"sight" = list(
|
||||
"BLIND" = BLIND,
|
||||
"SEE_BLACKNESS" = SEE_BLACKNESS,
|
||||
"SEE_INFRA" = SEE_INFRA,
|
||||
"SEE_MOBS" = SEE_MOBS,
|
||||
"SEE_OBJS" = SEE_OBJS,
|
||||
"SEE_PIXELS" = SEE_PIXELS,
|
||||
"SEE_SELF" = SEE_SELF,
|
||||
"SEE_THRU" = SEE_THRU,
|
||||
"SEE_TURFS" = SEE_TURFS,
|
||||
),
|
||||
GLOBAL_LIST_INIT(bitfields, generate_bitfields())
|
||||
|
||||
/// Specifies a bitfield for smarter debugging
|
||||
/datum/bitfield
|
||||
/// The variable name that contains the bitfield
|
||||
var/variable
|
||||
|
||||
/// An associative list of the readable flag and its true value
|
||||
var/list/flags
|
||||
|
||||
/// Turns /datum/bitfield subtypes into a list for use in debugging
|
||||
/proc/generate_bitfields()
|
||||
var/list/bitfields = list()
|
||||
for (var/_bitfield in subtypesof(/datum/bitfield))
|
||||
var/datum/bitfield/bitfield = new _bitfield
|
||||
bitfields[bitfield.variable] = bitfield.flags
|
||||
return bitfields
|
||||
|
||||
DEFINE_BITFIELD(admin_flags, list(
|
||||
"ADMIN" = R_ADMIN,
|
||||
"REJUVINATE" = R_REJUVINATE,
|
||||
"BAN" = R_BAN,
|
||||
"BUILDMODE" = R_BUILDMODE,
|
||||
"DEBUG" = R_DEBUG,
|
||||
"FUN" = R_FUN,
|
||||
"PERMISSIONS" = R_PERMISSIONS,
|
||||
"MOD" = R_MOD,
|
||||
"POSSESS" = R_POSSESS,
|
||||
"SERVER" = R_SERVER,
|
||||
"SOUNDS" = R_SOUNDS,
|
||||
"SPAWN" = R_SPAWN,
|
||||
"STEALTH" = R_STEALTH,
|
||||
"VAREDIT" = R_VAREDIT,
|
||||
))
|
||||
|
||||
DEFINE_BITFIELD(datum_flags, list(
|
||||
"DF_VAR_EDITED" = DF_VAR_EDITED,
|
||||
"DF_ISPROCESSING" = DF_ISPROCESSING
|
||||
))
|
||||
|
||||
DEFINE_BITFIELD(appearance_flags, list(
|
||||
"KEEP_APART" = KEEP_APART,
|
||||
"KEEP_TOGETHER" = KEEP_TOGETHER,
|
||||
"LONG_GLIDE" = LONG_GLIDE,
|
||||
"NO_CLIENT_COLOR" = NO_CLIENT_COLOR,
|
||||
"PIXEL_SCALE" = PIXEL_SCALE,
|
||||
"PLANE_MASTER" = PLANE_MASTER,
|
||||
"RESET_ALPHA" = RESET_ALPHA,
|
||||
"RESET_COLOR" = RESET_COLOR,
|
||||
"RESET_TRANSFORM" = RESET_TRANSFORM,
|
||||
"TILE_BOUND" = TILE_BOUND,
|
||||
"PASS_MOUSE" = PASS_MOUSE,
|
||||
"TILE_MOVER" = TILE_MOVER
|
||||
))
|
||||
|
||||
DEFINE_BITFIELD(vis_flags, list(
|
||||
"VIS_HIDE" = VIS_HIDE,
|
||||
"VIS_INHERIT_DIR" = VIS_INHERIT_DIR,
|
||||
"VIS_INHERIT_ICON" = VIS_INHERIT_ICON,
|
||||
"VIS_INHERIT_ICON_STATE" = VIS_INHERIT_ICON_STATE,
|
||||
"VIS_INHERIT_ID" = VIS_INHERIT_ID,
|
||||
"VIS_INHERIT_LAYER" = VIS_INHERIT_LAYER,
|
||||
"VIS_INHERIT_PLANE" = VIS_INHERIT_PLANE,
|
||||
"VIS_UNDERLAY" = VIS_UNDERLAY,
|
||||
))
|
||||
|
||||
DEFINE_BITFIELD(sight, list(
|
||||
"BLIND" = BLIND,
|
||||
"SEE_BLACKNESS" = SEE_BLACKNESS,
|
||||
"SEE_INFRA" = SEE_INFRA,
|
||||
"SEE_MOBS" = SEE_MOBS,
|
||||
"SEE_OBJS" = SEE_OBJS,
|
||||
"SEE_PIXELS" = SEE_PIXELS,
|
||||
"SEE_SELF" = SEE_SELF,
|
||||
"SEE_THRU" = SEE_THRU,
|
||||
"SEE_TURFS" = SEE_TURFS,
|
||||
))
|
||||
|
||||
9
code/_helpers/admin.dm
Normal file
9
code/_helpers/admin.dm
Normal file
@@ -0,0 +1,9 @@
|
||||
/// Returns if the given client is an admin, REGARDLESS of if they're deadminned or not.
|
||||
///proc/is_admin(client/client)
|
||||
// return !isnull(GLOB.admin_datums[client.ckey]) || !isnull(GLOB.deadmins[client.ckey])
|
||||
|
||||
/// Sends a message in the event that someone attempts to elevate their permissions through invoking a certain proc.
|
||||
/proc/alert_to_permissions_elevation_attempt(mob/user)
|
||||
var/message = " has tried to elevate permissions!"
|
||||
message_admins(key_name_admin(user) + message)
|
||||
log_admin(key_name(user) + message)
|
||||
@@ -352,7 +352,7 @@
|
||||
. += "<a href='byond://?priv_msg=\ref[C]'>"
|
||||
|
||||
if(C && C.holder && C.holder.fakekey)
|
||||
. += C.holder.rank // CHOMPEdit: Stealth mode displays staff rank in PM Messages
|
||||
. += C.holder.rank_names() // CHOMPEdit: Stealth mode displays staff rank in PM Messages
|
||||
else
|
||||
. += key
|
||||
|
||||
|
||||
@@ -631,3 +631,14 @@ GLOBAL_LIST_EMPTY(text_tag_cache)
|
||||
/proc/sanitize_css_class_name(name)
|
||||
var/static/regex/regex = new(@"[^a-zA-Z0-9]","g")
|
||||
return replacetext(name, regex, "")
|
||||
|
||||
//finds the first occurrence of one of the characters from needles argument inside haystack
|
||||
//it may appear this can be optimised, but it really can't. findtext() is so much faster than anything you can do in byondcode.
|
||||
//stupid byond :(
|
||||
/proc/findchar(haystack, needles, start=1, end=0)
|
||||
var/temp
|
||||
var/len = length(needles)
|
||||
for(var/i=1, i<=len, i++)
|
||||
temp = findtextEx(haystack, ascii2text(text2ascii(needles,i)), start, end) //Note: ascii2text(text2ascii) is faster than copytext()
|
||||
if(temp) end = temp
|
||||
return end
|
||||
|
||||
@@ -438,8 +438,17 @@
|
||||
|
||||
/datum/config_entry/flag/no_click_cooldown
|
||||
|
||||
/// Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt
|
||||
/datum/config_entry/flag/admin_legacy_system
|
||||
/datum/config_entry/flag/admin_legacy_system //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/flag/protect_legacy_admins //Stops any admins loaded by the legacy system from having their rank edited by the permissions panel
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/flag/protect_legacy_ranks //Stops any ranks loaded by the legacy system from having their flags edited by the permissions panel
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/flag/load_legacy_ranks_only //Loads admin ranks only from legacy admin_ranks.txt, while enabled ranks are mirrored to the database
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/// Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt
|
||||
/datum/config_entry/flag/ban_legacy_system
|
||||
@@ -721,3 +730,5 @@
|
||||
/// The endpoint for the chat to fetch the chatlogs from (for example, the last 2500 messages on init for the history)
|
||||
/// REQUIRES chatlog_database_backend to be enabled
|
||||
/datum/config_entry/string/chatlog_database_api_endpoint
|
||||
|
||||
/datum/config_entry/flag/forbid_admin_profiling
|
||||
|
||||
@@ -53,7 +53,7 @@ SUBSYSTEM_DEF(persistence)
|
||||
return
|
||||
|
||||
var/list/dat = list("<table width = '100%'>")
|
||||
var/can_modify = check_rights(R_ADMIN, 0, user)
|
||||
var/can_modify = check_rights_for(user.client, (R_ADMIN|R_DEBUG))
|
||||
for(var/thing in persistence_datums)
|
||||
var/datum/persistent/P = persistence_datums[thing]
|
||||
if(P.has_admin_data)
|
||||
|
||||
@@ -175,7 +175,9 @@ SUBSYSTEM_DEF(statpanels)
|
||||
/datum/controller/subsystem/statpanels/proc/set_tickets_tab(client/target)
|
||||
/* CHOMPRemove Start, our tickets are handled differently
|
||||
var/list/tickets = list()
|
||||
if(check_rights(R_ADMIN|R_SERVER|R_MOD,FALSE,target)) //Prevents non-staff from opening the list of ahelp tickets
|
||||
if(check_rights_for(target, R_ADMIN|R_SERVER|R_MOD)) //Prevents non-staff from opening the list of ahelp tickets
|
||||
tickets += GLOB.ahelp_tickets.stat_entry(target)
|
||||
tickets += GLOB.mhelp_tickets.stat_entry(target)
|
||||
*/// CHOMPRemove End
|
||||
var/list/tickets = GLOB.tickets.stat_entry(target) // CHOMPEdit
|
||||
target.stat_panel.send_message("update_tickets", tickets)
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
<html>
|
||||
<meta charset=ISO-8859-1">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
[head_content]
|
||||
</head>
|
||||
<body scroll=auto>
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
set name = "Release Virus"
|
||||
set desc = "Release a pre-set virus."
|
||||
|
||||
if(!is_admin())
|
||||
if(!check_rights(R_FUN|R_EVENT))
|
||||
return FALSE
|
||||
|
||||
var/disease = tgui_input_list(usr, "Choose virus", "Viruses", subtypesof(/datum/disease), subtypesof(/datum/disease))
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
var/database/query/last_query = null
|
||||
|
||||
/datum/managed_browser/feedback_viewer/New(client/new_client)
|
||||
if(!check_rights(R_ADMIN|R_DEBUG|R_EVENT, new_client)) // Just in case someone figures out a way to spawn this as non-staff.
|
||||
if(!check_rights_for(new_client, R_ADMIN|R_DEBUG|R_EVENT)) // Just in case someone figures out a way to spawn this as non-staff.
|
||||
message_admins("[new_client] tried to view feedback with insufficent permissions.")
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -403,7 +403,7 @@
|
||||
take_uplink()
|
||||
memory = null//Remove any memory they may have had.
|
||||
if("crystals")
|
||||
if (usr.client.holder.rights & R_FUN)
|
||||
if (check_rights_for(usr.client, R_FUN))
|
||||
// var/obj/item/uplink/hidden/suplink = find_syndicate_uplink() No longer needed, uses stored in mind
|
||||
var/crystals
|
||||
crystals = tcrystals
|
||||
|
||||
@@ -418,7 +418,7 @@ var/global/datum/controller/occupations/job_master
|
||||
permitted = 1
|
||||
|
||||
// Check if they're whitelisted for this gear (in alien whitelist? seriously?)
|
||||
if(G.whitelisted && !is_alien_whitelisted(H, GLOB.all_species[G.whitelisted]))
|
||||
if(G.whitelisted && !is_alien_whitelisted(H.client, GLOB.all_species[G.whitelisted]))
|
||||
permitted = 0
|
||||
|
||||
// If they aren't, tell them
|
||||
|
||||
@@ -46,13 +46,13 @@ GLOBAL_LIST_EMPTY(alien_whitelist) // CHOMPEdit - Managed Globals
|
||||
GLOB.alien_whitelist[key] = our_whitelists // CHOMPEdit - Managed Globals
|
||||
our_whitelists += left_and_right[2]
|
||||
|
||||
/proc/is_alien_whitelisted(mob/M, var/datum/species/species)
|
||||
/proc/is_alien_whitelisted(client/C, var/datum/species/species)
|
||||
//They are admin or the whitelist isn't in use
|
||||
if(whitelist_overrides(M))
|
||||
if(whitelist_overrides(C))
|
||||
return TRUE
|
||||
|
||||
//You did something wrong
|
||||
if(!M || !species)
|
||||
if(!C || !species)
|
||||
return FALSE
|
||||
|
||||
//The species isn't even whitelisted
|
||||
@@ -60,7 +60,7 @@ GLOBAL_LIST_EMPTY(alien_whitelist) // CHOMPEdit - Managed Globals
|
||||
return TRUE
|
||||
|
||||
//Search the whitelist
|
||||
var/list/our_whitelists = GLOB.alien_whitelist[M.ckey] // CHOMPEdit - Managed Globals
|
||||
var/list/our_whitelists = GLOB.alien_whitelist[C.ckey] // CHOMPEdit - Managed Globals
|
||||
if("All" in our_whitelists)
|
||||
return TRUE
|
||||
if(species.name in our_whitelists)
|
||||
@@ -112,10 +112,14 @@ GLOBAL_LIST_EMPTY(alien_whitelist) // CHOMPEdit - Managed Globals
|
||||
if(findtext(s,"[M.ckey] - All"))
|
||||
return 1
|
||||
|
||||
/proc/whitelist_overrides(mob/M)
|
||||
/proc/whitelist_overrides(client/C)
|
||||
if(!CONFIG_GET(flag/usealienwhitelist))
|
||||
return TRUE
|
||||
if(check_rights(R_ADMIN|R_EVENT, 0, M))
|
||||
if(ismob(C)) //Someone fed a mob into this by mistake. Bad, but we planned ahead for these mistakes.
|
||||
var/mob/mob = C
|
||||
C = mob.client
|
||||
|
||||
if(check_rights_for(C, R_ADMIN|R_EVENT|R_DEBUG))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
return
|
||||
|
||||
//No whitelist
|
||||
if(!is_alien_whitelisted(user, GLOB.all_species[user.client.prefs.species]))
|
||||
if(!is_alien_whitelisted(user.client, GLOB.all_species[user.client.prefs.species]))
|
||||
to_chat(user, span_warning("You cannot use this spawnpoint to spawn as a species you are not whitelisted for!"))
|
||||
return
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
|
||||
/obj/structure/mirror/raider/attack_hand(var/mob/living/carbon/human/user)
|
||||
if(istype(get_area(src),/area/syndicate_mothership))
|
||||
if(istype(user) && user.mind && user.mind.special_role == "Raider" && user.species.name != SPECIES_VOX && is_alien_whitelisted(user, SPECIES_VOX))
|
||||
if(istype(user) && user.mind && user.mind.special_role == "Raider" && user.species.name != SPECIES_VOX && is_alien_whitelisted(user.client, SPECIES_VOX))
|
||||
var/choice = tgui_alert(user, "Do you wish to become a true Vox of the Shoal? This is not reversible.", "Become Vox?", list("No","Yes"))
|
||||
if(choice && choice == "Yes")
|
||||
var/mob/living/carbon/human/vox/vox = new(get_turf(src),SPECIES_VOX)
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])
|
||||
|
||||
load_admins()
|
||||
|
||||
ConfigLoaded()
|
||||
makeDatumRefLists()
|
||||
VgsNew()
|
||||
@@ -165,7 +167,7 @@ var/world_topic_spam_protect_time = world.timeofday
|
||||
if(C.holder)
|
||||
if(C.holder.fakekey)
|
||||
continue
|
||||
admins[C.key] = C.holder.rank
|
||||
admins[C.key] = C.holder.rank_names()
|
||||
players += C.key
|
||||
if(isliving(C.mob))
|
||||
active++
|
||||
@@ -536,7 +538,7 @@ var/world_topic_spam_protect_time = world.timeofday
|
||||
continue
|
||||
|
||||
var/title = "Moderator"
|
||||
var/rights = admin_ranks[title]
|
||||
var/rights = GLOB.admin_ranks[title]
|
||||
|
||||
var/ckey = copytext(line, 1, length(line)+1)
|
||||
var/datum/admins/D = new /datum/admins(title, rights, ckey)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef OVERRIDE_BAN_SYSTEM
|
||||
//Blocks an attempt to connect before even creating our client datum thing.
|
||||
/world/IsBanned(key,address,computer_id)
|
||||
if(ckey(key) in admin_datums)
|
||||
if(ckey(key) in GLOB.admin_datums)
|
||||
return ..()
|
||||
|
||||
//Guest Checking
|
||||
|
||||
@@ -7,7 +7,7 @@ var/global/floorIsLava = 0
|
||||
//log_adminwarn(msg) //log_and_message_admins is for this
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if((R_ADMIN|R_MOD) & C.holder.rights)
|
||||
if(check_rights_for(C, (R_ADMIN|R_MOD|R_SERVER)))
|
||||
to_chat(C,
|
||||
type = MESSAGE_TYPE_ADMINLOG,
|
||||
html = msg,
|
||||
@@ -16,7 +16,7 @@ var/global/floorIsLava = 0
|
||||
/proc/msg_admin_attack(var/text) //Toggleable Attack Messages
|
||||
var/rendered = span_filter_attacklog(span_log_message(span_prefix("ATTACK:") + span_message("[text]")))
|
||||
for(var/client/C in GLOB.admins)
|
||||
if((R_ADMIN|R_MOD) & C.holder.rights)
|
||||
if(check_rights_for(C, (R_ADMIN|R_MOD)))
|
||||
if(C.prefs?.read_preference(/datum/preference/toggle/show_attack_logs))
|
||||
var/msg = rendered
|
||||
to_chat(C,
|
||||
@@ -26,8 +26,16 @@ var/global/floorIsLava = 0
|
||||
|
||||
/proc/admin_notice(var/message, var/rights)
|
||||
for(var/mob/M in mob_list)
|
||||
if(check_rights(rights, 0, M))
|
||||
to_chat(M,message)
|
||||
var/C = M.client
|
||||
|
||||
if(!C)
|
||||
return
|
||||
|
||||
if(!(istype(C, /client)))
|
||||
return
|
||||
|
||||
if(check_rights_for(C, rights))
|
||||
to_chat(C, message)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////Panels
|
||||
|
||||
@@ -49,7 +57,7 @@ var/global/floorIsLava = 0
|
||||
body += "<body>Options panel for" + span_bold("[M]")
|
||||
if(M.client)
|
||||
body += " played by " + span_bold("[M.client]")
|
||||
body += "\[<A href='byond://?src=\ref[src];[HrefToken()];editrights=show'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
|
||||
body += "\[<A href='byond://?src=\ref[src];[HrefToken()];editrights=show'>[M.client.holder ? M.client.holder.rank_names() : "Player"]</A>\]"
|
||||
|
||||
if(isnewplayer(M))
|
||||
body += span_bold(" Hasn't Entered Game")
|
||||
@@ -1353,7 +1361,7 @@ var/datum/announcement/minor/admin_min_announcer = new
|
||||
if(istype(whom, /mob))
|
||||
M = whom
|
||||
C = M.client
|
||||
if(R_HOST & C.holder.rights)
|
||||
if(check_rights_for(C, R_HOST))
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
@@ -1562,12 +1570,12 @@ var/datum/announcement/minor/admin_min_announcer = new
|
||||
if(P.sender) // sent as a reply
|
||||
log_admin("[key_name(src.owner)] replied to a fax message from [key_name(P.sender)]")
|
||||
for(var/client/C in GLOB.admins)
|
||||
if((R_ADMIN | R_MOD | R_EVENT) & C.holder.rights)
|
||||
if(check_rights_for(C, (R_ADMIN | R_MOD | R_EVENT)))
|
||||
to_chat(C, span_log_message("[span_prefix("FAX LOG:")][key_name_admin(src.owner)] replied to a fax message from [key_name_admin(P.sender)] (<a href='byond://?_src_=holder;[HrefToken()];AdminFaxView=\ref[rcvdcopy]'>VIEW</a>)"))
|
||||
else
|
||||
log_admin("[key_name(src.owner)] has sent a fax message to [destination.department]")
|
||||
for(var/client/C in GLOB.admins)
|
||||
if((R_ADMIN | R_MOD | R_EVENT) & C.holder.rights)
|
||||
if(check_rights_for(C, (R_ADMIN | R_MOD | R_EVENT)))
|
||||
to_chat(C, span_log_message("[span_prefix("FAX LOG:")][key_name_admin(src.owner)] has sent a fax message to [destination.department] (<a href='byond://?_src_=holder;[HrefToken()];AdminFaxView=\ref[rcvdcopy]'>VIEW</a>)"))
|
||||
|
||||
var/plaintext_title = P.sender ? "replied to [key_name(P.sender)]'s fax" : "sent a fax message to [destination.department]"
|
||||
@@ -1590,3 +1598,18 @@ var/datum/announcement/minor/admin_min_announcer = new
|
||||
qdel(P)
|
||||
faxreply = null
|
||||
return
|
||||
|
||||
/datum/admins/proc/set_uplink(mob/living/carbon/human/H as mob)
|
||||
set category = "Debug.Events"
|
||||
set name = "Set Uplink"
|
||||
set desc = "Allows admins to set up an uplink on a character. This will be required for a character to use telecrystals."
|
||||
set popup_menu = FALSE
|
||||
|
||||
if(check_rights(R_ADMIN|R_DEBUG))
|
||||
traitors.spawn_uplink(H)
|
||||
H.mind.tcrystals = DEFAULT_TELECRYSTAL_AMOUNT
|
||||
H.mind.accept_tcrystals = 1
|
||||
var/msg = "[key_name(usr)] has given [H.ckey] an uplink."
|
||||
message_admins(msg)
|
||||
else
|
||||
to_chat(usr, "You do not have access to this command.")
|
||||
|
||||
@@ -1,175 +1,398 @@
|
||||
var/list/admin_ranks = list() //list of all ranks with associated rights
|
||||
GLOBAL_LIST_EMPTY(admin_ranks) //list of all admin_rank datums
|
||||
GLOBAL_PROTECT(admin_ranks)
|
||||
|
||||
//load our rank - > rights associations
|
||||
/proc/load_admin_ranks()
|
||||
admin_ranks.Cut()
|
||||
GLOBAL_LIST_EMPTY(protected_ranks) //admin ranks loaded from txt
|
||||
GLOBAL_PROTECT(protected_ranks)
|
||||
|
||||
var/previous_rights = 0
|
||||
/datum/admin_rank
|
||||
var/name = "NoRank"
|
||||
var/rights = R_DEFAULT
|
||||
var/exclude_rights = NONE
|
||||
var/include_rights = NONE
|
||||
var/can_edit_rights = NONE
|
||||
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
/datum/admin_rank/New(init_name, init_rights, init_exclude_rights, init_edit_rights)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
if (name == "NoRank") //only del if this is a true creation (and not just a New() proc call), other wise trialmins/coders could abuse this to deadmin other admins
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin proc call creation of admin datum")
|
||||
return
|
||||
name = init_name
|
||||
if(!name)
|
||||
qdel(src)
|
||||
CRASH("Admin rank created without name.")
|
||||
if(init_rights)
|
||||
rights = init_rights
|
||||
include_rights = rights
|
||||
if(init_exclude_rights)
|
||||
exclude_rights = init_exclude_rights
|
||||
rights &= ~exclude_rights
|
||||
if(init_edit_rights)
|
||||
can_edit_rights = init_edit_rights
|
||||
|
||||
//load text from file
|
||||
var/list/Lines = file2list("config/admin_ranks.txt")
|
||||
/datum/admin_rank/Destroy()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
. = ..()
|
||||
|
||||
//process each line seperately
|
||||
for(var/line in Lines)
|
||||
if(!length(line)) continue
|
||||
if(copytext(line,1,2) == "#") continue
|
||||
/datum/admin_rank/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
var/list/List = splittext(line,"+")
|
||||
if(!List.len) continue
|
||||
|
||||
var/rank = ckeyEx(List[1])
|
||||
switch(rank)
|
||||
if(null,"") continue
|
||||
if("Removed") continue //Reserved
|
||||
|
||||
var/rights = 0
|
||||
for(var/i=2, i<=List.len, i++)
|
||||
switch(ckey(List[i]))
|
||||
if("@","prev") rights |= previous_rights
|
||||
if("buildmode","build") rights |= R_BUILDMODE
|
||||
if("admin") rights |= R_ADMIN
|
||||
if("ban") rights |= R_BAN
|
||||
if("fun") rights |= R_FUN
|
||||
if("server") rights |= R_SERVER
|
||||
if("debug") rights |= R_DEBUG
|
||||
if("permissions","rights") rights |= R_PERMISSIONS
|
||||
if("possess") rights |= R_POSSESS
|
||||
if("stealth") rights |= R_STEALTH
|
||||
if("rejuv","rejuvinate") rights |= R_REJUVINATE
|
||||
if("varedit") rights |= R_VAREDIT
|
||||
if("everything","host","all") rights |= (R_HOST | R_BUILDMODE | R_ADMIN | R_BAN | R_FUN | R_SERVER | R_DEBUG | R_PERMISSIONS | R_POSSESS | R_STEALTH | R_REJUVINATE | R_VAREDIT | R_SOUNDS | R_SPAWN | R_MOD| R_EVENT)
|
||||
if("sound","sounds") rights |= R_SOUNDS
|
||||
if("spawn","create") rights |= R_SPAWN
|
||||
if("mod") rights |= R_MOD
|
||||
if("event") rights |= R_EVENT
|
||||
|
||||
admin_ranks[rank] = rights
|
||||
previous_rights = rights
|
||||
// Adds/removes rights to this admin_rank
|
||||
/datum/admin_rank/proc/process_keyword(group, group_count, datum/admin_rank/previous_rank)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
var/list/keywords = splittext(group, " ")
|
||||
var/flag = 0
|
||||
for(var/k in keywords)
|
||||
switch(k)
|
||||
if("BUILD")
|
||||
flag = R_BUILDMODE
|
||||
if("ADMIN")
|
||||
flag = R_ADMIN
|
||||
if("BAN")
|
||||
flag = R_BAN
|
||||
if("FUN")
|
||||
flag = R_FUN
|
||||
if("SERVER")
|
||||
flag = R_SERVER
|
||||
if("DEBUG")
|
||||
flag = R_DEBUG
|
||||
if("PERMISSIONS")
|
||||
flag = R_PERMISSIONS
|
||||
if("POSSESS")
|
||||
flag = R_POSSESS
|
||||
if("STEALTH")
|
||||
flag = R_STEALTH
|
||||
if("REJUVINATE")
|
||||
flag = R_REJUVINATE
|
||||
if("VAREDIT")
|
||||
flag = R_VAREDIT
|
||||
if("EVERYTHING")
|
||||
flag = R_EVERYTHING
|
||||
if("SOUND")
|
||||
flag = R_SOUNDS
|
||||
if("SPAWN")
|
||||
flag = R_SPAWN
|
||||
if("MOD")
|
||||
flag = R_MOD
|
||||
if("EVENT")
|
||||
flag = R_EVENT
|
||||
if("@")
|
||||
if(previous_rank)
|
||||
switch(group_count)
|
||||
if(1)
|
||||
flag = previous_rank.include_rights
|
||||
if(2)
|
||||
flag = previous_rank.exclude_rights
|
||||
if(3)
|
||||
flag = previous_rank.can_edit_rights
|
||||
else
|
||||
continue
|
||||
switch(group_count)
|
||||
if(1)
|
||||
rights |= flag
|
||||
include_rights |= flag
|
||||
if(2)
|
||||
rights &= ~flag
|
||||
exclude_rights |= flag
|
||||
if(3)
|
||||
can_edit_rights |= flag
|
||||
|
||||
/// Loads admin ranks.
|
||||
/// Return a list containing the backup data if they were loaded from the database backup json
|
||||
/proc/load_admin_ranks(dbfail, no_update)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Reload blocked: Advanced ProcCall detected.</span>", confidential = TRUE)
|
||||
return
|
||||
GLOB.admin_ranks.Cut()
|
||||
GLOB.protected_ranks.Cut()
|
||||
//load text from file and process each entry
|
||||
var/ranks_text = file2text("[global.config.directory]/admin_ranks.txt")
|
||||
var/datum/admin_rank/previous_rank
|
||||
var/regex/admin_ranks_regex = new(@"^Name\s*=\s*(.+?)\s*\n+Include\s*=\s*([\l @]*?)\s*\n+Exclude\s*=\s*([\l @]*?)\s*\n+Edit\s*=\s*([\l @]*?)\s*\n*$", "gm")
|
||||
while(admin_ranks_regex.Find(ranks_text))
|
||||
var/datum/admin_rank/R = new(admin_ranks_regex.group[1])
|
||||
if(!R)
|
||||
continue
|
||||
var/count = 1
|
||||
for(var/i in admin_ranks_regex.group - admin_ranks_regex.group[1])
|
||||
if(i)
|
||||
R.process_keyword(i, count, previous_rank)
|
||||
count++
|
||||
GLOB.admin_ranks += R
|
||||
GLOB.protected_ranks += R
|
||||
previous_rank = R
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && !dbfail)
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
||||
if(!no_update)
|
||||
sync_ranks_with_db()
|
||||
else
|
||||
var/datum/db_query/query_load_admin_ranks = SSdbcore.NewQuery("SELECT `rank`, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
message_admins("Error loading admin ranks from database. Loading from backup.")
|
||||
log_sql("Error loading admin ranks from database. Loading from backup.")
|
||||
dbfail = TRUE
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/skip
|
||||
var/rank_name = query_load_admin_ranks.item[1]
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == rank_name) //this rank was already loaded from txt override
|
||||
skip = 1
|
||||
break
|
||||
if(!skip)
|
||||
var/rank_flags = text2num(query_load_admin_ranks.item[2])
|
||||
var/rank_exclude_flags = text2num(query_load_admin_ranks.item[3])
|
||||
var/rank_can_edit_flags = text2num(query_load_admin_ranks.item[4])
|
||||
var/datum/admin_rank/R = new(rank_name, rank_flags, rank_exclude_flags, rank_can_edit_flags)
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
qdel(query_load_admin_ranks)
|
||||
//load ranks from backup file
|
||||
if(dbfail)
|
||||
var/backup_file = file2text("data/admins_backup.json")
|
||||
if(backup_file == null)
|
||||
log_world("Unable to locate admins backup file.")
|
||||
return FALSE
|
||||
var/list/json = json_decode(backup_file)
|
||||
for(var/J in json["ranks"])
|
||||
var/skip
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == "[J]") //this rank was already loaded from txt override
|
||||
skip = TRUE
|
||||
if(skip)
|
||||
continue
|
||||
var/datum/admin_rank/R = new("[J]", json["ranks"]["[J]"]["include rights"], json["ranks"]["[J]"]["exclude rights"], json["ranks"]["[J]"]["can edit rights"])
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
return json
|
||||
#ifdef TESTING
|
||||
var/msg = "Permission Sets Built:\n"
|
||||
for(var/rank in admin_ranks)
|
||||
msg += "\t[rank] - [admin_ranks[rank]]\n"
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
msg += "\t[R.name]"
|
||||
var/rights = rights2text(R.rights,"\n\t\t")
|
||||
if(rights)
|
||||
msg += "\t\t[rights]\n"
|
||||
testing(msg)
|
||||
#endif
|
||||
|
||||
/hook/startup/proc/loadAdmins()
|
||||
load_admins()
|
||||
return 1
|
||||
/// Converts a rank name (such as "Coder+Moth") into a list of /datum/admin_rank
|
||||
/proc/ranks_from_rank_name(rank_name)
|
||||
var/list/rank_names = splittext(rank_name, "+")
|
||||
var/list/ranks = list()
|
||||
|
||||
/proc/load_admins()
|
||||
for (var/datum/admin_rank/rank as anything in GLOB.admin_ranks)
|
||||
if (rank.name in rank_names)
|
||||
rank_names -= rank.name
|
||||
ranks += rank
|
||||
|
||||
if (rank_names.len == 0)
|
||||
break
|
||||
|
||||
if (rank_names.len > 0)
|
||||
log_config("Admin rank names were invalid: [jointext(ranks, ", ")]")
|
||||
|
||||
return ranks
|
||||
|
||||
/// Takes a list of rank names and joins them with +
|
||||
/proc/join_admin_ranks(list/datum/admin_rank/ranks)
|
||||
var/list/names = list()
|
||||
|
||||
for (var/datum/admin_rank/rank as anything in ranks)
|
||||
names += rank.name
|
||||
|
||||
return jointext(names, "+")
|
||||
|
||||
/// (Re)Loads the admin list.
|
||||
/// returns TRUE if database admins had to be loaded from the backup json
|
||||
/proc/load_admins(no_update)
|
||||
var/dbfail
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && !SSdbcore.Connect())
|
||||
message_admins("Failed to connect to database while loading admins. Loading from backup.")
|
||||
log_sql("Failed to connect to database while loading admins. Loading from backup.")
|
||||
dbfail = TRUE
|
||||
//clear the datums references
|
||||
admin_datums.Cut()
|
||||
GLOB.admin_datums.Cut()
|
||||
for(var/client/C in GLOB.admins)
|
||||
C.remove_admin_verbs()
|
||||
C.holder = null
|
||||
GLOB.admins.Cut()
|
||||
load_admin_ranks() //CHOMP Edit: moved this from "f(config.admin_legacy_system)" and put it here instead, literally just moved it 3 lines.
|
||||
GLOB.protected_admins.Cut()
|
||||
GLOB.deadmins.Cut()
|
||||
var/list/backup_file_json = load_admin_ranks(dbfail, no_update)
|
||||
dbfail = backup_file_json != null
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
var/list/rank_names = list()
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
rank_names[R.name] = R
|
||||
//ckeys listed in admins.txt are always made admins before sql loading is attempted
|
||||
var/admins_text = file2text("[global.config.directory]/admins.txt")
|
||||
var/regex/admins_regex = new(@"^(?!#)(.+?)\s+=\s+(.+)", "gm")
|
||||
|
||||
if(CONFIG_GET(flag/admin_legacy_system)) // CHOMPEdit
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
while(admins_regex.Find(admins_text))
|
||||
var/admin_key = admins_regex.group[1]
|
||||
var/admin_rank = admins_regex.group[2]
|
||||
new /datum/admins(ranks_from_rank_name(admin_rank), ckey(admin_key), force_active = FALSE, protected = TRUE)
|
||||
|
||||
//load text from file
|
||||
var/list/Lines = file2list("config/admins.txt")
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && !dbfail)
|
||||
var/datum/db_query/query_load_admins = SSdbcore.NewQuery("SELECT ckey, `rank`, feedback FROM [format_table_name("admin")] ORDER BY `rank`")
|
||||
if(!query_load_admins.Execute())
|
||||
message_admins("Error loading admins from database. Loading from backup.")
|
||||
log_sql("Error loading admins from database. Loading from backup.")
|
||||
dbfail = 1
|
||||
else
|
||||
while(query_load_admins.NextRow())
|
||||
var/admin_ckey = ckey(query_load_admins.item[1])
|
||||
var/admin_rank = query_load_admins.item[2]
|
||||
var/admin_feedback = query_load_admins.item[3]
|
||||
var/skip
|
||||
|
||||
//process each line seperately
|
||||
for(var/line in Lines)
|
||||
if(!length(line)) continue
|
||||
if(copytext(line,1,2) == "#") continue
|
||||
|
||||
//Split the line at every "-"
|
||||
var/list/List = splittext(line, "-")
|
||||
if(!List.len) continue
|
||||
|
||||
//ckey is before the first "-"
|
||||
var/ckey = ckey(List[1])
|
||||
if(!ckey) continue
|
||||
|
||||
//rank follows the first "-"
|
||||
var/rank = ""
|
||||
if(List.len >= 2)
|
||||
rank = ckeyEx(List[2])
|
||||
|
||||
//load permissions associated with this rank
|
||||
var/rights = admin_ranks[rank]
|
||||
|
||||
//create the admin datum and store it for later use
|
||||
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
|
||||
|
||||
if(D.rights & R_DEBUG) //grant profile access
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
|
||||
//find the client for a ckey if they are connected and associate them with the new admin datum
|
||||
D.associate(GLOB.directory[ckey])
|
||||
|
||||
else
|
||||
//The current admin system uses SQL
|
||||
|
||||
establish_db_connection()
|
||||
if(!SSdbcore.IsConnected())
|
||||
error("Failed to connect to database in load_admins(). Reverting to legacy system.")
|
||||
log_misc("Failed to connect to database in load_admins(). Reverting to legacy system.")
|
||||
CONFIG_SET(flag/admin_legacy_system, TRUE)
|
||||
load_admins()
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin")
|
||||
query.Execute()
|
||||
while(query.NextRow())
|
||||
var/ckey = query.item[1]
|
||||
var/rank = query.item[2]
|
||||
if(rank == "Removed") continue //This person was de-adminned. They are only in the admin list for archive purposes.
|
||||
|
||||
var/rights = query.item[4]
|
||||
if(istext(rights)) rights = text2num(rights)
|
||||
var/datum/admins/D = new /datum/admins(rank, rights, ckey)
|
||||
|
||||
if(D.rights & R_DEBUG) //grant profile access
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
|
||||
//find the client for a ckey if they are connected and associate them with the new admin datum
|
||||
D.associate(GLOB.directory[ckey])
|
||||
qdel(query)
|
||||
if(!admin_datums)
|
||||
error("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.")
|
||||
log_misc("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.")
|
||||
CONFIG_SET(flag/admin_legacy_system, TRUE)
|
||||
load_admins()
|
||||
return
|
||||
var/list/admin_ranks = ranks_from_rank_name(admin_rank)
|
||||
|
||||
if(admin_ranks.len == 0)
|
||||
message_admins("[admin_ckey] loaded with invalid admin rank [admin_rank].")
|
||||
skip = 1
|
||||
if(GLOB.admin_datums[admin_ckey] || GLOB.deadmins[admin_ckey])
|
||||
skip = 1
|
||||
if(!skip)
|
||||
var/datum/admins/admin_holder = new(admin_ranks, admin_ckey)
|
||||
admin_holder.cached_feedback_link = admin_feedback || NO_FEEDBACK_LINK
|
||||
qdel(query_load_admins)
|
||||
if (!no_update)
|
||||
save_admin_backup()
|
||||
sync_admins_with_db()
|
||||
//load admins from backup file
|
||||
if(dbfail)
|
||||
if(!backup_file_json)
|
||||
if(backup_file_json != null)
|
||||
//already tried
|
||||
return
|
||||
var/backup_file = file2text("data/admins_backup.json")
|
||||
if(backup_file == null)
|
||||
log_world("Unable to locate admins backup file.")
|
||||
return
|
||||
backup_file_json = json_decode(backup_file)
|
||||
for(var/backup_admin_ckey in backup_file_json["admins"])
|
||||
var/skip
|
||||
for(var/admin_ckey in GLOB.admin_datums + GLOB.deadmins)
|
||||
if(ckey(admin_ckey) == ckey("[backup_admin_ckey]")) //this admin was already loaded from txt override
|
||||
skip = TRUE
|
||||
break
|
||||
if(skip)
|
||||
continue
|
||||
new /datum/admins(ranks_from_rank_name(backup_file_json["admins"]["[backup_admin_ckey]"]), ckey("[backup_admin_ckey]"))
|
||||
#ifdef TESTING
|
||||
var/msg = "Admins Built:\n"
|
||||
for(var/ckey in admin_datums)
|
||||
var/rank
|
||||
var/datum/admins/D = admin_datums[ckey]
|
||||
if(D) rank = D.rank
|
||||
msg += "\t[ckey] - [rank]\n"
|
||||
for(var/ckey in GLOB.admin_datums)
|
||||
var/datum/admins/D = GLOB.admin_datums[ckey]
|
||||
msg += "\t[ckey] - [D.rank_names()]\n"
|
||||
testing(msg)
|
||||
#endif
|
||||
return dbfail
|
||||
|
||||
|
||||
#ifdef TESTING
|
||||
/client/verb/changerank(newrank in admin_ranks)
|
||||
if(holder)
|
||||
holder.rank = newrank
|
||||
holder.rights = admin_ranks[newrank]
|
||||
else
|
||||
holder = new /datum/admins(newrank,admin_ranks[newrank],ckey)
|
||||
remove_admin_verbs()
|
||||
holder.associate(src)
|
||||
/proc/sync_ranks_with_db()
|
||||
set waitfor = FALSE
|
||||
|
||||
/client/verb/changerights(newrights as num)
|
||||
if(holder)
|
||||
holder.rights = newrights
|
||||
else
|
||||
holder = new /datum/admins("testing",newrights,ckey)
|
||||
remove_admin_verbs()
|
||||
holder.associate(src)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
#endif
|
||||
var/list/sql_ranks = list()
|
||||
for(var/datum/admin_rank/R as anything in GLOB.protected_ranks)
|
||||
sql_ranks += list(list("rank" = R.name, "flags" = R.include_rights, "exclude_flags" = R.exclude_rights, "can_edit_flags" = R.can_edit_rights))
|
||||
SSdbcore.MassInsert(format_table_name("admin_ranks"), sql_ranks, duplicate_key = TRUE)
|
||||
update_everything_flag_in_db()
|
||||
|
||||
|
||||
/proc/update_everything_flag_in_db()
|
||||
for(var/datum/admin_rank/R as anything in GLOB.admin_ranks)
|
||||
var/list/flags = list()
|
||||
if(R.include_rights == R_EVERYTHING)
|
||||
flags += "flags"
|
||||
if(R.exclude_rights == R_EVERYTHING)
|
||||
flags += "exclude_flags"
|
||||
if(R.can_edit_rights == R_EVERYTHING)
|
||||
flags += "can_edit_flags"
|
||||
if(!flags.len)
|
||||
continue
|
||||
var/flags_to_check = flags.Join(" != [R_EVERYTHING] AND ") + " != [R_EVERYTHING]"
|
||||
var/datum/db_query/query_check_everything_ranks = SSdbcore.NewQuery(
|
||||
"SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE rank = :rank AND ([flags_to_check])",
|
||||
list("rank" = R.name)
|
||||
)
|
||||
if(!query_check_everything_ranks.Execute())
|
||||
qdel(query_check_everything_ranks)
|
||||
return
|
||||
if(query_check_everything_ranks.NextRow()) //no row is returned if the rank already has the correct flag value
|
||||
var/flags_to_update = flags.Join(" = [R_EVERYTHING], ") + " = [R_EVERYTHING]"
|
||||
var/datum/db_query/query_update_everything_ranks = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("admin_ranks")] SET [flags_to_update] WHERE rank = :rank",
|
||||
list("rank" = R.name)
|
||||
)
|
||||
if(!query_update_everything_ranks.Execute())
|
||||
qdel(query_update_everything_ranks)
|
||||
return
|
||||
qdel(query_update_everything_ranks)
|
||||
qdel(query_check_everything_ranks)
|
||||
|
||||
|
||||
/proc/sync_admins_with_db()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>")
|
||||
return
|
||||
|
||||
if(CONFIG_GET(flag/admin_legacy_system) || !SSdbcore.IsConnected()) //we're already using legacy system so there's nothing to save
|
||||
return
|
||||
sync_ranks_with_db()
|
||||
var/list/sql_admins = list()
|
||||
for(var/holder_ckey in GLOB.protected_admins)
|
||||
var/datum/admins/holder = GLOB.protected_admins[holder_ckey]
|
||||
sql_admins += list(list("ckey" = holder.target, "rank" = holder.rank_names()))
|
||||
SSdbcore.MassInsert(format_table_name("admin"), sql_admins, duplicate_key = TRUE)
|
||||
var/datum/db_query/query_admin_rank_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] AS p INNER JOIN [format_table_name("admin")] AS a ON p.ckey = a.ckey SET p.lastadminrank = a.rank")
|
||||
query_admin_rank_update.Execute()
|
||||
qdel(query_admin_rank_update)
|
||||
|
||||
/proc/save_admin_backup()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>")
|
||||
return
|
||||
|
||||
if(CONFIG_GET(flag/admin_legacy_system)) //we're already using legacy system so there's nothing to save
|
||||
return
|
||||
|
||||
//json format backup file generation stored per server
|
||||
var/json_file = file("data/admins_backup.json")
|
||||
var/list/file_data = list(
|
||||
"ranks" = list(),
|
||||
"admins" = list()
|
||||
)
|
||||
for(var/datum/admin_rank/R as anything in GLOB.admin_ranks)
|
||||
file_data["ranks"]["[R.name]"] = list()
|
||||
file_data["ranks"]["[R.name]"]["include rights"] = R.include_rights
|
||||
file_data["ranks"]["[R.name]"]["exclude rights"] = R.exclude_rights
|
||||
file_data["ranks"]["[R.name]"]["can edit rights"] = R.can_edit_rights
|
||||
|
||||
for(var/admin_ckey in GLOB.admin_datums + GLOB.deadmins)
|
||||
var/datum/admins/admin = GLOB.admin_datums[admin_ckey]
|
||||
|
||||
if(!admin)
|
||||
admin = GLOB.deadmins[admin_ckey]
|
||||
if (!admin)
|
||||
continue
|
||||
|
||||
file_data["admins"][admin_ckey] = admin.rank_names()
|
||||
|
||||
//admin.backup_connections()
|
||||
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data, JSON_PRETTY_PRINT))
|
||||
|
||||
@@ -55,7 +55,7 @@ var/datum/admin_secrets/admin_secrets = new()
|
||||
return name
|
||||
|
||||
/datum/admin_secret_item/proc/can_view(var/mob/user)
|
||||
return check_rights(permissions, 0, user)
|
||||
return check_rights_for(user.client, permissions)
|
||||
|
||||
/datum/admin_secret_item/proc/can_execute(var/mob/user)
|
||||
if(can_view(user))
|
||||
|
||||
@@ -3,7 +3,7 @@ var/list/admin_verbs_default = list(
|
||||
/datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags,
|
||||
/client/proc/player_panel_new, //shows an interface for all players, with links to various panels,
|
||||
/client/proc/player_panel,
|
||||
/client/proc/deadmin_self, //destroys our own admin datum so we can play as a regular player,
|
||||
/client/proc/deadmin, //destroys our own admin datum so we can play as a regular player,
|
||||
/client/proc/hide_verbs, //hides all our adminverbs,
|
||||
/client/proc/hide_most_verbs, //hides all our hideable adminverbs,
|
||||
/client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify,
|
||||
@@ -273,7 +273,7 @@ var/list/admin_verbs_rejuv = list(
|
||||
|
||||
//verbs which can be hidden - needs work
|
||||
var/list/admin_verbs_hideable = list(
|
||||
/client/proc/deadmin_self,
|
||||
/client/proc/deadmin,
|
||||
// /client/proc/deadchat,
|
||||
/datum/admins/proc/show_traitor_panel,
|
||||
/datum/admins/proc/toggleenter,
|
||||
|
||||
@@ -3,7 +3,7 @@ var/list/admin_verbs_default = list(
|
||||
// /datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags, //VOREStation Remove,
|
||||
// /client/proc/player_panel_new, //shows an interface for all players, with links to various panels, //VOREStation Remove,
|
||||
// /client/proc/player_panel, //VOREStation Remove,
|
||||
/client/proc/deadmin_self, //destroys our own admin datum so we can play as a regular player,
|
||||
/client/proc/deadmin, //destroys our own admin datum so we can play as a regular player,
|
||||
/client/proc/cmd_admin_say, //VOREStation Add,
|
||||
/client/proc/cmd_mod_say, //VOREStation Add,
|
||||
/client/proc/cmd_event_say, //VOREStation Add,
|
||||
@@ -320,7 +320,7 @@ var/list/admin_verbs_rejuv = list(
|
||||
|
||||
//verbs which can be hidden - needs work
|
||||
var/list/admin_verbs_hideable = list(
|
||||
/client/proc/deadmin_self,
|
||||
/client/proc/deadmin,
|
||||
// /client/proc/deadchat,
|
||||
/datum/admins/proc/show_traitor_panel,
|
||||
/datum/admins/proc/toggleenter,
|
||||
@@ -596,24 +596,25 @@ var/list/admin_verbs_event_manager = list(
|
||||
|
||||
/client/proc/add_admin_verbs()
|
||||
if(holder)
|
||||
var/rights = holder.rank_flags()
|
||||
add_verb(src, admin_verbs_default)
|
||||
if(holder.rights & R_BUILDMODE) add_verb(src, /client/proc/togglebuildmodeself)
|
||||
if(holder.rights & R_ADMIN) add_verb(src, admin_verbs_admin)
|
||||
if(holder.rights & R_BAN) add_verb(src, admin_verbs_ban)
|
||||
if(holder.rights & R_FUN) add_verb(src, admin_verbs_fun)
|
||||
if(holder.rights & R_SERVER) add_verb(src, admin_verbs_server)
|
||||
if(holder.rights & R_DEBUG)
|
||||
if(rights & R_BUILDMODE) add_verb(src, /client/proc/togglebuildmodeself)
|
||||
if(rights & R_ADMIN) add_verb(src, admin_verbs_admin)
|
||||
if(rights & R_BAN) add_verb(src, admin_verbs_ban)
|
||||
if(rights & R_FUN) add_verb(src, admin_verbs_fun)
|
||||
if(rights & R_SERVER) add_verb(src, admin_verbs_server)
|
||||
if(rights & R_DEBUG)
|
||||
add_verb(src, admin_verbs_debug)
|
||||
if(CONFIG_GET(flag/debugparanoid) && !(holder.rights & R_ADMIN))
|
||||
if(CONFIG_GET(flag/debugparanoid) && !(rights & R_ADMIN))
|
||||
remove_verb(src, admin_verbs_paranoid_debug) //Right now it's just callproc but we can easily add others later on.
|
||||
if(holder.rights & R_POSSESS) add_verb(src, admin_verbs_possess)
|
||||
if(holder.rights & R_PERMISSIONS) add_verb(src, admin_verbs_permissions)
|
||||
if(holder.rights & R_STEALTH) add_verb(src, /client/proc/stealth)
|
||||
if(holder.rights & R_REJUVINATE) add_verb(src, admin_verbs_rejuv)
|
||||
if(holder.rights & R_SOUNDS) add_verb(src, admin_verbs_sounds)
|
||||
if(holder.rights & R_SPAWN) add_verb(src, admin_verbs_spawn)
|
||||
if(holder.rights & R_MOD) add_verb(src, admin_verbs_mod)
|
||||
if(holder.rights & R_EVENT) add_verb(src, admin_verbs_event_manager)
|
||||
if(rights & R_POSSESS) add_verb(src, admin_verbs_possess)
|
||||
if(rights & R_PERMISSIONS) add_verb(src, admin_verbs_permissions)
|
||||
if(rights & R_STEALTH) add_verb(src, /client/proc/stealth)
|
||||
if(rights & R_REJUVINATE) add_verb(src, admin_verbs_rejuv)
|
||||
if(rights & R_SOUNDS) add_verb(src, admin_verbs_sounds)
|
||||
if(rights & R_SPAWN) add_verb(src, admin_verbs_spawn)
|
||||
if(rights & R_MOD) add_verb(src, admin_verbs_mod)
|
||||
if(rights & R_EVENT) add_verb(src, admin_verbs_event_manager)
|
||||
|
||||
//CHOMPEdit Begin
|
||||
/client/proc/remove_admin_verbs()
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
|
||||
if(!warned_ckey || !istext(warned_ckey)) return
|
||||
if(warned_ckey in admin_datums)
|
||||
if(warned_ckey in GLOB.admin_datums)
|
||||
to_chat(usr, span_warning("Error: warn(): You can't warn admins."))
|
||||
return
|
||||
|
||||
@@ -335,36 +335,22 @@
|
||||
log_admin("[key_name(usr)] used 'kill air'.")
|
||||
message_admins(span_blue("[key_name_admin(usr)] used 'kill air'."), 1)
|
||||
|
||||
/client/proc/readmin_self()
|
||||
set name = "Re-Admin self"
|
||||
/client/proc/deadmin()
|
||||
set name = "DeAdmin"
|
||||
set category = "Admin.Misc"
|
||||
set desc = "Shed your admin powers."
|
||||
|
||||
if(deadmin_holder)
|
||||
deadmin_holder.reassociate()
|
||||
log_admin("[src] re-admined themself.")
|
||||
message_admins("[src] re-admined themself.", 1)
|
||||
to_chat(src, span_filter_system(span_interface("You now have the keys to control the planet, or at least a small space station")))
|
||||
remove_verb(src, /client/proc/readmin_self)
|
||||
if(isobserver(mob))
|
||||
var/mob/observer/dead/our_mob = mob
|
||||
our_mob.visualnet?.addVisibility(our_mob, src)
|
||||
|
||||
/client/proc/deadmin_self()
|
||||
set name = "De-admin self"
|
||||
set category = "Admin.Misc"
|
||||
|
||||
if(holder)
|
||||
if(tgui_alert(usr, "Confirm self-deadmin for the round? You can't re-admin yourself without someone promoting you.","Deadmin",list("Yes","No")) == "Yes")
|
||||
log_admin("[src] deadmined themself.")
|
||||
message_admins("[src] deadmined themself.", 1)
|
||||
deadmin()
|
||||
to_chat(src, span_filter_system(span_interface("You are now a normal player.")))
|
||||
add_verb(src, /client/proc/readmin_self)
|
||||
if(isobserver(mob))
|
||||
var/mob/observer/dead/our_mob = mob
|
||||
our_mob.visualnet?.removeVisibility(our_mob, src)
|
||||
src.holder.deactivate()
|
||||
to_chat(src, span_interface("You are now a normal player."))
|
||||
log_admin("[key_name(src)] deadminned themselves.")
|
||||
message_admins("[key_name_admin(src)] deadminned themselves.")
|
||||
//BLACKBOX_LOG_ADMIN_VERB("Deadmin")
|
||||
feedback_add_details("admin_verb","DAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
if(isobserver(mob))
|
||||
var/mob/observer/dead/our_mob = mob
|
||||
our_mob.visualnet?.removeVisibility(our_mob, src)
|
||||
|
||||
/client/proc/toggle_log_hrefs()
|
||||
set name = "Toggle href logging"
|
||||
set category = "Server.Config"
|
||||
@@ -584,3 +570,144 @@
|
||||
return
|
||||
SSmotiontracker.hide_all = !SSmotiontracker.hide_all
|
||||
log_admin("[key_name(usr)] changed the motion echo visibility to [SSmotiontracker.hide_all ? "hidden" : "visible"].")
|
||||
|
||||
/client/proc/adminorbit()
|
||||
set category = "Fun.Event Kit"
|
||||
set name = "Orbit Things"
|
||||
set desc = "Makes something orbit around something else."
|
||||
set popup_menu = FALSE
|
||||
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/center
|
||||
var/atom/movable/orbiter
|
||||
var/input
|
||||
|
||||
if(holder.marked_datum)
|
||||
input = tgui_alert(usr, "You have \n[holder.marked_datum] marked, should this be the center of the orbit, or the orbiter?", "Orbit", list("Center", "Orbiter", "Neither"))
|
||||
switch(input)
|
||||
if("Center")
|
||||
center = holder.marked_datum
|
||||
if("Orbiter")
|
||||
orbiter = holder.marked_datum
|
||||
var/list/possible_things = list()
|
||||
for(var/T as mob in view(view)) //Let's do mobs before objects
|
||||
if(ismob(T))
|
||||
possible_things |= T
|
||||
for(var/T as obj in view(view))
|
||||
if(isobj(T))
|
||||
possible_things |= T
|
||||
if(!center)
|
||||
center = tgui_input_list(src, "What should act as the center of the orbit?", "Center", possible_things)
|
||||
possible_things -= center
|
||||
if(!orbiter)
|
||||
orbiter = tgui_input_list(src, "What should act as the orbiter of the orbit?", "Orbiter", possible_things)
|
||||
if(!center || !orbiter)
|
||||
to_chat(usr, span_warning("A center of orbit and an orbiter must be configured. You can also do this by marking a target."))
|
||||
return
|
||||
if(center == orbiter)
|
||||
to_chat(usr, span_warning("The center of the orbit cannot also be the orbiter."))
|
||||
return
|
||||
if(isturf(orbiter))
|
||||
to_chat(usr, span_warning("The orbiter cannot be a turf. It can only be used as a center."))
|
||||
return
|
||||
var/distance = tgui_input_number(usr, "How large will their orbit radius be? (In pixels. 32 is 'near around a character)", "Orbit Radius", 32)
|
||||
var/speed = tgui_input_number(usr, "How fast will they orbit (negative numbers spin clockwise)", "Orbit Speed", 20)
|
||||
var/segments = tgui_input_number(usr, "How many segments will they have in their orbit? (3 is a triangle, 36 is a circle, etc)", "Orbit Segments", 36)
|
||||
var/clock = FALSE
|
||||
if(!distance)
|
||||
distance = 32
|
||||
if(!speed)
|
||||
speed = 20
|
||||
else if (speed < 0)
|
||||
clock = TRUE
|
||||
speed *= -1
|
||||
if(!segments)
|
||||
segments = 36
|
||||
if(tgui_alert(usr, "\The [orbiter] will orbit around [center]. Is this okay?", "Confirm Orbit", list("Yes", "No")) == "Yes")
|
||||
orbiter.orbit(center, distance, clock, speed, segments)
|
||||
|
||||
/client/proc/removetickets()
|
||||
set name = "Security Tickets"
|
||||
set category = "Admin.Investigate"
|
||||
set desc = "Allows one to remove tickets from the global list."
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(security_printer_tickets.len >= 1)
|
||||
var/input = tgui_input_list(usr, "Which message?", "Security Tickets", security_printer_tickets)
|
||||
if(!input)
|
||||
return
|
||||
if(tgui_alert(usr, "Do you want to remove the following message from the global list? \"[input]\"", "Remove Ticket", list("Yes", "No")) == "Yes")
|
||||
security_printer_tickets -= input
|
||||
log_and_message_admins("removed a security ticket from the global list: \"[input]\"", usr)
|
||||
|
||||
else
|
||||
tgui_alert_async(usr, "The ticket list is empty.","Empty")
|
||||
|
||||
/client/proc/delbook()
|
||||
set name = "Delete Book"
|
||||
set desc = "Permamently deletes a book from the database."
|
||||
set category = "Admin.Game"
|
||||
if(!src.holder)
|
||||
to_chat(src, "Only administrators may use this command.")
|
||||
return
|
||||
|
||||
var/obj/machinery/librarycomp/our_comp
|
||||
for(var/obj/machinery/librarycomp/l in world)
|
||||
if(istype(l, /obj/machinery/librarycomp))
|
||||
our_comp = l
|
||||
break
|
||||
|
||||
if(!our_comp)
|
||||
to_chat(usr, span_warning("Unable to locate a library computer to use for book deleting."))
|
||||
return
|
||||
|
||||
var/dat = "<HEAD><TITLE>Book Inventory Management</TITLE></HEAD><BODY>\n"
|
||||
dat += "<h3>ADMINISTRATIVE MANAGEMENT</h3>"
|
||||
establish_db_connection()
|
||||
|
||||
if(!SSdbcore.IsConnected())
|
||||
dat += span_red(span_bold("ERROR") + ": Unable to contact External Archive. Please contact your system administrator for assistance.")
|
||||
else
|
||||
dat += {"<A href='byond://?our_comp=\ref[our_comp];[HrefToken()];orderbyid=1'>(Order book by SS<sup>13</sup>BN)</A><BR><BR>
|
||||
<table>
|
||||
<tr><td><A href='byond://?our_comp=\ref[our_comp];[HrefToken()];sort=author>AUTHOR</A></td><td><A href='byond://?our_comp=\ref[our_comp];[HrefToken()];sort=title>TITLE</A></td><td><A href='byond://?our_comp=\ref[our_comp];[HrefToken()];sort=category>CATEGORY</A></td><td></td></tr>"}
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, author, title, category FROM library ORDER BY [our_comp.sortby]")
|
||||
query.Execute()
|
||||
|
||||
var/show_admin_options = check_rights(R_ADMIN, show_msg = FALSE)
|
||||
|
||||
while(query.NextRow())
|
||||
var/id = query.item[1]
|
||||
var/author = query.item[2]
|
||||
var/title = query.item[3]
|
||||
var/category = query.item[4]
|
||||
dat += "<tr><td>[author]</td><td>[title]</td><td>[category]</td><td>"
|
||||
if(show_admin_options) // This isn't the only check, since you can just href-spoof press this button. Just to tidy things up.
|
||||
dat += "<A href='byond://?our_comp=\ref[our_comp];[HrefToken()];delid=[id]'>\[Del\]</A>"
|
||||
dat += "</td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
qdel(query)
|
||||
usr << browse("<html>[dat]</html>", "window=library")
|
||||
onclose(usr, "library")
|
||||
|
||||
/client/proc/toggle_spawning_with_recolour()
|
||||
set name = "Toggle Simple/Robot recolour verb"
|
||||
set desc = "Makes it so new robots/simple_mobs spawn with a verb to recolour themselves for this round. You must set them separately."
|
||||
set category = "Server.Game"
|
||||
|
||||
if(!check_rights(R_ADMIN|R_EVENT|R_FUN))
|
||||
return
|
||||
|
||||
var/which = tgui_alert(usr, "Which do you want to toggle?", "Choose Recolour Toggle", list("Robot", "Simple Mob"))
|
||||
switch(which)
|
||||
if("Robot")
|
||||
CONFIG_SET(flag/allow_robot_recolor, !CONFIG_GET(flag/allow_robot_recolor))
|
||||
to_chat(usr, "You have [CONFIG_GET(flag/allow_robot_recolor) ? "enabled" : "disabled"] newly spawned cyborgs to spawn with the recolour verb")
|
||||
if("Simple Mob")
|
||||
CONFIG_SET(flag/allow_simple_mob_recolor, !CONFIG_GET(flag/allow_simple_mob_recolor))
|
||||
to_chat(usr, "You have [CONFIG_GET(flag/allow_simple_mob_recolor) ? "enabled" : "disabled"] newly spawned simple mobs to spawn with the recolour verb")
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/datum/admins/proc/set_uplink(mob/living/carbon/human/H as mob)
|
||||
set category = "Debug.Events"
|
||||
set name = "Set Uplink"
|
||||
set desc = "Allows admins to set up an uplink on a character. This will be required for a character to use telecrystals."
|
||||
set popup_menu = FALSE
|
||||
|
||||
if(check_rights(R_ADMIN|R_DEBUG))
|
||||
traitors.spawn_uplink(H)
|
||||
H.mind.tcrystals = DEFAULT_TELECRYSTAL_AMOUNT
|
||||
H.mind.accept_tcrystals = 1
|
||||
var/msg = "[key_name(usr)] has given [H.ckey] an uplink."
|
||||
message_admins(msg)
|
||||
else
|
||||
to_chat(usr, "You do not have access to this command.")
|
||||
@@ -1,13 +1,18 @@
|
||||
GLOBAL_LIST_EMPTY(admin_datums)
|
||||
GLOBAL_PROTECT(admin_datums)
|
||||
GLOBAL_LIST_EMPTY(protected_admins)
|
||||
GLOBAL_PROTECT(protected_admins)
|
||||
|
||||
GLOBAL_VAR_INIT(href_token, GenerateToken())
|
||||
GLOBAL_PROTECT(href_token)
|
||||
|
||||
var/list/admin_datums = list()
|
||||
|
||||
/datum/admins
|
||||
var/rank = "Temporary Admin"
|
||||
var/client/owner = null
|
||||
var/rights = 0
|
||||
var/fakekey = null
|
||||
var/list/datum/admin_rank/ranks
|
||||
|
||||
var/target
|
||||
var/name = "nobody's admin datum (no rank)" //Makes for better runtimes
|
||||
var/client/owner = null
|
||||
var/fakekey = null
|
||||
|
||||
var/datum/marked_datum
|
||||
|
||||
@@ -18,49 +23,194 @@ var/list/admin_datums = list()
|
||||
|
||||
var/href_token
|
||||
|
||||
/// Link from the database pointing to the admin's feedback forum
|
||||
var/cached_feedback_link
|
||||
|
||||
/datum/admins/New(initial_rank = "Temporary Admin", initial_rights = 0, ckey)
|
||||
if(!ckey)
|
||||
error("Admin datum created without a ckey argument. Datum has been deleted")
|
||||
qdel(src)
|
||||
var/deadmined
|
||||
|
||||
var/given_profiling = FALSE
|
||||
|
||||
|
||||
/datum/admins/New(list/datum/admin_rank/ranks, ckey, force_active = FALSE, protected)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
if (!target) //only del if this is a true creation (and not just a New() proc call), other wise trialmins/coders could abuse this to deadmin other admins
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin proc call creation of admin datum")
|
||||
return
|
||||
if(!ckey)
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin datum created without a ckey")
|
||||
if(!istype(ranks))
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin datum created with invalid ranks: [ranks] ([json_encode(ranks)])")
|
||||
target = ckey
|
||||
name = "[ckey]'s admin datum ([join_admin_ranks(ranks)])"
|
||||
src.ranks = ranks
|
||||
admincaster_signature = "[using_map.company_name] Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
|
||||
href_token = GenerateToken()
|
||||
rank = initial_rank
|
||||
rights = initial_rights
|
||||
admin_datums[ckey] = src
|
||||
if(rights & R_DEBUG) //grant profile access
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
if(protected)
|
||||
GLOB.protected_admins[target] = src
|
||||
activate()
|
||||
|
||||
/datum/admins/proc/associate(client/C)
|
||||
if(istype(C))
|
||||
owner = C
|
||||
owner.holder = src
|
||||
owner.add_admin_verbs() //TODO
|
||||
owner.init_verbs() //re-initialize the verb list
|
||||
GLOB.admins |= C
|
||||
/datum/admins/Destroy()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
. = ..()
|
||||
|
||||
/datum/admins/proc/activate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
GLOB.deadmins -= target
|
||||
GLOB.admin_datums[target] = src
|
||||
deadmined = FALSE
|
||||
//plane_debug = new(src)
|
||||
if (GLOB.directory[target])
|
||||
associate(GLOB.directory[target]) //find the client for a ckey if they are connected and associate them with us
|
||||
|
||||
/datum/admins/proc/deactivate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
GLOB.deadmins[target] = src
|
||||
GLOB.admin_datums -= target
|
||||
//QDEL_NULL(plane_debug)
|
||||
deadmined = TRUE
|
||||
|
||||
var/client/client = owner || GLOB.directory[target]
|
||||
|
||||
if (!isnull(client))
|
||||
disassociate()
|
||||
add_verb(client, /client/proc/readmin)
|
||||
//client.disable_combo_hud()
|
||||
//client.update_special_keybinds()
|
||||
|
||||
/datum/admins/proc/associate(client/client)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
|
||||
if(!istype(client))
|
||||
return
|
||||
|
||||
if(client?.ckey != target)
|
||||
var/msg = " has attempted to associate with [target]'s admin datum"
|
||||
message_admins("[key_name_admin(client)][msg]")
|
||||
log_admin("[key_name(client)][msg]")
|
||||
return
|
||||
|
||||
if (deadmined)
|
||||
activate()
|
||||
|
||||
owner = client
|
||||
owner.holder = src
|
||||
owner.add_admin_verbs()
|
||||
remove_verb(owner, /client/proc/readmin)
|
||||
owner.init_verbs() //re-initialize the verb list
|
||||
//owner.update_special_keybinds()
|
||||
GLOB.admins |= client
|
||||
|
||||
try_give_profiling()
|
||||
|
||||
/datum/admins/proc/disassociate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
if(owner)
|
||||
GLOB.admins -= owner
|
||||
owner.remove_admin_verbs()
|
||||
owner.init_verbs() //re-initialize the verb list
|
||||
owner.deadmin_holder = owner.holder
|
||||
// owner.init_verbs() //re-initialize the verb list
|
||||
owner.holder = null
|
||||
owner = null
|
||||
|
||||
/datum/admins/proc/reassociate()
|
||||
if(owner)
|
||||
GLOB.admins += owner
|
||||
owner.holder = src
|
||||
owner.deadmin_holder = null
|
||||
owner.add_admin_verbs()
|
||||
/// Returns the feedback forum thread for the admin holder's owner, as according to DB.
|
||||
/datum/admins/proc/feedback_link()
|
||||
// This intentionally does not follow the 10-second maximum TTL rule,
|
||||
// as this can be reloaded through the Reload-Admins verb.
|
||||
if (cached_feedback_link == NO_FEEDBACK_LINK)
|
||||
return null
|
||||
|
||||
if (!isnull(cached_feedback_link))
|
||||
return cached_feedback_link
|
||||
|
||||
if (!SSdbcore.IsConnected())
|
||||
return FALSE
|
||||
|
||||
var/datum/db_query/feedback_query = SSdbcore.NewQuery("SELECT feedback FROM [format_table_name("admin")] WHERE ckey = '[owner.ckey]'")
|
||||
|
||||
if(!feedback_query.Execute())
|
||||
log_sql("Error retrieving feedback link for [src]")
|
||||
qdel(feedback_query)
|
||||
return FALSE
|
||||
|
||||
if(!feedback_query.NextRow())
|
||||
qdel(feedback_query)
|
||||
return FALSE // no feedback link exists
|
||||
|
||||
cached_feedback_link = feedback_query.item[1] || NO_FEEDBACK_LINK
|
||||
qdel(feedback_query)
|
||||
|
||||
if (cached_feedback_link == NO_FEEDBACK_LINK) // Because we don't want to send fake clickable links.
|
||||
return null
|
||||
|
||||
return cached_feedback_link
|
||||
|
||||
/datum/admins/proc/check_for_rights(rights_required)
|
||||
if(rights_required && !(rights_required & rank_flags()))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/admins/proc/check_if_greater_rights_than_holder(datum/admins/other)
|
||||
if(!other)
|
||||
return TRUE //they have no rights
|
||||
if(rank_flags() == R_EVERYTHING)
|
||||
return TRUE //we have all the rights
|
||||
if(src == other)
|
||||
return TRUE //you always have more rights than yourself
|
||||
if(rank_flags() != other.rank_flags())
|
||||
if( (rank_flags() & other.rank_flags()) == other.rank_flags() )
|
||||
return TRUE //we have all the rights they have and more
|
||||
return FALSE
|
||||
|
||||
/// Get the rank name of the admin
|
||||
/datum/admins/proc/rank_names()
|
||||
return join_admin_ranks(ranks)
|
||||
|
||||
/// Get the rank flags of the admin
|
||||
/datum/admins/proc/rank_flags()
|
||||
var/combined_flags = NONE
|
||||
|
||||
for (var/datum/admin_rank/rank as anything in ranks)
|
||||
combined_flags |= rank.rights
|
||||
|
||||
return combined_flags
|
||||
|
||||
/// Get the permissions this admin is allowed to edit on other ranks
|
||||
/datum/admins/proc/can_edit_rights_flags()
|
||||
var/combined_flags = NONE
|
||||
|
||||
for (var/datum/admin_rank/rank as anything in ranks)
|
||||
combined_flags |= rank.can_edit_rights
|
||||
|
||||
return combined_flags
|
||||
|
||||
/datum/admins/proc/try_give_profiling()
|
||||
if (CONFIG_GET(flag/forbid_admin_profiling))
|
||||
return
|
||||
|
||||
if (given_profiling)
|
||||
return
|
||||
|
||||
if (!(rank_flags() & R_DEBUG))
|
||||
return
|
||||
|
||||
given_profiling = TRUE
|
||||
world.SetConfig("APP/admin", owner.ckey, "role=admin")
|
||||
|
||||
/datum/admins/vv_edit_var(var_name, var_value)
|
||||
if(var_name == NAMEOF(src, rights) || var_name == NAMEOF(src, owner) || var_name == NAMEOF(src, rank))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
//TODO: Proccall guard, when all try/catch are removed and WrapAdminProccall is ported.
|
||||
return FALSE //nice try trialmin
|
||||
|
||||
/*
|
||||
checks if usr is an admin with at least ONE of the flags in rights_required. (Note, they don't need all the flags)
|
||||
@@ -69,45 +219,36 @@ if it doesn't return 1 and show_msg=1 it will prints a message explaining why th
|
||||
generally it would be used like so:
|
||||
|
||||
/proc/admin_proc()
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
to_world("you have enough rights!")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
to_chat(world, "you have enough rights!", confidential = TRUE)
|
||||
|
||||
NOTE: It checks usr by default. Supply the "user" argument if you wish to check for a specific mob.
|
||||
NOTE: it checks usr! not src! So if you're checking somebody's rank in a proc which they did not call
|
||||
you will have to do something like if(client.rights & R_ADMIN) yourself.
|
||||
*/
|
||||
/proc/check_rights(rights_required, show_msg=1, var/client/C = usr)
|
||||
if(ismob(C))
|
||||
var/mob/M = C
|
||||
C = M.client
|
||||
if(!C)
|
||||
return FALSE
|
||||
if(!(istype(C, /client))) // If we still didn't find a client, something is wrong.
|
||||
return FALSE
|
||||
if(!C.holder)
|
||||
if(show_msg)
|
||||
to_chat(C, span_filter_adminlog(span_warning("Error: You are not an admin.")))
|
||||
return FALSE
|
||||
|
||||
if(rights_required)
|
||||
if(rights_required & C.holder.rights)
|
||||
/proc/check_rights(rights_required, show_msg=1)
|
||||
if(usr?.client)
|
||||
if (check_rights_for(usr.client, rights_required))
|
||||
return TRUE
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(C, span_filter_adminlog(span_warning("Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].")))
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
to_chat(usr, "<font color='red'>Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].</font>", confidential = TRUE)
|
||||
return FALSE
|
||||
|
||||
//probably a bit iffy - will hopefully figure out a better solution
|
||||
/proc/check_if_greater_rights_than(client/other)
|
||||
if(usr && usr.client)
|
||||
if(usr?.client)
|
||||
if(usr.client.holder)
|
||||
if(!other || !other.holder)
|
||||
return 1
|
||||
if(usr.client.holder.rights != other.holder.rights)
|
||||
if( (usr.client.holder.rights & other.holder.rights) == other.holder.rights )
|
||||
return 1 //we have all the rights they have and more
|
||||
to_chat(usr, span_filter_adminlog(span_warning("Error: Cannot proceed. They have more or equal rights to us.")))
|
||||
return 0
|
||||
return TRUE
|
||||
return usr.client.holder.check_if_greater_rights_than_holder(other.holder)
|
||||
return FALSE
|
||||
|
||||
//This proc checks whether subject has at least ONE of the rights specified in rights_required.
|
||||
/proc/check_rights_for(client/subject, rights_required)
|
||||
if(subject?.holder)
|
||||
return subject.holder.check_for_rights(rights_required)
|
||||
return FALSE
|
||||
|
||||
/client/proc/mark_datum(datum/D)
|
||||
if(!holder)
|
||||
@@ -122,20 +263,6 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check
|
||||
set name = "Mark Object"
|
||||
mark_datum(D)
|
||||
|
||||
/client/proc/deadmin()
|
||||
if(holder)
|
||||
holder.disassociate()
|
||||
//qdel(holder)
|
||||
return 1
|
||||
|
||||
//This proc checks whether subject has at least ONE of the rights specified in rights_required.
|
||||
/proc/check_rights_for(client/subject, rights_required)
|
||||
if(subject && subject.holder)
|
||||
if(rights_required && !(rights_required & subject.holder.rights))
|
||||
return 0
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/proc/GenerateToken()
|
||||
. = ""
|
||||
for(var/I in 1 to 32)
|
||||
|
||||
561
code/modules/admin/permissionedit.dm
Normal file
561
code/modules/admin/permissionedit.dm
Normal file
@@ -0,0 +1,561 @@
|
||||
/client/proc/edit_admin_permissions()
|
||||
set category = "Admin.Secrets"
|
||||
set name = "Permissions Panel"
|
||||
set desc = "Edit admin permissions"
|
||||
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
usr.client.holder.edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/edit_admin_permissions(action, target, operation, page)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/group/permissions)
|
||||
asset_cache_datum.send(usr)
|
||||
|
||||
var/list/output = list("<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url("panels.css")]'><a href='byond://?_src_=holder;[HrefToken()];editrightsbrowser=1'>\[Permissions\]</a>")
|
||||
if(action)
|
||||
output += " | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a> | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a><hr style='background:#000000; border:0; height:3px'>"
|
||||
else
|
||||
output += "<br><a href='byond://?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><br><a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a>"
|
||||
if(action == 1)
|
||||
var/logcount = 0
|
||||
var/logssperpage = 20
|
||||
var/pagecount = 0
|
||||
page = text2num(page)
|
||||
var/datum/db_query/query_count_admin_logs = SSdbcore.NewQuery(
|
||||
"SELECT COUNT(id) FROM [format_table_name("admin_log")] WHERE (:target IS NULL OR adminckey = :target) AND (:operation IS NULL OR operation = :operation)",
|
||||
list("target" = target, "operation" = operation)
|
||||
)
|
||||
if(!query_count_admin_logs.warn_execute())
|
||||
qdel(query_count_admin_logs)
|
||||
return
|
||||
if(query_count_admin_logs.NextRow())
|
||||
logcount = text2num(query_count_admin_logs.item[1])
|
||||
qdel(query_count_admin_logs)
|
||||
if(logcount > logssperpage)
|
||||
output += "<br><b>Page: </b>"
|
||||
while(logcount > 0)
|
||||
output += "|<a href='byond://?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightstarget=[target];editrightsoperation=[operation];editrightspage=[pagecount]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>"
|
||||
logcount -= logssperpage
|
||||
pagecount++
|
||||
output += "|"
|
||||
var/datum/db_query/query_search_admin_logs = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
datetime,
|
||||
round_id,
|
||||
IFNULL((SELECT ckey FROM [format_table_name("erro_player")] WHERE ckey = adminckey), adminckey),
|
||||
operation,
|
||||
IF(ckey IS NULL, target, ckey),
|
||||
log
|
||||
FROM [format_table_name("admin_log")]
|
||||
LEFT JOIN [format_table_name("erro_player")] ON target = ckey
|
||||
WHERE (:target IS NULL OR ckey = :target) AND (:operation IS NULL OR operation = :operation)
|
||||
ORDER BY datetime DESC
|
||||
LIMIT :skip, :take
|
||||
"}, list("target" = target, "operation" = operation, "skip" = logssperpage * page, "take" = logssperpage))
|
||||
if(!query_search_admin_logs.warn_execute())
|
||||
qdel(query_search_admin_logs)
|
||||
return
|
||||
while(query_search_admin_logs.NextRow())
|
||||
var/datetime = query_search_admin_logs.item[1]
|
||||
var/round_id = query_search_admin_logs.item[2]
|
||||
var/admin_key = query_search_admin_logs.item[3]
|
||||
operation = query_search_admin_logs.item[4]
|
||||
target = query_search_admin_logs.item[5]
|
||||
var/log = query_search_admin_logs.item[6]
|
||||
output += "<p style='margin:0px'><b>[datetime] | Round ID [round_id] | Admin [admin_key] | Operation [operation] on [target]</b><br>[log]</p><hr style='background:#000000; border:0; height:3px'>"
|
||||
qdel(query_search_admin_logs)
|
||||
if(action == 2)
|
||||
output += "<h3>Admin ckeys with invalid ranks</h3>"
|
||||
var/datum/db_query/query_check_admin_errors = SSdbcore.NewQuery("SELECT IFNULL((SELECT ckey FROM [format_table_name("erro_player")] WHERE [format_table_name("erro_player")].ckey = [format_table_name("admin")].ckey), ckey), [format_table_name("admin")].`rank` FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].`rank` = [format_table_name("admin")].`rank` WHERE [format_table_name("admin_ranks")].`rank` IS NULL")
|
||||
if(!query_check_admin_errors.warn_execute())
|
||||
qdel(query_check_admin_errors)
|
||||
return
|
||||
while(query_check_admin_errors.NextRow())
|
||||
var/admin_key = query_check_admin_errors.item[1]
|
||||
var/admin_rank = query_check_admin_errors.item[2]
|
||||
output += "[admin_key] has non-existent rank [admin_rank] | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightschange=[admin_key]'>\[Change Rank\]</a> | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremove=[admin_key]'>\[Remove\]</a>"
|
||||
output += "<hr style='background:#000000; border:0; height:1px'>"
|
||||
qdel(query_check_admin_errors)
|
||||
output += "<h3>Unused ranks</h3>"
|
||||
var/datum/db_query/query_check_unused_rank = SSdbcore.NewQuery("SELECT [format_table_name("admin_ranks")].`rank`, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] LEFT JOIN [format_table_name("admin")] ON [format_table_name("admin")].`rank` = [format_table_name("admin_ranks")].`rank` WHERE [format_table_name("admin")].`rank` IS NULL")
|
||||
if(!query_check_unused_rank.warn_execute())
|
||||
qdel(query_check_unused_rank)
|
||||
return
|
||||
while(query_check_unused_rank.NextRow())
|
||||
var/admin_rank = query_check_unused_rank.item[1]
|
||||
output += {"Rank [admin_rank] is not held by any admin | <a href='byond://?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremoverank=[admin_rank]'>\[Remove\]</a>
|
||||
<br>Permissions: [rights2text(text2num(query_check_unused_rank.item[2])," ")]
|
||||
<br>Denied: [rights2text(text2num(query_check_unused_rank.item[3])," ", "-")]
|
||||
<br>Allowed to edit: [rights2text(text2num(query_check_unused_rank.item[4])," ", "*")]
|
||||
<hr style='background:#000000; border:0; height:1px'>"}
|
||||
qdel(query_check_unused_rank)
|
||||
else if(!action)
|
||||
output += {"
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
|
||||
<title>Permissions Panel</title>
|
||||
<script type='text/javascript' src='[SSassets.transport.get_asset_url("search.js")]'></script>
|
||||
</head>
|
||||
<body onload='selectTextField();updateSearch();'>
|
||||
<div id='main'><table id='searchable' cellspacing='0'>
|
||||
<tr class='title'>
|
||||
<th style='width:150px;'>CKEY <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
<th style='width:125px;'>RANK</th>
|
||||
<th>PERMISSIONS</th>
|
||||
</tr>
|
||||
"}
|
||||
for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/D = GLOB.admin_datums[adm_ckey]
|
||||
if(!D)
|
||||
D = GLOB.deadmins[adm_ckey]
|
||||
if (!D)
|
||||
continue
|
||||
var/deadminlink = ""
|
||||
if(D.owner)
|
||||
adm_ckey = D.owner.key
|
||||
if (D.deadmined)
|
||||
deadminlink = " <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=activate;key=[adm_ckey]'>\[RA\]</a>"
|
||||
else
|
||||
deadminlink = " <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=deactivate;key=[adm_ckey]'>\[DA\]</a>"
|
||||
|
||||
var/verify_link = ""
|
||||
//if (D.blocked_by_2fa)
|
||||
// verify_link += " | <a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=verify;key=[adm_ckey]'>\[2FA VERIFY\]</a>"
|
||||
|
||||
output += "<tr>"
|
||||
output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=remove;key=[adm_ckey]'>\[-\]</a><a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=sync;key=[adm_ckey]'>\[SYNC TGDB\]</a>[verify_link]</td>"
|
||||
output += "<td><a href='byond://?src=[REF(src)];[HrefToken()];editrights=rank;key=[adm_ckey]'>[D.rank_names()]</a></td>"
|
||||
output += "<td><a class='small' href='byond://?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank_flags(), " ")]</a></td>"
|
||||
output += "</tr>"
|
||||
output += "</table></div><div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div></body>"
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
usr << browse("<!DOCTYPE html><html>[jointext(output, "")]</html>","window=editrights;size=1000x650")
|
||||
|
||||
/datum/admins/proc/edit_rights_topic(list/href_list)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
message_admins("[key_name_admin(usr)] attempted to edit admin permissions without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to edit admin permissions without sufficient rights.")
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Edit blocked: Advanced ProcCall detected.</span>", confidential = TRUE)
|
||||
return
|
||||
var/datum/asset/permissions_assets = get_asset_datum(/datum/asset/simple/namespaced/common)
|
||||
permissions_assets.send(usr.client)
|
||||
var/admin_key = href_list["key"]
|
||||
var/admin_ckey = ckey(admin_key)
|
||||
|
||||
var/task = href_list["editrights"]
|
||||
var/datum/admins/target_admin_datum = GLOB.admin_datums[admin_ckey]
|
||||
if(!target_admin_datum)
|
||||
target_admin_datum = GLOB.deadmins[admin_ckey]
|
||||
if (!target_admin_datum && task != "add")
|
||||
return
|
||||
var/use_db
|
||||
var/skip
|
||||
var/legacy_only
|
||||
if(task == "activate" || task == "deactivate" || task == "sync" || task == "verify")
|
||||
skip = TRUE
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_admins) && task == "rank")
|
||||
if(admin_ckey in GLOB.protected_admins)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the rank of this admin is blocked by server configuration.</span>", confidential = TRUE)
|
||||
return
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && task == "permissions")
|
||||
if((target_admin_datum.ranks & GLOB.protected_ranks).len > 0)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the flags of this rank is blocked by server configuration.</span>", confidential = TRUE)
|
||||
return
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only) && (task == "add" || task == "rank" || task == "permissions"))
|
||||
to_chat(usr, "<span class='admin prefix'>Database rank loading is disabled, only temporary changes can be made to a rank's permissions and permanently creating a new rank is blocked.</span>", confidential = TRUE)
|
||||
legacy_only = TRUE
|
||||
//if(check_rights(R_DBRANKS, FALSE))
|
||||
if(!skip)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, span_danger("Unable to connect to database, changes are temporary only."), confidential = TRUE)
|
||||
use_db = FALSE
|
||||
else
|
||||
use_db = tgui_alert(usr,"Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", list("Permanent", "Temporary", "Cancel"))
|
||||
if(use_db == "Cancel")
|
||||
return
|
||||
if(use_db == "Permanent")
|
||||
use_db = TRUE
|
||||
else
|
||||
use_db = FALSE
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
|
||||
if(target_admin_datum && (task != "sync" && task != "verify") && !check_if_greater_rights_than_holder(target_admin_datum))
|
||||
message_admins("[key_name_admin(usr)] attempted to change the rank of [admin_key] without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to change the rank of [admin_key] without sufficient rights.")
|
||||
return
|
||||
switch(task)
|
||||
if("add")
|
||||
admin_ckey = add_admin(admin_ckey, admin_key, use_db)
|
||||
if(!admin_ckey)
|
||||
return
|
||||
|
||||
if(!admin_key) // Prevents failures in logging admin rank changes.
|
||||
admin_key = admin_ckey
|
||||
|
||||
change_admin_rank(admin_ckey, admin_key, use_db, null, legacy_only)
|
||||
if("remove")
|
||||
remove_admin(admin_ckey, admin_key, use_db, target_admin_datum)
|
||||
if("rank")
|
||||
change_admin_rank(admin_ckey, admin_key, use_db, target_admin_datum, legacy_only)
|
||||
if("permissions")
|
||||
change_admin_flags(admin_ckey, admin_key, target_admin_datum)
|
||||
if("activate")
|
||||
force_readmin(admin_key, target_admin_datum)
|
||||
if("deactivate")
|
||||
force_deadmin(admin_key, target_admin_datum)
|
||||
if("sync")
|
||||
sync_lastadminrank(admin_ckey, admin_key, target_admin_datum)
|
||||
/*
|
||||
if("verify")
|
||||
var/msg = "has authenticated [admin_ckey]"
|
||||
message_admins("[key_name_admin(usr)] [msg]")
|
||||
log_admin("[key_name(usr)] [msg]")
|
||||
|
||||
target_admin_datum.bypass_2fa = TRUE
|
||||
target_admin_datum.associate(GLOB.directory[admin_ckey])
|
||||
*/
|
||||
edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/add_admin(admin_ckey, admin_key, use_db)
|
||||
if(admin_ckey)
|
||||
. = admin_ckey
|
||||
else
|
||||
admin_key = input("New admin's key","Admin key") as text|null
|
||||
. = ckey(admin_key)
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!admin_ckey && (. in (GLOB.admin_datums+GLOB.deadmins)))
|
||||
to_chat(usr, span_danger("[admin_key] is already an admin."), confidential = TRUE)
|
||||
return FALSE
|
||||
if(use_db)
|
||||
//if an admin exists without a datum they won't be caught by the above
|
||||
var/datum/db_query/query_admin_in_db = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin")] WHERE ckey = :ckey",
|
||||
list("ckey" = .)
|
||||
)
|
||||
if(!query_admin_in_db.warn_execute())
|
||||
qdel(query_admin_in_db)
|
||||
return FALSE
|
||||
if(query_admin_in_db.NextRow())
|
||||
qdel(query_admin_in_db)
|
||||
to_chat(usr, span_danger("[admin_key] already listed in admin database. Check the Management tab if they don't appear in the list of admins."), confidential = TRUE)
|
||||
return FALSE
|
||||
qdel(query_admin_in_db)
|
||||
var/datum/db_query/query_add_admin = SSdbcore.NewQuery(
|
||||
"INSERT INTO [format_table_name("admin")] (ckey, `rank`) VALUES (:ckey, 'NEW ADMIN')",
|
||||
list("ckey" = .)
|
||||
)
|
||||
if(!query_add_admin.warn_execute())
|
||||
qdel(query_add_admin)
|
||||
return FALSE
|
||||
qdel(query_add_admin)
|
||||
var/datum/db_query/query_add_admin_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'add admin', :target, CONCAT('New admin added: ', :target))
|
||||
"}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = .))
|
||||
if(!query_add_admin_log.warn_execute())
|
||||
qdel(query_add_admin_log)
|
||||
return FALSE
|
||||
qdel(query_add_admin_log)
|
||||
|
||||
/datum/admins/proc/remove_admin(admin_ckey, admin_key, use_db, datum/admins/D)
|
||||
if(tgui_alert(usr,"Are you sure you want to remove [admin_ckey]?","Confirm Removal",list("Do it","Cancel")) == "Do it")
|
||||
GLOB.admin_datums -= admin_ckey
|
||||
GLOB.deadmins -= admin_ckey
|
||||
if(D)
|
||||
D.disassociate()
|
||||
var/m1 = "[key_name_admin(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
|
||||
var/m2 = "[key_name(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
|
||||
if(use_db)
|
||||
var/datum/db_query/query_add_rank = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("admin")] WHERE ckey = :ckey",
|
||||
list("ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'remove admin', :admin_ckey, CONCAT('Admin removed: ', :admin_ckey))
|
||||
"}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_ckey" = admin_ckey))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
qdel(query_add_rank_log)
|
||||
sync_lastadminrank(admin_ckey, admin_key)
|
||||
message_admins(m1)
|
||||
log_admin(m2)
|
||||
|
||||
/datum/admins/proc/force_readmin(admin_key, datum/admins/D)
|
||||
if(!D || !D.deadmined)
|
||||
return
|
||||
D.activate()
|
||||
message_admins("[key_name_admin(usr)] forcefully readmined [admin_key]")
|
||||
log_admin("[key_name(usr)] forcefully readmined [admin_key]")
|
||||
|
||||
/datum/admins/proc/force_deadmin(admin_key, datum/admins/D)
|
||||
if(!D || D.deadmined)
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] forcefully deadmined [admin_key]")
|
||||
log_admin("[key_name(usr)] forcefully deadmined [admin_key]")
|
||||
D.deactivate() //after logs so the deadmined admin can see the message.
|
||||
|
||||
#define RANK_DONE ":) I'm Done"
|
||||
|
||||
/datum/admins/proc/change_admin_rank(admin_ckey, admin_key, use_db, datum/admins/D, legacy_only)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
var/list/rank_names = list()
|
||||
if(!use_db || (use_db && !legacy_only))
|
||||
rank_names += "*New Rank*"
|
||||
for(var/datum/admin_rank/admin_rank as anything in GLOB.admin_ranks)
|
||||
if((admin_rank.rights & usr.client.holder.can_edit_rights_flags()) == admin_rank.rights)
|
||||
rank_names[admin_rank.name] = admin_rank
|
||||
|
||||
var/list/new_rank_names = list()
|
||||
var/list/custom_ranks = list()
|
||||
|
||||
while (TRUE)
|
||||
var/list/display_rank_names = list(RANK_DONE)
|
||||
|
||||
if (new_rank_names.len > 0)
|
||||
display_rank_names += "** SELECTED **"
|
||||
for (var/rank_name in new_rank_names)
|
||||
display_rank_names += rank_name
|
||||
display_rank_names += "---------"
|
||||
|
||||
for (var/rank_name in rank_names)
|
||||
if (!(rank_name in display_rank_names))
|
||||
display_rank_names += rank_name
|
||||
|
||||
var/next_rank = input("Please select a rank, or select [RANK_DONE] if you are finished.") as null|anything in display_rank_names
|
||||
|
||||
if (isnull(next_rank))
|
||||
return
|
||||
|
||||
if (next_rank == RANK_DONE)
|
||||
break
|
||||
|
||||
// They clicked "** SELECTED **" or something silly.
|
||||
if (!(next_rank in rank_names))
|
||||
continue
|
||||
|
||||
if (next_rank in new_rank_names)
|
||||
new_rank_names -= next_rank
|
||||
continue
|
||||
|
||||
if (next_rank == "*New Rank*")
|
||||
var/new_rank_name = input("Please input a new rank", "New custom rank") as text|null
|
||||
if (!new_rank_name)
|
||||
return
|
||||
|
||||
var/datum/admin_rank/custom_rank = rank_names[new_rank_name]
|
||||
if (isnull(custom_rank))
|
||||
if (D)
|
||||
custom_rank = new(new_rank_name, D.rank_flags())
|
||||
else
|
||||
custom_rank = new(new_rank_name)
|
||||
|
||||
GLOB.admin_ranks += custom_rank
|
||||
custom_ranks += custom_rank
|
||||
new_rank_names += new_rank_name
|
||||
|
||||
new_rank_names += next_rank
|
||||
|
||||
var/list/new_ranks = list()
|
||||
for (var/datum/admin_rank/admin_rank as anything in GLOB.admin_ranks)
|
||||
if (admin_rank.name in new_rank_names)
|
||||
new_ranks += admin_rank
|
||||
new_rank_names -= admin_rank.name
|
||||
|
||||
if (new_rank_names.len == 0)
|
||||
break
|
||||
|
||||
var/joined_rank = join_admin_ranks(new_ranks)
|
||||
var/m1 = "[key_name_admin(usr)] edited the admin rank of [admin_key] to [joined_rank] [use_db ? "permanently" : "temporarily"]"
|
||||
var/m2 = "[key_name(usr)] edited the admin rank of [admin_key] to [joined_rank] [use_db ? "permanently" : "temporarily"]"
|
||||
if(use_db)
|
||||
//if a player was tempminned before having a permanent change made to their rank they won't yet be in the db
|
||||
var/old_rank
|
||||
var/datum/db_query/query_admin_in_db = SSdbcore.NewQuery(
|
||||
"SELECT `rank` FROM [format_table_name("admin")] WHERE ckey = :admin_ckey",
|
||||
list("admin_ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_admin_in_db.warn_execute())
|
||||
qdel(query_admin_in_db)
|
||||
return
|
||||
if(!query_admin_in_db.NextRow())
|
||||
add_admin(admin_ckey, admin_key, TRUE)
|
||||
old_rank = "NEW ADMIN"
|
||||
else
|
||||
old_rank = query_admin_in_db.item[1]
|
||||
qdel(query_admin_in_db)
|
||||
|
||||
for (var/datum/admin_rank/custom_rank in custom_ranks)
|
||||
//similarly if a temp rank is created it won't be in the db if someone is permanently changed to it
|
||||
var/datum/db_query/query_rank_in_db = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin_ranks")] WHERE `rank` = :new_rank",
|
||||
list("new_rank" = custom_rank.name)
|
||||
)
|
||||
if(!query_rank_in_db.warn_execute())
|
||||
qdel(query_rank_in_db)
|
||||
return
|
||||
if(!query_rank_in_db.NextRow())
|
||||
QDEL_NULL(query_rank_in_db)
|
||||
var/datum/db_query/query_add_rank = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_ranks")] (`rank`, flags, exclude_flags, can_edit_flags)
|
||||
VALUES (:new_rank, '0', '0', '0')
|
||||
"}, list("new_rank" = custom_rank.name))
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'add rank', :new_rank, CONCAT('New rank added: ', :new_rank))
|
||||
"}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "new_rank" = custom_rank.name))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
qdel(query_add_rank_log)
|
||||
qdel(query_rank_in_db)
|
||||
var/datum/db_query/query_change_rank = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("admin")] SET `rank` = :new_rank WHERE ckey = :admin_ckey",
|
||||
list("new_rank" = joined_rank, "admin_ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_change_rank.warn_execute())
|
||||
qdel(query_change_rank)
|
||||
return
|
||||
qdel(query_change_rank)
|
||||
var/datum/db_query/query_change_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'change admin rank', :target, CONCAT('Rank of ', :target, ' changed from ', :old_rank, ' to ', :new_rank))
|
||||
"}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = admin_ckey, "old_rank" = old_rank, "new_rank" = joined_rank))
|
||||
if(!query_change_rank_log.warn_execute())
|
||||
qdel(query_change_rank_log)
|
||||
return
|
||||
qdel(query_change_rank_log)
|
||||
if(D) //they were previously an admin
|
||||
D.disassociate() //existing admin needs to be disassociated
|
||||
D.ranks = new_ranks //set the admin_rank as our rank
|
||||
//D.bypass_2fa = TRUE // Another admin has cleared us
|
||||
var/client/C = GLOB.directory[admin_ckey]
|
||||
D.associate(C)
|
||||
else
|
||||
D = new(new_ranks, admin_ckey) //new admin
|
||||
//D.bypass_2fa = TRUE // Another admin has cleared us
|
||||
D.activate()
|
||||
message_admins(m1)
|
||||
log_admin(m2)
|
||||
|
||||
#undef RANK_DONE
|
||||
|
||||
/datum/admins/proc/change_admin_flags(admin_ckey, admin_key, datum/admins/admin_holder)
|
||||
var/new_flags = input_bitfield(
|
||||
usr,
|
||||
"Admin rights<br>This will affect only the current admin [admin_key]",
|
||||
"admin_flags",
|
||||
admin_holder.rank_flags(),
|
||||
350,
|
||||
590,
|
||||
allowed_edit_list = usr.client.holder.can_edit_rights_flags(),
|
||||
)
|
||||
|
||||
admin_holder.disassociate()
|
||||
|
||||
if (findtext(admin_holder.rank_names(), "([admin_ckey])"))
|
||||
var/datum/admin_rank/rank = admin_holder.ranks[1]
|
||||
rank.rights = new_flags
|
||||
rank.include_rights = new_flags
|
||||
rank.exclude_rights = NONE
|
||||
rank.can_edit_rights = rank.can_edit_rights
|
||||
else
|
||||
// Not a modified subrank, need to duplicate the admin_rank datum to prevent modifying others too.
|
||||
var/datum/admin_rank/new_admin_rank = new(
|
||||
/* init_name = */ "[admin_holder.rank_names()]([admin_ckey])",
|
||||
/* init_rights = */ new_flags,
|
||||
|
||||
// rank_flags() includes the exclude rights, so we no longer need to handle them separately.
|
||||
/* init_exclude_rights = */ NONE,
|
||||
|
||||
/* init_edit_rights = */ admin_holder.can_edit_rights_flags(),
|
||||
)
|
||||
|
||||
admin_holder.ranks = list(new_admin_rank)
|
||||
|
||||
var/log = "[key_name(usr)] has updated the admin rights of [admin_ckey] into [rights2text(new_flags)]"
|
||||
message_admins(log)
|
||||
log_admin(log)
|
||||
|
||||
var/client/admin_client = GLOB.directory[admin_ckey]
|
||||
admin_holder.associate(admin_client)
|
||||
|
||||
/datum/admins/proc/remove_rank(admin_rank)
|
||||
if(!admin_rank)
|
||||
return
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == admin_rank && (!(R.rights & usr.client.holder.can_edit_rights_flags()) == R.rights))
|
||||
to_chat(usr, "<span class='admin prefix'>You don't have edit rights to all the rights this rank has, rank deletion not permitted.</span>", confidential = TRUE)
|
||||
return
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && (admin_rank in GLOB.protected_ranks))
|
||||
to_chat(usr, "<span class='admin prefix'>Deletion of protected ranks is not permitted, it must be removed from admin_ranks.txt.</span>", confidential = TRUE)
|
||||
return
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
||||
to_chat(usr, "<span class='admin prefix'>Rank deletion not permitted while database rank loading is disabled.</span>", confidential = TRUE)
|
||||
return
|
||||
var/datum/db_query/query_admins_with_rank = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin")] WHERE `rank` = :admin_rank",
|
||||
list("admin_rank" = admin_rank)
|
||||
)
|
||||
if(!query_admins_with_rank.warn_execute())
|
||||
qdel(query_admins_with_rank)
|
||||
return
|
||||
if(query_admins_with_rank.NextRow())
|
||||
qdel(query_admins_with_rank)
|
||||
to_chat(usr, span_danger("Error: Rank deletion attempted while rank still used; Tell a coder, this shouldn't happen."), confidential = TRUE)
|
||||
return
|
||||
qdel(query_admins_with_rank)
|
||||
if(tgui_alert(usr,"Are you sure you want to remove [admin_rank]?","Confirm Removal",list("Do it","Cancel")) == "Do it")
|
||||
var/m1 = "[key_name_admin(usr)] removed rank [admin_rank] permanently"
|
||||
var/m2 = "[key_name(usr)] removed rank [admin_rank] permanently"
|
||||
var/datum/db_query/query_add_rank = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("admin_ranks")] WHERE `rank` = :admin_rank",
|
||||
list("admin_rank" = admin_rank)
|
||||
)
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'remove rank', :admin_rank, CONCAT('Rank removed: ', :admin_rank))
|
||||
"}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_rank" = admin_rank))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
qdel(query_add_rank_log)
|
||||
message_admins(m1)
|
||||
log_admin(m2)
|
||||
|
||||
/datum/admins/proc/sync_lastadminrank(admin_ckey, admin_key, datum/admins/D)
|
||||
var/sqlrank = "Player"
|
||||
if (D)
|
||||
sqlrank = D.rank_names()
|
||||
var/datum/db_query/query_sync_lastadminrank = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("erro_player")] SET lastadminrank = :rank WHERE ckey = :ckey",
|
||||
list("rank" = sqlrank, "ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_sync_lastadminrank.warn_execute())
|
||||
qdel(query_sync_lastadminrank)
|
||||
return
|
||||
qdel(query_sync_lastadminrank)
|
||||
to_chat(usr, span_admin("Sync of [admin_key] successful."), confidential = TRUE)
|
||||
@@ -1,158 +0,0 @@
|
||||
/client/proc/edit_admin_permissions()
|
||||
set category = "Admin.Secrets"
|
||||
set name = "Permissions Panel"
|
||||
set desc = "Edit admin permissions"
|
||||
if(!check_rights(R_PERMISSIONS)) return
|
||||
usr.client.holder.edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/edit_admin_permissions()
|
||||
if(!check_rights(R_PERMISSIONS)) return
|
||||
|
||||
var/output = {"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Permissions Panel</title>
|
||||
<script type='text/javascript' src='search.js'></script>
|
||||
<link rel='stylesheet' type='text/css' href='panels.css'>
|
||||
</head>
|
||||
<body onload='selectTextField();updateSearch();'>
|
||||
<div id='main'><table id='searchable' cellspacing='0'>
|
||||
<tr class='title'>
|
||||
<th style='width:125px;text-align:right;'>CKEY <a class='small' href='byond://?src=\ref[src];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
<th style='width:125px;'>RANK</th><th style='width:100%;'>PERMISSIONS</th>
|
||||
</tr>
|
||||
"}
|
||||
|
||||
for(var/adm_ckey in admin_datums)
|
||||
var/datum/admins/D = admin_datums[adm_ckey]
|
||||
if(!D) continue
|
||||
var/rank = D.rank ? D.rank : "*none*"
|
||||
var/rights = rights2text(D.rights," ")
|
||||
if(!rights) rights = "*none*"
|
||||
|
||||
output += "<tr>"
|
||||
output += "<td style='text-align:right;'>[adm_ckey] <a class='small' href='byond://?src=\ref[src];[HrefToken()];editrights=remove;ckey=[adm_ckey]'>\[-\]</a></td>"
|
||||
output += "<td><a href='byond://?src=\ref[src];[HrefToken()];editrights=rank;ckey=[adm_ckey]'>[rank]</a></td>"
|
||||
output += "<td><a class='small' href='byond://?src=\ref[src];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights]</a></td>"
|
||||
output += "</tr>"
|
||||
|
||||
output += {"
|
||||
</table></div>
|
||||
<div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div>
|
||||
</body>
|
||||
</html>"}
|
||||
|
||||
usr << browse(output,"window=editrights;size=600x500")
|
||||
|
||||
/datum/admins/proc/log_admin_rank_modification(var/adm_ckey, var/new_rank)
|
||||
if(CONFIG_GET(flag/admin_legacy_system)) return
|
||||
|
||||
if(!usr.client)
|
||||
return
|
||||
|
||||
if(!usr.client.holder || !(usr.client.holder.rights & R_PERMISSIONS))
|
||||
to_chat(usr, span_filter_adminlog("[span_red("You do not have permission to do this!")]"))
|
||||
return
|
||||
|
||||
establish_db_connection()
|
||||
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection")]"))
|
||||
return
|
||||
|
||||
if(!adm_ckey || !new_rank)
|
||||
return
|
||||
|
||||
adm_ckey = ckey(adm_ckey)
|
||||
|
||||
if(!adm_ckey)
|
||||
return
|
||||
|
||||
if(!istext(adm_ckey) || !istext(new_rank))
|
||||
return
|
||||
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id FROM erro_admin WHERE ckey = '[adm_ckey]'")
|
||||
select_query.Execute()
|
||||
|
||||
var/new_admin = 1
|
||||
var/admin_id
|
||||
while(select_query.NextRow())
|
||||
new_admin = 0
|
||||
admin_id = text2num(select_query.item[1])
|
||||
|
||||
qdel(select_query)
|
||||
if(new_admin)
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO `erro_admin` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)")
|
||||
insert_query.Execute()
|
||||
qdel(insert_query)
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');")
|
||||
log_query.Execute()
|
||||
qdel(log_query)
|
||||
to_chat(usr, span_filter_adminlog("[span_blue("New admin added.")]"))
|
||||
else
|
||||
if(!isnull(admin_id) && isnum(admin_id))
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE `erro_admin` SET rank = '[new_rank]' WHERE id = [admin_id]")
|
||||
insert_query.Execute()
|
||||
qdel(insert_query)
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');")
|
||||
log_query.Execute()
|
||||
qdel(log_query)
|
||||
to_chat(usr, span_filter_adminlog("[span_blue("Admin rank changed.")]"))
|
||||
|
||||
/datum/admins/proc/log_admin_permission_modification(var/adm_ckey, var/new_permission)
|
||||
if(CONFIG_GET(flag/admin_legacy_system)) return
|
||||
|
||||
if(!usr.client)
|
||||
return
|
||||
|
||||
if(!usr.client.holder || !(usr.client.holder.rights & R_PERMISSIONS))
|
||||
to_chat(usr, span_filter_adminlog("[span_red(">You do not have permission to do this!")]"))
|
||||
return
|
||||
|
||||
establish_db_connection()
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection!")]"))
|
||||
return
|
||||
|
||||
if(!adm_ckey || !new_permission)
|
||||
return
|
||||
|
||||
adm_ckey = ckey(adm_ckey)
|
||||
|
||||
if(!adm_ckey)
|
||||
return
|
||||
|
||||
if(istext(new_permission))
|
||||
new_permission = text2num(new_permission)
|
||||
|
||||
if(!istext(adm_ckey) || !isnum(new_permission))
|
||||
return
|
||||
|
||||
var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id, flags FROM erro_admin WHERE ckey = '[adm_ckey]'")
|
||||
select_query.Execute()
|
||||
|
||||
var/admin_id
|
||||
var/admin_rights
|
||||
while(select_query.NextRow())
|
||||
admin_id = text2num(select_query.item[1])
|
||||
admin_rights = text2num(select_query.item[2])
|
||||
qdel(select_query)
|
||||
if(!admin_id)
|
||||
return
|
||||
|
||||
if(admin_rights & new_permission) //This admin already has this permission, so we are removing it.
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE `erro_admin` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]")
|
||||
insert_query.Execute()
|
||||
qdel(insert_query)
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');")
|
||||
log_query.Execute()
|
||||
qdel(log_query)
|
||||
to_chat(usr, span_filter_adminlog("[span_blue("Permission removed.")]"))
|
||||
else //This admin doesn't have this permission, so we are adding it.
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE `erro_admin` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]")
|
||||
insert_query.Execute()
|
||||
qdel(insert_query)
|
||||
var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')")
|
||||
log_query.Execute()
|
||||
qdel(log_query)
|
||||
to_chat(usr, span_filter_adminlog("[span_blue("Permission added.")]"))
|
||||
@@ -27,7 +27,7 @@
|
||||
var/datum/player_info/P = new
|
||||
if (user)
|
||||
P.author = user.key
|
||||
P.rank = user.client.holder.rank
|
||||
P.rank = user.client.holder.rank_names()
|
||||
else
|
||||
P.author = "Adminbot"
|
||||
P.rank = "Friendly Robot"
|
||||
|
||||
@@ -129,99 +129,23 @@
|
||||
if((bantype == BANTYPE_PERMA || bantype == BANTYPE_TEMP) && playermob.client)
|
||||
qdel(playermob.client)
|
||||
|
||||
else if(href_list["editrightsbrowser"])
|
||||
edit_admin_permissions(0)
|
||||
|
||||
else if(href_list["editrightsbrowserlog"])
|
||||
edit_admin_permissions(1, href_list["editrightstarget"], href_list["editrightsoperation"], href_list["editrightspage"])
|
||||
|
||||
if(href_list["editrightsbrowsermanage"])
|
||||
if(href_list["editrightschange"])
|
||||
change_admin_rank(ckey(href_list["editrightschange"]), href_list["editrightschange"], TRUE)
|
||||
else if(href_list["editrightsremove"])
|
||||
remove_admin(ckey(href_list["editrightsremove"]), href_list["editrightsremove"], TRUE)
|
||||
else if(href_list["editrightsremoverank"])
|
||||
remove_rank(href_list["editrightsremoverank"])
|
||||
edit_admin_permissions(2)
|
||||
|
||||
else if(href_list["editrights"])
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
message_admins("[key_name_admin(usr)] attempted to edit the admin permissions without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to edit the admin permissions without sufficient rights.")
|
||||
return
|
||||
|
||||
var/adm_ckey
|
||||
|
||||
var/task = href_list["editrights"]
|
||||
if(task == "add")
|
||||
var/new_ckey = ckey(tgui_input_text(usr,"New admin's ckey","Admin ckey", null))
|
||||
if(!new_ckey) return
|
||||
if(new_ckey in admin_datums)
|
||||
to_chat(usr, span_filter_adminlog(span_warning("Error: Topic 'editrights': [new_ckey] is already an admin")))
|
||||
return
|
||||
adm_ckey = new_ckey
|
||||
task = "rank"
|
||||
else if(task != "show")
|
||||
adm_ckey = ckey(href_list["ckey"])
|
||||
if(!adm_ckey)
|
||||
to_chat(usr, span_filter_adminlog(span_warning("Error: Topic 'editrights': No valid ckey")))
|
||||
return
|
||||
|
||||
var/datum/admins/D = admin_datums[adm_ckey]
|
||||
|
||||
if(task == "remove")
|
||||
if(tgui_alert(usr, "Are you sure you want to remove [adm_ckey]?","Message",list("Yes","Cancel")) == "Yes")
|
||||
if(!D) return
|
||||
admin_datums -= adm_ckey
|
||||
D.disassociate()
|
||||
|
||||
message_admins("[key_name_admin(usr)] removed [adm_ckey] from the admins list")
|
||||
log_admin("[key_name(usr)] removed [adm_ckey] from the admins list")
|
||||
log_admin_rank_modification(adm_ckey, "Removed")
|
||||
|
||||
else if(task == "rank")
|
||||
var/new_rank
|
||||
if(admin_ranks.len)
|
||||
new_rank = tgui_input_list(usr, "Please select a rank", "New rank", (admin_ranks|"*New Rank*"))
|
||||
else
|
||||
new_rank = tgui_input_list(usr, "Please select a rank", "New rank", list("Game Master","Head Admin","Game Admin", "Trial Admin", "Admin Observer","Moderator","Mentor","Badmin","Retired Admin","Event Manager","Developer","DevMod","*New Rank*")) //CHOMP Edit bandaid fix to assigning titles because we're having some funky database issues, I think. Other option is to manually edit database entry for someone's title.
|
||||
|
||||
var/rights = 0
|
||||
if(D)
|
||||
rights = D.rights
|
||||
switch(new_rank)
|
||||
if(null,"") return
|
||||
if("*New Rank*")
|
||||
new_rank = tgui_input_text(usr, "Please input a new rank", "New custom rank")
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
new_rank = ckeyEx(new_rank)
|
||||
if(!new_rank)
|
||||
to_chat(usr, span_filter_adminlog(span_warning("Error: Topic 'editrights': Invalid rank")))
|
||||
return
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
if(admin_ranks.len)
|
||||
if(new_rank in admin_ranks)
|
||||
rights = admin_ranks[new_rank] //we typed a rank which already exists, use its rights
|
||||
else
|
||||
admin_ranks[new_rank] = 0 //add the new rank to admin_ranks
|
||||
else
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
new_rank = ckeyEx(new_rank)
|
||||
rights = admin_ranks[new_rank] //we input an existing rank, use its rights
|
||||
|
||||
if(D)
|
||||
D.disassociate() //remove adminverbs and unlink from client
|
||||
D.rank = new_rank //update the rank
|
||||
D.rights = rights //update the rights based on admin_ranks (default: 0)
|
||||
else
|
||||
D = new /datum/admins(new_rank, rights, adm_ckey)
|
||||
|
||||
var/client/C = GLOB.directory[adm_ckey] //find the client with the specified ckey (if they are logged in)
|
||||
D.associate(C) //link up with the client and add verbs
|
||||
|
||||
message_admins("[key_name_admin(usr)] edited the admin rank of [adm_ckey] to [new_rank]")
|
||||
log_admin("[key_name(usr)] edited the admin rank of [adm_ckey] to [new_rank]")
|
||||
log_admin_rank_modification(adm_ckey, new_rank)
|
||||
|
||||
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 = tgui_input_list(usr, "Select a permission to turn on/off", "Permission toggle", permissionlist)
|
||||
if(!new_permission) return
|
||||
D.rights ^= 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()
|
||||
edit_rights_topic(href_list)
|
||||
|
||||
else if(href_list["call_shuttle"])
|
||||
if(!check_rights(R_ADMIN|R_EVENT)) return
|
||||
@@ -692,7 +616,7 @@
|
||||
return
|
||||
|
||||
if(M != usr) //we can jobban ourselves
|
||||
if(M.client && M.client.holder && (M.client.holder.rights & R_BAN)) //they can ban too. So we can't ban them
|
||||
if(M.client && M.client.holder && (check_rights_for(M.client, R_BAN))) //they can ban too. So we can't ban them
|
||||
tgui_alert_async(usr, "You cannot perform this action. You must be of a higher administrative rank!")
|
||||
return
|
||||
|
||||
@@ -1364,7 +1288,7 @@
|
||||
if(ismob(M))
|
||||
var/take_msg = span_notice("<b>ADMINHELP</b>: <b>[key_name(usr.client)]</b> is attending to <b>[key_name(M)]'s</b> adminhelp, please don't dogpile them.")
|
||||
for(var/client/X in GLOB.admins)
|
||||
if((R_ADMIN|R_MOD|R_SERVER) & X.holder.rights) //VOREStation Edit
|
||||
if(check_rights_for(X, (R_ADMIN|R_MOD|R_SERVER)))
|
||||
to_chat(X, take_msg)
|
||||
to_chat(M, span_filter_pm(span_boldnotice("Your adminhelp is being attended to by [usr.client]. Thanks for your patience!")))
|
||||
// VoreStation Edit Start
|
||||
|
||||
27
code/modules/admin/verb_datums/_admin_verb_datum.dm
Normal file
27
code/modules/admin/verb_datums/_admin_verb_datum.dm
Normal file
@@ -0,0 +1,27 @@
|
||||
GENERAL_PROTECT_DATUM(/datum/admin_verb)
|
||||
|
||||
/**
|
||||
* This is the admin verb datum. It is used to store the verb's information and handle the verb's functionality.
|
||||
* All of this is setup for you, and you should not be defining this manually.
|
||||
* That means you reader.
|
||||
*/
|
||||
/datum/admin_verb
|
||||
var/name //! The name of the verb.
|
||||
var/description //! The description of the verb.
|
||||
var/category //! The category of the verb.
|
||||
var/permissions //! The permissions required to use the verb.
|
||||
var/visibility_flag //! The flag that determines if the verb is visible.
|
||||
VAR_PROTECTED/verb_path //! The path to the verb proc.
|
||||
|
||||
/datum/admin_verb/Destroy(force)
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
return ..()
|
||||
|
||||
/// Assigns the verb to the admin.
|
||||
/datum/admin_verb/proc/assign_to_client(client/admin)
|
||||
add_verb(admin, verb_path)
|
||||
|
||||
/// Unassigns the verb from the admin.
|
||||
/datum/admin_verb/proc/unassign_from_client(client/admin)
|
||||
remove_verb(admin, verb_path)
|
||||
@@ -296,7 +296,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
//send this msg to all admins
|
||||
|
||||
for(var/client/X in GLOB.admins)
|
||||
// if(!check_rights(R_ADMIN, 0, X)) //CHOMP Remove let everyone hear the ahelp
|
||||
// if(!check_rights_for(X, R_ADMIN)) //CHOMP Remove let everyone hear the ahelp
|
||||
// continue //CHOMP Remove let everyone hear the ahelp
|
||||
if(X.prefs?.read_preference(/datum/preference/toggle/holder/play_adminhelp_ping))
|
||||
X << 'sound/effects/adminhelp.ogg'
|
||||
@@ -723,7 +723,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
. = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
|
||||
for(var/client/X in GLOB.admins)
|
||||
.["total"] += X
|
||||
if(requiredflags != 0 && !check_rights(rights_required = requiredflags, show_msg = FALSE, C = X))
|
||||
if(requiredflags != 0 && !check_rights_for(X, requiredflags))
|
||||
.["noflags"] += X
|
||||
else if(X.is_afk())
|
||||
.["afk"] += X
|
||||
|
||||
@@ -202,14 +202,14 @@
|
||||
if(irc)
|
||||
log_admin("PM: [key_name(src)]->IRC: [rawmsg]")
|
||||
for(var/client/X in GLOB.admins)
|
||||
if(!check_rights(R_ADMIN|R_SERVER, 0, X)) //CHOMPEdit
|
||||
if(!check_rights_for(X, R_ADMIN|R_SERVER)) //CHOMPEdit
|
||||
continue
|
||||
to_chat(X, span_admin_pm_notice(span_bold("PM: [key_name(src, X, 0)]->IRC:") + " [keywordparsedmsg]"))
|
||||
else
|
||||
log_admin("PM: [key_name(src)]->[key_name(recipient)]: [rawmsg]")
|
||||
//we don't use message_admins here because the sender/receiver might get it too
|
||||
for(var/client/X in GLOB.admins)
|
||||
if(!check_rights(R_ADMIN|R_SERVER, 0, X)) //CHOMPEdit
|
||||
if(!check_rights_for(X, R_ADMIN|R_SERVER)) //CHOMPEdit
|
||||
continue
|
||||
if(X.key!=key && X.key!=recipient.key) //check client/X is an admin and isn't the sender or recipient
|
||||
to_chat(X, span_admin_pm_notice(span_bold("PM: [key_name(src, X, 0)]->[key_name(recipient, X, 0)]:") + " [keywordparsedmsg]"))
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
log_adminsay(msg,src)
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(check_rights(R_ADMIN, 0, C))
|
||||
if(check_rights_for(C, R_ADMIN))
|
||||
to_chat(C, span_admin_channel(create_text_tag("admin", "ADMIN:", C) + " " + span_name("[key_name(usr, 1)]") + "([admin_jump_link(mob, src)]): " + span_name("[msg]") ))
|
||||
|
||||
feedback_add_details("admin_verb","M") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
display_name = usr.client.holder.fakekey
|
||||
|
||||
// Name shown to other players. Admins whom are not also antags have their rank displayed.
|
||||
var/player_display = (is_admin && !is_antag) ? "[display_name]([usr.client.holder.rank])" : display_name
|
||||
var/player_display = (is_admin && !is_antag) ? "[display_name]([usr.client.holder.rank_names()])" : display_name
|
||||
|
||||
for(var/mob/M in mob_list)
|
||||
if(check_rights(R_ADMIN|R_MOD|R_EVENT, 0, M)) // Staff can see AOOC unconditionally, and with more details.
|
||||
if(check_rights_for(M.client, R_ADMIN|R_MOD|R_EVENT)) // Staff can see AOOC unconditionally, and with more details.
|
||||
to_chat(M, span_ooc(span_aooc("[create_text_tag("aooc", "Antag-OOC:", M.client)] <EM>[get_options_bar(src, 0, 1, 1)]([admin_jump_link(usr, M.client.holder)]):</EM> " + span_message("[msg]"))))
|
||||
else if(M.client) // Players can only see AOOC if observing, or if they are an antag type allowed to use AOOC.
|
||||
var/datum/antagonist/A = null
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
if (src.handle_spam_prevention(msg,MUTE_DEADCHAT))
|
||||
return
|
||||
|
||||
var/stafftype = uppertext(holder.rank)
|
||||
var/stafftype = uppertext(holder.rank_names())
|
||||
|
||||
msg = sanitize(msg)
|
||||
log_admin("DSAY: [key_name(src)] : [msg]")
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
var/msg = span_filter_pray(span_blue("[icon2html(cross, GLOB.admins)] <b>" + span_purple("PRAY: ") + "[key_name(src, 1)] [ADMIN_QUE(src)] [ADMIN_PP(src)] [ADMIN_VV(src)] [ADMIN_SM(src)] ([admin_jump_link(src, src)]) [ADMIN_CA(src)] [ADMIN_SC(src)] [ADMIN_SMITE(src)]:</b> [raw_msg]"))
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(!check_rights(R_ADMIN|R_EVENT, 0, C)) //CHOMPEdit
|
||||
if(!check_rights_for(C, R_ADMIN|R_EVENT)) //CHOMPEdit
|
||||
continue
|
||||
if(C.prefs?.read_preference(/datum/preference/toggle/show_chat_prayers))
|
||||
to_chat(C, msg, type = MESSAGE_TYPE_PRAYER, confidential = TRUE)
|
||||
@@ -29,7 +29,7 @@
|
||||
/proc/CentCom_announce(var/msg, var/mob/Sender, var/iamessage)
|
||||
msg = span_blue(span_bold(span_orange("[uppertext(using_map.boss_short)]M[iamessage ? " IA" : ""]:") + "[key_name(Sender, 1)] [ADMIN_PP(Sender)] [ADMIN_VV(Sender)] [ADMIN_SM(Sender)] ([admin_jump_link(Sender)]) [ADMIN_CA(Sender)] [ADMIN_BSA(Sender)] [ADMIN_CENTCOM_REPLY(Sender)]:") + " [msg]")
|
||||
for(var/client/C in GLOB.admins) //VOREStation Edit - GLOB admins
|
||||
if(!check_rights(R_ADMIN|R_EVENT, 0, C)) //CHOMPEdit
|
||||
if(!check_rights_for(C, R_ADMIN|R_EVENT)) //CHOMPEdit
|
||||
continue
|
||||
to_chat(C,msg)
|
||||
C << 'sound/machines/signal.ogg'
|
||||
@@ -37,7 +37,7 @@
|
||||
/proc/Syndicate_announce(var/msg, var/mob/Sender)
|
||||
msg = span_blue(span_bold(span_crimson("ILLEGAL:") + "[key_name(Sender, 1)] [ADMIN_PP(Sender)] [ADMIN_VV(Sender)] [ADMIN_SM(Sender)] ([admin_jump_link(Sender)]) [ADMIN_CA(Sender)] [ADMIN_BSA(Sender)] [ADMIN_SYNDICATE_REPLY(Sender)]:") + " [msg]")
|
||||
for(var/client/C in GLOB.admins) //VOREStation Edit - GLOB admins
|
||||
if(!check_rights(R_ADMIN|R_EVENT, 0, C)) //CHOMPEdit
|
||||
if(!check_rights_for(C, R_ADMIN|R_EVENT)) //CHOMPEdit
|
||||
continue
|
||||
to_chat(C,msg)
|
||||
C << 'sound/machines/signal.ogg'
|
||||
|
||||
30
code/modules/admin/verbs/special_verbs.dm
Normal file
30
code/modules/admin/verbs/special_verbs.dm
Normal file
@@ -0,0 +1,30 @@
|
||||
// Admin Verbs in this file are special and cannot use the AVD system for some reason or another.
|
||||
|
||||
/client/proc/readmin()
|
||||
set name = "Readmin"
|
||||
set category = "Admin.Misc"
|
||||
set desc = "Regain your admin powers."
|
||||
|
||||
var/datum/admins/A = GLOB.deadmins[ckey]
|
||||
|
||||
if(!A)
|
||||
A = GLOB.admin_datums[ckey]
|
||||
if (!A)
|
||||
var/msg = " is trying to readmin but they have no deadmin entry"
|
||||
message_admins("[key_name_admin(src)][msg]")
|
||||
log_admin_private("[key_name(src)][msg]")
|
||||
return
|
||||
|
||||
A.associate(src)
|
||||
|
||||
if(!holder)
|
||||
return //This can happen if an admin attempts to vv themself into somebody elses's deadmin datum by getting ref via brute force
|
||||
|
||||
to_chat(src, span_interface("You are now an admin."), confidential = TRUE)
|
||||
message_admins("[src] re-adminned themselves.")
|
||||
log_admin("[src] re-adminned themselves.")
|
||||
//BLACKBOX_LOG_ADMIN_VERB("Readmin")
|
||||
|
||||
if(isobserver(mob))
|
||||
var/mob/observer/dead/our_mob = mob
|
||||
our_mob.visualnet?.addVisibility(our_mob, src)
|
||||
@@ -172,21 +172,24 @@
|
||||
/client/VV_ckey_edit()
|
||||
return list("key", "ckey")
|
||||
|
||||
/datum/proc/may_edit_var(var/user, var/var_to_edit)
|
||||
/datum/proc/may_edit_var(var/user, var/var_to_edit) //User must be a CLIENT that is passed to this.
|
||||
if(!user)
|
||||
return FALSE
|
||||
if(ismob(user)) //Failsafe catch in case someone feeds a mob into us.
|
||||
var/mob/living = user
|
||||
user = living.client
|
||||
if(!(var_to_edit in vars))
|
||||
to_chat(user, span_warning("\The [src] does not have a var '[var_to_edit]'"))
|
||||
return FALSE
|
||||
if(var_to_edit in VV_static())
|
||||
return FALSE
|
||||
if((var_to_edit in VV_secluded()) && !check_rights(R_ADMIN|R_DEBUG, FALSE, C = user))
|
||||
if((var_to_edit in VV_secluded()) && !check_rights_for(user, R_ADMIN|R_DEBUG))
|
||||
return FALSE
|
||||
if((var_to_edit in VV_locked()) && !check_rights(R_DEBUG, C = user))
|
||||
if((var_to_edit in VV_locked()) && !check_rights_for(user, R_DEBUG))
|
||||
return FALSE
|
||||
if((var_to_edit in VV_ckey_edit()) && !check_rights(R_SPAWN|R_DEBUG, C = user))
|
||||
if((var_to_edit in VV_ckey_edit()) && !check_rights_for(user, R_SPAWN|R_DEBUG))
|
||||
return FALSE
|
||||
if((var_to_edit in VV_icon_edit_lock()) && !check_rights(R_FUN|R_DEBUG, C = user))
|
||||
if((var_to_edit in VV_icon_edit_lock()) && !check_rights_for(user, R_FUN|R_DEBUG))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/datum/asset/simple/generic
|
||||
assets = list(
|
||||
"search.js" = 'html/search.js',
|
||||
"panels.css" = 'html/panels.css',
|
||||
"loading.gif" = 'html/images/loading.gif',
|
||||
"ntlogo.png" = 'html/images/ntlogo.png',
|
||||
"sglogo.png" = 'html/images/sglogo.png',
|
||||
|
||||
3
code/modules/asset_cache/assets/common.dm
Normal file
3
code/modules/asset_cache/assets/common.dm
Normal file
@@ -0,0 +1,3 @@
|
||||
/datum/asset/simple/namespaced/common
|
||||
assets = list("padlock.png" = 'icons/ui/common/padlock.png')
|
||||
parents = list("common.css" = 'html/browser/common.css')
|
||||
11
code/modules/asset_cache/assets/permissions.dm
Normal file
11
code/modules/asset_cache/assets/permissions.dm
Normal file
@@ -0,0 +1,11 @@
|
||||
/datum/asset/simple/permissions
|
||||
assets = list(
|
||||
"search.js" = 'html/admin/search.js',
|
||||
"panels.css" = 'html/admin/panels.css'
|
||||
)
|
||||
|
||||
/datum/asset/group/permissions
|
||||
children = list(
|
||||
/datum/asset/simple/permissions,
|
||||
/datum/asset/simple/namespaced/common
|
||||
)
|
||||
@@ -40,7 +40,6 @@
|
||||
show_verb_panel = FALSE
|
||||
///Contains admin info. Null if client is not an admin.
|
||||
var/datum/admins/holder = null
|
||||
var/datum/admins/deadmin_holder = null
|
||||
var/buildmode = 0
|
||||
|
||||
///Contains the last message sent by this client - used to protect against copy-paste spamming.
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
GLOB.tickets.ClientLogin(src) // CHOMPedit - Tickets System
|
||||
|
||||
//Admin Authorisation
|
||||
holder = admin_datums[ckey]
|
||||
holder = GLOB.admin_datums[ckey]
|
||||
if(holder)
|
||||
GLOB.admins += src
|
||||
holder.owner = src
|
||||
@@ -465,7 +465,7 @@
|
||||
|
||||
var/admin_rank = "Player"
|
||||
if(src.holder)
|
||||
admin_rank = src.holder.rank
|
||||
admin_rank = src.holder.rank_names()
|
||||
|
||||
var/sql_ip = sql_sanitize_text(src.address)
|
||||
var/sql_computerid = sql_sanitize_text(src.computer_id)
|
||||
@@ -475,7 +475,7 @@
|
||||
|
||||
//Panic bunker code
|
||||
if (isnum(player_age) && player_age == 0) //first connection
|
||||
if (CONFIG_GET(flag/panic_bunker) && !holder && !deadmin_holder)
|
||||
if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[key])
|
||||
log_adminwarn("Failed Login: [key] - New account attempting to connect during panic bunker")
|
||||
message_admins(span_adminnotice("Failed Login: [key] - New account attempting to connect during panic bunker"))
|
||||
disconnect_with_message("Sorry but the server is currently not accepting connections from never before seen players.")
|
||||
|
||||
@@ -60,7 +60,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
|
||||
continue
|
||||
if(instance.ckeys_allowed && (!client || !(client.ckey in instance.ckeys_allowed)))
|
||||
continue
|
||||
if(instance.species_allowed && (!species || !(species in instance.species_allowed)) && (!client || !check_rights(R_ADMIN | R_EVENT | R_FUN, 0, client)) && (!custom_base || !(custom_base in instance.species_allowed)))
|
||||
if(instance.species_allowed && (!species || !(species in instance.species_allowed)) && (!client || !check_rights_for(client, R_ADMIN | R_EVENT | R_FUN)) && (!custom_base || !(custom_base in instance.species_allowed)))
|
||||
continue
|
||||
.[instance.name] = instance
|
||||
|
||||
@@ -539,7 +539,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
|
||||
else
|
||||
return TOPIC_NOACTION
|
||||
|
||||
if(((!(setting_species.spawn_flags & SPECIES_CAN_JOIN)) || (!is_alien_whitelisted(preference_mob(),setting_species))) && !check_rights(R_ADMIN|R_EVENT, 0) && !(setting_species.spawn_flags & SPECIES_WHITELIST_SELECTABLE))
|
||||
if(((!(setting_species.spawn_flags & SPECIES_CAN_JOIN)) || (!is_alien_whitelisted(user.client,setting_species))) && !check_rights(R_ADMIN|R_EVENT, 0) && !(setting_species.spawn_flags & SPECIES_WHITELIST_SELECTABLE))
|
||||
return TOPIC_NOACTION
|
||||
|
||||
var/prev_species = pref.species
|
||||
@@ -1237,7 +1237,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
|
||||
|
||||
if(!(current_species.spawn_flags & SPECIES_CAN_JOIN))
|
||||
restricted = 2
|
||||
else if(!is_alien_whitelisted(preference_mob(),current_species))
|
||||
else if(!is_alien_whitelisted(user.client,current_species))
|
||||
restricted = 1
|
||||
|
||||
if(restricted)
|
||||
|
||||
@@ -83,7 +83,7 @@ var/list/gear_datums = list()
|
||||
if(G.whitelisted && CONFIG_GET(flag/loadout_whitelist) != LOADOUT_WHITELIST_OFF && pref.client) //VOREStation Edit.
|
||||
if(CONFIG_GET(flag/loadout_whitelist) == LOADOUT_WHITELIST_STRICT && G.whitelisted != pref.species)
|
||||
continue
|
||||
if(CONFIG_GET(flag/loadout_whitelist) == LOADOUT_WHITELIST_LAX && !is_alien_whitelisted(preference_mob(), GLOB.all_species[G.whitelisted]))
|
||||
if(CONFIG_GET(flag/loadout_whitelist) == LOADOUT_WHITELIST_LAX && !is_alien_whitelisted(preference_mob.client, GLOB.all_species[G.whitelisted]))
|
||||
continue
|
||||
|
||||
if(max_cost && G.cost > max_cost)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
if(!.)
|
||||
return
|
||||
|
||||
return check_rights(R_MOD|R_ADMIN, FALSE, preferences.client)
|
||||
return check_rights_for(preferences.client, R_MOD|R_ADMIN)
|
||||
|
||||
/datum/preference/toggle/show_debug_logs
|
||||
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
|
||||
@@ -22,7 +22,7 @@
|
||||
if(!.)
|
||||
return
|
||||
|
||||
return check_rights(R_DEBUG|R_ADMIN, FALSE, preferences.client)
|
||||
return check_rights_for(preferences.client, R_DEBUG|R_ADMIN)
|
||||
|
||||
/datum/preference/toggle/show_chat_prayers
|
||||
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
|
||||
@@ -35,7 +35,7 @@
|
||||
if(!.)
|
||||
return
|
||||
|
||||
return check_rights(R_EVENT|R_ADMIN, FALSE, preferences.client)
|
||||
return check_rights_for(preferences.client, R_EVENT|R_ADMIN)
|
||||
|
||||
// General holder prefs
|
||||
/datum/preference/toggle/holder
|
||||
@@ -85,4 +85,4 @@
|
||||
if(!..(preferences))
|
||||
return FALSE
|
||||
|
||||
return CONFIG_GET(flag/allow_admin_ooccolor) && check_rights(R_ADMIN|R_EVENT|R_FUN, 0, preferences.client)
|
||||
return CONFIG_GET(flag/allow_admin_ooccolor) && check_rights_for(preferences.client, R_ADMIN|R_EVENT|R_FUN)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
var/list/Lines = list()
|
||||
|
||||
if(check_rights(R_ADMIN|R_SERVER|R_MOD,FALSE,src))
|
||||
if(check_rights_for(src, R_ADMIN|R_SERVER|R_MOD))
|
||||
for(var/client/C in GLOB.clients)
|
||||
var/entry = "<tr><td>[C.key]"
|
||||
if(C.holder && C.holder.fakekey)
|
||||
|
||||
@@ -51,13 +51,13 @@
|
||||
if(holder && !holder.fakekey)
|
||||
ooc_style = "elevated"
|
||||
|
||||
if(holder.rights & R_EVENT) //Retired Admins
|
||||
if(check_rights(R_EVENT)) //Retired Admins
|
||||
ooc_style = "event_manager"
|
||||
if(holder.rights & R_ADMIN && !(holder.rights & R_BAN)) //Game Masters
|
||||
if(check_rights(R_ADMIN) && !(check_rights(R_BAN))) //Game Masters
|
||||
ooc_style = "moderator"
|
||||
if(holder.rights & R_DEBUG && !(holder.rights & R_BAN)) //Developers
|
||||
if(check_rights(R_SERVER) && !(check_rights(R_BAN))) //Developers
|
||||
ooc_style = "developer"
|
||||
if(holder.rights & R_ADMIN && holder.rights & R_BAN) //Admins
|
||||
if(check_rights(R_ADMIN) && check_rights(R_BAN)) //Admins
|
||||
ooc_style = "admin"
|
||||
|
||||
msg = GLOB.is_valid_url.Replace(msg,span_linkify("$1"))
|
||||
@@ -74,7 +74,7 @@
|
||||
else
|
||||
display_name = holder.fakekey
|
||||
var/pref_color = prefs.read_preference(/datum/preference/color/ooc_color)
|
||||
if(holder && !holder.fakekey && (holder.rights & R_ADMIN|R_FUN|R_EVENT) && CONFIG_GET(flag/allow_admin_ooccolor) && pref_color != "#010000") // keeping this for the badmins
|
||||
if(holder && !holder.fakekey && (check_rights(R_ADMIN|R_FUN|R_EVENT)) && CONFIG_GET(flag/allow_admin_ooccolor) && pref_color != "#010000") // keeping this for the badmins
|
||||
to_chat(target, span_ooc("<font color='[pref_color]'>" + create_text_tag("ooc", "OOC:", target) + " <EM>[display_name]:</EM> [span_message(msg)]</font>"))
|
||||
else
|
||||
to_chat(target, span_ooc("<span class='[ooc_style]'>" + create_text_tag("ooc", "OOC:", target) + " <EM>[display_name]:</EM> " + span_message(msg)) + "</span>")
|
||||
@@ -163,7 +163,7 @@
|
||||
// Admins with RLOOC displayed who weren't already in
|
||||
for(var/client/admin in GLOB.admins)
|
||||
if(!(admin in receivers) && admin.prefs?.read_preference(/datum/preference/toggle/holder/show_rlooc))
|
||||
if(check_rights(R_ADMIN|R_SERVER, FALSE, admin)) //Stop rLOOC showing for retired staff //CHOMPEdit, admins should see LOOC
|
||||
if(check_rights_for(admin, R_ADMIN|R_SERVER)) //Stop rLOOC showing for retired staff //CHOMPEdit, admins should see LOOC
|
||||
r_receivers |= admin
|
||||
|
||||
msg = GLOB.is_valid_url.Replace(msg,span_linkify("$1"))
|
||||
|
||||
@@ -73,19 +73,19 @@
|
||||
if(C.holder.fakekey && !check_rights_for(src, R_ADMIN|R_MOD)) // Only admins and mods can see stealthmins
|
||||
continue
|
||||
// VOREStation Edit End
|
||||
if(check_rights(R_BAN, FALSE, C)) // admins //VOREStation Edit
|
||||
if(check_rights_for(C, R_BAN)) // admins //VOREStation Edit
|
||||
num_admins_online++
|
||||
else if(check_rights(R_ADMIN, FALSE, C) && !check_rights(R_SERVER, FALSE, C)) // mods //VOREStation Edit: Game masters
|
||||
else if(check_rights_for(C, R_ADMIN) && !check_rights_for(C, R_SERVER)) // mods //VOREStation Edit: Game masters
|
||||
category = R_MOD
|
||||
num_mods_online++
|
||||
else if(check_rights(R_SERVER, FALSE, C)) // developers
|
||||
else if(check_rights_for(C, R_SERVER)) // developers
|
||||
category = R_SERVER
|
||||
num_devs_online++
|
||||
else if(check_rights(R_STEALTH, FALSE, C)) // event managers //VOREStation Edit: Retired Staff
|
||||
else if(check_rights_for(C, R_STEALTH)) // event managers //VOREStation Edit: Retired Staff
|
||||
category = R_EVENT
|
||||
num_event_managers_online++
|
||||
|
||||
temp += "\t[C] is a [C.holder.rank]"
|
||||
temp += "\t[C] is a [C.holder.rank_names()]"
|
||||
if(holder)
|
||||
if(C.holder.fakekey)
|
||||
temp += " " + span_italics("(as [C.holder.fakekey])")
|
||||
|
||||
@@ -55,7 +55,7 @@ var/list/mentor_verbs_default = list(
|
||||
if(!target)
|
||||
return
|
||||
var/client/C = targets[target]
|
||||
if(has_mentor_powers(C) || C.deadmin_holder) // If an admin is deadminned you could mentor them and that will cause fuckery if they readmin
|
||||
if(has_mentor_powers(C) || GLOB.deadmins[C.ckey]) // If an admin is deadminned you could mentor them and that will cause fuckery if they readmin
|
||||
to_chat(src, span_admin_pm_warning("Error: They already have mentor powers."))
|
||||
return
|
||||
var/datum/mentor/M = new /datum/mentor(C.ckey)
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
visualnet = ghostnet
|
||||
|
||||
/mob/observer/dead/proc/checkStatic()
|
||||
return !(check_rights(R_ADMIN|R_FUN|R_EVENT|R_SERVER, 0, src) || (client && client.buildmode) || isbelly(loc))
|
||||
return !(check_rights_for(src.client, R_ADMIN|R_FUN|R_EVENT|R_SERVER) || (client && client.buildmode) || isbelly(loc))
|
||||
|
||||
/mob/observer/dead/Moved(atom/old_loc, direction, forced)
|
||||
. = ..()
|
||||
@@ -260,7 +260,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
announce_ghost_joinleave(ghostize(1))
|
||||
else
|
||||
var/response
|
||||
if(check_rights(R_ADMIN|R_SERVER|R_MOD,FALSE,src)) //No need to sanity check for client and holder here as that is part of check_rights
|
||||
if(check_rights_for(src.client, R_ADMIN|R_SERVER|R_MOD)) //No need to sanity check for client and holder here as that is part of check_rights
|
||||
response = tgui_alert(src, "You have the ability to Admin-Ghost. The regular Ghost verb will announce your presence to dead chat. Both variants will allow you to return to your body using 'aghost'.\n\nWhat do you wish to do?", "Are you sure you want to ghost?", list("Admin Ghost", "Ghost", "Stay in body"))
|
||||
if(response == "Admin Ghost")
|
||||
if(!src.client)
|
||||
@@ -613,7 +613,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
return 0
|
||||
|
||||
/mob/observer/dead/check_holy(var/turf/T)
|
||||
if(check_rights(R_ADMIN|R_FUN|R_EVENT, 0, src))
|
||||
if(check_rights_for(src.client, R_ADMIN|R_FUN|R_EVENT))
|
||||
return 0
|
||||
|
||||
return (T && T.holy) && (is_manifest || (mind in cult.current_antagonists))
|
||||
@@ -923,7 +923,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
return 1
|
||||
|
||||
/mob/observer/dead/proc/can_admin_interact()
|
||||
return check_rights(R_ADMIN|R_EVENT, 0, src)
|
||||
return check_rights_for(src.client, R_ADMIN|R_EVENT|R_DEBUG)
|
||||
|
||||
/mob/observer/dead/verb/toggle_ghostsee()
|
||||
set name = "Toggle Ghost Vision"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/mob/living/carbon/alien/diona/confirm_evolution()
|
||||
|
||||
if(!is_alien_whitelisted(src, GLOB.all_species[SPECIES_DIONA]))
|
||||
if(!is_alien_whitelisted(src.client, GLOB.all_species[SPECIES_DIONA]))
|
||||
tgui_alert(src, "You are currently not whitelisted to play as a full diona.")
|
||||
return null
|
||||
|
||||
|
||||
@@ -180,14 +180,14 @@
|
||||
for(var/current_species_name in GLOB.all_species)
|
||||
var/datum/species/current_species = GLOB.all_species[current_species_name]
|
||||
|
||||
if(check_whitelist && CONFIG_GET(flag/usealienwhitelist) && !check_rights(R_ADMIN|R_EVENT, 0, src)) //If we're using the whitelist, make sure to check it!
|
||||
if(check_whitelist && CONFIG_GET(flag/usealienwhitelist) && !check_rights_for(src.client, R_ADMIN|R_EVENT)) //If we're using the whitelist, make sure to check it!
|
||||
if(!(current_species.spawn_flags & SPECIES_CAN_JOIN))
|
||||
continue
|
||||
if(whitelist.len && !(current_species_name in whitelist))
|
||||
continue
|
||||
if(blacklist.len && (current_species_name in blacklist))
|
||||
continue
|
||||
if((current_species.spawn_flags & SPECIES_IS_WHITELISTED) && !is_alien_whitelisted(src, current_species))
|
||||
if((current_species.spawn_flags & SPECIES_IS_WHITELISTED) && !is_alien_whitelisted(src.client, current_species))
|
||||
continue
|
||||
|
||||
valid_species += current_species_name
|
||||
|
||||
@@ -87,3 +87,4 @@
|
||||
client.images += cloaked_selfimage
|
||||
client.init_verbs()
|
||||
SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client)
|
||||
SEND_SIGNAL(client, COMSIG_CLIENT_MOB_LOGIN, src)
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
update_client_z(null)
|
||||
log_access_out(src)
|
||||
unset_machine()
|
||||
if(admin_datums[src.ckey])
|
||||
if(GLOB.admin_datums[src.ckey])
|
||||
message_admins("Staff logout: [key_name(src)]") // CHOMPEdit: Admin logout notice displays no matter what//Edit2: STAFF
|
||||
if(ticker && ticker.current_state == GAME_STATE_PLAYING) //Only report this stuff if we are currently playing.
|
||||
if (ticker && ticker.current_state == GAME_STATE_PLAYING) //Only report this stuff if we are currently playing.
|
||||
var/admins_number = GLOB.admins.len
|
||||
|
||||
if(admins_number == 0) //Apparently the admin logging out is no longer an admin at this point, so we have to check this towards 0 and not towards 1. Awell.
|
||||
|
||||
@@ -467,7 +467,7 @@
|
||||
set category = "OOC.Game"
|
||||
var/is_admin = 0
|
||||
|
||||
if(client.holder && (client.holder.rights & R_ADMIN|R_EVENT))
|
||||
if(check_rights_for(client, R_ADMIN|R_EVENT))
|
||||
is_admin = 1
|
||||
else if(stat != DEAD || isnewplayer(src))
|
||||
to_chat(src, span_filter_notice("[span_blue("You must be observing to use this!")]"))
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
|
||||
/proc/is_admin(var/mob/user)
|
||||
return check_rights(R_ADMIN|R_EVENT, 0, user) != 0
|
||||
return check_rights_for(user.client, R_ADMIN|R_EVENT) != 0
|
||||
|
||||
/**
|
||||
* Moved into its own file as part of port from CHOMP.
|
||||
@@ -406,7 +406,7 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT)
|
||||
return // Can't talk in deadchat if you can't see it.
|
||||
|
||||
for(var/mob/M in player_list)
|
||||
if(M.client && ((!isnewplayer(M) && M.stat == DEAD) || (M.client.holder && M.client.holder.rights && M.client?.prefs?.read_preference(/datum/preference/toggle/holder/show_staff_dsay))) && M.client?.prefs?.read_preference(/datum/preference/toggle/show_dsay))
|
||||
if(M.client && ((!isnewplayer(M) && M.stat == DEAD) || (M.client.holder && check_rights_for(M.client, R_NONE) && M.client?.prefs?.read_preference(/datum/preference/toggle/holder/show_staff_dsay))) && M.client?.prefs?.read_preference(/datum/preference/toggle/show_dsay))
|
||||
var/follow
|
||||
var/lname
|
||||
if(M.forbid_seeing_deadchat && !M.client.holder)
|
||||
@@ -436,7 +436,7 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT)
|
||||
|
||||
/proc/say_dead_object(var/message, var/obj/subject = null)
|
||||
for(var/mob/M in player_list)
|
||||
if(M.client && ((!isnewplayer(M) && M.stat == DEAD) || (M.client.holder && M.client.holder.rights && M.client?.prefs?.read_preference(/datum/preference/toggle/holder/show_staff_dsay))) && M.client?.prefs?.read_preference(/datum/preference/toggle/show_dsay))
|
||||
if(M.client && ((!isnewplayer(M) && M.stat == DEAD) || (M.client.holder && check_rights_for(M.client, R_NONE) && M.client?.prefs?.read_preference(/datum/preference/toggle/holder/show_staff_dsay))) && M.client?.prefs?.read_preference(/datum/preference/toggle/show_dsay))
|
||||
var/follow
|
||||
var/lname = "Game Master"
|
||||
if(M.forbid_seeing_deadchat && !M.client.holder)
|
||||
|
||||
@@ -621,7 +621,7 @@
|
||||
|
||||
if(chosen_species && use_species_name)
|
||||
// Have to recheck admin due to no usr at roundstart. Latejoins are fine though.
|
||||
if(is_alien_whitelisted(chosen_species))
|
||||
if(is_alien_whitelisted(src.client, chosen_species))
|
||||
new_character = new(T, use_species_name)
|
||||
|
||||
if(!new_character)
|
||||
@@ -697,9 +697,6 @@
|
||||
src << browse(null, "window=News") //closes news window
|
||||
panel.close()
|
||||
|
||||
/mob/new_player/proc/has_admin_rights()
|
||||
return check_rights(R_ADMIN, 0, src)
|
||||
|
||||
/mob/new_player/get_species()
|
||||
var/datum/species/chosen_species
|
||||
if(client.prefs.species)
|
||||
@@ -708,7 +705,7 @@
|
||||
if(!chosen_species)
|
||||
return SPECIES_HUMAN
|
||||
|
||||
if(is_alien_whitelisted(chosen_species))
|
||||
if(is_alien_whitelisted(src.client, chosen_species))
|
||||
return chosen_species.name
|
||||
|
||||
return SPECIES_HUMAN
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
to_chat(src,span_warning("You have not set your scale yet. Do this on the VORE tab in character setup."))
|
||||
|
||||
//Can they play?
|
||||
if(!is_alien_whitelisted(src,GLOB.all_species[client?.prefs?.species]) && !check_rights(R_ADMIN, 0))
|
||||
if(!is_alien_whitelisted(src.client,GLOB.all_species[client?.prefs?.species]) && !check_rights(R_ADMIN, 0))
|
||||
pass = FALSE
|
||||
to_chat(src,span_warning("You are not allowed to spawn in as this species."))
|
||||
|
||||
|
||||
@@ -398,7 +398,7 @@
|
||||
|
||||
var/adminrank = "Player"
|
||||
if(usr && usr.client && usr.client.holder)
|
||||
adminrank = usr.client.holder.rank
|
||||
adminrank = usr.client.holder.rank_names()
|
||||
|
||||
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]')")
|
||||
@@ -448,7 +448,7 @@
|
||||
|
||||
var/adminrank = "Player"
|
||||
if(usr && usr.client && usr.client.holder)
|
||||
adminrank = usr.client.holder.rank
|
||||
adminrank = usr.client.holder.rank_names()
|
||||
|
||||
|
||||
replytext = replacetext(replytext, "%BR%", "")
|
||||
@@ -520,7 +520,7 @@
|
||||
|
||||
var/adminrank = "Player"
|
||||
if(usr && usr.client && usr.client.holder)
|
||||
adminrank = usr.client.holder.rank
|
||||
adminrank = usr.client.holder.rank_names()
|
||||
|
||||
|
||||
var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank, rating) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]', [(isnull(rating)) ? "null" : rating])")
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
/obj/item/modular_computer/attack_ghost(var/mob/observer/dead/user)
|
||||
if(enabled)
|
||||
tgui_interact(user)
|
||||
else if(check_rights(R_ADMIN|R_EVENT, 0, user))
|
||||
else if(check_rights_for(user.client, R_ADMIN|R_EVENT|R_DEBUG))
|
||||
var/response = tgui_alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", list("Yes", "No"))
|
||||
if(response == "Yes")
|
||||
turn_on(user)
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
return 1
|
||||
|
||||
// Admin override - allows operation of any computer as aghosted admin, as if you had any required access.
|
||||
if(isobserver(user) && check_rights(R_ADMIN|R_EVENT, 0, user))
|
||||
if(isobserver(user) && check_rights_for(user.client, R_ADMIN|R_EVENT|R_DEBUG))
|
||||
return 1
|
||||
|
||||
if(!istype(user))
|
||||
|
||||
@@ -425,7 +425,7 @@ Extracted to its own procedure for easier logic handling with paper bundles.
|
||||
msg = span_notice(msg)
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(check_rights((R_ADMIN|R_MOD|R_EVENT),0,C))
|
||||
if(check_rights_for(C, (R_ADMIN|R_MOD|R_EVENT)))
|
||||
to_chat(C,msg)
|
||||
C << 'sound/machines/printer.ogg'
|
||||
sender.client << 'sound/machines/printer.ogg' //CHOMPEdit - The pain must be felt
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
var/client/ghost_client = ghost.client
|
||||
|
||||
if(!is_alien_whitelisted(ghost, GLOB.all_species[ghost_client?.prefs?.species]) && !check_rights(R_ADMIN, 0)) // Prevents a ghost ghosting in on a slot and spawning via a resleever with race they're not whitelisted for, getting around normal join restrictions.
|
||||
if(!is_alien_whitelisted(ghost.client, GLOB.all_species[ghost_client?.prefs?.species]) && !check_rights(R_ADMIN, 0)) // Prevents a ghost ghosting in on a slot and spawning via a resleever with race they're not whitelisted for, getting around normal join restrictions.
|
||||
to_chat(ghost, span_warning("You are not whitelisted to spawn as this species!"))
|
||||
return
|
||||
|
||||
|
||||
@@ -63,13 +63,13 @@
|
||||
else
|
||||
keymsg += " (Ingame)"
|
||||
|
||||
if(R_ADMIN & C.holder.rights && R_BAN & C.holder.rights) // R_ADMIN and R_BAN apparently an admin makes
|
||||
if(check_rights_for(C, R_ADMIN) && check_rights_for(C, R_BAN)) // R_ADMIN and R_BAN apparently an admin makes
|
||||
admin_keys += keymsg
|
||||
|
||||
else if(R_ADMIN & C.holder.rights && !(R_SERVER & C.holder.rights)) // R_ADMIN but not R_SERVER makes a moderator
|
||||
else if(check_rights_for(C, R_ADMIN) && !(check_rights_for(C, R_SERVER))) // R_ADMIN but not R_SERVER makes a moderator
|
||||
mod_keys += keymsg
|
||||
|
||||
else if(R_SERVER & C.holder.rights) // R_SERVER makes a dev
|
||||
else if(check_rights_for(C, R_SERVER)) // R_SERVER makes a dev
|
||||
dev_keys += keymsg
|
||||
|
||||
else // No R_ADMIN&&R_BAN, R_ADMIN!R_BAN, R_SERVER, must be a GM or something
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
current_filter = filter
|
||||
|
||||
/datum/tgui_module/player_notes/proc/open_legacy()
|
||||
var/datum/admins/A = admin_datums[usr.ckey]
|
||||
var/datum/admins/A = GLOB.admin_datums[usr.ckey]
|
||||
A.PlayerNotesLegacy()
|
||||
|
||||
/datum/tgui_module/player_notes/tgui_state(mob/user)
|
||||
@@ -113,7 +113,7 @@
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/datum/admins/A = admin_datums[usr.ckey]
|
||||
var/datum/admins/A = GLOB.admin_datums[usr.ckey]
|
||||
A.show_player_info_legacy(key)
|
||||
|
||||
/datum/tgui_module/player_notes_info/tgui_act(action, params, datum/tgui/ui)
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
return
|
||||
|
||||
var/datum/species/S = GLOB.all_species[new_user.client.prefs.species]
|
||||
if(!is_alien_whitelisted(new_user, S))
|
||||
if(!is_alien_whitelisted(new_user.client, S))
|
||||
tgui_alert(new_user, "You are currently not whitelisted to play [new_user.client.prefs.species].")
|
||||
return 0
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
if(isobserver(user))
|
||||
// Admins can always interact.
|
||||
if(check_rights(R_ADMIN|R_EVENT, 0, src))
|
||||
if(check_rights_for(user.client, R_ADMIN|R_EVENT|R_DEBUG))
|
||||
. = max(., STATUS_INTERACTIVE)
|
||||
|
||||
// Regular ghosts can always at least view if in range.
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
GLOBAL_DATUM_INIT(tgui_admin_state, /datum/tgui_state/admin_state, new)
|
||||
|
||||
/datum/tgui_state/admin_state/can_use_topic(src_object, mob/user)
|
||||
if(check_rights_for(user.client, R_ADMIN|R_EVENT))
|
||||
if(check_rights_for(user.client, R_ADMIN|R_EVENT|R_DEBUG))
|
||||
return STATUS_INTERACTIVE
|
||||
return STATUS_CLOSE
|
||||
|
||||
@@ -79,6 +79,6 @@ GLOBAL_DATUM_INIT(tgui_default_state, /datum/tgui_state/default, new)
|
||||
return ..()
|
||||
|
||||
/mob/observer/dead/default_can_use_tgui_topic()
|
||||
if(check_rights(R_ADMIN|R_EVENT, 0, src))
|
||||
if(check_rights_for(src.client, R_ADMIN|R_EVENT|R_DEBUG))
|
||||
return STATUS_INTERACTIVE // Admins are more equal
|
||||
return STATUS_UPDATE // Ghosts can view updates
|
||||
|
||||
@@ -14,6 +14,6 @@ GLOBAL_DATUM_INIT(tgui_observer_state, /datum/tgui_state/observer_state, new)
|
||||
/datum/tgui_state/observer_state/can_use_topic(src_object, mob/user)
|
||||
if(isobserver(user))
|
||||
return STATUS_INTERACTIVE
|
||||
if(check_rights(R_ADMIN|R_EVENT, 0, src))
|
||||
if(check_rights_for(user.client, R_ADMIN|R_EVENT))
|
||||
return STATUS_INTERACTIVE
|
||||
return STATUS_CLOSE
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
data["question"] = question
|
||||
data["choices"] = choices
|
||||
|
||||
if(show_counts || check_rights(R_ADMIN, FALSE, user))
|
||||
if(show_counts || check_rights_for(user.client, R_ADMIN))
|
||||
data["show_counts"] = TRUE
|
||||
|
||||
var/list/counts = list()
|
||||
|
||||
@@ -97,4 +97,4 @@
|
||||
|
||||
|
||||
/proc/whitelist_overrides(mob/M)
|
||||
return !CONFIG_GET(flag/usealienwhitelist) || check_rights(R_ADMIN|R_EVENT, 0, M) // CHOMPEdit
|
||||
return !CONFIG_GET(flag/usealienwhitelist) || check_rights_for(M.client, R_ADMIN|R_EVENT) // CHOMPEdit
|
||||
|
||||
@@ -1,46 +1,89 @@
|
||||
########################################################################################
|
||||
# ADMIN RANK DEFINES #
|
||||
# The format of this is very simple. Rank name goes first. #
|
||||
# Rank is CASE-SENSITIVE, all punctuation will be stripped so spaces don't matter. #
|
||||
# Each rank is then followed by keywords with the prefix "+". #
|
||||
# These keywords represent groups of verbs and abilities which are given to that rank. #
|
||||
# +@ (or +prev) is a special shorthand which adds all the rights of the rank above it. #
|
||||
# Ranks with no keywords will just be given the most basic verbs and abilities ~Carn #
|
||||
########################################################################################
|
||||
# PLEASE NOTE: depending on config options, some abilities will be unavailable regardless if you have permission to use them!
|
||||
# ALSO NOTE: this is a WorkInProgress at the moment. Most of this is just arbitrarily thrown in whatever group because LoadsaWork2Do+LittleTime.
|
||||
# I'll be doing more moving around as feedback comes in. So be sure to check the notes after updates.
|
||||
#Admin Rank format is as follows:
|
||||
#
|
||||
#Name = Game Admin
|
||||
#Include = @ ADMIN BAN SOUND
|
||||
#Exclude = FUN
|
||||
#Edit =
|
||||
#
|
||||
#Name will match anything after '=' and must be identical to an admin's rank in admins.txt to be linked but otherwise has no formatting restrictions.
|
||||
#A rank's permissions are defined with keywords that control access to groups of verbs and abilities, they are case-sensitive and separated by a space with no prefix.
|
||||
#To define no permissions for a type, leave it empty.
|
||||
#There are three types of permissions:
|
||||
#Include will give a keyword to a rank.
|
||||
#Exclude removes a keyword and takes precedence over Include.
|
||||
#Edit will allow an admin to edit these permissions on other ranks or change an admin's rank to another if they can edit all the permissions it has.
|
||||
#Edit is only used when SQL-based admin loading is enabled.
|
||||
#If SQL-based admin loading is enabled, ranks and their keywords listed here will be loaded first and override any with the same name loaded from the database.
|
||||
#
|
||||
#The following are valid permission keywords:
|
||||
#ADMIN = general admin tools, verbs etc.
|
||||
#FUN = events, other event-orientated actions. Access to the fun secrets in the secrets panel.
|
||||
#BAN = the ability to ban and unban.
|
||||
#STEALTH = the ability to stealthmin (make yourself appear with a fake name to everyone but other admins).
|
||||
#POSSESS = the ability to possess objects.
|
||||
#REJUVINATE = the ability to heal, respawn, modify damage and use godmode
|
||||
#BUILDMODE = the ability to use buildmode.
|
||||
#SERVER = the ability to restart the server, change the game mode or force a round to start/end.
|
||||
#DEBUG = debug tools used for diagnosing and fixing problems. It's useful to give this to coders so they can investigate problems on a live server.
|
||||
#VAREDIT = everyone may view viewvars/debugvars/whatever you call it. This keyword allows you to actually EDIT those variables.
|
||||
#PERMISSIONS = allows you to promote and/or demote people.
|
||||
#SOUNDS = allows you to upload and play SOUND.
|
||||
#SPAWN = mob transformations, spawning of most atoms including mobs (high-risk atoms, e.g. blackholes, will require the +FUN flag too).
|
||||
#EVENT = a group of verbs that make it possible to run an event, or other badminnery.
|
||||
#EVERYTHING = Simply gives you everything without having to type every flag.
|
||||
#@ = special keyword for the current permission type that adds all the keywords that the preceding rank has of the same type.
|
||||
|
||||
# KEYWORDS:
|
||||
# +ADMIN = general admin tools, verbs etc
|
||||
# +FUN = events, other event-orientated actions. Access to the fun secrets in the secrets panel.
|
||||
# +BAN = the ability to ban, jobban and fullban
|
||||
# +STEALTH = the ability to stealthmin (make yourself appear with a fake name to everyone but other admins
|
||||
# +POSSESS = the ability to possess objects
|
||||
# +REJUV (or +REJUVINATE) = the ability to heal, respawn, modify damage and use godmode
|
||||
# +BUILD (or +BUILDMODE) = the ability to use buildmode
|
||||
# +SERVER = higher-risk admin verbs and abilities, such as those which affect the server configuration.
|
||||
# +DEBUG = debug tools used for diagnosing and fixing problems. It's useful to give this to coders so they can investigate problems on a live server.
|
||||
# +VAREDIT = everyone may view viewvars/debugvars/whatever you call it. This keyword allows you to actually EDIT those variables.
|
||||
# +RIGHTS (or +PERMISSIONS) = allows you to promote and/or demote people.
|
||||
# +SOUND (or +SOUNDS) = allows you to upload and play sounds
|
||||
# +SPAWN (or +CREATE) = mob transformations, spawning of most atoms including mobs (high-risk atoms, e.g. blackholes, will require the +FUN flag too)
|
||||
# +EVENT = a group of verbs that make it possible to run an event, or other badminnery.
|
||||
# +EVERYTHING (or +HOST or +ALL) = Simply gives you everything without having to type every flag
|
||||
Name = Admin Observer
|
||||
Include =
|
||||
Exclude =
|
||||
Edit =
|
||||
|
||||
Admin Observer
|
||||
Moderator +MOD
|
||||
Mentor +MENTOR
|
||||
Name = Moderator
|
||||
Include = MOD
|
||||
Exclude =
|
||||
Edit =
|
||||
|
||||
Admin Candidate +ADMIN
|
||||
Trial Admin +@ +STEALTH +SPAWN +REJUV +VAREDIT +BAN +FUN
|
||||
Admin +@ +POSSESS +BUILDMODE +SERVER
|
||||
Admin Supervisor +@ +SOUNDS +DEBUG +PERMISSIONS
|
||||
Game Master +ADMIN +FUN +POSSESS +REJUV +BUILD +SERVER +DEBUG +VAREDIT +SOUND +SPAWN
|
||||
Head Admin +EVERYTHING
|
||||
Retired Admin +ADMIN +STEALTH
|
||||
Name = Admin Candidate
|
||||
Include = ADMIN
|
||||
Exclude =
|
||||
Edit =
|
||||
|
||||
Host +EVERYTHING
|
||||
Name = Trial Admin
|
||||
Include = @ SPAWN REJUVINATE VAREDIT BAN
|
||||
Exclude =
|
||||
Edit =
|
||||
|
||||
Developer +DEBUG +VAREDIT +SERVER +SPAWN +REJUV +POSSESS +BUILDMODE
|
||||
Dev Mod +@ +MOD
|
||||
Name = Badmin
|
||||
Include = @ POSSESS BUILDMODE SERVER FUN
|
||||
Exclude =
|
||||
Edit =
|
||||
|
||||
Name = Game Admin
|
||||
Include = @ STEALTH SOUNDS DEBUG PERMISSIONS
|
||||
Exclude =
|
||||
Edit =
|
||||
|
||||
Name = Game Master
|
||||
Include = EVERYTHING
|
||||
Exclude =
|
||||
Edit = EVERYTHING
|
||||
|
||||
Name = Head Admin
|
||||
Include = EVERYTHING
|
||||
Exclude =
|
||||
Edit = EVERYTHING
|
||||
|
||||
Name = Retired Admin
|
||||
Include = ADMIN STEALTH
|
||||
Exclude =
|
||||
Edit =
|
||||
|
||||
Name = Host
|
||||
Include = EVERYTHING
|
||||
Exclude =
|
||||
Edit = EVERYTHING
|
||||
|
||||
Name = Developer
|
||||
Include = DEBUG VAREDIT SERVER SPAWN REJUVINATE POSSESS BUILDMODE
|
||||
Exclude =
|
||||
Edit =
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
######################################################################
|
||||
# Basically, ckey goes first. Rank goes after the "-" #
|
||||
# Case is not important for ckey. #
|
||||
# Case IS important for the rank. However punctuation/spaces are not #
|
||||
# Ranks can be anything defined in admin_ranks.txt ~Carn #
|
||||
######################################################################
|
||||
###############################################################################################
|
||||
# Basically, ckey goes first. Rank goes after the "=" #
|
||||
# Case is not important for ckey. #
|
||||
# Case IS important for the rank. #
|
||||
# All punctuation (spaces etc) EXCEPT '-', '_' and '@' will be stripped from rank names. #
|
||||
# Ranks can be anything defined in admin_ranks.txt #
|
||||
# NOTE: if the rank-name cannot be found in admin_ranks.txt, they will not be adminned! ~Carn #
|
||||
# NOTE: syntax was changed to allow hyphenation of ranknames, since spaces are stripped. #
|
||||
###############################################################################################
|
||||
|
||||
# not_a_user - Admin
|
||||
# not_a_user = Admin
|
||||
|
||||
@@ -17,9 +17,21 @@ $include sqlite.txt
|
||||
## Server name: This appears at the top of the screen in-game. In this case it will read "tgstation: station_name" where station_name is the randomly generated name of the station for the round. Remove the # infront of SERVERNAME and replace 'tgstation' with the name of your choice
|
||||
# SERVERNAME spacestation13
|
||||
|
||||
## Add a # infront of this if you want to use the SQL based admin system, the legacy system uses admins.txt. You need to set up your database to use the SQL based system.
|
||||
## Comment this out if you want to use the SQL based admin system, the legacy system uses admins.txt.
|
||||
## You need to set up your database to use the SQL based system.
|
||||
## This flag is automatically enabled if SQL_ENABLED isn't
|
||||
ADMIN_LEGACY_SYSTEM
|
||||
|
||||
##Uncomment this to stop any admins loaded by the legacy system from having their rank edited by the permissions panel
|
||||
#PROTECT_LEGACY_ADMINS
|
||||
|
||||
##Uncomment this to stop any ranks loaded by the legacy system from having their flags edited by the permissions panel
|
||||
#PROTECT_LEGACY_RANKS
|
||||
|
||||
##Uncomment this to have admin ranks only loaded from the legacy admin_ranks.txt
|
||||
##If enabled, each time admins are loaded ranks the database will be updated with the current ranks and their flags
|
||||
#LOAD_LEGACY_RANKS_ONLY
|
||||
|
||||
## Add a # infront of this if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system.
|
||||
BAN_LEGACY_SYSTEM
|
||||
|
||||
@@ -596,3 +608,6 @@ JUKEBOX_TRACK_FILES config/jukebox.json
|
||||
# The endpoint for the chat to fetch the chatlogs from (for example, the last 2500 messages on init for the history)
|
||||
# REQUIRES chatlog_database_backend to be enabled
|
||||
#CHATLOG_DATABASE_API_ENDPOINT https://example.com
|
||||
|
||||
## Uncomment to block granting profiling privileges to users with R_DEBUG, for performance purposes
|
||||
#FORBID_ADMIN_PROFILING
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
body {padding:0px;margin:0px;}
|
||||
#top {position:fixed;top:5px;left:10%;width:80%;text-align:center;background-color:#fff;border:2px solid #ccc;}
|
||||
#main {position:relative;top:50px;left:3%;width:96%;text-align:center;z-index:0;}
|
||||
#main {position:relative;top:10px;left:3%;width:96%;text-align:center;z-index:0;}
|
||||
#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";}
|
||||
tr.norm {background-color:#f4f4f4;}
|
||||
tr.title {background-color:#ccc;}
|
||||
tr.alt {background-color:#e7e7e7;}
|
||||
.small {font-size:80%;}
|
||||
a {text-decoration:none;color:#a0a;}
|
||||
a {text-decoration:none;}
|
||||
a:hover {color:#d3d;}
|
||||
@@ -23,11 +23,11 @@ function updateSearch(){
|
||||
}
|
||||
if(found == 0) row.style.display='none';
|
||||
else{
|
||||
row.style.display='block';
|
||||
row.style.display='table-row'; /* DON'T make tables with block property */
|
||||
row.className = alt_style;
|
||||
if(alt_style == 'alt') alt_style = 'norm';
|
||||
else alt_style = 'alt';
|
||||
}
|
||||
}catch(err) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
icons/ui/common/padlock.png
Normal file
BIN
icons/ui/common/padlock.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 173 B |
@@ -701,7 +701,7 @@ GLOBAL_DATUM_INIT(tickets, /datum/tickets, new)
|
||||
. = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
|
||||
for(var/client/X in GLOB.admins)
|
||||
.["total"] += X
|
||||
if(requiredflags != 0 && !check_rights(rights_required = requiredflags, show_msg = FALSE, C = X))
|
||||
if(requiredflags != 0 && !check_rights(X, requiredflags))
|
||||
.["noflags"] += X
|
||||
else if(X.is_afk())
|
||||
.["afk"] += X
|
||||
|
||||
66
tools/admin_rank_bitflag_calculator.py
Normal file
66
tools/admin_rank_bitflag_calculator.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
bitflags = {
|
||||
"R_BUILDMODE": 1<<0,
|
||||
"R_ADMIN": 1<<1,
|
||||
"R_BAN": 1<<2,
|
||||
"R_FUN": 1<<3,
|
||||
"R_SERVER": 1<<4,
|
||||
"R_DEBUG": 1<<5,
|
||||
"R_POSSESS": 1<<6,
|
||||
"R_PERMISSIONS": 1<<7,
|
||||
"R_STEALTH": 1<<8,
|
||||
"R_REJUVINATE": 1<<9,
|
||||
"R_VAREDIT": 1<<10,
|
||||
"R_SOUNDS": 1<<11,
|
||||
"R_SPAWN": 1<<12,
|
||||
"R_MOD": 1<<13,
|
||||
"R_EVENT": 1<<14,
|
||||
"R_HOST": 1<<15,
|
||||
"-------------": 0,
|
||||
"EVERYTHING": (1<<16)-1
|
||||
}
|
||||
|
||||
class BitflagCalculator:
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
master.title("Bitflag Calculator")
|
||||
master.geometry("300x625")
|
||||
|
||||
self.checkboxes = {}
|
||||
self.vars = {}
|
||||
|
||||
for i, (flag, value) in enumerate(bitflags.items()):
|
||||
var = tk.IntVar()
|
||||
cb = ttk.Checkbutton(master, text=flag, variable=var, command=self.update_result)
|
||||
cb.grid(row=i, column=0, sticky="w", padx=10, pady=2)
|
||||
self.checkboxes[flag] = cb
|
||||
self.vars[flag] = var
|
||||
|
||||
self.result_label = ttk.Label(master, text="Result: 0")
|
||||
self.result_label.grid(row=len(bitflags), column=0, pady=10)
|
||||
|
||||
self.copy_button = ttk.Button(master, text="Copy Result", command=self.copy_result)
|
||||
self.copy_button.grid(row=len(bitflags)+1, column=0, pady=5)
|
||||
|
||||
self.clear_button = ttk.Button(master, text="Clear All", command=self.clear_all)
|
||||
self.clear_button.grid(row=len(bitflags)+2, column=0, pady=5)
|
||||
|
||||
def update_result(self):
|
||||
result = sum(value for flag, value in bitflags.items() if self.vars[flag].get())
|
||||
self.result_label.config(text=f"Result: {result}")
|
||||
|
||||
def copy_result(self):
|
||||
result = sum(value for flag, value in bitflags.items() if self.vars[flag].get())
|
||||
self.master.clipboard_clear()
|
||||
self.master.clipboard_append(str(result))
|
||||
|
||||
def clear_all(self):
|
||||
for var in self.vars.values():
|
||||
var.set(0)
|
||||
self.update_result()
|
||||
|
||||
root = tk.Tk()
|
||||
calculator = BitflagCalculator(root)
|
||||
root.mainloop()
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "code\names.dm"
|
||||
#include "code\world.dm"
|
||||
#include "code\__defines\__globals.dm"
|
||||
#include "code\__defines\_bitfields.dm"
|
||||
#include "code\__defines\_click.dm"
|
||||
#include "code\__defines\_compile_options.dm"
|
||||
#include "code\__defines\_fruits.dm"
|
||||
@@ -35,6 +36,7 @@
|
||||
#include "code\__defines\action.dm"
|
||||
#include "code\__defines\admin.dm"
|
||||
#include "code\__defines\admin_ch.dm"
|
||||
#include "code\__defines\admin_verb.dm"
|
||||
#include "code\__defines\admin_vr.dm"
|
||||
#include "code\__defines\airlock_control.dm"
|
||||
#include "code\__defines\ammunition.dm"
|
||||
@@ -185,6 +187,7 @@
|
||||
#include "code\__defines\dcs\helpers.dm"
|
||||
#include "code\__defines\dcs\signals.dm"
|
||||
#include "code\__defines\dcs\signals_ch.dm"
|
||||
#include "code\__defines\dcs\signals\signals_client.dm"
|
||||
#include "code\__defines\dcs\signals\signals_subsystem.dm"
|
||||
#include "code\__defines\dcs\signals\signals_mobs\signals_mob_main.dm"
|
||||
#include "code\__defines\dcs\signals\signals_turf.dm"
|
||||
@@ -210,6 +213,7 @@
|
||||
#include "code\_helpers\_global_objects.dm"
|
||||
#include "code\_helpers\_global_objects_vr.dm"
|
||||
#include "code\_helpers\_lists.dm"
|
||||
#include "code\_helpers\admin.dm"
|
||||
#include "code\_helpers\announcements.dm"
|
||||
#include "code\_helpers\atmospherics.dm"
|
||||
#include "code\_helpers\atom_movables.dm"
|
||||
@@ -1966,8 +1970,6 @@
|
||||
#include "code\modules\admin\admin_tools.dm"
|
||||
#include "code\modules\admin\admin_verb_lists_vr.dm"
|
||||
#include "code\modules\admin\admin_verbs.dm"
|
||||
#include "code\modules\admin\admin_verbs_vr.dm"
|
||||
#include "code\modules\admin\admin_vr.dm"
|
||||
#include "code\modules\admin\banjob.dm"
|
||||
#include "code\modules\admin\ckey_vr.dm"
|
||||
#include "code\modules\admin\create_mob.dm"
|
||||
@@ -1980,6 +1982,7 @@
|
||||
#include "code\modules\admin\modify_robot.dm"
|
||||
#include "code\modules\admin\NewBan.dm"
|
||||
#include "code\modules\admin\news.dm"
|
||||
#include "code\modules\admin\permissionedit.dm"
|
||||
#include "code\modules\admin\persistence.dm"
|
||||
#include "code\modules\admin\player_effects.dm"
|
||||
#include "code\modules\admin\player_notes.dm"
|
||||
@@ -1988,7 +1991,6 @@
|
||||
#include "code\modules\admin\ToRban.dm"
|
||||
#include "code\modules\admin\callproc\callproc.dm"
|
||||
#include "code\modules\admin\DB ban\functions.dm"
|
||||
#include "code\modules\admin\permissionverbs\permissionedit.dm"
|
||||
#include "code\modules\admin\secrets\admin_secrets\admin_logs.dm"
|
||||
#include "code\modules\admin\secrets\admin_secrets\alter_narsie.dm"
|
||||
#include "code\modules\admin\secrets\admin_secrets\bombing_list.dm"
|
||||
@@ -2026,6 +2028,7 @@
|
||||
#include "code\modules\admin\secrets\random_events\gravity.dm"
|
||||
#include "code\modules\admin\secrets\random_events\trigger_cordical_borer_infestation.dm"
|
||||
#include "code\modules\admin\secrets\random_events\trigger_xenomorph_infestation.dm"
|
||||
#include "code\modules\admin\verb_datums\_admin_verb_datum.dm"
|
||||
#include "code\modules\admin\verbs\admin_ch.dm"
|
||||
#include "code\modules\admin\verbs\adminjump.dm"
|
||||
#include "code\modules\admin\verbs\adminpm.dm"
|
||||
@@ -2061,6 +2064,7 @@
|
||||
#include "code\modules\admin\verbs\randomverbs_vr.dm"
|
||||
#include "code\modules\admin\verbs\resize.dm"
|
||||
#include "code\modules\admin\verbs\smite.dm"
|
||||
#include "code\modules\admin\verbs\special_verbs.dm"
|
||||
#include "code\modules\admin\verbs\striketeam.dm"
|
||||
#include "code\modules\admin\verbs\tripAI.dm"
|
||||
#include "code\modules\admin\verbs\SDQL2\SDQL_2.dm"
|
||||
@@ -2124,10 +2128,12 @@
|
||||
#include "code\modules\asset_cache\assets\browser.dm"
|
||||
#include "code\modules\asset_cache\assets\circuits.dm"
|
||||
#include "code\modules\asset_cache\assets\cloning.dm"
|
||||
#include "code\modules\asset_cache\assets\common.dm"
|
||||
#include "code\modules\asset_cache\assets\fontawesome.dm"
|
||||
#include "code\modules\asset_cache\assets\icon_ref_map.dm"
|
||||
#include "code\modules\asset_cache\assets\jquery.dm"
|
||||
#include "code\modules\asset_cache\assets\ntos.dm"
|
||||
#include "code\modules\asset_cache\assets\permissions.dm"
|
||||
#include "code\modules\asset_cache\assets\preferences.dm"
|
||||
#include "code\modules\asset_cache\assets\tgfont.dm"
|
||||
#include "code\modules\asset_cache\assets\tgui.dm"
|
||||
|
||||
Reference in New Issue
Block a user