diff --git a/.travis.yml b/.travis.yml
index 464e01c8f53..146be925c77 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,8 +18,8 @@ addons:
env:
global:
- - BYOND_MAJOR="512"
- - BYOND_MINOR="1454"
+ - BYOND_MAJOR="513"
+ - BYOND_MINOR="1505"
- BYOND_MACRO_COUNT=4
matrix:
- DM_MAPFILE="cyberiad"
diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql
index 1e4692b7e3b..01f83ba0194 100644
--- a/SQL/paradise_schema.sql
+++ b/SQL/paradise_schema.sql
@@ -505,6 +505,7 @@ CREATE TABLE `notes` (
`last_editor` varchar(32),
`edits` text,
`server` varchar(50) NOT NULL,
+ `crew_playtime` mediumint(8) UNSIGNED DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -565,3 +566,32 @@ CREATE TABLE `oauth_tokens` (
PRIMARY KEY (`token`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
+
+
+--
+-- Table structure for table `playtime_history`
+--
+DROP TABLE IF EXISTS `playtime_history`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `playtime_history` (
+ `ckey` varchar(32) NOT NULL,
+ `date` DATE NOT NULL,
+ `time_living` SMALLINT NOT NULL,
+ `time_ghost` SMALLINT NOT NULL,
+ PRIMARY KEY (`ckey`, `date`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+
+--
+-- Table structure for table `connection_log`
+--
+DROP TABLE IF EXISTS `connection_log`;
+CREATE TABLE `connection_log` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `datetime` datetime NOT NULL,
+ `ckey` varchar(32) NOT NULL,
+ `ip` varchar(32) NOT NULL,
+ `computerid` varchar(32) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
\ No newline at end of file
diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql
index aa5d5895e56..9801c54d6f9 100644
--- a/SQL/paradise_schema_prefixed.sql
+++ b/SQL/paradise_schema_prefixed.sql
@@ -504,6 +504,7 @@ CREATE TABLE `SS13_notes` (
`last_editor` varchar(32),
`edits` text,
`server` varchar(50) NOT NULL,
+ `crew_playtime` mediumint(8) UNSIGNED DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -564,3 +565,30 @@ CREATE TABLE `SS13_oauth_tokens` (
PRIMARY KEY (`token`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Table structure for table `SS13_playtime_history`
+--
+DROP TABLE IF EXISTS `SS13_playtime_history`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `SS13_playtime_history` (
+ `ckey` varchar(32) NOT NULL,
+ `date` DATE NOT NULL,
+ `time_living` SMALLINT NOT NULL,
+ `time_ghost` SMALLINT NOT NULL,
+ PRIMARY KEY (`ckey`, `date`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+--
+-- Table structure for table `SS13_connection_log`
+--
+DROP TABLE IF EXISTS `SS13_connection_log`;
+CREATE TABLE `SS13_connection_log` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `datetime` datetime NOT NULL,
+ `ckey` varchar(32) NOT NULL,
+ `ip` varchar(32) NOT NULL,
+ `computerid` varchar(32) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
\ No newline at end of file
diff --git a/SQL/updates/9-10.sql b/SQL/updates/9-10.sql
new file mode 100644
index 00000000000..942aca1b541
--- /dev/null
+++ b/SQL/updates/9-10.sql
@@ -0,0 +1,24 @@
+# Updating SQL from ver 9 to 10 - Kyet
+
+# Add the 'playtime_history' table that tracks playtime per player per day
+CREATE TABLE `playtime_history` (
+ `ckey` varchar(32) NOT NULL,
+ `date` DATE NOT NULL,
+ `time_living` SMALLINT NOT NULL,
+ `time_ghost` SMALLINT NOT NULL,
+ PRIMARY KEY (`ckey`, `date`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+# Add the 'connection_log' table, which is used to log all connections to the server
+DROP TABLE IF EXISTS `connection_log`;
+CREATE TABLE `connection_log` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `datetime` datetime NOT NULL,
+ `ckey` varchar(32) NOT NULL,
+ `ip` varchar(32) NOT NULL,
+ `computerid` varchar(32) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+# Add the 'crew_playtime' field to the 'notes' table, which gives admins some idea of how many hours have passed for a player since they got a note
+ALTER TABLE `notes` ADD `crew_playtime` mediumint(8) UNSIGNED DEFAULT '0' AFTER `server`;
diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index f9fba3ff4a4..df957eaa11e 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -155,7 +155,6 @@
// /mob/living/carbon signals
#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
-#define COMSIG_CARBON_LIFE "carbon_life" //from base of mob/living/carbon/Life() ()
// /mob/living/simple_animal/hostile signals
#define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget"
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 169a5129eee..6e1fa5e01fd 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -319,7 +319,7 @@
#define INVESTIGATE_BOMB "bombs"
// The SQL version required by this version of the code
-#define SQL_VERSION 9
+#define SQL_VERSION 10
// Vending machine stuff
#define CAT_NORMAL 1
diff --git a/code/__DEFINES/typeids.dm b/code/__DEFINES/typeids.dm
index 4fd2c390fa7..16b6e475b8e 100644
--- a/code/__DEFINES/typeids.dm
+++ b/code/__DEFINES/typeids.dm
@@ -2,5 +2,5 @@
#define TYPEID_NULL "0"
#define TYPEID_NORMAL_LIST "f"
//helper macros
-#define GET_TYPEID(ref) ( ( (lentext(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, lentext(ref) - 6) ) )
+#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, length(ref) - 6) ) )
#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
\ No newline at end of file
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 65fc87c3b34..8c07fe175b2 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -140,6 +140,9 @@
/proc/log_asset(text)
WRITE_LOG(GLOB.world_asset_log, "ASSET: [text]")
+/proc/log_runtime_summary(text)
+ WRITE_LOG(GLOB.runtime_summary_log, "[text]")
+
/**
* Standardized method for tracking startup times.
*/
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index f3b76064517..0f356aa4f4a 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -20,7 +20,7 @@
if(!istext(t))
t = "[t]" // Just quietly assume any non-texts are supposed to be text
var/sqltext = dbcon.Quote(t);
- return copytext(sqltext, 2, lentext(sqltext));//Quote() adds quotes around input, we already do that
+ return copytext(sqltext, 2, length(sqltext));//Quote() adds quotes around input, we already do that
/proc/format_table_name(table as text)
return sqlfdbktableprefix + table
@@ -333,9 +333,9 @@ proc/checkhtml(var/t)
//is in the other string at the same spot (assuming it is not a replace char).
//This is used for fingerprints
var/newtext = text
- if(lentext(text) != lentext(compare))
+ if(length(text) != length(compare))
return 0
- for(var/i = 1, i < lentext(text), i++)
+ for(var/i = 1, i < length(text), i++)
var/a = copytext(text,i,i+1)
var/b = copytext(compare,i,i+1)
//if it isn't both the same letter, or if they are both the replacement character
@@ -355,7 +355,7 @@ proc/checkhtml(var/t)
if(!text || !character)
return 0
var/count = 0
- for(var/i = 1, i <= lentext(text), i++)
+ for(var/i = 1, i <= length(text), i++)
var/a = copytext(text,i,i+1)
if(a == character)
count++
@@ -400,8 +400,8 @@ proc/checkhtml(var/t)
//Used in preferences' SetFlavorText and human's set_flavor verb
//Previews a string of len or less length
/proc/TextPreview(var/string,var/len=40)
- if(lentext(string) <= len)
- if(!lentext(string))
+ if(length(string) <= len)
+ if(!length(string))
return "\[...\]"
else
return html_encode(string) //NO DECODED HTML YOU CHUCKLEFUCKS
@@ -541,7 +541,7 @@ proc/checkhtml(var/t)
text = "[text]"
else
text = "[text]"
-
+
text = copytext(text, 1, MAX_PAPER_MESSAGE_LEN)
return text
diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm
index 43482937afb..10c7d74c752 100644
--- a/code/_globalvars/logging.dm
+++ b/code/_globalvars/logging.dm
@@ -12,6 +12,8 @@ GLOBAL_VAR(world_href_log)
GLOBAL_PROTECT(world_href_log)
GLOBAL_VAR(world_asset_log)
GLOBAL_PROTECT(world_asset_log)
+GLOBAL_VAR(runtime_summary_log)
+GLOBAL_PROTECT(runtime_summary_log)
var/list/jobMax = list()
var/list/admin_log = list ( )
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 8ae35d52179..86883654997 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -79,7 +79,7 @@
var/auto_cryo_ssd_mins = 0
var/ssd_warning = 0
-
+
var/list_afk_minimum = 5 // How long people have to be AFK before it's listed on the "List AFK players" verb
var/traitor_objectives_amount = 2
@@ -102,6 +102,7 @@
var/donationsurl = "http://example.org"
var/repositoryurl = "http://example.org"
var/discordurl = "http://example.org"
+ var/discordforumurl = "http://example.org"
var/overflow_server_url
var/forbid_singulo_possession = 0
@@ -144,6 +145,7 @@
var/ipintel_detailsurl = "https://iphub.info/?ip="
var/forum_link_url
+ var/forum_playerinfo_url
var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt
var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt
@@ -244,7 +246,7 @@
//cube monkey limit
var/cubemonkeycap = 20
-
+
// Makes gamemodes respect player limits
var/enable_gamemode_player_limit = 0
@@ -354,6 +356,9 @@
if("forum_link_url")
config.forum_link_url = value
+ if("forum_playerinfo_url")
+ config.forum_playerinfo_url = value
+
if("log_ooc")
config.log_ooc = 1
@@ -483,6 +488,9 @@
if("discordurl")
config.discordurl = value
+ if("discordforumurl")
+ config.discordforumurl = value
+
if("donationsurl")
config.donationsurl = value
diff --git a/code/game/gamemodes/changeling/evolution_menu.dm b/code/game/gamemodes/changeling/evolution_menu.dm
index a9d1c3bb480..b6a0213f82f 100644
--- a/code/game/gamemodes/changeling/evolution_menu.dm
+++ b/code/game/gamemodes/changeling/evolution_menu.dm
@@ -383,9 +383,6 @@ var/list/sting_paths
var/mob/living/carbon/C = src //only carbons have dna now, so we have to typecaste
mind.changeling.absorbed_dna |= C.dna.Clone()
mind.changeling.trim_dna()
-
- RegisterSignal(C, COMSIG_CARBON_LIFE, CALLBACK(C, /mob/living/carbon/.proc/handle_changeling))
-
return 1
//Used to dump the languages from the changeling datum into the actual mob.
@@ -424,8 +421,6 @@ var/list/sting_paths
if(hud_used)
hud_used.lingstingdisplay.icon_state = null
hud_used.lingstingdisplay.invisibility = 101
- hud_used.lingchemdisplay.invisibility = 101
- UnregisterSignal(src, COMSIG_CARBON_LIFE)
/datum/changeling/proc/has_sting(datum/action/power)
for(var/datum/action/P in purchasedpowers)
diff --git a/code/game/jobs/job_exp.dm b/code/game/jobs/job_exp.dm
index 359981ded4f..b69dbfd3ed4 100644
--- a/code/game/jobs/job_exp.dm
+++ b/code/game/jobs/job_exp.dm
@@ -263,8 +263,11 @@ var/global/list/role_playtime_requirements = list(
myrole = mob.mind.playtime_role
else if(mob.mind.assigned_role)
myrole = mob.mind.assigned_role
+ var/added_living = 0
+ var/added_ghost = 0
if(mob.stat == CONSCIOUS && myrole)
play_records[EXP_TYPE_LIVING] += minutes
+ added_living += minutes
if(announce_changes)
to_chat(mob,"You got: [minutes] Living EXP!")
for(var/category in exp_jobsmap)
@@ -279,6 +282,7 @@ var/global/list/role_playtime_requirements = list(
to_chat(mob,"You got: [minutes] Special EXP!")
else if(isobserver(mob))
play_records[EXP_TYPE_GHOST] += minutes
+ added_ghost += minutes
if(announce_changes)
to_chat(mob,"You got: [minutes] Ghost EXP!")
else
@@ -286,9 +290,15 @@ var/global/list/role_playtime_requirements = list(
var/new_exp = list2params(play_records)
prefs.exp = new_exp
new_exp = sanitizeSQL(new_exp)
- var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("player")] SET exp = '[new_exp]' WHERE ckey='[ckey]'")
+ var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("player")] SET exp = '[new_exp]',lastseen = Now() WHERE ckey='[ckey]'")
if(!update_query.Execute())
var/err = update_query.ErrorMsg()
- log_game("SQL ERROR during exp_update_client write. Error : \[[err]\]\n")
- message_admins("SQL ERROR during exp_update_client write. Error : \[[err]\]\n")
+ log_game("SQL ERROR during exp_update_client write 1. Error : \[[err]\]\n")
+ message_admins("SQL ERROR during exp_update_client write 1. Error : \[[err]\]\n")
return
+ var/DBQuery/update_query_history = dbcon.NewQuery("INSERT INTO [format_table_name("playtime_history")] (ckey, date, time_living, time_ghost) VALUES ('[ckey]',CURDATE(),[added_living],[added_ghost]) ON DUPLICATE KEY UPDATE time_living=time_living+VALUES(time_living),time_ghost=time_ghost+VALUES(time_ghost)")
+ if(!update_query_history.Execute())
+ var/err = update_query_history.ErrorMsg()
+ log_game("SQL ERROR during exp_update_client write 2. Error : \[[err]\]\n")
+ message_admins("SQL ERROR during exp_update_client write 2. Error : \[[err]\]\n")
+ return
\ No newline at end of file
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index f23734a0079..8bd7af5dad4 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -444,7 +444,7 @@
//Stolen from status_display
/obj/machinery/door_timer/proc/texticon(tn, px = 0, py = 0)
var/image/I = image('icons/obj/status_display.dmi', "blank")
- var/len = lentext(tn)
+ var/len = length(tn)
for(var/d = 1 to len)
var/char = copytext(tn, len-d+1, len-d+2)
diff --git a/code/game/machinery/supply_display.dm b/code/game/machinery/supply_display.dm
index d08f68b2914..1fe7ee6e4cb 100644
--- a/code/game/machinery/supply_display.dm
+++ b/code/game/machinery/supply_display.dm
@@ -14,7 +14,7 @@
else
message1 = "CARGO"
message2 = SSshuttle.supply.getTimerStr()
- if(lentext(message2) > CHARS_PER_LINE)
+ if(length(message2) > CHARS_PER_LINE)
message2 = "Error"
update_display(message1, message2)
diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm
index 274645933b2..da3ec759d36 100644
--- a/code/game/objects/structures/musician.dm
+++ b/code/game/objects/structures/musician.dm
@@ -88,12 +88,12 @@
if(!playing || shouldStopPlaying(user)) //If the instrument is playing, or special case
playing = 0
return
- if(lentext(note) == 0)
+ if(length(note) == 0)
continue
var/cur_note = text2ascii(note) - 96
if(cur_note < 1 || cur_note > 7)
continue
- for(var/i=2 to lentext(note))
+ for(var/i=2 to length(note))
var/ni = copytext(note,i,i+1)
if(!text2num(ni))
if(ni == "#" || ni == "b" || ni == "n")
@@ -159,11 +159,11 @@
if(!in_range(instrumentObj, usr))
return
- if(lentext(t) >= 12000)
+ if(length(t) >= 12000)
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
if(cont == "no")
break
- while(lentext(t) > 12000)
+ while(length(t) > 12000)
//split into lines
spawn()
@@ -180,7 +180,7 @@
lines.Cut(201)
var/linenum = 1
for(var/l in lines)
- if(lentext(l) > 200)
+ if(length(l) > 200)
to_chat(usr, "Line [linenum] too long!")
lines.Remove(l)
else
@@ -223,7 +223,7 @@
return
if(lines.len > 200)
return
- if(lentext(newline) > 200)
+ if(length(newline) > 200)
newline = copytext(newline, 1, 200)
lines.Insert(num, newline)
@@ -241,7 +241,7 @@
var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null)
if(!content || !in_range(instrumentObj, usr))
return
- if(lentext(content) > 200)
+ if(length(content) > 200)
content = copytext(content, 1, 200)
if(num > lines.len || num < 1)
return
diff --git a/code/game/world.dm b/code/game/world.dm
index b059a7289de..4488cb2d218 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -414,6 +414,13 @@ var/failed_old_db_connections = 0
start_log(GLOB.world_runtime_log)
start_log(GLOB.world_qdel_log)
+ // This log follows a special format and this path should NOT be used for anything else
+ GLOB.runtime_summary_log = "data/logs/runtime_summary.log"
+ if(fexists(GLOB.runtime_summary_log))
+ fdel(GLOB.runtime_summary_log)
+ start_log(GLOB.runtime_summary_log)
+ // And back to sanity
+
if(fexists(GLOB.config_error_log))
fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log")
fdel(GLOB.config_error_log)
diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm
index 1ce6c2b90f0..86a6b228b60 100644
--- a/code/modules/admin/DB ban/functions.dm
+++ b/code/modules/admin/DB ban/functions.dm
@@ -469,13 +469,13 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
if(playercid)
cidsearch = "AND computerid = '[playercid]' "
else
- if(adminckey && lentext(adminckey) >= 3)
+ if(adminckey && length(adminckey) >= 3)
adminsearch = "AND a_ckey LIKE '[adminckey]%' "
- if(playerckey && lentext(playerckey) >= 3)
+ if(playerckey && length(playerckey) >= 3)
playersearch = "AND ckey LIKE '[playerckey]%' "
- if(playerip && lentext(playerip) >= 3)
+ if(playerip && length(playerip) >= 3)
ipsearch = "AND ip LIKE '[playerip]%' "
- if(playercid && lentext(playercid) >= 7)
+ if(playercid && length(playercid) >= 7)
cidsearch = "AND computerid LIKE '[playercid]%' "
if(dbbantype)
diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm
index 045819c365b..d776b4a2095 100644
--- a/code/modules/admin/IsBanned.dm
+++ b/code/modules/admin/IsBanned.dm
@@ -1,5 +1,5 @@
//Blocks an attempt to connect before even creating our client datum thing.
-world/IsBanned(key, address, computer_id, check_ipintel = TRUE)
+world/IsBanned(key, address, computer_id, type, check_ipintel = TRUE)
if(!config.ban_legacy_system)
if(address)
@@ -11,11 +11,20 @@ world/IsBanned(key, address, computer_id, check_ipintel = TRUE)
log_adminwarn("Failed Login (invalid data): [key] [address]-[computer_id]")
return list("reason"="invalid login data", "desc"="Error: Could not check ban status, please try again. Error message: Your computer provided invalid or blank information to the server on connection (BYOND Username, IP, and Computer ID). Provided information for reference: Username: '[key]' IP: '[address]' Computer ID: '[computer_id]'. If you continue to get this error, please restart byond or contact byond support.")
+ if(type == "world")
+ return ..() //shunt world topic banchecks to purely to byond's internal ban system
+
if(text2num(computer_id) == 2147483647) //this cid causes stickybans to go haywire
log_adminwarn("Failed Login (invalid cid): [key] [address]-[computer_id]")
return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided an invalid Computer ID.")
+
var/admin = 0
var/ckey = ckey(key)
+
+ var/client/C = GLOB.directory[ckey]
+ if (C && ckey == C.ckey && computer_id == C.computer_id && address == C.address)
+ return //don't recheck connected clients.
+
if((ckey in admin_datums) || (ckey in GLOB.deadmins))
var/datum/admins/A = admin_datums[ckey]
if(A && (A.rights & R_ADMIN))
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 6967a374b51..55fb1c4047a 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -100,8 +100,10 @@ var/global/nologevent = 0
body += "Jobban | "
body += "Appearance Ban | "
body += "Notes | "
+ if(config.forum_playerinfo_url)
+ body += "WebInfo | "
if(M.client)
- if(M.client.check_watchlist(M.client.ckey))
+ if(check_watchlist(M.client.ckey))
body += "Remove from Watchlist | "
body += "Edit Watchlist Reason "
else
diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm
index 9d9e60db014..57d58533437 100644
--- a/code/modules/admin/permissionverbs/permissionedit.dm
+++ b/code/modules/admin/permissionverbs/permissionedit.dm
@@ -86,17 +86,18 @@
new_admin = 0
admin_id = text2num(select_query.item[1])
+ flag_account_for_forum_sync(adm_ckey)
if(new_admin)
var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO [format_table_name("admin")] (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)")
insert_query.Execute()
- var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.[format_table_name("admin_log")] (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');")
+ var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO [format_table_name("admin_log")] (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');")
log_query.Execute()
to_chat(usr, "New admin added.")
else
if(!isnull(admin_id) && isnum(admin_id))
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE [format_table_name("admin")] SET rank = '[new_rank]' WHERE id = [admin_id]")
insert_query.Execute()
- var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.[format_table_name("admin_log")] (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');")
+ var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO [format_table_name("admin_log")] (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');")
log_query.Execute()
to_chat(usr, "Admin rank changed.")
@@ -141,16 +142,17 @@
if(!admin_id)
return
+ flag_account_for_forum_sync(adm_ckey)
if(admin_rights & new_permission) //This admin already has this permission, so we are removing it.
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE [format_table_name("admin")] SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]")
insert_query.Execute()
- var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.[format_table_name("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]');")
+ var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO [format_table_name("admin_log")] (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');")
log_query.Execute()
to_chat(usr, "Permission removed.")
else //This admin doesn't have this permission, so we are adding it.
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE [format_table_name("admin")] SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]")
insert_query.Execute()
- var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.[format_table_name("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]')")
+ var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO [format_table_name("admin_log")] (`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (Now() , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')")
log_query.Execute()
to_chat(usr, "Permission added.")
@@ -165,3 +167,4 @@
var/DBQuery/query_update = dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastadminrank = '[sql_admin_rank]' WHERE ckey = '[sql_ckey]'")
query_update.Execute()
+ flag_account_for_forum_sync(sql_ckey)
\ No newline at end of file
diff --git a/code/modules/admin/sql_notes.dm b/code/modules/admin/sql_notes.dm
index 18112f584c2..a6ac31a4114 100644
--- a/code/modules/admin/sql_notes.dm
+++ b/code/modules/admin/sql_notes.dm
@@ -4,22 +4,30 @@
if(!dbcon.IsConnected())
to_chat(usr, "Failed to establish database connection.")
return
+
if(!target_ckey)
var/new_ckey = ckey(clean_input("Who would you like to add a note for?","Enter a ckey",null))
if(!new_ckey)
return
- new_ckey = ckey(new_ckey)
- var/DBQuery/query_find_ckey = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ckey = '[new_ckey]'")
- if(!query_find_ckey.Execute())
- var/err = query_find_ckey.ErrorMsg()
- log_game("SQL ERROR obtaining ckey from player table. Error : \[[err]\]\n")
- return
- if(!query_find_ckey.NextRow())
- to_chat(usr, "[new_ckey] has not been seen before, you can only add notes to known players.")
- return
- else
- target_ckey = new_ckey
- var/target_sql_ckey = ckey(target_ckey)
+ target_ckey = ckey(new_ckey)
+ else
+ target_ckey = ckey(target_ckey)
+
+ var/DBQuery/query_find_ckey = dbcon.NewQuery("SELECT ckey, exp FROM [format_table_name("player")] WHERE ckey = '[target_ckey]'")
+ if(!query_find_ckey.Execute())
+ var/err = query_find_ckey.ErrorMsg()
+ log_game("SQL ERROR obtaining ckey from player table. Error : \[[err]\]\n")
+ return
+ if(!query_find_ckey.NextRow())
+ to_chat(usr, "[target_ckey] has not been seen before, you can only add notes to known players.")
+ return
+
+ var/exp_data = query_find_ckey.item[2]
+ var/crew_number = 0
+ if(exp_data)
+ var/list/play_records = params2list(exp_data)
+ crew_number = play_records[EXP_TYPE_CREW]
+
if(!notetext)
notetext = input(usr,"Write your note","Add Note") as message|null
if(!notetext)
@@ -38,7 +46,7 @@
if(config && config.server_name)
server = config.server_name
server = sanitizeSQL(server)
- var/DBQuery/query_noteadd = dbcon.NewQuery("INSERT INTO [format_table_name("notes")] (ckey, timestamp, notetext, adminckey, server) VALUES ('[target_sql_ckey]', '[timestamp]', '[notetext]', '[admin_sql_ckey]', '[server]')")
+ var/DBQuery/query_noteadd = dbcon.NewQuery("INSERT INTO [format_table_name("notes")] (ckey, timestamp, notetext, adminckey, server, crew_playtime) VALUES ('[target_ckey]', '[timestamp]', '[notetext]', '[admin_sql_ckey]', '[server]', '[crew_number]')")
if(!query_noteadd.Execute())
var/err = query_noteadd.ErrorMsg()
log_game("SQL ERROR adding new note to table. Error : \[[err]\]\n")
@@ -131,10 +139,10 @@
output = navbar
if(target_ckey)
var/target_sql_ckey = ckey(target_ckey)
- var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id, timestamp, notetext, adminckey, last_editor, server FROM [format_table_name("notes")] WHERE ckey = '[target_sql_ckey]' ORDER BY timestamp")
+ var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id, timestamp, notetext, adminckey, last_editor, server, crew_playtime FROM [format_table_name("notes")] WHERE ckey = '[target_sql_ckey]' ORDER BY timestamp")
if(!query_get_notes.Execute())
var/err = query_get_notes.ErrorMsg()
- log_game("SQL ERROR obtaining ckey, notetext, adminckey, last_editor, server from notes table. Error : \[[err]\]\n")
+ log_game("SQL ERROR obtaining ckey, notetext, adminckey, last_editor, server, crew_playtime from notes table. Error : \[[err]\]\n")
return
output += "Notes of [target_ckey]
"
if(!linkless)
@@ -147,7 +155,13 @@
var/adminckey = query_get_notes.item[4]
var/last_editor = query_get_notes.item[5]
var/server = query_get_notes.item[6]
- output += "[timestamp] | [server] | [adminckey]"
+ var/mins = text2num(query_get_notes.item[7])
+ output += "[timestamp] | [server] | [adminckey]"
+ if(mins)
+ var/playstring = get_exp_format(mins)
+ output += " | [playstring] as Crew"
+ output += ""
+
if(!linkless)
output += " \[Remove Note\] \[Edit Note\]"
if(last_editor)
@@ -182,10 +196,10 @@
/proc/show_player_info_irc(var/key as text)
var/target_sql_ckey = ckey(key)
- var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT timestamp, notetext, adminckey, server FROM [format_table_name("notes")] WHERE ckey = '[target_sql_ckey]' ORDER BY timestamp")
+ var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT timestamp, notetext, adminckey, server, crew_playtime FROM [format_table_name("notes")] WHERE ckey = '[target_sql_ckey]' ORDER BY timestamp")
if(!query_get_notes.Execute())
var/err = query_get_notes.ErrorMsg()
- log_game("SQL ERROR obtaining timestamp, notetext, adminckey, server from notes table. Error : \[[err]\]\n")
+ log_game("SQL ERROR obtaining timestamp, notetext, adminckey, server, crew_playtime from notes table. Error : \[[err]\]\n")
return
var/output = " Info on [key]%0D%0A"
while(query_get_notes.NextRow())
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index a318c316532..6903930bee6 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -212,7 +212,7 @@
if(admin_ranks.len)
new_rank = input("Please select a rank", "New rank", null, null) as null|anything in (admin_ranks|"*New Rank*")
else
- new_rank = input("Please select a rank", "New rank", null, null) as null|anything in list("Game Master","Game Admin", "Trial Admin", "Admin Observer","*New Rank*")
+ new_rank = input("Please select a rank", "New rank", null, null) as null|anything in list("Mentor", "Trial Admin", "Game Admin", "*New Rank*")
var/rights = 0
if(D)
@@ -936,6 +936,13 @@
target = text2num(target)
show_note(index = target)
+ else if(href_list["webtools"])
+ var/target_ckey = href_list["webtools"]
+ if(config.forum_playerinfo_url)
+ var/url_to_open = config.forum_playerinfo_url + target_ckey
+ if(alert("Open [url_to_open]",,"Yes","No")=="Yes")
+ usr.client << link(url_to_open)
+
else if(href_list["shownoteckey"])
var/target_ckey = href_list["shownoteckey"]
show_note(target_ckey)
@@ -995,6 +1002,8 @@
feedback_inc("ban_tmp",1)
DB_ban_record(BANTYPE_TEMP, M, mins, reason)
feedback_inc("ban_tmp_mins",mins)
+ if(M.client)
+ M.client.link_forum_account(TRUE)
if(config.banappeals)
to_chat(M, "To try to resolve this matter head to [config.banappeals]")
else
@@ -1011,6 +1020,8 @@
AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0, M.lastKnownIP)
to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].")
to_chat(M, "This ban does not expire automatically and must be appealed.")
+ if(M.client)
+ M.client.link_forum_account(TRUE)
if(config.banappeals)
to_chat(M, "To try to resolve this matter head to [config.banappeals]")
else
@@ -3066,7 +3077,7 @@
else if(href_list["ac_set_channel_name"])
src.admincaster_feed_channel.channel_name = strip_html_simple(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""))
while(findtext(src.admincaster_feed_channel.channel_name," ") == 1)
- src.admincaster_feed_channel.channel_name = copytext(src.admincaster_feed_channel.channel_name,2,lentext(src.admincaster_feed_channel.channel_name)+1)
+ src.admincaster_feed_channel.channel_name = copytext(src.admincaster_feed_channel.channel_name,2,length(src.admincaster_feed_channel.channel_name)+1)
src.access_news_network()
else if(href_list["ac_set_channel_lock"])
@@ -3105,7 +3116,7 @@
else if(href_list["ac_set_new_message"])
src.admincaster_feed_message.body = adminscrub(input(usr, "Write your Feed story", "Network Channel Handler", ""))
while(findtext(src.admincaster_feed_message.body," ") == 1)
- src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.body,2,lentext(src.admincaster_feed_message.body)+1)
+ src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.body,2,length(src.admincaster_feed_message.body)+1)
src.access_news_network()
else if(href_list["ac_submit_new_message"])
@@ -3159,13 +3170,13 @@
else if(href_list["ac_set_wanted_name"])
src.admincaster_feed_message.author = adminscrub(input(usr, "Provide the name of the Wanted person", "Network Security Handler", ""))
while(findtext(src.admincaster_feed_message.author," ") == 1)
- src.admincaster_feed_message.author = copytext(admincaster_feed_message.author,2,lentext(admincaster_feed_message.author)+1)
+ src.admincaster_feed_message.author = copytext(admincaster_feed_message.author,2,length(admincaster_feed_message.author)+1)
src.access_news_network()
else if(href_list["ac_set_wanted_desc"])
src.admincaster_feed_message.body = adminscrub(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", ""))
while(findtext(src.admincaster_feed_message.body," ") == 1)
- src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.body,2,lentext(src.admincaster_feed_message.body)+1)
+ src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.body,2,length(src.admincaster_feed_message.body)+1)
src.access_news_network()
else if(href_list["ac_submit_wanted"])
diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm
index f3be2161bb2..c5348fbeabe 100644
--- a/code/modules/admin/verbs/modifyvariables.dm
+++ b/code/modules/admin/verbs/modifyvariables.dm
@@ -306,11 +306,11 @@ var/list/VVpixelmovement = list("step_x", "step_y", "step_size", "bound_height",
// the type with the base type removed from the begaining
var/fancytype = types[D.type]
if(findtext(fancytype, types[type]))
- fancytype = copytext(fancytype, lentext(types[type])+1)
- var/shorttype = copytext("[D.type]", lentext("[type]")+1)
- if(lentext(shorttype) > lentext(fancytype))
+ fancytype = copytext(fancytype, length(types[type])+1)
+ var/shorttype = copytext("[D.type]", length("[type]")+1)
+ if(length(shorttype) > length(fancytype))
shorttype = fancytype
- if(!lentext(shorttype))
+ if(!length(shorttype))
shorttype = "/"
.["[D]([shorttype])\ref[D]#[i]"] = D
diff --git a/code/modules/admin/watchlist.dm b/code/modules/admin/watchlist.dm
index 040bc08112b..a908c2c264b 100644
--- a/code/modules/admin/watchlist.dm
+++ b/code/modules/admin/watchlist.dm
@@ -113,9 +113,7 @@
output += "
[reason]
"
usr << browse(output, "window=watchwin;size=900x500")
-/client/proc/check_watchlist(target_ckey)
- if(!check_rights(R_ADMIN,0))
- return
+/proc/check_watchlist(target_ckey)
var/target_sql_ckey = sanitizeSQL(target_ckey)
var/DBQuery/query_watch = dbcon.NewQuery("SELECT reason FROM [format_table_name("watch")] WHERE ckey = '[target_sql_ckey]'")
if(!query_watch.Execute())
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index 6f971d308fa..962be47cae9 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -360,10 +360,10 @@
. = ..() //calls mob.Login()
- if(ckey in clientmessages)
- for(var/message in clientmessages[ckey])
+ if(ckey in GLOB.clientmessages)
+ for(var/message in GLOB.clientmessages[ckey])
to_chat(src, message)
- clientmessages.Remove(ckey)
+ GLOB.clientmessages.Remove(ckey)
if(SSinput.initialized)
set_macros()
@@ -413,7 +413,7 @@
for(var/mob/M in GLOB.player_list)
if(M.client)
playercount += 1
-
+
if(playercount >= 150 && GLOB.panic_bunker_enabled == 0)
GLOB.panic_bunker_enabled = 1
message_admins("Panic bunker has been automatically enabled due to playercount surpassing 150")
@@ -553,16 +553,15 @@
src << "Sorry but the server is currently not accepting connections from never before seen players. Please try again later."
del(src)
return // Dont insert or they can just go in again
-
+
var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')")
if(!query_insert.Execute())
var/err = query_insert.ErrorMsg()
log_game("SQL ERROR during log_client_to_db (insert). Error : \[[err]\]\n")
message_admins("SQL ERROR during log_client_to_db (insert). Error : \[[err]\]\n")
- //Logging player access
- var/serverip = "[world.internet_address]:[world.port]"
- var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[ckey]','[sql_ip]','[sql_computerid]');")
+ // Log player connections to DB
+ var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`datetime`,`ckey`,`ip`,`computerid`) VALUES(Now(),'[ckey]','[sql_ip]','[sql_computerid]');")
query_accesslog.Execute()
/client/proc/check_ip_intel()
@@ -601,8 +600,13 @@
/client/proc/check_forum_link()
- if(config.forum_link_url && prefs && !prefs.fuid)
- to_chat(src, "You do not have your forum account linked. LINK FORUM ACCOUNT")
+ if(!config.forum_link_url || !prefs || prefs.fuid)
+ return
+ if(config.use_exp_tracking)
+ var/living_hours = get_exp_type_num(EXP_TYPE_LIVING) / 60
+ if(living_hours < 20)
+ return
+ to_chat(src, "You have no verified forum account. VERIFY FORUM ACCOUNT")
/client/proc/create_oauth_token()
var/DBQuery/query_find_token = dbcon.NewQuery("SELECT token FROM [format_table_name("oauth_tokens")] WHERE ckey = '[ckey]' limit 1")
@@ -617,12 +621,15 @@
return
return tokenstr
-/client/proc/link_forum_account()
+/client/proc/link_forum_account(fromban)
+ if(!config.forum_link_url)
+ return
if(IsGuestKey(key))
to_chat(src, "Guest keys cannot be linked.")
return
if(prefs && prefs.fuid)
- to_chat(src, "Your forum account is already set.")
+ if(!fromban)
+ to_chat(src, "Your forum account is already set.")
return
var/DBQuery/query_find_link = dbcon.NewQuery("SELECT fuid FROM [format_table_name("player")] WHERE ckey = '[ckey]' limit 1")
if(!query_find_link.Execute())
@@ -630,14 +637,19 @@
return
if(query_find_link.NextRow())
if(query_find_link.item[1])
- to_chat(src, "Your forum account is already set. (" + query_find_link.item[1] + ")")
+ if(!fromban)
+ to_chat(src, "Your forum account is already set. (" + query_find_link.item[1] + ")")
return
var/tokenid = create_oauth_token()
if(!tokenid)
to_chat(src, "link_forum_account: unable to create token")
return
var/url = "[config.forum_link_url][tokenid]"
- to_chat(src, {"Now opening a windows to verify your information with the forums. If the window does not load, please go to: [url]."})
+ if(fromban)
+ url += "&fwd=appeal"
+ to_chat(src, {"Now opening a window to verify your information with the forums, so that you can appeal your ban. If the window does not load, please copy/paste this link: [url]"})
+ else
+ to_chat(src, {"Now opening a window to verify your information with the forums. If the window does not load, please go to: [url]"})
src << link(url)
return
@@ -774,7 +786,7 @@
// Change the way they should download resources.
if(config.resource_urls)
preload_rsc = pick(config.resource_urls)
- else
+ else
preload_rsc = 1 // If config.resource_urls is not set, preload like normal.
// Most assets are now handled through global_cache.dm
getFiles(
diff --git a/code/modules/client/message.dm b/code/modules/client/message.dm
index a5c78008b4f..ba09e7e1567 100644
--- a/code/modules/client/message.dm
+++ b/code/modules/client/message.dm
@@ -1,9 +1,10 @@
-var/list/clientmessages = list()
+GLOBAL_LIST_EMPTY(clientmessages)
proc/addclientmessage(var/ckey, var/message)
ckey = ckey(ckey)
if(!ckey || !message)
return
- if(!(ckey in clientmessages))
- clientmessages[ckey] = list()
- clientmessages[ckey] += message
+ var/list/L = GLOB.clientmessages[ckey]
+ if(!L)
+ GLOB.clientmessages[ckey] = L = list()
+ L += message
\ No newline at end of file
diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm
index 11eb454a241..56cb55b6b80 100644
--- a/code/modules/client/preference/preferences.dm
+++ b/code/modules/client/preference/preferences.dm
@@ -294,8 +294,8 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
dat += "Disabilities: \[Set\]
"
dat += "Nanotrasen Relation: [nanotrasen_relation]
"
dat += "Set Flavor Text
"
- if(lentext(flavor_text) <= 40)
- if(!lentext(flavor_text)) dat += "\[...\]
"
+ if(length(flavor_text) <= 40)
+ if(!length(flavor_text)) dat += "\[...\]
"
else dat += "[flavor_text]
"
else dat += "[TextPreview(flavor_text)]...
"
@@ -886,21 +886,21 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
HTML += "Medical Records
"
- if(lentext(med_record) <= 40)
+ if(length(med_record) <= 40)
HTML += "[med_record]"
else
HTML += "[copytext(med_record, 1, 37)]..."
HTML += "
Employment Records
"
- if(lentext(gen_record) <= 40)
+ if(length(gen_record) <= 40)
HTML += "[gen_record]"
else
HTML += "[copytext(gen_record, 1, 37)]..."
HTML += "
Security Records
"
- if(lentext(sec_record) <= 40)
+ if(length(sec_record) <= 40)
HTML += "[sec_record]
"
else
HTML += "[copytext(sec_record, 1, 37)]...
"
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 84d77d1482e..adb35b0fb3b 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -527,7 +527,7 @@ BLIND // can't see anything
end up with a suffix of _open_open if adjusted twice, since their initial state is _open. */
item_state = copytext(item_state, 1, findtext(item_state, "_open"))
if(adjust_flavour)
- flavour = "[copytext(adjust_flavour, 3, lentext(adjust_flavour) + 1)] up" //Trims off the 'un' at the beginning of the word. unzip -> zip, unbutton->button.
+ flavour = "[copytext(adjust_flavour, 3, length(adjust_flavour) + 1)] up" //Trims off the 'un' at the beginning of the word. unzip -> zip, unbutton->button.
to_chat(user, "You [flavour] \the [src].")
suit_adjusted = 0 //Suit is no longer adjusted.
for(var/X in actions)
diff --git a/code/modules/error_handler/error_handler.dm b/code/modules/error_handler/error_handler.dm
index 09a5d20833e..4888948344a 100644
--- a/code/modules/error_handler/error_handler.dm
+++ b/code/modules/error_handler/error_handler.dm
@@ -44,6 +44,9 @@ var/total_runtimes_skipped = 0
error_last_seen[erroruid] = world.time
error_cooldown[erroruid] = cooldown
+ // This line will log a runtime summary to a file which can be publicly distributed without sending player data
+ log_runtime_summary("Runtime in [e.file],[e.line]: [e]")
+
// The detailed error info needs some tweaking to make it look nice
var/list/srcinfo = null
var/list/usrinfo = null
diff --git a/code/modules/flufftext/TextFilters.dm b/code/modules/flufftext/TextFilters.dm
index 02a02a6f5b2..e00f653ac45 100644
--- a/code/modules/flufftext/TextFilters.dm
+++ b/code/modules/flufftext/TextFilters.dm
@@ -1,7 +1,7 @@
proc/Intoxicated(phrase)
phrase = html_decode(phrase)
- var/leng=lentext(phrase)
- var/counter=lentext(phrase)
+ var/leng=length(phrase)
+ var/counter=length(phrase)
var/newphrase=""
var/newletter=""
while(counter>=1)
diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm
index d59e3da4e8e..f38e485d226 100644
--- a/code/modules/keybindings/bindings_client.dm
+++ b/code/modules/keybindings/bindings_client.dm
@@ -25,7 +25,7 @@
else
log_admin("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.")
message_admins("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.")
- QDEL_IN(src, 1)
+ qdel(src)
return
///Check if the key is short enough to even be a real key
@@ -33,7 +33,7 @@
to_chat(src, "Invalid KeyDown detected! You have been disconnected from the server automatically.")
log_admin("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
message_admins("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
- QDEL_IN(src, 1)
+ qdel(src)
return
//offset by 1 because the buffer address is 0 indexed because the math was simpler
keys_held[current_key_address + 1] = _key
diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm
index 45d4cda2202..a91aeed7bdf 100644
--- a/code/modules/mob/hear_say.dm
+++ b/code/modules/mob/hear_say.dm
@@ -162,7 +162,7 @@
if(copytext(heardword,1, 1) in punctuation)
heardword = copytext(heardword,2)
if(copytext(heardword,-1) in punctuation)
- heardword = copytext(heardword,1,lentext(heardword))
+ heardword = copytext(heardword,1,length(heardword))
heard = "...You hear something about... '[heardword]'..."
else
heard = "...You almost hear something......"
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index b859041d02f..85bb90a168e 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -376,7 +376,7 @@
msg += "*---------*"
if(pose)
- if( findtext(pose,".",lentext(pose)) == 0 && findtext(pose,"!",lentext(pose)) == 0 && findtext(pose,"?",lentext(pose)) == 0 )
+ if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 )
pose = addtext(pose,".") //Makes sure all emotes end with a period.
msg += "\n[p_they(TRUE)] [p_are()] [pose]"
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 6898b75b485..5352ba525f1 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -13,13 +13,13 @@
for(var/obj/item/organ/internal/O in internal_organs)
O.on_life()
+ handle_changeling()
handle_wetness(times_fired)
// Increase germ_level regularly
if(germ_level < GERM_LEVEL_AMBIENT && prob(30)) //if you're just standing there, you shouldn't get more germs beyond an ambient level
germ_level++
- SEND_SIGNAL(src, COMSIG_CARBON_LIFE, seconds, times_fired)
///////////////
// BREATHING //
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 25547e5de9e..4e280b20de8 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -538,7 +538,7 @@
if(print_flavor_text()) msg += "\n[print_flavor_text()]"
if(pose)
- if( findtext(pose,".",lentext(pose)) == 0 && findtext(pose,"!",lentext(pose)) == 0 && findtext(pose,"?",lentext(pose)) == 0 )
+ if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 )
pose = addtext(pose,".") //Makes sure all emotes end with a period.
msg += "\nIt is [pose]"
msg += "\n*---------*"
diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm
index 56d01fea839..198b687e496 100644
--- a/code/modules/mob/living/silicon/robot/examine.dm
+++ b/code/modules/mob/living/silicon/robot/examine.dm
@@ -50,7 +50,7 @@
if(print_flavor_text()) msg += "\n[print_flavor_text()]\n"
if(pose)
- if( findtext(pose,".",lentext(pose)) == 0 && findtext(pose,"!",lentext(pose)) == 0 && findtext(pose,"?",lentext(pose)) == 0 )
+ if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 )
pose = addtext(pose,".") //Makes sure all emotes end with a period.
msg += "\nIt is [pose]"
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index c9e77e294d2..609940bc2a6 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -726,7 +726,7 @@ var/list/slot_equipment_priority = list( \
/mob/proc/print_flavor_text(var/shrink = 1)
if(flavor_text && flavor_text != "")
var/msg = replacetext(flavor_text, "\n", " ")
- if(lentext(msg) <= 40 || !shrink)
+ if(length(msg) <= 40 || !shrink)
return "[html_encode(msg)]" //Repeat after me, "I will not give players access to decoded HTML."
else
return "[copytext_preserve_html(msg, 1, 37)]... More..."
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 0c2bb902737..a96a832fef4 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -201,8 +201,8 @@
/proc/slur(phrase, var/list/slurletters = ("'"))//use a different list as an input if you want to make robots slur with $#@%! characters
phrase = html_decode(phrase)
- var/leng=lentext(phrase)
- var/counter=lentext(phrase)
+ var/leng=length(phrase)
+ var/counter=length(phrase)
var/newphrase=""
var/newletter=""
while(counter>=1)
@@ -295,8 +295,8 @@
proc/muffledspeech(phrase)
phrase = html_decode(phrase)
- var/leng=lentext(phrase)
- var/counter=lentext(phrase)
+ var/leng=length(phrase)
+ var/counter=length(phrase)
var/newphrase=""
var/newletter=""
while(counter>=1)
@@ -571,7 +571,7 @@ var/list/intents = list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM)
for(var/datum/objective/objective in GLOB.all_objectives)
if(!mind || objective.target != mind)
continue
- length = lentext(oldname)
+ length = length(oldname)
pos = findtextEx(objective.explanation_text, oldname)
objective.explanation_text = copytext(objective.explanation_text, 1, pos)+newname+copytext(objective.explanation_text, pos+length)
return 1
@@ -610,8 +610,8 @@ var/list/intents = list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM)
/proc/cultslur(n) // Inflicted on victims of a stun talisman
var/phrase = html_decode(n)
- var/leng = lentext(phrase)
- var/counter=lentext(phrase)
+ var/leng = length(phrase)
+ var/counter=length(phrase)
var/newphrase=""
var/newletter=""
while(counter>=1)
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index 9da43d08fbf..446b6466dc5 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -475,7 +475,7 @@
SSnanoui.update_uis(src)
return 1
- var/index = copytext(href_list["doorder"], 1, lentext(href_list["doorder"])) //text2num(copytext(href_list["doorder"], 1))
+ var/index = copytext(href_list["doorder"], 1, length(href_list["doorder"])) //text2num(copytext(href_list["doorder"], 1))
var/multi = text2num(copytext(href_list["doorder"], -1))
if(!isnum(multi))
return 1
@@ -656,7 +656,7 @@
SSnanoui.update_uis(src)
return 1
- var/index = copytext(href_list["doorder"], 1, lentext(href_list["doorder"])) //text2num(copytext(href_list["doorder"], 1))
+ var/index = copytext(href_list["doorder"], 1, length(href_list["doorder"])) //text2num(copytext(href_list["doorder"], 1))
var/multi = text2num(copytext(href_list["doorder"], -1))
if(!isnum(multi))
return 1
diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm
index 54a9c4c88be..39c21bf1ee1 100644
--- a/code/modules/surgery/generic.dm
+++ b/code/modules/surgery/generic.dm
@@ -1,7 +1,7 @@
-//Procedures in this file: Gneric surgery steps
-//////////////////////////////////////////////////////////////////
+//Procedures in this file: Generic surgery steps
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// COMMON STEPS //
-//////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/surgery_step/generic/
can_infect = 1
@@ -237,7 +237,7 @@
/datum/surgery_step/generic/amputate/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(" [user]'s hand slips, sawing through the bone in [target]'s [affected.name] with \the [tool]!", \
- " Your hand slips, sawwing through the bone in [target]'s [affected.name] with \the [tool]!")
+ " Your hand slips, sawing through the bone in [target]'s [affected.name] with \the [tool]!")
affected.receive_damage(30)
affected.fracture()
return 0
diff --git a/config/example/config.txt b/config/example/config.txt
index 7dfdc1e413a..f4de07f581f 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -213,6 +213,9 @@ GUEST_BAN
## URL to use to link forum accounts. If not set, no link option will be offered.
#FORUM_LINK_URL https://example.com/link.php?token=
+## URL to use for admins accessing the web-based tools menu
+#FORUM_PLAYERINFO_URL https://example.com/info.php?ckey=
+
## Comment to disable checking for the cid randomizer dll. (disabled if database isn't enabled or connected)
CHECK_RANDOMIZER
@@ -237,6 +240,9 @@ CHECK_RANDOMIZER
## Discord address
# DISCORDURL http://example.org
+## Discord address (forum-based invite)
+# DISCORDFORUMURL http://example.org
+
## Donations address
# DONATIONSURL http://example.org
@@ -451,4 +457,4 @@ DISABLE_HIGH_POP_MC_MODE_AMOUNT 60
#START_NOW_CONFIRMATION
## If uncommented, all gamemodes will respect the number of required players. Defaults to no.
-#ENABLE_GAMEMODE_PLAYER_LIMIT
\ No newline at end of file
+#ENABLE_GAMEMODE_PLAYER_LIMIT
diff --git a/config/example/dbconfig.txt b/config/example/dbconfig.txt
index ad859d92543..654a7e348d5 100644
--- a/config/example/dbconfig.txt
+++ b/config/example/dbconfig.txt
@@ -9,7 +9,7 @@
## This value must be set to the version of the paradise schema in use.
## If this value does not match, the SQL database will not be loaded and an error will be generated.
## Roundstart will be delayed.
-DB_VERSION 9
+DB_VERSION 10
## Server the MySQL database can be found at.
# Examples: localhost, 200.135.5.43, www.mysqldb.com, etc.
diff --git a/goon/browserassets/js/browserOutput.js b/goon/browserassets/js/browserOutput.js
index 317fc02b9cb..40a69245188 100644
--- a/goon/browserassets/js/browserOutput.js
+++ b/goon/browserassets/js/browserOutput.js
@@ -416,7 +416,8 @@ function handleClientData(ckey, ip, compid) {
}
}
- if (opts.clientData.length >= opts.clientDataLimit) {
+ //Lets make sure we obey our limit (can connect from server with higher limit)
+ while (opts.clientData.length >= opts.clientDataLimit) {
opts.clientData.shift();
}
} else {
diff --git a/goon/code/datums/browserOutput.dm b/goon/code/datums/browserOutput.dm
index cbeb7ae3ab0..f782e663d0a 100644
--- a/goon/code/datums/browserOutput.dm
+++ b/goon/code/datums/browserOutput.dm
@@ -16,11 +16,18 @@ var/list/chatResources = list(
"goon/browserassets/html/saveInstructions.html"
)
+//Should match the value set in the browser js
+#define MAX_COOKIE_LENGTH 5
+
/var/savefile/iconCache = new /savefile("data/iconCache.sav")
/var/chatDebug = file("data/chatDebug.log")
/datum/chatOutput
var/client/owner = null
+ // How many times client data has been checked
+ var/total_checks = 0
+ // When to next clear the client data checks counter
+ var/next_time_to_clear = 0
var/loaded = 0
var/list/messageQueue = list()
var/cookieSent = 0
@@ -137,6 +144,16 @@ var/list/chatResources = list(
ehjax_send(data = data)
/datum/chatOutput/proc/analyzeClientData(cookie = "")
+ //Spam check
+ if(world.time > next_time_to_clear)
+ next_time_to_clear = world.time + (3 SECONDS)
+ total_checks = 0
+ total_checks += 1
+ if(total_checks > SPAM_TRIGGER_AUTOMUTE)
+ message_admins("[key_name(owner)] kicked for goonchat topic spam")
+ qdel(owner)
+ return
+
if(!cookie)
return
@@ -145,13 +162,21 @@ var/list/chatResources = list(
if(connData && islist(connData) && connData.len > 0 && connData["connData"])
connectionHistory = connData["connData"]
var/list/found = new()
+ if(connectionHistory.len > MAX_COOKIE_LENGTH)
+ message_admins("[key_name(src.owner)] was kicked for an invalid ban cookie)")
+ qdel(owner)
+ return
for(var/i = connectionHistory.len; i >= 1; i--)
+ if(QDELETED(owner))
+ //he got cleaned up before we were done
+ return
var/list/row = connectionHistory[i]
if(!row || row.len < 3 || !(row["ckey"] && row["compid"] && row["ip"]))
return
- if(world.IsBanned(row["ckey"], row["ip"], row["compid"], FALSE))
+ if(world.IsBanned(key=row["ckey"], address=row["ip"], computer_id=row["compid"], type=null, check_ipintel=FALSE))
found = row
break
+ CHECK_TICK
//Add autoban using the DB_ban_record function
//Uh oh this fucker has a history of playing on a banned account!!
if (found.len > 0)
@@ -284,3 +309,5 @@ var/to_chat_src
to_chat_immediate(target, message, flag)
return
SSchat.queue(target, message, flag)
+
+#undef MAX_COOKIE_LENGTH
\ No newline at end of file
diff --git a/interface/interface.dm b/interface/interface.dm
index 8edded38e93..4a140769f18 100644
--- a/interface/interface.dm
+++ b/interface/interface.dm
@@ -47,9 +47,10 @@
set desc = "Visit the forum."
set hidden = 1
if(config.forumurl)
- if(alert("This will open the forum in your browser. Are you sure?",,"Yes","No")=="No")
- return
- src << link(config.forumurl)
+ if(alert("Open the forum in your browser?",,"Yes","No")=="Yes")
+ if(config.forum_link_url && prefs && !prefs.fuid)
+ link_forum_account()
+ src << link(config.forumurl)
else
to_chat(src, "The forum URL is not set in the server configuration.")
@@ -79,13 +80,17 @@
set name = "Discord"
set desc = "Join our Discord server."
set hidden = 1
- if(config.discordurl)
- if(alert("This will invite you to our Discord server. Are you sure?",,"Yes","No")=="No")
- return
- src << link(config.discordurl)
- else
+
+ var/durl = config.discordurl
+ if(config.forum_link_url && prefs && prefs.fuid && config.discordforumurl)
+ durl = config.discordforumurl
+ if(!durl)
to_chat(src, "The Discord URL is not set in the server configuration.")
-
+ return
+ if(alert("This will invite you to our Discord server. Are you sure?",,"Yes","No")=="No")
+ return
+ src << link(durl)
+
/client/verb/donate()
set name = "Donate"
set desc = "Donate to help with hosting costs."
@@ -96,7 +101,7 @@
src << link(config.donationsurl)
else
to_chat(src, "The rules URL is not set in the server configuration.")
-
+
/client/verb/hotkeys_help()
set name = "Hotkey Help"
set category = "OOC"