From d5c7011cc4ada5025586d11e1949527d2c5a2919 Mon Sep 17 00:00:00 2001 From: bobhat <59947126+b0bhat@users.noreply.github.com> Date: Sat, 8 Jun 2024 19:04:32 -0700 Subject: [PATCH] Fix night vision goggles (#74298) * stat changes * Re-add green overlay for night vis * Character flag for green NVG overlay * fix rigid coverage and change views * astyle * module holder flag and inventory enchantment checking fix * set nv green overlay active * IR + NVG working for ENVG * fix * minor changes and balance * astyle and revert desc * lint --- data/json/effects.json | 6 +++ data/json/enchantments.json | 16 +++++- data/json/flags.json | 9 ++++ data/json/items/armor/head_attachments.json | 51 ++++++++++++------- data/json/items/armor/helmets.json | 8 +-- data/json/items/tool_armor.json | 2 +- .../items/armor/exosuit/exosuit_frame.json | 32 ++++++++++-- src/character.cpp | 33 ++++++++---- src/character.h | 6 ++- src/character_attire.cpp | 3 +- src/flag.cpp | 1 + src/flag.h | 1 + 12 files changed, 128 insertions(+), 40 deletions(-) diff --git a/data/json/effects.json b/data/json/effects.json index 9c5564573df0f..7aca1e9932648 100644 --- a/data/json/effects.json +++ b/data/json/effects.json @@ -4625,6 +4625,12 @@ } ] }, + { + "type": "effect_type", + "id": "nvg_green", + "name": [ "Night Vision Goggles (Green)" ], + "desc": [ "Your night vision goggles give a green tint to the world." ] + }, { "type": "effect_type", "id": "glowing_gas", diff --git a/data/json/enchantments.json b/data/json/enchantments.json index c9b3673d82be9..67a8be0747817 100644 --- a/data/json/enchantments.json +++ b/data/json/enchantments.json @@ -43,12 +43,22 @@ "condition": "ALWAYS", "values": [ { "value": "FOOTSTEP_NOISE", "multiply": 3 } ] }, + { + "type": "enchantment", + "id": "nvg_great", + "name": { "str": "Night Vision Goggles" }, + "description": "You are wearing night vision goggles which allow you to see really well in the dark.", + "condition": "ACTIVE", + "has": "WORN", + "values": [ { "value": "NIGHT_VIS", "add": 14 } ] + }, { "type": "enchantment", "id": "nvg_good", "name": { "str": "Night Vision Goggles" }, "description": "You are wearing night vision goggles which allow you to see quite well in the dark.", "condition": "ACTIVE", + "has": "WORN", "values": [ { "value": "NIGHT_VIS", "add": 12 } ] }, { @@ -57,7 +67,8 @@ "name": { "str": "Night Vision Goggles" }, "description": "You are wearing night vision goggles which allow you to see in the dark.", "condition": "ACTIVE", - "values": [ { "value": "NIGHT_VIS", "add": 9 } ] + "has": "WORN", + "values": [ { "value": "NIGHT_VIS", "add": 10 } ] }, { "type": "enchantment", @@ -65,7 +76,8 @@ "name": { "str": "Night Vision Goggles" }, "description": "You are wearing night vision goggles which allow you to poorly see in the dark.", "condition": "ACTIVE", - "values": [ { "value": "NIGHT_VIS", "add": 5 } ] + "has": "WORN", + "values": [ { "value": "NIGHT_VIS", "add": 8 } ] }, { "id": "ench_climate_control_warm", diff --git a/data/json/flags.json b/data/json/flags.json index 1844187cecf0b..513618b54a254 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -1568,6 +1568,11 @@ "id": "MISSION_ITEM", "type": "json_flag" }, + { + "id": "MODULE_HOLDER", + "//": "Allows enchantment check to get modules in pockets of this item (modules are items which have an enchantment effect and the HAS:WORN flag.", + "type": "json_flag" + }, { "id": "MOUNTED_GUN", "info": "This weapon is too unwieldy to fire on its own and must be mounted on a vehicle or furniture (window, table, mound of dirt, etc.) before use.", @@ -1690,6 +1695,10 @@ "id": "NPC_THROW_NOW", "type": "json_flag" }, + { + "id": "NVG_GREEN", + "type": "json_flag" + }, { "id": "ORGANIC", "type": "json_flag" diff --git a/data/json/items/armor/head_attachments.json b/data/json/items/armor/head_attachments.json index 0d97494f1e035..5ceddfd34e784 100644 --- a/data/json/items/armor/head_attachments.json +++ b/data/json/items/armor/head_attachments.json @@ -211,7 +211,7 @@ "type": "TOOL_ARMOR", "category": "armor", "name": { "str_sp": "night vision goggles" }, - "description": "Last generation double-tube night vision device, designed to be mounted to a helmet. Currently raised up and out of the way.", + "description": "Last generation double-tube night vision device, designed to be mounted on a compatible helmet. Currently raised up and out of the way.", "weight": "680 g", "volume": "1200 ml", "price": "10000 USD", @@ -239,17 +239,21 @@ "default_magazine": "light_plus_battery_cell" } ], - "relic_data": { "passive_effects": [ { "id": "nvg_good" } ] }, + "relic_data": { "passive_effects": [ { "id": "nvg_normal" } ] }, "flags": [ "HELMET_FRONT_ATTACHMENT", "CANT_WEAR", "OUTER", "ELECTRONIC", "MUNDANE" ], - "armor": [ { "covers": [ "head" ], "encumbrance": 8, "coverage": 70, "specifically_covers": [ "head_forehead" ] } ] + "armor": [ + { "covers": [ "eyes" ], "coverage": 10, "encumbrance": 0, "rigid_layer_only": true }, + { "covers": [ "head" ], "encumbrance": 8, "coverage": 70, "specifically_covers": [ "head_forehead" ] } + ] }, { "id": "military_nvg_on", "type": "TOOL_ARMOR", "copy-from": "military_nvg", "name": { "str_sp": "night vision goggles (on)" }, - "description": "Last generation double-tube night vision device, designed to be mounted to a helmet. Very limited field of view while activated. It is turned on, and continually draining batteries. Use it to turn it off.", + "description": "Last generation single-tube night vision device, designed to be mounted on a compatible helmet. Limited field of view while activated. It is turned on, and continually draining batteries. Use it to turn it off.", "//": "AN/PVS-7", + "extend": { "flags": [ "NVG_GREEN" ] }, "power_draw": "140 mW", "revert_to": "military_nvg", "use_action": { @@ -259,14 +263,14 @@ "msg": "Your %s deactivates.", "target": "military_nvg" }, - "armor": [ { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 20 } ] + "armor": [ { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 20, "rigid_layer_only": true } ] }, { "id": "advanced_gpnvg", "type": "TOOL_ARMOR", "category": "armor", "name": { "str_sp": "panoramic night vision goggles" }, - "description": "Advanced GPNVG with four image intensifier tubes, allowing for a large field of view at night, designed to be mounted to a helmet. Currently raised up and out of the way.", + "description": "Advanced GPNVG with four image intensifier tubes, allowing for a large field of view at night, designed to be mounted on a compatible helmet. Currently raised up and out of the way.", "weight": "765 g", "volume": "1600 ml", "price": "47000 USD", @@ -294,10 +298,16 @@ "default_magazine": "medium_plus_battery_cell" } ], - "relic_data": { "passive_effects": [ { "id": "nvg_normal" } ] }, + "relic_data": { "passive_effects": [ { "id": "nvg_good" } ] }, "flags": [ "HELMET_FRONT_ATTACHMENT", "CANT_WEAR", "OUTER", "ELECTRONIC", "MUNDANE" ], "armor": [ - { "covers": [ "head" ], "encumbrance": 12, "coverage": 80, "specifically_covers": [ "head_forehead", "head_crown" ] } + { "covers": [ "eyes" ], "coverage": 10, "encumbrance": 0, "rigid_layer_only": true }, + { + "covers": [ "head" ], + "encumbrance": 12, + "coverage": 80, + "specifically_covers": [ "head_forehead", "head_crown" ] + } ] }, { @@ -305,8 +315,9 @@ "type": "TOOL_ARMOR", "copy-from": "advanced_gpnvg", "name": { "str_sp": "panoramic night vision goggles (on)" }, - "description": "Advanced GPNVG with four image intensifier tubes, allowing for a large field of view at night, designed to be mounted to a helmet. It is turned on, and continually draining batteries. Use it to turn it off.", + "description": "Advanced GPNVG with four image intensifier tubes, allowing for a large field of view at night, designed to be mounted on a compatible helmet. It is turned on, and continually draining batteries. Use it to turn it off.", "//": "GPNVG-18", + "extend": { "flags": [ "NVG_GREEN" ] }, "power_draw": "180 mW", "revert_to": "advanced_gpnvg", "use_action": { @@ -317,7 +328,7 @@ "target": "advanced_gpnvg" }, "armor": [ - { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 15 }, + { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 15, "rigid_layer_only": true }, { "covers": [ "head" ], "encumbrance": 3, "coverage": 80, "specifically_covers": [ "head_crown" ] } ] }, @@ -326,7 +337,7 @@ "type": "TOOL_ARMOR", "category": "armor", "name": { "str_sp": "enhanced night vision goggles" }, - "description": "New and rare high-resolution thermal NVG device, designed to be mounted to a helmet. Lets you see in the dark, and detects heat signatures emitted by (un)living organisms. Currently raised up and out of the way.", + "description": "New and rare high-resolution thermal NVG device, designed to be mounted on a compatible helmet. Lets you see in the dark, and detects heat signatures emitted by (un)living organisms. Currently raised up and out of the way.", "weight": "720 g", "volume": "1400 ml", "price": "10000 USD", @@ -354,10 +365,16 @@ "default_magazine": "medium_plus_battery_cell" } ], - "relic_data": { "passive_effects": [ { "id": "nvg_normal" } ] }, + "relic_data": { "passive_effects": [ { "id": "nvg_good" } ] }, "flags": [ "HELMET_FRONT_ATTACHMENT", "CANT_WEAR", "OUTER", "ELECTRONIC", "MUNDANE" ], "armor": [ - { "covers": [ "head" ], "encumbrance": 10, "coverage": 70, "specifically_covers": [ "head_forehead", "head_crown" ] } + { "covers": [ "eyes" ], "coverage": 10, "encumbrance": 0, "rigid_layer_only": true }, + { + "covers": [ "head" ], + "encumbrance": 10, + "coverage": 70, + "specifically_covers": [ "head_forehead", "head_crown" ] + } ] }, { @@ -365,10 +382,10 @@ "type": "TOOL_ARMOR", "copy-from": "enhanced_nvg", "name": { "str_sp": "enhanced night vision goggles (on)" }, - "description": "New and rare high-resolution thermal NVG device, designed to be mounted to a helmet. Lets you see in the dark, and detects heat signatures emitted by (un)living organisms. It is turned on, and continually draining batteries. Use it to turn it off.", - "extend": { "flags": [ "IR_EFFECT" ] }, + "description": "New and rare high-resolution thermal NVG device, designed to be mounted on a compatible helmet. Lets you see in the dark, and detects heat signatures emitted by (un)living organisms. It is turned on, and continually draining batteries. Use it to turn it off.", "//": "AN/PSQ-42", - "power_draw": "250 W", + "extend": { "flags": [ "NVG_GREEN", "IR_EFFECT" ] }, + "power_draw": "320 mW", "revert_to": "enhanced_nvg", "use_action": { "ammo_scale": 0, @@ -378,7 +395,7 @@ "target": "enhanced_nvg" }, "armor": [ - { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 10 }, + { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 10, "rigid_layer_only": true }, { "covers": [ "head" ], "encumbrance": 3, "coverage": 80, "specifically_covers": [ "head_crown" ] } ] }, diff --git a/data/json/items/armor/helmets.json b/data/json/items/armor/helmets.json index fae93625ad67a..fd880cf8a1232 100644 --- a/data/json/items/armor/helmets.json +++ b/data/json/items/armor/helmets.json @@ -176,7 +176,7 @@ "warmth": 20, "material_thickness": 9, "techniques": [ "WBLOCK_1" ], - "flags": [ "VARSIZE", "WATERPROOF", "STURDY", "PADDED" ], + "flags": [ "VARSIZE", "WATERPROOF", "STURDY", "PADDED", "MODULE_HOLDER" ], "armor": [ { "encumbrance_modifiers": [ "NONE" ], @@ -363,7 +363,7 @@ "material_thickness": 8, "environmental_protection": 2, "techniques": [ "WBLOCK_1" ], - "flags": [ "VARSIZE", "WATERPROOF", "STURDY", "SUN_GLASSES", "PADDED" ], + "flags": [ "VARSIZE", "WATERPROOF", "STURDY", "SUN_GLASSES", "PADDED", "MODULE_HOLDER" ], "pocket_data": [ { "pocket_type": "CONTAINER", @@ -397,7 +397,7 @@ "warmth": 20, "material_thickness": 8, "techniques": [ "WBLOCK_1" ], - "flags": [ "VARSIZE", "WATERPROOF", "STURDY", "PADDED" ], + "flags": [ "VARSIZE", "WATERPROOF", "STURDY", "PADDED", "MODULE_HOLDER" ], "armor": [ { "encumbrance_modifiers": [ "NONE" ], @@ -2844,7 +2844,7 @@ "color": "dark_gray", "warmth": 15, "techniques": [ "WBLOCK_1" ], - "flags": [ "WATERPROOF", "PADDED" ], + "flags": [ "WATERPROOF", "PADDED", "MODULE_HOLDER" ], "armor": [ { "material": [ diff --git a/data/json/items/tool_armor.json b/data/json/items/tool_armor.json index b5c3dea3d3ae7..cf8d631b917e5 100644 --- a/data/json/items/tool_armor.json +++ b/data/json/items/tool_armor.json @@ -2439,7 +2439,7 @@ "name": { "str_pl": "pairs of light amp goggles (on)", "str": "pair of light amp goggles (on)" }, "description": "A pair of battery-powered goggles that use a infrared LED in conjunction with a IR camera, allowing you to see in the dark. It is turned on, and continually draining batteries. Use it to turn them off.", "material": [ "plastic", "steel" ], - "extend": { "flags": [ "TRADER_AVOID" ] }, + "extend": { "flags": [ "TRADER_AVOID", "NVG_GREEN" ] }, "//": "2019 commercial models can operate at under 0.375W with the IR illuminator on", "power_draw": "375 mW", "revert_to": "goggles_nv", diff --git a/data/mods/Aftershock/items/armor/exosuit/exosuit_frame.json b/data/mods/Aftershock/items/armor/exosuit/exosuit_frame.json index 328b41533edbc..57f91f19826c6 100644 --- a/data/mods/Aftershock/items/armor/exosuit/exosuit_frame.json +++ b/data/mods/Aftershock/items/armor/exosuit/exosuit_frame.json @@ -310,7 +310,18 @@ } ], "ammo": "battery", - "flags": [ "USE_UPS", "STURDY", "WATERPROOF", "ELECTRIC_IMMUNE", "COMBAT_TOGGLEABLE", "OUTER", "MUNDANE", "DEAF", "TARDIS" ], + "flags": [ + "USE_UPS", + "STURDY", + "WATERPROOF", + "ELECTRIC_IMMUNE", + "COMBAT_TOGGLEABLE", + "OUTER", + "MUNDANE", + "DEAF", + "TARDIS", + "MODULE_HOLDER" + ], "relic_data": { "passive_effects": [ { "condition": "ACTIVE", "values": [ { "value": "STRENGTH", "add": 10 }, { "value": "CARRY_WEIGHT", "add": 20000 } ] } @@ -346,7 +357,8 @@ "PARTIAL_DEAF", "SUN_GLASSES", "FLASH_PROTECTION", - "TARDIS" + "TARDIS", + "MODULE_HOLDER" ], "power_draw": "6460 mW", "revert_to": "modular_exosuit", @@ -529,7 +541,18 @@ } ], "ammo": "battery", - "flags": [ "USE_UPS", "STURDY", "WATERPROOF", "ELECTRIC_IMMUNE", "COMBAT_TOGGLEABLE", "OUTER", "MUNDANE", "DEAF", "TARDIS" ], + "flags": [ + "USE_UPS", + "STURDY", + "WATERPROOF", + "ELECTRIC_IMMUNE", + "COMBAT_TOGGLEABLE", + "OUTER", + "MUNDANE", + "DEAF", + "TARDIS", + "MODULE_HOLDER" + ], "relic_data": { "passive_effects": [ { "id": "ench_exo_strength" } ] }, "use_action": [ { @@ -561,7 +584,8 @@ "PARTIAL_DEAF", "SUN_GLASSES", "FLASH_PROTECTION", - "TARDIS" + "TARDIS", + "MODULE_HOLDER" ], "relic_data": { "passive_effects": [ { "condition": "ACTIVE", "values": [ { "value": "STRENGTH", "add": 5 } ] } ] }, "power_draw": "5787 mW", diff --git a/src/character.cpp b/src/character.cpp index a372590232e03..cce5aa112901b 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -324,6 +324,7 @@ static const json_character_flag json_flag_NIGHT_VISION( "NIGHT_VISION" ); static const json_character_flag json_flag_NON_THRESH( "NON_THRESH" ); static const json_character_flag json_flag_NO_RADIATION( "NO_RADIATION" ); static const json_character_flag json_flag_NO_THIRST( "NO_THIRST" ); +static const json_character_flag json_flag_NVG_GREEN( "NVG_GREEN" ); static const json_character_flag json_flag_PAIN_IMMUNE( "PAIN_IMMUNE" ); static const json_character_flag json_flag_PLANTBLOOD( "PLANTBLOOD" ); static const json_character_flag json_flag_PRED2( "PRED2" ); @@ -2555,7 +2556,7 @@ void Character::recalc_sight_limits() if( has_trait( trait_DEBUG_NIGHTVISION ) ) { vision_mode_cache.set( DEBUG_NIGHTVISION ); } - if( has_nv() ) { + if( has_nv_goggles() ) { vision_mode_cache.set( NV_GOGGLES ); } if( has_active_mutation( trait_NIGHTVISION3 ) || is_wearing( itype_rm13_armor_on ) || @@ -2588,7 +2589,7 @@ void Character::recalc_sight_limits() } // Not exactly a sight limit thing, but related enough - if( has_flag( json_flag_INFRARED ) || + if( has_flag( json_flag_INFRARED ) || has_worn_module_with_flag( flag_IR_EFFECT ) || worn_with_flag( flag_IR_EFFECT ) || ( is_mounted() && mounted_creature->has_flag( mon_flag_MECH_RECON_VISION ) ) ) { vision_mode_cache.set( IR_VISION ); @@ -2622,8 +2623,8 @@ float Character::get_vision_threshold( float light_level ) const ( LIGHT_AMBIENT_LIT - LIGHT_AMBIENT_MINIMAL ) ); float range = get_per() / 3.0f; - if( vision_mode_cache[NV_GOGGLES] || vision_mode_cache[NIGHTVISION_3] || - vision_mode_cache[FULL_ELFA_VISION] || vision_mode_cache[CEPH_VISION] ) { + if( vision_mode_cache[NIGHTVISION_3] || vision_mode_cache[FULL_ELFA_VISION] || + vision_mode_cache[CEPH_VISION] ) { range += 10; } else if( vision_mode_cache[NIGHTVISION_2] || vision_mode_cache[FELINE_VISION] || vision_mode_cache[URSINE_VISION] || vision_mode_cache[ELFA_VISION] ) { @@ -2636,7 +2637,12 @@ float Character::get_vision_threshold( float light_level ) const range++; } - range = enchantment_cache->modify_value( enchant_vals::mod::NIGHT_VIS, range ); + // bionic night vision and other old night vision flagged items + if( worn_with_flag( flag_GNV_EFFECT ) || has_flag( json_flag_NIGHT_VISION ) ) { + range += 10; + } else { + range = enchantment_cache->modify_value( enchant_vals::mod::NIGHT_VIS, range ); + } // Clamp range to 1+, so that we can always see where we are range = std::max( 1.0f, range * get_limb_score( limb_score_night_vis ) ); @@ -3871,19 +3877,28 @@ void Character::reset() reset_stats(); } -bool Character::has_nv() +bool Character::has_nv_goggles() { static bool nv = false; if( !nv_cached ) { nv_cached = true; - nv = ( worn_with_flag( flag_GNV_EFFECT ) || - has_flag( json_flag_NIGHT_VISION ) ); + nv = worn_with_flag( flag_GNV_EFFECT ) || has_flag( json_flag_NIGHT_VISION ) || + worn_with_flag( json_flag_NVG_GREEN ) || has_worn_module_with_flag( json_flag_NVG_GREEN ); } - return nv; } +bool Character::has_worn_module_with_flag( const flag_id &f ) +{ + std::vector flag_items = cache_get_items_with( f ); + bool has_flag = std::any_of( flag_items.begin(), flag_items.end(), + [this]( item * i ) { + return is_worn_module( *i ); + } ); + return has_flag; +} + void Character::calc_discomfort() { // clear all instances of discomfort diff --git a/src/character.h b/src/character.h index cdc37dcd3a37e..ae0151a4e7a76 100644 --- a/src/character.h +++ b/src/character.h @@ -1923,6 +1923,8 @@ class Character : public Creature, public visitable bool is_worn_module( const item &thing ) const { return worn.is_worn_module( thing ); } + + bool has_worn_module_with_flag( const flag_id &f ); /** * Asks how to use the item (if it has more than one use_method) and uses it. * Returns true if it destroys the item. Consumes charges from the item. @@ -2612,8 +2614,8 @@ class Character : public Creature, public visitable /** Returns overall % of HP remaining */ int hp_percentage() const override; - /** Returns true if the player has some form of night vision */ - bool has_nv(); + /** Returns true if the player has some form of night vision with green overlay */ + bool has_nv_goggles(); int get_lift_assist() const; diff --git a/src/character_attire.cpp b/src/character_attire.cpp index 895866d8fcb22..d1cdbac669183 100644 --- a/src/character_attire.cpp +++ b/src/character_attire.cpp @@ -992,7 +992,8 @@ bool outfit::is_worn_module( const item &thing ) const { return thing.has_flag( flag_CANT_WEAR ) && std::any_of( worn.cbegin(), worn.cend(), [&thing]( item const & elem ) { - return elem.contained_where( thing ) != nullptr; + return elem.has_flag( flag_MODULE_HOLDER ) && + elem.contained_where( thing ) != nullptr; } ); } diff --git a/src/flag.cpp b/src/flag.cpp index 4f318499d00fb..7ab1e8039d0c3 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -191,6 +191,7 @@ const flag_id flag_MECH_BAT( "MECH_BAT" ); const flag_id flag_MELTS( "MELTS" ); const flag_id flag_MESSY( "MESSY" ); const flag_id flag_MISSION_ITEM( "MISSION_ITEM" ); +const flag_id flag_MODULE_HOLDER( "MODULE_HOLDER" ); const flag_id flag_MOUNTED_GUN( "MOUNTED_GUN" ); const flag_id flag_MOUSE( "MOUSE" ); const flag_id flag_MUNDANE( "MUNDANE" ); diff --git a/src/flag.h b/src/flag.h index 1310783db6514..38cf65efa7376 100644 --- a/src/flag.h +++ b/src/flag.h @@ -199,6 +199,7 @@ extern const flag_id flag_MECH_BAT; extern const flag_id flag_MELTS; extern const flag_id flag_MESSY; extern const flag_id flag_MISSION_ITEM; +extern const flag_id flag_MODULE_HOLDER; extern const flag_id flag_MOUNTED_GUN; extern const flag_id flag_MOUSE; extern const flag_id flag_MUNDANE;