Merge pull request #147 from Tastyfish/master

coats, changeling, piano, also admins can delete books, paper/books more robust against dynamic content, custom votes
This commit is contained in:
Albert Iordache
2011-12-27 04:26:51 -08:00
13 changed files with 398 additions and 116 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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 << "<B>The current game mode is - Changeling!</B>"
@@ -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)

View File

@@ -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))

View File

@@ -239,9 +239,10 @@
return
// check for exploits
if(findtext(t, "<script") != 0 || findtext(t, "<frame") != 0 || findtext(t, "<iframe") != 0 || findtext(t, "<input") != 0 || findtext(t, "<button") != 0 || findtext(t, "<a") != 0)
user << "\blue You think to yourself, \"Hm.. this is only paper...\""
return
for(var/tag in paper_blacklist)
if(findtext(t,"<"+tag))
user << "\blue You think to yourself, \"Hm.. this is only paper...\""
return
src.dat = t
if("Author")

View File

@@ -1,7 +1,8 @@
/datum/song
var
name = "Untitled"
lines[] = list()
list/lines = new()
tempo = 5
/obj/structure/device/piano
name = "space piano"
@@ -12,10 +13,12 @@
var
datum/song/song
playing = 0
tempo = 5
help = 0
edit = 1
proc
playnote(var/note as text)
//world << "Note: [note]"
var/soundfile
/*BYOND loads resource files at compile time if they are ''. This means you can't really manipulate them dynamically.
Tried doing it dynamically at first but its more trouble than its worth. Would have saved many lines tho.*/
@@ -361,90 +364,168 @@
else
return
for(var/mob/M in range(15, src))
for(var/mob/M in hearers(15, src))
M << sound(soundfile)
playsong()
var/cur_oct[7]
var/cur_acc[7]
for(var/i = 1 to 7)
cur_oct[i] = "3"
cur_acc[i] = "n"
for(var/line in song.lines)
for(var/i = 1, i <= length(line), i+=4)//i starts as 1, or beggining of list. Goes up by 4, skipping every fourth character.
if(!playing)//If the piano is playing and you don't want it playing, this will stop the proc.
return
var/currentnote = copytext(line, i, i+3)
playnote(currentnote)
sleep(tempo)
//world << line
for(var/beat in dd_text2list(lowertext(line), ","))
//world << "beat: [beat]"
var/list/notes = dd_text2list(beat, "/")
for(var/note in dd_text2list(notes[1], "-"))
//world << "note: [note]"
if(!playing)//If the piano is playing and you don't want it playing, this will stop the proc.
return
if(lentext(note) == 0)
continue
//world << "Parse: [copytext(note,1,2)]"
var/cur_note = text2ascii(note) - 96
if(cur_note < 1 || cur_note > 7)
continue
for(var/i=2 to lentext(note))
var/ni = copytext(note,i,i+1)
if(!text2num(ni))
if(ni == "#" || ni == "b")
cur_acc[cur_note] = ni
else if(ni == "s")
cur_acc[cur_note] = "#" // so shift is never required
else
cur_oct[cur_note] = ni
playnote(uppertext(copytext(note,1,2)) + cur_acc[cur_note] + cur_oct[cur_note])
if(notes.len >= 2 && text2num(notes[2]))
sleep(song.tempo / text2num(notes[2]))
else
sleep(song.tempo)
playing = 0
attack_hand(var/mob/user as mob)
usr.machine = src
var/dat = "<HEAD><TITLE>Piano</TITLE></HEAD><BODY>\n <META HTTP-EQUIV='Refresh' CONTENT='10'>"
var/calctempo = (10/tempo)*60
dat += "Tempo : [calctempo] BPM (<A href='?src=\ref[src];choice=lowertempo'>-</A>/<A href='?src=\ref[src];choice=raisetempo'>+</A>)"
dat += "<A href='?src=\ref[src];choice=newsong'>(Start a New Song)</A><br>"
var/dat = "<HEAD><TITLE>Piano</TITLE></HEAD><BODY>"
if(song)
var/linecount = 0
for(var/line in song.lines)
linecount += 1
dat += "Bar [linecount]: [line]<br>"//<A href='?src=\ref[src];deletebar=[linecount]'>(Delete bar)</A><br>" // TODO: Replace delimeters with spaces, clean up display
dat += "<A href='?src=\ref[src];choice=newbar'>(Write a new bar)</A><br>"
if(song.lines.len > 0 && !(playing))
dat += "<A href='?src=\ref[src];choice=play'>(Play song)</A><br>"
dat += "<A href='?src=\ref[src];play=1'>Play Song</A><BR><BR>"
if(playing)
dat += "<A href='?src=\ref[src];choice=stop'>(Stop playing)</A><br>"
dat += {"
<br><br>
Bars are a series of notes separated by asterisks (*) or anything else you want to put there.<br>
Just know that every fourth character will act as a stop, delaying the next note by tempo.<br>
<br>
Notes are played by the names of the note, the accidental, then the octave number.<br>
Example: <i>An3*Bn3*Cn3*Dn3*En3*Fn3*Gn3</i> will play a scale.<br>
Chords can be played simply by listing more than one note before a pause: <i>AB*CD*EF*GA</i><br>
<br>
Bars may be up to 30 characters (including pauses).<br>
A song may only contain up to 10 bars.<br>
"}
user << browse(dat, "window=piano")
dat += "<A href='?src=\ref[src];stop=1'>Stop Playing</A><BR><BR>"
if(!edit)
dat += "<A href='?src=\ref[src];edit=2'>Show Editer</A><BR><BR>"
else
dat += "<A href='?src=\ref[src];edit=1'>Hide Editer</A><BR>"
dat += "<A href='?src=\ref[src];newsong=1'>Start a New Song</A><BR>"
dat += "<A href='?src=\ref[src];import=1'>Import a Song</A><BR><BR>"
if(song)
var/calctempo = (10/song.tempo)*60
dat += "Tempo : <A href='?src=\ref[src];tempo=10'>-</A><A href='?src=\ref[src];tempo=1'>-</A> [calctempo] BPM <A href='?src=\ref[src];tempo=-1'>+</A><A href='?src=\ref[src];tempo=-10'>+</A><BR><BR>"
var/linecount = 0
for(var/line in song.lines)
linecount += 1
dat += "Line [linecount]: [line] <A href='?src=\ref[src];deleteline=[linecount]'>Delete Line</A> <A href='?src=\ref[src];modifyline=[linecount]'>Modify Line</A><BR>"
dat += "<A href='?src=\ref[src];newline=1'>Add Line</A><BR><BR>"
if(help)
dat += "<A href='?src=\ref[src];help=1'>Hide Help</A><BR>"
dat += {"
Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).<br>
Every note in a chord will play together, with chord timed by the tempo.<br>
<br>
Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.<br>
By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.<br>
Example: <i>C,D,E,F,G,A,B</i> will play a C major scale.<br>
After a note has an accidental placed, it will be remembered: <i>C,C4,C,C3</i> is C3,C4,C4,C3</i><br>
Chords can be played simply by seperating each note with a hyphon: <i>A-C#,Cn-E,E-G#,Gn-B</i><br>
A pause may be denoted by an empty chord: <i>C,E,,C,G</i><br>
To make a chord be a different time, end it with /x, where the chord length will be length<br>
defined by tempo / x: <i>C,G/2,E/4</i><br>
Combined, an example is: <i>E-E4/4,/2,G#/8,B/8,E3-E4/4</i>
<br>
Lines may be up to 50 characters.<br>
A song may only contain up to 50 lines.<br>
"}
else
dat += "<A href='?src=\ref[src];help=2'>Show Help</A><BR>"
dat += "</BODY></HTML>"
user << browse(dat, "window=piano;size=700x300")
onclose(user, "piano")
Topic(href, href_list)
//You need some safety checks here. Where is the person located, etc.
switch(href_list["choice"])
if("lowertempo")
tempo += 1
if(tempo < 1)
tempo = 1
if("raisetempo")
tempo -= 1
if(tempo < 1)
tempo = 1
if("play")
if(in_range(src, usr) && !issilicon(usr))
if(href_list["tempo"])
song.tempo += text2num(href_list["tempo"])
if(song.tempo < 1)
song.tempo = 1
if(href_list["play"])
if(song)
playing = 1
spawn() playsong()
if("newsong")
song = new /datum/song
if("newbar")
var/newbar = input("Enter your bar: ") as text|null
if(!newbar)
if(href_list["newsong"])
song = new()
if(href_list["newline"])
var/newline = input("Enter your line: ", "Piano") as text|null
if(!newline)
return
if(song.lines.len >= 10)
if(song.lines.len > 50)
return
if(lentext(newbar) > 30)
newbar = copytext(newbar, 1, 30)
song.lines.Add(newbar)
if("deletebar")
var/num = href_list["deletebar"]
num -= 1
var/line = song.lines[num]
usr << "Line found is [line]"
song.lines.Remove(line)
if("stop")
if(lentext(newline) > 50)
newline = copytext(newline, 1, 50)
song.lines.Add(newline)
if(href_list["deleteline"])
var/num = text2num(href_list["deleteline"])
song.lines.Cut(num, num+1)
if(href_list["modifyline"])
var/num = text2num(href_list["modifyline"])
var/content = input("Enter your line: ", "Piano", song.lines[num]) as text|null
if(!content)
return
if(lentext(content) > 50)
content = copytext(content, 1, 50)
song.lines[num] = content
if(href_list["stop"])
playing = 0
if(href_list["help"])
help = text2num(href_list["help"]) - 1
if(href_list["edit"])
edit = text2num(href_list["edit"]) - 1
if(href_list["import"])
var/t = ""
do
t = input(usr, "Please paste the entire song, formated:", text("[]", src.name), t) as message
if (!in_range(src, usr))
return
if(lentext(t) >= MAX_PAPER_MESSAGE_LEN)
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) > MAX_PAPER_MESSAGE_LEN)
//split into lines
spawn()
var/list/lines = dd_text2list(t, "\n")
var/tempo = 5
if(copytext(lines[1],1,6) == "BPM: ")
tempo = 600 / text2num(copytext(lines[1],6))
lines.Cut(1,2)
if(lines.len > 50)
usr << "Too many lines!"
lines.Cut(51)
var/linenum = 1
for(var/l in lines)
if(lentext(l) > 50)
usr << "Line [linenum] too long!"
lines.Remove(l)
else
linenum++
song = new()
song.lines = lines
song.tempo = tempo
updateUsrDialog()
add_fingerprint(usr)
updateUsrDialog()
return
/* playing = 1
var/datum/song/S = new /datum/song
S.lines.Add("A;B;C;D;E;F;G;A;A;B;B;A;G;A;F;F;A;*;*;*;*;B;C;C;F;G")
S.lines.Add("A;B;C;D;E;F;G;A;A;B;B;A;G;A;F;F;A;*;*;*;*;B;C;C;F;G")
song = S*/

