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, " 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 = "Piano\n " - var/calctempo = (10/tempo)*60 - dat += "Tempo : [calctempo] BPM (-/+)" - dat += "(Start a New Song)
" + var/dat = "Piano" + if(song) - var/linecount = 0 - for(var/line in song.lines) - linecount += 1 - dat += "Bar [linecount]: [line]
"//(Delete bar)
" // TODO: Replace delimeters with spaces, clean up display - dat += "(Write a new bar)
" if(song.lines.len > 0 && !(playing)) - dat += "(Play song)
" + dat += "Play Song

" if(playing) - dat += "(Stop playing)
" - dat += {" -

- Bars are a series of notes separated by asterisks (*) or anything else you want to put there.
- Just know that every fourth character will act as a stop, delaying the next note by tempo.
-
- Notes are played by the names of the note, the accidental, then the octave number.
- Example: An3*Bn3*Cn3*Dn3*En3*Fn3*Gn3 will play a scale.
- Chords can be played simply by listing more than one note before a pause: AB*CD*EF*GA
-
- Bars may be up to 30 characters (including pauses).
- A song may only contain up to 10 bars.
- "} - user << browse(dat, "window=piano") + dat += "Stop Playing

" + + if(!edit) + dat += "Show Editer

" + else + dat += "Hide Editer
" + dat += "Start a New Song
" + dat += "Import a Song

" + if(song) + var/calctempo = (10/song.tempo)*60 + dat += "Tempo : -- [calctempo] BPM ++

" + var/linecount = 0 + for(var/line in song.lines) + linecount += 1 + dat += "Line [linecount]: [line] Delete Line Modify Line
" + dat += "Add Line

" + if(help) + dat += "Hide Help
" + dat += {" + Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).
+ Every note in a chord will play together, with chord timed by the tempo.
+
+ Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.
+ By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.
+ Example: C,D,E,F,G,A,B will play a C major scale.
+ After a note has an accidental placed, it will be remembered: C,C4,C,C3 is C3,C4,C4,C3
+ Chords can be played simply by seperating each note with a hyphon: A-C#,Cn-E,E-G#,Gn-B
+ A pause may be denoted by an empty chord: C,E,,C,G
+ To make a chord be a different time, end it with /x, where the chord length will be length
+ defined by tempo / x: C,G/2,E/4
+ Combined, an example is: E-E4/4,/2,G#/8,B/8,E3-E4/4 +
+ Lines may be up to 50 characters.
+ A song may only contain up to 50 lines.
+ "} + else + dat += "Show Help
" + dat += "" + 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*/ \ No newline at end of file diff --git a/code/game/objects/items/weapons/papers_bins.dm b/code/game/objects/items/weapons/papers_bins.dm index 0b8bdbbc5f..1a5d3501f7 100644 --- a/code/game/objects/items/weapons/papers_bins.dm +++ b/code/game/objects/items/weapons/papers_bins.dm @@ -10,7 +10,6 @@ CLIPBOARDS */ - // PAPER /obj/item/weapon/paper/New() @@ -112,9 +111,10 @@ CLIPBOARDS return // check for exploits - if(findtext(t, " 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*/ \ No newline at end of file +*/ \ No newline at end of file diff --git a/code/game/vote.dm b/code/game/vote.dm index 2c3b57034b..cd62786617 100644 --- a/code/game/vote.dm +++ b/code/game/vote.dm @@ -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 << "The game will start soon." @@ -191,12 +198,38 @@ if(vote.voting) // vote in progress, do the current - text += "Vote to [vote.mode?"change mode":"restart round"] in progress.
" - text += "[vote.endwait()] until voting is closed.
" - var/list/votes = vote.getvotes() + if(vote.mode == 2) + text += "A custom vote is in progress.
" + text += "[vote.endwait()] until voting is closed.
" + 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 += "
  • [disp]" + else + text += "
  • [disp]" + + text += "[votes[md]>0?" - [votes[md]] vote\s":null]
    " + + text += "" + + text +="

    Current winner: [vote.calcwin()]
    " + + text += footer + + usr << browse(text, "window=vote") + + else if(vote.mode == 1) // true if changing mode + + text += "Vote to change mode in progress.
    " + text += "[vote.endwait()] until voting is closed.
    " text += "Current game mode is: [master_mode].
    Select the mode to change to:

      " @@ -223,6 +256,8 @@ usr << browse(text, "window=vote") else // voting to restart + text += "Vote to restart round in progress.
      " + text += "[vote.endwait()] until voting is closed.
      " text += "Restart the world?
        " @@ -279,12 +314,13 @@ text += "Begin change mode vote.
        " else text += "Change mode votes are disabled while a round is in progress, vote to restart first.
        " - + if(src.client.holder) //Strumpetplaya Add - Custom Votes for Admins + text += "Begin custom vote.
        " 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*** A custom vote has been initiated by [M.key]." + 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 << "The game start has been delayed." diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index bd287024d5..1e67e8179d 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -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 << "The game start has been delayed." - 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 << "The game start has been delayed." + 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 diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index bcd5ff6024..99ee24a0fc 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -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 diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm index a1d4db9963..3604b51990 100644 --- a/code/modules/mob/living/carbon/human/whisper.dm +++ b/code/modules/mob/living/carbon/human/whisper.dm @@ -50,6 +50,8 @@ message = dd_replaceText(message, "u", "µ") message = dd_replaceText(message, "b", "ß") + message = capitalize(message) + if (src.stuttering) message = stutter(message) if (src.slurring) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index f33818cb33..43a8fc9f0d 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -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 ", " ")