From e6efe1a82d42d6e03f734db249e8907de797829d Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Mon, 18 Mar 2013 21:29:08 -0400 Subject: [PATCH 01/14] Updated the violin to use the new UI style and datum, and fixed a bunch of dialog updating bugs within. Fixed a couple buttons to work before song created, that should, such as import song. Changing tempo works more naturally now. --- code/game/objects/items/devices/violin.dm | 198 ++++++++++++---------- 1 file changed, 111 insertions(+), 87 deletions(-) diff --git a/code/game/objects/items/devices/violin.dm b/code/game/objects/items/devices/violin.dm index 63f7828fc80..1da8e13afda 100644 --- a/code/game/objects/items/devices/violin.dm +++ b/code/game/objects/items/devices/violin.dm @@ -8,10 +8,11 @@ item_state = "violin" force = 10 var/datum/song/song - var/playing = 0 - var/help = 0 - var/edit = 1 - var/repeat = 0 + var/playing = 0 // if we're playing + var/help = 0 // if help is open + var/edit = 1 // if we're in editing mode + var/repeat = 0 // number of times remaining to repeat + var/max_repeats = 10 // maximum times we can repeat /obj/item/device/violin/proc/playnote(var/note as text) //world << "Note: [note]" @@ -192,8 +193,8 @@ hearers(15, get_turf(src)) << sound(soundfile) -/obj/item/device/violin/proc/playsong() - do +/obj/item/device/violin/proc/playsong(mob/user as mob) + while(repeat >= 0) var/cur_oct[7] var/cur_acc[7] for(var/i = 1 to 7) @@ -230,40 +231,57 @@ sleep(song.tempo / text2num(notes[2])) else sleep(song.tempo) - if(repeat > 0) - repeat-- //Infinite loops are baaaad. - while(repeat > 0) + repeat-- + if(repeat >= 0) // don't show the last -1 repeat + interact(user) playing = 0 + repeat = 0 + interact(user) /obj/item/device/violin/attack_self(mob/user as mob) if(!isliving(user) || user.stat || user.restrained() || user.lying) return user.set_machine(src) + interact(user) - var/dat = "Violin" +/obj/item/device/violin/interact(mob/user as mob) + if(!user) + return - if(song) - if(song.lines.len > 0 && !(playing)) - dat += "Play Song

" - dat += "Repeat Song: [repeat] times.

" - if(playing) - dat += "Stop Playing
" - dat += "Repeats left: [repeat].

" + if(!isliving(user) || user.stat || user.restrained() || user.lying) return + + var/dat = "" + + if(song && song.lines.len > 0) + dat += "

Playback

" + if(!playing) + dat += "Play Stop

" + dat += "Repeat Song: " + dat += repeat > 0 ? "--" : "--" + dat += " [repeat] times " + dat += repeat < max_repeats ? "++" : "++" + dat += "
" + else + dat += "Play Stop
" + dat += "Repeats left: [repeat]
" if(!edit) - dat += "Show Editor

" + dat += "
Show Editor
" else - dat += "Hide Editor
" - dat += "Start a New Song
" - dat += "Import a Song

" + dat += "

Editing

" + dat += "Hide Editor" + dat += " Start a New Song" + dat += " Import a Song

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

" + var/calctempo = round(600 / song.tempo) + var/calcstep = song.tempo - 600 / (calctempo+1) + var/calcstep_b = song.tempo - 600 / (calctempo+10) + dat += "Tempo: -- [calctempo] BPM ++

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

