diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index fc4911211a3..1f170276c8f 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -1,13 +1,14 @@
//Preference toggles
-#define SOUND_ADMINHELP 1
-#define SOUND_MIDI 2
-#define SOUND_AMBIENCE 4
-#define SOUND_LOBBY 8
-#define SOUND_STREAMING 16
-#define SOUND_HEARTBEAT 32
-#define SOUND_BUZZ 64
+#define SOUND_ADMINHELP 1
+#define SOUND_MIDI 2
+#define SOUND_AMBIENCE 4
+#define SOUND_LOBBY 8
+#define SOUND_STREAMING 16
+#define SOUND_HEARTBEAT 32
+#define SOUND_BUZZ 64
+#define SOUND_INSTRUMENTS 128
-#define SOUND_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|SOUND_STREAMING|SOUND_HEARTBEAT|SOUND_BUZZ)
+#define SOUND_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|SOUND_STREAMING|SOUND_HEARTBEAT|SOUND_BUZZ|SOUND_INSTRUMENTS)
#define CHAT_OOC 1
#define CHAT_DEAD 2
diff --git a/code/game/objects/items/devices/violin.dm b/code/game/objects/items/devices/violin.dm
index 5891b163794..02038717aff 100644
--- a/code/game/objects/items/devices/violin.dm
+++ b/code/game/objects/items/devices/violin.dm
@@ -18,6 +18,10 @@
qdel(song)
song = null
return ..()
+
+/obj/item/device/violin/initialize()
+ song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
+ ..()
/obj/item/device/violin/attack_self(mob/user as mob)
interact(user)
diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm
index 3d3adcf9339..36dca481c59 100644
--- a/code/game/objects/structures/musician.dm
+++ b/code/game/objects/structures/musician.dm
@@ -3,7 +3,7 @@
/datum/song
var/name = "Untitled"
var/list/lines = new()
- var/tempo = 5
+ var/tempo = 5 // delay between notes
var/playing = 0 // if we're playing
var/help = 0 // if help is open
@@ -16,6 +16,7 @@
var/obj/instrumentObj = null // the associated obj playing the sound
/datum/song/New(dir, obj)
+ tempo = sanitize_tempo(tempo)
instrumentDir = dir
instrumentObj = obj
@@ -58,13 +59,17 @@
// and play
var/turf/source = get_turf(instrumentObj)
for(var/mob/M in hearers(15, source))
+ if(!M.client || !(M.client.prefs.toggles & SOUND_INSTRUMENTS))
+ continue
M.playsound_local(source, soundfile, 100, falloff = 5)
/datum/song/proc/updateDialog(mob/user as mob)
instrumentObj.updateDialog() // assumes it's an object in world, override if otherwise
-/datum/song/proc/shouldStopPlaying()
+/datum/song/proc/shouldStopPlaying(mob/user)
if(instrumentObj)
+ //if(!user.canUseTopic(instrumentObj))
+ //return 1
return !instrumentObj.anchored // add special cases to stop in subclasses
else
return 1
@@ -84,7 +89,7 @@
var/list/notes = text2list(beat, "/")
for(var/note in text2list(notes[1], "-"))
//world << "note: [note]"
- if(!playing || shouldStopPlaying())//If the instrument is playing, or special case
+ if(!playing || shouldStopPlaying(user))//If the instrument is playing, or special case
playing = 0
return
if(lentext(note) == 0)
@@ -104,7 +109,7 @@
cur_oct[cur_note] = text2num(ni)
playnote(cur_note, cur_acc[cur_note], cur_oct[cur_note])
if(notes.len >= 2 && text2num(notes[2]))
- sleep(tempo / text2num(notes[2]))
+ sleep(sanitize_tempo(tempo / text2num(notes[2])))
else
sleep(tempo)
repeat--
@@ -136,10 +141,8 @@
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/bpm = round(600 / tempo)
+ dat += "Tempo: - [bpm] BPM +
"
var/linecount = 0
for(var/line in lines)
linecount += 1
@@ -183,7 +186,7 @@
if(href_list["newsong"])
lines = new()
- tempo = 5 // default 120 BPM
+ tempo = sanitize_tempo(5) // default 120 BPM
name = ""
else if(href_list["import"])
@@ -203,10 +206,10 @@
spawn()
lines = text2list(t, "\n")
if(copytext(lines[1],1,6) == "BPM: ")
- tempo = 600 / max(1, text2num(copytext(lines[1],6)))
+ tempo = sanitize_tempo(600 / text2num(copytext(lines[1],6)))
lines.Cut(1,2)
else
- tempo = 5 // default 120 BPM
+ tempo = sanitize_tempo(5) // default 120 BPM
if(lines.len > 50)
usr << "Too many lines!"
lines.Cut(51)
@@ -235,11 +238,7 @@
repeat = max_repeats
else if(href_list["tempo"])
- tempo += text2num(href_list["tempo"])
- if(tempo < 1)
- tempo = 1
- if(tempo > 600)
- tempo = 600
+ tempo = sanitize_tempo(tempo + text2num(href_list["tempo"]))
else if(href_list["play"])
playing = 1
@@ -279,6 +278,9 @@
updateDialog(usr)
return
+/datum/song/proc/sanitize_tempo(new_tempo)
+ new_tempo = abs(new_tempo)
+ return max(round(new_tempo, world.tick_lag), world.tick_lag)
// subclass for handheld instruments, like violin
/datum/song/handheld
@@ -321,6 +323,10 @@
qdel(song)
song = null
return ..()
+
+/obj/structure/piano/initialize()
+ song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
+ ..()
/obj/structure/piano/attack_hand(mob/user as mob)
interact(user)
diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm
index 6463e65ada2..c79224d2e5a 100644
--- a/code/modules/client/preferences_toggles.dm
+++ b/code/modules/client/preferences_toggles.dm
@@ -178,6 +178,19 @@
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1)
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)
feedback_add_details("admin_verb","Thb") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+// This needs a toggle because you people are awful and spammed terrible music
+/client/verb/toggle_instruments()
+ set name = "Hear/Silence Instruments"
+ set category = "Preferences"
+ set desc = "Toggles hearing musical instruments like the violin and piano"
+ prefs.toggles ^= SOUND_INSTRUMENTS
+ prefs.save_preferences()
+ if(prefs.toggles & SOUND_INSTRUMENTS)
+ src << "You will now hear people playing musical instruments."
+ else
+ src << "You will no longer hear musical instruments."
+ feedback_add_details("admin_verb","TInstru") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//be special
/client/verb/toggle_be_special(role in be_special_flags)