|
|
|
@@ -40,8 +40,8 @@
|
|
|
|
|
for(var/char in repl_chars)
|
|
|
|
|
var/index = findtext(t, char)
|
|
|
|
|
while(index)
|
|
|
|
|
t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index+1)
|
|
|
|
|
index = findtext(t, char, index+1)
|
|
|
|
|
t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index + length(char))
|
|
|
|
|
index = findtext(t, char, index + length(char))
|
|
|
|
|
return t
|
|
|
|
|
|
|
|
|
|
/proc/sanitize_filename(t)
|
|
|
|
@@ -63,22 +63,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Returns null if there is any bad text in the string
|
|
|
|
|
/proc/reject_bad_text(text, max_length=512)
|
|
|
|
|
if(length(text) > max_length)
|
|
|
|
|
return //message too long
|
|
|
|
|
var/non_whitespace = 0
|
|
|
|
|
for(var/i=1, i<=length(text), i++)
|
|
|
|
|
switch(text2ascii(text,i))
|
|
|
|
|
if(62,60,92,47)
|
|
|
|
|
return //rejects the text if it contains these bad characters: <, >, \ or /
|
|
|
|
|
if(127 to 255)
|
|
|
|
|
return //rejects weird letters like �
|
|
|
|
|
/proc/reject_bad_text(text, max_length = 512, ascii_only = TRUE)
|
|
|
|
|
var/char_count = 0
|
|
|
|
|
var/non_whitespace = FALSE
|
|
|
|
|
var/lenbytes = length(text)
|
|
|
|
|
var/char = ""
|
|
|
|
|
for(var/i = 1, i <= lenbytes, i += length(char))
|
|
|
|
|
char = text[i]
|
|
|
|
|
char_count++
|
|
|
|
|
if(char_count > max_length)
|
|
|
|
|
return
|
|
|
|
|
switch(text2ascii(char))
|
|
|
|
|
if(62,60,92,47) // <, >, \, /
|
|
|
|
|
return
|
|
|
|
|
if(0 to 31)
|
|
|
|
|
return //more weird stuff
|
|
|
|
|
return
|
|
|
|
|
if(32)
|
|
|
|
|
continue //whitespace
|
|
|
|
|
if(127 to INFINITY)
|
|
|
|
|
if(ascii_only)
|
|
|
|
|
return
|
|
|
|
|
else
|
|
|
|
|
non_whitespace = 1
|
|
|
|
|
non_whitespace = TRUE
|
|
|
|
|
if(non_whitespace)
|
|
|
|
|
return text //only accepts the text if it has some non-spaces
|
|
|
|
|
|
|
|
|
@@ -101,73 +107,84 @@
|
|
|
|
|
else
|
|
|
|
|
return trim(html_encode(name), max_length)
|
|
|
|
|
|
|
|
|
|
#define NO_CHARS_DETECTED 0
|
|
|
|
|
#define SPACES_DETECTED 1
|
|
|
|
|
#define SYMBOLS_DETECTED 2
|
|
|
|
|
#define NUMBERS_DETECTED 3
|
|
|
|
|
#define LETTERS_DETECTED 4
|
|
|
|
|
|
|
|
|
|
//Filters out undesirable characters from names
|
|
|
|
|
/proc/reject_bad_name(t_in, allow_numbers=0, max_length=MAX_NAME_LEN)
|
|
|
|
|
if(!t_in || length(t_in) > max_length)
|
|
|
|
|
return //Rejects the input if it is null or if it is longer then the max length allowed
|
|
|
|
|
/proc/reject_bad_name(t_in, allow_numbers = FALSE, max_length = MAX_NAME_LEN, ascii_only = TRUE)
|
|
|
|
|
if(!t_in)
|
|
|
|
|
return //Rejects the input if it is null
|
|
|
|
|
|
|
|
|
|
var/number_of_alphanumeric = 0
|
|
|
|
|
var/last_char_group = 0
|
|
|
|
|
var/number_of_alphanumeric = 0
|
|
|
|
|
var/last_char_group = NO_CHARS_DETECTED
|
|
|
|
|
var/t_out = ""
|
|
|
|
|
var/t_len = length(t_in)
|
|
|
|
|
var/charcount = 0
|
|
|
|
|
var/char = ""
|
|
|
|
|
|
|
|
|
|
for(var/i=1, i<=length(t_in), i++)
|
|
|
|
|
var/ascii_char = text2ascii(t_in,i)
|
|
|
|
|
switch(ascii_char)
|
|
|
|
|
|
|
|
|
|
for(var/i = 1, i <= t_len, i += length(char))
|
|
|
|
|
char = t_in[i]
|
|
|
|
|
|
|
|
|
|
switch(text2ascii(char))
|
|
|
|
|
// A .. Z
|
|
|
|
|
if(65 to 90) //Uppercase Letters
|
|
|
|
|
t_out += ascii2text(ascii_char)
|
|
|
|
|
number_of_alphanumeric++
|
|
|
|
|
last_char_group = 4
|
|
|
|
|
last_char_group = LETTERS_DETECTED
|
|
|
|
|
|
|
|
|
|
// a .. z
|
|
|
|
|
if(97 to 122) //Lowercase Letters
|
|
|
|
|
if(last_char_group<2)
|
|
|
|
|
t_out += ascii2text(ascii_char-32) //Force uppercase first character
|
|
|
|
|
else
|
|
|
|
|
t_out += ascii2text(ascii_char)
|
|
|
|
|
if(last_char_group == NO_CHARS_DETECTED || last_char_group == SPACES_DETECTED || last_char_group == SYMBOLS_DETECTED) //start of a word
|
|
|
|
|
char = uppertext(char)
|
|
|
|
|
number_of_alphanumeric++
|
|
|
|
|
last_char_group = 4
|
|
|
|
|
last_char_group = LETTERS_DETECTED
|
|
|
|
|
|
|
|
|
|
// 0 .. 9
|
|
|
|
|
if(48 to 57) //Numbers
|
|
|
|
|
if(!last_char_group)
|
|
|
|
|
continue //suppress at start of string
|
|
|
|
|
if(!allow_numbers)
|
|
|
|
|
if(last_char_group == NO_CHARS_DETECTED || !allow_numbers) //suppress at start of string
|
|
|
|
|
continue
|
|
|
|
|
t_out += ascii2text(ascii_char)
|
|
|
|
|
number_of_alphanumeric++
|
|
|
|
|
last_char_group = 3
|
|
|
|
|
last_char_group = NUMBERS_DETECTED
|
|
|
|
|
|
|
|
|
|
// ' - .
|
|
|
|
|
if(39,45,46) //Common name punctuation
|
|
|
|
|
if(!last_char_group)
|
|
|
|
|
if(last_char_group == NO_CHARS_DETECTED)
|
|
|
|
|
continue
|
|
|
|
|
t_out += ascii2text(ascii_char)
|
|
|
|
|
last_char_group = 2
|
|
|
|
|
last_char_group = SYMBOLS_DETECTED
|
|
|
|
|
|
|
|
|
|
// ~ | @ : # $ % & * +
|
|
|
|
|
if(126,124,64,58,35,36,37,38,42,43) //Other symbols that we'll allow (mainly for AI)
|
|
|
|
|
if(!last_char_group)
|
|
|
|
|
continue //suppress at start of string
|
|
|
|
|
if(!allow_numbers)
|
|
|
|
|
if(last_char_group == NO_CHARS_DETECTED || !allow_numbers) //suppress at start of string
|
|
|
|
|
continue
|
|
|
|
|
t_out += ascii2text(ascii_char)
|
|
|
|
|
last_char_group = 2
|
|
|
|
|
last_char_group = SYMBOLS_DETECTED
|
|
|
|
|
|
|
|
|
|
//Space
|
|
|
|
|
if(32)
|
|
|
|
|
if(last_char_group <= 1)
|
|
|
|
|
continue //suppress double-spaces and spaces at start of string
|
|
|
|
|
t_out += ascii2text(ascii_char)
|
|
|
|
|
last_char_group = 1
|
|
|
|
|
if(last_char_group == NO_CHARS_DETECTED || last_char_group == SPACES_DETECTED) //suppress double-spaces and spaces at start of string
|
|
|
|
|
continue
|
|
|
|
|
last_char_group = SPACES_DETECTED
|
|
|
|
|
|
|
|
|
|
if(127 to INFINITY)
|
|
|
|
|
if(ascii_only)
|
|
|
|
|
continue
|
|
|
|
|
last_char_group = SYMBOLS_DETECTED //for now, we'll treat all non-ascii characters like symbols even though most are letters
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
return
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
t_out += char
|
|
|
|
|
charcount++
|
|
|
|
|
if(charcount >= max_length)
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if(number_of_alphanumeric < 2)
|
|
|
|
|
return //protects against tiny names like "A" and also names like "' ' ' ' ' ' ' '"
|
|
|
|
|
|
|
|
|
|
if(last_char_group == 1)
|
|
|
|
|
t_out = copytext(t_out,1,length(t_out)) //removes the last character (in this case a space)
|
|
|
|
|
if(last_char_group == SPACES_DETECTED)
|
|
|
|
|
t_out = copytext_char(t_out, 1, -1) //removes the last character (in this case a space)
|
|
|
|
|
|
|
|
|
|
for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai")) //prevents these common metagamey names
|
|
|
|
|
if(cmptext(t_out,bad_name))
|
|
|
|
@@ -175,6 +192,11 @@
|
|
|
|
|
|
|
|
|
|
return t_out
|
|
|
|
|
|
|
|
|
|
#undef NO_CHARS_DETECTED
|
|
|
|
|
#undef SPACES_DETECTED
|
|
|
|
|
#undef NUMBERS_DETECTED
|
|
|
|
|
#undef LETTERS_DETECTED
|
|
|
|
|
|
|
|
|
|
//html_encode helper proc that returns the smallest non null of two numbers
|
|
|
|
|
//or 0 if they're both null (needed because of findtext returning 0 when a value is not present)
|
|
|
|
|
/proc/non_zero_min(a, b)
|
|
|
|
@@ -184,39 +206,6 @@
|
|
|
|
|
return a
|
|
|
|
|
return (a < b ? a : b)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Text searches
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//Checks the beginning of a string for a specified sub-string
|
|
|
|
|
//Returns the position of the substring or 0 if it was not found
|
|
|
|
|
/proc/dd_hasprefix(text, prefix)
|
|
|
|
|
var/start = 1
|
|
|
|
|
var/end = length(prefix) + 1
|
|
|
|
|
return findtext(text, prefix, start, end)
|
|
|
|
|
|
|
|
|
|
//Checks the beginning of a string for a specified sub-string. This proc is case sensitive
|
|
|
|
|
//Returns the position of the substring or 0 if it was not found
|
|
|
|
|
/proc/dd_hasprefix_case(text, prefix)
|
|
|
|
|
var/start = 1
|
|
|
|
|
var/end = length(prefix) + 1
|
|
|
|
|
return findtextEx(text, prefix, start, end)
|
|
|
|
|
|
|
|
|
|
//Checks the end of a string for a specified substring.
|
|
|
|
|
//Returns the position of the substring or 0 if it was not found
|
|
|
|
|
/proc/dd_hassuffix(text, suffix)
|
|
|
|
|
var/start = length(text) - length(suffix)
|
|
|
|
|
if(start)
|
|
|
|
|
return findtext(text, suffix, start, null)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
//Checks the end of a string for a specified substring. This proc is case sensitive
|
|
|
|
|
//Returns the position of the substring or 0 if it was not found
|
|
|
|
|
/proc/dd_hassuffix_case(text, suffix)
|
|
|
|
|
var/start = length(text) - length(suffix)
|
|
|
|
|
if(start)
|
|
|
|
|
return findtextEx(text, suffix, start, null)
|
|
|
|
|
|
|
|
|
|
//Checks if any of a given list of needles is in the haystack
|
|
|
|
|
/proc/text_in_list(haystack, list/needle_list, start=1, end=0)
|
|
|
|
|
for(var/needle in needle_list)
|
|
|
|
@@ -231,23 +220,19 @@
|
|
|
|
|
return 1
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
//Adds 'u' number of zeros ahead of the text 't'
|
|
|
|
|
/proc/add_zero(t, u)
|
|
|
|
|
while (length(t) < u)
|
|
|
|
|
t = "0[t]"
|
|
|
|
|
return t
|
|
|
|
|
//Adds 'char' ahead of 'text' until there are 'count' characters total
|
|
|
|
|
/proc/add_leading(text, count, char = " ")
|
|
|
|
|
text = "[text]"
|
|
|
|
|
var/charcount = count - length_char(text)
|
|
|
|
|
var/list/chars_to_add[max(charcount + 1, 0)]
|
|
|
|
|
return jointext(chars_to_add, char) + text
|
|
|
|
|
|
|
|
|
|
//Adds 'u' number of spaces ahead of the text 't'
|
|
|
|
|
/proc/add_lspace(t, u)
|
|
|
|
|
while(length(t) < u)
|
|
|
|
|
t = " [t]"
|
|
|
|
|
return t
|
|
|
|
|
|
|
|
|
|
//Adds 'u' number of spaces behind the text 't'
|
|
|
|
|
/proc/add_tspace(t, u)
|
|
|
|
|
while(length(t) < u)
|
|
|
|
|
t = "[t] "
|
|
|
|
|
return t
|
|
|
|
|
//Adds 'char' behind 'text' until there are 'count' characters total
|
|
|
|
|
/proc/add_trailing(text, count, char = " ")
|
|
|
|
|
text = "[text]"
|
|
|
|
|
var/charcount = count - length_char(text)
|
|
|
|
|
var/list/chars_to_add[max(charcount + 1, 0)]
|
|
|
|
|
return text + jointext(chars_to_add, char)
|
|
|
|
|
|
|
|
|
|
//Returns a string with reserved characters and spaces before the first letter removed
|
|
|
|
|
/proc/trim_left(text)
|
|
|
|
@@ -267,57 +252,41 @@
|
|
|
|
|
//Returns a string with reserved characters and spaces before the first word and after the last word removed.
|
|
|
|
|
/proc/trim(text, max_length)
|
|
|
|
|
if(max_length)
|
|
|
|
|
text = copytext(text, 1, max_length)
|
|
|
|
|
text = copytext_char(text, 1, max_length)
|
|
|
|
|
return trim_left(trim_right(text))
|
|
|
|
|
|
|
|
|
|
//Returns a string with the first element of the string capitalized.
|
|
|
|
|
/proc/capitalize(t as text)
|
|
|
|
|
return uppertext(copytext(t, 1, 2)) + copytext(t, 2)
|
|
|
|
|
|
|
|
|
|
//Centers text by adding spaces to either side of the string.
|
|
|
|
|
/proc/dd_centertext(message, length)
|
|
|
|
|
var/new_message = message
|
|
|
|
|
var/size = length(message)
|
|
|
|
|
var/delta = length - size
|
|
|
|
|
if(size == length)
|
|
|
|
|
return new_message
|
|
|
|
|
if(size > length)
|
|
|
|
|
return copytext(new_message, 1, length + 1)
|
|
|
|
|
if(delta == 1)
|
|
|
|
|
return new_message + " "
|
|
|
|
|
if(delta % 2)
|
|
|
|
|
new_message = " " + new_message
|
|
|
|
|
delta--
|
|
|
|
|
var/spaces = add_lspace("",delta/2-1)
|
|
|
|
|
return spaces + new_message + spaces
|
|
|
|
|
|
|
|
|
|
//Limits the length of the text. Note: MAX_MESSAGE_LEN and MAX_NAME_LEN are widely used for this purpose
|
|
|
|
|
/proc/dd_limittext(message, length)
|
|
|
|
|
var/size = length(message)
|
|
|
|
|
if(size <= length)
|
|
|
|
|
return message
|
|
|
|
|
return copytext(message, 1, length + 1)
|
|
|
|
|
|
|
|
|
|
. = t
|
|
|
|
|
if(t)
|
|
|
|
|
. = t[1]
|
|
|
|
|
return uppertext(.) + copytext(t, 1 + length(.))
|
|
|
|
|
|
|
|
|
|
/proc/stringmerge(text,compare,replace = "*")
|
|
|
|
|
//This proc fills in all spaces with the "replace" var (* by default) with whatever
|
|
|
|
|
//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(length(text) != length(compare))
|
|
|
|
|
return 0
|
|
|
|
|
for(var/i = 1, i < length(text), i++)
|
|
|
|
|
var/a = copytext(text,i,i+1)
|
|
|
|
|
var/b = copytext(compare,i,i+1)
|
|
|
|
|
var/text_it = 1 //iterators
|
|
|
|
|
var/comp_it = 1
|
|
|
|
|
var/newtext_it = 1
|
|
|
|
|
var/text_length = length(text)
|
|
|
|
|
var/comp_length = length(compare)
|
|
|
|
|
while(comp_it <= comp_length && text_it <= text_length)
|
|
|
|
|
var/a = text[text_it]
|
|
|
|
|
var/b = compare[comp_it]
|
|
|
|
|
//if it isn't both the same letter, or if they are both the replacement character
|
|
|
|
|
//(no way to know what it was supposed to be)
|
|
|
|
|
if(a != b)
|
|
|
|
|
if(a == replace) //if A is the replacement char
|
|
|
|
|
newtext = copytext(newtext,1,i) + b + copytext(newtext, i+1)
|
|
|
|
|
newtext = copytext(newtext, 1, newtext_it) + b + copytext(newtext, newtext_it + length(newtext[newtext_it]))
|
|
|
|
|
else if(b == replace) //if B is the replacement char
|
|
|
|
|
newtext = copytext(newtext,1,i) + a + copytext(newtext, i+1)
|
|
|
|
|
newtext = copytext(newtext, 1, newtext_it) + a + copytext(newtext, newtext_it + length(newtext[newtext_it]))
|
|
|
|
|
else //The lists disagree, Uh-oh!
|
|
|
|
|
return 0
|
|
|
|
|
text_it += length(a)
|
|
|
|
|
comp_it += length(b)
|
|
|
|
|
newtext_it += length(newtext[newtext_it])
|
|
|
|
|
return newtext
|
|
|
|
|
|
|
|
|
|
/proc/stringpercent(text,character = "*")
|
|
|
|
@@ -326,16 +295,21 @@
|
|
|
|
|
if(!text || !character)
|
|
|
|
|
return 0
|
|
|
|
|
var/count = 0
|
|
|
|
|
for(var/i = 1, i <= length(text), i++)
|
|
|
|
|
var/a = copytext(text,i,i+1)
|
|
|
|
|
var/lentext = length(text)
|
|
|
|
|
var/a = ""
|
|
|
|
|
for(var/i = 1, i <= lentext, i += length(a))
|
|
|
|
|
a = text[i]
|
|
|
|
|
if(a == character)
|
|
|
|
|
count++
|
|
|
|
|
return count
|
|
|
|
|
|
|
|
|
|
/proc/reverse_text(text = "")
|
|
|
|
|
var/new_text = ""
|
|
|
|
|
for(var/i = length(text); i > 0; i--)
|
|
|
|
|
new_text += copytext(text, i, i+1)
|
|
|
|
|
var/lentext = length(text)
|
|
|
|
|
var/letter = ""
|
|
|
|
|
for(var/i = 1, i <= lentext, i += length(letter))
|
|
|
|
|
letter = text[i]
|
|
|
|
|
new_text = letter + new_text
|
|
|
|
|
return new_text
|
|
|
|
|
|
|
|
|
|
GLOBAL_LIST_INIT(zero_character_only, list("0"))
|
|
|
|
@@ -358,15 +332,6 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
|
|
|
|
/proc/random_color()
|
|
|
|
|
return random_string(6, GLOB.hex_characters)
|
|
|
|
|
|
|
|
|
|
/proc/add_zero2(t, u)
|
|
|
|
|
var/temp1
|
|
|
|
|
while (length(t) < u)
|
|
|
|
|
t = "0[t]"
|
|
|
|
|
temp1 = t
|
|
|
|
|
if (length(t) > u)
|
|
|
|
|
temp1 = copytext(t,2,u+1)
|
|
|
|
|
return temp1
|
|
|
|
|
|
|
|
|
|
//merges non-null characters (3rd argument) from "from" into "into". Returns result
|
|
|
|
|
//e.g. into = "Hello World"
|
|
|
|
|
// from = "Seeya______"
|
|
|
|
@@ -379,41 +344,48 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
|
|
|
|
into = ""
|
|
|
|
|
if(!istext(from))
|
|
|
|
|
from = ""
|
|
|
|
|
var/null_ascii = istext(null_char) ? text2ascii(null_char,1) : null_char
|
|
|
|
|
|
|
|
|
|
var/previous = 0
|
|
|
|
|
var/null_ascii = istext(null_char) ? text2ascii(null_char, 1) : null_char
|
|
|
|
|
var/copying_into = FALSE
|
|
|
|
|
var/char = ""
|
|
|
|
|
var/start = 1
|
|
|
|
|
var/end = length(into) + 1
|
|
|
|
|
|
|
|
|
|
for(var/i=1, i<end, i++)
|
|
|
|
|
var/ascii = text2ascii(from, i)
|
|
|
|
|
if(ascii == null_ascii)
|
|
|
|
|
if(previous != 1)
|
|
|
|
|
. += copytext(from, start, i)
|
|
|
|
|
start = i
|
|
|
|
|
previous = 1
|
|
|
|
|
var/end_from = length(from)
|
|
|
|
|
var/end_into = length(into)
|
|
|
|
|
var/into_it = 1
|
|
|
|
|
var/from_it = 1
|
|
|
|
|
while(from_it <= end_from && into_it <= end_into)
|
|
|
|
|
char = from[from_it]
|
|
|
|
|
if(text2ascii(char) == null_ascii)
|
|
|
|
|
if(!copying_into)
|
|
|
|
|
. += copytext(from, start, from_it)
|
|
|
|
|
start = into_it
|
|
|
|
|
copying_into = TRUE
|
|
|
|
|
else
|
|
|
|
|
if(previous != 0)
|
|
|
|
|
. += copytext(into, start, i)
|
|
|
|
|
start = i
|
|
|
|
|
previous = 0
|
|
|
|
|
if(copying_into)
|
|
|
|
|
. += copytext(into, start, into_it)
|
|
|
|
|
start = from_it
|
|
|
|
|
copying_into = FALSE
|
|
|
|
|
into_it += length(into[into_it])
|
|
|
|
|
from_it += length(char)
|
|
|
|
|
|
|
|
|
|
if(previous == 0)
|
|
|
|
|
. += copytext(from, start, end)
|
|
|
|
|
if(copying_into)
|
|
|
|
|
. += copytext(into, start)
|
|
|
|
|
else
|
|
|
|
|
. += copytext(into, start, end)
|
|
|
|
|
. += copytext(from, start, from_it)
|
|
|
|
|
if(into_it <= end_into)
|
|
|
|
|
. += copytext(into, into_it)
|
|
|
|
|
|
|
|
|
|
//finds the first occurrence of one of the characters from needles argument inside haystack
|
|
|
|
|
//it may appear this can be optimised, but it really can't. findtext() is so much faster than anything you can do in byondcode.
|
|
|
|
|
//stupid byond :(
|
|
|
|
|
/proc/findchar(haystack, needles, start=1, end=0)
|
|
|
|
|
var/temp
|
|
|
|
|
var/char = ""
|
|
|
|
|
var/len = length(needles)
|
|
|
|
|
for(var/i=1, i<=len, i++)
|
|
|
|
|
temp = findtextEx(haystack, ascii2text(text2ascii(needles,i)), start, end) //Note: ascii2text(text2ascii) is faster than copytext()
|
|
|
|
|
if(temp)
|
|
|
|
|
end = temp
|
|
|
|
|
return end
|
|
|
|
|
for(var/i = 1, i <= len, i += length(char))
|
|
|
|
|
char = needles[i]
|
|
|
|
|
. = findtextEx(haystack, char, start, end)
|
|
|
|
|
if(.)
|
|
|
|
|
return
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
/proc/parsemarkdown_basic_step1(t, limited=FALSE)
|
|
|
|
|
if(length(t) <= 0)
|
|
|
|
@@ -571,23 +543,28 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
|
|
|
|
|
|
|
|
|
return t
|
|
|
|
|
|
|
|
|
|
#define string2charlist(string) (splittext(string, regex("(.)")) - splittext(string, ""))
|
|
|
|
|
/proc/text2charlist(text)
|
|
|
|
|
var/char = ""
|
|
|
|
|
var/lentext = length(text)
|
|
|
|
|
. = list()
|
|
|
|
|
for(var/i = 1, i <= lentext, i += length(char))
|
|
|
|
|
char = text[i]
|
|
|
|
|
. += char
|
|
|
|
|
|
|
|
|
|
/proc/rot13(text = "")
|
|
|
|
|
var/list/textlist = string2charlist(text)
|
|
|
|
|
var/list/result = list()
|
|
|
|
|
for(var/c in textlist)
|
|
|
|
|
var/ca = text2ascii(c)
|
|
|
|
|
if(ca >= text2ascii("a") && ca <= text2ascii("m"))
|
|
|
|
|
ca += 13
|
|
|
|
|
else if(ca >= text2ascii("n") && ca <= text2ascii("z"))
|
|
|
|
|
ca -= 13
|
|
|
|
|
else if(ca >= text2ascii("A") && ca <= text2ascii("M"))
|
|
|
|
|
ca += 13
|
|
|
|
|
else if(ca >= text2ascii("N") && ca <= text2ascii("Z"))
|
|
|
|
|
ca -= 13
|
|
|
|
|
result += ascii2text(ca)
|
|
|
|
|
return jointext(result, "")
|
|
|
|
|
var/lentext = length(text)
|
|
|
|
|
var/char = ""
|
|
|
|
|
var/ascii = 0
|
|
|
|
|
. = ""
|
|
|
|
|
for(var/i = 1, i <= lentext, i += length(char))
|
|
|
|
|
char = text[i]
|
|
|
|
|
ascii = text2ascii(char)
|
|
|
|
|
switch(ascii)
|
|
|
|
|
if(65 to 77, 97 to 109) //A to M, a to m
|
|
|
|
|
ascii += 13
|
|
|
|
|
if(78 to 90, 110 to 122) //N to Z, n to z
|
|
|
|
|
ascii -= 13
|
|
|
|
|
. += ascii2text(ascii)
|
|
|
|
|
|
|
|
|
|
//Takes a list of values, sanitizes it down for readability and character count,
|
|
|
|
|
//then exports it as a json file at data/npc_saves/[filename].json.
|
|
|
|
@@ -599,7 +576,8 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
//Regular expressions are, as usual, absolute magic
|
|
|
|
|
var/regex/all_invalid_symbols = new("\[^ -~]+")
|
|
|
|
|
//Any characters outside of 32 (space) to 126 (~) because treating things you don't understand as "magic" is really stupid
|
|
|
|
|
var/regex/all_invalid_symbols = new(@"[^ -~]{1}")
|
|
|
|
|
|
|
|
|
|
var/list/accepted = list()
|
|
|
|
|
for(var/string in proposed)
|
|
|
|
@@ -607,34 +585,44 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
|
|
|
|
continue
|
|
|
|
|
var/buffer = ""
|
|
|
|
|
var/early_culling = TRUE
|
|
|
|
|
for(var/pos = 1, pos <= length(string), pos++)
|
|
|
|
|
var/let = copytext(string, pos, (pos + 1) % length(string))
|
|
|
|
|
if(early_culling && !findtext(let,GLOB.is_alphanumeric))
|
|
|
|
|
var/lentext = length(string)
|
|
|
|
|
var/let = ""
|
|
|
|
|
|
|
|
|
|
for(var/pos = 1, pos <= lentext, pos += length(let))
|
|
|
|
|
let = string[pos]
|
|
|
|
|
if(!findtext(let, GLOB.is_alphanumeric))
|
|
|
|
|
continue
|
|
|
|
|
early_culling = FALSE
|
|
|
|
|
buffer += let
|
|
|
|
|
if(!findtext(buffer,GLOB.is_alphanumeric))
|
|
|
|
|
buffer = copytext(string, pos)
|
|
|
|
|
break
|
|
|
|
|
if(early_culling) //Never found any letters! Bail!
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
var/punctbuffer = ""
|
|
|
|
|
var/cutoff = length(buffer)
|
|
|
|
|
for(var/pos = length(buffer), pos >= 0, pos--)
|
|
|
|
|
var/let = copytext(buffer, pos, (pos + 1) % length(buffer))
|
|
|
|
|
if(findtext(let,GLOB.is_alphanumeric))
|
|
|
|
|
var/cutoff = 0
|
|
|
|
|
lentext = length_char(buffer)
|
|
|
|
|
for(var/pos = 1, pos <= lentext, pos++)
|
|
|
|
|
let = copytext_char(buffer, -pos, -pos + 1)
|
|
|
|
|
if(!findtext(let, GLOB.is_punctuation)) //This won't handle things like Nyaaaa!~ but that's fine
|
|
|
|
|
break
|
|
|
|
|
if(findtext(let,GLOB.is_punctuation))
|
|
|
|
|
punctbuffer = let + punctbuffer //Note this isn't the same thing as using +=
|
|
|
|
|
cutoff = pos
|
|
|
|
|
punctbuffer += let
|
|
|
|
|
cutoff += length(let)
|
|
|
|
|
if(punctbuffer) //We clip down excessive punctuation to get the letter count lower and reduce repeats. It's not perfect but it helps.
|
|
|
|
|
var/exclaim = FALSE
|
|
|
|
|
var/question = FALSE
|
|
|
|
|
var/periods = 0
|
|
|
|
|
for(var/pos = length(punctbuffer), pos >= 0, pos--)
|
|
|
|
|
var/punct = copytext(punctbuffer, pos, (pos + 1) % length(punctbuffer))
|
|
|
|
|
if(!exclaim && findtext(punct,"!"))
|
|
|
|
|
lentext = length(punctbuffer)
|
|
|
|
|
for(var/pos = 1, pos <= lentext, pos += length(let))
|
|
|
|
|
let = punctbuffer[pos]
|
|
|
|
|
if(!exclaim && findtext(let, "!"))
|
|
|
|
|
exclaim = TRUE
|
|
|
|
|
if(!question && findtext(punct,"?"))
|
|
|
|
|
if(question)
|
|
|
|
|
break
|
|
|
|
|
if(!question && findtext(let, "?"))
|
|
|
|
|
question = TRUE
|
|
|
|
|
if(!exclaim && !question && findtext(punct,"."))
|
|
|
|
|
if(exclaim)
|
|
|
|
|
break
|
|
|
|
|
if(!exclaim && !question && findtext(let, ".")) //? and ! take priority over periods
|
|
|
|
|
periods += 1
|
|
|
|
|
if(exclaim)
|
|
|
|
|
if(question)
|
|
|
|
@@ -643,15 +631,13 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
|
|
|
|
punctbuffer = "!"
|
|
|
|
|
else if(question)
|
|
|
|
|
punctbuffer = "?"
|
|
|
|
|
else if(periods)
|
|
|
|
|
if(periods > 1)
|
|
|
|
|
punctbuffer = "..."
|
|
|
|
|
else
|
|
|
|
|
punctbuffer = "" //Grammer nazis be damned
|
|
|
|
|
buffer = copytext(buffer, 1, cutoff) + punctbuffer
|
|
|
|
|
if(!findtext(buffer,GLOB.is_alphanumeric))
|
|
|
|
|
continue
|
|
|
|
|
if(!buffer || length(buffer) > 280 || length(buffer) <= cullshort || buffer in accepted)
|
|
|
|
|
else if(periods > 1)
|
|
|
|
|
punctbuffer = "..."
|
|
|
|
|
else
|
|
|
|
|
punctbuffer = "" //Grammer nazis be damned
|
|
|
|
|
buffer = copytext(buffer, 1, -cutoff) + punctbuffer
|
|
|
|
|
lentext = length_char(buffer)
|
|
|
|
|
if(!buffer || lentext > 280 || lentext <= cullshort || (buffer in accepted))
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
accepted += buffer
|
|
|
|
@@ -688,7 +674,7 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
|
|
|
|
|
|
|
|
|
var/leng = length(string)
|
|
|
|
|
|
|
|
|
|
var/next_space = findtext(string, " ", next_backslash + 1)
|
|
|
|
|
var/next_space = findtext(string, " ", next_backslash + length(string[next_backslash]))
|
|
|
|
|
if(!next_space)
|
|
|
|
|
next_space = leng - next_backslash
|
|
|
|
|
|
|
|
|
@@ -696,8 +682,8 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
|
|
|
|
return string
|
|
|
|
|
|
|
|
|
|
var/base = next_backslash == 1 ? "" : copytext(string, 1, next_backslash)
|
|
|
|
|
var/macro = lowertext(copytext(string, next_backslash + 1, next_space))
|
|
|
|
|
var/rest = next_backslash > leng ? "" : copytext(string, next_space + 1)
|
|
|
|
|
var/macro = lowertext(copytext(string, next_backslash + length(string[next_space]), next_space))
|
|
|
|
|
var/rest = next_backslash > leng ? "" : copytext(string, next_space + length(string[next_space]))
|
|
|
|
|
|
|
|
|
|
//See https://secure.byond.com/docs/ref/info.html#/DM/text/macros
|
|
|
|
|
switch(macro)
|
|
|
|
@@ -769,28 +755,24 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
|
|
|
|
return "[number]\th"
|
|
|
|
|
|
|
|
|
|
/proc/unintelligize(message)
|
|
|
|
|
var/prefix=copytext(message,1,2)
|
|
|
|
|
var/regex/word_boundaries = regex(@"\b[\S]+\b", "g")
|
|
|
|
|
var/prefix = message[1]
|
|
|
|
|
if(prefix == ";")
|
|
|
|
|
message = copytext(message,2)
|
|
|
|
|
else if(prefix in list(":","#"))
|
|
|
|
|
prefix += copytext(message,2,3)
|
|
|
|
|
message = copytext(message,3)
|
|
|
|
|
message = copytext(message, 1 + length(prefix))
|
|
|
|
|
else if(prefix in list(":", "#"))
|
|
|
|
|
prefix += message[1 + length(prefix)]
|
|
|
|
|
message = copytext(message, length(prefix))
|
|
|
|
|
else
|
|
|
|
|
prefix=""
|
|
|
|
|
prefix = ""
|
|
|
|
|
|
|
|
|
|
var/list/words = splittext(message," ")
|
|
|
|
|
var/list/rearranged = list()
|
|
|
|
|
for(var/i=1;i<=words.len;i++)
|
|
|
|
|
var/cword = pick(words)
|
|
|
|
|
words.Remove(cword)
|
|
|
|
|
var/suffix = copytext(cword,length(cword)-1,length(cword))
|
|
|
|
|
while(length(cword)>0 && suffix in list(".",",",";","!",":","?"))
|
|
|
|
|
cword = copytext(cword,1 ,length(cword)-1)
|
|
|
|
|
suffix = copytext(cword,length(cword)-1,length(cword) )
|
|
|
|
|
while(word_boundaries.Find(message))
|
|
|
|
|
var/cword = word_boundaries.match
|
|
|
|
|
if(length(cword))
|
|
|
|
|
rearranged += cword
|
|
|
|
|
message = "[prefix][jointext(rearranged," ")]"
|
|
|
|
|
. = message
|
|
|
|
|
shuffle_inplace(rearranged)
|
|
|
|
|
return "[prefix][jointext(rearranged, " ")]"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define is_alpha(X) ((text2ascii(X) <= 122) && (text2ascii(X) >= 97))
|
|
|
|
|
#define is_digit(X) ((length(X) == 1) && (length(text2num(X)) == 1))
|