View File

@@ -10,7 +10,6 @@ CLIPBOARDS
*/
// PAPER
/obj/item/weapon/paper/New()
@@ -112,9 +111,10 @@ CLIPBOARDS
return
// check for exploits
if(findtext(t, "<script") != 0 || findtext(t, "<frame") != 0 || findtext(t, "<iframe") != 0 || findtext(t, "<input") != 0 || findtext(t, "<button") != 0 || findtext(t, "<a") != 0)
user << "\blue You think to yourself, \"Hm.. this is only paper...\""
return
for(var/tag in paper_blacklist)
if(findtext(t,"<"+tag))
user << "\blue You think to yourself, \"Hm.. this is only paper...\""
return
if(!overlays.Find("paper_words"))
src.overlays += "paper_words"

View File

@@ -24,12 +24,6 @@
user.client.screen += src.boxes
user.client.screen += src.closer
user.client.screen += src.contents
var/xs = 7
var/ys = 7
for(var/obj/O in src.contents)
O.screen_loc = "[xs],[ys]"
O.layer = 20
xs++
/obj/item/clothing/suit/storage/proc/close(mob/user as mob)
if(!user)
@@ -39,9 +33,30 @@
user.client.screen -= src.closer
user.client.screen -= src.contents
/obj/item/clothing/suit/storage/MouseDrop(atom/A)
if(istype(A,/mob/living/carbon))
src.view_inv(A)
/obj/item/clothing/suit/storage/MouseDrop(atom/over_object)
if(ishuman(usr))
var/mob/living/carbon/human/M = usr
if (!( istype(over_object, /obj/screen) ))
return ..()
playsound(src.loc, "rustle", 50, 1, -5)
if ((!( M.restrained() ) && !( M.stat ) && M.wear_suit == src))
if (over_object.name == "r_hand")
if (!( M.r_hand ))
M.u_equip(src)
M.r_hand = src
else
if (over_object.name == "l_hand")
if (!( M.l_hand ))
M.u_equip(src)
M.l_hand = src
M.update_clothing()
src.add_fingerprint(usr)
return
if(over_object == usr && in_range(src, usr) || usr.contents.Find(src))
src.view_inv(M)
src.orient_objs(7,7,9,7)
return
return
/obj/item/clothing/suit/storage/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(W.w_class > 2 || src.loc == W )
@@ -56,7 +71,56 @@
else if(user.s_active == src)
close(user)
view_inv(user)
orient2hud(user)
W.dropped(user)
/obj/item/clothing/suit/storage/attack_paw(mob/user as mob)
playsound(src.loc, "rustle", 50, 1, -5)
return attack_hand(user)
/obj/item/clothing/suit/storage/attack_hand(mob/user as mob)
playsound(src.loc, "rustle", 50, 1, -5)
if (src.loc == user)
if (user.s_active)
user.s_active.close(user)
view_inv(user)
orient2hud(user)
else
..()
for(var/mob/M in range(1))
if (M.s_active == src)
src.close(M)
src.add_fingerprint(user)
return
/obj/item/clothing/suit/storage/proc/orient2hud(mob/user as mob)
if (src == user.l_hand)
src.orient_objs(3, 5, 3, 3)
else if (src == user.r_hand)
src.orient_objs(1, 5, 1, 3)
else if (istype(user,/mob/living/carbon/human) && src == user:wear_suit)
src.orient_objs(1, 3, 3, 3)
else
src.orient_objs(4, 4, 4, 2)
return
/obj/item/clothing/suit/storage/proc/orient_objs(tx, ty, mx, my)
var/cx = tx
var/cy = ty
src.boxes.screen_loc = text("[],[] to [],[]", tx, ty, mx, my)
for(var/obj/O in src.contents)
O.screen_loc = text("[],[]", cx, cy)
O.layer = 20
cx++
if (cx > mx)
cx = tx
cy--
//Foreach goto(56)
src.closer.screen_loc = text("[],[]", mx, my)
return
/*/obj/item/clothing/suit/storage/New()
src.boxes = new /obj/screen/storage( )
@@ -199,17 +263,4 @@
//Foreach goto(56)
src.closer.screen_loc = text("[],[]", mx, my)
return
/obj/item/weapon/storage/proc/orient2hud(mob/user as mob)
if (src == user.l_hand)
src.orient_objs(3, 11, 3, 4)
else
if (src == user.r_hand)
src.orient_objs(1, 11, 1, 4)
else
if (src == user.back)
src.orient_objs(4, 10, 4, 3)
else
src.orient_objs(4, 10, 4, 3)
return*/
*/

