From 4840ee2e553ca74e14f3bbd624750cc51766ec8f Mon Sep 17 00:00:00 2001 From: Venera3 <72006894+Venera3@users.noreply.github.com> Date: Mon, 12 Sep 2022 13:11:28 +0200 Subject: [PATCH] Limbify/flagify field immunity (#60852) * Field immunity changes * Update doc/JSON_INFO.md Co-authored-by: Fris0uman <41293484+Fris0uman@users.noreply.github.com> Co-authored-by: Venera3 Co-authored-by: Fris0uman <41293484+Fris0uman@users.noreply.github.com> --- data/json/field_type.json | 9 ++--- .../monster_deaths.json | 6 ++-- data/json/monsters/turrets.json | 2 +- data/json/mutations/mutations.json | 5 ++- data/mods/Aftershock/effects.json | 2 +- data/mods/Aftershock/mutations/mutations.json | 3 +- data/mods/Magiclysm/field.json | 4 +-- data/mods/Magiclysm/monsters/dragon.json | 2 +- data/mods/Magiclysm/traits/attunements.json | 4 +-- data/mods/desert_region/weather/fd_dust.json | 2 +- doc/JSON_INFO.md | 7 ++-- src/character.cpp | 34 ++++++++++++++++--- src/field_type.cpp | 12 ++++--- src/field_type.h | 6 ++-- 14 files changed, 68 insertions(+), 30 deletions(-) diff --git a/data/json/field_type.json b/data/json/field_type.json index a0b84e470e7a2..283218a65ec18 100644 --- a/data/json/field_type.json +++ b/data/json/field_type.json @@ -93,7 +93,7 @@ } ], "description_affix": "covered_in", - "immunity_data": { "traits": [ "WEB_WALKER" ] }, + "immunity_data": { "flags": [ "WEBWALK" ] }, "immune_mtypes": [ "mon_spider_web", "mon_spider_web_s", "mon_mutant_arthropod" ], "decrease_intensity_on_contact": true, "priority": 2, @@ -158,7 +158,7 @@ { "name": "pool of acid", "color": "green" } ], "description_affix": "covered_in", - "immunity_data": { "traits": [ "ACIDPROOF" ] }, + "immunity_data": { "flags": [ "ACID_IMMUNE" ] }, "underwater_age_speedup": "2 minutes", "has_acid": true, "priority": 2, @@ -262,7 +262,7 @@ "half_life": "30 minutes", "phase": "liquid", "display_field": true, - "immunity_data": { "traits": [ "GASTROPOD_FOOT" ] }, + "immunity_data": { "flags": [ "SLUDGE_IMMUNE" ] }, "looks_like": "fd_sap" }, { @@ -940,6 +940,7 @@ { "//": "repeat last entry" } ], "description_affix": "illuminated_by", + "immunity_data": { "immunity_flags_worn": [ [ "sensor", "FLASH_PROTECTION" ] ] }, "priority": 4, "half_life": "1 turns", "phase": "plasma", @@ -1305,7 +1306,7 @@ "outdoor_age_speedup": "5 turns", "dirty_transparency_cache": true, "has_fume": true, - "immunity_data": { "traits": [ "M_IMMUNE" ], "body_part_env_resistance": [ [ "mouth", 15 ], [ "eyes", 15 ] ] }, + "immunity_data": { "flags": [ "MYCUS_IMMUNE" ], "body_part_env_resistance": [ [ "mouth", 15 ], [ "sensor", 15 ] ] }, "priority": 8, "half_life": "4 minutes", "phase": "gas", diff --git a/data/json/monster_special_attacks/monster_deaths.json b/data/json/monster_special_attacks/monster_deaths.json index 8d6dc82ace963..4cac8b1a93016 100644 --- a/data/json/monster_special_attacks/monster_deaths.json +++ b/data/json/monster_special_attacks/monster_deaths.json @@ -534,9 +534,11 @@ "valid_targets": [ "hostile", "ally", "ground" ], "effect": "attack", "shape": "blast", - "flags": [ "NO_EXPLOSION_SFX" ], + "flags": [ "NO_EXPLOSION_SFX", "RANDOM_AOE" ], "field_id": "fd_dazzling", - "field_chance": 1, + "min_aoe": 1, + "max_aoe": 2, + "field_chance": 2, "min_field_intensity": 2, "max_field_intensity": 2, "min_range": 2, diff --git a/data/json/monsters/turrets.json b/data/json/monsters/turrets.json index c065dcdba3356..c379f52d2f3b1 100644 --- a/data/json/monsters/turrets.json +++ b/data/json/monsters/turrets.json @@ -73,7 +73,7 @@ "special_attacks": [ [ "SEARCHLIGHT", 1 ] ], "death_drops": { "groups": [ [ "robots", 1 ], [ "turret_searchlight", 1 ] ] }, "death_function": { - "effect": { "id": "death_focused_beam" }, + "effect": { "id": "death_focused_beam", "hit_self": true }, "message": "As the final light is destroyed, it erupts in a blinding flare!", "corpse_type": "NO_CORPSE" }, diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 2631794cfdc3a..0379c7708782d 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -3369,7 +3369,8 @@ "valid": false, "purifiable": false, "threshreq": [ "THRESH_MYCUS" ], - "category": [ "MYCUS" ] + "category": [ "MYCUS" ], + "flags": [ "MYCUS_IMMUNE" ] }, { "type": "mutation", @@ -4567,6 +4568,7 @@ "prereqs": [ "SLIMY" ], "threshreq": [ "THRESH_GASTROPOD" ], "leads_to": [ "GASTROPOD_BALANCE" ], + "flags": [ "SLUDGE_IMMUNE" ], "visibility": 8, "ugliness": 9, "encumbrance_always": [ [ "leg_l", 10 ], [ "leg_r", 10 ], [ "foot_l", 10 ], [ "foot_r", 10 ] ], @@ -4711,6 +4713,7 @@ "points": 1, "description": "Your body excretes very fine amounts of a chemical which prevents you from sticking to webs. Walking through webs does not affect you at all.", "leads_to": [ "WEB_WEAVER" ], + "flags": [ "WEBWALK" ], "category": [ "SPIDER" ] }, { diff --git a/data/mods/Aftershock/effects.json b/data/mods/Aftershock/effects.json index 0356a8a04686a..e62838f8ba409 100644 --- a/data/mods/Aftershock/effects.json +++ b/data/mods/Aftershock/effects.json @@ -50,7 +50,7 @@ "outdoor_age_speedup": "3 minutes", "dirty_transparency_cache": true, "has_fume": true, - "immunity_data": { "body_part_env_resistance": [ [ "mouth", 15 ] ], "traits": [ "MIGO_BREATHE" ] }, + "immunity_data": { "body_part_env_resistance": [ [ "mouth", 15 ] ], "flags": [ "MIGO_IMMUNE" ] }, "priority": 8, "half_life": "10 minutes", "phase": "gas" diff --git a/data/mods/Aftershock/mutations/mutations.json b/data/mods/Aftershock/mutations/mutations.json index 711c8a43080ae..10fe9a20ea89e 100644 --- a/data/mods/Aftershock/mutations/mutations.json +++ b/data/mods/Aftershock/mutations/mutations.json @@ -290,7 +290,8 @@ "points": 4, "description": "You can now breathe the gasses the mi-go thrive in.", "starting_trait": false, - "category": [ "MIGO" ] + "category": [ "MIGO" ], + "flags": [ "MIGO_IMMUNE" ] }, { "type": "mutation", diff --git a/data/mods/Magiclysm/field.json b/data/mods/Magiclysm/field.json index adbf412138356..86aac34f86153 100644 --- a/data/mods/Magiclysm/field.json +++ b/data/mods/Magiclysm/field.json @@ -78,7 +78,7 @@ } ], "description_affix": "covered_in", - "immunity_data": { "traits": [ "SHAPESHIFTER" ] }, + "immunity_data": { "flags": [ "ALKAHEST_IMMUNE" ] }, "underwater_age_speedup": "8 h", "priority": 2, "half_life": "8 h", @@ -114,7 +114,7 @@ "effects": [ { "effect_id": "ice_energy", "intensity": 3, "immune_in_vehicle": true, "is_environmental": false } ] } ], - "immunity_data": { "traits": [ "PERMAFROST_MAGE" ] }, + "immunity_data": { "flags": [ "COLD_ENERGY_IMMUNE" ] }, "half_life": "3 seconds" }, { diff --git a/data/mods/Magiclysm/monsters/dragon.json b/data/mods/Magiclysm/monsters/dragon.json index 8760000586c15..652e51ea22f45 100644 --- a/data/mods/Magiclysm/monsters/dragon.json +++ b/data/mods/Magiclysm/monsters/dragon.json @@ -52,7 +52,7 @@ "dirty_transparency_cache": true, "percent_spread": 40, "outdoor_age_speedup": "0 turns", - "immunity_data": { "body_part_env_resistance": [ [ "eyes", 12 ] ] }, + "immunity_data": { "body_part_env_resistance": [ [ "sensor", 12 ] ] }, "priority": 8, "half_life": "2 minutes", "phase": "gas", diff --git a/data/mods/Magiclysm/traits/attunements.json b/data/mods/Magiclysm/traits/attunements.json index eec0a345b66db..d1effde8110f6 100644 --- a/data/mods/Magiclysm/traits/attunements.json +++ b/data/mods/Magiclysm/traits/attunements.json @@ -758,7 +758,7 @@ "SOULFIRE", "WITHER_MAGE" ], - "flags": [ "ATTUNEMENT" ] + "flags": [ "ATTUNEMENT", "COLD_ENERGY_IMMUNE" ] }, { "id": "RADIATION_MAGE", @@ -879,7 +879,7 @@ "SOULFIRE", "WITHER_MAGE" ], - "flags": [ "ATTUNEMENT" ] + "flags": [ "ATTUNEMENT", "ALKAHEST_IMMUNE" ] }, { "id": "SOULFIRE", diff --git a/data/mods/desert_region/weather/fd_dust.json b/data/mods/desert_region/weather/fd_dust.json index 670aba37426c2..cdd1a503ca684 100644 --- a/data/mods/desert_region/weather/fd_dust.json +++ b/data/mods/desert_region/weather/fd_dust.json @@ -106,7 +106,7 @@ "gas_absorption_factor": 12, "outdoor_age_speedup": "20 seconds", "dirty_transparency_cache": true, - "immunity_data": { "body_part_env_resistance": [ [ "mouth", 3 ], [ "eyes", 1 ] ] }, + "immunity_data": { "body_part_env_resistance": [ [ "mouth", 3 ], [ "sensor", 1 ] ] }, "priority": 8, "half_life": "20 seconds", "phase": "gas", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 698ebbc40740a..a5e301863b7cd 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -5317,9 +5317,10 @@ Fields can exist on top of terrain/furniture, and support different intensity le ], "npc_complain": { "chance": 20, "issue": "weed_smoke", "duration": "10 minutes", "speech": "" }, // NPCs in this field will complain about being in it once per if a 1-in- roll succeeds, giving off a bark that supports snippets "immunity_data": { - { "traits": [ "WEB_WALKER" ] }, - { "body_part_env_resistance": [ [ "mouth", 15 ] ] } - }, // If the character in the field has the defined traits or env resistance on the bodypart they will be considered immune to the field + { "flags": [ "WEBWALK" ] }, + { "body_part_env_resistance": [ [ "mouth", 15 ], [ "sensor", 10 ] ] }, + "immunity_flags_worn": [ [ "sensor", "FLASH_PROTECTION" ] ] + }, // If the character in the field has the defined character flags (see Character Flags), necessary env resistance or worn item flags on ALL bodyparts of the defined type they will be considered immune to the field's effects -- in this example a player is immune if they have the WEBWALK flag, wear flash protection on their eyes or have both their eyes and mouth covered "decay_amount_factor": 2, // The field's rain decay amount is divided by this when processing the field, the rain decay is a function of the weather type's precipitation class: very_light = 5s, light = 15s, heavy = 45 s "half_life": "3 minutes", // If above 0 the field will disappear after two half-lifes on average "underwater_age_speedup": "25 minutes", // Increase the field's age by this time every tick if it's on a terrain with the SWIMMABLE flag diff --git a/src/character.cpp b/src/character.cpp index fdf892ff15986..42852b812c9b0 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -5278,19 +5278,43 @@ bool Character::is_immune_field( const field_type_id &fid ) const } // Check to see if we are immune const field_type &ft = fid.obj(); - for( const trait_id &t : ft.immunity_data_traits ) { - if( has_trait( t ) ) { + for( const json_character_flag &flag : ft.immunity_data_flags ) { + if( has_flag( flag ) ) { return true; } } bool immune_by_body_part_resistance = !ft.immunity_data_body_part_env_resistance.empty(); - for( const std::pair &fide : ft.immunity_data_body_part_env_resistance ) { - immune_by_body_part_resistance = immune_by_body_part_resistance && - get_env_resist( fide.first.id() ) >= fide.second; + for( const std::pair &fide : + ft.immunity_data_body_part_env_resistance ) { + for( const bodypart_id &bp : get_all_body_parts_of_type( fide.first ) ) { + if( get_env_resist( bp ) < fide.second ) { + // If any one of a bodypart type is unprotected disregard this immunity type + // TODO: mitigate effect strength based on protected:unprotected ratio? + immune_by_body_part_resistance = false; + break; + } + } } if( immune_by_body_part_resistance ) { return true; } + + bool immune_by_worn_flags = !ft.immunity_data_part_item_flags.empty(); + for( const std::pair &fide : + ft.immunity_data_part_item_flags ) { + for( const bodypart_id &bp : get_all_body_parts_of_type( fide.first ) ) { + if( !worn_with_flag( fide.second, bp ) ) { + // If any one of a bodypart type is unprotected disregard this immunity type + // TODO: mitigate effect strength based on protected:unprotected ratio? + immune_by_worn_flags = false; + break; + } + } + } + if( immune_by_worn_flags ) { + return true; + } + if( ft.has_elec ) { return is_elec_immune(); } diff --git a/src/field_type.cpp b/src/field_type.cpp index 8119eb2ef439c..7a4e379b6479d 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -270,12 +270,16 @@ void field_type::load( const JsonObject &jo, const std::string & ) } JsonObject jid = jo.get_object( "immunity_data" ); - for( const std::string id : jid.get_array( "traits" ) ) { - immunity_data_traits.emplace_back( id ); + for( const std::string id : jid.get_array( "flags" ) ) { + immunity_data_flags.emplace_back( id ); } for( JsonArray jao : jid.get_array( "body_part_env_resistance" ) ) { - immunity_data_body_part_env_resistance.emplace_back( std::make_pair( bodypart_str_id( - jao.get_string( 0 ) ), jao.get_int( 1 ) ) ); + immunity_data_body_part_env_resistance.emplace_back( std::make_pair( + io::string_to_enum( jao.get_string( 0 ) ), jao.get_int( 1 ) ) ); + } + for( JsonArray jao : jid.get_array( "immunity_flags_worn" ) ) { + immunity_data_part_item_flags.emplace_back( std::make_pair( + io::string_to_enum( jao.get_string( 0 ) ), jao.get_string( 1 ) ) ); } optional( jo, was_loaded, "immune_mtypes", immune_mtypes ); diff --git a/src/field_type.h b/src/field_type.h index c397d7d9a6608..3a86dc16d1a28 100644 --- a/src/field_type.h +++ b/src/field_type.h @@ -13,6 +13,7 @@ #include #include +#include "bodypart.h" #include "calendar.h" #include "catacharset.h" #include "color.h" @@ -200,8 +201,9 @@ struct field_type { // chance, issue, duration, speech std::tuple npc_complain_data; - std::vector immunity_data_traits; - std::vector> immunity_data_body_part_env_resistance; + std::vector immunity_data_flags; + std::vector> immunity_data_body_part_env_resistance; + std::vector < std::pair> immunity_data_part_item_flags; std::set immune_mtypes; int priority = 0;