diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index fb738dc18ac..beee5f6c47d 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -59,6 +59,7 @@ #define ORGAN_VITAL (1<<4) //Currently only the brain #define ORGAN_EDIBLE (1<<5) //is a snack? :D #define ORGAN_SYNTHETIC_EMP (1<<6) //Synthetic organ affected by an EMP. Deteriorates over time. +#define ORGAN_UNREMOVABLE (1<<7) //Can't be removed using surgery /// Integrity defines for clothing (not flags but close enough) #define CLOTHING_PRISTINE 0 // We have no damage on the clothing diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 656c2f1592a..2b74bd98042 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -192,6 +192,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good.... #define TRAIT_TUMOR_SUPPRESSED "brain_tumor_suppressed" //prevents the damage done by a brain tumor #define TRAIT_PERMANENTLY_ONFIRE "permanently_onfire" //overrides the update_fire proc to always add fire (for lava) +#define TRAIT_SIGN_LANG "sign_language" //Galactic Common Sign Language //SKILLS #define TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE "underwater_basketweaving" diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 287d168c329..f196a136317 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -120,6 +120,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NICE_SHOT" = TRAIT_NICE_SHOT, "TRAIT_TUMOR_SUPPRESSION" = TRAIT_TUMOR_SUPPRESSED, "TRAIT_PERMANENTLY_ONFIRE" = TRAIT_PERMANENTLY_ONFIRE, + "TRAIT_SIGN_LANG" = TRAIT_SIGN_LANG, "TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE, "TRAIT_WINE_TASTER" = TRAIT_WINE_TASTER, "TRAIT_BONSAI" = TRAIT_BONSAI, @@ -150,6 +151,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_GRABWEAKNESS" = TRAIT_GRABWEAKNESS, "TRAIT_SNOB" = TRAIT_SNOB, "TRAIT_BALD" = TRAIT_BALD + ), /obj/item/bodypart = list( "TRAIT_PARALYSIS" = TRAIT_PARALYSIS diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index 80fea40c72e..358d80ae207 100644 --- a/code/datums/components/crafting/recipes.dm +++ b/code/datums/components/crafting/recipes.dm @@ -385,6 +385,17 @@ /obj/item/organ/ears/cat = 1) category = CAT_CLOTHING + +/datum/crafting_recipe/radiogloves + name = "Translation Gloves" + result = /obj/item/clothing/gloves/radio + time = 15 + reqs = list(/obj/item/clothing/gloves/color/black = 1, + /obj/item/stack/cable_coil = 2, + /obj/item/radio = 1) + tools = list(TOOL_WIRECUTTER) + category = CAT_CLOTHING + /datum/crafting_recipe/mixedbouquet name = "Mixed bouquet" result = /obj/item/bouquet @@ -414,6 +425,7 @@ parts = list(/obj/item/camera = 1) category = CAT_MISC + /datum/crafting_recipe/skateboard name = "Skateboard" result = /obj/vehicle/ridden/scooter/skateboard diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm index 9cdb7e3ae4f..94db88f2bcf 100644 --- a/code/datums/traits/neutral.dm +++ b/code/datums/traits/neutral.dm @@ -244,3 +244,27 @@ SIGNAL_HANDLER SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "bad_hair_day", /datum/mood_event/bald) + + +/datum/quirk/tongue_tied + name = "Tongue Tied" + desc = "Due to a past incident, your ability to communicate has been relegated to your hands." + value = 0 + medical_record_text = "During physical examination, patient's tongue was found to be uniquely damaged." + +//Adds tongue & gloves +/datum/quirk/tongue_tied/on_spawn() + var/mob/living/carbon/human/H = quirk_holder + var/obj/item/organ/tongue/old_tongue = locate() in H.internal_organs + var/obj/item/organ/tongue/tied/new_tongue = new(get_turf(H)) + var/obj/item/clothing/gloves/radio/gloves = new(get_turf(H)) + old_tongue.Remove(H) + new_tongue.Insert(H) + qdel(old_tongue) + H.put_in_hands(gloves) + H.equip_to_slot(gloves, ITEM_SLOT_GLOVES) + H.regenerate_icons() + +/datum/quirk/tongue_tied/post_add() + to_chat(quirk_holder, "Because you speak with your hands, having them full hinders your ability to communicate!") + diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 73e368a8236..5de46b3ae22 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -186,6 +186,19 @@ . = TRUE /obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language, list/message_mods) + if(HAS_TRAIT(M, TRAIT_SIGN_LANG)) //Forces Sign Language users to wear the translation gloves to speak over radios + var/mob/living/carbon/mute = M + if(istype(mute)) + var/empty_indexes = mute.get_empty_held_indexes() //How many hands the player has empty + var/obj/item/clothing/gloves/radio/G = mute.get_item_by_slot(ITEM_SLOT_GLOVES) + if(!istype(G)) + return FALSE + if(length(empty_indexes) == 1) + message = stars(message) + if(length(empty_indexes) == 0) //Due to the requirement of gloves, the arm check for normal speech would be redundant here. + return FALSE + if(mute.handcuffed)//Would be weird if they couldn't sign but their words still went over the radio + return FALSE if(!spans) spans = list(M.speech_span) if(!language) diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index ffbf74fe636..79353906d63 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -146,6 +146,12 @@ icon_state = "wizard" inhand_icon_state = "purplegloves" +/obj/item/clothing/gloves/radio + name = "translation gloves" + desc = "A pair of electronic gloves which connect to nearby radios wirelessly. Allows for sign language users to 'speak' over comms." + icon_state = "radio_g" + inhand_icon_state = "radio_g" + /obj/item/clothing/gloves/color/plasmaman/head_of_personnel name = "head of personnel's envirogloves" desc = "Covers up those scandalous, bony hands. Appears to be an attempt at making a replica of the captain's gloves." diff --git a/code/modules/mob/living/carbon/carbon_say.dm b/code/modules/mob/living/carbon/carbon_say.dm index b57d4e4d270..7ce6fca9030 100644 --- a/code/modules/mob/living/carbon/carbon_say.dm +++ b/code/modules/mob/living/carbon/carbon_say.dm @@ -11,7 +11,10 @@ /mob/living/carbon/can_speak_vocal(message) if(silent) - return 0 + if(HAS_TRAIT(src, TRAIT_SIGN_LANG)) + return ..() + else + return FALSE return ..() /mob/living/carbon/could_speak_language(datum/language/language) diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index b9a1eeac630..a19d680222c 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -222,6 +222,27 @@ GLOBAL_LIST_INIT(department_radio_keys, list( var/deaf_message var/deaf_type + if(HAS_TRAIT(speaker, TRAIT_SIGN_LANG)) //Checks if speaker is using sign language + deaf_message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mods) + if(speaker != src) + if(!radio_freq) //I'm about 90% sure there's a way to make this less cluttered + deaf_type = 1 + else + deaf_type = 2 + + // Create map text prior to modifying message for goonchat, sign lang edition + if (client?.prefs.chat_on_map && !(stat == UNCONSCIOUS || stat == HARD_CRIT) && (client.prefs.see_chat_non_mob || ismob(speaker))) + create_chat_message(speaker, message_language, raw_message, spans) + + if(is_blind(src)) + return FALSE + + + message = deaf_message + + show_message(message, MSG_VISUAL, deaf_message, deaf_type, avoid_highlighting = speaker == src) + return message + if(speaker != src) if(!radio_freq) //These checks have to be seperate, else people talking on the radio will make "You can't hear yourself!" appear when hearing people over the radio while deaf. deaf_message = "[speaker] [speaker.verb_say] something but you cannot hear [speaker.p_them()]." @@ -246,6 +267,24 @@ GLOBAL_LIST_INIT(department_radio_keys, list( eavesdrop_range = EAVESDROP_EXTRA_RANGE var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source) var/list/the_dead = list() + if(HAS_TRAIT(src, TRAIT_SIGN_LANG)) + var/mob/living/carbon/mute = src + if(istype(mute)) + var/empty_indexes = get_empty_held_indexes() //How many hands the player has empty + if(length(empty_indexes) == 1 || !mute.get_bodypart(BODY_ZONE_L_ARM) || !mute.get_bodypart(BODY_ZONE_R_ARM)) + message = stars(message) + if(length(empty_indexes) == 0)//Both hands full, can't sign + to_chat(src, "You can't sign with your hands full!") + return FALSE + if(!mute.get_bodypart(BODY_ZONE_L_ARM) && !mute.get_bodypart(BODY_ZONE_R_ARM))//Can't sign with no arms! + to_chat(src, "You can't sign with no hands!") + return FALSE + if(mute.handcuffed)//Can't sign when your hands are cuffed, but can at least make a visual effort to + mute.visible_message("[src] tries to sign, but can't with [src.p_their()] hands cuffed!") + return FALSE + if(mute.has_status_effect(STATUS_EFFECT_PARALYZED)) + to_chat(src, "You can't sign in this state!") + return FALSE if(client) //client is so that ghosts don't have to listen to mice for(var/_M in GLOB.player_list) var/mob/M = _M @@ -303,14 +342,15 @@ GLOBAL_LIST_INIT(department_radio_keys, list( return TRUE /mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels + var/mob/living/carbon/human/H = src if(HAS_TRAIT(src, TRAIT_MUTE)) - return FALSE + return (HAS_TRAIT(src, TRAIT_SIGN_LANG) && !H.mind.miming) //Makes sure mimes can't speak using sign language if(is_muzzled()) - return FALSE + return (HAS_TRAIT(src, TRAIT_SIGN_LANG) && !H.mind.miming) if(!IsVocal()) - return FALSE + return (HAS_TRAIT(src, TRAIT_SIGN_LANG) && !H.mind.miming) return TRUE @@ -376,9 +416,15 @@ GLOBAL_LIST_INIT(department_radio_keys, list( else if(message_mods[MODE_SING]) . = verb_sing else if(stuttering) - . = "stammers" + if(HAS_TRAIT(src, TRAIT_SIGN_LANG)) + . = "shakily signs" + else + . = "stammers" else if(derpspeech) - . = "gibbers" + if(HAS_TRAIT(src, TRAIT_SIGN_LANG)) + . = "incoherently signs" + else + . = "gibbers" else . = ..() diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index 829a74b6225..dc5f90442d0 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -119,12 +119,16 @@ I = organs[I] if(!I) return -1 + if(I.organ_flags & ORGAN_UNREMOVABLE) + to_chat(user, "[I] is too well connected to take out!") + return -1 display_results(user, target, "You begin to extract [I] from [target]'s [parse_zone(target_zone)]...", "[user] begins to extract [I] from [target]'s [parse_zone(target_zone)].", "[user] begins to extract something from [target]'s [parse_zone(target_zone)].") else return -1 + /datum/surgery_step/manipulate_organs/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) if(current_type == "insert") if(istype(tool, /obj/item/organ_storage)) diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index 2acdd9d3a7a..4aacbd38612 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -318,3 +318,53 @@ /obj/item/organ/tongue/ethereal/Initialize(mapload) . = ..() languages_possible = languages_possible_ethereal + +//Sign Language Tongue - yep, that's how you speak sign language. +/obj/item/organ/tongue/tied + name = "tied tongue" + desc = "If only one had a sword so we may finally untie this knot." + say_mod = "signs" + icon_state = "tonguetied" + modifies_speech = TRUE + organ_flags = ORGAN_UNREMOVABLE + +/obj/item/organ/tongue/tied/Insert(mob/living/carbon/M) + . = ..() + M.verb_ask = "signs" + M.verb_exclaim = "signs" + M.verb_whisper = "subtly signs" + M.verb_sing = "rythmically signs" + M.verb_yell = "emphatically signs" + ADD_TRAIT(M, TRAIT_SIGN_LANG, "tongue") + REMOVE_TRAIT(M, TRAIT_MUTE, "tongue") + +/obj/item/organ/tongue/tied/Remove(mob/living/carbon/M, special = 0) + ..() + M.verb_ask = initial(verb_ask) + M.verb_exclaim = initial(verb_exclaim) + M.verb_whisper = initial(verb_whisper) + M.verb_sing = initial(verb_sing) + M.verb_yell = initial(verb_yell) + REMOVE_TRAIT(M, TRAIT_SIGN_LANG, "tongue") //People who are Ahealed get "cured" of their sign language-having ways. If I knew how to make the tied tongue persist through aheals, I'd do that. + +//Thank you Jwapplephobia for helping me with the literal hellcode below + +/obj/item/organ/tongue/tied/handle_speech(datum/source, list/speech_args) + var/new_message + var/message = speech_args[SPEECH_MESSAGE] + var/exclamation_found = findtext(message, "!") + var/question_found = findtext(message, "?") + var/mob/living/carbon/M = owner + new_message = message + if(exclamation_found) + new_message = replacetext(new_message, "!", "") + if(question_found) + new_message = replacetext(new_message, "?", "") + speech_args[SPEECH_MESSAGE] = new_message + + if(exclamation_found && question_found) + M.visible_message("[M] lowers one of [M.p_their()] eyebrows, raising the other.") + else if(exclamation_found) + M.visible_message("[M] raises [M.p_their()] eyebrows.") + else if(question_found) + M.visible_message("[M] lowers [M.p_their()] eyebrows.") diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index e00aac8c7d3..deaa2c08902 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index d10a3931fa5..cbf0904277a 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index c681bcfd235..ea1169737b8 100755 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