diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 5695995713..9cae56645f 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -80,7 +80,7 @@ //DNA - Because fuck you and your magic numbers being all over the codebase. #define DNA_BLOCK_SIZE 3 -#define DNA_UNI_IDENTITY_BLOCKS 15 +#define DNA_UNI_IDENTITY_BLOCKS 19 #define DNA_HAIR_COLOR_BLOCK 1 #define DNA_FACIAL_HAIR_COLOR_BLOCK 2 #define DNA_SKIN_TONE_BLOCK 3 @@ -96,6 +96,10 @@ #define DNA_MUTANTEAR_BLOCK 13 #define DNA_MUTANTMARKING_BLOCK 14 #define DNA_TAUR_BLOCK 15 +#define DNA_BARK_SOUND_BLOCK 16 +#define DNA_BARK_SPEED_BLOCK 17 +#define DNA_BARK_PITCH_BLOCK 18 +#define DNA_BARK_VARIANCE_BLOCK 19 #define DNA_SEQUENCE_LENGTH 4 #define DNA_MUTATION_BLOCKS 8 diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index d2aa2f6a91..5581d71080 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -15,6 +15,7 @@ #define DISABLE_DEATHRATTLE (1<<12) #define DISABLE_ARRIVALRATTLE (1<<13) #define COMBOHUD_LIGHTING (1<<14) +#define SOUND_BARK (1<<15) #define DEADMIN_ALWAYS (1<<0) #define DEADMIN_ANTAGONIST (1<<1) @@ -22,7 +23,7 @@ #define DEADMIN_POSITION_SECURITY (1<<3) #define DEADMIN_POSITION_SILICON (1<<4) -#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE|SOUND_PRAYERS|SOUND_ANNOUNCEMENTS) +#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE|SOUND_PRAYERS|SOUND_ANNOUNCEMENTS|SOUND_BARK) //Chat toggles #define CHAT_OOC (1<<0) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 3e5658fa00..cd17b3aed0 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -79,6 +79,10 @@ var/datum/emote/E = new path() E.emote_list[E.key] = E + for(var/path in subtypesof(/datum/bark)) + var/datum/bark/B = new path() + GLOB.bark_list[B.id] = path + // Hair Gradients - Initialise all /datum/sprite_accessory/hair_gradient into an list indexed by gradient-style name for(var/path in subtypesof(/datum/sprite_accessory/hair_gradient)) var/datum/sprite_accessory/hair_gradient/H = new path() diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index da8b0ed3ee..f300455173 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -43,6 +43,9 @@ GLOBAL_LIST_EMPTY(arachnid_spinneret_list) GLOBAL_LIST_EMPTY(arachnid_mandibles_list) GLOBAL_LIST_EMPTY(caps_list) + //Bark bits +GLOBAL_LIST_EMPTY(bark_list) + //a way to index the right bodypart list given the type of bodypart GLOBAL_LIST_INIT(mutant_reference_list, list( "tail_lizard" = GLOB.tails_list_lizard, diff --git a/code/datums/bark.dm b/code/datums/bark.dm new file mode 100644 index 0000000000..7e7a2dcc5d --- /dev/null +++ b/code/datums/bark.dm @@ -0,0 +1,98 @@ +//Datums for barks and bark accessories + +/datum/bark + var/name = "Default" + var/id = "Default" + var/soundpath //Path for the actual sound file used for the bark + + // Pitch vars. The actual range for a bark is [(pitch - (maxvariance*0.5)) to (pitch + (maxvariance*0.5))] + // Make absolutely sure to take variance into account when curating a sound for bark purposes. + var/minpitch = 0.6 + var/maxpitch = 1.4 + var/minvariance = 0.1 + var/maxvariance = 0.4 + + // Speed vars. Speed determines the number of characters required for each bark, with lower speeds being faster with higher bark density + var/minspeed = 2 + var/maxspeed = 8 + + // Visibility vars. Regardless of what's set below, these can still be obtained via adminbus and genetics. Rule of fun. + var/list/ckeys_allowed + var/ignore = FALSE //Controls whether or not this can be chosen in chargen + + +// So the basic jist of the sound design here: We make use primarily of shorter instrument samples for barks. We would've went with animalese instead, but doing so would've involved quite a bit of overhead to saycode. +// Short instrument samples tend to sound surprisingly nice for barks, being able to be played in rapid succession without being outright obnoxious. +// It isn't just instruments that work well here, however. Anything that works well as a stab? Short attack, no sustain, a decent amount of release? Also works extremely well for barks. + +/datum/bark/mutedc2 + name = "Muted String (Low)" + id = "mutedc2" + soundpath = 'sound/instruments/synthesis_samples/guitar/crisis_muted/C2.ogg' + +/datum/bark/mutedc3 + name = "Muted String (Medium)" + id = "mutedc3" + soundpath = 'sound/instruments/synthesis_samples/guitar/crisis_muted/C3.ogg' + +/datum/bark/mutedc4 + name = "Muted String (High)" + id = "mutedc4" + soundpath = 'sound/instruments/synthesis_samples/guitar/crisis_muted/C4.ogg' + +/datum/bark/banjoc3 + name = "Banjo (Medium)" + id = "banjoc3" + soundpath = 'sound/instruments/banjo/Cn3.ogg' + +/datum/bark/banjoc4 + name = "Banjo (High)" + id = "banjoc4" + soundpath = 'sound/instruments/banjo/Cn4.ogg' + +/datum/bark/bikehorn + name = "Bikehorn" + id = "horn" + soundpath = 'sound/instruments/bikehorn/Cn4.ogg' + ignore = TRUE // Genetics only. This is an unusually quiet sound, but genetics should be allowed to have some !!fun!! + +/datum/bark/bwoink + name = "Bwoink" + id = "bwoink" + soundpath = 'sound/effects/adminhelp.ogg' + ignore = TRUE // Also genetics only. Emergent heart attack generation + +/datum/bark/squeaky + name = "Squeaky" + id = "squeak" + soundpath = 'sound/items/toysqueak1.ogg' + maxspeed = 4 + +/datum/bark/beep + name = "Beepy" + id = "beep" + soundpath = 'sound/machines/terminal_select.ogg' + maxpitch = 1 //Bringing the pitch higher just hurts your ears :< + maxspeed = 4 //This soundbyte's too short for larger speeds to not sound awkward + +/datum/bark/chitter + name = "Chittery" + id = "chitter" + minspeed = 6 //This is a pretty long sound + soundpath = 'sound/items/Ratchet.ogg' + +/datum/bark/synthetic_grunt + name = "Synthetic (Grunt)" + id = "synthgrunt" + soundpath = 'sound/misc/bloop.ogg' + +/datum/bark/synthetic + name = "Synthetic (Normal)" + id = "synth" + soundpath = 'sound/machines/uplinkerror.ogg' + +/datum/bark/bullet + name = "Windy" + id = "bullet" + maxpitch = 1.6 //This works well with higher pitches! + soundpath = 'sound/weapons/bulletflyby.ogg' //This works... Surprisingly well as a bark? It's neat! diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 5d0ff4daec..6a93838d09 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -153,6 +153,10 @@ if(!GLOB.taur_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list) L[DNA_TAUR_BLOCK] = construct_block(GLOB.taur_list.Find(features["taur"]), GLOB.taur_list.len) + L[DNA_BARK_SOUND_BLOCK] = construct_block(GLOB.bark_list.Find(H.vocal_bark_id), GLOB.bark_list.len) + L[DNA_BARK_SPEED_BLOCK] = construct_block(H.vocal_speed * 4, 16) + L[DNA_BARK_PITCH_BLOCK] = construct_block(H.vocal_pitch * 30, 48) + L[DNA_BARK_VARIANCE_BLOCK] = construct_block(H.vocal_pitch_range * 48, 48) for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++) if(L[i]) @@ -248,19 +252,19 @@ if(DNA_HAIR_STYLE_BLOCK) setblock(uni_identity, blocknumber, construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len)) if(DNA_COLOR_ONE_BLOCK) - sanitize_hexcolor(features["mcolor"], 6) + setblock(uni_identity, blocknumber, sanitize_hexcolor(features["mcolor"], 6)) if(DNA_COLOR_TWO_BLOCK) - sanitize_hexcolor(features["mcolor2"], 6) + setblock(uni_identity, blocknumber, sanitize_hexcolor(features["mcolor2"], 6)) if(DNA_COLOR_THREE_BLOCK) - sanitize_hexcolor(features["mcolor3"], 6) + setblock(uni_identity, blocknumber, sanitize_hexcolor(features["mcolor3"], 6)) if(DNA_MUTANTTAIL_BLOCK) - construct_block(GLOB.mam_tails_list.Find(features["mam_tail"]), GLOB.mam_tails_list.len) + setblock(uni_identity, blocknumber, construct_block(GLOB.mam_tails_list.Find(features["mam_tail"]), GLOB.mam_tails_list.len)) if(DNA_MUTANTEAR_BLOCK) - construct_block(GLOB.mam_ears_list.Find(features["mam_ears"]), GLOB.mam_ears_list.len) + setblock(uni_identity, blocknumber, construct_block(GLOB.mam_ears_list.Find(features["mam_ears"]), GLOB.mam_ears_list.len)) if(DNA_MUTANTMARKING_BLOCK) - construct_block(GLOB.mam_body_markings_list.Find(features["mam_body_markings"]), GLOB.mam_body_markings_list.len) + setblock(uni_identity, blocknumber, construct_block(GLOB.mam_body_markings_list.Find(features["mam_body_markings"]), GLOB.mam_body_markings_list.len)) if(DNA_TAUR_BLOCK) - construct_block(GLOB.taur_list.Find(features["taur"]), GLOB.taur_list.len) + setblock(uni_identity, blocknumber, construct_block(GLOB.taur_list.Find(features["taur"]), GLOB.taur_list.len)) if(species.mutant_bodyparts["taur"] && ishuman(holder)) var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]] switch(T?.taur_mode) @@ -272,6 +276,14 @@ H.physiology.footstep_type = FOOTSTEP_MOB_CRAWL else H.physiology.footstep_type = null + if(DNA_BARK_SOUND_BLOCK) + setblock(uni_identity, blocknumber, construct_block(GLOB.bark_list.Find(H.vocal_bark_id), GLOB.bark_list.len)) + if(DNA_BARK_SPEED_BLOCK) + setblock(uni_identity, blocknumber, construct_block(H.vocal_speed * 4, 16)) + if(DNA_BARK_PITCH_BLOCK) + setblock(uni_identity, blocknumber, construct_block(H.vocal_pitch * 30, 48)) + if(DNA_BARK_VARIANCE_BLOCK) + setblock(uni_identity, blocknumber, construct_block(H.vocal_pitch_range * 48, 48)) //Please use add_mutation or activate_mutation instead /datum/dna/proc/force_give(datum/mutation/human/HM) @@ -491,6 +503,10 @@ update_body_parts() if(mutations_overlay_update) update_mutations_overlay() + set_bark(GLOB.bark_list[deconstruct_block(getblock(structure, DNA_BARK_SOUND_BLOCK), GLOB.bark_list.len)]) + vocal_speed = (deconstruct_block(getblock(structure, DNA_BARK_PITCH_BLOCK), 16) / 16) + vocal_pitch = (deconstruct_block(getblock(structure, DNA_BARK_PITCH_BLOCK), 48) / 30) + vocal_pitch_range = (deconstruct_block(getblock(structure, DNA_BARK_VARIANCE_BLOCK), 48) / 48) /mob/proc/domutcheck() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 7cad67bd84..ca133f882e 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -64,6 +64,14 @@ /// last time we yelled var/last_yell = 0 + // Text-to-bark sounds + var/sound/vocal_bark + var/vocal_bark_id + var/vocal_pitch = 1 + var/vocal_pitch_range = 0.2 //Actual pitch is (pitch - (vocal_pitch_range*0.5)) to (pitch + (vocal_pitch_range*0.5)) + var/vocal_volume = 70 //Baseline. This gets modified by yelling and other factors + var/vocal_speed = 4 //Lower values are faster, higher values are slower + /atom/movable/Initialize(mapload) . = ..() switch(blocks_emissive) @@ -696,6 +704,17 @@ var/datum/language_holder/LH = get_language_holder() return LH.update_atom_languages(src) +/// Sets the vocal bark for the atom, using the bark's ID +/atom/movable/proc/set_bark(id) + if(!id) + return FALSE + var/datum/bark/B = GLOB.bark_list[id] + if(!B) + return FALSE + vocal_bark = sound(initial(B.soundpath)) + vocal_bark_id = id + return vocal_bark + /* End language procs */ diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 0d95448702..1fb2405584 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -104,6 +104,9 @@ Class Procs: anchored = TRUE interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT + vocal_bark_id = "synth" + vocal_pitch = 0.6 + var/stat = 0 var/use_power = IDLE_POWER_USE //0 = dont run the auto diff --git a/code/game/say.dm b/code/game/say.dm index b7bfe540d0..0de96fa3db 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -31,14 +31,35 @@ GLOBAL_LIST_INIT(freqtospan, list( /atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source) SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args) +/atom/movable/proc/bark(list/hearers, distance, volume, pitch) + if(!vocal_bark) + if(!vocal_bark_id || !set_bark(vocal_bark_id)) //just-in-time bark generation + return + volume = min(volume, 100) + var/turf/T = get_turf(src) + for(var/mob/M in hearers) + M.playsound_local(T, vol = volume, vary = TRUE, frequency = pitch, max_distance = distance, falloff_distance = distance * 0.75, S = vocal_bark, distance_multiplier = 1) + /atom/movable/proc/can_speak() return 1 /atom/movable/proc/send_speech(message, range = 7, atom/movable/source = src, bubble_type, list/spans, datum/language/message_language = null, message_mode) var/rendered = compose_message(src, message_language, message, , spans, message_mode, source) - for(var/_AM in get_hearers_in_view(range, source)) + var/list/hearers = get_hearers_in_view(range, source) + for(var/_AM in hearers) var/atom/movable/AM = _AM AM.Hear(rendered, src, message_language, message, , spans, message_mode, source) + if(vocal_bark || vocal_bark_id) + for(var/mob/M in hearers) + if(!M.client) + continue + if(!(M.client.prefs.toggles & SOUND_BARK)) + hearers -= M + var/barks = round((LAZYLEN(message) / vocal_speed)) + 1 + var/total_delay + for(var/i in 1 to barks) + addtimer(CALLBACK(src, .proc/bark, hearers, range, vocal_volume, rand((vocal_pitch * 100), (vocal_pitch*100) + (vocal_pitch_range*100)) / 100), total_delay) + total_delay += rand(DS2TICKS(vocal_speed/4), DS2TICKS(vocal_speed/4) + DS2TICKS(vocal_speed/4)) TICKS /atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, face_name = FALSE, atom/movable/source) if(!source) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 8600e44faf..33e87ca0e3 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -140,6 +140,13 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/modified_limbs = list() //prosthetic/amputated limbs var/chosen_limb_id //body sprite selected to load for the users limbs, null means default, is sanitized when loaded + // Vocal bark prefs + var/bark_id = "mutedc3" + var/bark_speed = 4 + var/bark_pitch = 1 + var/bark_variance = 0.2 + COOLDOWN_DECLARE(bark_previewing) + /// Security record note section var/security_records /// Medical record note section @@ -795,11 +802,21 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
"
dat += "Speech preferences" dat += "Custom Speech Verb:" - dat += "[custom_speech_verb] " + dat += "[custom_speech_verb] " dat += "Custom Tongue: " - dat += "[custom_tongue] " + dat += "[custom_tongue] " dat += "Additional Language " - dat += "[additional_language] " + dat += "[additional_language] " + dat += " | "
+ dat += ""
+ dat += "Vocal Bark preferences" + var/datum/bark/B = GLOB.bark_list[bark_id] + dat += "Vocal Bark Sound:" + dat += "[B ? initial(B.name) : "INVALID"] " + dat += "Vocal Bark Speed: [bark_speed] " + dat += "Vocal Bark Pitch: [bark_pitch] " + dat += "Vocal Bark Variance: [bark_variance] " + dat += " Preview Bark " dat += " | "
dat += "