" if(help) - dat += "Hide 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.
@@ -276,45 +294,94 @@ 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 + Combined, an example is: E-E4/4,F#/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=violin;size=700x300") - onclose(user, "violin") + dat += "Show Help
" + + var/datum/browser/popup = new(user, "apc", name) + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.open() + return /obj/item/device/violin/Topic(href, href_list) - if(!in_range(src, usr) || issilicon(usr) || !isliving(usr) || !usr.canmove || usr.restrained()) - usr << browse(null, "window=violin;size=700x300") - onclose(usr, "violin") + usr << browse(null, "window=violin") + usr.unset_machine() return + add_fingerprint(usr) + if(href_list["newsong"]) song = new() + + else if(href_list["import"]) + var/t = "" + do + t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message) + if(!in_range(src, usr)) + return + + if(lentext(t) >= 3072) + 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) > 3072) + + //split into lines + spawn() + var/list/lines = 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 + interact(usr) // make sure updates when complete + + else if(href_list["help"]) + help = text2num(href_list["help"]) - 1 + + else if(href_list["edit"]) + edit = text2num(href_list["edit"]) - 1 + else if(song) if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops. - if(playing) return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing. - var/tempnum = input("How many times do you want to repeat this piece? (max:10)") as num|null - if(tempnum > 10) - tempnum = 10 - if(tempnum < 0) - tempnum = 0 - repeat = round(tempnum) + if(playing) + return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing. + repeat += round(text2num(href_list["repeat"])) + if(repeat < 0) + repeat = 0 + if(repeat > max_repeats) + repeat = max_repeats else if(href_list["tempo"]) - song.tempo += round(text2num(href_list["tempo"])) + song.tempo += text2num(href_list["tempo"]) if(song.tempo < 1) song.tempo = 1 + if(song.tempo > 600) + song.tempo = 600 else if(href_list["play"]) if(song) playing = 1 - spawn() playsong() + spawn() + playsong(usr) else if(href_list["newline"]) var/newline = html_encode(input("Enter your line: ", "violin") as text|null) @@ -346,48 +413,5 @@ else if(href_list["stop"]) playing = 0 - else if(href_list["help"]) - help = text2num(href_list["help"]) - 1 - - else if(href_list["edit"]) - edit = text2num(href_list["edit"]) - 1 - - else if(href_list["import"]) - var/t = "" - do - t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message) - if(!in_range(src, usr)) - return - - if(lentext(t) >= 3072) - 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) > 3072) - - //split into lines - spawn() - var/list/lines = 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 - - add_fingerprint(usr) - for(var/mob/M in viewers(1, loc)) - if((M.client && M.machine == src)) - attack_self(M) - return \ No newline at end of file + interact(usr) + return From 806d784b16b38b486e070bd3e433ce79cc84e9c7 Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Wed, 20 Mar 2013 04:52:17 -0400 Subject: [PATCH 02/14] Moved backend and UI functionality into the datum/song class and made in generalizable for special-case functionalities for player checks, etc --- code/game/objects/items/devices/violin.dm | 404 +------------ code/game/objects/structures/musician.dm | 690 ++++++++++++---------- 2 files changed, 378 insertions(+), 716 deletions(-) diff --git a/code/game/objects/items/devices/violin.dm b/code/game/objects/items/devices/violin.dm index 1da8e13afda..d37dee969c1 100644 --- a/code/game/objects/items/devices/violin.dm +++ b/code/game/objects/items/devices/violin.dm @@ -7,411 +7,21 @@ icon_state = "violin" item_state = "violin" force = 10 - var/datum/song/song - var/playing = 0 // if we're playing - var/help = 0 // if help is open - var/edit = 1 // if we're in editing mode - var/repeat = 0 // number of times remaining to repeat - var/max_repeats = 10 // maximum times we can repeat + var/datum/song/handheld/song -/obj/item/device/violin/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.*/ - switch(note) - if("Cn1") soundfile = 'sound/violin/Cn1.mid' - if("C#1") soundfile = 'sound/violin/C#1.mid' - if("Db1") soundfile = 'sound/violin/Db1.mid' - if("Dn1") soundfile = 'sound/violin/Dn1.mid' - if("D#1") soundfile = 'sound/violin/D#1.mid' - if("Eb1") soundfile = 'sound/violin/Eb1.mid' - if("En1") soundfile = 'sound/violin/En1.mid' - if("E#1") soundfile = 'sound/violin/E#1.mid' - if("Fb1") soundfile = 'sound/violin/Fb1.mid' - if("Fn1") soundfile = 'sound/violin/Fn1.mid' - if("F#1") soundfile = 'sound/violin/F#1.mid' - if("Gb1") soundfile = 'sound/violin/Gb1.mid' - if("Gn1") soundfile = 'sound/violin/Gn1.mid' - if("G#1") soundfile = 'sound/violin/G#1.mid' - if("Ab1") soundfile = 'sound/violin/Ab1.mid' - if("An1") soundfile = 'sound/violin/An1.mid' - if("A#1") soundfile = 'sound/violin/A#1.mid' - if("Bb1") soundfile = 'sound/violin/Bb1.mid' - if("Bn1") soundfile = 'sound/violin/Bn1.mid' - if("B#1") soundfile = 'sound/violin/B#1.mid' - if("Cb2") soundfile = 'sound/violin/Cb2.mid' - if("Cn2") soundfile = 'sound/violin/Cn2.mid' - if("C#2") soundfile = 'sound/violin/C#2.mid' - if("Db2") soundfile = 'sound/violin/Db2.mid' - if("Dn2") soundfile = 'sound/violin/Dn2.mid' - if("D#2") soundfile = 'sound/violin/D#2.mid' - if("Eb2") soundfile = 'sound/violin/Eb2.mid' - if("En2") soundfile = 'sound/violin/En2.mid' - if("E#2") soundfile = 'sound/violin/E#2.mid' - if("Fb2") soundfile = 'sound/violin/Fb2.mid' - if("Fn2") soundfile = 'sound/violin/Fn2.mid' - if("F#2") soundfile = 'sound/violin/F#2.mid' - if("Gb2") soundfile = 'sound/violin/Gb2.mid' - if("Gn2") soundfile = 'sound/violin/Gn2.mid' - if("G#2") soundfile = 'sound/violin/G#2.mid' - if("Ab2") soundfile = 'sound/violin/Ab2.mid' - if("An2") soundfile = 'sound/violin/An2.mid' - if("A#2") soundfile = 'sound/violin/A#2.mid' - if("Bb2") soundfile = 'sound/violin/Bb2.mid' - if("Bn2") soundfile = 'sound/violin/Bn2.mid' - if("B#2") soundfile = 'sound/violin/B#2.mid' - if("Cb3") soundfile = 'sound/violin/Cb3.mid' - if("Cn3") soundfile = 'sound/violin/Cn3.mid' - if("C#3") soundfile = 'sound/violin/C#3.mid' - if("Db3") soundfile = 'sound/violin/Db3.mid' - if("Dn3") soundfile = 'sound/violin/Dn3.mid' - if("D#3") soundfile = 'sound/violin/D#3.mid' - if("Eb3") soundfile = 'sound/violin/Eb3.mid' - if("En3") soundfile = 'sound/violin/En3.mid' - if("E#3") soundfile = 'sound/violin/E#3.mid' - if("Fb3") soundfile = 'sound/violin/Fb3.mid' - if("Fn3") soundfile = 'sound/violin/Fn3.mid' - if("F#3") soundfile = 'sound/violin/F#3.mid' - if("Gb3") soundfile = 'sound/violin/Gb3.mid' - if("Gn3") soundfile = 'sound/violin/Gn3.mid' - if("G#3") soundfile = 'sound/violin/G#3.mid' - if("Ab3") soundfile = 'sound/violin/Ab3.mid' - if("An3") soundfile = 'sound/violin/An3.mid' - if("A#3") soundfile = 'sound/violin/A#3.mid' - if("Bb3") soundfile = 'sound/violin/Bb3.mid' - if("Bn3") soundfile = 'sound/violin/Bn3.mid' - if("B#3") soundfile = 'sound/violin/B#3.mid' - if("Cb4") soundfile = 'sound/violin/Cb4.mid' - if("Cn4") soundfile = 'sound/violin/Cn4.mid' - if("C#4") soundfile = 'sound/violin/C#4.mid' - if("Db4") soundfile = 'sound/violin/Db4.mid' - if("Dn4") soundfile = 'sound/violin/Dn4.mid' - if("D#4") soundfile = 'sound/violin/D#4.mid' - if("Eb4") soundfile = 'sound/violin/Eb4.mid' - if("En4") soundfile = 'sound/violin/En4.mid' - if("E#4") soundfile = 'sound/violin/E#4.mid' - if("Fb4") soundfile = 'sound/violin/Fb4.mid' - if("Fn4") soundfile = 'sound/violin/Fn4.mid' - if("F#4") soundfile = 'sound/violin/F#4.mid' - if("Gb4") soundfile = 'sound/violin/Gb4.mid' - if("Gn4") soundfile = 'sound/violin/Gn4.mid' - if("G#4") soundfile = 'sound/violin/G#4.mid' - if("Ab4") soundfile = 'sound/violin/Ab4.mid' - if("An4") soundfile = 'sound/violin/An4.mid' - if("A#4") soundfile = 'sound/violin/A#4.mid' - if("Bb4") soundfile = 'sound/violin/Bb4.mid' - if("Bn4") soundfile = 'sound/violin/Bn4.mid' - if("B#4") soundfile = 'sound/violin/B#4.mid' - if("Cb5") soundfile = 'sound/violin/Cb5.mid' - if("Cn5") soundfile = 'sound/violin/Cn5.mid' - if("C#5") soundfile = 'sound/violin/C#5.mid' - if("Db5") soundfile = 'sound/violin/Db5.mid' - if("Dn5") soundfile = 'sound/violin/Dn5.mid' - if("D#5") soundfile = 'sound/violin/D#5.mid' - if("Eb5") soundfile = 'sound/violin/Eb5.mid' - if("En5") soundfile = 'sound/violin/En5.mid' - if("E#5") soundfile = 'sound/violin/E#5.mid' - if("Fb5") soundfile = 'sound/violin/Fb5.mid' - if("Fn5") soundfile = 'sound/violin/Fn5.mid' - if("F#5") soundfile = 'sound/violin/F#5.mid' - if("Gb5") soundfile = 'sound/violin/Gb5.mid' - if("Gn5") soundfile = 'sound/violin/Gn5.mid' - if("G#5") soundfile = 'sound/violin/G#5.mid' - if("Ab5") soundfile = 'sound/violin/Ab5.mid' - if("An5") soundfile = 'sound/violin/An5.mid' - if("A#5") soundfile = 'sound/violin/A#5.mid' - if("Bb5") soundfile = 'sound/violin/Bb5.mid' - if("Bn5") soundfile = 'sound/violin/Bn5.mid' - if("B#5") soundfile = 'sound/violin/B#5.mid' - if("Cb6") soundfile = 'sound/violin/Cb6.mid' - if("Cn6") soundfile = 'sound/violin/Cn6.mid' - if("C#6") soundfile = 'sound/violin/C#6.mid' - if("Db6") soundfile = 'sound/violin/Db6.mid' - if("Dn6") soundfile = 'sound/violin/Dn6.mid' - if("D#6") soundfile = 'sound/violin/D#6.mid' - if("Eb6") soundfile = 'sound/violin/Eb6.mid' - if("En6") soundfile = 'sound/violin/En6.mid' - if("E#6") soundfile = 'sound/violin/E#6.mid' - if("Fb6") soundfile = 'sound/violin/Fb6.mid' - if("Fn6") soundfile = 'sound/violin/Fn6.mid' - if("F#6") soundfile = 'sound/violin/F#6.mid' - if("Gb6") soundfile = 'sound/violin/Gb6.mid' - if("Gn6") soundfile = 'sound/violin/Gn6.mid' - if("G#6") soundfile = 'sound/violin/G#6.mid' - if("Ab6") soundfile = 'sound/violin/Ab6.mid' - if("An6") soundfile = 'sound/violin/An6.mid' - if("A#6") soundfile = 'sound/violin/A#6.mid' - if("Bb6") soundfile = 'sound/violin/Bb6.mid' - if("Bn6") soundfile = 'sound/violin/Bn6.mid' - if("B#6") soundfile = 'sound/violin/B#6.mid' - if("Cb7") soundfile = 'sound/violin/Cb7.mid' - if("Cn7") soundfile = 'sound/violin/Cn7.mid' - if("C#7") soundfile = 'sound/violin/C#7.mid' - if("Db7") soundfile = 'sound/violin/Db7.mid' - if("Dn7") soundfile = 'sound/violin/Dn7.mid' - if("D#7") soundfile = 'sound/violin/D#7.mid' - if("Eb7") soundfile = 'sound/violin/Eb7.mid' - if("En7") soundfile = 'sound/violin/En7.mid' - if("E#7") soundfile = 'sound/violin/E#7.mid' - if("Fb7") soundfile = 'sound/violin/Fb7.mid' - if("Fn7") soundfile = 'sound/violin/Fn7.mid' - if("F#7") soundfile = 'sound/violin/F#7.mid' - if("Gb7") soundfile = 'sound/violin/Gb7.mid' - if("Gn7") soundfile = 'sound/violin/Gn7.mid' - if("G#7") soundfile = 'sound/violin/G#7.mid' - if("Ab7") soundfile = 'sound/violin/Ab7.mid' - if("An7") soundfile = 'sound/violin/An7.mid' - if("A#7") soundfile = 'sound/violin/A#7.mid' - if("Bb7") soundfile = 'sound/violin/Bb7.mid' - if("Bn7") soundfile = 'sound/violin/Bn7.mid' - if("B#7") soundfile = 'sound/violin/B#7.mid' - if("Cb8") soundfile = 'sound/violin/Cb8.mid' - if("Cn8") soundfile = 'sound/violin/Cn8.mid' - if("C#8") soundfile = 'sound/violin/C#8.mid' - if("Db8") soundfile = 'sound/violin/Db8.mid' - if("Dn8") soundfile = 'sound/violin/Dn8.mid' - if("D#8") soundfile = 'sound/violin/D#8.mid' - if("Eb8") soundfile = 'sound/violin/Eb8.mid' - if("En8") soundfile = 'sound/violin/En8.mid' - if("E#8") soundfile = 'sound/violin/E#8.mid' - if("Fb8") soundfile = 'sound/violin/Fb8.mid' - if("Fn8") soundfile = 'sound/violin/Fn8.mid' - if("F#8") soundfile = 'sound/violin/F#8.mid' - if("Gb8") soundfile = 'sound/violin/Gb8.mid' - if("Gn8") soundfile = 'sound/violin/Gn8.mid' - if("G#8") soundfile = 'sound/violin/G#8.mid' - if("Ab8") soundfile = 'sound/violin/Ab8.mid' - if("An8") soundfile = 'sound/violin/An8.mid' - if("A#8") soundfile = 'sound/violin/A#8.mid' - if("Bb8") soundfile = 'sound/violin/Bb8.mid' - if("Bn8") soundfile = 'sound/violin/Bn8.mid' - if("B#8") soundfile = 'sound/violin/B#8.mid' - if("Cb9") soundfile = 'sound/violin/Cb9.mid' - if("Cn9") soundfile = 'sound/violin/Cn9.mid' - else return - - hearers(15, get_turf(src)) << sound(soundfile) - -/obj/item/device/violin/proc/playsong(mob/user as mob) - while(repeat >= 0) - 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) - //world << line - for(var/beat in text2list(lowertext(line), ",")) - //world << "beat: [beat]" - var/list/notes = text2list(beat, "/") - for(var/note in text2list(notes[1], "-")) - //world << "note: [note]" - if(!playing || !isliving(loc))//If the violin is playing, or isn't held by a person - playing = 0 - 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" || ni == "n") - 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) - repeat-- - if(repeat >= 0) // don't show the last -1 repeat - interact(user) - playing = 0 - repeat = 0 - interact(user) +/obj/item/device/violin/New() + song = new("violin", src) + song.instrumentExt = "mid" /obj/item/device/violin/attack_self(mob/user as mob) - if(!isliving(user) || user.stat || user.restrained() || user.lying) return - user.set_machine(src) interact(user) /obj/item/device/violin/interact(mob/user as mob) if(!user) return - if(!isliving(user) || user.stat || user.restrained() || user.lying) return - - var/dat = "" - - if(song && song.lines.len > 0) - dat += "

Playback

" - if(!playing) - dat += "Play Stop

" - dat += "Repeat Song: " - dat += repeat > 0 ? "--" : "--" - dat += " [repeat] times " - dat += repeat < max_repeats ? "++" : "++" - dat += "
" - else - dat += "Play Stop
" - dat += "Repeats left: [repeat]
" - if(!edit) - dat += "
Show Editor
" - else - dat += "

Editing

" - dat += "Hide Editor" - dat += " Start a New Song" - dat += " Import a Song

" - if(song) - var/calctempo = round(600 / song.tempo) - var/calcstep = song.tempo - 600 / (calctempo+1) - var/calcstep_b = song.tempo - 600 / (calctempo+10) - dat += "Tempo: -- [calctempo] BPM ++

