diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql
index 22369d5470d..87623cea1de 100644
--- a/SQL/paradise_schema.sql
+++ b/SQL/paradise_schema.sql
@@ -457,6 +457,23 @@ CREATE TABLE `erro_watch` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--- Dump completed on 2013-03-24 18:02:35
--- Dump completed on 2015-05-28 19:57:44
+--
+-- Table structure for table `notes`
+--
+
+DROP TABLE IF EXISTS `erro_notes`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `erro_notes` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `ckey` varchar(32) NOT NULL,
+ `notetext` text NOT NULL,
+ `timestamp` datetime NOT NULL,
+ `adminckey` varchar(32) NOT NULL,
+ `last_editor` varchar(32),
+ `edits` text,
+ `server` varchar(50) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+/*!40101 SET character_set_client = @saved_cs_client */;
diff --git a/bin/bygex.dll b/bin/bygex.dll
new file mode 100644
index 00000000000..b19c0f14b1e
Binary files /dev/null and b/bin/bygex.dll differ
diff --git a/code/__HELPERS/bygex/bygex.dm b/code/__HELPERS/bygex/bygex.dm
new file mode 100644
index 00000000000..c5c4999ccca
--- /dev/null
+++ b/code/__HELPERS/bygex/bygex.dm
@@ -0,0 +1,144 @@
+/*
+ This file is part of bygex.
+
+ bygex is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ bygex is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with bygex. If not, see
+
+ Based on code by Zac Stringham - Copyright 2009 (LGPL)
+ Written 6-Oct-2013 - carnie (elly1989@rocketmail.com), accreditation appreciated but not required.
+ Please do not remove this comment.
+
+ Full source code is available at https://code.google.com/p/byond-regex/
+ Please report any relevant issues on the tracker at the above address.
+ ~Carn
+*/
+
+#ifdef USE_BYGEX
+
+#ifndef LIBREGEX_LIBRARY
+ #define LIBREGEX_LIBRARY "bin/bygex"
+#endif
+
+/proc
+ regEx_compare(str, exp)
+ return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_compare")(str, exp))
+
+ regex_compare(str, exp)
+ return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_compare")(str, exp))
+
+ regEx_find(str, exp)
+ return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_find")(str, exp))
+
+ regex_find(str, exp)
+ return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_find")(str, exp))
+
+ regEx_replaceall(str, exp, fmt)
+ return call(LIBREGEX_LIBRARY, "regEx_replaceall")(str, exp, fmt)
+
+ regex_replaceall(str, exp, fmt)
+ return call(LIBREGEX_LIBRARY, "regex_replaceall")(str, exp, fmt)
+
+ replacetextEx(str, exp, fmt)
+ return call(LIBREGEX_LIBRARY, "regEx_replaceallliteral")(str, exp, fmt)
+
+ replacetext(str, exp, fmt)
+ return call(LIBREGEX_LIBRARY, "regex_replaceallliteral")(str, exp, fmt)
+
+ regEx_replace(str, exp, fmt)
+ return call(LIBREGEX_LIBRARY, "regEx_replace")(str, exp, fmt)
+
+ regex_replace(str, exp, fmt)
+ return call(LIBREGEX_LIBRARY, "regex_replace")(str, exp, fmt)
+
+ regEx_findall(str, exp)
+ return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_findall")(str, exp))
+
+ regex_findall(str, exp)
+ return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_findall")(str, exp))
+
+
+//upon calling a regex match or search, a /datum/regex object is created with str(haystack) and exp(needle) variables set
+//it also contains a list(matches) of /datum/match objects, each of which holds the position and length of the match
+//matched strings are not returned from the dll, in order to save on memory allocation for large numbers of strings
+//instead, you can use regex.str(matchnum) to fetch this string as needed.
+//likewise you can also use regex.pos(matchnum) and regex.len(matchnum) as shorthands
+/datum/regex
+ var/str
+ var/exp
+ var/error
+ var/anchors = 0
+ var/list/matches = list()
+
+ New(str, exp, results)
+ src.str = str
+ src.exp = exp
+
+ if(findtext(results, "$Err$", 1, 6)) //error message
+ src.error = results
+ else
+ var/list/L = params2list(results)
+ var/list/M
+ var{i;j}
+ for(i in L)
+ M = L[i]
+ for(j=2, j<=M.len, j+=2)
+ matches += new /datum/match(text2num(M[j-1]),text2num(M[j]))
+ anchors = (j-2)/2
+ return matches
+
+ proc
+ str(i)
+ if(!i) return str
+ var/datum/match/M = matches[i]
+ if(i < 1 || i > matches.len)
+ throw EXCEPTION("str(): out of bounds")
+ return copytext(str, M.pos, M.pos+M.len)
+
+ pos(i)
+ if(!i) return 1
+ if(i < 1 || i > matches.len)
+ throw EXCEPTION("pos(): out of bounds")
+ var/datum/match/M = matches[i]
+ return M.pos
+
+ len(i)
+ if(!i) return length(str)
+ if(i < 1 || i > matches.len)
+ throw EXCEPTION("len(): out of bounds")
+ var/datum/match/M = matches[i]
+ return M.len
+
+ end(i)
+ if(!i) return length(str)
+ if(i < 1 || i > matches.len)
+ throw EXCEPTION("end() out of bounds")
+ var/datum/match/M = matches[i]
+ return M.pos + M.len
+
+ report() //debug tool
+ . = ":: RESULTS ::\n:: str :: [html_encode(str)]\n:: exp :: [html_encode(exp)]\n:: anchors :: [anchors]"
+ if(error)
+ . += "\n[error]"
+ return
+ for(var/i=1, i<=matches.len, ++i)
+ . += "\nMatch[i]\n\t[html_encode(str(i))]\n\tpos=[pos(i)] len=[len(i)]"
+
+/datum/match
+ var/pos
+ var/len
+
+ New(pos, len)
+ src.pos = pos
+ src.len = len
+
+#endif
\ No newline at end of file
diff --git a/code/__HELPERS/bygex/demo.dm b/code/__HELPERS/bygex/demo.dm
new file mode 100644
index 00000000000..f89be30ded2
--- /dev/null
+++ b/code/__HELPERS/bygex/demo.dm
@@ -0,0 +1,54 @@
+/mob
+ var/expression = "\\S+"
+ var/format = "*"
+
+ var/datum/regex/results
+
+ verb
+ set_expression()
+ var/t = input(usr,"Input Expression","title",expression) as text|null
+ if(t != null)
+ expression = t
+ usr << "Expression set to:\t[html_encode(t)]"
+
+ set_format()
+ var/t = input(usr,"Input Formatter","title",format) as text|null
+ if(t != null)
+ format = t
+ usr << "Format set to:\t[html_encode(t)]"
+
+ compare_casesensitive(t as text)
+ results = regEx_compare(t, expression)
+ world << results.report()
+
+ compare(t as text)
+ results = regex_compare(t, expression)
+ world << results.report()
+
+ find_casesensitive(t as text)
+ results = regEx_find(t, expression)
+ world << results.report()
+
+ find(t as text)
+ results = regex_find(t, expression)
+ world << results.report()
+
+ replaceall_casesensitive(t as text)
+ usr << regEx_replaceall(t, expression, format)
+
+ replaceall(t as text)
+ usr << regex_replaceall(t, expression, format)
+
+ replace_casesensitive(t as text)
+ usr << html_encode(regEx_replace(t, expression, format))
+
+ replace(t as text)
+ usr << regex_replace(t, expression, format)
+
+ findall(t as text)
+ results = regex_findall(t, expression)
+ world << results.report()
+
+ findall_casesensitive(t as text)
+ results = regEx_findall(t, expression)
+ world << results.report()
\ No newline at end of file
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index a18a377b30c..5b720291b48 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -202,11 +202,14 @@ proc/checkhtml(var/t)
/*
* Text modification
*/
+// See bygex.dm
+#ifndef USE_BYGEX
/proc/replacetext(text, find, replacement)
return list2text(text2list(text, find), replacement)
/proc/replacetextEx(text, find, replacement)
return list2text(text2listEx(text, find), replacement)
+#endif
/proc/replace_characters(var/t,var/list/repl_chars)
for(var/char in repl_chars)
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index 84f3b3048c9..a2bf32f53c7 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -17,4 +17,6 @@ Due to BYOND features used in this codebase, you must update to version 508 or l
This may require updating to a beta release.
#endif
-var/global/list/processing_objects = list() //This has to be initialized BEFORE world
\ No newline at end of file
+var/global/list/processing_objects = list() //This has to be initialized BEFORE world
+
+#define USE_BYGEX
\ No newline at end of file
diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm
index 780f17a1b90..47e942225fc 100644
--- a/code/_globalvars/lists/misc.dm
+++ b/code/_globalvars/lists/misc.dm
@@ -1,4 +1,8 @@
-var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z") //added for Xenoarchaeology, might be useful for other stuff
+var/global/list/alphabet = list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")
+var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
+var/global/list/zero_character_only = list("0")
+var/global/list/hex_characters = list("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f")
+var/global/list/binary = list("0","1")
//Reagent stuff
var/list/tachycardics = list("coffee", "methamphetamine", "nitroglycerin", "thirteenloko", "nicotine") //increase heart rate
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index a958c3b4eec..5f6f5c9978a 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -162,6 +162,8 @@
var/list/overflow_whitelist = list() //whitelist for overflow
var/disable_away_missions = 0 // disable away missions
+
+ var/autoconvert_notes = 0 //if all connecting player's notes should attempt to be converted to the database
/datum/configuration/New()
var/list/L = subtypesof(/datum/game_mode)
@@ -526,6 +528,9 @@
if("disable_away_missions")
config.disable_away_missions = 1
+ if("autoconvert_notes")
+ config.autoconvert_notes = 1
+
else
diary << "Unknown setting in configuration: '[name]'"
diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm
index ecc2a812bf0..b871ada026d 100644
--- a/code/modules/admin/NewBan.dm
+++ b/code/modules/admin/NewBan.dm
@@ -120,9 +120,9 @@ var/savefile/Banlist
if (temp)
Banlist["minutes"] << bantimestamp
if(!temp)
- notes_add(ckey, "Permanently banned - [reason]")
+ add_note(ckey, "Permanently banned - [reason]", null, bannedby, 0)
else
- notes_add(ckey, "Banned for [minutes] minutes - [reason]")
+ add_note(ckey, "Banned for [minutes] minutes - [reason]", null, bannedby, 0)
return 1
/proc/RemoveBan(foldername)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index a4a836db6a6..7a17941ad1a 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -65,7 +65,7 @@ var/global/nologevent = 0
body += "Ban | "
body += "Jobban | "
body += "Appearance Ban | "
- body += "Notes | "
+ body += "Notes | "
if(M.client)
if(M.client.check_watchlist(M.client.ckey))
body += "Remove from Watchlist | "
@@ -215,112 +215,29 @@ var/global/nologevent = 0
/datum/admins/proc/PlayerNotes()
set category = "Admin"
set name = "Player Notes"
- if (!istype(src,/datum/admins))
- src = usr.client.holder
- if (!istype(src,/datum/admins))
- usr << "Error: you are not an admin!"
+
+ if(!check_rights(R_ADMIN))
return
- PlayerNotesPage(1)
+
+ show_note()
-/datum/admins/proc/PlayerNotesPage(page)
- var/dat = "Player notes
"
- var/savefile/S=new("data/player_notes.sav")
- var/list/note_keys
- S >> note_keys
- if(!note_keys)
- dat += "No notes found."
- else
- dat += ""
- note_keys = sortList(note_keys)
-
- // Display the notes on the current page
- var/number_pages = note_keys.len / PLAYER_NOTES_ENTRIES_PER_PAGE
- // Emulate ceil(why does BYOND not have ceil)
- if(number_pages != round(number_pages))
- number_pages = round(number_pages) + 1
- var/page_index = page - 1
- if(page_index < 0 || page_index >= number_pages)
- return
-
- var/lower_bound = page_index * PLAYER_NOTES_ENTRIES_PER_PAGE + 1
- var/upper_bound = (page_index + 1) * PLAYER_NOTES_ENTRIES_PER_PAGE
- upper_bound = min(upper_bound, note_keys.len)
- for(var/index = lower_bound, index <= upper_bound, index++)
- var/t = note_keys[index]
- dat += "| [t] |
"
-
- dat += "
"
-
- // Display a footer to select different pages
- for(var/index = 1, index <= number_pages, index++)
- if(index == page)
- dat += ""
- dat += "[index] "
- if(index == page)
- dat += ""
-
- usr << browse(dat, "window=player_notes;size=400x400")
-
-
-/datum/admins/proc/player_has_info(var/key as text)
- var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
- var/list/infos
- info >> infos
- if(!infos || !infos.len) return 0
- else return 1
-
-
-/datum/admins/proc/show_player_info(var/key as text)
+/datum/admins/proc/show_player_notes(var/key as text)
set category = "Admin"
- set name = "Show Player Info"
- if (!istype(src,/datum/admins))
- src = usr.client.holder
- if (!istype(src,/datum/admins))
- usr << "Error: you are not an admin!"
+ set name = "Show Player Notes"
+
+ if(!check_rights(R_ADMIN))
return
- var/dat = "Info on [key]"
- dat += ""
-
- var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
- var/list/infos
- info >> infos
- if(!infos)
- dat += "No information found on the given key.
"
- else
- var/update_file = 0
- var/i = 0
- for(var/datum/player_info/I in infos)
- i += 1
- if(!I.timestamp)
- I.timestamp = "Pre-4/3/2012"
- update_file = 1
- if(!I.rank)
- I.rank = "N/A"
- update_file = 1
- dat += "[I.content] by [I.author] ([I.rank]) on [I.timestamp] "
- if(I.author == usr.key)
- dat += "Remove"
- dat += "
"
- if(update_file) info << infos
-
- dat += "
"
- dat += "Add Comment
"
-
- dat += ""
- usr << browse(dat, "window=adminplayerinfo;size=480x480")
-
-
-
+
+ show_note(key)
+
/datum/admins/proc/access_news_network() //MARKER
set category = "Event"
set name = "Access Newscaster Network"
set desc = "Allows you to view, add and edit news feeds."
- if (!istype(src,/datum/admins))
- src = usr.client.holder
- if (!istype(src,/datum/admins))
- usr << "Error: you are not an admin!"
+ if(!check_rights(R_EVENT))
return
+
var/dat
dat = text("Admin NewscasterAdmin Newscaster Unit
")
diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm
index 0fc31b8848a..04a86404ccb 100644
--- a/code/modules/admin/admin_investigate.dm
+++ b/code/modules/admin/admin_investigate.dm
@@ -26,7 +26,7 @@
F << "[time_stamp()] \ref[src] ([x],[y],[z]) || [src] [message]
"
//ADMINVERBS
-/client/proc/investigate_show( subject in list("hrefs","pda","singulo","atmos","watchlist","ntsl","gold core","cult") )
+/client/proc/investigate_show( subject in list("hrefs","notes","pda","singulo","atmos","watchlist","ntsl","gold core","cult") )
set name = "Investigate"
set category = "Admin"
if(!holder) return
@@ -78,4 +78,7 @@
src << browse(F,"window=investigate[subject];size=800x300")
if("watchlist")
- watchlist_show()
\ No newline at end of file
+ watchlist_show()
+
+ if("notes")
+ show_note()
\ No newline at end of file
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index c0b1aba0a61..77b7ae94bda 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -55,7 +55,7 @@ var/list/admin_verbs_admin = list(
/client/proc/cmd_admin_say, /*admin-only ooc chat*/
/datum/admins/proc/PlayerNotes,
/client/proc/cmd_mod_say,
- /datum/admins/proc/show_player_info,
+ /datum/admins/proc/show_player_notes,
/client/proc/free_slot, /*frees slot for chosen job*/
/client/proc/toggleattacklogs,
/client/proc/toggledebuglogs,
diff --git a/code/modules/admin/player_notes.dm b/code/modules/admin/player_notes.dm
deleted file mode 100644
index 8b439ea6fe9..00000000000
--- a/code/modules/admin/player_notes.dm
+++ /dev/null
@@ -1,167 +0,0 @@
-//This stuff was originally intended to be integrated into the ban-system I was working on
-//but it's safe to say that'll never be finished. So I've merged it into the current player panel.
-//enjoy ~Carn
-/*
-#define NOTESFILE "data/player_notes.sav" //where the player notes are saved
-
-datum/admins/proc/notes_show(var/ckey)
- usr << browse("Player Notes[notes_gethtml(ckey)]","window=player_notes;size=700x400")
-
-
-datum/admins/proc/notes_gethtml(var/ckey)
- var/savefile/notesfile = new(NOTESFILE)
- if(!notesfile) return "Error: Cannot access [NOTESFILE]"
- if(ckey)
- . = "Notes for [ckey]: \[+\] \[-\]
"
- notesfile.cd = "/[ckey]"
- var/index = 1
- while( !notesfile.eof )
- var/note
- notesfile >> note
- . += "[note] \[-\]
"
- index++
- else
- . = "All Notes: \[+\] \[-\]
"
- notesfile.cd = "/"
- for(var/dir in notesfile.dir)
- . += "[dir]
"
- return
-
-
-//handles adding notes to the end of a ckey's buffer
-//originally had seperate entries such as var/by to record who left the note and when
-//but the current bansystem is a heap of dung.
-/proc/notes_add(var/ckey, var/note)
- if(!ckey)
- ckey = ckey(input(usr,"Who would you like to add notes for?","Enter a ckey",null) as text|null)
- if(!ckey) return
-
- if(!note)
- note = html_encode(input(usr,"Enter your note:","Enter some text",null) as message|null)
- if(!note) return
-
- var/savefile/notesfile = new(NOTESFILE)
- if(!notesfile) return
- notesfile.cd = "/[ckey]"
- notesfile.eof = 1 //move to the end of the buffer
- notesfile << "[time2text(world.realtime,"DD-MMM-YYYY")] | [note][(usr && usr.ckey)?" ~[usr.ckey]":""]"
- return
-
-//handles removing entries from the buffer, or removing the entire directory if no start_index is given
-/proc/notes_remove(var/ckey, var/start_index, var/end_index)
- var/savefile/notesfile = new(NOTESFILE)
- if(!notesfile) return
-
- if(!ckey)
- notesfile.cd = "/"
- ckey = ckey(input(usr,"Who would you like to remove notes for?","Enter a ckey",null) as null|anything in notesfile.dir)
- if(!ckey) return
-
- if(start_index)
- notesfile.cd = "/[ckey]"
- var/list/noteslist = list()
- if(!end_index) end_index = start_index
- var/index = 0
- while( !notesfile.eof )
- index++
- var/temp
- notesfile >> temp
- if( (start_index <= index) && (index <= end_index) )
- continue
- noteslist += temp
-
- notesfile.eof = -2 //Move to the start of the buffer and then erase.
-
- for( var/note in noteslist )
- notesfile << note
- else
- notesfile.cd = "/"
- if(alert(usr,"Are you sure you want to remove all their notes?","Confirmation","No","Yes - Remove all notes") == "Yes - Remove all notes")
- notesfile.dir.Remove(ckey)
- return
-
-#undef NOTESFILE
-*/
-
-//Hijacking this file for BS12 playernotes functions. I like this ^ one systemm alright, but converting sounds too bothersome~ Chinsky.
-
-/proc/notes_add(var/key, var/note, var/mob/usr)
- if (!key || !note)
- return
-
- //Loading list of notes for this key
- var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
- var/list/infos
- info >> infos
- if(!infos) infos = list()
-
- //Overly complex timestamp creation
- var/modifyer = "th"
- switch(time2text(world.timeofday, "DD"))
- if("01","21","31")
- modifyer = "st"
- if("02","22",)
- modifyer = "nd"
- if("03","23")
- modifyer = "rd"
- var/day_string = "[time2text(world.timeofday, "DD")][modifyer]"
- if(copytext(day_string,1,2) == "0")
- day_string = copytext(day_string,2)
- var/full_date = time2text(world.timeofday, "DDD, Month DD of YYYY")
- var/day_loc = findtext(full_date, time2text(world.timeofday, "DD"))
-
- var/datum/player_info/P = new
- if (usr)
- P.author = usr.key
- P.rank = usr.client.holder.rank
- else
- P.author = "Adminbot"
- P.rank = "Friendly Robot"
- P.content = note
- P.timestamp = "[copytext(full_date,1,day_loc)][day_string][copytext(full_date,day_loc+2)]"
-
- infos += P
- info << infos
-
- message_admins("\blue [key_name_admin(usr)] has edited [key]'s notes.")
- log_admin("[key_name(usr)] has edited [key]'s notes.")
-
- del(info)
-
- //Updating list of keys with notes on them
- var/savefile/note_list = new("data/player_notes.sav")
- var/list/note_keys
- note_list >> note_keys
- if(!note_keys) note_keys = list()
- if(!note_keys.Find(key)) note_keys += key
- note_list << note_keys
- del(note_list)
-
-
-/proc/notes_del(var/key, var/index)
- var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
- var/list/infos
- info >> infos
- if(!infos || infos.len < index) return
-
- var/datum/player_info/item = infos[index]
- infos.Remove(item)
- info << infos
-
- message_admins("\blue [key_name_admin(usr)] deleted one of [key]'s notes.")
- log_admin("[key_name(usr)] deleted one of [key]'s notes.")
-
- del(info)
-
-/proc/show_player_info_irc(var/key as text)
- var/dat = " Info on [key]%0D%0A"
- var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
- var/list/infos
- info >> infos
- if(!infos)
- dat = "No information found on the given key."
- else
- for(var/datum/player_info/I in infos)
- dat += "[I.content]%0D%0Aby [I.author] ([I.rank]) on [I.timestamp]%0D%0A%0D%0A"
-
- return dat
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index a345f9df321..7e6ebcf4c5a 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -76,7 +76,7 @@
body += "";
body += "PP - "
- body += "N - "
+ body += "N - "
body += "VV - "
body += "TP - "
body += "PM - "
diff --git a/code/modules/admin/sql_notes.dm b/code/modules/admin/sql_notes.dm
new file mode 100644
index 00000000000..2a76ed97f90
--- /dev/null
+++ b/code/modules/admin/sql_notes.dm
@@ -0,0 +1,226 @@
+/proc/add_note(target_ckey, notetext, timestamp, adminckey, logged = 1, server)
+ if(!dbcon.IsConnected())
+ usr << "Failed to establish database connection."
+ return
+ if(!target_ckey)
+ var/new_ckey = ckey(input(usr,"Who would you like to add a note for?","Enter a ckey",null) as text|null)
+ if(!new_ckey)
+ return
+ new_ckey = sanitizeSQL(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())
+ 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 = sanitizeSQL(target_ckey)
+ if(!notetext)
+ notetext = input(usr,"Write your Note","Add Note") as message
+ if(!notetext)
+ return
+ notetext = sanitizeSQL(notetext)
+ if(!timestamp)
+ timestamp = SQLtime()
+ if(!adminckey)
+ adminckey = usr.ckey
+ if(!adminckey)
+ return
+ var/admin_sql_ckey = sanitizeSQL(adminckey)
+ if(!server)
+ 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]')")
+ if(!query_noteadd.Execute())
+ var/err = query_noteadd.ErrorMsg()
+ log_game("SQL ERROR adding new note to table. Error : \[[err]\]\n")
+ return
+ if(logged)
+ log_admin("[key_name(usr)] has added a note to [target_ckey]: [notetext]")
+ message_admins("[key_name_admin(usr)] has added a note to [target_ckey]: [notetext]")
+ show_note(target_ckey)
+
+/proc/remove_note(note_id)
+ var/ckey
+ var/notetext
+ var/adminckey
+ if(!dbcon.IsConnected())
+ usr << "Failed to establish database connection."
+ return
+ if(!note_id)
+ return
+ note_id = text2num(note_id)
+ var/DBQuery/query_find_note_del = dbcon.NewQuery("SELECT ckey, notetext, adminckey FROM [format_table_name("notes")] WHERE id = [note_id]")
+ if(!query_find_note_del.Execute())
+ var/err = query_find_note_del.ErrorMsg()
+ log_game("SQL ERROR obtaining ckey, notetext, adminckey from player table. Error : \[[err]\]\n")
+ return
+ if(query_find_note_del.NextRow())
+ ckey = query_find_note_del.item[1]
+ notetext = query_find_note_del.item[2]
+ adminckey = query_find_note_del.item[3]
+ var/DBQuery/query_del_note = dbcon.NewQuery("DELETE FROM [format_table_name("notes")] WHERE id = [note_id]")
+ if(!query_del_note.Execute())
+ var/err = query_del_note.ErrorMsg()
+ log_game("SQL ERROR removing note from table. Error : \[[err]\]\n")
+ return
+ log_admin("[key_name(usr)] has removed a note made by [adminckey] from [ckey]: [notetext]")
+ message_admins("[key_name_admin(usr)] has removed a note made by [adminckey] from [ckey]: [notetext]")
+ show_note(ckey)
+
+/proc/edit_note(note_id)
+ if(!dbcon.IsConnected())
+ usr << "Failed to establish database connection."
+ return
+ if(!note_id)
+ return
+ note_id = text2num(note_id)
+ var/target_ckey
+ var/sql_ckey = sanitizeSQL(usr.ckey)
+ var/DBQuery/query_find_note_edit = dbcon.NewQuery("SELECT ckey, notetext, adminckey FROM [format_table_name("notes")] WHERE id = [note_id]")
+ if(!query_find_note_edit.Execute())
+ var/err = query_find_note_edit.ErrorMsg()
+ log_game("SQL ERROR obtaining notetext from notes table. Error : \[[err]\]\n")
+ return
+ if(query_find_note_edit.NextRow())
+ target_ckey = query_find_note_edit.item[1]
+ var/old_note = query_find_note_edit.item[2]
+ var/adminckey = query_find_note_edit.item[3]
+ var/new_note = input("Input new note", "New Note", "[old_note]") as message
+ if(!new_note)
+ return
+ new_note = sanitizeSQL(new_note)
+ var/edit_text = "Edited by [sql_ckey] on [SQLtime()] from '[old_note]' to '[new_note]' "
+ edit_text = sanitizeSQL(edit_text)
+ var/DBQuery/query_update_note = dbcon.NewQuery("UPDATE [format_table_name("notes")] SET notetext = '[new_note]', last_editor = '[sql_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [note_id]")
+ if(!query_update_note.Execute())
+ var/err = query_update_note.ErrorMsg()
+ log_game("SQL ERROR editing note. Error : \[[err]\]\n")
+ return
+ log_admin("[key_name(usr)] has edited [target_ckey]'s note made by [adminckey] from [old_note] to [new_note]")
+ message_admins("[key_name_admin(usr)] has edited [target_ckey]'s note made by [adminckey] from '[old_note]' to '[new_note]'")
+ show_note(target_ckey)
+
+/proc/show_note(target_ckey, index, linkless = 0)
+ var/output
+ var/navbar
+ var/ruler
+ ruler = " "
+ navbar = "\[All\]|\[#\]"
+ for(var/letter in alphabet)
+ navbar += "|\[[letter]\]"
+ navbar += " "
+ if(!linkless)
+ output = navbar
+ if(target_ckey)
+ var/target_sql_ckey = sanitizeSQL(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")
+ 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")
+ return
+ output += "Notes of [target_ckey]"
+ if(!linkless)
+ output += "\[Add Note\]"
+ output += ruler
+ while(query_get_notes.NextRow())
+ var/id = query_get_notes.item[1]
+ var/timestamp = query_get_notes.item[2]
+ var/notetext = query_get_notes.item[3]
+ 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]"
+ if(!linkless)
+ output += " \[Remove Note\] \[Edit Note\]"
+ if(last_editor)
+ output += " Last edit by [last_editor] (Click here to see edit log)"
+ output += " [notetext] "
+ else if(index)
+ var/index_ckey
+ var/search
+ output += "\[Add Note\]"
+ output += ruler
+ if(!isnum(index))
+ index = sanitizeSQL(index)
+ switch(index)
+ if(1)
+ search = "^."
+ if(2)
+ search = "^\[^\[:alpha:\]\]"
+ else
+ search = "^[index]"
+ var/DBQuery/query_list_notes = dbcon.NewQuery("SELECT DISTINCT ckey FROM [format_table_name("notes")] WHERE ckey REGEXP '[search]' ORDER BY ckey")
+ if(!query_list_notes.Execute())
+ var/err = query_list_notes.ErrorMsg()
+ log_game("SQL ERROR obtaining ckey from notes table. Error : \[[err]\]\n")
+ return
+ while(query_list_notes.NextRow())
+ index_ckey = query_list_notes.item[1]
+ output += "[index_ckey] "
+ else
+ output += "\[Add Note\]"
+ output += ruler
+ usr << browse(output, "window=show_notes;size=900x500")
+
+/proc/regex_note_sql_extract(str, exp)
+ return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_find")(str, exp))
+
+#define NOTESFILE "data/player_notes.sav"
+//if the AUTOCONVERT_NOTES is turned on, anytime a player connects this will be run to try and add all their notes to the databas
+/proc/convert_notes_sql(ckey)
+ var/savefile/notesfile = new(NOTESFILE)
+ if(!notesfile)
+ log_game("Error: Cannot access [NOTESFILE]")
+ return
+ notesfile.cd = "/[ckey]"
+ while(!notesfile.eof)
+ var/notetext
+ notesfile >> notetext
+ var/server
+ if (config && config.server_name)
+ server = config.server_name
+ var/regex = "^(\\d{2}-\\w{3}-\\d{4}) \\| (.+) ~(\\w+)$"
+ var/datum/regex/results = regex_note_sql_extract(notetext, regex)
+ var/timestamp = results.str(2)
+ notetext = results.str(3)
+ var/adminckey = results.str(4)
+ var/DBQuery/query_convert_time = dbcon.NewQuery("SELECT ADDTIME(STR_TO_DATE('[timestamp]','%d-%b-%Y'), '0')")
+ if(!query_convert_time.Execute())
+ var/err = query_convert_time.ErrorMsg()
+ log_game("SQL ERROR converting timestamp. Error : \[[err]\]\n")
+ return
+ if(query_convert_time.NextRow())
+ timestamp = query_convert_time.item[1]
+ if(ckey && notetext && timestamp && adminckey && server)
+ add_note(ckey, notetext, timestamp, adminckey, 0, server)
+ notesfile.cd = "/"
+ notesfile.dir.Remove(ckey)
+
+/*alternatively this proc can be run once to pass through every note and attempt to convert it before deleting the file, if done then AUTOCONVERT_NOTES should be turned off
+this proc can take several minutes to execute fully if converting and cause DD to hang if converting a lot of notes; it's not advised to do so while a server is live
+/proc/mass_convert_notes()
+ world << "Beginning mass note conversion"
+ var/savefile/notesfile = new(NOTESFILE)
+ if(!notesfile)
+ log_game("Error: Cannot access [NOTESFILE]")
+ return
+ notesfile.cd = "/"
+ for(var/ckey in notesfile.dir)
+ convert_notes_sql(ckey)
+ world << "Deleting NOTESFILE"
+ fdel(NOTESFILE)
+ world << "Finished mass note conversion, remember to turn off AUTOCONVERT_NOTES"*/
+
+/proc/show_player_info_irc(var/key as text)
+ var/notes = show_note(key, linkless = 1)
+ return notes
+
+#undef NOTESFILE
\ No newline at end of file
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 32cd8fb90ba..c48041774bd 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -445,7 +445,7 @@
feedback_inc("ban_appearance",1)
DB_ban_record(BANTYPE_APPEARANCE, M, -1, reason)
appearance_fullban(M, "[reason]; By [usr.ckey] on [time2text(world.realtime)]")
- notes_add(M.ckey, "Appearance banned - [reason]")
+ add_note(M.ckey, "Appearance banned - [reason]", null, usr, 0)
message_admins("\blue [key_name_admin(usr)] appearance banned [key_name_admin(M)]", 1)
M << "\redYou have been appearance banned by [usr.client.ckey]."
M << "\red The reason is: [reason]"
@@ -886,7 +886,7 @@
msg = job
else
msg += ", [job]"
- notes_add(M.ckey, "Banned from [msg] - [reason]")
+ add_note(M.ckey, "Banned from [msg] - [reason]", null, usr, 0)
message_admins("\blue [key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes", 1)
M << "\redYou have been jobbanned by [usr.client.ckey] from: [msg]."
M << "\red The reason is: [reason]"
@@ -905,8 +905,8 @@
feedback_add_details("ban_job","- [job]")
jobban_fullban(M, job, "[reason]; By [usr.ckey] on [time2text(world.realtime)]")
if(!msg) msg = job
- else msg += ", [job]"
- notes_add(M.ckey, "Banned from [msg] - [reason]")
+ else msg += ", [job]"
+ add_note(M.ckey, "Banned from [msg] - [reason]", null, usr, 0)
message_admins("\blue [key_name_admin(usr)] banned [key_name_admin(M)] from [msg]", 1)
M << "\redYou have been jobbanned by [usr.client.ckey] from: [msg]."
M << "\red The reason is: [reason]"
@@ -956,25 +956,51 @@
message_admins("\blue [key_name_admin(usr)] booted [key_name_admin(M)].", 1)
//M.client = null
del(M.client)
-/*
- //Player Notes
- else if(href_list["notes"])
- var/ckey = href_list["ckey"]
- if(!ckey)
- var/mob/M = locate(href_list["mob"])
- if(ismob(M))
- ckey = M.ckey
- switch(href_list["notes"])
- if("show")
- notes_show(ckey)
- if("add")
- notes_add(ckey,href_list["text"])
- notes_show(ckey)
- if("remove")
- notes_remove(ckey,text2num(href_list["from"]),text2num(href_list["to"]))
- notes_show(ckey)
-*/
+ //Player Notes
+ else if(href_list["addnote"])
+ var/target_ckey = href_list["addnote"]
+ add_note(target_ckey)
+
+ else if(href_list["addnoteempty"])
+ add_note()
+
+ else if(href_list["removenote"])
+ var/note_id = href_list["removenote"]
+ remove_note(note_id)
+
+ else if(href_list["editnote"])
+ var/note_id = href_list["editnote"]
+ edit_note(note_id)
+
+ else if(href_list["shownote"])
+ var/target = href_list["shownote"]
+ show_note(index = target)
+
+ else if(href_list["nonalpha"])
+ var/target = href_list["nonalpha"]
+ target = text2num(target)
+ show_note(index = target)
+
+ else if(href_list["shownoteckey"])
+ var/target_ckey = href_list["shownoteckey"]
+ show_note(target_ckey)
+
+ else if(href_list["notessearch"])
+ var/target = href_list["notessearch"]
+ show_note(index = target)
+
+ else if(href_list["noteedits"])
+ var/note_id = sanitizeSQL("[href_list["noteedits"]]")
+ var/DBQuery/query_noteedits = dbcon.NewQuery("SELECT edits FROM [format_table_name("notes")] WHERE id = '[note_id]'")
+ if(!query_noteedits.Execute())
+ var/err = query_noteedits.ErrorMsg()
+ log_game("SQL ERROR obtaining edits from notes table. Error : \[[err]\]\n")
+ return
+ if(query_noteedits.NextRow())
+ var/edit_log = query_noteedits.item[1]
+ usr << browse(edit_log,"window=noteedits")
+
else if(href_list["removejobban"])
if(!check_rights(R_BAN)) return
@@ -3031,35 +3057,6 @@
src.admincaster_signature = adminscrub(input(usr, "Provide your desired signature", "Network Identity Handler", ""))
src.access_news_network()
- if(href_list["add_player_info"])
- var/key = href_list["add_player_info"]
- var/add = input("Add Player Info") as null|text
- if(!add) return
-
- notes_add(key,add,usr)
- show_player_info(key)
-
- if(href_list["remove_player_info"])
- var/key = href_list["remove_player_info"]
- var/index = text2num(href_list["remove_index"])
-
- notes_del(key, index)
- show_player_info(key)
-
- if(href_list["notes"])
- var/ckey = href_list["ckey"]
- if(!ckey)
- var/mob/M = locate(href_list["mob"])
- if(ismob(M))
- ckey = M.ckey
-
- switch(href_list["notes"])
- if("show")
- show_player_info(ckey)
- if("list")
- PlayerNotesPage(text2num(href_list["index"]))
- return
-
if(href_list["secretsmenu"])
switch(href_list["secretsmenu"])
if("tab")
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index cc97f6193f7..3bd236ee42b 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -282,6 +282,9 @@
winset(src, null, "command=\".configure graphics-hwmode on\"")
log_client_to_db()
+
+ if (config && config.autoconvert_notes)
+ convert_notes_sql(ckey)
send_resources()
diff --git a/config/example/config.txt b/config/example/config.txt
index 1ee86a8a09c..b1ae26f6803 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -271,8 +271,8 @@ EVENT_DELAY_UPPER 15;45;70
## The delay until the first time an event of the given severity runs in minutes.
## Unset setting use the EVENT_DELAY_LOWER and EVENT_DELAY_UPPER values instead.
-# EVENT_CUSTOM_START_MINOR 10;15
-# EVENT_CUSTOM_START_MODERATE 30;45
+#EVENT_CUSTOM_START_MINOR 10;15
+#EVENT_CUSTOM_START_MODERATE 30;45
EVENT_CUSTOM_START_MAJOR 80;100
## Strength of ambient star light. Set to 0 or less to turn off.
@@ -288,4 +288,7 @@ PLAYER_REROUTE_CAP 0
#OVERFLOW_SERVER_URL byond://example.org:1111
## Disable the loading of away missions
-# DISABLE_AWAY_MISSIONS
\ No newline at end of file
+#DISABLE_AWAY_MISSIONS
+
+## Comment this out if you've used the mass conversion sql proc for notes or want to stop converting notes
+AUTOCONVERT_NOTES
\ No newline at end of file
diff --git a/paradise.dme b/paradise.dme
index 12deff3c44e..3024d97fff4 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -55,6 +55,7 @@
#include "code\__HELPERS\timed_alerts.dm"
#include "code\__HELPERS\type2type.dm"
#include "code\__HELPERS\unsorted.dm"
+#include "code\__HELPERS\bygex\bygex.dm"
#include "code\_globalvars\configuration.dm"
#include "code\_globalvars\database.dm"
#include "code\_globalvars\game_modes.dm"
@@ -910,9 +911,9 @@
#include "code\modules\admin\machine_upgrade.dm"
#include "code\modules\admin\NewBan.dm"
#include "code\modules\admin\newbanjob.dm"
-#include "code\modules\admin\player_notes.dm"
#include "code\modules\admin\player_panel.dm"
#include "code\modules\admin\secrets.dm"
+#include "code\modules\admin\sql_notes.dm"
#include "code\modules\admin\topic.dm"
#include "code\modules\admin\ToRban.dm"
#include "code\modules\admin\watchlist.dm"
|