diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index b4253951536..77bd066f547 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -37,6 +37,7 @@ GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list( list(/datum/quirk/light_drinker, /datum/quirk/drunkhealing), list(/datum/quirk/oversized, /datum/quirk/freerunning), list(/datum/quirk/oversized, /datum/quirk/item_quirk/settler), + list(/datum/quirk/echolocation, /datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/nearsighted, /datum/quirk/item_quirk/deafness), //SKYRAT EDIT ADDITION END )) diff --git a/code/datums/components/echolocation.dm b/code/datums/components/echolocation.dm index 020c47ad875..f5181a98147 100644 --- a/code/datums/components/echolocation.dm +++ b/code/datums/components/echolocation.dm @@ -32,7 +32,7 @@ /// Cooldown for the echolocation. COOLDOWN_DECLARE(cooldown_last) -/datum/component/echolocation/Initialize(echo_range, cooldown_time, image_expiry_time, fade_in_time, fade_out_time, images_are_static, blocking_trait, echo_group, echo_icon = "echo", color_path) +/datum/component/echolocation/Initialize(echo_range, cooldown_time, image_expiry_time, fade_in_time, fade_out_time, images_are_static, blocking_trait, echo_group, echo_icon, color_path, use_echo = TRUE, show_own_outline = FALSE, personal_color = "#ffffff") // SKYRAT EDIT CHANGE - ORIGINAL: /datum/component/echolocation/Initialize(echo_range, cooldown_time, image_expiry_time, fade_in_time, fade_out_time, images_are_static, blocking_trait, echo_group, echo_icon = "echo", color_path) . = ..() var/mob/living/echolocator = parent if(!istype(echolocator)) @@ -55,12 +55,19 @@ src.images_are_static = images_are_static if(!isnull(blocking_trait)) src.blocking_trait = blocking_trait + // SKYRAT ADDITION START: echolocation + src.show_own_outline = show_own_outline + src.echo_color = personal_color + // SKYRAT EDIT ADDITION END if(ispath(color_path)) client_color = echolocator.add_client_colour(color_path) src.echo_group = echo_group || REF(src) echolocator.add_traits(list(TRAIT_ECHOLOCATION_RECEIVER, TRAIT_TRUE_NIGHT_VISION), echo_group) //so they see all the tiles they echolocated, even if they are in the dark echolocator.become_blind(ECHOLOCATION_TRAIT) - echolocator.overlay_fullscreen("echo", /atom/movable/screen/fullscreen/echo, echo_icon) + // SKYRAT EDIT ADDITION START + if (use_echo) // add constructor toggle to not use the eye overlay + echolocator.overlay_fullscreen("echo", /atom/movable/screen/fullscreen/echo, echo_icon) + // SKYRAT EDIT ADDITION END START_PROCESSING(SSfastprocess, src) /datum/component/echolocation/Destroy(force) @@ -85,7 +92,7 @@ echolocate() /datum/component/echolocation/proc/echolocate() - if(!COOLDOWN_FINISHED(src, cooldown_last)) + if(stall || !COOLDOWN_FINISHED(src, cooldown_last)) // SKYRAT EDIT CHANGE - ORIGINAL: if(!COOLDOWN_FINISHED(src, cooldown_last)) return COOLDOWN_START(src, cooldown_last, cooldown_time) var/mob/living/echolocator = parent @@ -121,11 +128,18 @@ if(images_are_static) final_image.pixel_x = input.pixel_x final_image.pixel_y = input.pixel_y - if(HAS_TRAIT_FROM(input, TRAIT_ECHOLOCATION_RECEIVER, echo_group)) //mark other echolocation with full white - final_image.color = white_matrix + // SKYRAT ADDITION START: echolocation (show outlines on self) + if(HAS_TRAIT_FROM(input, TRAIT_ECHOLOCATION_RECEIVER, echo_group)) //mark other echolocation with full white, except ourselves + var/datum/component/echolocation/located_component = input.GetComponent(/datum/component/echolocation) + var/mob/living/echolocator = parent + if(located_component) + final_image.color = located_component.echo_color + else if(input != echolocator) + final_image.color = white_matrix + // SKYRAT EDIT ADDITION END var/list/fade_ins = list(final_image) for(var/mob/living/echolocate_receiver as anything in receivers) - if(echolocate_receiver == input) + if(echolocate_receiver == input && !show_own_outline) // SKYRAT EDIT CHANGE - ORIGINAL: if(echolocate_receiver == input) continue if(receivers[echolocate_receiver][input]) var/previous_image = receivers[echolocate_receiver][input]["image"] diff --git a/code/modules/client/preferences/clothing.dm b/code/modules/client/preferences/clothing.dm index b54149db299..e57d87bf2c8 100644 --- a/code/modules/client/preferences/clothing.dm +++ b/code/modules/client/preferences/clothing.dm @@ -155,7 +155,7 @@ return /datum/sprite_accessory/undershirt/sports_bra::name return ..() -*/ // NOVA EDIT REMOVAL END +*/ // SKYRAT EDIT REMOVAL END /datum/preference/choiced/undershirt/icon_for(value) var/static/icon/body diff --git a/modular_skyrat/modules/quirks/echolocation/echolocation.dm b/modular_skyrat/modules/quirks/echolocation/echolocation.dm new file mode 100644 index 00000000000..2fa3f5fc30a --- /dev/null +++ b/modular_skyrat/modules/quirks/echolocation/echolocation.dm @@ -0,0 +1,106 @@ +/datum/quirk/echolocation + name = "Echolocation" + desc = "Though your eyes no longer function, you accommodate for it by some means of extrasensory echolocation and sensitive hearing. Beware: if you're ever deafened, you'll also lose your echolocation until you recover!" + gain_text = span_notice("The slightest sounds map your surroundings.") + lose_text = span_notice("The world resolves into colour and clarity.") + value = -14 + icon = FA_ICON_EAR_LISTEN + mob_trait = TRAIT_GOOD_HEARING + medical_record_text = "Patient's eyes are biologically nonfunctional. Hearing tests indicate almost supernatural acuity." + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE + mail_goodies = list(/obj/item/clothing/glasses/sunglasses, /obj/item/cane/white) + /// where we store easy access to the character's echolocation component (for stuff like drugs) + var/datum/component/echolocation/esp + /// where we store access to the client colour we make + var/datum/client_colour/echolocation_custom/esp_color + /// The action we add with this quirk in add(), used for easy deletion later + var/datum/action/cooldown/spell/added_action + +/datum/quirk/echolocation/add(client/client_source) + // echolocation component handles blinding us already so we don't need to worry about that + var/mob/living/carbon/human/human_holder = quirk_holder + // set up the desired echo group from our quirk preferences + var/client_echo_group = LOWER_TEXT(client_source?.prefs.read_preference(/datum/preference/choiced/echolocation_key)) + if (isnull(client_echo_group)) + client_echo_group = "echolocation" + if (client_echo_group == "psychic") + client_echo_group = "psyker" // set this non-player-facing so they share echolocation with coded chaplain psykers/pirates and the like + + // Get the prefs + var/client_show_outline = client_source?.prefs.read_preference(/datum/preference/toggle/echolocation_overlay) + var/col = color_hex2color_matrix(client_source?.prefs.read_preference(/datum/preference/color/echolocation_outline)) + + human_holder.AddComponent(\ + /datum/component/echolocation, \ + blocking_trait = TRAIT_DEAF, \ + cooldown_time = 2 SECONDS, \ + echo_range = 7, \ + echo_group = client_echo_group, \ + images_are_static = FALSE, \ + use_echo = FALSE, \ + show_own_outline = client_show_outline, \ + personal_color = col \ + ) + esp = human_holder.GetComponent(/datum/component/echolocation) + + human_holder.remove_client_colour(/datum/client_colour/monochrome/blind) + esp_color = human_holder.add_client_colour(/datum/client_colour/echolocation_custom) + esp_color.update_colour(col) + + // add an action/spell to allow the player to toggle echolocation off for a bit (eyestrain on longer rounds, or just roleplay) + var/datum/action/cooldown/spell/echolocation_toggle/toggle_action = new /datum/action/cooldown/spell/echolocation_toggle() + toggle_action.Grant(human_holder) + added_action = toggle_action + RegisterSignal(human_holder, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine_text)) + +/datum/quirk/echolocation/remove() + QDEL_NULL(esp) // echolocation component removal handles graceful disposal of everything above + QDEL_NULL(added_action) // remove the stall action, too + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.remove_client_colour(/datum/client_colour/echolocation_custom) // clean up the custom colour override we added + UnregisterSignal(human_holder, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine_text)) + +/datum/quirk/echolocation/proc/on_examine_text(client/client_source, mob/user, list/examine_list) + SIGNAL_HANDLER + var/mob/living/carbon/human/human_holder = quirk_holder + var/datum/quirk/echolocation/echo = human_holder.get_quirk(/datum/quirk/echolocation) + var/datum/component/echolocation/quirk_esp = echo.esp + + if(quirk_esp.stall == TRUE) + return + examine_list += span_cyan("[human_holder.p_They()] [human_holder.p_have()] [human_holder.p_their()] ears perked up, listening closely to even slightest noise.") + +/datum/client_colour/echolocation_custom + colour = COLOR_MATRIX_SEPIATONE + priority = 1 + override = TRUE + +/datum/action/cooldown/spell/echolocation_toggle + name = "Toggle echolocation" + desc = "Decide whether you want to stop echolocating (or start again). Useful if you need a break - it's not an easy process!" + spell_requirements = NONE + cooldown_time = 2 SECONDS + check_flags = AB_CHECK_CONSCIOUS + button_icon_state = "blink" + +/datum/action/cooldown/spell/echolocation_toggle/is_valid_target(atom/cast_on) + return ishuman(cast_on) + +/datum/action/cooldown/spell/echolocation_toggle/cast(mob/living/carbon/human/cast_on) + . = ..() + var/datum/quirk/echolocation/echo = cast_on.get_quirk(/datum/quirk/echolocation) + if (isnull(echo)) + return + + var/datum/component/echolocation/quirk_esp = echo.esp + if (isnull(quirk_esp)) + return + + if (quirk_esp.stall) + quirk_esp.stall = FALSE + cast_on.balloon_alert(cast_on, "started echolocating!") + cast_on.visible_message(span_notice("[cast_on] perks up, suddenly seeming more vigilant!")) + else + quirk_esp.stall = TRUE + cast_on.balloon_alert(cast_on, "stopped echolocating!") + cast_on.visible_message(span_notice("[cast_on] relaxes slightly, seeming less vigilant for the moment.")) diff --git a/modular_skyrat/modules/quirks/echolocation/echolocation_component.dm b/modular_skyrat/modules/quirks/echolocation/echolocation_component.dm new file mode 100644 index 00000000000..9edecdd9014 --- /dev/null +++ b/modular_skyrat/modules/quirks/echolocation/echolocation_component.dm @@ -0,0 +1,7 @@ +/datum/component/echolocation + /// Should the mob see itself outlined? + var/show_own_outline = FALSE + /// Are we temporarily halting visual processing on this component? + var/stall = FALSE + /// The color of the echolocation user when seen by other echolocators + var/echo_color = "#ffffff" diff --git a/modular_skyrat/modules/quirks/echolocation/echolocation_pref.dm b/modular_skyrat/modules/quirks/echolocation/echolocation_pref.dm new file mode 100644 index 00000000000..1806e3a305a --- /dev/null +++ b/modular_skyrat/modules/quirks/echolocation/echolocation_pref.dm @@ -0,0 +1,52 @@ +/datum/quirk_constant_data/echolocation + associated_typepath = /datum/quirk/echolocation + customization_options = list(/datum/preference/color/echolocation_outline, /datum/preference/choiced/echolocation_key, /datum/preference/toggle/echolocation_overlay) + +// Client preference for echolocation outline colour +/datum/preference/color/echolocation_outline + savefile_key = "echolocation_outline" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + +/datum/preference/color/echolocation_outline/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return "Echolocation" in preferences.all_quirks + +/datum/preference/color/echolocation_outline/apply_to_human(mob/living/carbon/human/target, value) + return + +// Client preference for echolocation key type +/datum/preference/choiced/echolocation_key + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "echolocation_key" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/choiced/echolocation_key/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return "Echolocation" in preferences.all_quirks + +/datum/preference/choiced/echolocation_key/init_possible_values() + var/list/values = list("Extrasensory", "Psychic", "Auditory/Vibrational") + return values + +/datum/preference/choiced/echolocation_key/apply_to_human(mob/living/carbon/human/target, value) + return + +// Client preference for whether we display the echolocation overlay or not +/datum/preference/toggle/echolocation_overlay + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "echolocation_use_echo" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/toggle/echolocation_overlay/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return "Echolocation" in preferences.all_quirks + +/datum/preference/toggle/echolocation_overlay/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/modular_skyrat/master_files/code/datums/traits/good.dm b/modular_skyrat/modules/quirks/good.dm similarity index 100% rename from modular_skyrat/master_files/code/datums/traits/good.dm rename to modular_skyrat/modules/quirks/good.dm diff --git a/modular_skyrat/master_files/code/datums/traits/negative.dm b/modular_skyrat/modules/quirks/negative.dm similarity index 100% rename from modular_skyrat/master_files/code/datums/traits/negative.dm rename to modular_skyrat/modules/quirks/negative.dm diff --git a/modular_skyrat/master_files/code/datums/traits/neutral.dm b/modular_skyrat/modules/quirks/neutral.dm similarity index 100% rename from modular_skyrat/master_files/code/datums/traits/neutral.dm rename to modular_skyrat/modules/quirks/neutral.dm diff --git a/tgstation.dme b/tgstation.dme index 8fceb28ac59..c4d61fc2f0f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6510,9 +6510,6 @@ #include "modular_skyrat\master_files\code\datums\status_effects\debuffs\debuffs.dm" #include "modular_skyrat\master_files\code\datums\storage\storage.dm" #include "modular_skyrat\master_files\code\datums\storage\subtypes\pockets.dm" -#include "modular_skyrat\master_files\code\datums\traits\good.dm" -#include "modular_skyrat\master_files\code\datums\traits\negative.dm" -#include "modular_skyrat\master_files\code\datums\traits\neutral.dm" #include "modular_skyrat\master_files\code\datums\votes\_vote_datum.dm" #include "modular_skyrat\master_files\code\datums\votes\map_vote.dm" #include "modular_skyrat\master_files\code\game\atoms.dm" @@ -8278,6 +8275,12 @@ #include "modular_skyrat\modules\QOL\code\_under.dm" #include "modular_skyrat\modules\QOL\code\datums\components\crafting\recipes\recipes_misc.dm" #include "modular_skyrat\modules\QOL\code\game\objects\items\mop.dm" +#include "modular_skyrat\modules\quirks\good.dm" +#include "modular_skyrat\modules\quirks\negative.dm" +#include "modular_skyrat\modules\quirks\neutral.dm" +#include "modular_skyrat\modules\quirks\echolocation\echolocation.dm" +#include "modular_skyrat\modules\quirks\echolocation\echolocation_component.dm" +#include "modular_skyrat\modules\quirks\echolocation\echolocation_pref.dm" #include "modular_skyrat\modules\radiosound\code\headset.dm" #include "modular_skyrat\modules\reagent_forging\code\anvil.dm" #include "modular_skyrat\modules\reagent_forging\code\crafting_bench.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/echolocation.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/echolocation.tsx new file mode 100644 index 00000000000..f232cb16e5b --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/echolocation.tsx @@ -0,0 +1,24 @@ +// THIS IS A Skyrat SECTOR UI FILE +import { + CheckboxInput, + Feature, + FeatureChoiced, + FeatureColorInput, + FeatureToggle, +} from '../../base'; +import { FeatureDropdownInput } from '../../dropdowns'; + +export const echolocation_outline: Feature = { + name: 'Echo outline color', + component: FeatureColorInput, +}; + +export const echolocation_key: FeatureChoiced = { + name: 'Echolocation group', + component: FeatureDropdownInput, +}; + +export const echolocation_use_echo: FeatureToggle = { + name: 'Display own overlay', + component: CheckboxInput, +};