View File

@@ -58,7 +58,14 @@
calcwin()
if(mode)
if(mode == 2)
var/wintext = capitalize(winner)
world << "Result is [wintext]"
for(var/md in vote.choices)
vote.choices -= md
return
else if(mode == 1)
if(ticker.current_state == 1)
if(!going)
world << "<B>The game will start soon.</B>"
@@ -191,12 +198,38 @@
if(vote.voting)
// vote in progress, do the current
text += "Vote to [vote.mode?"change mode":"restart round"] in progress.<BR>"
text += "[vote.endwait()] until voting is closed.<BR>"
var/list/votes = vote.getvotes()
if(vote.mode == 2)
text += "A custom vote is in progress.<BR>"
text += "[vote.endwait()] until voting is closed.<BR>"
text += "[vote.customname]"
if(vote.mode) // true if changing mode
for(var/md in vote.choices)
var/disp = capitalize(md)
if(md=="default")
disp = "No change"
//world << "[md]|[disp]|[src.client.vote]|[votes[md]]"
if(src.client.vote == md)
text += "<LI><B>[disp]</B>"
else
text += "<LI><A href='?src=\ref[vote];voter=\ref[src];vote=[md]'>[disp]</A>"
text += "[votes[md]>0?" - [votes[md]] vote\s":null]<BR>"
text += "</UL>"
text +="<p>Current winner: <B>[vote.calcwin()]</B><BR>"
text += footer
usr << browse(text, "window=vote")
else if(vote.mode == 1) // true if changing mode
text += "Vote to change mode in progress.<BR>"
text += "[vote.endwait()] until voting is closed.<BR>"
text += "Current game mode is: <B>[master_mode]</B>.<BR>Select the mode to change to:<UL>"
@@ -223,6 +256,8 @@
usr << browse(text, "window=vote")
else // voting to restart
text += "Vote to restart round in progress.<BR>"
text += "[vote.endwait()] until voting is closed.<BR>"
text += "Restart the world?<BR><UL>"
@@ -279,12 +314,13 @@
text += "<A href='?src=\ref[vote];voter=\ref[src];vmode=2'>Begin change mode vote.</A><BR>"
else
text += "Change mode votes are disabled while a round is in progress, vote to restart first.<BR>"
if(src.client.holder) //Strumpetplaya Add - Custom Votes for Admins
text += "<A href='?src=\ref[vote];voter=\ref[src];vmode=3'>Begin custom vote.</A><BR>"
text += footer
usr << browse(text, "window=vote")
spawn(20)
if(usr.client && usr.client.showvote)
if(usr.client && usr.client.showvote && !vote.enteringchoices)
usr.vote()
else
usr << browse(null, "window=vote")
@@ -312,6 +348,48 @@
return
vote.mode = text2num(href_list["vmode"])-1 // hack to yield 0=restart, 1=changemode
if(vote.mode == 2)
vote.enteringchoices = 1
vote.voting = 1
vote.customname = input(usr, "What are you voting for?", "Custom Vote") as text
if(!vote.customname)
vote.enteringchoices = 0
vote.voting = 0
return
var/N = input(usr, "How many options does this vote have?", "Custom Vote", 0) as num
if(!N)
vote.enteringchoices = 0
vote.voting = 0
return
//world << "You're voting for [N] options!"
var/i
for(i=1; i<=N; i++)
var/addvote = input(usr, "What is option #[i]?", "Enter Option #[i]") as text
vote.choices += addvote
//for(var/O in vote.choices)
//world << "[O]"
vote.enteringchoices = 0
vote.votetime = world.timeofday + config.vote_period*10 // when the vote will end
spawn(config.vote_period * 10)
vote.endvote()
world << "\red<B>*** A custom vote has been initiated by [M.key].</B>"
world << "\red You have [vote.timetext(config.vote_period)] to vote."
//log_vote("Voting to [vote.mode ? "change mode" : "restart round"] started by [M.name]/[M.key]")
for(var/client/C)
if(config.vote_no_default || (config.vote_no_dead && C.mob.stat == 2))
C.vote = "none"
else
C.vote = "default"
if(M) M.vote()
return
if(!ticker && vote.mode == 1)
if(going)
world << "<B>The game start has been delayed.</B>"