" - var/linecount = 0 - for(var/line in song.lines) - linecount += 1 - dat += "Line [linecount]: Edit X [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,F#/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
" - - var/datum/browser/popup = new(user, "apc", name) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() - return - -/obj/item/device/violin/Topic(href, href_list) - if(!in_range(src, usr) || issilicon(usr) || !isliving(usr) || !usr.canmove || usr.restrained()) - usr << browse(null, "window=violin") - usr.unset_machine() + if(!isliving(user) || user.stat || user.restrained() || user.lying) return - add_fingerprint(usr) - - if(href_list["newsong"]) - song = new() - - else if(href_list["import"]) - var/t = "" - do - t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message) - if(!in_range(src, usr)) - return - - if(lentext(t) >= 3072) - 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) > 3072) - - //split into lines - spawn() - var/list/lines = 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 - interact(usr) // make sure updates when complete - - else if(href_list["help"]) - help = text2num(href_list["help"]) - 1 - - else if(href_list["edit"]) - edit = text2num(href_list["edit"]) - 1 - - else if(song) - if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops. - if(playing) - return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing. - repeat += round(text2num(href_list["repeat"])) - if(repeat < 0) - repeat = 0 - if(repeat > max_repeats) - repeat = max_repeats - - else if(href_list["tempo"]) - song.tempo += text2num(href_list["tempo"]) - if(song.tempo < 1) - song.tempo = 1 - if(song.tempo > 600) - song.tempo = 600 - - else if(href_list["play"]) - if(song) - playing = 1 - spawn() - playsong(usr) - - else if(href_list["newline"]) - var/newline = html_encode(input("Enter your line: ", "violin") as text|null) - if(!newline) - return - if(song.lines.len > 50) - return - if(lentext(newline) > 50) - newline = copytext(newline, 1, 50) - song.lines.Add(newline) - - else if(href_list["deleteline"]) - var/num = round(text2num(href_list["deleteline"])) - if(num > song.lines.len || num < 1) - return - song.lines.Cut(num, num+1) - - else if(href_list["modifyline"]) - var/num = round(text2num(href_list["modifyline"]),1) - var/content = html_encode(input("Enter your line: ", "violin", song.lines[num]) as text|null) - if(!content) - return - if(lentext(content) > 50) - content = copytext(content, 1, 50) - if(num > song.lines.len || num < 1) - return - song.lines[num] = content - - else if(href_list["stop"]) - playing = 0 - - interact(usr) - return + user.set_machine(src) + song.interact(user) diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm index c9bcbda3e5f..cd8cd627579 100644 --- a/code/game/objects/structures/musician.dm +++ b/code/game/objects/structures/musician.dm @@ -5,223 +5,221 @@ var/list/lines = new() var/tempo = 5 -/obj/structure/device/piano - name = "space minimoog" - icon = 'icons/obj/musician.dmi' - icon_state = "minimoog" - anchored = 1 - density = 1 - var/datum/song/song - var/playing = 0 - var/help = 0 - var/edit = 1 - var/repeat = 0 + var/playing = 0 // if we're playing + var/help = 0 // if help is open + var/edit = 1 // if we're in editing mode + var/repeat = 0 // number of times remaining to repeat + var/max_repeats = 10 // maximum times we can repeat -/obj/structure/device/piano/New() - if(prob(50)) - name = "space minimoog" - desc = "This is a minimoog, like a space piano, but more spacey!" - icon_state = "minimoog" - else - name = "space piano" - desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't." - icon_state = "piano" + var/instrumentDir = "piano" // the folder with the sounds + var/instrumentExt = "ogg" // the file extension + var/obj/instrumentObj = null // the associated obj playing the sound -/obj/structure/device/piano/proc/playnote(var/note as text) +/datum/song/New(dir, obj) + instrumentDir = dir + instrumentObj = obj + +/datum/song/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.*/ switch(note) - if("Cn1") soundfile = 'sound/piano/Cn1.ogg' - if("C#1") soundfile = 'sound/piano/C#1.ogg' - if("Db1") soundfile = 'sound/piano/Db1.ogg' - if("Dn1") soundfile = 'sound/piano/Dn1.ogg' - if("D#1") soundfile = 'sound/piano/D#1.ogg' - if("Eb1") soundfile = 'sound/piano/Eb1.ogg' - if("En1") soundfile = 'sound/piano/En1.ogg' - if("E#1") soundfile = 'sound/piano/E#1.ogg' - if("Fb1") soundfile = 'sound/piano/Fb1.ogg' - if("Fn1") soundfile = 'sound/piano/Fn1.ogg' - if("F#1") soundfile = 'sound/piano/F#1.ogg' - if("Gb1") soundfile = 'sound/piano/Gb1.ogg' - if("Gn1") soundfile = 'sound/piano/Gn1.ogg' - if("G#1") soundfile = 'sound/piano/G#1.ogg' - if("Ab1") soundfile = 'sound/piano/Ab1.ogg' - if("An1") soundfile = 'sound/piano/An1.ogg' - if("A#1") soundfile = 'sound/piano/A#1.ogg' - if("Bb1") soundfile = 'sound/piano/Bb1.ogg' - if("Bn1") soundfile = 'sound/piano/Bn1.ogg' - if("B#1") soundfile = 'sound/piano/B#1.ogg' - if("Cb2") soundfile = 'sound/piano/Cb2.ogg' - if("Cn2") soundfile = 'sound/piano/Cn2.ogg' - if("C#2") soundfile = 'sound/piano/C#2.ogg' - if("Db2") soundfile = 'sound/piano/Db2.ogg' - if("Dn2") soundfile = 'sound/piano/Dn2.ogg' - if("D#2") soundfile = 'sound/piano/D#2.ogg' - if("Eb2") soundfile = 'sound/piano/Eb2.ogg' - if("En2") soundfile = 'sound/piano/En2.ogg' - if("E#2") soundfile = 'sound/piano/E#2.ogg' - if("Fb2") soundfile = 'sound/piano/Fb2.ogg' - if("Fn2") soundfile = 'sound/piano/Fn2.ogg' - if("F#2") soundfile = 'sound/piano/F#2.ogg' - if("Gb2") soundfile = 'sound/piano/Gb2.ogg' - if("Gn2") soundfile = 'sound/piano/Gn2.ogg' - if("G#2") soundfile = 'sound/piano/G#2.ogg' - if("Ab2") soundfile = 'sound/piano/Ab2.ogg' - if("An2") soundfile = 'sound/piano/An2.ogg' - if("A#2") soundfile = 'sound/piano/A#2.ogg' - if("Bb2") soundfile = 'sound/piano/Bb2.ogg' - if("Bn2") soundfile = 'sound/piano/Bn2.ogg' - if("B#2") soundfile = 'sound/piano/B#2.ogg' - if("Cb3") soundfile = 'sound/piano/Cb3.ogg' - if("Cn3") soundfile = 'sound/piano/Cn3.ogg' - if("C#3") soundfile = 'sound/piano/C#3.ogg' - if("Db3") soundfile = 'sound/piano/Db3.ogg' - if("Dn3") soundfile = 'sound/piano/Dn3.ogg' - if("D#3") soundfile = 'sound/piano/D#3.ogg' - if("Eb3") soundfile = 'sound/piano/Eb3.ogg' - if("En3") soundfile = 'sound/piano/En3.ogg' - if("E#3") soundfile = 'sound/piano/E#3.ogg' - if("Fb3") soundfile = 'sound/piano/Fb3.ogg' - if("Fn3") soundfile = 'sound/piano/Fn3.ogg' - if("F#3") soundfile = 'sound/piano/F#3.ogg' - if("Gb3") soundfile = 'sound/piano/Gb3.ogg' - if("Gn3") soundfile = 'sound/piano/Gn3.ogg' - if("G#3") soundfile = 'sound/piano/G#3.ogg' - if("Ab3") soundfile = 'sound/piano/Ab3.ogg' - if("An3") soundfile = 'sound/piano/An3.ogg' - if("A#3") soundfile = 'sound/piano/A#3.ogg' - if("Bb3") soundfile = 'sound/piano/Bb3.ogg' - if("Bn3") soundfile = 'sound/piano/Bn3.ogg' - if("B#3") soundfile = 'sound/piano/B#3.ogg' - if("Cb4") soundfile = 'sound/piano/Cb4.ogg' - if("Cn4") soundfile = 'sound/piano/Cn4.ogg' - if("C#4") soundfile = 'sound/piano/C#4.ogg' - if("Db4") soundfile = 'sound/piano/Db4.ogg' - if("Dn4") soundfile = 'sound/piano/Dn4.ogg' - if("D#4") soundfile = 'sound/piano/D#4.ogg' - if("Eb4") soundfile = 'sound/piano/Eb4.ogg' - if("En4") soundfile = 'sound/piano/En4.ogg' - if("E#4") soundfile = 'sound/piano/E#4.ogg' - if("Fb4") soundfile = 'sound/piano/Fb4.ogg' - if("Fn4") soundfile = 'sound/piano/Fn4.ogg' - if("F#4") soundfile = 'sound/piano/F#4.ogg' - if("Gb4") soundfile = 'sound/piano/Gb4.ogg' - if("Gn4") soundfile = 'sound/piano/Gn4.ogg' - if("G#4") soundfile = 'sound/piano/G#4.ogg' - if("Ab4") soundfile = 'sound/piano/Ab4.ogg' - if("An4") soundfile = 'sound/piano/An4.ogg' - if("A#4") soundfile = 'sound/piano/A#4.ogg' - if("Bb4") soundfile = 'sound/piano/Bb4.ogg' - if("Bn4") soundfile = 'sound/piano/Bn4.ogg' - if("B#4") soundfile = 'sound/piano/B#4.ogg' - if("Cb5") soundfile = 'sound/piano/Cb5.ogg' - if("Cn5") soundfile = 'sound/piano/Cn5.ogg' - if("C#5") soundfile = 'sound/piano/C#5.ogg' - if("Db5") soundfile = 'sound/piano/Db5.ogg' - if("Dn5") soundfile = 'sound/piano/Dn5.ogg' - if("D#5") soundfile = 'sound/piano/D#5.ogg' - if("Eb5") soundfile = 'sound/piano/Eb5.ogg' - if("En5") soundfile = 'sound/piano/En5.ogg' - if("E#5") soundfile = 'sound/piano/E#5.ogg' - if("Fb5") soundfile = 'sound/piano/Fb5.ogg' - if("Fn5") soundfile = 'sound/piano/Fn5.ogg' - if("F#5") soundfile = 'sound/piano/F#5.ogg' - if("Gb5") soundfile = 'sound/piano/Gb5.ogg' - if("Gn5") soundfile = 'sound/piano/Gn5.ogg' - if("G#5") soundfile = 'sound/piano/G#5.ogg' - if("Ab5") soundfile = 'sound/piano/Ab5.ogg' - if("An5") soundfile = 'sound/piano/An5.ogg' - if("A#5") soundfile = 'sound/piano/A#5.ogg' - if("Bb5") soundfile = 'sound/piano/Bb5.ogg' - if("Bn5") soundfile = 'sound/piano/Bn5.ogg' - if("B#5") soundfile = 'sound/piano/B#5.ogg' - if("Cb6") soundfile = 'sound/piano/Cb6.ogg' - if("Cn6") soundfile = 'sound/piano/Cn6.ogg' - if("C#6") soundfile = 'sound/piano/C#6.ogg' - if("Db6") soundfile = 'sound/piano/Db6.ogg' - if("Dn6") soundfile = 'sound/piano/Dn6.ogg' - if("D#6") soundfile = 'sound/piano/D#6.ogg' - if("Eb6") soundfile = 'sound/piano/Eb6.ogg' - if("En6") soundfile = 'sound/piano/En6.ogg' - if("E#6") soundfile = 'sound/piano/E#6.ogg' - if("Fb6") soundfile = 'sound/piano/Fb6.ogg' - if("Fn6") soundfile = 'sound/piano/Fn6.ogg' - if("F#6") soundfile = 'sound/piano/F#6.ogg' - if("Gb6") soundfile = 'sound/piano/Gb6.ogg' - if("Gn6") soundfile = 'sound/piano/Gn6.ogg' - if("G#6") soundfile = 'sound/piano/G#6.ogg' - if("Ab6") soundfile = 'sound/piano/Ab6.ogg' - if("An6") soundfile = 'sound/piano/An6.ogg' - if("A#6") soundfile = 'sound/piano/A#6.ogg' - if("Bb6") soundfile = 'sound/piano/Bb6.ogg' - if("Bn6") soundfile = 'sound/piano/Bn6.ogg' - if("B#6") soundfile = 'sound/piano/B#6.ogg' - if("Cb7") soundfile = 'sound/piano/Cb7.ogg' - if("Cn7") soundfile = 'sound/piano/Cn7.ogg' - if("C#7") soundfile = 'sound/piano/C#7.ogg' - if("Db7") soundfile = 'sound/piano/Db7.ogg' - if("Dn7") soundfile = 'sound/piano/Dn7.ogg' - if("D#7") soundfile = 'sound/piano/D#7.ogg' - if("Eb7") soundfile = 'sound/piano/Eb7.ogg' - if("En7") soundfile = 'sound/piano/En7.ogg' - if("E#7") soundfile = 'sound/piano/E#7.ogg' - if("Fb7") soundfile = 'sound/piano/Fb7.ogg' - if("Fn7") soundfile = 'sound/piano/Fn7.ogg' - if("F#7") soundfile = 'sound/piano/F#7.ogg' - if("Gb7") soundfile = 'sound/piano/Gb7.ogg' - if("Gn7") soundfile = 'sound/piano/Gn7.ogg' - if("G#7") soundfile = 'sound/piano/G#7.ogg' - if("Ab7") soundfile = 'sound/piano/Ab7.ogg' - if("An7") soundfile = 'sound/piano/An7.ogg' - if("A#7") soundfile = 'sound/piano/A#7.ogg' - if("Bb7") soundfile = 'sound/piano/Bb7.ogg' - if("Bn7") soundfile = 'sound/piano/Bn7.ogg' - if("B#7") soundfile = 'sound/piano/B#7.ogg' - if("Cb8") soundfile = 'sound/piano/Cb8.ogg' - if("Cn8") soundfile = 'sound/piano/Cn8.ogg' - if("C#8") soundfile = 'sound/piano/C#8.ogg' - if("Db8") soundfile = 'sound/piano/Db8.ogg' - if("Dn8") soundfile = 'sound/piano/Dn8.ogg' - if("D#8") soundfile = 'sound/piano/D#8.ogg' - if("Eb8") soundfile = 'sound/piano/Eb8.ogg' - if("En8") soundfile = 'sound/piano/En8.ogg' - if("E#8") soundfile = 'sound/piano/E#8.ogg' - if("Fb8") soundfile = 'sound/piano/Fb8.ogg' - if("Fn8") soundfile = 'sound/piano/Fn8.ogg' - if("F#8") soundfile = 'sound/piano/F#8.ogg' - if("Gb8") soundfile = 'sound/piano/Gb8.ogg' - if("Gn8") soundfile = 'sound/piano/Gn8.ogg' - if("G#8") soundfile = 'sound/piano/G#8.ogg' - if("Ab8") soundfile = 'sound/piano/Ab8.ogg' - if("An8") soundfile = 'sound/piano/An8.ogg' - if("A#8") soundfile = 'sound/piano/A#8.ogg' - if("Bb8") soundfile = 'sound/piano/Bb8.ogg' - if("Bn8") soundfile = 'sound/piano/Bn8.ogg' - if("B#8") soundfile = 'sound/piano/B#8.ogg' - if("Cb9") soundfile = 'sound/piano/Cb9.ogg' - if("Cn9") soundfile = 'sound/piano/Cn9.ogg' + if("Cn1") soundfile = "sound/[instrumentDir]/Cn1.[instrumentExt]" + if("C#1") soundfile = "sound/[instrumentDir]/C#1.[instrumentExt]" + if("Db1") soundfile = "sound/[instrumentDir]/Db1.[instrumentExt]" + if("Dn1") soundfile = "sound/[instrumentDir]/Dn1.[instrumentExt]" + if("D#1") soundfile = "sound/[instrumentDir]/D#1.[instrumentExt]" + if("Eb1") soundfile = "sound/[instrumentDir]/Eb1.[instrumentExt]" + if("En1") soundfile = "sound/[instrumentDir]/En1.[instrumentExt]" + if("E#1") soundfile = "sound/[instrumentDir]/E#1.[instrumentExt]" + if("Fb1") soundfile = "sound/[instrumentDir]/Fb1.[instrumentExt]" + if("Fn1") soundfile = "sound/[instrumentDir]/Fn1.[instrumentExt]" + if("F#1") soundfile = "sound/[instrumentDir]/F#1.[instrumentExt]" + if("Gb1") soundfile = "sound/[instrumentDir]/Gb1.[instrumentExt]" + if("Gn1") soundfile = "sound/[instrumentDir]/Gn1.[instrumentExt]" + if("G#1") soundfile = "sound/[instrumentDir]/G#1.[instrumentExt]" + if("Ab1") soundfile = "sound/[instrumentDir]/Ab1.[instrumentExt]" + if("An1") soundfile = "sound/[instrumentDir]/An1.[instrumentExt]" + if("A#1") soundfile = "sound/[instrumentDir]/A#1.[instrumentExt]" + if("Bb1") soundfile = "sound/[instrumentDir]/Bb1.[instrumentExt]" + if("Bn1") soundfile = "sound/[instrumentDir]/Bn1.[instrumentExt]" + if("B#1") soundfile = "sound/[instrumentDir]/B#1.[instrumentExt]" + if("Cb2") soundfile = "sound/[instrumentDir]/Cb2.[instrumentExt]" + if("Cn2") soundfile = "sound/[instrumentDir]/Cn2.[instrumentExt]" + if("C#2") soundfile = "sound/[instrumentDir]/C#2.[instrumentExt]" + if("Db2") soundfile = "sound/[instrumentDir]/Db2.[instrumentExt]" + if("Dn2") soundfile = "sound/[instrumentDir]/Dn2.[instrumentExt]" + if("D#2") soundfile = "sound/[instrumentDir]/D#2.[instrumentExt]" + if("Eb2") soundfile = "sound/[instrumentDir]/Eb2.[instrumentExt]" + if("En2") soundfile = "sound/[instrumentDir]/En2.[instrumentExt]" + if("E#2") soundfile = "sound/[instrumentDir]/E#2.[instrumentExt]" + if("Fb2") soundfile = "sound/[instrumentDir]/Fb2.[instrumentExt]" + if("Fn2") soundfile = "sound/[instrumentDir]/Fn2.[instrumentExt]" + if("F#2") soundfile = "sound/[instrumentDir]/F#2.[instrumentExt]" + if("Gb2") soundfile = "sound/[instrumentDir]/Gb2.[instrumentExt]" + if("Gn2") soundfile = "sound/[instrumentDir]/Gn2.[instrumentExt]" + if("G#2") soundfile = "sound/[instrumentDir]/G#2.[instrumentExt]" + if("Ab2") soundfile = "sound/[instrumentDir]/Ab2.[instrumentExt]" + if("An2") soundfile = "sound/[instrumentDir]/An2.[instrumentExt]" + if("A#2") soundfile = "sound/[instrumentDir]/A#2.[instrumentExt]" + if("Bb2") soundfile = "sound/[instrumentDir]/Bb2.[instrumentExt]" + if("Bn2") soundfile = "sound/[instrumentDir]/Bn2.[instrumentExt]" + if("B#2") soundfile = "sound/[instrumentDir]/B#2.[instrumentExt]" + if("Cb3") soundfile = "sound/[instrumentDir]/Cb3.[instrumentExt]" + if("Cn3") soundfile = "sound/[instrumentDir]/Cn3.[instrumentExt]" + if("C#3") soundfile = "sound/[instrumentDir]/C#3.[instrumentExt]" + if("Db3") soundfile = "sound/[instrumentDir]/Db3.[instrumentExt]" + if("Dn3") soundfile = "sound/[instrumentDir]/Dn3.[instrumentExt]" + if("D#3") soundfile = "sound/[instrumentDir]/D#3.[instrumentExt]" + if("Eb3") soundfile = "sound/[instrumentDir]/Eb3.[instrumentExt]" + if("En3") soundfile = "sound/[instrumentDir]/En3.[instrumentExt]" + if("E#3") soundfile = "sound/[instrumentDir]/E#3.[instrumentExt]" + if("Fb3") soundfile = "sound/[instrumentDir]/Fb3.[instrumentExt]" + if("Fn3") soundfile = "sound/[instrumentDir]/Fn3.[instrumentExt]" + if("F#3") soundfile = "sound/[instrumentDir]/F#3.[instrumentExt]" + if("Gb3") soundfile = "sound/[instrumentDir]/Gb3.[instrumentExt]" + if("Gn3") soundfile = "sound/[instrumentDir]/Gn3.[instrumentExt]" + if("G#3") soundfile = "sound/[instrumentDir]/G#3.[instrumentExt]" + if("Ab3") soundfile = "sound/[instrumentDir]/Ab3.[instrumentExt]" + if("An3") soundfile = "sound/[instrumentDir]/An3.[instrumentExt]" + if("A#3") soundfile = "sound/[instrumentDir]/A#3.[instrumentExt]" + if("Bb3") soundfile = "sound/[instrumentDir]/Bb3.[instrumentExt]" + if("Bn3") soundfile = "sound/[instrumentDir]/Bn3.[instrumentExt]" + if("B#3") soundfile = "sound/[instrumentDir]/B#3.[instrumentExt]" + if("Cb4") soundfile = "sound/[instrumentDir]/Cb4.[instrumentExt]" + if("Cn4") soundfile = "sound/[instrumentDir]/Cn4.[instrumentExt]" + if("C#4") soundfile = "sound/[instrumentDir]/C#4.[instrumentExt]" + if("Db4") soundfile = "sound/[instrumentDir]/Db4.[instrumentExt]" + if("Dn4") soundfile = "sound/[instrumentDir]/Dn4.[instrumentExt]" + if("D#4") soundfile = "sound/[instrumentDir]/D#4.[instrumentExt]" + if("Eb4") soundfile = "sound/[instrumentDir]/Eb4.[instrumentExt]" + if("En4") soundfile = "sound/[instrumentDir]/En4.[instrumentExt]" + if("E#4") soundfile = "sound/[instrumentDir]/E#4.[instrumentExt]" + if("Fb4") soundfile = "sound/[instrumentDir]/Fb4.[instrumentExt]" + if("Fn4") soundfile = "sound/[instrumentDir]/Fn4.[instrumentExt]" + if("F#4") soundfile = "sound/[instrumentDir]/F#4.[instrumentExt]" + if("Gb4") soundfile = "sound/[instrumentDir]/Gb4.[instrumentExt]" + if("Gn4") soundfile = "sound/[instrumentDir]/Gn4.[instrumentExt]" + if("G#4") soundfile = "sound/[instrumentDir]/G#4.[instrumentExt]" + if("Ab4") soundfile = "sound/[instrumentDir]/Ab4.[instrumentExt]" + if("An4") soundfile = "sound/[instrumentDir]/An4.[instrumentExt]" + if("A#4") soundfile = "sound/[instrumentDir]/A#4.[instrumentExt]" + if("Bb4") soundfile = "sound/[instrumentDir]/Bb4.[instrumentExt]" + if("Bn4") soundfile = "sound/[instrumentDir]/Bn4.[instrumentExt]" + if("B#4") soundfile = "sound/[instrumentDir]/B#4.[instrumentExt]" + if("Cb5") soundfile = "sound/[instrumentDir]/Cb5.[instrumentExt]" + if("Cn5") soundfile = "sound/[instrumentDir]/Cn5.[instrumentExt]" + if("C#5") soundfile = "sound/[instrumentDir]/C#5.[instrumentExt]" + if("Db5") soundfile = "sound/[instrumentDir]/Db5.[instrumentExt]" + if("Dn5") soundfile = "sound/[instrumentDir]/Dn5.[instrumentExt]" + if("D#5") soundfile = "sound/[instrumentDir]/D#5.[instrumentExt]" + if("Eb5") soundfile = "sound/[instrumentDir]/Eb5.[instrumentExt]" + if("En5") soundfile = "sound/[instrumentDir]/En5.[instrumentExt]" + if("E#5") soundfile = "sound/[instrumentDir]/E#5.[instrumentExt]" + if("Fb5") soundfile = "sound/[instrumentDir]/Fb5.[instrumentExt]" + if("Fn5") soundfile = "sound/[instrumentDir]/Fn5.[instrumentExt]" + if("F#5") soundfile = "sound/[instrumentDir]/F#5.[instrumentExt]" + if("Gb5") soundfile = "sound/[instrumentDir]/Gb5.[instrumentExt]" + if("Gn5") soundfile = "sound/[instrumentDir]/Gn5.[instrumentExt]" + if("G#5") soundfile = "sound/[instrumentDir]/G#5.[instrumentExt]" + if("Ab5") soundfile = "sound/[instrumentDir]/Ab5.[instrumentExt]" + if("An5") soundfile = "sound/[instrumentDir]/An5.[instrumentExt]" + if("A#5") soundfile = "sound/[instrumentDir]/A#5.[instrumentExt]" + if("Bb5") soundfile = "sound/[instrumentDir]/Bb5.[instrumentExt]" + if("Bn5") soundfile = "sound/[instrumentDir]/Bn5.[instrumentExt]" + if("B#5") soundfile = "sound/[instrumentDir]/B#5.[instrumentExt]" + if("Cb6") soundfile = "sound/[instrumentDir]/Cb6.[instrumentExt]" + if("Cn6") soundfile = "sound/[instrumentDir]/Cn6.[instrumentExt]" + if("C#6") soundfile = "sound/[instrumentDir]/C#6.[instrumentExt]" + if("Db6") soundfile = "sound/[instrumentDir]/Db6.[instrumentExt]" + if("Dn6") soundfile = "sound/[instrumentDir]/Dn6.[instrumentExt]" + if("D#6") soundfile = "sound/[instrumentDir]/D#6.[instrumentExt]" + if("Eb6") soundfile = "sound/[instrumentDir]/Eb6.[instrumentExt]" + if("En6") soundfile = "sound/[instrumentDir]/En6.[instrumentExt]" + if("E#6") soundfile = "sound/[instrumentDir]/E#6.[instrumentExt]" + if("Fb6") soundfile = "sound/[instrumentDir]/Fb6.[instrumentExt]" + if("Fn6") soundfile = "sound/[instrumentDir]/Fn6.[instrumentExt]" + if("F#6") soundfile = "sound/[instrumentDir]/F#6.[instrumentExt]" + if("Gb6") soundfile = "sound/[instrumentDir]/Gb6.[instrumentExt]" + if("Gn6") soundfile = "sound/[instrumentDir]/Gn6.[instrumentExt]" + if("G#6") soundfile = "sound/[instrumentDir]/G#6.[instrumentExt]" + if("Ab6") soundfile = "sound/[instrumentDir]/Ab6.[instrumentExt]" + if("An6") soundfile = "sound/[instrumentDir]/An6.[instrumentExt]" + if("A#6") soundfile = "sound/[instrumentDir]/A#6.[instrumentExt]" + if("Bb6") soundfile = "sound/[instrumentDir]/Bb6.[instrumentExt]" + if("Bn6") soundfile = "sound/[instrumentDir]/Bn6.[instrumentExt]" + if("B#6") soundfile = "sound/[instrumentDir]/B#6.[instrumentExt]" + if("Cb7") soundfile = "sound/[instrumentDir]/Cb7.[instrumentExt]" + if("Cn7") soundfile = "sound/[instrumentDir]/Cn7.[instrumentExt]" + if("C#7") soundfile = "sound/[instrumentDir]/C#7.[instrumentExt]" + if("Db7") soundfile = "sound/[instrumentDir]/Db7.[instrumentExt]" + if("Dn7") soundfile = "sound/[instrumentDir]/Dn7.[instrumentExt]" + if("D#7") soundfile = "sound/[instrumentDir]/D#7.[instrumentExt]" + if("Eb7") soundfile = "sound/[instrumentDir]/Eb7.[instrumentExt]" + if("En7") soundfile = "sound/[instrumentDir]/En7.[instrumentExt]" + if("E#7") soundfile = "sound/[instrumentDir]/E#7.[instrumentExt]" + if("Fb7") soundfile = "sound/[instrumentDir]/Fb7.[instrumentExt]" + if("Fn7") soundfile = "sound/[instrumentDir]/Fn7.[instrumentExt]" + if("F#7") soundfile = "sound/[instrumentDir]/F#7.[instrumentExt]" + if("Gb7") soundfile = "sound/[instrumentDir]/Gb7.[instrumentExt]" + if("Gn7") soundfile = "sound/[instrumentDir]/Gn7.[instrumentExt]" + if("G#7") soundfile = "sound/[instrumentDir]/G#7.[instrumentExt]" + if("Ab7") soundfile = "sound/[instrumentDir]/Ab7.[instrumentExt]" + if("An7") soundfile = "sound/[instrumentDir]/An7.[instrumentExt]" + if("A#7") soundfile = "sound/[instrumentDir]/A#7.[instrumentExt]" + if("Bb7") soundfile = "sound/[instrumentDir]/Bb7.[instrumentExt]" + if("Bn7") soundfile = "sound/[instrumentDir]/Bn7.[instrumentExt]" + if("B#7") soundfile = "sound/[instrumentDir]/B#7.[instrumentExt]" + if("Cb8") soundfile = "sound/[instrumentDir]/Cb8.[instrumentExt]" + if("Cn8") soundfile = "sound/[instrumentDir]/Cn8.[instrumentExt]" + if("C#8") soundfile = "sound/[instrumentDir]/C#8.[instrumentExt]" + if("Db8") soundfile = "sound/[instrumentDir]/Db8.[instrumentExt]" + if("Dn8") soundfile = "sound/[instrumentDir]/Dn8.[instrumentExt]" + if("D#8") soundfile = "sound/[instrumentDir]/D#8.[instrumentExt]" + if("Eb8") soundfile = "sound/[instrumentDir]/Eb8.[instrumentExt]" + if("En8") soundfile = "sound/[instrumentDir]/En8.[instrumentExt]" + if("E#8") soundfile = "sound/[instrumentDir]/E#8.[instrumentExt]" + if("Fb8") soundfile = "sound/[instrumentDir]/Fb8.[instrumentExt]" + if("Fn8") soundfile = "sound/[instrumentDir]/Fn8.[instrumentExt]" + if("F#8") soundfile = "sound/[instrumentDir]/F#8.[instrumentExt]" + if("Gb8") soundfile = "sound/[instrumentDir]/Gb8.[instrumentExt]" + if("Gn8") soundfile = "sound/[instrumentDir]/Gn8.[instrumentExt]" + if("G#8") soundfile = "sound/[instrumentDir]/G#8.[instrumentExt]" + if("Ab8") soundfile = "sound/[instrumentDir]/Ab8.[instrumentExt]" + if("An8") soundfile = "sound/[instrumentDir]/An8.[instrumentExt]" + if("A#8") soundfile = "sound/[instrumentDir]/A#8.[instrumentExt]" + if("Bb8") soundfile = "sound/[instrumentDir]/Bb8.[instrumentExt]" + if("Bn8") soundfile = "sound/[instrumentDir]/Bn8.[instrumentExt]" + if("B#8") soundfile = "sound/[instrumentDir]/B#8.[instrumentExt]" + if("Cb9") soundfile = "sound/[instrumentDir]/Cb9.[instrumentExt]" + if("Cn9") soundfile = "sound/[instrumentDir]/Cn9.[instrumentExt]" else return - hearers(15, src) << sound(soundfile) + hearers(15, get_turf(instrumentObj)) << sound(soundfile) -/obj/structure/device/piano/proc/playsong() - do +/datum/song/proc/updateDialog(mob/user as mob) + instrumentObj.updateDialog() // assumes it's an object in world, override if otherwise + +/datum/song/proc/shouldStopPlaying() + return !instrumentObj.anchored // add special cases to stop in subclasses + +/datum/song/proc/playsong(mob/user as mob) + while(repeat >= 0) 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/line in lines) //world << line for(var/beat in text2list(lowertext(line), ",")) //world << "beat: [beat]" var/list/notes = text2list(beat, "/") for(var/note in text2list(notes[1], "-")) //world << "note: [note]" - if(!playing || !anchored)//If the piano is playing, or is loose + if(!playing || shouldStopPlaying())//If the instrument is playing, or special case playing = 0 return if(lentext(note) == 0) @@ -241,45 +239,49 @@ 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])) + sleep(tempo / text2num(notes[2])) else - sleep(song.tempo) - if(repeat > 0) - repeat-- //Infinite loops are baaaad. - while(repeat > 0) + sleep(tempo) + repeat-- + if(repeat >= 0) // don't show the last -1 repeat + updateDialog(user) playing = 0 - updateUsrDialog() + repeat = 0 + updateDialog(user) -/obj/structure/device/piano/attack_hand(var/mob/user as mob) - if(!anchored) - return +/datum/song/proc/interact(mob/user as mob) + var/dat = "" - usr.machine = src - var/dat = "Piano" - - if(song) - if(song.lines.len > 0 && !(playing)) - dat += "Play Song

" - dat += "Repeat Song: [repeat] times.

" - if(playing) - dat += "Stop Playing
" - dat += "Repeats left: [repeat].

" + if(lines.len > 0) + dat += "

Playback

" + if(!playing) + dat += "Play Stop

" + dat += "Repeat Song: " + dat += repeat > 0 ? "--" : "--" + dat += " [repeat] times " + dat += repeat < max_repeats ? "++" : "++" + dat += "
" + else + dat += "Play Stop
" + dat += "Repeats left: [repeat]
" if(!edit) - dat += "Show Editor

" + dat += "
Show Editor
" else - dat += "Hide Editor
" - 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

" + dat += "

Editing

" + dat += "Hide Editor" + dat += " Start a New Song" + dat += " Import a Song

" + var/calctempo = round(600 / tempo) + var/calcstep = tempo - 600 / (calctempo+1) + var/calcstep_b = tempo - 600 / (calctempo+10) + dat += "Tempo: -- [calctempo] BPM ++

" + var/linecount = 0 + for(var/line in lines) + linecount += 1 + dat += "Line [linecount]: Edit X [line]
" + dat += "Add Line

" if(help) - dat += "Hide 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.
@@ -292,121 +294,171 @@ 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 + Combined, an example is: E-E4/4,F#/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") + dat += "Show Help
" -/obj/structure/device/piano/Topic(href, href_list) + var/datum/browser/popup = new(user, "instrument", instrumentObj.name, 700, 500) + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(instrumentObj.icon, instrumentObj.icon_state)) + popup.open() - if(!in_range(src, usr) || issilicon(usr) || !anchored || !usr.canmove || usr.restrained()) - usr << browse(null, "window=piano;size=700x300") - onclose(usr, "piano") + +/datum/song/Topic(href, href_list) + if(!in_range(instrumentObj, usr) || issilicon(usr) || !isliving(usr) || !usr.canmove || usr.restrained()) + usr << browse(null, "window=instrument") + usr.unset_machine() return + instrumentObj.add_fingerprint(usr) + if(href_list["newsong"]) - song = new() - else if(song) - if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops. - if(playing) return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing. - var/tempnum = input("How many times do you want to repeat this piece? (max:10)") as num|null - if(tempnum > 10) - tempnum = 10 - if(tempnum < 0) - tempnum = 0 - repeat = round(tempnum) + lines = new() + tempo = 5 // default 120 BPM + name = "" - else if(href_list["tempo"]) - song.tempo += round(text2num(href_list["tempo"])) - if(song.tempo < 1) - song.tempo = 1 - - else if(href_list["play"]) - if(song) - playing = 1 - spawn() playsong() - - else if(href_list["newline"]) - var/newline = html_encode(input("Enter your line: ", "Piano") as text|null) - if(!newline) + else if(href_list["import"]) + var/t = "" + do + t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message) + if(!in_range(instrumentObj, usr)) return - if(song.lines.len > 50) - return - if(lentext(newline) > 50) - newline = copytext(newline, 1, 50) - song.lines.Add(newline) - else if(href_list["deleteline"]) - var/num = round(text2num(href_list["deleteline"])) - if(num > song.lines.len || num < 1) - return - song.lines.Cut(num, num+1) + if(lentext(t) >= 3072) + 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) > 3072) - else if(href_list["modifyline"]) - var/num = round(text2num(href_list["modifyline"]),1) - var/content = html_encode(input("Enter your line: ", "Piano", song.lines[num]) as text|null) - if(!content) - return - if(lentext(content) > 50) - content = copytext(content, 1, 50) - if(num > song.lines.len || num < 1) - return - song.lines[num] = content + //split into lines + spawn() + lines = text2list(t, "\n") + if(copytext(lines[1],1,6) == "BPM: ") + tempo = 600 / text2num(copytext(lines[1],6)) + lines.Cut(1,2) + else + tempo = 5 // default 120 BPM + 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++ + updateDialog(usr) // make sure updates when complete - else if(href_list["stop"]) - playing = 0 + else if(href_list["help"]) + help = text2num(href_list["help"]) - 1 - else if(href_list["help"]) - help = text2num(href_list["help"]) - 1 + else if(href_list["edit"]) + edit = text2num(href_list["edit"]) - 1 - else if(href_list["edit"]) - edit = text2num(href_list["edit"]) - 1 + if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops. + if(playing) + return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing. + repeat += round(text2num(href_list["repeat"])) + if(repeat < 0) + repeat = 0 + if(repeat > max_repeats) + repeat = max_repeats - else if(href_list["import"]) - var/t = "" - do - t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", src.name), t) as message) - if (!in_range(src, usr)) - return + else if(href_list["tempo"]) + tempo += text2num(href_list["tempo"]) + if(tempo < 1) + tempo = 1 + if(tempo > 600) + tempo = 600 - if(lentext(t) >= 3072) - 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) > 3072) + else if(href_list["play"]) + playing = 1 + spawn() + playsong(usr) - //split into lines - spawn() - var/list/lines = 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() + else if(href_list["newline"]) + var/newline = html_encode(input("Enter your line: ", instrumentObj.name) as text|null) + if(!newline || !in_range(instrumentObj, usr)) + return + if(lines.len > 50) + return + if(lentext(newline) > 50) + newline = copytext(newline, 1, 50) + lines.Add(newline) - add_fingerprint(usr) - updateUsrDialog() + else if(href_list["deleteline"]) + var/num = round(text2num(href_list["deleteline"])) + if(num > lines.len || num < 1) + return + lines.Cut(num, num+1) + + else if(href_list["modifyline"]) + var/num = round(text2num(href_list["modifyline"]),1) + var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null) + if(!content || !in_range(instrumentObj, usr)) + return + if(lentext(content) > 50) + content = copytext(content, 1, 50) + if(num > lines.len || num < 1) + return + lines[num] = content + + else if(href_list["stop"]) + playing = 0 + + updateDialog(usr) return + +// subclass for handheld instruments, like violin +/datum/song/handheld + + updateDialog(mob/user as mob) + instrumentObj.interact(user) + + shouldStopPlaying() + return !isliving(instrumentObj.loc) + + +////////////////////////////////////////////////////////////////////////// + + +/obj/structure/device/piano + name = "space minimoog" + icon = 'icons/obj/musician.dmi' + icon_state = "minimoog" + anchored = 1 + density = 1 + var/datum/song/song + + +/obj/structure/device/piano/New() + song = new("piano", src) + + if(prob(50)) + name = "space minimoog" + desc = "This is a minimoog, like a space piano, but more spacey!" + icon_state = "minimoog" + else + name = "space piano" + desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't." + icon_state = "piano" + +/obj/structure/device/piano/attack_hand(mob/user as mob) + interact(user) + +/obj/structure/device/piano/interact(mob/user as mob) + if(!user || !anchored) + return + + user.set_machine(src) + song.interact(user) + /obj/structure/device/piano/attackby(obj/item/O as obj, mob/user as mob) if (istype(O, /obj/item/weapon/wrench)) if (anchored) From 9e50852028b8e6f0a66172fd278331c666754806 Mon Sep 17 00:00:00 2001 From: Pete Goodfellow Date: Sun, 24 Mar 2013 16:00:36 +0000 Subject: [PATCH 03/14] Fixes a typo in the dirty floor MC setup. \ref -> \red. --- code/controllers/master_controller.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index cdebd83aca8..4eaadfc5896 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -94,7 +94,7 @@ datum/controller/game_controller/proc/setup_objects() var/obj/machinery/atmospherics/unary/vent_scrubber/T = U T.broadcast_status() - world << "\ref \b Making a mess..." + world << "\red \b Making a mess..." sleep(-1) for(var/turf/simulated/floor/F in world) F.MakeDirty() From 2b3c769662785c48ced3214dc8a76284b297a19e Mon Sep 17 00:00:00 2001 From: Pete Goodfellow Date: Sun, 24 Mar 2013 16:01:49 +0000 Subject: [PATCH 04/14] Makes /obj/effect/decal/cleanable/dirt mouse_opacity 0, as it covers the whole tile and prevents people from crowbarring it up. It can still be cleaned by mopping the tile. --- code/game/objects/effects/decals/Cleanable/misc.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm index 67c82a8f440..3d260fe3b05 100644 --- a/code/game/objects/effects/decals/Cleanable/misc.dm +++ b/code/game/objects/effects/decals/Cleanable/misc.dm @@ -26,12 +26,13 @@ /obj/effect/decal/cleanable/dirt name = "dirt" desc = "Someone should clean that up." + icon = 'icons/effects/effects.dmi' + icon_state = "dirt" gender = PLURAL density = 0 anchored = 1 layer = 2 - icon = 'icons/effects/effects.dmi' - icon_state = "dirt" + mouse_opacity = 0 /obj/effect/decal/cleanable/flour name = "flour" From 38093ee48923fdae9a8093c35cef510888be8de7 Mon Sep 17 00:00:00 2001 From: Pete Goodfellow Date: Sun, 24 Mar 2013 16:03:45 +0000 Subject: [PATCH 05/14] Standardises dirtystation.dm, and vastly reduces the chances for 'interesting' dirt, such as blood and vomit. Blood in particular is much rarer. Makes virology always clean. --- code/game/turfs/simulated/dirtystation.dm | 113 +++++++++++----------- 1 file changed, 54 insertions(+), 59 deletions(-) diff --git a/code/game/turfs/simulated/dirtystation.dm b/code/game/turfs/simulated/dirtystation.dm index 058a24bc4dd..f5ea7bddc90 100644 --- a/code/game/turfs/simulated/dirtystation.dm +++ b/code/game/turfs/simulated/dirtystation.dm @@ -1,7 +1,7 @@ //Janitors! Janitors, janitors, janitors! -Sayu -// Conspicuously not-recent versions of suspicious cleanables +//Conspicuously not-recent versions of suspicious cleanables /obj/effect/decal/cleanable/blood/old name = "dried blood" @@ -30,117 +30,112 @@ desc = "Looks like nobody has touched this in a while." -// Making the station dirty, one tile at a time. Called by master controller's setup_objects +//Making the station dirty, one tile at a time. Called by master controller's setup_objects /turf/simulated/floor/proc/MakeDirty() - if(prob(66)) // fastest possible exit 2/3 of the time + if(prob(66)) //fastest possible exit 2/3 of the time return // These look weird if you make them dirty - if(istype(src,/turf/simulated/floor/carpet) || istype(src,/turf/simulated/floor/grass) || istype(src,/turf/simulated/floor/beach) || istype(src,/turf/simulated/floor/holofloor) || istype(src,/turf/simulated/floor/plating/snow) || istype(src,/turf/simulated/floor/plating/ironsand)) + if(istype(src, /turf/simulated/floor/carpet) || istype(src, /turf/simulated/floor/grass) || istype(src, /turf/simulated/floor/beach) || istype(src, /turf/simulated/floor/holofloor) || istype(src, /turf/simulated/floor/plating/snow) || istype(src, /turf/simulated/floor/plating/ironsand)) return var/area/A = loc - // zero dirt - if(!istype(A) || istype(A,/area/centcom) || istype(A,/area/holodeck) || istype(A,/area/library) || istype(A,/area/janitor) || istype(A,/area/chapel) || istype(A,/area/mine/explored) || istype(A,/area/mine/unexplored) || istype(A,/area/solar) || istype(A,/area/atmos)) + //zero dirt + if(!istype(A) || istype(A, /area/centcom) || istype(A, /area/holodeck) || istype(A, /area/library) || istype(A, /area/janitor) || istype(A, /area/chapel) || istype(A, /area/mine/explored) || istype(A, /area/mine/unexplored) || istype(A, /area/solar) || istype(A, /area/atmos) || istype(A, /area/medical/virology)) return - // high dirt - 1/3 - if(istype(A,/area/toxins/test_area) || istype(A,/area/mine/production) || istype(A,/area/mine/living_quarters) || istype(A,/area/mine/north_outpost) || istype(A,/area/mine/west_outpost) || istype(A,/area/wreck) || istype(A,/area/derelict) || istype(A,/area/djstation)) - new/obj/effect/decal/cleanable/dirt(src) // vanilla, but it works + //high dirt - 1/3 + if(istype(A, /area/toxins/test_area) || istype(A, /area/mine/production) || istype(A, /area/mine/living_quarters) || istype(A, /area/mine/north_outpost) || istype(A, /area/mine/west_outpost) || istype(A, /area/wreck) || istype(A, /area/derelict) || istype(A, /area/djstation)) + new /obj/effect/decal/cleanable/dirt(src) //vanilla, but it works return - if(prob(80))// mid dirt - 1/15 + if(prob(80)) //mid dirt - 1/15 return - if(istype(A,/area/engine) || istype(A,/area/assembly) || istype(A,/area/maintenance) || istype(A,/area/construction)) - // Blood, sweat, and oil. Oh, and dirt. - if(prob(5)) - new/obj/effect/decal/cleanable/blood/old(src) + if(istype(A, /area/engine) || istype(A,/area/assembly) || istype(A,/area/maintenance) || istype(A,/area/construction)) + //Blood, sweat, and oil. Oh, and dirt. + if(prob(3)) + new /obj/effect/decal/cleanable/blood/old(src) else - if(prob(55)) - if(prob(5)) - new/obj/effect/decal/cleanable/robot_debris/old(src) + if(prob(35)) + if(prob(4)) + new /obj/effect/decal/cleanable/robot_debris/old(src) else - new/obj/effect/decal/cleanable/oil(src) + new /obj/effect/decal/cleanable/oil(src) else - new/obj/effect/decal/cleanable/dirt(src) + new /obj/effect/decal/cleanable/dirt(src) return - if(istype(A,/area/crew_quarters/toilet) || istype(A,/area/crew_quarters/locker/locker_toilet) || istype(A,/area/crew_quarters/bar)) - if(prob(60)) - if(prob(70)) - new/obj/effect/decal/cleanable/vomit/old(src) + if(istype(A, /area/crew_quarters/toilet) || istype(A, /area/crew_quarters/locker/locker_toilet) || istype(A, /area/crew_quarters/bar)) + if(prob(40)) + if(prob(90)) + new /obj/effect/decal/cleanable/vomit/old(src) else - new/obj/effect/decal/cleanable/blood/old(src) + new /obj/effect/decal/cleanable/blood/old(src) else - new/obj/effect/decal/cleanable/dirt(src) + new /obj/effect/decal/cleanable/dirt(src) return - if(istype(A,/area/quartermaster)) + if(istype(A, /area/quartermaster)) if(prob(75)) - new/obj/effect/decal/cleanable/dirt(src) + new /obj/effect/decal/cleanable/dirt(src) else - new/obj/effect/decal/cleanable/oil(src) + new /obj/effect/decal/cleanable/oil(src) return - if(prob(75))// low dirt - 1/60 + if(prob(75)) //low dirt - 1/60 return - if(istype(A,/area/turret_protected) || istype(A,/area/security)) // chance of incident - if(prob(25)) - if(prob(10)) - new/obj/effect/decal/cleanable/blood/gibs/old(src) + if(istype(A, /area/turret_protected) || istype(A, /area/security)) //chance of incident + if(prob(20)) + if(prob(5)) + new /obj/effect/decal/cleanable/blood/gibs/old(src) else - new/obj/effect/decal/cleanable/blood/old(src) + new /obj/effect/decal/cleanable/blood/old(src) else - new/obj/effect/decal/cleanable/dirt(src) + new /obj/effect/decal/cleanable/dirt(src) return - if(istype(A,/area/crew_quarters/kitchen)) // Kitchen messes + if(istype(A, /area/crew_quarters/kitchen)) //Kitchen messes if(prob(60)) if(prob(50)) - new/obj/effect/decal/cleanable/egg_smudge(src) + new /obj/effect/decal/cleanable/egg_smudge(src) else - new/obj/effect/decal/cleanable/flour(src) - else - if(prob(33)) - new/obj/effect/decal/cleanable/dirt(src) - else - new/obj/effect/decal/cleanable/blood/old(src) + new /obj/effect/decal/cleanable/flour(src) + else if(prob(33)) + new /obj/effect/decal/cleanable/dirt(src) return - if(istype(A,/area/medical)) // Kept clean, but chance of blood + if(istype(A, /area/medical)) //Kept clean, but chance of blood if(prob(66)) - if(prob(10)) - new/obj/effect/decal/cleanable/blood/gibs/old(src) + if(prob(5)) + new /obj/effect/decal/cleanable/blood/gibs/old(src) else - new/obj/effect/decal/cleanable/blood/old(src) + new /obj/effect/decal/cleanable/blood/old(src) else - if(prob(40)) - if(istype(A,/area/medical/morgue)) - new/obj/item/weapon/ectoplasm(src) + if(prob(30)) + if(istype(A, /area/medical/morgue)) + new /obj/item/weapon/ectoplasm(src) else - new/obj/effect/decal/cleanable/vomit/old(src) - else - new/obj/effect/decal/cleanable/dirt(src) + new /obj/effect/decal/cleanable/vomit/old(src) return - if(istype(A,/area/toxins)) + + if(istype(A, /area/toxins)) if(prob(80)) - new/obj/effect/decal/cleanable/dirt(src) + new /obj/effect/decal/cleanable/dirt(src) else - new/obj/effect/decal/cleanable/greenglow(src) // this cleans itself up but it might startle you when you see it. + new /obj/effect/decal/cleanable/greenglow(src) //this cleans itself up but it might startle you when you see it. return //default - new/obj/effect/decal/cleanable/dirt(src) - return - + new /obj/effect/decal/cleanable/dirt(src) + return \ No newline at end of file From a389835a309871f220141a5f9222bcadd0f1e17c Mon Sep 17 00:00:00 2001 From: Pete Goodfellow Date: Sun, 24 Mar 2013 23:43:58 +0000 Subject: [PATCH 06/14] Abstract items no longer show up on examine. --- code/modules/mob/living/carbon/human/examine.dm | 4 ++-- code/modules/mob/mob_grab.dm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index f100161316e..2eb34249e7a 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -104,14 +104,14 @@ msg += "[t_He] [t_has] \icon[back] \a [back] on [t_his] back.\n" //left hand - if(l_hand) + if(l_hand && !l_hand.abstract) if(l_hand.blood_DNA) msg += "[t_He] [t_is] holding \icon[l_hand] [l_hand.gender==PLURAL?"some":"a"] blood-stained [l_hand.name] in [t_his] left hand!\n" else msg += "[t_He] [t_is] holding \icon[l_hand] \a [l_hand] in [t_his] left hand.\n" //right hand - if(r_hand) + if(r_hand && !r_hand.abstract) if(r_hand.blood_DNA) msg += "[t_He] [t_is] holding \icon[r_hand] [r_hand.gender==PLURAL?"some":"a"] blood-stained [r_hand.name] in [t_his] right hand!\n" else diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index dcf41997aa0..7e0cb82f2e6 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -12,7 +12,7 @@ var/last_upgrade = 0 layer = 21 - abstract = 1.0 + abstract = 1 item_state = "nothing" w_class = 5.0 From 33657359217da6e58ca194c3747e995502e67bea Mon Sep 17 00:00:00 2001 From: "Rastaf.zero" Date: Mon, 25 Mar 2013 18:41:07 +0400 Subject: [PATCH 07/14] Fixes #88 panic syphon status gets stuck on. Also air alarm "off" state returns back. It turns off all the machines in area. --- .../components/unary/vent_scrubber.dm | 30 +++++++++---------- code/game/machinery/alarm.dm | 9 +++--- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm index 4c386f44ec4..5da8ed0d964 100644 --- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -173,13 +173,13 @@ if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command")) return 0 - if(signal.data["power"] != null) + if("power" in signal.data) on = text2num(signal.data["power"]) - if(signal.data["power_toggle"] != null) + if("power_toggle" in signal.data) on = !on - if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing - panic = text2num(signal.data["panic_siphon"] != null) + if("panic_siphon" in signal.data) //must be before if("scrubbing" thing + panic = text2num(signal.data["panic_siphon"]) if(panic) on = 1 scrubbing = 0 @@ -187,7 +187,7 @@ else scrubbing = 1 volume_rate = initial(volume_rate) - if(signal.data["toggle_panic_siphon"] != null) + if("toggle_panic_siphon" in signal.data) panic = !panic if(panic) on = 1 @@ -197,31 +197,31 @@ scrubbing = 1 volume_rate = initial(volume_rate) - if(signal.data["scrubbing"] != null) + if("scrubbing" in signal.data) scrubbing = text2num(signal.data["scrubbing"]) - if(signal.data["toggle_scrubbing"]) + if("toggle_scrubbing" in signal.data) scrubbing = !scrubbing - if(signal.data["co2_scrub"] != null) + if("co2_scrub" in signal.data) scrub_CO2 = text2num(signal.data["co2_scrub"]) - if(signal.data["toggle_co2_scrub"]) + if("toggle_co2_scrub" in signal.data) scrub_CO2 = !scrub_CO2 - if(signal.data["tox_scrub"] != null) + if("tox_scrub" in signal.data) scrub_Toxins = text2num(signal.data["tox_scrub"]) - if(signal.data["toggle_tox_scrub"]) + if("toggle_tox_scrub" in signal.data) scrub_Toxins = !scrub_Toxins - if(signal.data["n2o_scrub"] != null) + if("n2o_scrub" in signal.data) scrub_N2O = text2num(signal.data["n2o_scrub"]) - if(signal.data["toggle_n2o_scrub"]) + if("toggle_n2o_scrub" in signal.data) scrub_N2O = !scrub_N2O - if(signal.data["init"] != null) + if("init" in signal.data) name = signal.data["init"] return - if(signal.data["status"] != null) + if("status" in signal.data) spawn(2) broadcast_status() return //do not update_icon diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index f5606fa39cc..c74b90627d1 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -842,15 +842,16 @@ table tr:first-child th:first-child { border: none;} send_signal(device_id, list( "power"= 0 )) - /*if(AALARM_MODE_OFF) Commented out cause the "turn off panic" uses scrubbing mode now instead. + if(AALARM_MODE_OFF) for(var/device_id in alarm_area.air_scrub_names) send_signal(device_id, list( - "panic_siphon" = 0 + "panic_siphon"= 0, + "power"= 0 )) for(var/device_id in alarm_area.air_vent_names) send_signal(device_id, list( - "power"= 1 - ))*/ + "power"= 0 + )) /obj/machinery/alarm/update_icon() if(wiresexposed) From fbd46f1f532d7dafb72bb8d8ba3d365c952c45e6 Mon Sep 17 00:00:00 2001 From: Giacomand Date: Mon, 25 Mar 2013 16:44:57 +0000 Subject: [PATCH 08/14] * Removing an unneeded exploitable snippet of code. (The game doesn't even use it) --- code/game/gamemodes/malfunction/malfunction.dm | 7 ------- 1 file changed, 7 deletions(-) diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index f1d371ee988..c1a0047c1e9 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -142,13 +142,6 @@ return ..() //check for shuttle and nuke -/datum/game_mode/malfunction/Topic(href, href_list) - ..() - if (href_list["ai_win"]) - ai_win() - return - - /datum/game_mode/malfunction/proc/takeover() set category = "Malfunction" set name = "System Override" From d53fdcaededcf2e0bfa10f005adcff6f2d7af8a6 Mon Sep 17 00:00:00 2001 From: Pete Goodfellow Date: Mon, 25 Mar 2013 17:15:14 +0000 Subject: [PATCH 09/14] Set the twohanded.dm offhand item to abstract = 1. --- code/game/objects/items/weapons/twohanded.dm | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 8883431014b..c02a1b69a4e 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -89,17 +89,20 @@ user.put_in_inactive_hand(O) return + ///////////OFFHAND/////////////// /obj/item/weapon/twohanded/offhand - w_class = 5.0 - icon_state = "offhand" name = "offhand" + icon_state = "offhand" + w_class = 5.0 + abstract = 1 - unwield() - del(src) +/obj/item/weapon/twohanded/offhand/unwield() + del(src) + +/obj/item/weapon/twohanded/offhand/wield() + del(src) - wield() - del(src) /* * Fireaxe From bf4b58cc7d58d9501c0338af4651bb48a596e849 Mon Sep 17 00:00:00 2001 From: Uristqwerty Date: Mon, 25 Mar 2013 16:28:04 -0400 Subject: [PATCH 10/14] Fixed infinite loop in powernet rebuild. If a machine was not anchored, it would spin forever, doing nothing. Fixed on baystation a while ago. --- code/modules/power/power.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index d9cfa042f35..c1363055922 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -183,6 +183,9 @@ M.powernet = PN P = M.get_connections() + else + return + if(P.len == 0) return O = P[1] From 37bff0076aa69725140399baeb70c285d3d3c117 Mon Sep 17 00:00:00 2001 From: Carnie Date: Tue, 26 Mar 2013 04:08:23 +0000 Subject: [PATCH 11/14] Update README.txt Added a (rubbish) guide to downloading the source code. --- README.txt | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 2c3c7210ef3..2f949788d99 100644 --- a/README.txt +++ b/README.txt @@ -4,6 +4,25 @@ Website: http://nanotrasen.com Code: https://github.com/tgstation/-tg-station IRC: irc://irc.rizon.net/tgstation13 +================================================================================ +DOWNLOADING +================================================================================ +There are a number of ways to download tgstation13. I've listed 3 here (easiest first). + +Option 1: Download the source code as a zip by clicking the ZIP button in the code tab of https://github.com/tgstation/-tg-station +(note: this will use a lot of bandwidth if you wish to update andis alot of hassle if you want to make any changes at all, so I don't recommend it) + +(Option 2 & 3): Install Git-scm from here first: http://git-scm.com/download/win +Option 2: +Install GitHub::windows from http://windows.github.com/ +It handles most of the setup/configuraton of Git for you. +Then you simply search for tgstation repository and click the big clone button. + +Option 3: +Follow this guide linked in Giacom's post thread here: http://forums.nanotrasen.com/viewtopic.php?f=16&t=12552 +(I recommend usng git-scm rather than the git CLI suggested by the guide linked to in that thread) + + ================================================================================ INSTALLATION ================================================================================ @@ -73,4 +92,4 @@ IRC Bot Setup ================================================================================ Included in the SVN is an IRC bot capable of relaying adminhelps to a specified IRC channel/server (thanks to Skibiliano) -Instructions for bot setup are included in the /bot/ folder along with the bot/relay script itself \ No newline at end of file +Instructions for bot setup are included in the /bot/ folder along with the bot/relay script itself From 10bd174a0350319a60a6ca409b2e500860d0955e Mon Sep 17 00:00:00 2001 From: Cheridan Date: Wed, 27 Mar 2013 00:08:45 -0500 Subject: [PATCH 12/14] Underwear update! Adds two new undie styles, a modest tankini for ladies and red briefs for the guys. Adjusts a couple hardcoded lines to make adding more undies in the future easier. Adds dressers! Similar to mirrors, they let you change your underpants. --- code/__HELPERS/global_lists.dm | 4 ++-- .../mob/living/carbon/human/update_icons.dm | 2 +- .../mob/new_player/preferences_setup.dm | 2 +- icons/mob/human.dmi | Bin 24562 -> 26123 bytes icons/obj/stationobjs.dmi | Bin 75065 -> 75829 bytes 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 1c06e09a99a..d630d983c05 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -28,8 +28,8 @@ var/global/list/facial_hair_styles_list = list() //stores /datum/sprite_accessor var/global/list/facial_hair_styles_male_list = list() var/global/list/facial_hair_styles_female_list = list() //Underwear -var/global/list/underwear_m = list("White", "Grey", "Green", "Blue", "Black", "Mankini", "Love-Hearts", "Black2", "Grey2", "Stripey", "Kinky", "None") //Curse whoever made male/female underwear diffrent colours -var/global/list/underwear_f = list("Red", "White", "Yellow", "Blue", "Black", "Thong", "Babydoll", "Baby-Blue", "Green", "Pink", "Kinky", "None") +var/global/list/underwear_m = list("White", "Grey", "Green", "Blue", "Black", "Mankini", "Love-Hearts", "Black2", "Grey2", "Stripey", "Kinky", "Red", "None") //Curse whoever made male/female underwear diffrent colours +var/global/list/underwear_f = list("Red", "White", "Yellow", "Blue", "Black", "Thong", "Babydoll", "Baby-Blue", "Green", "Pink", "Kinky", "Tankini", "None") //Backpacks var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel") diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 870bbafe1b9..047c25a1bc3 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -233,7 +233,7 @@ Please contact me on #coderbus IRC. ~Carn x lying_icon.Blend(new/icon('icons/mob/human_face.dmi', "lips_[lip_style]_l"), ICON_OVERLAY) //Underwear - if(underwear >0 && underwear < 12) + if(underwear >0 && underwear < underwear_m.len) if(!fat && !skeleton) stand_icon.Blend(new /icon('icons/mob/human.dmi', "underwear[underwear]_[g]_s"), ICON_OVERLAY) lying_icon.Blend(new /icon('icons/mob/human.dmi', "underwear[underwear]_[g]_l"), ICON_OVERLAY) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 41e6d280cef..7ab0a74932b 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -144,7 +144,7 @@ datum/preferences else preview_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT) - if (underwear < 12) + if (underwear < underwear_m.len) preview_icon.Blend(new /icon('icons/mob/human.dmi', "underwear[underwear]_[g]_s"), ICON_OVERLAY) var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "eyes_s") diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi index 3850c7365fdc1decfb7f2143abb45522cd51947b..6d61b079b32602de8f3bceb2e3c49962ad5d5554 100644 GIT binary patch literal 26123 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 F{0|$DVS@kw literal 24562 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 From 293b2cfdfca15d53fe54d5e16d9b6aadc4e5dc58 Mon Sep 17 00:00:00 2001 From: Cheridan Date: Wed, 27 Mar 2013 11:24:23 -0500 Subject: [PATCH 13/14] -ADDS THE DRESSER.DM. FUUUUUCK. --- code/game/objects/structures/dresser.dm | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 code/game/objects/structures/dresser.dm diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm new file mode 100644 index 00000000000..aac665b85ea --- /dev/null +++ b/code/game/objects/structures/dresser.dm @@ -0,0 +1,27 @@ +/obj/structure/dresser + name = "dresser" + desc = "A nicely-crafted wooden dresser. It's filled with lots of undies." + icon = 'stationobjs.dmi' + icon_state = "dresser" + density = 1 + anchored = 1 + +/obj/structure/dresser/attack_hand(mob/user as mob) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + + if(H.gender == MALE) + var/new_undies = input(user, "Select your underwear", "Changing") as null|anything in underwear_m + if(!in_range(src, usr))//no tele-grooming + return + if(new_undies) + H.underwear = underwear_m.Find(new_undies) + else + var/new_undies = input(user, "Select your underwear", "Changing") as null|anything in underwear_f + if(!in_range(src, usr)) + return + if(new_undies) + H.underwear = underwear_f.Find(new_undies) + + add_fingerprint(H) + H.update_body() \ No newline at end of file From 565cbbc197c15fbdffc05831a940e57f79731015 Mon Sep 17 00:00:00 2001 From: Pete Goodfellow Date: Wed, 27 Mar 2013 17:03:51 +0000 Subject: [PATCH 14/14] Updated dresser.dm icon to the full path. Adds dresser.dm to the dme. --- code/game/objects/structures/dresser.dm | 2 +- tgstation.dme | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index aac665b85ea..5e9e8f5c4a7 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -1,7 +1,7 @@ /obj/structure/dresser name = "dresser" desc = "A nicely-crafted wooden dresser. It's filled with lots of undies." - icon = 'stationobjs.dmi' + icon = 'icons/obj/stationobjs.dmi' icon_state = "dresser" density = 1 anchored = 1 diff --git a/tgstation.dme b/tgstation.dme index d7da32b7ea5..cf351ee3ad6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -529,6 +529,7 @@ #include "code\game\objects\structures\bedsheet_bin.dm" #include "code\game\objects\structures\displaycase.dm" #include "code\game\objects\structures\door_assembly.dm" +#include "code\game\objects\structures\dresser.dm" #include "code\game\objects\structures\electricchair.dm" #include "code\game\objects\structures\extinguisher.dm" #include "code\game\objects\structures\false_walls.dm"