Skip to content

[PORT] Replaces Upgraded Cybernetic Ears with two new variants #6356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 19, 2025
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/signals_object.dm
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@
#define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency"
///called from base of /obj/item/radio/proc/talk_into(): (atom/movable/M, message, channel)
#define COMSIG_RADIO_NEW_MESSAGE "radio_new_message"
///called from base of /obj/item/radio/proc/on_receive_messgae(): (list/data)
#define COMSIG_RADIO_RECEIVE_MESSAGE "radio_receive_message"

// /obj/item/pen signals

Expand Down
6 changes: 5 additions & 1 deletion code/__DEFINES/say.dm
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,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
Expand Down
4 changes: 2 additions & 2 deletions code/__DEFINES/traits/declarations.dm
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// 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" */
#define TRAIT_GOOD_HEARING "good_hearing"
/// Allows you to hear speech through walls
/* #define TRAIT_XRAY_HEARING "xray_hearing" */
#define TRAIT_XRAY_HEARING "xray_hearing"

/// This mob can not enter or move on a shuttle
/* #define TRAIT_BLOCK_SHUTTLE_MOVEMENT "block_shuttle_movement" */
Expand Down
34 changes: 34 additions & 0 deletions code/__HELPERS/spatial_info.dm
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,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
Expand Down
4 changes: 2 additions & 2 deletions code/_globalvars/traits/_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_GIANT" = TRAIT_GIANT,
"TRAIT_GODMODE" = TRAIT_GODMODE,
"TRAIT_GONE_FISHING" = TRAIT_GONE_FISHING,
"TRAIT_GOOD_HEARING" = TRAIT_GOOD_HEARING,
"TRAIT_GOURMAND" = TRAIT_GOURMAND,
"TRAIT_GRABWEAKNESS" = TRAIT_GRABWEAKNESS,
"TRAIT_GUNFLIP" = TRAIT_GUNFLIP,
Expand Down Expand Up @@ -528,6 +529,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_WING_BUFFET_TIRED" = TRAIT_WING_BUFFET_TIRED,
"TRAIT_XENO_HOST" = TRAIT_XENO_HOST,
"TRAIT_XENO_IMMUNE" = TRAIT_XENO_IMMUNE,
"TRAIT_XRAY_HEARING" = TRAIT_XRAY_HEARING,
"TRAIT_XRAY_VISION" = TRAIT_XRAY_VISION,
"TRAIT_COLD_BLOODED" = TRAIT_COLD_BLOODED,
"TRAIT_ZOMBIE_CONSUMED" = TRAIT_ZOMBIE_CONSUMED,
Expand Down Expand Up @@ -558,7 +560,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
/* "TRAIT_FAST_TYING" = TRAIT_FAST_TYING, */
/* "TRAIT_FIST_MINING" = TRAIT_FIST_MINING, */
/* "TRAIT_FOV_APPLIED" = TRAIT_FOV_APPLIED, */
/* "TRAIT_GOOD_HEARING" = TRAIT_GOOD_HEARING, */
/* "TRAIT_GREENTEXT_CURSED" = TRAIT_GREENTEXT_CURSED, */
/* "TRAIT_HAS_CRANIAL_FISSURE" = TRAIT_HAS_CRANIAL_FISSURE, */
/* "TRAIT_HEAD_INJURY_BLOCKED" = TRAIT_HEAD_INJURY_BLOCKED, */
Expand Down Expand Up @@ -620,7 +621,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
/* "TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE, */
/* "TRAIT_USER_SCOPED" = TRAIT_USER_SCOPED, */
/* "TRAIT_WOUND_LICKER" = TRAIT_WOUND_LICKER, */
/* "TRAIT_XRAY_HEARING" = TRAIT_XRAY_HEARING, */
// MONKESTATION ADDITION START
"TRAIT_STABLE_DWARF" = TRAIT_STABLE_DWARF,
"TRAIT_RADHEALING" = TRAIT_RADHEALING,
Expand Down
2 changes: 1 addition & 1 deletion code/datums/brain_damage/imaginary_friend.dm
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,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
Expand Down
2 changes: 1 addition & 1 deletion code/datums/station_traits/positive_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@
/datum/job/nanotrasen_representative = /obj/item/organ/internal/cyberimp/leg/shove_resist, /obj/item/organ/internal/cyberimp/leg/shove_resist/l, // monkestation edit: NT kneels to noone.
/datum/job/paramedic = /obj/item/organ/internal/cyberimp/arm/item_set/paramedic, // monkestation edit: cybernetics overhaul (on-site healing / assistance)
/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/arm/item_set/connector, // monkestation edit: cybernetics overhaul (useful job stuff)
Expand Down
2 changes: 1 addition & 1 deletion code/game/machinery/hologram.dm
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(speaker == holocall_to_update.hologram && holocall_to_update.user.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat))
holocall_to_update.user.create_chat_message(speaker, message_language, raw_message, spans)
else
holocall_to_update.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods, message_range)
holocall_to_update.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods, message_range = INFINITY)

