From 599761fe067645fbcce9b84c74c769df59c3ce06 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Sat, 27 Jan 2024 02:03:43 +0300 Subject: [PATCH] The Enlightening: Selectable Night Vision color tint and mechanical rebalancing (it's better now... usually) (#1709) * Night vision uses eye color to determine overlay hue + photophobia scaling * Use correct restoration proc for eye sensitivity * Allow direct selection of night vision color tinting, default to left eye color if not available * Modularization formatting improvements * Further modularization & readability improvements, and refresh eyes after photophobia flash_protect adjustment * Use correct var name * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review --------- Co-authored-by: Ephemeralis Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/__DEFINES/~nova_defines/quirks.dm | 7 ++ .../quirks/negative_quirks/photophobia.dm | 4 +- .../quirks/positive_quirks/night_vision.dm | 2 +- .../surgery/organs/internal/eyes/_eyes.dm | 9 ++- .../quirks/negative_quirks/photophobia.dm | 37 +++++++++++ .../quirks/positive_quirks/night_vision.dm | 64 +++++++++++++++++++ tgstation.dme | 2 + .../nova/night_vision.tsx | 7 ++ .../nova/photophobia.tsx | 7 ++ 9 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 modular_nova/master_files/code/datums/quirks/negative_quirks/photophobia.dm create mode 100644 modular_nova/master_files/code/datums/quirks/positive_quirks/night_vision.dm create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/night_vision.tsx create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/photophobia.tsx diff --git a/code/__DEFINES/~nova_defines/quirks.dm b/code/__DEFINES/~nova_defines/quirks.dm index 7acc8b3e9b1..5237be29176 100644 --- a/code/__DEFINES/~nova_defines/quirks.dm +++ b/code/__DEFINES/~nova_defines/quirks.dm @@ -25,3 +25,10 @@ #define DEATH_CONSEQUENCES_SHOW_HEALTH_ANALYZER_DATA "dc_show_health_analyzer_data" #define DEATH_CONSEQUENCES_TIME_BETWEEN_REMINDERS 5 MINUTES + +/// the minimum percentage of RGB darkness reduction that Nova's NV will always give. for base reference, the old NV quirk was equal to 4.5. note: some wide variance in min/max is needed to ensure hue has some chance to linear convert across +#define NOVA_NIGHT_VISION_POWER_MIN 4.5 +/// the maximum percentage. for reference, low-light adapted eyes (icecats and ashwalkers) have 30. +#define NOVA_NIGHT_VISION_POWER_MAX 9 +/// percentage of the NIGHT_VISION_POWER_MAX increase that is applied for eyes with low innate flash protection (photophobia quirk/moth eyes). At 0.75, this raises NV to 22.5 at hypersensitive flash_protect. +#define NOVA_NIGHT_VISION_SENSITIVITY_MULT 0.75 diff --git a/code/datums/quirks/negative_quirks/photophobia.dm b/code/datums/quirks/negative_quirks/photophobia.dm index b543aeda076..ea9ef428a50 100644 --- a/code/datums/quirks/negative_quirks/photophobia.dm +++ b/code/datums/quirks/negative_quirks/photophobia.dm @@ -40,13 +40,15 @@ /datum/quirk/photophobia/proc/update_eyes(obj/item/organ/internal/eyes/target_eyes) if(!istype(target_eyes)) return - target_eyes.flash_protect = max(target_eyes.flash_protect - 1, FLASH_PROTECTION_HYPER_SENSITIVE) + target_eyes.flash_protect = max(target_eyes.flash_protect - severity, FLASH_PROTECTION_HYPER_SENSITIVE) // NOVA EDIT CHANGE - ORIGINAL: target_eyes.flash_protect = max(target_eyes.flash_protect - 1, FLASH_PROTECTION_HYPER_SENSITIVE) + target_eyes.refresh() // NOVA EDIT ADDITION /datum/quirk/photophobia/proc/restore_eyes(obj/item/organ/internal/eyes/normal_eyes) SIGNAL_HANDLER if(!istype(normal_eyes)) return normal_eyes.flash_protect = initial(normal_eyes.flash_protect) + normal_eyes.refresh() // NOVA EDIT ADDITION /datum/quirk/photophobia/proc/on_holder_moved(mob/living/source, atom/old_loc, dir, forced) SIGNAL_HANDLER diff --git a/code/datums/quirks/positive_quirks/night_vision.dm b/code/datums/quirks/positive_quirks/night_vision.dm index 808a213db51..db94ab57555 100644 --- a/code/datums/quirks/positive_quirks/night_vision.dm +++ b/code/datums/quirks/positive_quirks/night_vision.dm @@ -22,7 +22,7 @@ /datum/quirk/night_vision/proc/refresh_quirk_holder_eyes() var/mob/living/carbon/human/human_quirk_holder = quirk_holder var/obj/item/organ/internal/eyes/eyes = human_quirk_holder.get_organ_by_type(/obj/item/organ/internal/eyes) - if(!eyes || eyes.lighting_cutoff) + if(!eyes) // NOVA EDIT CHANGE - ORIGINAL: if(!eyes || eyes.lighting_cutoff) return // We've either added or removed TRAIT_NIGHT_VISION before calling this proc. Just refresh the eyes. eyes.refresh() diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm index a447b508c71..a323f7c87d8 100644 --- a/code/modules/surgery/organs/internal/eyes/_eyes.dm +++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm @@ -86,8 +86,13 @@ affected_human.eye_color_right = eye_color_right else eye_color_right = affected_human.eye_color_right - if(HAS_TRAIT(affected_human, TRAIT_NIGHT_VISION) && !lighting_cutoff) - lighting_cutoff = LIGHTING_CUTOFF_REAL_LOW + if(HAS_TRAIT(affected_human, TRAIT_NIGHT_VISION)) // NOVA EDIT CHANGE - ORIGINAL: if(HAS_TRAIT(affected_human, TRAIT_NIGHT_VISION) && !lighting_cutoff) + //lighting_cutoff = LIGHTING_CUTOFF_REAL_LOW // NOVA EDIT REMOVAL + // NOVA EDIT ADDITION START - NIGHT VISION ADJUSTMENT - adjusts color cutoffs based on chosen quirk color, or left eye colour if not available + var/datum/quirk/night_vision/nv_quirk = affected_human.get_quirk(/datum/quirk/night_vision) + nv_quirk.nv_color_cutoffs = nv_quirk.calculate_color_cutoffs(nv_quirk.nv_color) + color_cutoffs = nv_quirk.nv_color_cutoffs + // NOVA EDIT ADDITION END if(CONFIG_GET(flag/native_fov) && native_fov) affected_human.add_fov_trait(type, native_fov) diff --git a/modular_nova/master_files/code/datums/quirks/negative_quirks/photophobia.dm b/modular_nova/master_files/code/datums/quirks/negative_quirks/photophobia.dm new file mode 100644 index 00000000000..a4224b926a7 --- /dev/null +++ b/modular_nova/master_files/code/datums/quirks/negative_quirks/photophobia.dm @@ -0,0 +1,37 @@ +/datum/quirk/photophobia + desc = "Bright lights are uncomfortable and upsetting to you for whatever reason. Your eyes are also more sensitive to light in general. This shares a unique interaction with Night Vision." + /// how much of a flash_protect deficit the quirk inflicts + var/severity = 1 + +/datum/quirk/photophobia/add_unique(client/client_source) + var/sensitivity = client_source?.prefs.read_preference(/datum/preference/choiced/photophobia_severity) + switch (sensitivity) + if ("Hypersensitive") + severity = 2 + if ("Sensitive") + severity = 1 + var/obj/item/organ/internal/eyes/holder_eyes = quirk_holder.get_organ_slot(ORGAN_SLOT_EYES) + restore_eyes(holder_eyes) // add_unique() happens after add() so we need to jank reset this to ensure sensitivity is properly applied at roundstart + check_eyes(holder_eyes) + +/datum/quirk_constant_data/photophobia + associated_typepath = /datum/quirk/photophobia + customization_options = list(/datum/preference/choiced/photophobia_severity) + +/datum/preference/choiced/photophobia_severity + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "photophobia_severity" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/choiced/photophobia_severity/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return "Photophobia" in preferences.all_quirks + +/datum/preference/choiced/photophobia_severity/init_possible_values() + var/list/values = list("Sensitive", "Hypersensitive") + return values + +/datum/preference/choiced/photophobia_severity/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/modular_nova/master_files/code/datums/quirks/positive_quirks/night_vision.dm b/modular_nova/master_files/code/datums/quirks/positive_quirks/night_vision.dm new file mode 100644 index 00000000000..2c3d0e06766 --- /dev/null +++ b/modular_nova/master_files/code/datums/quirks/positive_quirks/night_vision.dm @@ -0,0 +1,64 @@ +// This NV quirk variant applies color_offsets night vision to a mob based on its chosen eye color. +// Some eye colors will produce very slightly stronger mechanical night vision effects just by virtue of their RGB values being scaled higher (typically lighter colours). + +/datum/quirk/night_vision + desc = "You can see a little better in darkness than most ordinary humanoids. If your eyes are naturally more sensitive to light through other means (such as being photophobic or a mothperson), this effect is significantly stronger." + medical_record_text = "Patient's visual sensory organs demonstrate non-standard performance in low-light conditions." + var/nv_color = null /// Holds the player's selected night vision colour + var/list/nv_color_cutoffs = null /// Contains the color_cutoffs applied to the user's eyes w/ our custom hue (once built) + +/datum/quirk/night_vision/add_unique(client/client_source) + . = ..() + nv_color = client_source?.prefs.read_preference(/datum/preference/color/nv_color) + if (isnull(nv_color)) + var/mob/living/carbon/human/human_holder = quirk_holder + nv_color = process_chat_color(human_holder.eye_color_left) + nv_color_cutoffs = calculate_color_cutoffs(nv_color) + refresh_quirk_holder_eyes() // make double triple dog sure we apply the overlay + +/// Calculate eye organ color_cutoffs used in tinted night vision with a supplied hexcode colour, clamping and scaling appropriately. +/datum/quirk/night_vision/proc/calculate_color_cutoffs(color) + var/mob/living/carbon/human/target = quirk_holder + + // if we have more sensitive eyes, increase the power + var/obj/item/organ/internal/eyes/target_eyes = target.get_organ_slot(ORGAN_SLOT_EYES) + if (!istype(target_eyes)) + return + var/infravision_multiplier = max(0, (-(target_eyes.flash_protect) * NOVA_NIGHT_VISION_SENSITIVITY_MULT)) + 1 + + var/list/new_rgb_cutoffs = new /list(3) + for(var/i in 1 to 3) + var/base_color = hex2num(copytext(color, (i*2), (i*2)+2)) //convert their supplied hex colour value to RGB + var/adjusted_color = max(((base_color / 255) * (NOVA_NIGHT_VISION_POWER_MAX * infravision_multiplier)), (NOVA_NIGHT_VISION_POWER_MIN * infravision_multiplier)) //linear convert their eye color into a color_cutoff range, ensuring it is clamped + new_rgb_cutoffs[i] = adjusted_color + + return new_rgb_cutoffs + +/datum/quirk_constant_data/night_vision + associated_typepath = /datum/quirk/night_vision + customization_options = list(/datum/preference/color/nv_color) + +// Client preference for night vision colour +/datum/preference/color/nv_color + savefile_key = "nv_color" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + +/datum/preference/color/nv_color/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return "Night Vision" in preferences.all_quirks + +/datum/preference/color/nv_color/apply_to_human(mob/living/carbon/human/target, value) + return + +// run the Blessed Runechat Proc since it does most of what we want regarding luminance clamping anyway. could it be better? probably. is it more work? yes, it's a LOT of work. +/datum/preference/color/nv_color/deserialize(input, datum/preferences/preferences) + return process_chat_color(sanitize_hexcolor(input)) + +/datum/preference/color/nv_color/serialize(input) + return process_chat_color(sanitize_hexcolor(input)) + +/datum/preference/color/nv_color/create_default_value() + return process_chat_color("#[random_color()]") diff --git a/tgstation.dme b/tgstation.dme index 2764bdbc59d..47ec0507cd0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6221,8 +6221,10 @@ #include "modular_nova\master_files\code\datums\quirks\negative_quirks\heavy_sleeper.dm" #include "modular_nova\master_files\code\datums\quirks\negative_quirks\narcolepsy.dm" #include "modular_nova\master_files\code\datums\quirks\negative_quirks\nerve_staple.dm" +#include "modular_nova\master_files\code\datums\quirks\negative_quirks\photophobia.dm" #include "modular_nova\master_files\code\datums\quirks\neutral_quirks\equipping.dm" #include "modular_nova\master_files\code\datums\quirks\neutral_quirks\lungs.dm" +#include "modular_nova\master_files\code\datums\quirks\positive_quirks\night_vision.dm" #include "modular_nova\master_files\code\datums\quirks\positive_quirks\spacer.dm" #include "modular_nova\master_files\code\datums\records\record.dm" #include "modular_nova\master_files\code\datums\station_traits\negative_traits.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/night_vision.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/night_vision.tsx new file mode 100644 index 00000000000..098e4b8d508 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/night_vision.tsx @@ -0,0 +1,7 @@ +// THIS IS A NOVA SECTOR UI FILE +import { Feature, FeatureColorInput } from '../../base'; + +export const nv_color: Feature = { + name: 'Night vision tint', + component: FeatureColorInput, +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/photophobia.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/photophobia.tsx new file mode 100644 index 00000000000..4e1fcbfea8f --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/photophobia.tsx @@ -0,0 +1,7 @@ +// THIS IS A NOVA SECTOR UI FILE +import { FeatureChoiced, FeatureDropdownInput } from '../../base'; + +export const photophobia_severity: FeatureChoiced = { + name: 'Severity', + component: FeatureDropdownInput, +};