From 2fbd7b20bbfd9612f10b5a124d1422d488c8498f Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Wed, 1 Dec 2021 23:18:36 +0100 Subject: [PATCH] Synthesizers and headphones can now have circuits! (#62825) About The Pull Request A circuit and shell components have been added to Synthesizers (headphones and spacepods included, though with a reduced capacity because of their size), so they can now be used for wiremod. Just like for instant cameras, no shell design here. They are meant to be found in dorms or maybe ordered from cargo. Why It's Good For The Game The station outside the sci department has plenty of USB ports stuff but is lacking when it comes to circuits shell. This is another small step toward a better and more applicable wiremod. Changelog cl expansion: Synthesizers and headphones can now have circuits installed. /cl --- code/__DEFINES/dcs/signals/signals_music.dm | 2 + code/__DEFINES/song.dm | 9 + code/__DEFINES/wiremod.dm | 1 + .../subsystem/processing/instruments.dm | 1 + code/modules/instruments/items.dm | 65 +----- code/modules/instruments/piano_synth.dm | 191 ++++++++++++++++++ code/modules/instruments/songs/_song.dm | 56 +++-- code/modules/instruments/songs/editor.dm | 31 +-- code/modules/instruments/songs/play_legacy.dm | 4 +- .../instruments/songs/play_synthesized.dm | 4 +- code/modules/instruments/stationary.dm | 12 +- tgstation.dme | 1 + 12 files changed, 267 insertions(+), 110 deletions(-) create mode 100644 code/modules/instruments/piano_synth.dm diff --git a/code/__DEFINES/dcs/signals/signals_music.dm b/code/__DEFINES/dcs/signals/signals_music.dm index 3bb023378cd..e41207713e2 100644 --- a/code/__DEFINES/dcs/signals/signals_music.dm +++ b/code/__DEFINES/dcs/signals/signals_music.dm @@ -4,3 +4,5 @@ #define COMSIG_SONG_START "song_start" ///sent to the instrument when a song stops playing #define COMSIG_SONG_END "song_end" +///sent to the instrument on /should_stop_playing(): (atom/player). Return values can be found in DEFINES/song.dm +#define COMSIG_SONG_SHOULD_STOP_PLAYING "song_should_stop_playing" diff --git a/code/__DEFINES/song.dm b/code/__DEFINES/song.dm index 26121707f7d..7af269fbe21 100644 --- a/code/__DEFINES/song.dm +++ b/code/__DEFINES/song.dm @@ -2,5 +2,14 @@ #define MUSIC_MAXLINES 1000 #define MUSIC_MAXLINECHARS 300 +#define BPM_TO_TEMPO_SETTING(value) (600 / round(value, 1)) + +//Return values of song/should_stop_playing() + +///When the song should stop being played +#define STOP_PLAYING 1 +///Will ignore the instrument checks and play the song anyway. +#define IGNORE_INSTRUMENT_CHECKS 2 + ///it's what monkeys play! #define MONKEY_SONG "BPM: 200\nC4/0,14,C,A4-F2,F3,A3,F-F2,A-F,F4,G4,F,D4-Bb2-G2\nD3,G3,D-G2,G3-G2,D,D4-G3,D,B4-B2,G,B3,G-B2,B3-B2\nG4,A4,G,E4-C3,E3,G3,E-C,G-C,E,E4-G,E,C5-E-A3,C4\nA-E3,C,E4-C3,A4-C4,B4-A3-A2,C5-C4,D5-F-B3,D4,B-F3\nD,F4-D3,D4,F-B-B2,G4-D,A4-C-F3,F,C/2,B3/2,A3-C3/2\nB/2,C4,E-C3,F4,G-C,F-F3,F-C,C4/2,B/2,A-A2/2,G3/2\nF/I" diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm index 124d9f4da47..4277380c055 100644 --- a/code/__DEFINES/wiremod.dm +++ b/code/__DEFINES/wiremod.dm @@ -94,6 +94,7 @@ #define SHELL_FLAG_ALLOW_FAILURE_ACTION (1<<3) // Shell capacities. These can be converted to configs very easily later +#define SHELL_CAPACITY_TINY 12 #define SHELL_CAPACITY_SMALL 25 #define SHELL_CAPACITY_MEDIUM 50 #define SHELL_CAPACITY_LARGE 100 diff --git a/code/controllers/subsystem/processing/instruments.dm b/code/controllers/subsystem/processing/instruments.dm index ee0fd1ea009..0d14c19c2bb 100644 --- a/code/controllers/subsystem/processing/instruments.dm +++ b/code/controllers/subsystem/processing/instruments.dm @@ -20,6 +20,7 @@ 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) /datum/controller/subsystem/processing/instruments/Initialize() initialize_instrument_data() diff --git a/code/modules/instruments/items.dm b/code/modules/instruments/items.dm index 9575ddb1451..1b2d64ed1d0 100644 --- a/code/modules/instruments/items.dm +++ b/code/modules/instruments/items.dm @@ -23,8 +23,12 @@ QDEL_NULL(song) return ..() -/obj/item/instrument/proc/should_stop_playing(mob/user) - return user.incapacitated() || !((loc == user) || (isturf(loc) && Adjacent(user))) // sorry, no more TK playing. +/obj/item/instrument/proc/should_stop_playing(atom/music_player) + if(!ismob(music_player)) + return STOP_PLAYING + var/mob/user = music_player + if(user.incapacitated() || !((loc == user) || (isturf(loc) && Adjacent(user)))) // sorry, no more TK playing. + return STOP_PLAYING /obj/item/instrument/suicide_act(mob/user) user.visible_message(span_suicide("[user] begins to play 'Gloomy Sunday'! It looks like [user.p_theyre()] trying to commit suicide!")) @@ -61,63 +65,6 @@ inhand_icon_state = "golden_violin" resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF -/obj/item/instrument/piano_synth - name = "synthesizer" - desc = "An advanced electronic synthesizer that can be used as various instruments." - icon_state = "synth" - inhand_icon_state = "synth" - allowed_instrument_ids = "piano" - -/obj/item/instrument/piano_synth/Initialize(mapload) - . = ..() - song.allowed_instrument_ids = SSinstruments.synthesizer_instrument_ids - -/obj/item/instrument/piano_synth/headphones - name = "headphones" - desc = "Unce unce unce unce. Boop!" - icon = 'icons/obj/clothing/accessories.dmi' - lefthand_file = 'icons/mob/inhands/clothing_lefthand.dmi' - righthand_file = 'icons/mob/inhands/clothing_righthand.dmi' - icon_state = "headphones" - inhand_icon_state = "headphones" - slot_flags = ITEM_SLOT_EARS | ITEM_SLOT_HEAD - force = 0 - w_class = WEIGHT_CLASS_SMALL - custom_price = PAYCHECK_ASSISTANT * 2.5 - instrument_range = 1 - -/obj/item/instrument/piano_synth/headphones/ComponentInitialize() - . = ..() - AddElement(/datum/element/update_icon_updates_onmob) - RegisterSignal(src, COMSIG_SONG_START, .proc/start_playing) - RegisterSignal(src, COMSIG_SONG_END, .proc/stop_playing) - -/** - * Called by a component signal when our song starts playing. - */ -/obj/item/instrument/piano_synth/headphones/proc/start_playing() - SIGNAL_HANDLER - icon_state = "[initial(icon_state)]_on" - update_appearance() - -/** - * Called by a component signal when our song stops playing. - */ -/obj/item/instrument/piano_synth/headphones/proc/stop_playing() - SIGNAL_HANDLER - icon_state = "[initial(icon_state)]" - update_appearance() - -/obj/item/instrument/piano_synth/headphones/spacepods - name = "\improper Nanotrasen space pods" - desc = "Flex your money, AND ignore what everyone else says, all at once!" - icon_state = "spacepods" - inhand_icon_state = "spacepods" - slot_flags = ITEM_SLOT_EARS - strip_delay = 100 //air pods don't fall out - instrument_range = 0 //you're paying for quality here - custom_premium_price = PAYCHECK_ASSISTANT * 36 //Save up 5 shifts worth of pay just to lose it down a drainpipe on the sidewalk - /obj/item/instrument/banjo name = "banjo" desc = "A 'Mura' brand banjo. It's pretty much just a drum with a neck and strings." diff --git a/code/modules/instruments/piano_synth.dm b/code/modules/instruments/piano_synth.dm new file mode 100644 index 00000000000..90748d0f18f --- /dev/null +++ b/code/modules/instruments/piano_synth.dm @@ -0,0 +1,191 @@ + +/obj/item/instrument/piano_synth + name = "synthesizer" + desc = "An advanced electronic synthesizer that can be used as various instruments." + icon_state = "synth" + inhand_icon_state = "synth" + allowed_instrument_ids = "piano" + var/circuit_type = /obj/item/circuit_component/synth + var/shell_capacity = SHELL_CAPACITY_SMALL + +/obj/item/instrument/piano_synth/Initialize(mapload) + . = ..() + song.allowed_instrument_ids = SSinstruments.synthesizer_instrument_ids + AddComponent(/datum/component/shell, list(new circuit_type), shell_capacity) + +/obj/item/instrument/piano_synth/headphones + name = "headphones" + desc = "Unce unce unce unce. Boop!" + icon = 'icons/obj/clothing/accessories.dmi' + lefthand_file = 'icons/mob/inhands/clothing_lefthand.dmi' + righthand_file = 'icons/mob/inhands/clothing_righthand.dmi' + icon_state = "headphones" + inhand_icon_state = "headphones" + slot_flags = ITEM_SLOT_EARS | ITEM_SLOT_HEAD + force = 0 + w_class = WEIGHT_CLASS_SMALL + custom_price = PAYCHECK_ASSISTANT * 2.5 + instrument_range = 1 + circuit_type = /obj/item/circuit_component/synth/headphones + shell_capacity = SHELL_CAPACITY_TINY + +/obj/item/instrument/piano_synth/headphones/ComponentInitialize() + . = ..() + AddElement(/datum/element/update_icon_updates_onmob) + RegisterSignal(src, COMSIG_SONG_START, .proc/start_playing) + RegisterSignal(src, COMSIG_SONG_END, .proc/stop_playing) + +/** + * Called by a component signal when our song starts playing. + */ +/obj/item/instrument/piano_synth/headphones/proc/start_playing() + SIGNAL_HANDLER + icon_state = "[initial(icon_state)]_on" + update_appearance() + +/** + * Called by a component signal when our song stops playing. + */ +/obj/item/instrument/piano_synth/headphones/proc/stop_playing() + SIGNAL_HANDLER + icon_state = "[initial(icon_state)]" + update_appearance() + +/obj/item/instrument/piano_synth/headphones/spacepods + name = "\improper Nanotrasen space pods" + desc = "Flex your money, AND ignore what everyone else says, all at once!" + icon_state = "spacepods" + inhand_icon_state = "spacepods" + slot_flags = ITEM_SLOT_EARS + strip_delay = 100 //air pods don't fall out + instrument_range = 0 //you're paying for quality here + custom_premium_price = PAYCHECK_ASSISTANT * 36 //Save up 5 shifts worth of pay just to lose it down a drainpipe on the sidewalk + +/obj/item/circuit_component/synth + display_name = "Synthesizer" + desc = "An advanced electronic synthesizer that can be used as various instruments." + + /// The song, represented in latin alphabet A to G, that'll be played when play is triggered. + var/datum/port/input/song + /// Starts playing the song. + var/datum/port/input/play + /// Stop playing the song. + var/datum/port/input/stop + /// How many times the song will be played. + var/datum/port/input/repetitions + /// The beats per minute of the song + var/datum/port/input/beats_per_min + /// The volume of the song + var/datum/port/input/volume + /// Notes with volume below this threshold will be dead + var/datum/port/input/volume_dropoff + /// Note shift + var/datum/port/input/note_shift + /// Sustain Mode + var/datum/port/input/sustain_mode + /// The value of the above + var/datum/port/input/sustain_value + /// If set the last held note will decay + var/datum/port/input/note_decay + /// The list of instruments which sound can be synthesized. + var/datum/port/input/option/selected_instrument + /// Whether a song is currently playing + var/datum/port/output/is_playing + /// Sent when a new song has started playing + var/datum/port/output/started_playing + /// Sent when a song has finished playing + var/datum/port/output/stopped_playing + + /// The synthesizer this circut is attached to. + var/obj/item/instrument/piano_synth/synth + +/obj/item/circuit_component/synth/populate_ports() + song = add_input_port("Song", PORT_TYPE_LIST(PORT_TYPE_STRING), trigger = .proc/import_song) + play = add_input_port("Play", PORT_TYPE_SIGNAL, trigger = .proc/start_playing) + stop = add_input_port("Stop", PORT_TYPE_SIGNAL, trigger = .proc/stop_playing) + repetitions = add_input_port("Repetitions", PORT_TYPE_NUMBER, trigger = .proc/set_repetitions) + beats_per_min = add_input_port("BPM", PORT_TYPE_NUMBER, trigger = .proc/set_bpm) + selected_instrument = add_option_port("Selected Instrument", SSinstruments.synthesizer_instrument_ids, trigger = .proc/set_instrument) + volume = add_input_port("Volume", PORT_TYPE_NUMBER, trigger = .proc/set_volume) + volume_dropoff = add_input_port("Volume Dropoff Threshold", PORT_TYPE_NUMBER, trigger = .proc/set_dropoff) + note_shift = add_input_port("Note Shift", PORT_TYPE_NUMBER, trigger = .proc/set_note_shift) + sustain_mode = add_option_port("Note Sustain Mode", SSinstruments.note_sustain_modes, trigger = .proc/set_sustain_mode) + sustain_value = add_input_port("Note Sustain Value", PORT_TYPE_NUMBER, trigger = .proc/set_sustain_value) + note_decay = add_input_port("Held Note Decay", PORT_TYPE_NUMBER, trigger = .proc/set_sustain_decay) + + is_playing = add_output_port("Currently Playing", PORT_TYPE_NUMBER) + started_playing = add_output_port("Started Playing", PORT_TYPE_SIGNAL) + stopped_playing = add_output_port("Stopped Playing", PORT_TYPE_SIGNAL) + +/obj/item/circuit_component/synth/register_shell(atom/movable/shell) + . = ..() + synth = shell + RegisterSignal(synth, COMSIG_SONG_START, .proc/on_song_start) + RegisterSignal(synth, COMSIG_SONG_END, .proc/on_song_end) + RegisterSignal(synth, COMSIG_SONG_SHOULD_STOP_PLAYING, .proc/continue_if_autoplaying) + +/obj/item/circuit_component/synth/unregister_shell(atom/movable/shell) + if(synth.song.music_player == src) + synth.song.stop_playing() + synth = null + UnregisterSignal(synth, list(COMSIG_SONG_START, COMSIG_SONG_END, COMSIG_SONG_SHOULD_STOP_PLAYING)) + return ..() + +/obj/item/circuit_component/synth/proc/start_playing(datum/port/input/port) + synth.song.start_playing(src) + +/obj/item/circuit_component/synth/proc/on_song_start() + SIGNAL_HANDLER + is_playing.set_output(TRUE) + started_playing.set_output(COMPONENT_SIGNAL) + +/obj/item/circuit_component/synth/proc/continue_if_autoplaying(datum/source, atom/music_player) + SIGNAL_HANDLER + if(music_player == src) + return IGNORE_INSTRUMENT_CHECKS + +/obj/item/circuit_component/synth/proc/stop_playing(datum/port/input/port) + synth.song.stop_playing() + +/obj/item/circuit_component/synth/proc/on_song_end() + SIGNAL_HANDLER + is_playing.set_output(FALSE) + stopped_playing.set_output(COMPONENT_SIGNAL) + +/obj/item/circuit_component/synth/proc/import_song() + synth.song.ParseSong(song.value) + +/obj/item/circuit_component/synth/proc/set_repetitions() + synth.song.set_repeats(repetitions.value) + +/obj/item/circuit_component/synth/proc/set_bpm() + synth.song.sanitize_tempo(BPM_TO_TEMPO_SETTING(beats_per_min.value)) + +/obj/item/circuit_component/synth/proc/set_instrument() + synth.song.set_instrument(selected_instrument.value) + +/obj/item/circuit_component/synth/proc/set_volume() + synth.song.set_volume(volume.value) + +/obj/item/circuit_component/synth/proc/set_dropoff() + synth.song.set_dropoff_volume(volume_dropoff.value) + +/obj/item/circuit_component/synth/proc/set_note_shift() + 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] + +/obj/item/circuit_component/synth/proc/set_sustain_value() + switch(synth.song.sustain_mode) + if(SUSTAIN_LINEAR) + synth.song.set_linear_falloff_duration(sustain_value.value) + if(SUSTAIN_EXPONENTIAL) + synth.song.set_exponential_drop_rate(sustain_value.value) + +/obj/item/circuit_component/synth/proc/set_sustain_decay() + synth.song.full_sustain_held_note = !!synth.song.full_sustain_held_note + +/obj/item/circuit_component/synth/headphones + display_name = "Headphones" + desc = "An advanced electronic device that plays music into your ears." diff --git a/code/modules/instruments/songs/_song.dm b/code/modules/instruments/songs/_song.dm index afe19090ff4..35408eaa35d 100644 --- a/code/modules/instruments/songs/_song.dm +++ b/code/modules/instruments/songs/_song.dm @@ -74,8 +74,8 @@ var/list/channels_playing = list() /// List of channels that aren't being used, as text. This is to prevent unnecessary freeing and reallocations from SSsounds/SSinstruments. var/list/channels_idle = list() - /// Person playing us - var/mob/user_playing + /// Who or what's playing us + var/atom/music_player ////////////////////////////////////////////////////// /// Last world.time we checked for who can hear us @@ -197,7 +197,7 @@ /** * Attempts to start playing our song. */ -/datum/song/proc/start_playing(mob/user) +/datum/song/proc/start_playing(atom/user) if(playing) return if(!using_instrument?.ready()) @@ -208,7 +208,6 @@ to_chat(user, span_warning("Song is empty.")) return playing = TRUE - updateDialog(user_playing) //we can not afford to runtime, since we are going to be doing sound channel reservations and if we runtime it means we have a channel allocation leak. //wrap the rest of the stuff to ensure stop_playing() is called. do_hearcheck() @@ -216,7 +215,9 @@ elapsed_delay = 0 delay_by = 0 current_chord = 1 - user_playing = user + music_player = user + if(ismob(music_player)) + updateDialog(music_player) START_PROCESSING(SSinstruments, src) /** @@ -232,13 +233,13 @@ SEND_SIGNAL(parent, COMSIG_SONG_END) terminate_all_sounds(TRUE) hearing_mobs.len = 0 - user_playing = null + music_player = null /** * Processes our song. */ /datum/song/proc/process_song(wait) - if(!length(compiled_chords) || should_stop_playing(user_playing)) + if(!length(compiled_chords) || should_stop_playing(music_player) == STOP_PLAYING) stop_playing() return var/list/chord = compiled_chords[current_chord] @@ -276,13 +277,26 @@ /datum/song/proc/play_chord(list/chord) // last value is timing information for(var/i in 1 to (length(chord) - 1)) - legacy? playkey_legacy(chord[i][1], chord[i][2], chord[i][3], user_playing) : playkey_synth(chord[i], user_playing) + legacy? playkey_legacy(chord[i][1], chord[i][2], chord[i][3], music_player) : playkey_synth(chord[i], music_player) /** * Checks if we should halt playback. */ -/datum/song/proc/should_stop_playing(mob/user) - return QDELETED(parent) || !using_instrument || !playing +/datum/song/proc/should_stop_playing(atom/player) + if(QDELETED(player) || !using_instrument || !playing) + return STOP_PLAYING + return SEND_SIGNAL(parent, COMSIG_SONG_SHOULD_STOP_PLAYING, player) + +/// Sets and sanitizes the repeats variable. +/datum/song/proc/set_repeats(new_repeats_value) + 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(new_repeats_value) + if(repeat < 0) + repeat = 0 + if(repeat > max_repeats) + repeat = max_repeats + /** * Sanitizes tempo to a value that makes sense and fits the current world.tick_lag. @@ -332,7 +346,7 @@ * Setter for setting output volume. */ /datum/song/proc/set_volume(volume) - src.volume = clamp(volume, max(0, min_volume), min(100, max_volume)) + src.volume = clamp(round(volume, 1), max(0, min_volume), min(100, max_volume)) update_sustain() updateDialog() @@ -340,7 +354,7 @@ * Setter for setting how low the volume has to get before a note is considered "dead" and dropped */ /datum/song/proc/set_dropoff_volume(volume) - sustain_dropoff_volume = clamp(volume, INSTRUMENT_MIN_SUSTAIN_DROPOFF, 100) + sustain_dropoff_volume = clamp(round(volume, 0.01), INSTRUMENT_MIN_SUSTAIN_DROPOFF, 100) update_sustain() updateDialog() @@ -348,7 +362,7 @@ * Setter for setting exponential falloff factor. */ /datum/song/proc/set_exponential_drop_rate(drop) - sustain_exponential_dropoff = clamp(drop, INSTRUMENT_EXP_FALLOFF_MIN, INSTRUMENT_EXP_FALLOFF_MAX) + sustain_exponential_dropoff = clamp(round(drop, 0.00001), INSTRUMENT_EXP_FALLOFF_MIN, INSTRUMENT_EXP_FALLOFF_MAX) update_sustain() updateDialog() @@ -356,7 +370,7 @@ * Setter for setting linear falloff duration. */ /datum/song/proc/set_linear_falloff_duration(duration) - sustain_linear_duration = clamp(duration, 0.1, INSTRUMENT_MAX_TOTAL_SUSTAIN) + sustain_linear_duration = clamp(round(duration * 10, world.tick_lag), 0.1, INSTRUMENT_MAX_TOTAL_SUSTAIN) update_sustain() updateDialog() @@ -379,12 +393,12 @@ /datum/song/handheld/updateDialog(mob/user) parent.ui_interact(user || usr) -/datum/song/handheld/should_stop_playing(mob/user) +/datum/song/handheld/should_stop_playing(atom/player) . = ..() - if(.) - return TRUE + if(. == STOP_PLAYING || . == IGNORE_INSTRUMENT_CHECKS) + return var/obj/item/instrument/I = parent - return I.should_stop_playing(user) + return I.should_stop_playing(player) // subtype for stationary structures, like pianos /datum/song/stationary @@ -392,9 +406,9 @@ /datum/song/stationary/updateDialog(mob/user) parent.ui_interact(user || usr) -/datum/song/stationary/should_stop_playing(mob/user) +/datum/song/stationary/should_stop_playing(atom/player) . = ..() - if(.) + if(. == STOP_PLAYING || . == IGNORE_INSTRUMENT_CHECKS) return TRUE var/obj/structure/musician/M = parent - return M.should_stop_playing(user) + return M.should_stop_playing(player) diff --git a/code/modules/instruments/songs/editor.dm b/code/modules/instruments/songs/editor.dm index c2ff449c614..78c8ab5df00 100644 --- a/code/modules/instruments/songs/editor.dm +++ b/code/modules/instruments/songs/editor.dm @@ -90,15 +90,15 @@ /** * Parses a song the user has input into lines and stores them. */ -/datum/song/proc/ParseSong(text) +/datum/song/proc/ParseSong(new_song) set waitfor = FALSE //split into lines - lines = splittext(text, "\n") + lines = islist(new_song) ? new_song : splittext(new_song, "\n") if(lines.len) var/bpm_string = "BPM: " if(findtext(lines[1], bpm_string, 1, length(bpm_string) + 1)) var/divisor = text2num(copytext(lines[1], length(bpm_string) + 1)) || 120 // default - tempo = sanitize_tempo(600 / round(divisor, 1)) + tempo = sanitize_tempo(BPM_TO_TEMPO_SETTING(divisor)) lines.Cut(1, 2) else tempo = sanitize_tempo(5) // default 120 BPM @@ -148,13 +148,7 @@ editing = 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 + set_repeats(repeat + text2num(href_list["repeat"])) else if(href_list["tempo"]) tempo = sanitize_tempo(tempo + text2num(href_list["tempo"])) @@ -193,22 +187,22 @@ else if(href_list["setlinearfalloff"]) var/amount = input(usr, "Set linear sustain duration in seconds", "Linear Sustain Duration") as null|num if(!isnull(amount)) - set_linear_falloff_duration(round(amount * 10, world.tick_lag)) + set_linear_falloff_duration(amount) else if(href_list["setexpfalloff"]) var/amount = input(usr, "Set exponential sustain factor", "Exponential sustain factor") as null|num if(!isnull(amount)) - set_exponential_drop_rate(round(amount, 0.00001)) + set_exponential_drop_rate(amount) else if(href_list["setvolume"]) var/amount = input(usr, "Set volume", "Volume") as null|num if(!isnull(amount)) - set_volume(round(amount, 1)) + set_volume(amount) else if(href_list["setdropoffvolume"]) var/amount = input(usr, "Set dropoff threshold", "Dropoff Threshold Volume") as null|num if(!isnull(amount)) - set_dropoff_volume(round(amount, 0.01)) + set_dropoff_volume(amount) else if(href_list["switchinstrument"]) if(!length(allowed_instrument_ids)) @@ -238,12 +232,9 @@ note_shift = clamp(amount, note_shift_min, note_shift_max) else if(href_list["setsustainmode"]) - var/choice = input(usr, "Choose a sustain mode", "Sustain Mode") as null|anything in list("Linear", "Exponential") - switch(choice) - if("Linear") - sustain_mode = SUSTAIN_LINEAR - if("Exponential") - sustain_mode = SUSTAIN_EXPONENTIAL + var/choice = input(usr, "Choose a sustain mode", "Sustain Mode") as null|anything in 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 diff --git a/code/modules/instruments/songs/play_legacy.dm b/code/modules/instruments/songs/play_legacy.dm index bcd9935ab4c..c3664aca3be 100644 --- a/code/modules/instruments/songs/play_legacy.dm +++ b/code/modules/instruments/songs/play_legacy.dm @@ -46,7 +46,7 @@ * * acc is either "b", "n", or "#" * * oct is 1-8 (or 9 for C) */ -/datum/song/proc/playkey_legacy(note, acc as text, oct, mob/user) +/datum/song/proc/playkey_legacy(note, acc as text, oct, atom/player) // handle accidental -> B<>C of E<>F if(acc == "b" && (note == 3 || note == 6)) // C or F if(note == 3) @@ -82,7 +82,7 @@ var/sound/music_played = sound(soundfile) for(var/i in hearing_mobs) var/mob/M = i - if(user && HAS_TRAIT(user, TRAIT_MUSICIAN) && isliving(M)) + if(player && HAS_TRAIT(player, TRAIT_MUSICIAN) && isliving(M)) var/mob/living/L = M L.apply_status_effect(STATUS_EFFECT_GOOD_MUSIC) if(!(M?.client?.prefs?.toggles & SOUND_INSTRUMENTS)) diff --git a/code/modules/instruments/songs/play_synthesized.dm b/code/modules/instruments/songs/play_synthesized.dm index 649368b61ba..12062fc5db3 100644 --- a/code/modules/instruments/songs/play_synthesized.dm +++ b/code/modules/instruments/songs/play_synthesized.dm @@ -42,7 +42,7 @@ * Plays a specific numerical key from our instrument to anyone who can hear us. * Does a hearing check if enough time has passed. */ -/datum/song/proc/playkey_synth(key, mob/user) +/datum/song/proc/playkey_synth(key, atom/player) if(can_noteshift) key = clamp(key + note_shift, key_min, key_max) if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck) @@ -62,7 +62,7 @@ last_channel_played = channel_text for(var/i in hearing_mobs) var/mob/M = i - if(user && HAS_TRAIT(user, TRAIT_MUSICIAN) && isliving(M)) + if(player && HAS_TRAIT(player, TRAIT_MUSICIAN) && isliving(M)) var/mob/living/L = M L.apply_status_effect(STATUS_EFFECT_GOOD_MUSIC) if(!(M?.client?.prefs?.toggles & SOUND_INSTRUMENTS)) diff --git a/code/modules/instruments/stationary.dm b/code/modules/instruments/stationary.dm index 41d2c0e7284..97fe44d1dfd 100644 --- a/code/modules/instruments/stationary.dm +++ b/code/modules/instruments/stationary.dm @@ -15,12 +15,12 @@ QDEL_NULL(song) return ..() -/obj/structure/musician/proc/should_stop_playing(mob/user) - if(!(anchored || can_play_unanchored)) - return TRUE - if(!user) - return FALSE - return !user.canUseTopic(src, FALSE, TRUE, FALSE, FALSE) //can play with TK and while resting because fun. +/obj/structure/musician/proc/should_stop_playing(atom/music_player) + if(!(anchored || can_play_unanchored) || !ismob(music_player)) + return STOP_PLAYING + var/mob/user = music_player + if(!user.canUseTopic(src, FALSE, TRUE, FALSE, FALSE)) //can play with TK and while resting because fun. + return STOP_PLAYING /obj/structure/musician/ui_interact(mob/user) . = ..() diff --git a/tgstation.dme b/tgstation.dme index f3fae2101be..ceda498dbce 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2649,6 +2649,7 @@ #include "code\modules\hydroponics\grown\weeds\nettle.dm" #include "code\modules\hydroponics\grown\weeds\starthistle.dm" #include "code\modules\instruments\items.dm" +#include "code\modules\instruments\piano_synth.dm" #include "code\modules\instruments\stationary.dm" #include "code\modules\instruments\instrument_data\_instrument_data.dm" #include "code\modules\instruments\instrument_data\_instrument_key.dm"