diff --git a/code/datums/vote.dm b/code/datums/vote.dm
index 8856cb5193..dc193540d3 100644
--- a/code/datums/vote.dm
+++ b/code/datums/vote.dm
@@ -5,3 +5,7 @@
var/mode = 0 // 0 = restart vote, 1 = mode vote
// modes which can be voted for
var/winner = null // the vote winner
+
+ var/customname
+ var/choices = list()
+ var/enteringchoices = 0
\ No newline at end of file
diff --git a/code/defines/global.dm b/code/defines/global.dm
index 9a7286f26e..5f3b6e027b 100644
--- a/code/defines/global.dm
+++ b/code/defines/global.dm
@@ -167,6 +167,8 @@ var
const/MAX_MESSAGE_LEN = 1024
const/MAX_PAPER_MESSAGE_LEN = 3072
+ list/paper_blacklist = list("script","frame","iframe","input","button","a","embed","object")
+
const/shuttle_time_in_station = 1800 // 3 minutes in the station
const/shuttle_time_to_arrive = 6000 // 10 minutes to arrive
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index b753e5c78e..663a5cd4ad 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -10,6 +10,7 @@
required_enemies = 1
var
+ changeling_amount
const
prob_int_murder_target = 50 // intercept names the assassination target half the time
prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target
@@ -31,7 +32,8 @@
waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds)
waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds)
- const/changeling_amount = 4
+ changeling_min = 2 //lower bound on number of traitors, assuming there are this many players
+ changeling_max = 3 //upper bound on number of traitors
/datum/game_mode/changeling/announce()
world << "The current game mode is - Changeling!"
@@ -40,6 +42,8 @@
/datum/game_mode/changeling/pre_setup()
var/list/datum/mind/possible_changelings = get_players_for_role(BE_CHANGELING)
+ changeling_amount = rand(changeling_min, changeling_max)
+
for(var/datum/mind/player in possible_changelings)
for(var/job in restricted_jobs)//Removing robots from the list
if(player.assigned_role == job)
diff --git a/code/game/magic/archived_book.dm b/code/game/magic/archived_book.dm
index 0e9225c66b..c5a589816e 100644
--- a/code/game/magic/archived_book.dm
+++ b/code/game/magic/archived_book.dm
@@ -29,6 +29,32 @@ datum/book_manager/proc/freeid()
return id
+/client/proc/delbook()
+ set name = "Delete Book"
+ set desc = "Permamently deletes a book from the database."
+ set category = "Admin"
+ if(!src.holder)
+ src << "Only administrators may use this command."
+ return
+
+ var/isbn = input("ISBN number?", "Delete Book") as num | null
+ if(!isbn)
+ return
+
+ if(config.sql_enabled)
+ var/DBConnection/dbcon = new()
+ dbcon.Connect("dbi:mysql:[sqldb]:[sqladdress]:[sqlport]","[sqllogin]","[sqlpass]")
+ if(!dbcon.IsConnected())
+ alert("Connection to Archive has been severed. Aborting.")
+ else
+ var/DBQuery/query = dbcon.NewQuery("DELETE FROM library WHERE id=[isbn]")
+ if(!query.Execute())
+ usr << query.ErrorMsg()
+ dbcon.Disconnect()
+ else
+ book_mgr.remove(isbn)
+ log_admin("[usr.key] has deleted the book [isbn]")
+
// delete a book
datum/book_manager/proc/remove(var/id)
fdel(path(id))
@@ -62,6 +88,13 @@ datum/archived_book/New(var/path)
F["id"] >> id
F["dat"] >> dat
+ // let's sanitize it here too!
+ for(var/tag in paper_blacklist)
+ if(findtext(dat,"<"+tag))
+ dat = ""
+ return
+
+
datum/archived_book/proc/save()
var/savefile/F = new(book_mgr.path(id))
diff --git a/code/game/magic/library.dm b/code/game/magic/library.dm
index a18a3f3a29..5949573024 100644
--- a/code/game/magic/library.dm
+++ b/code/game/magic/library.dm
@@ -239,9 +239,10 @@
return
// check for exploits
- if(findtext(t, "