diff --git a/code/__DEFINES/instruments.dm b/code/__DEFINES/instruments.dm
index fa09eee0dd7..bf54ddf1b90 100644
--- a/code/__DEFINES/instruments.dm
+++ b/code/__DEFINES/instruments.dm
@@ -6,6 +6,8 @@
/// Max number of playing notes per instrument.
#define CHANNELS_PER_INSTRUMENT 128
+/// Minimum length a note should ever go for
+#define INSTRUMENT_MIN_TOTAL_SUSTAIN 0.1
/// Maximum length a note should ever go for
#define INSTRUMENT_MAX_TOTAL_SUSTAIN (5 SECONDS)
@@ -16,8 +18,8 @@
/// Minimum volume for when the sound is considered dead.
#define INSTRUMENT_MIN_SUSTAIN_DROPOFF 0
-#define SUSTAIN_LINEAR 1
-#define SUSTAIN_EXPONENTIAL 2
+#define SUSTAIN_LINEAR "Linear"
+#define SUSTAIN_EXPONENTIAL "Exponential"
// /datum/instrument instrument_flags
#define INSTRUMENT_LEGACY (1<<0) //Legacy instrument. Implies INSTRUMENT_DO_NOT_AUTOSAMPLE
diff --git a/code/controllers/subsystem/processing/instruments.dm b/code/controllers/subsystem/processing/instruments.dm
index acee4480b94..1cfbb144e5f 100644
--- a/code/controllers/subsystem/processing/instruments.dm
+++ b/code/controllers/subsystem/processing/instruments.dm
@@ -20,7 +20,10 @@ PROCESSING_SUBSYSTEM_DEF(instruments)
var/static/current_instrument_channels = 0
/// Single cached list for synthesizer instrument ids, so you don't have to have a new list with every synthesizer.
var/static/list/synthesizer_instrument_ids
- var/static/list/note_sustain_modes = list("Linear" = SUSTAIN_LINEAR, "Exponential" = SUSTAIN_EXPONENTIAL)
+ var/static/list/note_sustain_modes = list(
+ SUSTAIN_LINEAR,
+ SUSTAIN_EXPONENTIAL,
+ )
/datum/controller/subsystem/processing/instruments/Initialize()
initialize_instrument_data()
diff --git a/code/datums/ai/generic/generic_behaviors.dm b/code/datums/ai/generic/generic_behaviors.dm
index 43e37f66e8c..b70375ef393 100644
--- a/code/datums/ai/generic/generic_behaviors.dm
+++ b/code/datums/ai/generic/generic_behaviors.dm
@@ -333,7 +333,7 @@
//just in case- it won't do anything if the instrument isn't playing
song.stop_playing()
- song.ParseSong(song_lines)
+ song.ParseSong(new_song = song_lines)
song.repeat = 10
song.volume = song.max_volume - 10
finish_action(controller, TRUE)
diff --git a/code/modules/instruments/items.dm b/code/modules/instruments/items.dm
index d9a7e2f3e8b..dcc4ef8daba 100644
--- a/code/modules/instruments/items.dm
+++ b/code/modules/instruments/items.dm
@@ -34,20 +34,7 @@
user.visible_message(span_suicide("[user] begins to play 'Gloomy Sunday'! It looks like [user.p_theyre()] trying to commit suicide!"))
return BRUTELOSS
-/obj/item/instrument/attack_self(mob/user)
- if(!ISADVANCEDTOOLUSER(user))
- to_chat(user, span_warning("You don't have the dexterity to do this!"))
- return TRUE
- interact(user)
-
-/obj/item/instrument/interact(mob/user)
- ui_interact(user)
-
-/obj/item/instrument/ui_interact(mob/living/user)
- if(!isliving(user) || user.stat != CONSCIOUS || (HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) && !ispAI(user)))
- return
-
- user.set_machine(src)
+/obj/item/instrument/ui_interact(mob/user, datum/tgui/ui)
song.ui_interact(user)
/obj/item/instrument/violin
@@ -130,9 +117,9 @@
. = ..()
AddElement(/datum/element/spooky)
-/obj/item/instrument/trumpet/spectral/attack(mob/living/carbon/C, mob/user)
- playsound (src, 'sound/runtime/instruments/trombone/En4.mid', 100,1,-1)
- ..()
+/obj/item/instrument/trumpet/spectral/attack(mob/living/target_mob, mob/living/user, params)
+ playsound(src, 'sound/runtime/instruments/trombone/En4.mid', 1000, 1, -1)
+ return ..()
/obj/item/instrument/saxophone
name = "saxophone"
@@ -154,9 +141,9 @@
. = ..()
AddElement(/datum/element/spooky)
-/obj/item/instrument/saxophone/spectral/attack(mob/living/carbon/C, mob/user)
- playsound (src, 'sound/runtime/instruments/saxophone/En4.mid', 100,1,-1)
- ..()
+/obj/item/instrument/saxophone/spectral/attack(mob/living/target_mob, mob/living/user, params)
+ playsound(src, 'sound/runtime/instruments/trombone/En4.mid', 1000, 1, -1)
+ return ..()
/obj/item/instrument/trombone
name = "trombone"
@@ -178,9 +165,9 @@
. = ..()
AddElement(/datum/element/spooky)
-/obj/item/instrument/trombone/spectral/attack(mob/living/carbon/C, mob/user)
- playsound (src, 'sound/runtime/instruments/trombone/Cn4.mid', 100,1,-1)
- ..()
+/obj/item/instrument/trombone/spectral/attack(mob/living/target_mob, mob/living/user, params)
+ playsound(src, 'sound/runtime/instruments/trombone/Cn4.mid', 1000, 1, -1)
+ return ..()
/obj/item/instrument/recorder
name = "recorder"
@@ -201,19 +188,24 @@
w_class = WEIGHT_CLASS_SMALL
actions_types = list(/datum/action/item_action/instrument)
+/obj/item/instrument/harmonica/equipped(mob/user, slot, initial = FALSE)
+ . = ..()
+ if(!(slot & slot_flags))
+ return
+ RegisterSignal(user, COMSIG_MOB_SAY, PROC_REF(handle_speech))
+
+/obj/item/instrument/harmonica/dropped(mob/user, silent = FALSE)
+ . = ..()
+ UnregisterSignal(user, COMSIG_MOB_SAY)
+
/obj/item/instrument/harmonica/proc/handle_speech(datum/source, list/speech_args)
SIGNAL_HANDLER
- if(song.playing && ismob(loc))
- to_chat(loc, span_warning("You stop playing the harmonica to talk..."))
- song.playing = FALSE
-
-/obj/item/instrument/harmonica/equipped(mob/M, slot)
- . = ..()
- RegisterSignal(M, COMSIG_MOB_SAY, PROC_REF(handle_speech))
-
-/obj/item/instrument/harmonica/dropped(mob/M)
- . = ..()
- UnregisterSignal(M, COMSIG_MOB_SAY)
+ if(!song.playing)
+ return
+ if(!ismob(loc))
+ CRASH("[src] was still registered to listen in on [source] but was not found to be on their mob.")
+ to_chat(loc, span_warning("You stop playing the harmonica to talk..."))
+ song.playing = FALSE
/datum/action/item_action/instrument
name = "Use Instrument"
diff --git a/code/modules/instruments/piano_synth.dm b/code/modules/instruments/piano_synth.dm
index 71d0d96ef56..8e107d494c7 100644
--- a/code/modules/instruments/piano_synth.dm
+++ b/code/modules/instruments/piano_synth.dm
@@ -148,7 +148,7 @@
stopped_playing.set_output(COMPONENT_SIGNAL)
/obj/item/circuit_component/synth/proc/import_song()
- synth.song.ParseSong(song.value)
+ synth.song.ParseSong(new_song = song.value)
/obj/item/circuit_component/synth/proc/set_repetitions()
synth.song.set_repeats(repetitions.value)
@@ -169,7 +169,9 @@
synth.song.note_shift = clamp(note_shift.value, synth.song.note_shift_min, synth.song.note_shift_max)
/obj/item/circuit_component/synth/proc/set_sustain_mode()
- synth.song.sustain_mode = SSinstruments.note_sustain_modes[sustain_mode.value]
+ if(!(sustain_mode.value in SSinstruments.note_sustain_modes))
+ return
+ synth.song.sustain_mode = sustain_mode.value
/obj/item/circuit_component/synth/proc/set_sustain_value()
switch(synth.song.sustain_mode)
diff --git a/code/modules/instruments/songs/_song.dm b/code/modules/instruments/songs/_song.dm
index 68039df2146..fb0e4f08744 100644
--- a/code/modules/instruments/songs/_song.dm
+++ b/code/modules/instruments/songs/_song.dm
@@ -23,11 +23,6 @@
/// Are we currently playing?
var/playing = FALSE
- /// Are we currently editing?
- var/editing = TRUE
- /// Is the help screen open?
- var/help = FALSE
-
/// Repeats left
var/repeat = 0
/// Maximum times we can repeat
@@ -107,7 +102,6 @@
var/note_shift = 0
var/note_shift_min = -100
var/note_shift_max = 100
- var/can_noteshift = TRUE
/// The kind of sustain we're using
var/sustain_mode = SUSTAIN_LINEAR
/// When a note is considered dead if it is below this in volume
@@ -129,7 +123,7 @@
tempo = sanitize_tempo(tempo, TRUE)
src.parent = parent
if(instrument_ids)
- allowed_instrument_ids = islist(instrument_ids)? instrument_ids : list(instrument_ids)
+ allowed_instrument_ids = islist(instrument_ids) ? instrument_ids : list(instrument_ids)
if(length(allowed_instrument_ids))
set_instrument(allowed_instrument_ids[1])
hearing_mobs = list()
@@ -217,8 +211,6 @@
delay_by = 0
current_chord = 1
music_player = user
- if(ismob(music_player))
- updateDialog(music_player)
START_PROCESSING(SSinstruments, src)
/**
@@ -328,12 +320,6 @@
/datum/song/proc/set_bpm(bpm)
tempo = sanitize_tempo(600 / bpm)
-/**
- * Updates the window for our users. Override down the line.
- */
-/datum/song/proc/updateDialog(mob/user)
- ui_interact(user)
-
/datum/song/process(wait)
if(!playing)
return PROCESS_KILL
@@ -359,7 +345,6 @@
/datum/song/proc/set_volume(volume)
src.volume = clamp(round(volume, 1), max(0, min_volume), min(100, max_volume))
update_sustain()
- updateDialog()
/**
* Setter for setting how low the volume has to get before a note is considered "dead" and dropped
@@ -367,7 +352,6 @@
/datum/song/proc/set_dropoff_volume(volume)
sustain_dropoff_volume = clamp(round(volume, 0.01), INSTRUMENT_MIN_SUSTAIN_DROPOFF, 100)
update_sustain()
- updateDialog()
/**
* Setter for setting exponential falloff factor.
@@ -375,7 +359,6 @@
/datum/song/proc/set_exponential_drop_rate(drop)
sustain_exponential_dropoff = clamp(round(drop, 0.00001), INSTRUMENT_EXP_FALLOFF_MIN, INSTRUMENT_EXP_FALLOFF_MAX)
update_sustain()
- updateDialog()
/**
* Setter for setting linear falloff duration.
@@ -383,7 +366,6 @@
/datum/song/proc/set_linear_falloff_duration(duration)
sustain_linear_duration = clamp(round(duration * 10, world.tick_lag), world.tick_lag, INSTRUMENT_MAX_TOTAL_SUSTAIN)
update_sustain()
- updateDialog()
/datum/song/vv_edit_var(var_name, var_value)
. = ..()
@@ -401,9 +383,6 @@
// subtype for handheld instruments, like violin
/datum/song/handheld
-/datum/song/handheld/updateDialog(mob/user)
- parent.ui_interact(user || usr)
-
/datum/song/handheld/should_stop_playing(atom/player)
. = ..()
if(. == STOP_PLAYING || . == IGNORE_INSTRUMENT_CHECKS)
@@ -414,9 +393,6 @@
// subtype for stationary structures, like pianos
/datum/song/stationary
-/datum/song/stationary/updateDialog(mob/user)
- parent.ui_interact(user || usr)
-
/datum/song/stationary/should_stop_playing(atom/player)
. = ..()
if(. == STOP_PLAYING || . == IGNORE_INSTRUMENT_CHECKS)
diff --git a/code/modules/instruments/songs/editor.dm b/code/modules/instruments/songs/editor.dm
index 58c0562c9b0..927e03d055d 100644
--- a/code/modules/instruments/songs/editor.dm
+++ b/code/modules/instruments/songs/editor.dm
@@ -1,96 +1,189 @@
-/**
- * Returns the HTML for the status UI for this song datum.
- */
-/datum/song/proc/instrument_status_ui()
- . = list()
- . += "
"
- . += "
Current instrument: "
- if(!using_instrument)
- . += "[span_danger("No instrument loaded!")]
"
- else
- . += "[using_instrument.name]
"
- . += "Playback Settings:
"
- if(can_noteshift)
- . += "
Note Shift/Note Transpose: [note_shift] keys / [round(note_shift / 12, 0.01)] octaves
"
- var/smt
- var/modetext = ""
+/datum/song/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if (!ui)
+ ui = new(user, src, "InstrumentEditor", parent.name)
+ ui.open()
+
+/datum/song/ui_host(mob/user)
+ return parent
+
+/datum/song/ui_data(mob/user)
+ var/list/data = ..()
+ data["using_instrument"] = using_instrument?.name || "No instrument loaded!"
+ data["note_shift"] = note_shift
+ data["octaves"] = round(note_shift / 12, 0.01)
+ data["sustain_mode"] = sustain_mode
switch(sustain_mode)
if(SUSTAIN_LINEAR)
- smt = "Linear"
- modetext = "
Linear Sustain Duration: [sustain_linear_duration / 10] seconds
"
+ data["sustain_mode_button"] = "Linear Sustain Duration (in seconds)"
+ data["sustain_mode_duration"] = sustain_linear_duration / 10
+ data["sustain_mode_min"] = INSTRUMENT_MIN_TOTAL_SUSTAIN
+ data["sustain_mode_max"] = INSTRUMENT_MAX_TOTAL_SUSTAIN
if(SUSTAIN_EXPONENTIAL)
- smt = "Exponential"
- modetext = "
Exponential Falloff Factor: [sustain_exponential_dropoff]% per decisecond
"
- . += "
Sustain Mode: [smt]
"
- . += modetext
- . += using_instrument?.ready()? "Status:
Ready" : "Status:
!Instrument Definition Error!"
- . += "Instrument Type: [legacy? "Legacy" : "Synthesized"]
"
- . += "
Volume: [volume]
"
- . += "
Volume Dropoff Threshold: [sustain_dropoff_volume]
"
- . += "
Sustain indefinitely last held note: [full_sustain_held_note? "Enabled" : "Disabled"].
"
- . += "
"
+ data["sustain_mode_button"] = "Exponential Falloff Factor (% per decisecond)"
+ data["sustain_mode_duration"] = sustain_exponential_dropoff
+ data["sustain_mode_min"] = INSTRUMENT_EXP_FALLOFF_MIN
+ data["sustain_mode_max"] = INSTRUMENT_EXP_FALLOFF_MAX
+ data["instrument_ready"] = using_instrument?.ready()
+ data["volume"] = volume
+ data["volume_dropoff_threshold"] = sustain_dropoff_volume
+ data["sustain_indefinitely"] = full_sustain_held_note
+ data["playing"] = playing
+ data["repeat"] = repeat
+ data["bpm"] = round(60 SECONDS / tempo)
+ data["lines"] = list()
+ var/linecount
+ for(var/line in lines)
+ linecount++
+ data["lines"] += list(list(
+ "line_count" = linecount,
+ "line_text" = line,
+ ))
+ return data
-/datum/song/ui_interact(mob/user)
- var/list/dat = list()
+/datum/song/ui_static_data(mob/user)
+ var/list/data = ..()
+ data["can_switch_instrument"] = (length(allowed_instrument_ids) > 1)
+ data["possible_instruments"] = list()
+ for(var/instrument in allowed_instrument_ids)
+ UNTYPED_LIST_ADD(data["possible_instruments"], list("name" = SSinstruments.instrument_data[instrument], "id" = instrument))
+ data["sustain_modes"] = SSinstruments.note_sustain_modes
+ data["max_repeats"] = max_repeats
+ data["min_volume"] = min_volume
+ data["max_volume"] = max_volume
+ data["note_shift_min"] = note_shift_min
+ data["note_shift_max"] = note_shift_max
+ data["max_line_chars"] = MUSIC_MAXLINECHARS
+ data["max_lines"] = MUSIC_MAXLINES
+ return data
- dat += instrument_status_ui()
+/datum/song/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ var/mob/user = ui.user
+ if(!istype(user))
+ return FALSE
- 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(!editing)
- dat += "
Show Editor
"
- else
- dat += "Editing
"
- dat += "Hide Editor"
- dat += " Start a New Song"
- dat += " Import a Song
"
- var/bpm = round(600 / tempo)
- dat += "Tempo: - [bpm] 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 += {"
- Lines are a series of chords, separated by commas (,), each with notes separated 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 [MUSIC_MAXLINECHARS] characters.
- A song may only contain up to [MUSIC_MAXLINES] lines.
- "}
- else
- dat += "Show Help
"
+ switch(action)
+ //SETTINGS
+ if("play_music")
+ if(!playing)
+ INVOKE_ASYNC(src, PROC_REF(start_playing), user)
+ else
+ stop_playing()
+ return TRUE
+ if("change_instrument")
+ var/new_instrument = params["new_instrument"]
+ //only one instrument, so no need to bother changing it.
+ if(!length(allowed_instrument_ids))
+ return FALSE
+ if(!(new_instrument in allowed_instrument_ids))
+ return FALSE
+ set_instrument(new_instrument)
+ return TRUE
+ if("tempo")
+ var/move_direction = params["tempo_change"]
+ var/tempo_diff
+ if(move_direction == "increase_speed")
+ tempo_diff = world.tick_lag
+ else
+ tempo_diff = -world.tick_lag
+ tempo = sanitize_tempo(tempo + tempo_diff)
+ return TRUE
- var/datum/browser/popup = new(user, "instrument", parent?.name || "instrument", 700, 500)
- popup.set_content(dat.Join(""))
- popup.open()
+ //SONG MAKING
+ if("import_song")
+ var/song_text = ""
+ do
+ song_text = tgui_input_text(user, "Please paste the entire song, formatted:", name, max_length = (MUSIC_MAXLINES * MUSIC_MAXLINECHARS))
+ if(!in_range(parent, user))
+ return
+ if(length_char(song_text) >= MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
+ var/should_continue = tgui_alert(user, "Your message is too long! Would you like to continue editing it?", "Warning", list("Yes", "No"))
+ if(should_continue != "Yes")
+ break
+ while(length_char(song_text) > MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
+ ParseSong(user, song_text)
+ return TRUE
+ if("start_new_song")
+ name = ""
+ lines = new()
+ tempo = sanitize_tempo(5) // default 120 BPM
+ return TRUE
+ if("add_new_line")
+ var/newline = tgui_input_text(user, "Enter your line", parent.name)
+ if(!newline || !in_range(parent, user))
+ return
+ if(lines.len > MUSIC_MAXLINES)
+ return
+ if(length(newline) > MUSIC_MAXLINECHARS)
+ newline = copytext(newline, 1, MUSIC_MAXLINECHARS)
+ lines.Add(newline)
+ if("delete_line")
+ var/line_to_delete = params["line_deleted"]
+ if(line_to_delete > lines.len || line_to_delete < 1)
+ return FALSE
+ lines.Cut(line_to_delete, line_to_delete + 1)
+ return TRUE
+ if("modify_line")
+ var/line_to_edit = params["line_editing"]
+ if(line_to_edit > lines.len || line_to_edit < 1)
+ return FALSE
+ var/new_line_text = tgui_input_text(user, "Enter your line ", parent.name, lines[line_to_edit], MUSIC_MAXLINECHARS)
+ if(isnull(new_line_text) || !in_range(parent, user))
+ return FALSE
+ lines[line_to_edit] = new_line_text
+ return TRUE
+
+ //MODE STUFF
+ if("set_sustain_mode")
+ var/new_mode = params["new_mode"]
+ if(isnull(new_mode) || !(new_mode in SSinstruments.note_sustain_modes))
+ return FALSE
+ sustain_mode = new_mode
+ return TRUE
+ if("set_note_shift")
+ var/amount = params["amount"]
+ if(!isnum(amount))
+ return FALSE
+ note_shift = clamp(amount, note_shift_min, note_shift_max)
+ return TRUE
+ if("set_volume")
+ var/new_volume = params["amount"]
+ if(!isnum(new_volume))
+ return FALSE
+ set_volume(new_volume)
+ return TRUE
+ if("set_dropoff_volume")
+ var/dropoff_threshold = params["amount"]
+ if(!isnum(dropoff_threshold))
+ return FALSE
+ set_dropoff_volume(dropoff_threshold)
+ return TRUE
+ if("toggle_sustain_hold_indefinitely")
+ full_sustain_held_note = !full_sustain_held_note
+ return TRUE
+ if("set_repeat_amount")
+ if(playing)
+ return
+ var/repeat_amount = params["amount"]
+ if(!isnum(repeat_amount))
+ return FALSE
+ set_repeats(repeat_amount)
+ return TRUE
+ if("edit_sustain_mode")
+ var/sustain_amount = params["amount"]
+ if(isnull(sustain_amount) || !isnum(sustain_amount))
+ return
+ switch(sustain_mode)
+ if(SUSTAIN_LINEAR)
+ set_linear_falloff_duration(sustain_amount)
+ if(SUSTAIN_EXPONENTIAL)
+ set_exponential_drop_rate(sustain_amount)
/**
* Parses a song the user has input into lines and stores them.
*/
-/datum/song/proc/ParseSong(new_song)
+/datum/song/proc/ParseSong(mob/user, new_song)
set waitfor = FALSE
//split into lines
lines = islist(new_song) ? new_song : splittext(new_song, "\n")
@@ -103,142 +196,14 @@
else
tempo = sanitize_tempo(5) // default 120 BPM
if(lines.len > MUSIC_MAXLINES)
- to_chat(usr, "Too many lines!")
+ if(user)
+ to_chat(user, "Too many lines!")
lines.Cut(MUSIC_MAXLINES + 1)
var/linenum = 1
for(var/l in lines)
if(length_char(l) > MUSIC_MAXLINECHARS)
- to_chat(usr, "Line [linenum] too long!")
+ if(user)
+ to_chat(user, "Line [linenum] too long!")
lines.Remove(l)
else
linenum++
- updateDialog(usr) // make sure updates when complete
-
-/datum/song/Topic(href, href_list)
- if(!usr.can_perform_action(parent, ALLOW_RESTING))
- usr << browse(null, "window=instrument")
- usr.unset_machine()
- return
-
- parent.add_fingerprint(usr)
-
- if(href_list["newsong"])
- lines = new()
- tempo = sanitize_tempo(5) // default 120 BPM
- name = ""
-
- else if(href_list["import"])
- var/t = ""
- do
- t = html_encode(input(usr, "Please paste the entire song, formatted:", name, t) as message)
- if(!in_range(parent, usr))
- return
-
- if(length_char(t) >= MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
- var/cont = tgui_alert(usr, "Your message is too long! Would you like to continue editing it?", "Warning", list("Yes", "No"))
- if(cont != "Yes")
- break
- while(length_char(t) > MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
- ParseSong(t)
-
- else if(href_list["help"])
- help = text2num(href_list["help"]) - 1
-
- else if(href_list["edit"])
- editing = text2num(href_list["edit"]) - 1
-
- if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
- set_repeats(repeat + text2num(href_list["repeat"]))
-
- else if(href_list["tempo"])
- tempo = sanitize_tempo(tempo + text2num(href_list["tempo"]))
-
- else if(href_list["play"])
- INVOKE_ASYNC(src, PROC_REF(start_playing), usr)
-
- else if(href_list["newline"])
- var/newline = tgui_input_text(usr, "Enter your line ", parent.name)
- if(!newline || !in_range(parent, usr))
- return
- if(lines.len > MUSIC_MAXLINES)
- return
- if(length(newline) > MUSIC_MAXLINECHARS)
- newline = copytext(newline, 1, MUSIC_MAXLINECHARS)
- lines.Add(newline)
-
- 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 = tgui_input_text(usr, "Enter your line ", parent.name, lines[num], MUSIC_MAXLINECHARS)
- if(!content || !in_range(parent, usr))
- return
- if(num > lines.len || num < 1)
- return
- lines[num] = content
-
- else if(href_list["stop"])
- stop_playing()
-
- else if(href_list["setlinearfalloff"])
- var/amount = tgui_input_number(usr, "Set linear sustain duration in seconds", "Linear Sustain Duration", 0.1, INSTRUMENT_MAX_TOTAL_SUSTAIN, 0.1, round_value = FALSE)
- if(!isnull(amount))
- set_linear_falloff_duration(amount)
-
- else if(href_list["setexpfalloff"])
- var/amount = tgui_input_number(usr, "Set exponential sustain factor", "Exponential sustain factor", INSTRUMENT_EXP_FALLOFF_MIN, INSTRUMENT_EXP_FALLOFF_MAX, INSTRUMENT_EXP_FALLOFF_MIN, round_value = FALSE)
- if(!isnull(amount))
- set_exponential_drop_rate(amount)
-
- else if(href_list["setvolume"])
- var/amount = tgui_input_number(usr, "Set volume", "Volume", 1, 75, 1)
- if(!isnull(amount))
- set_volume(amount)
-
- else if(href_list["setdropoffvolume"])
- var/amount = tgui_input_number(usr, "Set dropoff threshold", "Dropoff Volume", max_value = 100)
- if(!isnull(amount))
- set_dropoff_volume(amount)
-
- else if(href_list["switchinstrument"])
- if(!length(allowed_instrument_ids))
- return
- else if(length(allowed_instrument_ids) == 1)
- set_instrument(allowed_instrument_ids[1])
- return
- var/list/categories = list()
- for(var/i in allowed_instrument_ids)
- var/datum/instrument/I = SSinstruments.get_instrument(i)
- if(I)
- LAZYSET(categories[I.category || "ERROR CATEGORY"], I.name, I.id)
- var/cat = tgui_input_list(usr, "Select Category", "Instrument Category", categories)
- if(isnull(cat))
- return
- var/list/instruments = categories[cat]
- var/choice = tgui_input_list(usr, "Select Instrument", "Instrument Selection", instruments)
- if(isnull(choice))
- return
- if(isnull(instruments[choice]))
- return
- choice = instruments[choice] //get id
- if(choice)
- set_instrument(choice)
-
- else if(href_list["setnoteshift"])
- var/amount = input(usr, "Set note shift", "Note Shift") as null|num
- if(!isnull(amount))
- note_shift = clamp(amount, note_shift_min, note_shift_max)
-
- else if(href_list["setsustainmode"])
- var/choice = tgui_input_list(usr, "Choose a sustain mode", "Sustain Mode", SSinstruments.note_sustain_modes)
- if(choice)
- sustain_mode = SSinstruments.note_sustain_modes[choice]
-
- else if(href_list["togglesustainhold"])
- full_sustain_held_note = !full_sustain_held_note
-
- updateDialog(usr)
diff --git a/code/modules/instruments/songs/play_synthesized.dm b/code/modules/instruments/songs/play_synthesized.dm
index 3b5f3d5b9f4..836c2fdd86b 100644
--- a/code/modules/instruments/songs/play_synthesized.dm
+++ b/code/modules/instruments/songs/play_synthesized.dm
@@ -43,8 +43,7 @@
* Does a hearing check if enough time has passed.
*/
/datum/song/proc/playkey_synth(key, atom/player)
- if(can_noteshift)
- key = clamp(key + note_shift, key_min, key_max)
+ key = clamp(key + note_shift, key_min, key_max)
if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck)
do_hearcheck()
var/datum/instrument_key/K = using_instrument.samples[num2text(key)] //See how fucking easy it is to make a number text? You don't need a complicated 9 line proc!
diff --git a/tgui/packages/tgui/components/Collapsible.tsx b/tgui/packages/tgui/components/Collapsible.tsx
index b470ed5ce6d..9f5f944b0ec 100644
--- a/tgui/packages/tgui/components/Collapsible.tsx
+++ b/tgui/packages/tgui/components/Collapsible.tsx
@@ -13,11 +13,12 @@ type Props = Partial<{
buttons: ReactNode;
open: boolean;
title: ReactNode;
+ icon: string;
}> &
BoxProps;
export function Collapsible(props: Props) {
- const { children, color, title, buttons, ...rest } = props;
+ const { children, color, title, buttons, icon, ...rest } = props;
const [open, setOpen] = useState(props.open);
return (
@@ -27,7 +28,7 @@ export function Collapsible(props: Props) {