mirror of
https://github.com/fulpstation/fulpstation.git
synced 2025-12-09 07:54:14 +00:00
[READY] SSdiscord and Round Notifications (#44231)
* Notify System * V2 * Adds a hint * Stoned fixes round 1 * Use grammar wells I can * This didnt work * I wish you could test on TGS without committing * Jordie fixes round 1 * oops * This took way longer than it should have taken * Adds in endnotify for serverops * Spacing
This commit is contained in:
@@ -1,15 +1,23 @@
|
||||
Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255.
|
||||
|
||||
The latest database version is 5.1; The query to update the schema revision table is:
|
||||
The latest database version is 5.2; The query to update the schema revision table is:
|
||||
|
||||
INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 1);
|
||||
INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 2);
|
||||
or
|
||||
INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 1);
|
||||
INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 2);
|
||||
|
||||
In any query remember to add a prefix to the table names if you use one.
|
||||
|
||||
----------------------------------------------------
|
||||
|
||||
|
||||
Version 5.2, 30 May 2019, by AffectedArc07
|
||||
Added a field to the `player` table to track ckey and discord ID relationships
|
||||
|
||||
ALTER TABLE `player`
|
||||
ADD COLUMN `discord_id` BIGINT NULL DEFAULT NULL AFTER `flags`;
|
||||
----------------------------------------------------
|
||||
|
||||
Version 5.1, 25 Feb 2018, by MrStonedOne
|
||||
Added four tables to enable storing of stickybans in the database since byond can lose them, and to enable disabling stickybans for a round without depending on a crash free round. Existing stickybans are automagically imported to the tables.
|
||||
|
||||
|
||||
@@ -320,6 +320,7 @@ CREATE TABLE `player` (
|
||||
`lastadminrank` varchar(32) NOT NULL DEFAULT 'Player',
|
||||
`accountjoindate` DATE DEFAULT NULL,
|
||||
`flags` smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||
`discord_id` BIGINT(20) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`ckey`),
|
||||
KEY `idx_player_cid_ckey` (`computerid`,`ckey`),
|
||||
KEY `idx_player_ip_ckey` (`ip`,`ckey`)
|
||||
@@ -513,7 +514,6 @@ CREATE TABLE `stickyban_matched_cid` (
|
||||
PRIMARY KEY (`stickyban`, `matched_cid`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
|
||||
@@ -320,6 +320,7 @@ CREATE TABLE `SS13_player` (
|
||||
`lastadminrank` varchar(32) NOT NULL DEFAULT 'Player',
|
||||
`accountjoindate` DATE DEFAULT NULL,
|
||||
`flags` smallint(5) unsigned DEFAULT '0' NOT NULL,
|
||||
`discord_id` BIGINT(20) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`ckey`),
|
||||
KEY `idx_player_cid_ckey` (`computerid`,`ckey`),
|
||||
KEY `idx_player_ip_ckey` (`ip`,`ckey`)
|
||||
@@ -513,8 +514,6 @@ CREATE TABLE `SS13_stickyban_matched_cid` (
|
||||
PRIMARY KEY (`stickyban`, `matched_cid`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//Update this whenever the db schema changes
|
||||
//make sure you add an update to the schema_version stable in the db changelog
|
||||
#define DB_MAJOR_VERSION 5
|
||||
#define DB_MINOR_VERSION 1
|
||||
#define DB_MINOR_VERSION 2
|
||||
|
||||
|
||||
//Timing subsystem
|
||||
@@ -78,6 +78,7 @@
|
||||
#define INIT_ORDER_SHUTTLE -21
|
||||
#define INIT_ORDER_MINOR_MAPPING -40
|
||||
#define INIT_ORDER_PATH -50
|
||||
#define INIT_ORDER_DISCORD -60
|
||||
#define INIT_ORDER_PERSISTENCE -100
|
||||
|
||||
// Subsystem fire priority, from lowest to highest priority
|
||||
|
||||
@@ -164,8 +164,6 @@
|
||||
|
||||
to_chat(world, "<BR><BR><BR><span class='big bold'>The round has ended.</span>")
|
||||
log_game("The round has ended.")
|
||||
if(LAZYLEN(GLOB.round_end_notifiees))
|
||||
send2irc("Notice", "[GLOB.round_end_notifiees.Join(", ")] the round has ended.")
|
||||
|
||||
for(var/I in round_end_events)
|
||||
var/datum/callback/cb = I
|
||||
|
||||
115
code/controllers/subsystem/discord.dm
Normal file
115
code/controllers/subsystem/discord.dm
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
NOTES:
|
||||
There is a DB table to track ckeys and associated discord IDs.
|
||||
This system REQUIRES TGS, and will auto-disable if TGS is not present.
|
||||
The SS uses fire() instead of just pure shutdown, so people can be notified if it comes back after a crash, where the SS wasnt properly shutdown
|
||||
It only writes to the disk every 5 minutes, and it wont write to disk if the file is the same as it was the last time it was written. This is to save on disk writes
|
||||
The system is kept per-server (EG: Terry will not notify people who pressed notify on Sybil), but the accounts are between servers so you dont have to relink on each server.
|
||||
|
||||
##################
|
||||
# HOW THIS WORKS #
|
||||
##################
|
||||
|
||||
ROUNDSTART:
|
||||
1] The file is loaded and the discord IDs are extracted
|
||||
2] A ping is sent to the discord with the IDs of people who wished to be notified
|
||||
3] The file is emptied
|
||||
|
||||
MIDROUND:
|
||||
1] Someone usees the notify verb, it adds their discord ID to the list.
|
||||
2] On fire, it will write that to the disk, as long as conditions above are correct
|
||||
|
||||
END ROUND:
|
||||
1] The file is force-saved, incase it hasnt fired at end round
|
||||
|
||||
This is an absolute clusterfuck, but its my clusterfuck -aa07
|
||||
*/
|
||||
|
||||
SUBSYSTEM_DEF(discord)
|
||||
name = "Discord"
|
||||
wait = 3000
|
||||
init_order = INIT_ORDER_DISCORD
|
||||
|
||||
var/list/notify_members = list() // People to save to notify file
|
||||
var/list/notify_members_cache = list() // Copy of previous list, so the SS doesnt have to fire if no new members have been added
|
||||
var/list/people_to_notify = list() // People to notify on roundstart
|
||||
var/list/account_link_cache = list() // List that holds accounts to link, used in conjunction with TGS
|
||||
var/notify_file = file("data/notify.json")
|
||||
var/enabled = 0 // Is TGS enabled (If not we wont fire because otherwise this is useless)
|
||||
|
||||
/datum/controller/subsystem/discord/Initialize(start_timeofday)
|
||||
// Check for if we are using TGS, otherwise return and disabless firing
|
||||
if(world.TgsAvailable())
|
||||
enabled = 1 // Allows other procs to use this (Account linking, etc)
|
||||
else
|
||||
can_fire = 0 // We dont want excess firing
|
||||
return ..() // Cancel
|
||||
|
||||
try
|
||||
people_to_notify = json_decode(file2text(notify_file))
|
||||
catch
|
||||
pass() // The list can just stay as its defualt (blank). Pass() exists because it needs a catch
|
||||
var/notifymsg = ""
|
||||
for(var/id in people_to_notify)
|
||||
// I would use jointext here, but I dont think you can two-side glue with it, and I would have to strip characters otherwise
|
||||
notifymsg += "<@[id]> " // 22 charaters per notify, 90 notifies per message, so I am not making a failsafe because 90 people arent going to notify at once
|
||||
if(notifymsg)
|
||||
send2chat("[notifymsg]", CONFIG_GET(string/chat_announce_new_game)) // Sends the message to the discord, using same config option as the roundstart notification
|
||||
fdel(notify_file) // Deletes the file
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/discord/fire()
|
||||
if(!enabled)
|
||||
return // Dont do shit if its disabled
|
||||
if(notify_members == notify_members_cache)
|
||||
return // Dont re-write the file
|
||||
// If we are all clear
|
||||
write_notify_file()
|
||||
|
||||
/datum/controller/subsystem/discord/Shutdown()
|
||||
write_notify_file() // Guaranteed force-write on server close
|
||||
|
||||
/datum/controller/subsystem/discord/proc/write_notify_file()
|
||||
if(!enabled) // Dont do shit if its disabled
|
||||
return
|
||||
fdel(notify_file) // Deletes the file first to make sure it writes properly
|
||||
WRITE_FILE(notify_file, json_encode(notify_members)) // Writes the file
|
||||
notify_members_cache = notify_members // Updates the cache list
|
||||
|
||||
// Returns ID from ckey
|
||||
/datum/controller/subsystem/discord/proc/lookup_id(lookup_ckey)
|
||||
var/datum/DBQuery/query_get_discord_id = SSdbcore.NewQuery("SELECT discord_id FROM [format_table_name("player")] WHERE ckey = '[sanitizeSQL(lookup_ckey)]'")
|
||||
if(!query_get_discord_id.Execute())
|
||||
qdel(query_get_discord_id)
|
||||
return
|
||||
if(query_get_discord_id.NextRow())
|
||||
. = query_get_discord_id.item[1]
|
||||
qdel(query_get_discord_id)
|
||||
|
||||
// Returns ckey from ID
|
||||
/datum/controller/subsystem/discord/proc/lookup_ckey(lookup_id)
|
||||
var/datum/DBQuery/query_get_discord_ckey = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE discord_id = '[sanitizeSQL(lookup_id)]'")
|
||||
if(!query_get_discord_ckey.Execute())
|
||||
qdel(query_get_discord_ckey)
|
||||
return
|
||||
if(query_get_discord_ckey.NextRow())
|
||||
. = query_get_discord_ckey.item[1]
|
||||
qdel(query_get_discord_ckey)
|
||||
|
||||
// Finalises link
|
||||
/datum/controller/subsystem/discord/proc/link_account(ckey)
|
||||
var/datum/DBQuery/link_account = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET discord_id = '[sanitizeSQL(account_link_cache[ckey])]' WHERE ckey = '[sanitizeSQL(ckey)]'")
|
||||
link_account.Execute()
|
||||
qdel(link_account)
|
||||
account_link_cache -= ckey
|
||||
|
||||
// Unlink account (Admin verb used)
|
||||
/datum/controller/subsystem/discord/proc/unlink_account(ckey)
|
||||
var/datum/DBQuery/unlink_account = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET discord_id = NULL WHERE ckey = '[sanitizeSQL(ckey)]'")
|
||||
unlink_account.Execute()
|
||||
qdel(unlink_account)
|
||||
|
||||
// Clean up a discord account mention
|
||||
/datum/controller/subsystem/discord/proc/id_clean(input)
|
||||
var/regex/num_only = regex("\[^0-9\]", "g")
|
||||
return num_only.Replace(input, "")
|
||||
@@ -72,6 +72,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/resetasaycolor,
|
||||
/client/proc/toggleadminhelpsound,
|
||||
/client/proc/respawn_character,
|
||||
/client/proc/discord_id_manipulation,
|
||||
/datum/admins/proc/open_borgopanel
|
||||
)
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/ban_panel, /client/proc/stickybanpanel))
|
||||
|
||||
@@ -75,12 +75,12 @@
|
||||
|
||||
GLOBAL_LIST(round_end_notifiees)
|
||||
|
||||
/datum/tgs_chat_command/notify
|
||||
name = "notify"
|
||||
/datum/tgs_chat_command/endnotify
|
||||
name = "endnotify"
|
||||
help_text = "Pings the invoker when the round ends"
|
||||
admin_only = TRUE
|
||||
|
||||
/datum/tgs_chat_command/notify/Run(datum/tgs_chat_user/sender, params)
|
||||
/datum/tgs_chat_command/endnotify/Run(datum/tgs_chat_user/sender, params)
|
||||
if(!SSticker.IsRoundInProgress() && SSticker.HasRoundStarted())
|
||||
return "[sender.mention], the round has already ended!"
|
||||
LAZYINITLIST(GLOB.round_end_notifiees)
|
||||
|
||||
45
code/modules/discord/accountlink.dm
Normal file
45
code/modules/discord/accountlink.dm
Normal file
@@ -0,0 +1,45 @@
|
||||
// Verb to link discord accounts to BYOND accounts
|
||||
/client/verb/linkdiscord()
|
||||
set category = "Special Verbs"
|
||||
set name = "Link Discord Account"
|
||||
set desc = "Link your discord account to your BYOND account."
|
||||
|
||||
// Safety checks
|
||||
if(!CONFIG_GET(flag/sql_enabled))
|
||||
to_chat(src, "<span class='warning'>This feature requires the SQL backend to be running.</span>")
|
||||
return
|
||||
|
||||
if(!SSdiscord) // SS is still starting
|
||||
to_chat(src, "<span class='notice'>The server is still starting up. Please wait before attempting to link your account </span>")
|
||||
return
|
||||
|
||||
if(!SSdiscord.enabled)
|
||||
to_chat(src, "<span class='warning'>This feature requires the server is running on the TGS toolkit</span>")
|
||||
return
|
||||
|
||||
var/stored_id = SSdiscord.lookup_id(usr.ckey)
|
||||
if(!stored_id) // Account is not linked
|
||||
var/know_how = alert("Do you know how to get a discord user ID? This ID is NOT your discord username and numbers! (Pressing NO will open a guide)","Question","Yes","No","Cancel Linking")
|
||||
if(know_how == "No") // Opens discord support on how to collect IDs
|
||||
src << link("https://support.discordapp.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID")
|
||||
if(know_how == "Cancel Linking")
|
||||
return
|
||||
var/entered_id = input("Please enter your Discord ID (18-ish digits)", "Enter Discord ID", null, null) as text|null
|
||||
SSdiscord.account_link_cache[replacetext(lowertext(usr.ckey), " ", "")] = "[entered_id]" // Prepares for TGS-side verification, also fuck spaces
|
||||
alert(usr, "Account link started. Please ping the bot of the server you\'re currently on, follows by \"verify [usr.ckey]\" in the Discord to successfuly verify your account (Example: @Mr_Terry verify [usr.ckey])")
|
||||
|
||||
else // Account is already linked
|
||||
var/choice = alert("You already have the Discord Account [stored_id] linked to [usr.ckey]. Would you like to link a different account?","Already Linked","Yes","No")
|
||||
if(choice == "Yes")
|
||||
var/know_how = alert("Do you know how to get a discord user ID? This ID is NOT your discord username and numbers! (Pressing NO will open a guide)","Question","Yes","No", "Cancel Linking")
|
||||
if(know_how == "No") // Opens discord support on how to collect IDs
|
||||
src << link("https://support.discordapp.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID")
|
||||
|
||||
if(know_how == "Cancel Linking")
|
||||
return
|
||||
|
||||
var/entered_id = input("Please enter your Discord ID (18-ish digits)", "Enter Discord ID", null, null) as text|null
|
||||
SSdiscord.account_link_cache[replacetext(lowertext(usr.ckey), " ", "")] = "[entered_id]" // Prepares for TGS-side verification, also fuck spaces
|
||||
alert(usr, "Account link started. Please ping the bot of the server you\'re currently on, followed by \"verify [usr.ckey]\" in the Discord to successfuly verify your account (Example: @Mr_Terry verify [usr.ckey])")
|
||||
// This is so people cant fill the notify list with a fuckload of ckeys
|
||||
SSdiscord.notify_members -= "[stored_id]" // The list uses strings because BYOND cannot handle a 17 digit integer
|
||||
36
code/modules/discord/manipulation.dm
Normal file
36
code/modules/discord/manipulation.dm
Normal file
@@ -0,0 +1,36 @@
|
||||
// Verb to manipulate IDs and ckeys
|
||||
/client/proc/discord_id_manipulation()
|
||||
set name = "Discord Manipulation"
|
||||
set category = "Admin"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
holder.discord_manipulation()
|
||||
|
||||
|
||||
/datum/admins/proc/discord_manipulation()
|
||||
if(!usr.client.holder)
|
||||
return
|
||||
|
||||
if(!SSdiscord.enabled)
|
||||
to_chat(usr, "<span class='warning'>TGS is not enabled</span>")
|
||||
return
|
||||
|
||||
var/lookup_choice = alert(usr, "Do you wish to lookup account by ID or ckey?", "Lookup Type", "ID", "Ckey", "Cancel")
|
||||
switch(lookup_choice)
|
||||
if("ID")
|
||||
var/lookup_id = input(usr,"Enter Discord ID to lookup ckey") as text
|
||||
var/returned_ckey = SSdiscord.lookup_id(lookup_id)
|
||||
if(returned_ckey)
|
||||
var/unlink_choice = alert(usr, "Discord ID [lookup_id] is linked to Ckey [returned_ckey]. Do you wish to unlink or cancel?", "Account Found", "Unlink", "Cancel")
|
||||
if(unlink_choice == "Unlink")
|
||||
SSdiscord.unlink_account(returned_ckey)
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Discord ID <b>[lookup_id]</b> has no associated ckey</span>")
|
||||
if("Ckey")
|
||||
var/lookup_ckey = input(usr,"Enter Ckey to lookup ID") as text
|
||||
var/returned_id = SSdiscord.lookup_id(lookup_ckey)
|
||||
if(returned_id)
|
||||
to_chat(usr, "<span class='notice'>Ckey <b>[lookup_ckey]</b> is assigned to Discord ID <b>[returned_id]</b></span>")
|
||||
to_chat(usr, "<span class='notice'>Discord mention format: <b><@[returned_id]></b></span>") // < and > print < > in HTML without using them as tags
|
||||
30
code/modules/discord/tgs_commands.dm
Normal file
30
code/modules/discord/tgs_commands.dm
Normal file
@@ -0,0 +1,30 @@
|
||||
// Notify
|
||||
/datum/tgs_chat_command/notify
|
||||
name = "notify"
|
||||
help_text = "Pings the invoker when the round ends"
|
||||
|
||||
/datum/tgs_chat_command/notify/Run(datum/tgs_chat_user/sender, params)
|
||||
for(var/member in SSdiscord.notify_members) // If they are in the list, take them out
|
||||
if(member == "[sender.mention]")
|
||||
SSdiscord.notify_members -= "[SSdiscord.id_clean(sender.mention)]" // The list uses strings because BYOND cannot handle a 17 digit integer
|
||||
return "You will no longer be notified when the server restarts"
|
||||
|
||||
// If we got here, they arent in the list. Chuck 'em in!
|
||||
SSdiscord.notify_members += "[SSdiscord.id_clean(sender.mention)]" // The list uses strings because BYOND cannot handle a 17 digit integer
|
||||
return "You will now be notified when the server restarts"
|
||||
|
||||
// Verify
|
||||
/datum/tgs_chat_command/verify
|
||||
name = "verify"
|
||||
help_text = "Verifies your discord account and your BYOND account linkage"
|
||||
|
||||
/datum/tgs_chat_command/verify/Run(datum/tgs_chat_user/sender, params)
|
||||
var/lowerparams = replacetext(lowertext(params), " ", "") // Fuck spaces
|
||||
if(SSdiscord.account_link_cache[lowerparams]) // First if they are in the list, then if the ckey matches
|
||||
if(SSdiscord.account_link_cache[lowerparams] == "[SSdiscord.id_clean(sender.mention)]") // If the associated ID is the correct one
|
||||
SSdiscord.link_account(lowerparams)
|
||||
return "Successfully linked accounts"
|
||||
else
|
||||
return "That ckey is not associated to this discord account. If someone has used your ID, please inform an administrator"
|
||||
else
|
||||
return "Account not setup for linkage"
|
||||
34
code/modules/discord/toggle_notify.dm
Normal file
34
code/modules/discord/toggle_notify.dm
Normal file
@@ -0,0 +1,34 @@
|
||||
// Verb to toggle restart notifications
|
||||
/client/verb/notify_restart()
|
||||
set category = "Special Verbs"
|
||||
set name = "Notify Restart"
|
||||
set desc = "Notifies you on Discord when the server restarts."
|
||||
|
||||
// Safety checks
|
||||
if(!CONFIG_GET(flag/sql_enabled))
|
||||
to_chat(src, "<span class='warning'>This feature requires the SQL backend to be running.</span>")
|
||||
return
|
||||
|
||||
if(!SSdiscord) // SS is still starting
|
||||
to_chat(src, "<span class='notice'>The server is still starting up. Please wait before attempting to link your account </span>")
|
||||
return
|
||||
|
||||
if(!SSdiscord.enabled)
|
||||
to_chat(src, "<span class='warning'>This feature requires the server is running on the TGS toolkit</span>")
|
||||
return
|
||||
|
||||
var/stored_id = SSdiscord.lookup_id(usr.ckey)
|
||||
if(!stored_id) // Account is not linked
|
||||
to_chat(src, "<span class='warning'>This requires you to link your Discord account with the \"Link Discord Account\" verb.</span>")
|
||||
return
|
||||
|
||||
else // Linked
|
||||
for(var/member in SSdiscord.notify_members) // If they are in the list, take them out
|
||||
if(member == "[stored_id]")
|
||||
SSdiscord.notify_members -= "[stored_id]" // The list uses strings because BYOND cannot handle a 17 digit integer
|
||||
to_chat(src, "<span class='notice'>You will no longer be notified when the server restarts</span>")
|
||||
return // This is necassary so it doesnt get added again, as it relies on the for loop being unsuccessful to tell us if they are in the list or not
|
||||
|
||||
// If we got here, they arent in the list. Chuck 'em in!
|
||||
to_chat(src, "<span class='notice'>You will now be notified when the server restarts</span>")
|
||||
SSdiscord.notify_members += "[stored_id]" // The list uses strings because BYOND cannot handle a 17 digit integer
|
||||
@@ -454,7 +454,7 @@ MINUTE_CLICK_LIMIT 400
|
||||
## If using TGS4, the string option can be set as a chat channel tag to limit the message to channels of that tag type (case-sensitive)
|
||||
## i.e. CHAT_ANNOUNCE_NEW_GAME chat_channel_tag
|
||||
|
||||
## Send a message with the station name starting a new game
|
||||
## Send a message with the station name starting a new game. Also required for the notify function
|
||||
#CHAT_ANNOUNCE_NEW_GAME
|
||||
|
||||
|
||||
|
||||
@@ -230,6 +230,7 @@
|
||||
#include "code\controllers\subsystem\communications.dm"
|
||||
#include "code\controllers\subsystem\dbcore.dm"
|
||||
#include "code\controllers\subsystem\dcs.dm"
|
||||
#include "code\controllers\subsystem\discord.dm"
|
||||
#include "code\controllers\subsystem\disease.dm"
|
||||
#include "code\controllers\subsystem\economy.dm"
|
||||
#include "code\controllers\subsystem\events.dm"
|
||||
@@ -1617,6 +1618,10 @@
|
||||
#include "code\modules\detectivework\evidence.dm"
|
||||
#include "code\modules\detectivework\footprints_and_rag.dm"
|
||||
#include "code\modules\detectivework\scanner.dm"
|
||||
#include "code\modules\discord\accountlink.dm"
|
||||
#include "code\modules\discord\manipulation.dm"
|
||||
#include "code\modules\discord\tgs_commands.dm"
|
||||
#include "code\modules\discord\toggle_notify.dm"
|
||||
#include "code\modules\economy\_economy.dm"
|
||||
#include "code\modules\economy\account.dm"
|
||||
#include "code\modules\economy\pay_stand.dm"
|
||||
|
||||
Reference in New Issue
Block a user