View File

@@ -2207,18 +2207,40 @@
set desc="Starts vote"
if (!usr.client.holder)
return
var/confirm = alert("What vote would you like to start?", "Vote", "Restart", "Change Game Mode", "Cancel")
if(confirm == "Cancel")
return
if(confirm == "Restart")
vote.mode = 0
// hack to yield 0=restart, 1=changemode
if(confirm == "Change Game Mode")
vote.mode = 1
if(!ticker)
if(going)
world << "<B>The game start has been delayed.</B>"
going = 0
var/confirm = alert("What vote would you like to start?", "Vote", "Restart", "Custom Vote", "Change Game Mode", "Cancel")
switch(confirm)
if("Cancel")
return
if("Restart")
vote.mode = 0
// hack to yield 0=restart, 1=changemode
if("Change Game Mode")
vote.mode = 1
if(!ticker)
if(going)
world << "<B>The game start has been delayed.</B>"
going = 0
if("Custom Vote")
vote.mode = 2
vote.enteringchoices = 1
vote.customname = input(usr, "What are you voting for?", "Custom Vote") as text
if(!vote.customname)
vote.enteringchoices = 0
vote.voting = 0
return
var/N = input(usr, "How many options does this vote have?", "Custom Vote", 0) as num
if(!N)
vote.enteringchoices = 0
vote.voting = 0
return
var/i
for(i=1; i<=N; i++)
var/addvote = input(usr, "What is option #[i]?", "Enter Option #[i]") as text
vote.choices += addvote
vote.enteringchoices = 0
vote.voting = 1
// now voting
vote.votetime = world.timeofday + config.vote_period*10

View File

@@ -175,6 +175,7 @@
verbs += /client/proc/strike_team
verbs += /client/proc/admin_invis
verbs += /client/proc/cmd_admin_godmode
verbs += /client/proc/delbook
if (holder.level >= 4)//Badmin********************************************************************
verbs += /obj/admins/proc/adrev //toggle admin revives
@@ -412,6 +413,7 @@
verbs -= /client/proc/callprocgen
verbs -= /client/proc/callprocobj
verbs -= /client/proc/cmd_admin_godmode
verbs -= /client/proc/delbook
return

View File

@@ -50,6 +50,8 @@
message = dd_replaceText(message, "u", "<22>")
message = dd_replaceText(message, "b", "<22>")
message = capitalize(message)
if (src.stuttering)
message = stutter(message)
if (src.slurring)

View File

@@ -132,6 +132,8 @@
if (!message)
return
message = capitalize(message) //capitalize the first letter of what they actually say
// :downs:
if (brainloss >= 60)
message = dd_replacetext(message, " am ", " ")