[MIRROR] Replaces Upgraded Cybernetic Ears with two new variants [MDB IGNORE] (#22854)

* Replaces Upgraded Cybernetic Ears with two new variants  (#75931)

## About The Pull Request
Adjusts the placement of basic and upgraded cybernetic ears in the
research tree and adds two new variants: Whisper-sensitive Cybernetic
Ears, which make it slightly easier to hear whispers from a tile away,
at the cost of higher vulnerability to flashbangs and other loud noises;
and Wall-penetrating Cybernetic Ears, which allow you to 'hear through
walls' so to speak, also at the cost of higher vulnerability to loud
noises.

Basic cybernetic ears are now in basic medical tech node, meaning that
medbay can print them roundstart the same as other basic cybernetics.
The upgraded cybernetic ears are now unlocked with the other tier 2
cybernetics. The two new ear variants are unlocked with the other tier 3
cybernetic organs, and the luminiscent and welding shield eyes have also
been moved there from the cybernetic implants node for consistency
reasons.

The whisper ears allow you to clearly hear whispers from up to seven
tiles away, the same range where you can hear normal speech. The
wall-penetrating ears allow you to hear normal speech within seven tiles
even through walls. Due to technical limitations, runechat popups do not
show up for people you can't see, but the messages will still show up in
chat.
## Why It's Good For The Game
Currently, upgraded cybernetic ears are very underwhelming compared to
other high-tier cybernetic organs. All other high tier organs provide
some sort of benefit; even if the benefit is minor like a built-in
flashlight, a slightly higher tolerance to alcohol and toxins, or higher
tolerance to disgusting food. This change is intended to grant similarly
minor but useful benefits to the cybernetic ears.
## Changelog
🆑
add: Added whisper-sensitive cybernetic ears, which make it much easier
for the user to hear whispers at the cost of being more vulnerable to
loud noises
add: Added wall-penetrating cybernetic ears, which allow you to hear
speech through walls
balance: Basic cybernetic ears and upgraded cybernetic ears are now
unlocked with the other basic/normal cybernetics
balance: The welding shield and luminiscent cybernetic eyes are now
unlocked with the other upgraded cybernetics
/🆑

* Replaces Upgraded Cybernetic Ears with two new variants

* Modular adjustments

* Linters

* Linters

---------

Co-authored-by: GPeckman <21979502+GPeckman@users.noreply.github.com>
Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-08-03 06:51:26 -04:00
committed by GitHub
co-authored by GPeckman Giz
parent 87b014cb04
commit b9f559776e
14 changed files with 177 additions and 50 deletions
+5 -1
View File
@@ -82,7 +82,11 @@
#define REDUCE_RANGE (1<<1)
#define NOPASS (1<<2)
//Eavesdropping
/// Range to hear normal messages
#define MESSAGE_RANGE 7
/// Range to hear whispers normally
#define WHISPER_RANGE 1
/// Additional range to partially hear whispers
#define EAVESDROP_EXTRA_RANGE 1 //how much past the specified message_range does the message get starred, whispering only
/// How close intercoms can be for radio code use
+4
View File
@@ -359,6 +359,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define IGNORING_GRAVITY_NEGATION "ignoring_gravity_negation"
/// We have some form of forced gravity acting on us
#define TRAIT_FORCED_GRAVITY "forced_gravity"
/// Makes whispers clearly heard from seven tiles away, the full hearing range
#define TRAIT_GOOD_HEARING "good_hearing"
/// Allows you to hear speech through walls
#define TRAIT_XRAY_HEARING "xray_hearing"
/// Lets us scan reagents
#define TRAIT_REAGENT_SCANNER "reagent_scanner"
+1
View File
@@ -3,3 +3,4 @@
#define EXAMINE_SECTION_BREAK "<hr>"
#define LOOC_RANGE 7
+34
View File
@@ -118,6 +118,40 @@
return .
/**
* The exact same as get_hearers_in_view, but not limited by visibility. Does no filtering for traits, line of sight, or any other such criteria.
* Filtering is intended to be done by whatever calls this function.
*
* This function exists to allow for mobs to hear speech without line of sight, if such a thing is needed.
*
* * radius - what radius search circle we are using, worse performance as this increases
* * source - object at the center of our search area. everything in get_turf(source) is guaranteed to be part of the search area
*/
/proc/get_hearers_in_range(range, atom/source)
var/turf/center_turf = get_turf(source)
if(!center_turf)
return
. = list()
if(range <= 0)//special case for if only source cares
for(var/atom/movable/target as anything in center_turf)
var/list/recursive_contents = target.important_recursive_contents?[RECURSIVE_CONTENTS_HEARING_SENSITIVE]
if(recursive_contents)
. += recursive_contents
return .
var/list/hearables_from_grid = SSspatial_grid.orthogonal_range_search(source, RECURSIVE_CONTENTS_HEARING_SENSITIVE, range)
if(!length(hearables_from_grid))//we know that something is returned by the grid, but we dont know if we need to actually filter down the output
return .
for(var/atom/movable/hearable as anything in hearables_from_grid)
if (get_dist(center_turf, hearable) <= range)
. += hearable
return .
/**
* Returns a list of movable atoms that are hearing sensitive in view_radius and line of sight to source
* the majority of the work is passed off to the spatial grid if view_radius > 0
+1 -1
View File
@@ -17,7 +17,7 @@
/** Get all hearers in range, ignores walls and such. Code stolen from `/proc/get_hearers_in_view()`
* Much faster and less expensive than range()
*/
/proc/get_hearers_in_range(range_radius, atom/source)
/proc/get_hearers_in_looc_range(atom/source, range_radius = LOOC_RANGE)
var/turf/center_turf = get_turf(source)
if(!center_turf)
return
+2
View File
@@ -207,6 +207,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_MORBID" = TRAIT_MORBID,
"TRAIT_UNDENSE" = TRAIT_UNDENSE,
"TRAIT_EXPANDED_FOV" = TRAIT_EXPANDED_FOV,
"TRAIT_GOOD_HEARING" = TRAIT_GOOD_HEARING,
"TRAIT_XRAY_HEARING" = TRAIT_XRAY_HEARING,
),
/obj/item/bodypart = list(
"TRAIT_PARALYSIS" = TRAIT_PARALYSIS,
+1 -1
View File
@@ -241,7 +241,7 @@
Hear(rendered, src, language, message, null, spans, message_mods) // We always hear what we say
var/group = owner.imaginary_group - src // The people in our group don't, so we have to exclude ourselves not to hear twice
for(var/mob/person in group)
if(eavesdrop_range && get_dist(src, person) > 1 + eavesdrop_range)
if(eavesdrop_range && get_dist(src, person) > WHISPER_RANGE + eavesdrop_range && !HAS_TRAIT(person, TRAIT_GOOD_HEARING))
var/new_rendered = "[span_name("[name]")] [say_quote(say_emphasis(eavesdropped_message), spans, message_mods)]"
person.Hear(new_rendered, src, language, eavesdropped_message, null, spans, message_mods)
else
@@ -304,7 +304,7 @@
/datum/job/mime = /obj/item/organ/internal/tongue/robot, //...
/datum/job/paramedic = /obj/item/organ/internal/cyberimp/eyes/hud/medical,
/datum/job/prisoner = /obj/item/organ/internal/eyes/robotic/shield,
/datum/job/psychologist = /obj/item/organ/internal/ears/cybernetic/upgraded,
/datum/job/psychologist = /obj/item/organ/internal/ears/cybernetic/whisper,
/datum/job/quartermaster = /obj/item/organ/internal/stomach/cybernetic/tier3,
/datum/job/research_director = /obj/item/organ/internal/cyberimp/bci,
/datum/job/roboticist = /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic,
@@ -317,7 +317,7 @@
// SKYRAT EDIT ADDITION START - MODULAR JOBS
/datum/job/blueshield = /obj/item/organ/internal/cyberimp/brain/anti_stun,
/datum/job/nanotrasen_consultant = /obj/item/organ/internal/heart/cybernetic/tier3,
/datum/job/barber = /obj/item/organ/internal/ears/cybernetic/upgraded,
/datum/job/barber = /obj/item/organ/internal/ears/cybernetic/whisper,
/datum/job/corrections_officer = /obj/item/organ/internal/cyberimp/arm/flash,
/datum/job/orderly = /obj/item/organ/internal/cyberimp/brain/anti_drop,
/datum/job/science_guard = /obj/item/organ/internal/cyberimp/arm/flash,
+2
View File
@@ -36,6 +36,8 @@
/obj/item/organ/internal/ears = TRUE,
/obj/item/organ/internal/ears/cybernetic = FALSE,
/obj/item/organ/internal/ears/cybernetic/upgraded = TRUE,
/obj/item/organ/internal/ears/cybernetic/whisper = TRUE,
/obj/item/organ/internal/ears/cybernetic/xray = TRUE,
)
/datum/bounty/item/medical/liver
+16 -5
View File
@@ -279,10 +279,13 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
understood = FALSE
// if someone is whispering we make an extra type of message that is obfuscated for people out of range
var/is_speaker_whispering = message_mods[WHISPER_MODE]
var/can_hear_whisper = get_dist(speaker, src) <= message_range
if(is_speaker_whispering && !can_hear_whisper && !isobserver(src)) // ghosts can hear all messages clearly
// Less than or equal to 0 means normal hearing. More than 0 and less than or equal to EAVESDROP_EXTRA_RANGE means
// partial hearing. More than EAVESDROP_EXTRA_RANGE means no hearing. Exception for GOOD_HEARING trait
var/dist = get_dist(speaker, src) - message_range
if(dist > 0 && dist <= EAVESDROP_EXTRA_RANGE && !HAS_TRAIT(src, TRAIT_GOOD_HEARING) && !isobserver(src)) // ghosts can hear all messages clearly
raw_message = stars(raw_message)
if (dist > EAVESDROP_EXTRA_RANGE && !HAS_TRAIT(src, TRAIT_GOOD_HEARING) && !isobserver(src))
return FALSE // Too far away and don't have good hearing, you can't hear anything
// we need to send this signal before compose_message() is used since other signals need to modify
// the raw_message first. After the raw_message is passed through the various signals, it's ready to be formatted
@@ -337,10 +340,18 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
var/whisper_range = 0
var/is_speaker_whispering = FALSE
if(message_mods[WHISPER_MODE]) //If we're whispering
whisper_range = EAVESDROP_EXTRA_RANGE
// Needed for good hearing trait. The actual filtering for whispers happens at the /mob/living/Hear proc
whisper_range = MESSAGE_RANGE - WHISPER_RANGE
is_speaker_whispering = TRUE
var/list/listening = get_hearers_in_view(message_range + whisper_range, source)
var/list/in_view = get_hearers_in_view(message_range + whisper_range, source)
var/list/listening = get_hearers_in_range(message_range + whisper_range, source)
// Pre-process listeners to account for line-of-sight
for(var/atom/movable/listening_movable as anything in listening)
if(!(listening_movable in in_view) && !HAS_TRAIT(listening_movable, TRAIT_XRAY_HEARING))
listening.Remove(listening_movable)
if(client) //client is so that ghosts don't have to listen to mice
for(var/mob/player_mob as anything in GLOB.player_list)
if(QDELETED(player_mob)) //Some times nulls and deleteds stay in this list. This is a workaround to prevent ic chat breaking for everyone when they do.
@@ -348,32 +348,6 @@
//////////Cybernetic Implants////////////
/////////////////////////////////////////
/datum/design/cyberimp_welding
name = "Welding Shield Eyes"
desc = "These reactive micro-shields will protect you from welders and flashes without obscuring your vision."
id = "ci-welding"
build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
construction_time = 40
materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT*6, /datum/material/glass = SMALL_MATERIAL_AMOUNT*4)
build_path = /obj/item/organ/internal/eyes/robotic/shield
category = list(
RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_MISC
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/design/cyberimp_gloweyes
name = "Luminescent Eyes"
desc = "A pair of cybernetic eyes that can emit multicolored light"
id = "ci-gloweyes"
build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
construction_time = 40
materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT*6, /datum/material/glass =HALF_SHEET_MATERIAL_AMOUNT)
build_path = /obj/item/organ/internal/eyes/robotic/glow
category = list(
RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_MISC
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/design/cyberimp_breather
name = "Breathing Tube Implant"
desc = "This simple implant adds an internals connector to your back, allowing you to use internals without a mask and protecting you from being choked."
@@ -845,13 +819,51 @@
id = "cybernetic_ears_u"
build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
construction_time = 40
materials = list(/datum/material/iron =SMALL_MATERIAL_AMOUNT*5, /datum/material/glass =SMALL_MATERIAL_AMOUNT*5, /datum/material/silver =SMALL_MATERIAL_AMOUNT*5)
materials = list(
/datum/material/iron = SMALL_MATERIAL_AMOUNT*5,
/datum/material/glass = SMALL_MATERIAL_AMOUNT*5,
/datum/material/silver = SMALL_MATERIAL_AMOUNT*5,
)
build_path = /obj/item/organ/internal/ears/cybernetic/upgraded
category = list(
RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_2
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/design/cybernetic_ears_whisper
name = "Whisper-sensitive Cybernetic Ears"
desc = "A pair of whisper-sensitive cybernetic ears."
id = "cybernetic_ears_whisper"
build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
construction_time = 40
materials = list(
/datum/material/iron = SMALL_MATERIAL_AMOUNT*5,
/datum/material/glass = SMALL_MATERIAL_AMOUNT*5,
/datum/material/silver = SMALL_MATERIAL_AMOUNT*5,
)
build_path = /obj/item/organ/internal/ears/cybernetic/whisper
category = list(
RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_3
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/design/cybernetic_ears_xray
name = "Wall-penetrating Cybernetic Ears"
desc = "A pair of wall-penetrating cybernetic ears."
id = "cybernetic_ears_xray"
build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
construction_time = 40
materials = list(
/datum/material/iron = SMALL_MATERIAL_AMOUNT*5,
/datum/material/glass = SMALL_MATERIAL_AMOUNT*5,
/datum/material/silver = SMALL_MATERIAL_AMOUNT*5,
)
build_path = /obj/item/organ/internal/ears/cybernetic/xray
category = list(
RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_3
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/design/cybernetic_eyes
name = "Basic Cybernetic Eyes"
desc = "A basic pair of cybernetic eyes."
@@ -875,6 +887,32 @@
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/design/cyberimp_welding
name = "Welding Shield Eyes"
desc = "These reactive micro-shields will protect you from welders and flashes without obscuring your vision."
id = "ci-welding"
build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
construction_time = 40
materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT*6, /datum/material/glass = SMALL_MATERIAL_AMOUNT*4)
build_path = /obj/item/organ/internal/eyes/robotic/shield
category = list(
RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_3
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/datum/design/cyberimp_gloweyes
name = "Luminescent Eyes"
desc = "A pair of cybernetic eyes that can emit multicolored light"
id = "ci-gloweyes"
build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
construction_time = 40
materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT*6, /datum/material/glass =HALF_SHEET_MATERIAL_AMOUNT)
build_path = /obj/item/organ/internal/eyes/robotic/glow
category = list(
RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_ORGANS_3
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
/////////////////////
///Surgery Designs///
/////////////////////
+6 -4
View File
@@ -277,6 +277,7 @@
"bonesetter",
"cautery",
"circular_saw",
"cybernetic_ears",
"cybernetic_eyes",
"cybernetic_heart",
"cybernetic_liver",
@@ -1381,7 +1382,7 @@
description = "We have the technology to rebuild him."
prereq_ids = list("biotech")
design_ids = list(
"cybernetic_ears",
"cybernetic_ears_u",
"cybernetic_eyes_improved",
"cybernetic_heart_tier2",
"cybernetic_liver_tier2",
@@ -1402,7 +1403,10 @@
description = "We have the technology to upgrade him."
prereq_ids = list("adv_biotech", "cyber_organs")
design_ids = list(
"cybernetic_ears_u",
"cybernetic_ears_whisper",
"cybernetic_ears_xray",
"ci-gloweyes",
"ci-welding",
"cybernetic_heart_tier3",
"cybernetic_liver_tier3",
"cybernetic_lungs_tier3",
@@ -1423,11 +1427,9 @@
design_ids = list(
"ci-breather",
"ci-diaghud",
"ci-gloweyes",
"ci-medhud",
"ci-nutriment",
"ci-sechud",
"ci-welding",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
@@ -104,18 +104,51 @@
ear_owner.RemoveElement(/datum/element/waddling)
/obj/item/organ/internal/ears/cybernetic
name = "cybernetic ears"
name = "basic cybernetic ears"
icon_state = "ears-c"
desc = "A basic cybernetic organ designed to mimic the operation of ears."
damage_multiplier = 0.9
organ_flags = ORGAN_ROBOTIC
/obj/item/organ/internal/ears/cybernetic/upgraded
name = "upgraded cybernetic ears"
name = "cybernetic ears"
icon_state = "ears-c-u"
desc = "An advanced cybernetic ear, surpassing the performance of organic ears."
desc = "An advanced cybernetic ear, surpassing the performance of organic ears."
damage_multiplier = 0.5
/obj/item/organ/internal/ears/cybernetic/whisper
name = "whisper-sensitive cybernetic ears"
icon_state = "ears-c-u"
desc = "Allows the user to more easily hear whispers. The user becomes extra vulnerable to loud noises, however"
// Same sensitivity as felinid ears
damage_multiplier = 2
// The original idea was to use signals to do this not traits. Unfortunately, the star effect used for whispers applies before any relevant signals
// This seems like the least invasive solution
/obj/item/organ/internal/ears/cybernetic/whisper/on_insert(mob/living/carbon/ear_owner)
. = ..()
ADD_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT)
/obj/item/organ/internal/ears/cybernetic/whisper/on_remove(mob/living/carbon/ear_owner)
. = ..()
REMOVE_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT)
// "X-ray ears" that let you hear through walls
/obj/item/organ/internal/ears/cybernetic/xray
name = "wall-penetrating cybernetic ears"
icon_state = "ears-c-u"
desc = "Throguh the power of modern engineering, allows the user to hear speech through walls. The user becomes extra vulnerable to loud noises, however"
// Same sensitivity as felinid ears
damage_multiplier = 2
/obj/item/organ/internal/ears/cybernetic/xray/on_insert(mob/living/carbon/ear_owner)
. = ..()
ADD_TRAIT(ear_owner, TRAIT_XRAY_HEARING, ORGAN_TRAIT)
/obj/item/organ/internal/ears/cybernetic/xray/on_remove(mob/living/carbon/ear_owner)
. = ..()
REMOVE_TRAIT(ear_owner, TRAIT_XRAY_HEARING, ORGAN_TRAIT)
/obj/item/organ/internal/ears/cybernetic/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
+2 -6
View File
@@ -1,5 +1,3 @@
#define LOOC_RANGE 7
/client/verb/looc(msg as text)
set name = "LOOC"
set desc = "Local OOC, seen only by those in view."
@@ -54,7 +52,7 @@
mob.log_talk(msg,LOG_OOC, tag="LOOC")
var/list/heard
if(wall_pierce)
heard = get_hearers_in_range(LOOC_RANGE, mob.get_top_level_mob())
heard = get_hearers_in_looc_range(mob.get_top_level_mob())
else
heard = get_hearers_in_view(LOOC_RANGE, mob.get_top_level_mob())
@@ -62,7 +60,7 @@
if(istype(mob, /mob/living/silicon/ai))
var/mob/living/silicon/ai/ai = mob
if(wall_pierce)
heard = get_hearers_in_range(LOOC_RANGE, ai.eyeobj)
heard = get_hearers_in_looc_range(ai.eyeobj)
else
heard = get_hearers_in_view(LOOC_RANGE, ai.eyeobj)
//so the ai can see looc text
@@ -90,5 +88,3 @@
to_chat(cli_client, span_looc("[ADMIN_FLW(usr)] <span class='prefix'>LOOC[wall_pierce ? " (WALL PIERCE)" : ""]:</span> <EM>[src.key]/[src.mob.name]:</EM> <span class='message'>[msg]</span>"))
else if (cli_client.prefs.read_preference(/datum/preference/toggle/admin/see_looc))
to_chat(cli_client, span_rlooc("[ADMIN_FLW(usr)] <span class='prefix'>(R)LOOC[wall_pierce ? " (WALL PIERCE)" : ""]:</span> <EM>[src.key]/[src.mob.name]:</EM> <span class='message'>[msg]</span>"))
#undef LOOC_RANGE