diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 792482643ef..fcb840a894d 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -56,7 +56,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
#define MAX_SAVE_SLOTS 10 // Save slots for regular players
#define MAX_SAVE_SLOTS_MEMBER 10 // Save slots for BYOND members
-datum/preferences
+/datum/preferences
//doohickeys for savefiles
// var/path
var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used
@@ -73,7 +73,6 @@ datum/preferences
// var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
var/ooccolor = "#b82e00"
var/be_special = list() //Special role selection
- var/old_be_special = 0 //For converting from the old format
var/UI_style = "Midnight"
var/toggles = TOGGLES_DEFAULT
var/sound = SOUND_DEFAULT
@@ -1427,8 +1426,10 @@ datum/preferences
if("be_special")
var/r = href_list["role"]
if(!(r in special_roles))
- message_admins("[user] attempted an href exploit! (This could have possibly lead to a \"Bobby Tables\" exploit, so they're probably up to no good). String: [r] ID: [last_id] IP: [last_ip]")
- user << "Nice try."
+ var/cleaned_r = sql_sanitize_text(r)
+ if(r != cleaned_r) // hold it right there criminal scum
+ message_admins("[user] attempted an href exploit! (This could have possibly lead to a \"Bobby Tables\" exploit, so they're probably up to no good). String: [r] ID: [last_id] IP: [last_ip]")
+ user << "Hold it right there, criminal scum"
else
be_special ^= r
diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm
index a8816db68ce..e10c5fb30d4 100644
--- a/code/modules/client/preferences_mysql.dm
+++ b/code/modules/client/preferences_mysql.dm
@@ -35,6 +35,8 @@
randomslot = text2num(query.item[9])
volume = text2num(query.item[10])
+ old_roles_to_new(C)
+
//Sanitize
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
// lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
@@ -50,6 +52,11 @@
/datum/preferences/proc/save_preferences(client/C)
+ // Might as well scrub out any malformed be_special list entries while we're here
+ for (var/role in be_special)
+ if(!(role in special_roles))
+ be_special -= role
+
var/DBQuery/query = dbcon.NewQuery({"UPDATE [format_table_name("player")]
SET
ooccolor='[ooccolor]',
@@ -384,6 +391,83 @@
message_admins("SQL ERROR during character slot saving. Error : \[[err]\]\n")
return
return 1
+
+// If you see this proc lying around and don't know why it's there, expunge it, as this is for a short-term DB update
+// 0 on failed update, 1 on success
+/datum/preferences/proc/old_roles_to_new(var/client/C)
+ var/DBQuery/query = dbcon.NewQuery({"
+ SELECT be_special
+ FROM [format_table_name("players")]
+ WHERE ckey='[C.ckey]'"})
+ if(!query.Execute())
+ var/err = query.ErrorMsg()
+ log_game("SQL NOTICE: be_special has been purged from the database, bug the coders. Error : \[[err]\]\n")
+ message_admins("SQL NOTICE: be_special has been purged from the database, bug the coders. Error : \[[err]\]\n")
+ return 0
+ var/old_be_special = query.item[1]
+ var/B_traitor = 1
+ var/B_operative = 2
+ var/B_changeling = 4
+ var/B_wizard = 8
+ var/B_malf = 16
+ var/B_rev = 32
+ var/B_alien = 64
+ var/B_pai = 128
+ var/B_cultist = 256
+ var/B_ninja = 512
+ var/B_raider = 1024
+ var/B_vampire = 2048
+ var/B_mutineer = 4096
+ var/B_blob = 8192
+ var/B_shadowling = 16384
+ var/B_revenant = 32768
+
+ var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_ninja,B_raider,B_vampire,B_mutineer,B_blob,B_revenant)
+
+ // meow meow I am the copy cat
+ for(var/flag in archived)
+ if(old_be_special & flag)
+ switch(flag)
+ // hello i am byond i think constant variables r dumm
+ if(1)
+ be_special |= ROLE_TRAITOR
+ if(2)
+ be_special |= ROLE_OPERATIVE
+ if(4)
+ be_special |= ROLE_CHANGELING
+ if(8)
+ be_special |= ROLE_WIZARD
+ if(16)
+ be_special |= ROLE_MALF
+ if(32)
+ be_special |= ROLE_REV
+ if(64)
+ be_special |= ROLE_ALIEN
+ be_special |= ROLE_SENTIENT
+ be_special |= ROLE_DEMON
+ if(128)
+ be_special |= ROLE_PAI
+ be_special |= ROLE_POSIBRAIN
+ be_special |= ROLE_GUARDIAN
+ if(256)
+ be_special |= ROLE_CULTIST
+ if(512)
+ be_special |= ROLE_NINJA
+// be_special |= ROLE_GANG since they will occupy the same ID and all
+ if(1024)
+ be_special |= ROLE_RAIDER
+ if(2048)
+ be_special |= ROLE_VAMPIRE
+ if(4096)
+ be_special |= ROLE_MUTINEER
+ if(8192)
+ be_special |= ROLE_BLOB
+ if(16384)
+ be_special |= ROLE_SHADOWLING
+ if(32768)
+ be_special |= ROLE_REVENANT
+ return 1
+
/*
/datum/preferences/proc/random_character(client/C)
var/DBQuery/query = dbcon.NewQuery("SELECT slot FROM [format_table_name("characters")] WHERE ckey='[C.ckey]' ORDER BY slot")