if(outgoing_call?.hologram && speaker == outgoing_call.user)
outgoing_call.hologram.say(raw_message, sanitize = FALSE)
Expand Down
2 changes: 1 addition & 1 deletion code/game/machinery/telecomms/broadcasting.dm
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@

for(var/obj/item/radio/called_radio as anything in radios)
if(!QDELETED(called_radio))
called_radio.on_recieve_message()
called_radio.on_recieve_message(data)

// From the list of radios, find all mobs who can hear those.
var/list/receive = get_hearers_in_radio_ranges(radios)
Expand Down
3 changes: 2 additions & 1 deletion code/game/objects/items/devices/radio/radio.dm
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,8 @@
return TRUE
return FALSE

/obj/item/radio/proc/on_recieve_message()
/obj/item/radio/proc/on_recieve_message(list/data)
SEND_SIGNAL(src, COMSIG_RADIO_RECEIVE_MESSAGE, data)
flick_overlay_view(overlay_speaker_active, 5 SECONDS)

/obj/item/radio/ui_state(mob/user)
Expand Down
2 changes: 2 additions & 0 deletions code/modules/cargo/bounties/medical.dm
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
/obj/item/organ/internal/ears/synth = FALSE,// monkestation edit: prevent easy bounties
/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
Expand Down
20 changes: 15 additions & 5 deletions code/modules/mob/living/living_say.dm
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,13 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
raw_message = translate_language(src, message_language, raw_message) // translate

// 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 (message_range != INFINITY && 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
Expand Down Expand Up @@ -360,10 +363,17 @@ 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)
Expand Down
34 changes: 34 additions & 0 deletions code/modules/research/designs/medical_designs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,40 @@
)
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."
Expand Down
1 change: 1 addition & 0 deletions code/modules/research/techweb/all_nodes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@
"bonesetter",
"cautery",
"circular_saw",
"cybernetic_ears",
"cybernetic_eyes",
"cybernetic_heart",
"cybernetic_liver",
Expand Down
10 changes: 6 additions & 4 deletions code/modules/research/techweb/cyborg_nodes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,16 @@
description = "Electronic implants that improve humans."
prereq_ids = list("adv_biotech", "datatheory")
design_ids = list(
"cybernetic_ears_whisper",
"cybernetic_ears_xray",
"ci-breather",
"ci-diaghud",
"ci-gloweyes",
"ci-medhud",
"ci-meson", // monkestation addition
"ci-meson",
"ci-nutriment",
"ci-pathohud", // monkestation addition
"ci-scihud", // monkestastion addition
"ci-pathohud",
"ci-scihud",
"ci-sechud",
"ci-welding",
)
Expand Down Expand Up @@ -157,7 +159,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",
Expand Down
21 changes: 19 additions & 2 deletions code/modules/surgery/organs/ears.dm
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,35 @@
bang_protect = 1 //Fear me weaklings.

/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_SYNTHETIC

/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."
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
organ_traits = list(TRAIT_GOOD_HEARING)

// "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 = "Through 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
organ_traits = list(TRAIT_XRAY_HEARING)

/obj/item/organ/internal/ears/cybernetic/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
Expand Down
Loading
Loading