diff --git a/data/json/bionics.json b/data/json/bionics.json index 715e739b3dc4c..b8ab0e02e72c7 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -815,6 +815,7 @@ "name": { "str": "Enhanced Hearing" }, "description": "When this bionic is active, your hearing will be drastically improved, allowing you to hear ten times better than the average person. Additionally, high-intensity sounds will be automatically dampened before they can damage your hearing.", "occupied_bodyparts": [ [ "head", 2 ] ], + "mutation_conflicts": [ "BATEARS" ], "flags": [ "BIONIC_TOGGLED", "IMMUNE_HEARING_DAMAGE" ], "active_flags": [ "SUPER_HEARING" ], "auto_deactivates": [ "bio_earplugs" ], @@ -1600,6 +1601,18 @@ "flags": [ "BIONIC_NPC_USABLE" ], "enchantments": [ { "condition": "ALWAYS", "values": [ { "value": "WEAPON_DISPERSION", "multiply": -0.25 } ] } ] }, + { + "id": "bio_sonar", + "type": "bionic", + "name": { "str": "Subaquatic Navigation System" }, + "description": "While active, a tiny device in your inner ear periodically generates ultrasonic pulses which aid in navigation, provided you are underwater and able to hear.", + "occupied_bodyparts": [ [ "head", 1 ] ], + "act_cost": "1 J", + "trigger_cost": "5 J", + "flags": [ "BIONIC_TOGGLED" ], + "activated_eocs": [ "EOC_BIO_SONAR_activated" ], + "deactivated_eocs": [ "EOC_BIO_SONAR_deactivated" ] + }, { "id": "bio_taser", "type": "bionic", diff --git a/data/json/climbing.json b/data/json/climbing.json index 7ba1108ac7682..1afdf360ada41 100644 --- a/data/json/climbing.json +++ b/data/json/climbing.json @@ -195,7 +195,7 @@ "//": "Allows players to safely climb up/down or hold position against a wall.", "copy-from": "generic_superpower", "down": { - "menu_text": "Crawl down the wall with your sticky pads.", + "menu_text": "Crawl down the wall.", "confirm_text": "Crawl down the wall?", "msg_after": "You crawl down the wall.", "//": "Can be used repeatedly to descend 1 floor at a time.", diff --git a/data/json/dreams.json b/data/json/dreams.json index 2f16b7e439f6d..ca6f6dcb10d46 100644 --- a/data/json/dreams.json +++ b/data/json/dreams.json @@ -35,6 +35,16 @@ "category": "GASTROPOD", "strength": 1 }, + { + "type": "dream", + "messages": [ + "You dream about the moon.", + "You dream you're safely at home with a bustling family.", + "You dream of chasing a beautiful butterfly." + ], + "category": "CHIROPTERAN", + "strength": 1 + }, { "type": "dream", "messages": [ @@ -207,6 +217,17 @@ "category": "RABBIT", "strength": 2 }, + { + "type": "dream", + "messages": [ + "You dream of flying.", + "You have an upsetting dream about falling and being unable to get back up.", + "Tinnitus follows you into your dreams, where it becomes a chorus of crickets.", + "You dream of warm breath and fresh blood." + ], + "category": "CHIROPTERAN", + "strength": 2 + }, { "type": "dream", "messages": [ @@ -442,6 +463,17 @@ "category": "BIRD", "strength": 3 }, + { + "type": "dream", + "messages": [ + "You have a nightmare of being all alone, but then your family flies home to comfort you.", + "You dream of sneaking into someone's home to listen to them sleep.", + "You taste iron all night long, like you've bitten your tongue.", + "You dream in sounds and smells, not images." + ], + "category": "CHIROPTERAN", + "strength": 3 + }, { "type": "dream", "messages": [ @@ -721,6 +753,16 @@ "category": "CATTLE", "strength": 4 }, + { + "type": "dream", + "messages": [ + "In your dreams, your fangs slip through flesh like scalpels. You quickly crawl away to let your clumsy prey bleed out.", + "You flutter through the air, listening for echoes to guide you through your dream.", + "You dream of friends and family crowded around, chattering noisily, grooming one another, and sharing blood." + ], + "category": "CHIROPTERAN", + "strength": 4 + }, { "type": "dream", "messages": [ diff --git a/data/json/effects.json b/data/json/effects.json index cf6c36fdae7ef..f9783ea772ffe 100644 --- a/data/json/effects.json +++ b/data/json/effects.json @@ -348,10 +348,10 @@ "type": "effect_type", "id": "sneezing", "name": [ "Sneezing" ], - "desc": [ "Effect to briefly distract you while you sneeze. You should not be able to see this." ], + "rating": "bad", + "desc": [ "It's hard to pay attention to anything when you're in the middle of sneezing!" ], "max_duration": "1 s", - "base_mods": { "speed_mod": [ -20 ], "dex_mod": [ -2 ], "per_mod": [ -4 ] }, - "show_in_info": false + "base_mods": { "speed_mod": [ -20 ], "dex_mod": [ -2 ], "per_mod": [ -4 ] } }, { "type": "effect_type", @@ -1720,6 +1720,31 @@ "rating": "bad", "blood_analysis_description": "Rat Primer Contamination" }, + { + "type": "effect_type", + "id": "mutagen_chiropteran", + "name": [ "Chiropteran Mutation", "Chiropteran Transformation", "Chiropteran Metamorphosis" ], + "desc": [ + "You consumed chiropteran primer.", + "You taste iron, and you want more.", + "Every sound is a painful screech in your ears. It's all too much!." + ], + "max_intensity": 3, + "resist_traits": [ "THRESH_CHIROPTERAN" ], + "base_mods": { + "hurt_min": [ 1 ], + "hurt_max": [ 2 ], + "hurt_chance": [ -22 ], + "hurt_tick": [ 150 ], + "pain_min": [ 1 ], + "pain_max": [ 2 ], + "pain_chance": [ 100 ], + "pain_tick": [ 75 ] + }, + "scaling_mods": { "dex_mod": [ 1 ], "int_mod": [ -2 ], "speed_mod": [ 3.5 ], "hurt_chance": [ 21, 0 ], "pain_chance": [ -30 ] }, + "rating": "bad", + "blood_analysis_description": "Chiropteran Primer Contamination" + }, { "type": "effect_type", "id": "mutagen_slime", @@ -4859,5 +4884,34 @@ "desc": [ "You are descending at a safe speed." ], "flags": [ "FEATHER_FALL" ], "max_duration": "1 s" + }, + { + "type": "effect_type", + "id": "quadruped_full", + "name": [ "" ], + "//": "Allows fully-quadrupedal mutants to run and crouch on all fours. For annoying reasons, this is handled via enchantments." + }, + { + "type": "effect_type", + "id": "quadruped_half", + "name": [ "" ], + "//": "Allows quadrupedal mutants with front paws only to crouch-walk slightly faster than normal. For annoying reasons, this is handled via enchantments." + }, + { + "type": "effect_type", + "id": "natural_stance", + "name": [ "Natural Stance" ], + "rating": "good", + "desc": [ + "You are positioned to take advantage of your mutated anatomy, and will receive no penalties for crouching in melee combat. Wielding a weapon will cause you to lose this effect." + ] + }, + { + "type": "effect_type", + "id": "subaquatic_sonar", + "name": [ "Subaquatic SONAR" ], + "desc": [ + "Every few seconds, an ultrasonic pulse is broadcast from your location. If you're underwater and your hearing is good enough, you may be able to navigate by the pings that come back." + ] } ] diff --git a/data/json/effects_on_condition/bionic_eocs.json b/data/json/effects_on_condition/bionic_eocs.json index 2363e12e6c596..348368ed979da 100644 --- a/data/json/effects_on_condition/bionic_eocs.json +++ b/data/json/effects_on_condition/bionic_eocs.json @@ -141,5 +141,17 @@ "condition": { "u_has_bionics": "bio_leaky" }, "deactivate_condition": { "not": { "u_has_bionics": "bio_leaky" } }, "effect": [ { "u_mod_healthy": -1, "cap": -200 } ] + }, + { + "type": "effect_on_condition", + "id": "EOC_BIO_SONAR_activated", + "condition": { "and": [ { "not": { "u_has_effect": "subaquatic_sonar" } }, { "u_has_bionics": "bio_sonar" } ] }, + "effect": [ { "u_add_effect": "subaquatic_sonar", "duration": "PERMANENT" } ] + }, + { + "type": "effect_on_condition", + "id": "EOC_BIO_SONAR_deactivated", + "condition": { "u_has_effect": "subaquatic_sonar" }, + "effect": [ { "u_lose_effect": "subaquatic_sonar" } ] } ] diff --git a/data/json/effects_on_condition/mutation_eocs/mutation_activation_eocs.json b/data/json/effects_on_condition/mutation_eocs/mutation_activation_eocs.json index 536010ad009bc..ce05576f8e6db 100644 --- a/data/json/effects_on_condition/mutation_eocs/mutation_activation_eocs.json +++ b/data/json/effects_on_condition/mutation_eocs/mutation_activation_eocs.json @@ -10,7 +10,7 @@ "condition": { "and": [ { "expects_vars": [ "prep_time", "spell_to_cast", "message_success", "message_fail" ] }, - { "math": [ "u_val('stamina')", ">", "_energy_amount" ] } + { "math": [ "u_val('stamina')", ">", "energy_amount" ] } ] }, "effect": [ diff --git a/data/json/enchantments.json b/data/json/enchantments.json index 145dbb57f8c26..7434c4fa87ff5 100644 --- a/data/json/enchantments.json +++ b/data/json/enchantments.json @@ -113,5 +113,36 @@ "description": "Your rapidly buzzing wings propel you with extra speed.", "condition": "ALWAYS", "values": [ { "value": "REGEN_STAMINA", "add": -110 } ] + }, + { + "id": "ench_quadruped_movement_full", + "//": "For quadrupeds with all four of their animal limbs. We should avoid giving this to every animal mutant, as it helps keep lines distinct.", + "type": "enchantment", + "condition": { + "and": [ + { "u_has_flag": "QUADRUPED_CROUCH" }, + { "u_has_any_trait": [ "THRESH_RABBIT", "THRESH_BEAST", "THRESH_LUPINE", "THRESH_FELINE" ] }, + { "u_has_flag": "QUADRUPED_RUN" }, + { "or": [ { "u_has_move_mode": "crouch" }, { "u_has_move_mode": "run" } ] }, + { "not": "u_can_drop_weapon" } + ] + }, + "values": [ { "value": "MOVE_COST", "multiply": -0.15 }, { "value": "CARRY_WEIGHT", "multiply": 0.35 } ], + "ench_effects": [ { "effect": "natural_stance", "intensity": 1 } ] + }, + { + "id": "ench_quadruped_movement_half", + "//": "For quadrupeds who only have their front paws. Makes crouch-walking a bit faster, but that's all.", + "type": "enchantment", + "condition": { + "and": [ + { "u_has_flag": "QUADRUPED_CROUCH" }, + { "u_has_any_trait": [ "THRESH_RABBIT", "THRESH_BEAST", "THRESH_LUPINE", "THRESH_FELINE" ] }, + { "not": { "u_has_flag": "QUADRUPED_RUN" } }, + { "u_has_move_mode": "crouch" }, + { "not": "u_can_drop_weapon" } + ] + }, + "values": [ { "value": "MOVE_COST", "multiply": -0.5 } ] } ] diff --git a/data/json/flags.json b/data/json/flags.json index 0074012ad93d0..8fd63478a82d7 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -2397,5 +2397,40 @@ "id": "BLEEDSLOW2", "type": "json_flag", "info": "The character bleeds even slower than normal, losing blood at 1/3rd the normal rate." + }, + { + "id": "PSEUDOPOD_GRASP", + "type": "json_flag", + "//": "Removes some penalties for melee attacks made while prone or crouching." + }, + { + "id": "HEMOVORE", + "type": "json_flag", + "//": "You eat blood to survive." + }, + { + "id": "BLOODFEEDER", + "type": "json_flag", + "//": "You really like blood, and get less enjoyment out of other foods." + }, + { + "id": "HEMOVORE_FUN", + "type": "json_flag", + "//": "This item contains blood and satisfies a hemovore's requirements." + }, + { + "id": "QUADRUPED_CROUCH", + "type": "json_flag", + "//": "This character goes down on all fours when they crouch, if their hands are free. Used for paw mutations." + }, + { + "id": "QUADRUPED_RUN", + "type": "json_flag", + "//": "This character can run or crouch on all fours if they have QUADRUPED_CROUCH, and gains the natural_stance effect. Used for paw mutations." + }, + { + "id": "HEARING_PROTECTION", + "type": "json_flag", + "//": "This character treats received sounds as half as loud for the purposes of determing hearing damage." } ] diff --git a/data/json/harvest_dissect.json b/data/json/harvest_dissect.json index 46e10aa9c4e5c..534efa143ea99 100644 --- a/data/json/harvest_dissect.json +++ b/data/json/harvest_dissect.json @@ -671,6 +671,30 @@ { "drop": "bird_sample_single", "type": "mutagen_group" } ] }, + { + "id": "dissect_chiropteran_sample_single", + "type": "harvest", + "message": "With cuts and pulls equally similar to both extraction and vandalism, you scrape together the most important parts of the creature.", + "entries": [ { "drop": "chiropteran_sample_single", "type": "mutagen_group" } ] + }, + { + "id": "dissect_chiropteran_sample_small", + "type": "harvest", + "message": "With cuts and pulls equally similar to both extraction and vandalism, you scrape together the most important parts of the creature.", + "entries": [ { "drop": "chiropteran_sample_small", "type": "mutagen_group" } ] + }, + { + "id": "dissect_chiropteran_sample_large", + "type": "harvest", + "message": "With cuts and pulls equally similar to both extraction and vandalism, you scrape together the most important parts of the creature.", + "entries": [ { "drop": "chiropteran_sample_large", "type": "mutagen_group" } ] + }, + { + "id": "dissect_chiropteran_sample_huge", + "type": "harvest", + "message": "With cuts and pulls equally similar to both extraction and vandalism, you scrape together the most important parts of the creature.", + "entries": [ { "drop": "chiropteran_sample_huge", "type": "mutagen_group" } ] + }, { "id": "dissect_flying_rodent_small", "type": "harvest", diff --git a/data/json/itemgroups/Labs/labs_mutagen.json b/data/json/itemgroups/Labs/labs_mutagen.json index ca1b88cf662ce..4203e5061df54 100644 --- a/data/json/itemgroups/Labs/labs_mutagen.json +++ b/data/json/itemgroups/Labs/labs_mutagen.json @@ -39,6 +39,7 @@ { "item": "meat", "prob": 40, "count": [ 1, 3 ] }, { "item": "rabbit_sample", "prob": 40, "count": [ 1, 3 ] }, { "item": "rat_sample", "prob": 40, "count": [ 1, 3 ] }, + { "item": "chiropteran_sample", "prob": 40, "count": [ 1, 3 ] }, { "item": "mouse_sample", "prob": 40, "count": [ 1, 3 ] }, { "item": "fish_sample", "prob": 40, "count": [ 1, 3 ] }, { "item": "meat_tainted", "prob": 30, "count": [ 1, 3 ] }, diff --git a/data/json/itemgroups/Monsters_Animals_Lairs/harvest_dissection.json b/data/json/itemgroups/Monsters_Animals_Lairs/harvest_dissection.json index ae1174f7914b4..44e1d19fdd3af 100644 --- a/data/json/itemgroups/Monsters_Animals_Lairs/harvest_dissection.json +++ b/data/json/itemgroups/Monsters_Animals_Lairs/harvest_dissection.json @@ -167,6 +167,30 @@ "subtype": "collection", "entries": [ { "item": "chimera_sample", "count-min": 10, "count-max": 20 } ] }, + { + "id": "chiropteran_sample_single", + "type": "item_group", + "subtype": "collection", + "entries": [ { "item": "chiropteran_sample" } ] + }, + { + "id": "chiropteran_sample_small", + "type": "item_group", + "subtype": "collection", + "entries": [ { "item": "chiropteran_sample", "count-min": 1, "count-max": 3 } ] + }, + { + "id": "chiropteran_sample_large", + "type": "item_group", + "subtype": "collection", + "entries": [ { "item": "chiropteran_sample", "count-min": 3, "count-max": 6 } ] + }, + { + "id": "chiropteran_sample_huge", + "type": "item_group", + "subtype": "collection", + "entries": [ { "item": "chiropteran_sample", "count-min": 10, "count-max": 20 } ] + }, { "id": "elfa_sample_single", "type": "item_group", diff --git a/data/json/itemgroups/bionics.json b/data/json/itemgroups/bionics.json index 01e80b41635c9..6b53d83148341 100644 --- a/data/json/itemgroups/bionics.json +++ b/data/json/itemgroups/bionics.json @@ -93,6 +93,7 @@ [ "bio_ar", 10 ], [ "bio_fitnessband", 10 ], [ "bio_radio", 10 ], + [ "bio_sonar", 10 ], [ "bio_synlungs", 10 ], [ "bio_taser", 10 ] ] @@ -164,6 +165,7 @@ [ "bio_radscrubber", 10 ], [ "bio_ads", 10 ], [ "bio_ods", 10 ], + [ "bio_sonar", 10 ], [ "bio_uncanny_dodge", 10 ], [ "bio_laser", 10 ], [ "bio_emp", 10 ], diff --git a/data/json/itemgroups/science_and_tech.json b/data/json/itemgroups/science_and_tech.json index 821e81a89a726..ec3e9d2848631 100644 --- a/data/json/itemgroups/science_and_tech.json +++ b/data/json/itemgroups/science_and_tech.json @@ -309,6 +309,7 @@ { "item": "iv_mutagen_fish", "prob": 2 }, { "item": "iv_mutagen_slime", "prob": 2 }, { "item": "iv_mutagen_rat", "prob": 2 }, + { "item": "iv_mutagen_chiropteran", "prob": 2 }, { "item": "iv_mutagen_beast", "prob": 2 }, { "item": "iv_mutagen_cattle", "prob": 2 }, { "item": "iv_mutagen_cephalopod", "prob": 2 }, @@ -364,6 +365,7 @@ { "item": "iv_mutagen_fish", "prob": 2, "count": [ 4, 5 ] }, { "item": "iv_mutagen_slime", "prob": 2, "count": [ 4, 5 ] }, { "item": "iv_mutagen_rat", "prob": 2, "count": [ 4, 5 ] }, + { "item": "iv_mutagen_chiropteran", "prob": 2, "count": [ 4, 5 ] }, { "item": "iv_mutagen_beast", "prob": 2, "count": [ 4, 5 ] }, { "item": "iv_mutagen_cattle", "prob": 2, "count": [ 4, 5 ] }, { "item": "iv_mutagen_cephalopod", "prob": 2, "count": [ 4, 5 ] }, @@ -405,6 +407,7 @@ { "item": "mutagen_fish", "count": [ 7, 11 ], "prob": 2 }, { "item": "mutagen_slime", "count": [ 7, 11 ], "prob": 2 }, { "item": "mutagen_rat", "count": [ 7, 11 ], "prob": 2 }, + { "item": "mutagen_chiropteran", "count": [ 7, 11 ], "prob": 2 }, { "item": "mutagen_beast", "count": [ 7, 11 ], "prob": 2 }, { "item": "mutagen_cattle", "count": [ 7, 11 ], "prob": 2 }, { "item": "mutagen_cephalopod", "count": [ 7, 11 ], "prob": 2 }, diff --git a/data/json/itemgroups/supplies.json b/data/json/itemgroups/supplies.json index 151eec6439a30..2675b4feb5e88 100644 --- a/data/json/itemgroups/supplies.json +++ b/data/json/itemgroups/supplies.json @@ -532,6 +532,7 @@ { "item": "mouse_sample", "prob": 40, "count": [ 1, 3 ] }, { "item": "rat_sample", "prob": 40, "count": [ 1, 3 ] }, { "item": "fish_sample", "prob": 40, "count": [ 1, 3 ] }, + { "item": "chiropteran_sample", "prob": 40, "count": [ 1, 3 ] }, { "item": "meat_tainted", "prob": 30, "count": [ 1, 3 ] }, { "item": "brain", "prob": 10, "count": [ 4, 12 ] }, { "item": "rabbit_sample", "prob": 10, "count": [ 1, 3 ] }, diff --git a/data/json/items/bionics.json b/data/json/items/bionics.json index 66171a81bf6dc..596662ca55537 100644 --- a/data/json/items/bionics.json +++ b/data/json/items/bionics.json @@ -310,6 +310,18 @@ "weight": "500 g", "difficulty": 6 }, + { + "id": "bio_sonar", + "copy-from": "bionic_general", + "type": "BIONIC_ITEM", + "name": { "str": "Subaquatic Navigation System CBM" }, + "looks_like": "bio_int_enhancer", + "description": "A tiny device implanted in the inner ear. When active, it will periodically generate ultrasonic pulses which aid in navigation, provided the user is underwater and able to hear.", + "price": 250000, + "price_postapoc": 1250, + "weight": "50 g", + "difficulty": 4 + }, { "id": "bio_emp", "copy-from": "bionic_general", diff --git a/data/json/items/comestibles/carnivore.json b/data/json/items/comestibles/carnivore.json index d413bf598db52..cc27acb772861 100644 --- a/data/json/items/comestibles/carnivore.json +++ b/data/json/items/comestibles/carnivore.json @@ -1308,7 +1308,7 @@ "comestible_type": "DRINK", "symbol": "~", "price_postapoc": 10, - "description": "Blood, possibly that of a human. Disgusting!", + "description": "Blood extracted from a human being.", "price": 0, "material": [ "hblood" ], "volume": "250 ml", @@ -1480,7 +1480,7 @@ "type": "COMESTIBLE", "copy-from": "meat_tainted", "name": { "str_sp": "tainted blood" }, - "description": "Blood that's obviously unhealthy. You could eat it, but it will poison you.", + "description": "Blood that's obviously unhealthy. You could drink it, but it will poison you.", "comestible_type": "DRINK", "looks_like": "blood", "symbol": "~", diff --git a/data/json/items/comestibles/mutagen.json b/data/json/items/comestibles/mutagen.json index a0671ab35a027..d347db7a0ea69 100644 --- a/data/json/items/comestibles/mutagen.json +++ b/data/json/items/comestibles/mutagen.json @@ -311,6 +311,21 @@ "vitamins": [ [ "mutagen_rat", 450, 550 ] ] } }, + { + "id": "iv_mutagen_chiropteran", + "copy-from": "iv_mutagen_flavor", + "type": "COMESTIBLE", + "name": { "str_sp": "chiropteran mutagenic primer" }, + "description": "A processed mutagenic primer, black as night.", + "looks_like": "iv_mutagen", + "color": "black", + "use_action": { + "type": "consume_drug", + "activation_message": "You inject the chiropteran mutagenic primer.", + "tools_needed": { "syringe": -1 }, + "vitamins": [ [ "mutagen_chiropteran", 450, 550 ] ] + } + }, { "id": "iv_mutagen_slime", "copy-from": "iv_mutagen_flavor", @@ -675,6 +690,19 @@ "vitamins": [ [ "mutagen_rat", 225 ], [ "mutagen", 125 ] ] } }, + { + "id": "mutagen_chiropteran", + "copy-from": "mutagen_flavor", + "type": "COMESTIBLE", + "name": { "str_sp": "chiropteran mutagen" }, + "description": "A murky black liquid that smells of blood.", + "looks_like": "mutagen", + "use_action": { + "type": "consume_drug", + "activation_message": "You drink the chiropteran mutagen.", + "vitamins": [ [ "mutagen_chiropteran", 225 ], [ "mutagen", 125 ] ] + } + }, { "id": "mutagen_slime", "copy-from": "mutagen_flavor", diff --git a/data/json/items/mutagen_ingredients.json b/data/json/items/mutagen_ingredients.json index 97350073d2d2b..36b7276af8df3 100644 --- a/data/json/items/mutagen_ingredients.json +++ b/data/json/items/mutagen_ingredients.json @@ -272,5 +272,15 @@ "description": "A slurry of toughness.", "looks_like": "medical_sample", "material": [ "flesh", "chitin" ] + }, + { + "type": "GENERIC", + "id": "chiropteran_sample", + "copy-from": "mutagen_sample", + "color": "brown", + "name": { "str": "chiropteran sample" }, + "description": "A slurry of silence.", + "looks_like": "medical_sample", + "material": [ "bone", "blood" ] } ] diff --git a/data/json/monsters/mammal.json b/data/json/monsters/mammal.json index bb1931793f326..a3fe76f268a39 100644 --- a/data/json/monsters/mammal.json +++ b/data/json/monsters/mammal.json @@ -57,7 +57,7 @@ "melee_damage": [ { "damage_type": "cut", "amount": 1 } ], "dodge": 8, "harvest": "mammal_tiny", - "dissect": "dissect_beast_sample_single", + "dissect": "dissect_chiropteran_sample_single", "families": [ "prof_intro_biology", "prof_physiology", "prof_wp_flying" ], "vision_day": 20, "vision_night": 20, diff --git a/data/json/mutations/mutation_category.json b/data/json/mutations/mutation_category.json index 3c154646528c8..8ee8ebe23faf4 100644 --- a/data/json/mutations/mutation_category.json +++ b/data/json/mutations/mutation_category.json @@ -286,6 +286,17 @@ "base_removal_chance": 33, "base_removal_cost_mul": 2.5 }, + { + "type": "mutation_category", + "id": "CHIROPTERAN", + "name": "Chiropteran", + "threshold_mut": "THRESH_CHIROPTERAN", + "mutagen_message": "Your ears ring and you taste iron.", + "memorial_message": "Became the night.", + "vitamin": "mutagen_chiropteran", + "base_removal_chance": 33, + "base_removal_cost_mul": 2.5 + }, { "type": "mutation_category", "id": "MYCUS", diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index d252de334cbcc..ab235f56383a3 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -138,6 +138,7 @@ "HIBERNATE", "PROJUNK", "QUICK", + "ANTIWHEAT", "SAPROVORE", "PICKYEATER" ], @@ -152,7 +153,7 @@ "dummy": true, "category": [ "HUMAN" ], "types": [ "ATTRACTIVENESS", "MUZZLE", "TEETH", "TONGUE" ], - "cancels": [ "SLIT_NOSTRILS" ], + "cancels": [ "SLIT_NOSTRILS", "LEAFNOSE" ], "description": "You have a human mouth with human teeth." }, { @@ -476,9 +477,67 @@ "description": "Your hearing is better than average, and you can hear distant sounds more easily.", "starting_trait": true, "types": [ "HEARING" ], - "category": [ "ALPHA", "MOUSE", "ELFA", "RABBIT" ], + "changes_to": [ "BATEARS" ], + "category": [ "ALPHA", "MOUSE", "ELFA", "RABBIT", "CHIROPTERAN" ], "hearing_modifier": 1.25 }, + { + "type": "mutation", + "id": "BATEARS", + "name": { "str": "Bat Ears" }, + "points": 1, + "ugliness": 8, + "visibility": 8, + "description": "Your broad, pointed ears are like radar dishes. You can hear even the slightest sounds at great distance, and are less likely to be deafened by loud noises.", + "types": [ "HEARING" ], + "//": "Super_hearing multiplies hearing by 3.5 and let you crack safes. A bat mutant is a bit better at hearing overall than someone with GOODHEARING and a CBM.", + "flags": [ "HEARING_PROTECTION", "SUPER_HEARING" ], + "prereqs": [ "GOODHEARING" ], + "category": [ "CHIROPTERAN" ], + "hearing_modifier": 1.8 + }, + { + "type": "mutation", + "id": "ECHOLOCATION", + "name": { "str": "Echolocation" }, + "points": 3, + "purifiable": false, + "description": "You've learned how to hunt without sight. Activate this mutation to make a quiet chirp that can reveal obstacles and enemies by its echo.", + "prereqs": [ "BATEARS" ], + "threshreq": [ "THRESH_CHIROPTERAN" ], + "category": [ "CHIROPTERAN" ], + "active": true + }, + { + "type": "mutation", + "id": "LEAFNOSE", + "name": { "str": "Leaf Nose" }, + "points": 2, + "prereqs": [ "SLIT_NOSTRILS", "BLOODFEEDER" ], + "flags": [ "INFRARED" ], + "category": [ "CHIROPTERAN" ], + "ugliness": 3, + "description": "Your nose is upturned, ridged and flared out into a leaf shape that humans will likely find unsightly. On the plus side, thermoreceptors in your nostrils allow you to smell heat as long as you can breathe.", + "triggers": [ + [ + { + "condition": { + "not": { + "or": [ + { "u_has_effect": "smoke", "bodypart": "mouth" }, + { "u_has_effect": "asthma" }, + { "u_has_effect": "tpollen" }, + { "u_has_effect": "asthma" }, + { "u_has_effect": "hay_fever" }, + "u_is_underwater" + ] + } + }, + "msg_on": { "text": "", "rating": "good" } + } + ] + ] + }, { "type": "mutation", "id": "FEYHEARING", @@ -531,7 +590,7 @@ "starting_trait": true, "types": [ "CARDIO" ], "changes_to": [ "GOODCARDIO2" ], - "category": [ "FISH", "LUPINE", "MOUSE", "INSECT", "RABBIT" ], + "category": [ "FISH", "LUPINE", "MOUSE", "INSECT", "RABBIT", "CHIROPTERAN" ], "cardio_multiplier": 1.3 }, { @@ -553,7 +612,7 @@ "points": 3, "description": "You're just generally quick! You get a 10% bonus to action points.", "starting_trait": true, - "category": [ "FISH", "BIRD", "INSECT", "TROGLOBITE", "CHIMERA", "RAPTOR", "MOUSE", "RABBIT" ], + "category": [ "FISH", "BIRD", "INSECT", "TROGLOBITE", "CHIMERA", "RAPTOR", "MOUSE", "RABBIT", "CHIROPTERAN" ], "enchantments": [ { "condition": "ALWAYS", "values": [ { "value": "SPEED", "multiply": 0.1 } ] } ] }, { @@ -639,7 +698,7 @@ "cancels": [ "MET_RAT" ], "types": [ "METABOLISM" ], "changes_to": [ "GIZZARD" ], - "category": [ "FISH", "BIRD", "TROGLOBITE", "GASTROPOD", "CEPHALOPOD", "RAPTOR" ], + "category": [ "FISH", "BIRD", "TROGLOBITE", "CHIROPTERAN", "GASTROPOD", "CEPHALOPOD", "RAPTOR" ], "metabolism_modifier": -0.333 }, { @@ -1024,7 +1083,7 @@ "description": "It's very unlikely that you will catch ambient diseases like the cold or flu.", "starting_trait": true, "changes_to": [ "DISIMMUNE" ], - "category": [ "CATTLE", "RAT", "MEDICAL", "PLANT", "SLIME", "TROGLOBITE", "CHIMERA" ] + "category": [ "CATTLE", "RAT", "MEDICAL", "PLANT", "SLIME", "TROGLOBITE", "CHIMERA", "CHIROPTERAN" ] }, { "type": "mutation", @@ -1103,7 +1162,7 @@ "description": "You make less noise while walking. You're also less likely to set off traps.", "starting_trait": true, "cancels": [ "CLUMSY" ], - "category": [ "BIRD", "ELFA", "FELINE" ], + "category": [ "BIRD", "ELFA", "FELINE", "CHIROPTERAN" ], "noise_modifier": 0.4 }, { @@ -1376,7 +1435,7 @@ "description": "Without glasses, your seeing radius is severely reduced! However, you are guaranteed to start with a pair of glasses.", "starting_trait": true, "cancels": [ "URSINE_EYE" ], - "category": [ "BEAST", "TROGLOBITE" ], + "category": [ "BEAST" ], "flags": [ "MYOPIC" ] }, { @@ -1587,6 +1646,7 @@ "points": -1, "description": "Your skin is fragile. Cutting and bashing damage is slightly increased for you.", "types": [ "ARMOR" ], + "category": [ "CHIROPTERAN" ], "armor": [ { "part_types": [ "torso", "head", "arm", "hand", "leg", "foot", "mouth", "tail" ], "cut": -1, "bash": -1 } ] }, { @@ -1638,7 +1698,7 @@ "starting_trait": true, "cancels": [ "PROJUNK" ], "vitamins_absorb_multi": [ [ "junk", [ [ "vitC", 0 ], [ "calcium", 0 ], [ "iron", 0 ] ] ] ], - "category": [ "RAPTOR", "ALPHA", "ELFA", "RABBIT", "GASTROPOD" ] + "category": [ "RAPTOR", "ALPHA", "ELFA", "RABBIT", "GASTROPOD", "CHIROPTERAN" ] }, { "type": "mutation", @@ -1647,7 +1707,8 @@ "points": -2, "description": "You have a rare allergy that prevents you from eating wheat. It's possible for you to eat wheat-based products, but you will suffer morale penalties and obtain less nutrition from them.", "vitamins_absorb_multi": [ [ "wheat", [ [ "vitC", 0 ], [ "calcium", 0 ], [ "iron", 0 ] ] ] ], - "starting_trait": true + "starting_trait": true, + "category": [ "CHIROPTERAN" ] }, { "type": "mutation", @@ -1948,7 +2009,8 @@ "RAT", "CHIMERA", "SPIDER", - "CRUSTACEAN" + "CRUSTACEAN", + "CHIROPTERAN" ], "cancels": [ "VANITY" ] }, @@ -1973,7 +2035,7 @@ "starting_trait": true, "social_modifiers": { "intimidate": -2 }, "types": [ "DURABILITY" ], - "category": [ "MOUSE", "ELFA", "RABBIT" ], + "category": [ "MOUSE", "ELFA", "RABBIT", "CHIROPTERAN" ], "changes_to": [ "FLIMSY2" ], "cancels": [ "TOUGH", "TOUGH2", "TOUGH3" ], "hp_modifier": -0.25 @@ -2063,7 +2125,7 @@ "description": "Your body hair is growing in thicker than it used to. It's almost like you're going through a second puberty or something.", "types": [ "SKIN", "BODY_ARMOR", "ARMOR", "BODY_ARMOR_MOD" ], "changes_to": [ "LIGHTFUR" ], - "category": [ "MOUSE", "BEAST", "CATTLE", "RAT", "FELINE", "LUPINE", "RABBIT", "URSINE" ] + "category": [ "MOUSE", "BEAST", "CATTLE", "RAT", "FELINE", "LUPINE", "RABBIT", "URSINE", "CHIROPTERAN" ] }, { "type": "mutation", @@ -2235,12 +2297,23 @@ "points": 1, "description": "Your visual processing has shifted: though you can see better in the dark, you're nearsighted in the light. Maybe glasses would help. Activate to toggle NV-visible areas on or off.", "types": [ "EYES", "VISION" ], - "cancels": [ "MYOPIC" ], + "cancels": [ "MYOPIC", "MESOPIC" ], "category": [ "URSINE" ], "flags": [ "MYOPIC_IN_LIGHT" ], "active": true, "starts_active": true }, + { + "type": "mutation", + "id": "MESOPIC", + "name": { "str": "Mesopic" }, + "points": -1, + "description": "You find it difficult to see very far in bright light. On its own, this doesn't necessarily make you any better in the dark.", + "types": [ "EYES", "VISION" ], + "cancels": [ "MYOPIC" ], + "category": [ "CHIROPTERAN", "TROGLOBITE" ], + "flags": [ "MYOPIC_IN_LIGHT" ] + }, { "type": "mutation", "id": "BIRD_EYE", @@ -2370,8 +2443,8 @@ "ugliness": 2, "description": "Your teeth have grown into two-inch-long fangs, allowing you to make an extra attack when conditions favor it.", "types": [ "TEETH" ], - "changes_to": [ "SABER_TEETH", "SHARKTEETH" ], - "category": [ "LIZARD", "FISH", "LUPINE", "FELINE", "CHIMERA" ], + "changes_to": [ "SABER_TEETH", "SHARKTEETH", "FANGS_VAMPIRE" ], + "category": [ "LIZARD", "FISH", "LUPINE", "FELINE", "CHIMERA", "CHIROPTERAN" ], "attacks": [ { "attack_text_u": "You sink your fangs into %s!", @@ -2427,6 +2500,26 @@ "base_damage": [ { "damage_type": "cut", "amount": 3 }, { "damage_type": "bash", "amount": 3 } ] } }, + { + "type": "mutation", + "id": "FANGS_VAMPIRE", + "name": { "str": "Vampire Fangs" }, + "points": 2, + "visibility": 3, + "ugliness": 3, + "description": "Your teeth are so sharp, you can use them to shave the fur from your victims before you feed. What's more, anticoagulants in your saliva will keep their blood flowing long after it should have clotted.", + "types": [ "TEETH" ], + "prereqs": [ "FANGS" ], + "threshreq": [ "THRESH_CHIROPTERAN" ], + "category": [ "CHIROPTERAN" ], + "attacks": { + "attack_text_u": "You sink your fangs into %s!", + "attack_text_npc": "%1$s sinks their fangs into %2$s!", + "body_part": "mouth", + "chance": 18, + "base_damage": [ { "damage_type": "cut", "amount": 3 }, { "damage_type": "bash", "amount": 2 } ] + } + }, { "type": "mutation", "id": "MEMBRANE", @@ -2452,7 +2545,7 @@ "category": [ "BATRACHIAN" ], "flags": [ "EYE_MEMBRANE", "SEESLEEP", "MYOPIC_IN_LIGHT" ], "types": [ "EYES", "VISION" ], - "cancels": [ "MEMBRANE", "MYOPIC", "URSINE_EYE" ], + "cancels": [ "MEMBRANE", "MYOPIC", "URSINE_EYE", "MESOPIC" ], "threshreq": [ "THRESH_BATRACHIAN" ], "wet_protection": [ { "part": "eyes", "neutral": 1 } ], "armor": [ { "parts": "eyes", "cut": 3, "bash": 1 } ], @@ -2690,7 +2783,7 @@ "mixed_effect": true, "description": "Your bones are very light. This enables you to move and attack 10% faster, but also reduces your carrying weight by 20% and makes bashing attacks hurt a little more.", "types": [ "BONES" ], - "category": [ "MOUSE", "RABBIT", "BIRD", "SLIME", "ELFA", "SPIDER" ], + "category": [ "MOUSE", "RABBIT", "BIRD", "SLIME", "ELFA", "SPIDER", "CHIROPTERAN" ], "changes_to": [ "HOLLOW_BONES" ], "movecost_modifier": 0.9, "attackcost_modifier": 0.9, @@ -2736,7 +2829,7 @@ "ugliness": 2, "bodytemp_sleep": 75, "description": "Light fur has grown to cover your entire body, providing marginal protection against attacks and slight protection from cold.", - "category": [ "MOUSE", "BEAST", "RAT", "LUPINE", "URSINE", "FELINE", "RABBIT", "CATTLE" ], + "category": [ "MOUSE", "BEAST", "RAT", "LUPINE", "URSINE", "FELINE", "RABBIT", "CATTLE", "CHIROPTERAN" ], "types": [ "SKIN" ], "prereqs": [ "HIRSUTE" ], "changes_to": [ "FUR", "FELINE_FUR", "LUPINE_FUR", "RABBIT_FUR", "LUPINE_FUR_SUMMER" ], @@ -3789,6 +3882,7 @@ "//": "Didn't integrate-ize tentacle rakes because they are hardcoded, waiting for limb rework.", "description": "Your upper tentacles have grown large, hook-barbed rakes on the ends. They're quite vicious, but really aren't suited for fine manipulation.", "encumbrance_always": [ [ "hand_l", 20 ], [ "hand_r", 20 ] ], + "flags": [ "PSEUDOPOD_GRASP" ], "prereqs": [ "ARM_TENTACLES", "ARM_TENTACLES_4", "ARM_TENTACLES_8" ], "threshreq": [ "THRESH_CEPHALOPOD" ], "category": [ "CEPHALOPOD" ] @@ -3975,10 +4069,10 @@ "name": { "str": "Mammal Pheromones" }, "points": 2, "description": "Your body produces low-level pheromones which put mammals at ease. They will be less likely to attack or flee from you.", - "prereqs": [ "SMELLY2" ], + "prereqs": [ "SMELLY2", "LEGS_BAT" ], "types": [ "PHEROMONE" ], - "category": [ "BEAST", "CATTLE" ], - "threshreq": [ "THRESH_BEAST", "THRESH_CATTLE" ] + "category": [ "BEAST", "CATTLE", "CHIROPTERAN" ], + "threshreq": [ "THRESH_BEAST", "THRESH_CATTLE", "THRESH_CHIROPTERAN" ] }, { "type": "mutation", @@ -4050,6 +4144,7 @@ "description": "Your body produces a potent venom. Cutting or stabbing attacks from mutations have a chance to poison your target.", "prereqs": [ "POISRESIST" ], "changes_to": [ "POISONOUS2" ], + "flags": [ "VENOM1" ], "category": [ "SLIME", "TROGLOBITE", "SPIDER", "CEPHALOPOD", "GASTROPOD", "CHIMERA", "BATRACHIAN" ] }, { @@ -4114,13 +4209,14 @@ "visibility": 2, "ugliness": 2, "mixed_effect": true, - "description": "Your pseudopod-like limbs can fit into anything! +4 Dexterity, -4 Strength.", + "description": "Your pseudopod-like limbs can fit into anything! You also suffer reduced penalties to attacking while prone. +4 Dexterity, -4 Strength.", "purifiable": false, "prereqs": [ "BENDY2" ], "prereqs2": [ "AMORPHOUS" ], "cancels": [ "HUMAN_ARMS", "HUMAN_LEGS" ], "threshreq": [ "THRESH_SLIME" ], "category": [ "SLIME" ], + "flags": [ "PSEUDOPOD_GRASP" ], "passive_mods": { "dex_mod": 4, "str_mod": -4 }, "hp_adjustment": 6 }, @@ -4215,6 +4311,66 @@ "movecost_modifier": 0.88, "category": [ "BATRACHIAN", "RABBIT", "FELINE", "LUPINE", "SPIDER" ] }, + { + "type": "mutation", + "id": "LEGS_BAT", + "name": { "str": "Bow-legged" }, + "points": -1, + "mixed_effect": true, + "visibility": 2, + "ugliness": 2, + "description": "Your lower limbs have shortened and splayed, slowing your bipedal movement. As long as you're not wielding anything and you've got both wings, you're able to crawl quickly and quietly when you run or crouch.", + "types": [ "LEGS" ], + "prereqs": [ "PADDED_FEET", "WINGS_BAT" ], + "category": [ "CHIROPTERAN" ], + "threshreq": [ "THRESH_CHIROPTERAN" ], + "movecost_modifier": 1.38, + "wet_protection": [ { "part": "foot_l", "neutral": 10 }, { "part": "foot_r", "neutral": 10 } ], + "//": "Uses bespoke stuff here rather than the quadruped enchantments as bat-crawling gives different buffs.", + "triggers": [ + [ + { + "condition": { + "and": [ + { "or": [ { "u_has_move_mode": "run" }, { "u_has_move_mode": "crouch" } ] }, + { "not": "u_can_drop_weapon" }, + { "u_has_trait": "WINGS_BAT" } + ] + }, + "msg_on": { "text": "You hunch forward to crawl quickly on folded wings." }, + "msg_off": { "text": "You rise up to walk like a human." } + } + ] + ], + "enchantments": [ + { + "condition": { "and": [ { "u_has_move_mode": "crouch" }, { "not": "u_can_drop_weapon" }, { "u_has_trait": "WINGS_BAT" } ] }, + "values": [ { "value": "MOVE_COST", "multiply": -0.58 }, { "value": "FOOTSTEP_NOISE", "multiply": 0 } ], + "ench_effects": [ { "effect": "natural_stance", "intensity": 1 } ] + }, + { + "condition": { "and": [ { "u_has_move_mode": "run" }, { "not": "u_can_drop_weapon" }, { "u_has_trait": "WINGS_BAT" } ] }, + "values": [ { "value": "MOVE_COST", "multiply": -0.2 }, { "value": "FOOTSTEP_NOISE", "multiply": -0.6 } ], + "ench_effects": [ { "effect": "natural_stance", "intensity": 1 } ] + } + ] + }, + { + "type": "mutation", + "id": "HOOKED_TOES", + "name": { "str": "Hooked Toes" }, + "points": 2, + "visibility": 2, + "ugliness": 2, + "description": "Your feet have grown into strong, curved claws. They won't fit into normal shoes and are not much help in combat, but they allow you to climb most vertical surfaces with ease. You can even cling to walls you glide into!", + "types": [ "FEET" ], + "prereqs": [ "LEGS_BAT" ], + "category": [ "CHIROPTERAN" ], + "threshreq": [ "THRESH_CHIROPTERAN" ], + "flags": [ "WALL_CLING" ], + "restricts_gear": [ "foot_l", "foot_r" ], + "destroys_gear": true + }, { "type": "mutation", "id": "ANIMAL_FEET", @@ -4227,67 +4383,35 @@ "prereqs": [ "PADDED_FEET" ], "category": [ "LUPINE", "FELINE", "BEAST", "RABBIT" ], "changes_to": [ "RABBIT_FEET" ], + "flags": [ "QUADRUPED_RUN" ], "wet_protection": [ { "part": "foot_l", "neutral": 10 }, { "part": "foot_r", "neutral": 10 } ], "restricts_gear": [ "foot_l", "foot_r" ], "destroys_gear": true, - "weight_capacity_modifier": 0.8, "triggers": [ [ { "condition": { "and": [ - { "u_has_move_mode": "run" }, + { "or": [ { "u_has_move_mode": "run" }, { "u_has_move_mode": "crouch" } ] }, { "not": "u_can_drop_weapon" }, - { "u_has_any_trait": [ "THRESH_BEAST", "THRESH_FELINE", "THRESH_LUPINE" ] }, - { "u_has_trait": "PAWS" } + { "u_has_any_trait": [ "THRESH_BEAST", "THRESH_LUPINE", "THRESH_FELINE", "THRESH_RABBIT" ] }, + { "u_has_flag": "QUADRUPED_CROUCH" } ] }, "msg_on": { "text": "You drop down on all fours." }, - "msg_off": { "text": "You rise up to walk on your hind feet." } + "msg_off": { "text": "You assume a less bestial posture." } } ] ], "enchantments": [ + "ench_quadruped_movement_full", { - "condition": { - "and": [ - { "u_has_move_mode": "crouch" }, - { "not": "u_can_drop_weapon" }, - { "u_has_any_trait": [ "THRESH_LUPINE", "THRESH_FELINE", "THRESH_BEAST" ] }, - { "u_has_trait": "PAWS" } - ] - }, - "values": [ { "value": "MOVE_COST", "multiply": -0.15 }, { "value": "CARRY_WEIGHT", "multiply": 0.35 } ] - }, - { - "condition": { - "and": [ - { "u_has_move_mode": "run" }, - { "not": "u_can_drop_weapon" }, - { "u_has_any_trait": [ "THRESH_LUPINE", "THRESH_FELINE", "THRESH_BEAST" ] }, - { "u_has_trait": "PAWS" } - ] - }, - "values": [ { "value": "MOVE_COST", "multiply": -0.15 }, { "value": "CARRY_WEIGHT", "multiply": 0.35 } ] - }, - { - "condition": { - "or": [ - "u_can_drop_weapon", - { "u_has_move_mode": "walk" }, - { - "and": [ - { "not": { "u_has_trait": "THRESH_LUPINE" } }, - { "not": { "u_has_trait": "THRESH_FELINE" } }, - { "not": { "u_has_trait": "THRESH_BEAST" } } - ] - }, - { "not": { "u_has_trait": "PAWS" } } - ] - }, - "values": [ { "value": "MOVE_COST", "multiply": -0.1 } ] + "condition": { "and": [ { "u_has_move_mode": "crouch" }, { "not": "u_can_drop_weapon" }, { "u_has_flag": "QUADRUPED_CROUCH" } ] }, + "values": [ { "value": "MOVE_COST", "multiply": -0.35 } ], + "ench_effects": [ { "effect": "natural_stance", "intensity": 1 } ] } - ] + ], + "weight_capacity_modifier": 0.8 }, { "type": "mutation", @@ -5286,7 +5410,8 @@ "prereqs2": [ "HOLLOW_BONES" ], "threshreq": [ "THRESH_BIRD" ], "category": [ "BIRD" ], - "flags": [ "WINGS_2" ] + "restricts_gear": [ "arm_l", "arm_r", "hand_l", "hand_r" ], + "flags": [ "WINGS_2", "WING_GLIDE", "ARM_WINGS" ] }, { "type": "mutation", @@ -5836,6 +5961,7 @@ "changes_to": [ "DEX_UP_2" ], "category": [ "INSECT", + "CHIROPTERAN", "ALPHA", "LIZARD", "SPIDER", @@ -5860,7 +5986,21 @@ "types": [ "DEX" ], "prereqs": [ "DEX_UP" ], "changes_to": [ "DEX_UP_3", "DEX_ALPHA" ], - "category": [ "LIZARD", "SPIDER", "CHIMERA", "RAPTOR", "MOUSE", "RABBIT", "BIRD", "ELFA", "FELINE", "CEPHALOPOD", "FISH", "ALPHA" ], + "category": [ + "LIZARD", + "SPIDER", + "CHIMERA", + "RAPTOR", + "MOUSE", + "RABBIT", + "BIRD", + "ELFA", + "FELINE", + "CEPHALOPOD", + "FISH", + "ALPHA", + "CHIROPTERAN" + ], "passive_mods": { "dex_mod": 2 } }, { @@ -5872,8 +6012,8 @@ "types": [ "DEX" ], "prereqs": [ "DEX_UP_2" ], "changes_to": [ "DEX_UP_4" ], - "category": [ "BIRD", "ELFA", "FELINE", "CEPHALOPOD", "FISH" ], - "threshreq": [ "THRESH_BIRD", "THRESH_ELFA", "THRESH_FELINE", "THRESH_CEPHALOPOD", "THRESH_FISH" ], + "category": [ "BIRD", "ELFA", "FELINE", "CEPHALOPOD", "FISH", "CHIROPTERAN" ], + "threshreq": [ "THRESH_BIRD", "THRESH_ELFA", "THRESH_FELINE", "THRESH_CEPHALOPOD", "THRESH_FISH", "THRESH_CHIROPTERAN" ], "passive_mods": { "dex_mod": 4 } }, { @@ -6233,7 +6373,8 @@ "ugliness": 4, "description": "You have a flattened nose and thin slits for nostrils, giving you a lizard-like appearance. This makes breathing slightly difficult and increases mouth encumbrance by 10.", "encumbrance_always": [ [ "mouth", 10 ] ], - "category": [ "LIZARD", "CEPHALOPOD", "RAPTOR" ] + "changes_to": [ "LEAFNOSE" ], + "category": [ "LIZARD", "CEPHALOPOD", "RAPTOR", "CHIROPTERAN" ] }, { "type": "mutation", @@ -6359,22 +6500,25 @@ "ugliness": 2, "description": "You have a pair of stubby little wings projecting from your shoulderblades. They can be wiggled at will, but are useless.", "types": [ "WINGS" ], - "changes_to": [ "WINGS_INSECT", "WINGS_BUTTERFLY", "WINGS_BAT" ], - "category": [ "INSECT", "BEAST", "BIRD" ] + "changes_to": [ "WINGS_INSECT", "WINGS_BUTTERFLY" ], + "category": [ "INSECT", "BIRD" ] }, { "type": "mutation", "id": "WINGS_BAT", "name": { "str": "Bat Wings" }, - "points": -5, + "points": 4, "visibility": 9, "ugliness": 4, - "description": "You have a pair of large, leathery wings. You can move them a little, but they are useless, and in fact put you off balance, reducing your ability to dodge slightly.", - "types": [ "WINGS" ], - "prereqs": [ "WINGS_STUB" ], - "category": [ "BEAST" ], - "threshreq": [ "THRESH_BEAST" ], - "dodge_modifier": -2 + "mixed_effect": true, + "description": "Most of your fingers have grown to tremendous length, becoming a broad pair of leathery wings. This allows you to arrest a fall or glide from a ledge if you aren't too weighed down, but naturally impedes your fine motor skills. They even keep you warm when you sleep.", + "types": [ "ARMS", "HANDS" ], + "flags": [ "WING_GLIDE", "WINGS_2", "ARM_WINGS" ], + "encumbrance_always": [ [ "arm_r", 20 ], [ "arm_l", 20 ], [ "hand_r", 40 ], [ "hand_l", 40 ] ], + "prereqs": [ "WEBBED" ], + "category": [ "CHIROPTERAN" ], + "restricts_gear": [ "arm_l", "arm_r", "hand_l", "hand_r" ], + "threshreq": [ "THRESH_CHIROPTERAN" ] }, { "type": "mutation", @@ -6460,7 +6604,8 @@ "RAT", "CHIMERA", "SPIDER", - "CRUSTACEAN" + "CRUSTACEAN", + "CHIROPTERAN" ] }, { @@ -6577,7 +6722,7 @@ "visibility": 5, "ugliness": 6, "mixed_effect": true, - "description": "Your face resembles that of a bull, with a significant snout. It looks fearsome but prevents wearing mouthgear.", + "description": "Your face resembles that of a bull, with a significant snout. It looks fearsome but makes it difficult to find gear that covers your face.", "types": [ "MUZZLE" ], "prereqs": [ "SNOUT" ], "category": [ "CATTLE" ], @@ -6673,7 +6818,7 @@ "visibility": 8, "ugliness": 8, "mixed_effect": true, - "description": "Your face and jaws have widened like a frogs. It looks hideous but it allows you to eat food whole.", + "description": "You have an unsettlingly wide mouth, like a frog. This looks hideous, but allows you to swallow your food whole.", "types": [ "MUZZLE" ], "category": [ "BATRACHIAN" ], "wet_protection": [ { "part": "mouth", "good": 6 } ], @@ -6998,7 +7143,7 @@ "types": [ "SUNLIGHT" ], "changes_to": [ "TROGLO2" ], "cancels": [ "SEASONAL_AFFECTIVE" ], - "category": [ "BEAST", "INSECT", "SLIME", "SPIDER", "BATRACHIAN", "RAT", "TROGLOBITE" ] + "category": [ "BEAST", "INSECT", "SLIME", "SPIDER", "BATRACHIAN", "RAT", "TROGLOBITE", "CHIROPTERAN" ] }, { "type": "mutation", @@ -7028,11 +7173,13 @@ "points": 0, "visibility": 3, "ugliness": 2, + "mixed_effect": true, "types": [ "HANDS" ], "description": "Your hands are heavily webbed, reducing your Dexterity by 1 and causing problems with gloves. However, you can swim much faster. Slightly decreases wet penalties.", "leads_to": [ "WEBBED_FEET" ], - "category": [ "LIZARD", "FISH", "SLIME", "BATRACHIAN" ], + "category": [ "LIZARD", "FISH", "SLIME", "BATRACHIAN", "CHIROPTERAN" ], "flags": [ "WEBBED_HANDS" ], + "changes_to": [ "WINGS_BAT" ], "wet_protection": [ { "part": "hand_l", "good": 3 }, { "part": "hand_r", "good": 3 } ], "encumbrance_covered": [ [ "hand_l", 50 ], [ "hand_r", 50 ] ], "passive_mods": { "dex_mod": -1 } @@ -7064,39 +7211,26 @@ "types": [ "HANDS" ], "prereqs": [ "NAILS", "CLAWS", "CLAWS_RETRACT", "CLAWS_RAT" ], "cancels": [ "TALONS" ], + "flags": [ "QUADRUPED_CROUCH" ], "changes_to": [ "PAWS_LARGE" ], - "category": [ "LUPINE", "RAT", "FELINE", "BEAST", "URSINE" ], "triggers": [ [ { "condition": { "and": [ { "u_has_move_mode": "crouch" }, + { "u_has_any_trait": [ "THRESH_BEAST", "THRESH_LUPINE", "THRESH_RABBIT", "THRESH_FELINE" ] }, { "not": "u_can_drop_weapon" }, - { - "u_has_any_trait": [ "THRESH_BEAST", "THRESH_FELINE", "THRESH_LUPINE", "THRESH_URSINE", "THRESH_RAT", "THRESH_MOUSE", "THRESH_RABBIT" ] - } + { "not": { "u_has_flag": "QUADRUPED_RUN" } } ] }, "msg_on": { "text": "You drop down on all fours." }, - "msg_off": { "text": "You rise up to walk on your hind feet." } + "msg_off": { "text": "You come out of your quadrupedal posture." } } ] ], - "enchantments": [ - { - "condition": { - "and": [ - { "u_has_move_mode": "crouch" }, - { "not": "u_can_drop_weapon" }, - { - "u_has_any_trait": [ "THRESH_BEAST", "THRESH_FELINE", "THRESH_LUPINE", "THRESH_URSINE", "THRESH_RAT", "THRESH_MOUSE", "THRESH_RABBIT" ] - } - ] - }, - "values": [ { "value": "MOVE_COST", "multiply": -0.5 } ] - } - ] + "enchantments": [ "ench_quadruped_movement_half" ], + "category": [ "LUPINE", "RAT", "FELINE", "BEAST", "URSINE" ] }, { "type": "mutation", @@ -7123,38 +7257,25 @@ "types": [ "HANDS" ], "prereqs": [ "PAWS" ], "cancels": [ "TALONS" ], - "category": [ "BEAST", "URSINE" ], + "flags": [ "QUADRUPED_CROUCH" ], "triggers": [ [ { "condition": { "and": [ { "u_has_move_mode": "crouch" }, + { "u_has_any_trait": [ "THRESH_BEAST", "THRESH_LUPINE", "THRESH_RABBIT", "THRESH_FELINE" ] }, { "not": "u_can_drop_weapon" }, - { - "u_has_any_trait": [ "THRESH_BEAST", "THRESH_FELINE", "THRESH_LUPINE", "THRESH_URSINE", "THRESH_RAT", "THRESH_MOUSE", "THRESH_RABBIT" ] - } + { "not": { "u_has_flag": "QUADRUPED_RUN" } } ] }, "msg_on": { "text": "You drop down on all fours." }, - "msg_off": { "text": "You rise up to walk on your hind feet." } + "msg_off": { "text": "You come out of your quadrupedal posture." } } ] ], - "enchantments": [ - { - "condition": { - "and": [ - { "u_has_move_mode": "crouch" }, - { "not": "u_can_drop_weapon" }, - { - "u_has_any_trait": [ "THRESH_BEAST", "THRESH_FELINE", "THRESH_LUPINE", "THRESH_URSINE", "THRESH_RAT", "THRESH_MOUSE", "THRESH_RABBIT" ] - } - ] - }, - "values": [ { "value": "MOVE_COST", "multiply": -0.5 } ] - } - ] + "enchantments": [ "ench_quadruped_movement_half" ], + "category": [ "BEAST", "URSINE" ] }, { "type": "mutation", @@ -7165,7 +7286,8 @@ "ugliness": 4, "mixed_effect": true, "description": "You have a beak for a mouth. You can occasionally use it to peck at your enemies, but it is impossible for you to wear mouth gear. Slightly reduces wet effects.", - "types": [ "TEETH", "MUZZLE" ], + "types": [ "TEETH" ], + "cancels": [ "MUZZLE", "MUZZLE_RAT", "MUZZLE_BEAR" ], "changes_to": [ "BEAK_HUM", "BEAK_PECK" ], "category": [ "BIRD", "CEPHALOPOD" ], "wet_protection": [ { "part": "mouth", "ignored": 1 } ], @@ -7188,8 +7310,8 @@ "ugliness": 5, "description": "Pecking at prey is part of your daily routine now. Slightly reduces wet effects.", "purifiable": false, - "types": [ "TEETH", "MUZZLE" ], - "cancels": [ "MOUTH_TENTACLES" ], + "types": [ "TEETH" ], + "cancels": [ "MOUTH_TENTACLES", "MUZZLE", "MUZZLE_RAT", "MUZZLE_LONG", "MUZZLE_RAPTOR", "MUZZLE_BEAR" ], "prereqs": [ "BEAK" ], "threshreq": [ "THRESH_BIRD" ], "category": [ "BIRD" ], @@ -7216,7 +7338,7 @@ "consume_time_modifier": 1.8, "description": "Though your beak's not suitable for pecking, those flowers out there are a good source of energy. Examine them to feed.", "purifiable": false, - "types": [ "TEETH", "MUZZLE" ], + "types": [ "TEETH" ], "cancels": [ "MOUTH_TENTACLES" ], "prereqs": [ "BEAK" ], "threshreq": [ "THRESH_BIRD" ], @@ -7400,6 +7522,35 @@ "category": [ "LIZARD", "SPIDER", "CHIMERA", "RAPTOR", "FELINE", "BATRACHIAN", "BEAST", "LUPINE" ], "vitamin_rates": [ [ "vitC", -1200 ] ] }, + { + "type": "mutation", + "id": "HEMOVORE", + "name": { "str": "Hemovore" }, + "points": -4, + "description": "You can still eat other food, but you crave the taste of blood over everything else. Without a steady supply or some kind of iron supplement, you're prone to developing anemia.", + "types": [ "DIET" ], + "flags": [ "HEMOVORE" ], + "cancels": [ "VEGAN" ], + "category": [ "CHIROPTERAN" ], + "changes_to": [ "BLOODFEEDER" ], + "vitamin_rates": [ [ "iron", 1000 ], [ "vitC", -300 ] ] + }, + { + "type": "mutation", + "id": "BLOODFEEDER", + "name": { "str": "Bloodfeeder" }, + "points": -2, + "mixed_effect": true, + "description": "Your craving for blood borders on obsession. You need the stuff too much to care about whether it came from a human, and your body can filter out most of the toxins in mutant blood.", + "types": [ "DIET" ], + "flags": [ "BLOODFEEDER" ], + "cancels": [ "VEGAN" ], + "prereqs": [ "HEMOVORE" ], + "vitamins_absorb_multi": [ [ "blood", [ [ "mutant_toxin", 0.25 ] ] ], [ "flesh", [ [ "mutant_toxin", 0.75 ] ] ] ], + "category": [ "CHIROPTERAN" ], + "threshreq": [ "THRESH_CHIROPTERAN" ], + "vitamin_rates": [ [ "iron", 800 ], [ "vitC", -600 ] ] + }, { "type": "mutation", "id": "PONDEROUS1", @@ -7855,12 +8006,13 @@ "visibility": 7, "ugliness": 4, "mixed_effect": true, - "description": "Your arms have transformed into tentacles, resulting in a +1 bonus to Dexterity, permanent hand encumbrance of 30, and an inability to wear gloves. Somewhat decreases wet penalties.", + "description": "Your arms have transformed into tentacles, resulting in a +1 bonus to Dexterity, permanent hand encumbrance of 30, and an inability to wear gloves. Reduces penalties for attacking while prone and somewhat decreases wet penalties.", "encumbrance_always": [ [ "hand_l", 30 ], [ "hand_r", 30 ] ], "restricts_gear": [ "hand_l", "hand_r" ], "types": [ "HANDS", "CLAWS" ], "leads_to": [ "CLAWS_TENTACLE" ], "changes_to": [ "ARM_TENTACLES_4" ], + "flags": [ "PSEUDOPOD_GRASP" ], "category": [ "CEPHALOPOD" ], "wet_protection": [ { "part": "arm_l", "neutral": 19 }, @@ -7893,7 +8045,7 @@ "points": 0, "visibility": 8, "ugliness": 5, - "description": "Your arms have transformed into four tentacles, resulting in a +1 bonus to Dexterity, permanent hand encumbrance of 30, and an inability to wear gloves. You can make up to 3 extra attacks with them. Somewhat decreases wet penalties.", + "description": "Your arms have transformed into four tentacles, resulting in a +1 bonus to Dexterity, permanent hand encumbrance of 30, and an inability to wear gloves. You can make up to 3 extra attacks with them, and you suffer reduced penalties to attacking while prone. Somewhat decreases wet penalties.", "encumbrance_always": [ [ "hand_l", 30 ], [ "hand_r", 30 ] ], "restricts_gear": [ "hand_l", "hand_r" ], "types": [ "HANDS", "CLAWS" ], @@ -7932,7 +8084,7 @@ "points": 0, "visibility": 9, "ugliness": 6, - "description": "Your arms have transformed into eight tentacles, resulting in a +1 bonus to Dexterity, permanent hand encumbrance of 30, and an inability to wear gloves. You can make up to 7 extra attacks with them. Somewhat decreases wet penalties.", + "description": "Your arms have transformed into eight tentacles, resulting in a +1 bonus to Dexterity, permanent hand encumbrance of 30, and an inability to wear gloves. You can make up to 7 extra attacks with them, and suffer reduced penalties to attacking while prone. Somewhat decreases wet penalties.", "encumbrance_always": [ [ "hand_l", 30 ], [ "hand_r", 30 ] ], "restricts_gear": [ "hand_l", "hand_r" ], "types": [ "HANDS", "CLAWS" ], @@ -8146,7 +8298,6 @@ "name": { "str": "Bear" }, "points": 1, "description": "So the humans died; what's the worry? Now they won't ruin the woods.", - "cancels": [ "CARNIVORE" ], "valid": false, "purifiable": false, "threshold": true @@ -8340,6 +8491,16 @@ "purifiable": false, "threshold": true }, + { + "type": "mutation", + "id": "THRESH_CHIROPTERAN", + "name": { "str": "Chiropteran" }, + "points": 1, + "description": "You long for a colony, the cover of darkness, and a meal on the wing.", + "valid": false, + "purifiable": false, + "threshold": true + }, { "type": "mutation", "id": "ACIDPROOF", @@ -9188,6 +9349,7 @@ "description": "Your feet have grown into strong and large rabbit feet. This makes your kicks pack a little more oomph. Emphasis on little. It also offers some warmth, and the lucky part is but superstition. The downside is you are unable to wear shoes.", "types": [ "FEET" ], "category": [ "RABBIT" ], + "flags": [ "QUADRUPED_RUN" ], "wet_protection": [ { "part": "foot_l", "neutral": 10 }, { "part": "foot_r", "neutral": 10 } ], "restricts_gear": [ "foot_l", "foot_r" ], "destroys_gear": true, @@ -9198,7 +9360,9 @@ "attack_text_npc": "%1$s kicks %2$s with their large feet!", "chance": 15, "strength_damage": { "damage_type": "bash", "amount": 1.5 } - } + }, + "enchantments": [ "ench_quadruped_movement_full" ], + "weight_capacity_modifier": 0.8 }, { "type": "mutation", @@ -9225,38 +9389,25 @@ "types": [ "HANDS" ], "prereqs": [ "NAILS" ], "cancels": [ "TALONS" ], - "category": [ "RABBIT" ], + "flags": [ "QUADRUPED_CROUCH" ], "triggers": [ [ { "condition": { "and": [ { "u_has_move_mode": "crouch" }, + { "u_has_any_trait": [ "THRESH_BEAST", "THRESH_LUPINE", "THRESH_RABBIT", "THRESH_FELINE" ] }, { "not": "u_can_drop_weapon" }, - { - "u_has_any_trait": [ "THRESH_BEAST", "THRESH_FELINE", "THRESH_LUPINE", "THRESH_URSINE", "THRESH_RAT", "THRESH_MOUSE", "THRESH_RABBIT" ] - } + { "not": { "u_has_flag": "QUADRUPED_RUN" } } ] }, "msg_on": { "text": "You drop down on all fours." }, - "msg_off": { "text": "You rise up to walk on your hind feet." } + "msg_off": { "text": "You come out of your quadrupedal posture." } } ] ], - "enchantments": [ - { - "condition": { - "and": [ - { "u_has_move_mode": "crouch" }, - { "not": "u_can_drop_weapon" }, - { - "u_has_any_trait": [ "THRESH_BEAST", "THRESH_FELINE", "THRESH_LUPINE", "THRESH_URSINE", "THRESH_RAT", "THRESH_MOUSE", "THRESH_RABBIT" ] - } - ] - }, - "values": [ { "value": "MOVE_COST", "multiply": -0.5 } ] - } - ] + "enchantments": [ "ench_quadruped_movement_half" ], + "category": [ "RABBIT" ] }, { "type": "mutation", diff --git a/data/json/npcs/exodii/exodii_merchant_itemlist.json b/data/json/npcs/exodii/exodii_merchant_itemlist.json index fdeea36ff8cd9..3afe112f94335 100644 --- a/data/json/npcs/exodii/exodii_merchant_itemlist.json +++ b/data/json/npcs/exodii/exodii_merchant_itemlist.json @@ -238,6 +238,7 @@ [ "bio_infrared", 10 ], [ "bio_lockpick", 10 ], [ "bio_night_vision", 10 ], + [ "bio_sonar", 10 ], [ "bio_power_storage_mkII", 10 ], [ "bio_scent_mask", 10 ], [ "bio_jointservo", 10 ], diff --git a/data/json/recipes/chem/mutagens.json b/data/json/recipes/chem/mutagens.json index 5e643faa6b945..69906fab33c6e 100644 --- a/data/json/recipes/chem/mutagens.json +++ b/data/json/recipes/chem/mutagens.json @@ -426,6 +426,55 @@ "components": [ [ [ "mutagen_rat", 2 ] ], [ [ "rat_sample", 1 ] ] ], "flags": [ "SECRET" ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "mutagen_chiropteran", + "category": "CC_*", + "subcategory": "CSC_*_NESTED", + "skill_used": "chemistry", + "skills_required": [ "firstaid", 1 ], + "difficulty": 7, + "time": "45 m", + "batch_time_factors": [ 80, 20 ], + "book_learn": [ [ "recipe_creepy", 6 ] ], + "proficiencies": [ + { "proficiency": "prof_intro_chemistry" }, + { "proficiency": "prof_organic_chemistry" }, + { "proficiency": "prof_intro_chem_synth" }, + { "proficiency": "prof_chem_synth" } + ], + "using": [ [ "mutagen_production_standard", 25 ] ], + "components": [ + [ [ "mutagen", 1 ] ], + [ [ "chiropteran_sample", 1 ] ], + [ [ "animal_blood", 6 ], [ "mutant_blood", 6 ] ], + [ [ "meal_bone_tainted", 1 ], [ "chiropteran_sample", 1 ] ] + ], + "flags": [ "SECRET" ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "iv_mutagen_chiropteran", + "category": "CC_*", + "subcategory": "CSC_*_NESTED", + "skill_used": "chemistry", + "skills_required": [ "firstaid", 3 ], + "difficulty": 7, + "time": "2 h", + "batch_time_factors": [ 20, 5 ], + "book_learn": [ [ "recipe_serum", 6 ], [ "recipe_creepy", 6 ] ], + "proficiencies": [ + { "proficiency": "prof_intro_chemistry" }, + { "proficiency": "prof_organic_chemistry" }, + { "proficiency": "prof_intro_chem_synth" }, + { "proficiency": "prof_chem_synth" } + ], + "using": [ [ "serum_production_standard", 37 ] ], + "components": [ [ [ "mutagen_chiropteran", 2 ] ], [ [ "chiropteran_sample", 1 ] ] ], + "flags": [ "SECRET" ] + }, { "type": "recipe", "activity_level": "LIGHT_EXERCISE", diff --git a/data/json/recipes/nested.json b/data/json/recipes/nested.json index d4c113946f865..e1b8681eb9f05 100644 --- a/data/json/recipes/nested.json +++ b/data/json/recipes/nested.json @@ -6915,6 +6915,7 @@ "iv_purifier", "iv_mutagen", "iv_mutagen_rat", + "iv_mutagen_chiropteran", "iv_mutagen_fish", "iv_mutagen_bird", "iv_mutagen_mouse", @@ -6955,6 +6956,7 @@ "purifier", "mutagen", "mutagen_rat", + "mutagen_chiropteran", "mutagen_fish", "mutagen_bird", "mutagen_mouse", diff --git a/data/json/traps.json b/data/json/traps.json index 9766db24cc231..2369742a8719a 100644 --- a/data/json/traps.json +++ b/data/json/traps.json @@ -216,6 +216,7 @@ "difficulty": 3, "action": "beartrap", "drops": [ "beartrap" ], + "flags": [ "ECHOLOCATION_DETECTABLE" ], "vehicle_data": { "damage": 300, "sound_volume": 8, @@ -258,6 +259,7 @@ "color": "light_gray", "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a spiked board." }, "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a spiked board." }, + "flags": [ "ECHOLOCATION_DETECTABLE" ], "symbol": "_", "visibility": 1, "avoidance": 6, @@ -318,6 +320,7 @@ "color": "green", "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a crossbow trap." }, "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a crossbow trap." }, + "flags": [ "ECHOLOCATION_DETECTABLE" ], "symbol": "^", "visibility": 5, "avoidance": 4, @@ -343,6 +346,7 @@ "color": "red", "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shotgun trap." }, "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shotgun trap." }, + "flags": [ "ECHOLOCATION_DETECTABLE" ], "symbol": "^", "visibility": 4, "avoidance": 5, @@ -367,6 +371,7 @@ "color": "red", "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shotgun trap." }, "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shotgun trap." }, + "flags": [ "ECHOLOCATION_DETECTABLE" ], "symbol": "^", "visibility": 4, "avoidance": 5, @@ -392,6 +397,7 @@ "color": "red", "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shotgun trap." }, "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shotgun trap." }, + "flags": [ "ECHOLOCATION_DETECTABLE" ], "symbol": "^", "visibility": 4, "avoidance": 5, @@ -414,6 +420,7 @@ "id": "tr_engine", "trigger_weight": "200 g", "name": "spinning blade engine", + "flags": [ "ECHOLOCATION_DETECTABLE" ], "color": "light_red", "symbol": "_", "visibility": 0, @@ -430,6 +437,7 @@ "color": "cyan", "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a blade trap." }, "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a blade trap." }, + "flags": [ "ECHOLOCATION_DETECTABLE" ], "symbol": "\\", "visibility": 0, "avoidance": 4, @@ -445,6 +453,7 @@ "color": "red", "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a land mine." }, "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a land mine." }, + "flags": [ "ECHOLOCATION_DETECTABLE" ], "symbol": "^", "visibility": 1, "avoidance": 14, @@ -521,6 +530,7 @@ "color": "cyan", "memorial_male": { "ctxt": "memorial_male", "str": "Stepped into an exposed high-energy conduit." }, "memorial_female": { "ctxt": "memorial_female", "str": "Stepped into an exposed high-energy conduit." }, + "flags": [ "ECHOLOCATION_DETECTABLE" ], "symbol": "7", "visibility": 2, "avoidance": 20, @@ -550,11 +560,11 @@ "color": "brown", "memorial_male": { "ctxt": "memorial_male", "str": "Fell in a pit." }, "memorial_female": { "ctxt": "memorial_female", "str": "Fell in a pit." }, + "flags": [ "ECHOLOCATION_DETECTABLE", "PIT" ], "symbol": "0", "visibility": 0, "avoidance": 8, "difficulty": 99, - "flags": [ "PIT" ], "action": "pit", "vehicle_data": { "damage": 500 } }, @@ -565,11 +575,11 @@ "color": "blue", "memorial_male": { "ctxt": "memorial_male", "str": "Fell into a spiked pit." }, "memorial_female": { "ctxt": "memorial_female", "str": "Fell into a spiked pit." }, + "flags": [ "ECHOLOCATION_DETECTABLE", "PIT" ], "symbol": "0", "visibility": 0, "avoidance": 8, "difficulty": 99, - "flags": [ "PIT" ], "action": "pit_spikes", "vehicle_data": { "damage": 500 } }, @@ -612,6 +622,7 @@ "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a booby trap." }, "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a booby trap." }, "symbol": "^", + "flags": [ "ECHOLOCATION_DETECTABLE" ], "visibility": 5, "avoidance": 4, "difficulty": 7, @@ -634,6 +645,7 @@ "color": "light_gray", "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a flood trap." }, "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a flood trap." }, + "flags": [ "ECHOLOCATION_DETECTABLE" ], "symbol": "^", "visibility": 9, "avoidance": 20, @@ -769,7 +781,7 @@ "visibility": 0, "avoidance": 8, "difficulty": 99, - "flags": [ "PIT" ], + "flags": [ "PIT", "ECHOLOCATION_DETECTABLE" ], "action": "pit_glass", "vehicle_data": { "damage": 500 } }, diff --git a/data/json/vitamin.json b/data/json/vitamin.json index 0b30226d1af4b..0639271f9cc7b 100644 --- a/data/json/vitamin.json +++ b/data/json/vitamin.json @@ -123,6 +123,7 @@ [ "mutagen_rat", 1 ], [ "mutagen_spider", 1 ], [ "mutagen_troglobite", 1 ], + [ "mutagen_chiropteran", 1 ], [ "mutagen_ursine", 1 ], [ "instability", 1 ], [ "mutant_toxin", 2 ] @@ -421,6 +422,17 @@ "rate": "1 h", "disease_excess": [ [ 100, 500 ], [ 501, 2199 ], [ 2200, 2500 ] ] }, + { + "id": "mutagen_chiropteran", + "type": "vitamin", + "vit_type": "counter", + "name": { "str": "Chiropteran Primer" }, + "excess": "mutagen_chiropteran", + "min": 0, + "max": 2500, + "rate": "1 h", + "disease_excess": [ [ 100, 500 ], [ 501, 2199 ], [ 2200, 2500 ] ] + }, { "id": "mutagen_slime", "type": "vitamin", diff --git a/data/mods/Aftershock/mutations/mutations.json b/data/mods/Aftershock/mutations/mutations.json index c0dc455a8908b..005d8b0847e3e 100644 --- a/data/mods/Aftershock/mutations/mutations.json +++ b/data/mods/Aftershock/mutations/mutations.json @@ -482,7 +482,20 @@ "description": "Your skin has patches of light fur. This has no impact on your life except marking you as not fully human.", "types": [ "SKIN", "BODY_ARMOR", "BODY_ARMOR_MOD", "ARMOR" ], "changes_to": [ "LIGHTFUR" ], - "category": [ "MASTODON", "SPIDER", "MOUSE", "BEAST", "CATTLE", "RAT", "FELINE", "LUPINE", "RABBIT", "INSECT", "URSINE" ] + "category": [ + "MASTODON", + "SPIDER", + "MOUSE", + "BEAST", + "CATTLE", + "RAT", + "FELINE", + "LUPINE", + "RABBIT", + "INSECT", + "URSINE", + "CHIROPTERAN" + ] }, { "type": "mutation", diff --git a/src/avatar.cpp b/src/avatar.cpp index 357f9193bf34f..457bab30ea4fd 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -1299,6 +1299,8 @@ void avatar::set_movement_mode( const move_mode_id &new_mode ) } add_msg( new_mode->change_message( true, get_steed_type() ) ); move_mode = new_mode; + // Enchantments based on move modes can stack inappropriately without a recalc here + recalculate_enchantment_cache(); // crouching affects visibility get_map().set_seen_cache_dirty( pos().z ); recoil = MAX_RECOIL; diff --git a/src/bonuses.cpp b/src/bonuses.cpp index 0fd54fcc31a41..84a599ca481a6 100644 --- a/src/bonuses.cpp +++ b/src/bonuses.cpp @@ -283,4 +283,4 @@ float effect_scaling::get( const Character &u ) const } return bonus; -} +} \ No newline at end of file diff --git a/src/bonuses.h b/src/bonuses.h index 9949836589518..3810f82795dcc 100644 --- a/src/bonuses.h +++ b/src/bonuses.h @@ -91,4 +91,4 @@ class bonus_container bonus_map bonuses_mult; }; -#endif // CATA_SRC_BONUSES_H +#endif // CATA_SRC_BONUSES_H \ No newline at end of file diff --git a/src/character.cpp b/src/character.cpp index dfc7c165813d9..e081d964612de 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -158,6 +158,7 @@ static const bionic_id bio_shock_absorber( "bio_shock_absorber" ); static const bionic_id bio_sleep_shutdown( "bio_sleep_shutdown" ); static const bionic_id bio_soporific( "bio_soporific" ); static const bionic_id bio_synlungs( "bio_synlungs" ); +static const bionic_id bio_targeting( "bio_targeting" ); static const bionic_id bio_uncanny_dodge( "bio_uncanny_dodge" ); static const bionic_id bio_ups( "bio_ups" ); static const bionic_id bio_voice( "bio_voice" ); @@ -262,6 +263,7 @@ static const efftype_id effect_slept_through_alarm( "slept_through_alarm" ); static const efftype_id effect_slippery_terrain( "slippery_terrain" ); static const efftype_id effect_stumbled_into_invisible( "stumbled_into_invisible" ); static const efftype_id effect_stunned( "stunned" ); +static const efftype_id effect_subaquatic_sonar( "subaquatic_sonar" ); static const efftype_id effect_tapeworm( "tapeworm" ); static const efftype_id effect_tied( "tied" ); static const efftype_id effect_transition_contacts( "transition_contacts" ); @@ -350,7 +352,7 @@ static const limb_score_id limb_score_night_vis( "night_vis" ); static const limb_score_id limb_score_reaction( "reaction" ); static const limb_score_id limb_score_vision( "vision" ); -static const matec_id tec_none( "tec_none" ); +const matec_id tec_none( "tec_none" ); static const material_id material_budget_steel( "budget_steel" ); static const material_id material_ch_steel( "ch_steel" ); @@ -480,9 +482,6 @@ static const trait_id trait_SPIRITUAL( "SPIRITUAL" ); static const trait_id trait_STRONGBACK( "STRONGBACK" ); static const trait_id trait_SUNLIGHT_DEPENDENT( "SUNLIGHT_DEPENDENT" ); static const trait_id trait_THORNS( "THORNS" ); -static const trait_id trait_THRESH_BEAST( "THRESH_BEAST" ); -static const trait_id trait_THRESH_FELINE( "THRESH_FELINE" ); -static const trait_id trait_THRESH_LUPINE( "THRESH_LUPINE" ); static const trait_id trait_THRESH_SPIDER( "THRESH_SPIDER" ); static const trait_id trait_TRANSPIRATION( "TRANSPIRATION" ); static const trait_id trait_UNDINE_SLEEP_WATER( "UNDINE_SLEEP_WATER" ); @@ -2189,20 +2188,6 @@ bool Character::is_crouching() const return move_mode->type() == move_mode_type::CROUCHING; } -bool Character::is_runallfours() const -{ - bool allfour = false; - if( move_mode->type() == move_mode_type::RUNNING && !is_armed() ) { - if( has_trait( trait_PAWS ) && ( has_trait( trait_THRESH_LUPINE ) || - has_trait( trait_THRESH_FELINE ) - || has_trait( trait_THRESH_BEAST ) ) ) { - allfour = true; - } - } - - return allfour; -} - bool Character::is_prone() const { return move_mode->type() == move_mode_type::PRONE; @@ -10637,13 +10622,7 @@ bool Character::sees_with_infrared( const Creature &critter ) const map &here = get_map(); - if( is_avatar() || critter.is_avatar() ) { - // Players should not use map::sees - // Likewise, players should not be "looked at" with map::sees, not to break symmetry - return here.pl_line_of_sight( critter.pos(), unimpaired_range() ); - } - - return here.sees( pos(), critter.pos(), unimpaired_range() ); + return here.sees( pos(), critter.pos(), unimpaired_range(), false ); } bool Character::is_visible_in_range( const Creature &critter, const int range ) const @@ -10715,6 +10694,145 @@ std::vector Character::get_hostile_creatures( int range ) const } ); } +void Character::echo_pulse() +{ + map &here = get_map(); + int echo_volume = 0; + int pulse_range = 10; + // Sound travels farther underwater + if( has_effect( effect_subaquatic_sonar ) && is_underwater() ) { + pulse_range = 16; + sounds::sound( this->pos(), 5, sounds::sound_t::movement, _( "boop." ), true, + "none", "none" ); + } else if( !has_effect( effect_subaquatic_sonar ) && is_underwater() ) { + add_msg_if_player( m_warning, _( "You can't echolocate underwater!" ) ); + return; + } else { + sounds::sound( this->pos(), 5, sounds::sound_t::movement, _( "chirp." ), true, + "none", "none" ); + } + for( tripoint origin : points_in_radius( pos(), pulse_range ) ) { + if( here.move_cost( origin ) == 0 && here.sees( pos(), origin, pulse_range, false ) ) { + sounds::sound( origin, 5, sounds::sound_t::sensory, _( "clack." ), true, + "none", "none" ); + // This only counts obstacles which can be moved through, so the echo is pretty quiet. + } else if( is_obstacle( origin ) && here.sees( pos(), origin, pulse_range, false ) ) { + sounds::sound( origin, 1, sounds::sound_t::sensory, _( "click." ), true, + "none", "none" ); + } + const trap &tr = here.tr_at( origin ); + if( !knows_trap( origin ) && tr.detected_by_echolocation() ) { + const std::string direction = direction_name( direction_from( pos(), origin ) ); + add_msg_if_player( m_warning, _( "You detect a %1$s to the %2$s!" ), + tr.name(), direction ); + add_known_trap( origin, tr ); + } + Creature *critter = get_creature_tracker().creature_at( origin, true ); + if( critter && here.sees( pos(), origin, pulse_range, false ) ) { + switch( critter->get_size() ) { + case creature_size::tiny: + echo_volume = 1; + break; + case creature_size::small: + echo_volume = 2; + break; + case creature_size::medium: + echo_volume = 3; + break; + case creature_size::large: + echo_volume = 4; + break; + case creature_size::huge: + echo_volume = 5; + break; + case creature_size::num_sizes: + debugmsg( "ERROR: Invalid Creature size class." ); + break; + } + // Some monsters are harder to get a read on + if( critter->has_flag( mon_flag_PLASTIC ) ) { + echo_volume -= std::max( 1, 1 ); + } + if( critter->has_flag( mon_flag_HARDTOSHOOT ) ) { + echo_volume -= std::max( 1, 1 ); + } + const char *echo_string = nullptr; + // bio_targeting has a visual HUD and automatically interprets the raw audio data, + // but only for electronic SONAR. Its designers didn't anticipate bat mutations + if( has_bionic( bio_targeting ) && has_effect( effect_subaquatic_sonar ) ) { + switch( echo_volume ) { + case 1: + echo_string = _( "Target [Tiny]." ); + break; + case 2: + echo_string = _( "Target [Small]." ); + break; + case 3: + echo_string = _( "Target [Medium]." ); + break; + case 4: + echo_string = _( "Warning! Target [Large]." ); + break; + case 5: + echo_string = _( "Warning! Target [Huge]." ); + break; + default: + debugmsg( "ERROR: Invalid echo string." ); + break; + } + } else if( !has_bionic( bio_targeting ) && has_effect( effect_subaquatic_sonar ) ) { + switch( echo_volume ) { + case 1: + echo_string = _( "tick." ); + break; + case 2: + echo_string = _( "pii." ); + break; + case 3: + echo_string = _( "ping." ); + break; + case 4: + echo_string = _( "pong." ); + break; + case 5: + echo_string = _( "bloop." ); + break; + default: + debugmsg( "ERROR: Invalid echo string." ); + break; + } + } else { + switch( echo_volume ) { + case 1: + echo_string = _( "ch." ); + break; + case 2: + echo_string = _( "chk." ); + break; + case 3: + echo_string = _( "chhk." ); + break; + case 4: + echo_string = _( "chkch." ); + break; + case 5: + echo_string = _( "chkchh." ); + break; + default: + debugmsg( "ERROR: Invalid echo string." ); + break; + } + } + // It's not moving. Must be an obstacle + if( critter->has_flag( mon_flag_IMMOBILE ) ) { + echo_string = _( "click." ); + } + sounds::sound( origin, echo_volume, sounds::sound_t::sensory, _( echo_string ), false, + "none", "none" ); + } + } +} + bool Character::knows_trap( const tripoint &pos ) const { const tripoint p = get_map().getabs( pos ); @@ -12973,6 +13091,9 @@ void Character::search_surroundings() if( controlling_vehicle ) { return; } + if( has_effect( effect_subaquatic_sonar ) && is_underwater() && calendar::once_every( 4_turns ) ) { + echo_pulse(); + } map &here = get_map(); // Search for traps in a larger area than before because this is the only // way we can "find" traps that aren't marked as visible. @@ -12982,6 +13103,7 @@ void Character::search_surroundings() if( tr.is_null() || tp == pos() ) { continue; } + // Note that echolocation and SONAR also do this separately in echo_pulse() if( has_active_bionic( bio_ground_sonar ) && !knows_trap( tp ) && tr.detected_by_ground_sonar() ) { const std::string direction = direction_name( direction_from( pos(), tp ) ); add_msg_if_player( m_warning, _( "Your ground sonar detected a %1$s to the %2$s!" ), diff --git a/src/character.h b/src/character.h index b31b211c0088f..041d6a3ed84c3 100644 --- a/src/character.h +++ b/src/character.h @@ -1030,7 +1030,6 @@ class Character : public Creature, public visitable bool is_running() const; bool is_walking() const; bool is_crouching() const; - bool is_runallfours() const; bool is_prone() const; int footstep_sound() const; @@ -3673,6 +3672,9 @@ class Character : public Creature, public visitable /** Creates an auditory hallucination */ void sound_hallu(); + /** All nearby obstacles make a very quiet sound */ + void echo_pulse(); + /** Checks if a Character is driving */ bool is_driving() const; diff --git a/src/consumption.cpp b/src/consumption.cpp index 10a3ef7308494..26ffc4b96c006 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -99,7 +99,9 @@ static const itype_id itype_apparatus( "apparatus" ); static const itype_id itype_dab_pen_on( "dab_pen_on" ); static const itype_id itype_syringe( "syringe" ); +static const json_character_flag json_flag_BLOODFEEDER( "BLOODFEEDER" ); static const json_character_flag json_flag_CANNIBAL( "CANNIBAL" ); +static const json_character_flag json_flag_HEMOVORE( "HEMOVORE" ); static const json_character_flag json_flag_IMMUNE_SPOIL( "IMMUNE_SPOIL" ); static const json_character_flag json_flag_NUMB( "NUMB" ); static const json_character_flag json_flag_PARAIMMUNE( "PARAIMMUNE" ); @@ -509,6 +511,29 @@ std::pair Character::fun_for( const item &comest, bool ignore_already_ } } + // Cooked blood is OK, but it's really better raw + // This is automatically handled by raw blood having negative fun + if( comest.has_flag( flag_HEMOVORE_FUN ) ) { + if( has_flag( json_flag_BLOODFEEDER ) ) { + if( fun <= 0 ) { + fun += 25; + } else { + fun *= 1.2; + } + } else if( has_flag( json_flag_HEMOVORE ) ) { + if( fun <= 0 ) { + fun += 13; + } else { + fun *= 1.1; + } + } + } + + // This cherry soda's just not the same... + if( has_flag( json_flag_BLOODFEEDER ) && !comest.has_flag( flag_HEMOVORE_FUN ) && fun > 0 ) { + fun *= 0.5; + } + if( has_trait( trait_GOURMAND ) ) { if( fun < -1 ) { fun_max = fun; @@ -925,13 +950,15 @@ ret_val Character::will_eat( const item &food, bool interactive ) const bool food_is_human_flesh = food.has_flag( flag_CANNIBALISM ) || ( food.has_flag( flag_STRICT_HUMANITARIANISM ) && !has_flag( json_flag_STRICT_HUMANITARIAN ) ); - if( food_is_human_flesh && ( !has_flag( STATIC( json_character_flag( "CANNIBAL" ) ) ) && - !has_flag( json_flag_PSYCHOPATH ) ) ) { + if( ( food_is_human_flesh && !has_flag( STATIC( json_character_flag( "CANNIBAL" ) ) ) && + !has_flag( json_flag_PSYCHOPATH ) && !has_flag( json_flag_SAPIOVORE ) ) && + ( !food.has_flag( flag_HEMOVORE_FUN ) || ( !has_flag( json_flag_BLOODFEEDER ) ) ) ) { add_consequence( _( "The thought of eating human flesh makes you feel sick." ), CANNIBALISM ); } if( food.get_comestible()->parasites > 0 && !food.has_flag( flag_NO_PARASITES ) && - !has_flag( json_flag_PARAIMMUNE ) ) { + !has_flag( json_flag_PARAIMMUNE ) && ( !food.has_flag( flag_HEMOVORE_FUN ) || + ( !has_flag( json_flag_HEMOVORE ) && !has_flag( json_flag_BLOODFEEDER ) ) ) ) { add_consequence( string_format( _( "Consuming this %s probably isn't very healthy." ), food.tname() ), PARASITES ); @@ -1148,7 +1175,8 @@ static bool eat( item &food, Character &you, bool force ) // Chance to become parasitised if( !will_vomit && !you.has_flag( json_flag_PARAIMMUNE ) ) { if( food.get_comestible()->parasites > 0 && !food.has_flag( flag_NO_PARASITES ) && - one_in( food.get_comestible()->parasites ) ) { + one_in( food.get_comestible()->parasites ) && ( !food.has_flag( flag_HEMOVORE_FUN ) || + ( !you.has_flag( json_flag_HEMOVORE ) && !you.has_flag( json_flag_BLOODFEEDER ) ) ) ) { switch( rng( 0, 3 ) ) { case 0: if( !you.has_trait( trait_EATHEALTH ) ) { @@ -1323,10 +1351,16 @@ void Character::modify_morale( item &food, const int nutr ) add_msg_if_player( _( "You greedily devour the taboo meat." ) ); // Small bonus for violating a taboo. add_morale( MORALE_CANNIBAL, 5, 50 ); + } else if( has_flag( json_flag_BLOODFEEDER ) && food.has_flag( flag_HEMOVORE_FUN ) ) { + add_msg_if_player( _( "The human blood tastes as good as any other." ) ); } else if( psycho ) { add_msg_if_player( _( "Meh. You've eaten worse." ) ); } else if( sapiovore ) { add_msg_if_player( _( "Mmh. Tastes like venison." ) ); + } else if( has_flag( json_flag_HEMOVORE ) && food.has_flag( flag_HEMOVORE_FUN ) ) { + add_msg_if_player( + _( "Despite your cravings, you still can't help feeling weird about drinking somebody's blood." ) ); + add_morale( MORALE_CANNIBAL, -10, -30, 30_minutes, 15_minutes ); } else if( spiritual ) { add_msg_if_player( m_bad, _( "This is probably going to count against you if there's still an afterlife." ) ); diff --git a/src/creature.cpp b/src/creature.cpp index 4e343c23fc80f..2ba94eb559251 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -72,6 +72,7 @@ static const damage_type_id damage_bash( "bash" ); static const damage_type_id damage_electric( "electric" ); static const damage_type_id damage_heat( "heat" ); +static const efftype_id effect_all_fours( "all_fours" ); static const efftype_id effect_blind( "blind" ); static const efftype_id effect_bounced( "bounced" ); static const efftype_id effect_downed( "downed" ); @@ -431,7 +432,8 @@ bool Creature::sees( const Creature &critter ) const return false; } if( ch != nullptr ) { - if( ch->is_crouching() || ch->is_prone() || pos().z != critter.pos().z ) { + if( ch->is_crouching() || ch->has_effect( effect_all_fours ) || ch->is_prone() || + pos().z != critter.pos().z ) { const int coverage = std::max( here.obstacle_coverage( pos(), critter.pos() ), here.ledge_coverage( *this, critter.pos() ) ); if( coverage < 30 ) { @@ -459,7 +461,7 @@ bool Creature::sees( const Creature &critter ) const } int profile = 120 / size_modifier; - if( ch->is_crouching() ) { + if( ch->is_crouching() || ch->has_effect( effect_all_fours ) ) { profile *= 0.5; } else if( ch->is_prone() ) { profile *= 0.275; diff --git a/src/flag.cpp b/src/flag.cpp index baf923d20d094..2f8dcc457888d 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -151,6 +151,7 @@ const flag_id flag_GIBBED( "GIBBED" ); const flag_id flag_GNV_EFFECT( "GNV_EFFECT" ); const flag_id flag_HARD( "HARD" ); const flag_id flag_HEAT_IMMUNE( "HEAT_IMMUNE" ); +const flag_id flag_HEMOVORE_FUN( "HEMOVORE_FUN" ); const flag_id flag_HIDDEN_HALLU( "HIDDEN_HALLU" ); const flag_id flag_HIDDEN_POISON( "HIDDEN_POISON" ); const flag_id flag_HOOD( "HOOD" ); @@ -196,6 +197,7 @@ const flag_id flag_MYCUS_OK( "MYCUS_OK" ); const flag_id flag_NANOFAB_REPAIR( "NANOFAB_REPAIR" ); const flag_id flag_NANOFAB_TEMPLATE( "NANOFAB_TEMPLATE" ); const flag_id flag_NANOFAB_TEMPLATE_SINGLE_USE( "NANOFAB_TEMPLATE_SINGLE_USE" ); +const flag_id flag_NATURAL_WEAPON( "NATURAL_WEAPON" ); const flag_id flag_NEEDS_NO_LUBE( "NEEDS_NO_LUBE" ); const flag_id flag_NEEDS_UNFOLD( "NEEDS_UNFOLD" ); const flag_id flag_NEGATIVE_MONOTONY_OK( "NEGATIVE_MONOTONY_OK" ); @@ -248,6 +250,7 @@ const flag_id flag_PRIMITIVE_RANGED_WEAPON( "PRIMITIVE_RANGED_WEAPON" ); const flag_id flag_PROCESSING( "PROCESSING" ); const flag_id flag_PROCESSING_RESULT( "PROCESSING_RESULT" ); const flag_id flag_PSEUDO( "PSEUDO" ); +const flag_id flag_PSEUDOPOD_GRASP( "PSEUDOPOD_GRASP" ); const flag_id flag_PSYSHIELD_PARTIAL( "PSYSHIELD_PARTIAL" ); const flag_id flag_PULPED( "PULPED" ); const flag_id flag_PUMP_ACTION( "PUMP_ACTION" ); diff --git a/src/flag.h b/src/flag.h index 8505876a0ea90..650237ed3b276 100644 --- a/src/flag.h +++ b/src/flag.h @@ -160,6 +160,7 @@ extern const flag_id flag_GIBBED; extern const flag_id flag_GNV_EFFECT; extern const flag_id flag_HARVEST_SEEDS; extern const flag_id flag_HEAT_IMMUNE; +extern const flag_id flag_HEMOVORE_FUN; extern const flag_id flag_HIDDEN_HALLU; extern const flag_id json_flag_HIDDEN_ITEM; extern const flag_id flag_HIDDEN_POISON; @@ -205,6 +206,7 @@ extern const flag_id flag_MYCUS_OK; extern const flag_id flag_NANOFAB_REPAIR; extern const flag_id flag_NANOFAB_TEMPLATE; extern const flag_id flag_NANOFAB_TEMPLATE_SINGLE_USE; +extern const flag_id flag_NATURAL_WEAPON; extern const flag_id flag_NEEDS_NO_LUBE; extern const flag_id flag_NEEDS_UNFOLD; extern const flag_id flag_NEGATIVE_MONOTONY_OK; @@ -255,6 +257,7 @@ extern const flag_id flag_PRIMITIVE_RANGED_WEAPON; extern const flag_id flag_PROCESSING; extern const flag_id flag_PROCESSING_RESULT; extern const flag_id flag_PSEUDO; +extern const flag_id flag_PSEUDOPOD_GRASP; extern const flag_id flag_PSYSHIELD_PARTIAL; extern const flag_id flag_PULPED; extern const flag_id flag_PUMP_ACTION; diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 809457da0e36f..7523fcff7919e 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -3567,7 +3567,7 @@ void Item_factory::load_generic( const JsonObject &jo, const std::string &src ) // Set for all items (not just food and clothing) to avoid edge cases void Item_factory::set_allergy_flags( itype &item_template ) { - static const std::array, 29> all_pairs = { { + static const std::array, 31> all_pairs = { { // First allergens: // An item is an allergen even if it has trace amounts of allergenic material { material_hflesh, flag_CANNIBALISM }, @@ -3600,7 +3600,9 @@ void Item_factory::set_allergy_flags( itype &item_template ) { material_iflesh, flag_CARNIVORE_OK }, { material_blood, flag_CARNIVORE_OK }, { material_hblood, flag_CARNIVORE_OK }, - { material_honey, flag_URSINE_HONEY } + { material_honey, flag_URSINE_HONEY }, + { material_blood, flag_HEMOVORE_FUN }, + { material_hblood, flag_HEMOVORE_FUN } } }; diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 16793b93c135d..5088a896c0941 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -50,6 +50,7 @@ static const efftype_id effect_haslight( "haslight" ); static const efftype_id effect_onfire( "onfire" ); +static const efftype_id effect_quadruped_full( "quadruped_full" ); static constexpr int LIGHTMAP_CACHE_X = MAPSIZE_X; static constexpr int LIGHTMAP_CACHE_Y = MAPSIZE_Y; @@ -207,13 +208,15 @@ bool map::build_vision_transparency_cache( const int zlev ) bool dirty = false; bool is_crouching = player_character.is_crouching(); - bool is_runallfours = player_character.is_runallfours(); + bool low_profile = player_character.has_effect( effect_quadruped_full ) && + player_character.is_running(); bool is_prone = player_character.is_prone(); + for( const tripoint &loc : points_in_radius( p, 1 ) ) { if( loc == p ) { // The tile player is standing on should always be visible vision_transparency_cache[p.x][p.y] = LIGHT_TRANSPARENCY_OPEN_AIR; - } else if( ( is_crouching || is_prone || is_runallfours ) && coverage( loc ) >= 30 ) { + } else if( ( is_crouching || is_prone || low_profile ) && coverage( loc ) >= 30 ) { // If we're crouching or prone behind an obstacle, we can't see past it. vision_transparency_cache[loc.x][loc.y] = LIGHT_TRANSPARENCY_SOLID; dirty = true; @@ -803,26 +806,6 @@ bool map::pl_sees( const tripoint &t, const int max_range ) const map_cache.sm[t.x][t.y] > 0.0 ); } -bool map::pl_line_of_sight( const tripoint &t, const int max_range ) const -{ - if( !inbounds( t ) ) { - return false; - } - - const level_cache &map_cache = get_cache_ref( t.z ); - if( map_cache.camera_cache[t.x][t.y] > 0.075f ) { - return true; - } - - if( max_range >= 0 && square_dist( t, get_player_character().pos() ) > max_range ) { - // Out of range! - return false; - } - - // Any epsilon > 0 is fine - it means lightmap processing visited the point - return map_cache.seen_cache[t.x][t.y] > 0.0f; -} - // For a direction vector defined by x, y, return the quadrant that's the // source of that direction. Assumes x != 0 && y != 0 // NOLINTNEXTLINE(cata-xy) diff --git a/src/map.cpp b/src/map.cpp index 17e4cb2d135be..9b0ad58b3c569 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -7226,10 +7226,10 @@ void map::draw_from_above( const catacurses::window &w, const tripoint &p, } } -bool map::sees( const tripoint &F, const tripoint &T, const int range ) const +bool map::sees( const tripoint &F, const tripoint &T, const int range, bool with_fields ) const { int dummy = 0; - return sees( F, T, range, dummy ); + return sees( F, T, range, dummy, with_fields ); } point map::sees_cache_key( const tripoint &from, const tripoint &to ) const @@ -7250,8 +7250,11 @@ point map::sees_cache_key( const tripoint &from, const tripoint &to ) const * This one is internal-only, we don't want to expose the slope tweaking ickiness outside the map class. **/ bool map::sees( const tripoint &F, const tripoint &T, const int range, - int &bresenham_slope ) const + int &bresenham_slope, bool with_fields ) const { + bool ( map::*f_transparent )( const tripoint & p ) const = + with_fields ? &map::is_transparent : &map::is_transparent_wo_fields; + lru_cache_t &skew_cache = with_fields ? skew_vision_cache : skew_vision_wo_fields_cache; if( std::abs( F.z - T.z ) > fov_3d_z_range || ( range >= 0 && range < rl_dist( F, T ) ) || !inbounds( T ) ) { @@ -7259,7 +7262,7 @@ bool map::sees( const tripoint &F, const tripoint &T, const int range, return false; // Out of range! } const point key = sees_cache_key( F, T ); - char cached = skew_vision_cache.get( key, -1 ); + char cached = skew_cache.get( key, -1 ); if( cached >= 0 ) { return cached > 0; } @@ -7268,24 +7271,24 @@ bool map::sees( const tripoint &F, const tripoint &T, const int range, // Ugly `if` for now if( F.z == T.z ) { bresenham( F.xy(), T.xy(), bresenham_slope, - [this, &visible, &T]( const point & new_point ) { + [this, f_transparent, &visible, &T]( const point & new_point ) { // Exit before checking the last square, it's still visible even if opaque. if( new_point.x == T.x && new_point.y == T.y ) { return false; } - if( !this->is_transparent( tripoint( new_point, T.z ) ) ) { + if( !( this->*f_transparent )( tripoint( new_point, T.z ) ) ) { visible = false; return false; } return true; } ); - skew_vision_cache.insert( 100000, key, visible ? 1 : 0 ); + skew_cache.insert( 100000, key, visible ? 1 : 0 ); return visible; } tripoint last_point = F; bresenham( F, T, bresenham_slope, 0, - [this, &visible, &T, &last_point]( const tripoint & new_point ) { + [this, f_transparent, &visible, &T, &last_point]( const tripoint & new_point ) { // Exit before checking the last square if it's not a vertical transition, // it's still visible even if opaque. if( new_point == T && last_point.z == T.z ) { @@ -7294,16 +7297,16 @@ bool map::sees( const tripoint &F, const tripoint &T, const int range, // TODO: Allow transparent floors (and cache them!) if( new_point.z == last_point.z ) { - if( !this->is_transparent( new_point ) ) { + if( !( this->*f_transparent )( new_point ) ) { visible = false; return false; } } else { const int max_z = std::max( new_point.z, last_point.z ); if( ( has_floor_or_support( {new_point.xy(), max_z} ) || - !is_transparent( {new_point.xy(), last_point.z} ) ) && + !( this->*f_transparent )( {new_point.xy(), last_point.z} ) ) && ( has_floor_or_support( {last_point.xy(), max_z} ) || - !is_transparent( {last_point.xy(), new_point.z} ) ) ) { + !( this->*f_transparent )( {last_point.xy(), new_point.z} ) ) ) { visible = false; return false; } @@ -7312,7 +7315,7 @@ bool map::sees( const tripoint &F, const tripoint &T, const int range, last_point = new_point; return true; } ); - skew_vision_cache.insert( 100000, key, visible ? 1 : 0 ); + skew_cache.insert( 100000, key, visible ? 1 : 0 ); return visible; } @@ -9413,6 +9416,7 @@ void map::build_map_cache( const int zlev, bool skip_lightmap ) if( seen_cache_dirty ) { skew_vision_cache.clear(); + skew_vision_wo_fields_cache.clear(); } avatar &u = get_avatar(); Character::moncam_cache_t mcache = u.get_active_moncams(); diff --git a/src/map.h b/src/map.h index 627382a354fe6..3aa7abe5bcfab 100644 --- a/src/map.h +++ b/src/map.h @@ -602,7 +602,7 @@ class map /** * Returns whether `F` sees `T` with a view range of `range`. */ - bool sees( const tripoint &F, const tripoint &T, int range ) const; + bool sees( const tripoint &F, const tripoint &T, int range, bool with_fields = true ) const; private: /** * Don't expose the slope adjust outside map functions. @@ -614,7 +614,8 @@ class map * the two points, and may subsequently be used to form a path between them. * Set to zero if the function returns false. **/ - bool sees( const tripoint &F, const tripoint &T, int range, int &bresenham_slope ) const; + bool sees( const tripoint &F, const tripoint &T, int range, int &bresenham_slope, + bool with_fields = true ) const; point sees_cache_key( const tripoint &from, const tripoint &to ) const; public: /** @@ -1824,12 +1825,7 @@ class map * Ignored if smaller than 0. */ bool pl_sees( const tripoint &t, int max_range ) const; - /** - * Uses the map cache to tell if the player could see the given square. - * pl_sees implies pl_line_of_sight - * Used for infrared. - */ - bool pl_line_of_sight( const tripoint &t, int max_range ) const; + std::set dirty_vehicle_list; /** return @ref abs_sub */ @@ -2262,7 +2258,9 @@ class map /** * Cache of coordinate pairs recently checked for visibility. */ - mutable lru_cache skew_vision_cache; + using lru_cache_t = lru_cache; + mutable lru_cache_t skew_vision_cache; + mutable lru_cache_t skew_vision_wo_fields_cache; // Note: no bounds check level_cache &get_cache( int zlev ) const { diff --git a/src/martialarts.cpp b/src/martialarts.cpp index 25adf17c0092b..66ca665236692 100644 --- a/src/martialarts.cpp +++ b/src/martialarts.cpp @@ -45,8 +45,6 @@ static const json_character_flag json_flag_NONSTANDARD_BLOCK( "NONSTANDARD_BLOCK static const limb_score_id limb_score_block( "block" ); -static const matec_id tec_none( "tec_none" ); - static const skill_id skill_unarmed( "unarmed" ); static const weapon_category_id weapon_category_OTHER_INVALID_WEAP_CAT( "OTHER_INVALID_WEAP_CAT" ); @@ -2186,4 +2184,4 @@ bool ma_style_callback::key( const input_context &ctxt, const input_event &event } while( true ); } return true; -} +} \ No newline at end of file diff --git a/src/martialarts.h b/src/martialarts.h index 4cb609a5d2b68..a8000f7d001a8 100644 --- a/src/martialarts.h +++ b/src/martialarts.h @@ -26,6 +26,8 @@ class effect; class item; struct itype; +extern const matec_id tec_none; + class weapon_category { public: @@ -425,4 +427,4 @@ std::string martialart_difficulty( const matype_id &mstyle ); std::vector all_martialart_types(); std::vector autolearn_martialart_types(); -#endif // CATA_SRC_MARTIALARTS_H +#endif // CATA_SRC_MARTIALARTS_H \ No newline at end of file diff --git a/src/melee.cpp b/src/melee.cpp index 8675394e88dff..fa4ac6e53c09a 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -102,6 +102,7 @@ static const efftype_id effect_hit_by_player( "hit_by_player" ); static const efftype_id effect_incorporeal( "incorporeal" ); static const efftype_id effect_lightsnare( "lightsnare" ); static const efftype_id effect_narcosis( "narcosis" ); +static const efftype_id effect_natural_stance( "natural_stance" ); static const efftype_id effect_pet( "pet" ); static const efftype_id effect_stunned( "stunned" ); static const efftype_id effect_transition_contacts( "transition_contacts" ); @@ -122,6 +123,7 @@ static const json_character_flag json_flag_HARDTOHIT( "HARDTOHIT" ); static const json_character_flag json_flag_HYPEROPIC( "HYPEROPIC" ); static const json_character_flag json_flag_NEED_ACTIVE_TO_MELEE( "NEED_ACTIVE_TO_MELEE" ); static const json_character_flag json_flag_NULL( "NULL" ); +static const json_character_flag json_flag_PSEUDOPOD_GRASP( "PSEUDOPOD_GRASP" ); static const json_character_flag json_flag_UNARMED_BONUS( "UNARMED_BONUS" ); static const limb_score_id limb_score_block( "block" ); @@ -132,7 +134,6 @@ static const matec_id WBLOCK_1( "WBLOCK_1" ); static const matec_id WBLOCK_2( "WBLOCK_2" ); static const matec_id WBLOCK_3( "WBLOCK_3" ); static const matec_id WHIP_DISARM( "WHIP_DISARM" ); -static const matec_id tec_none( "tec_none" ); static const material_id material_glass( "glass" ); static const material_id material_steel( "steel" ); @@ -377,9 +378,19 @@ float Character::hit_roll() const } // Difficult to land a hit while prone + // Quadrupeds don't mind crouching as long as they're unarmed + // Tentacles and goo-limbs care even less + item_location cur_weapon = used_weapon(); + item cur_weap = cur_weapon ? *cur_weapon : null_item_reference(); if( is_on_ground() ) { - hit -= 8.0f; - } else if( is_crouching() ) { + if( has_flag( json_flag_PSEUDOPOD_GRASP ) ) { + hit -= 2.0f; + } else { + hit -= 8.0f; + } + } else if( is_crouching() && ( !has_flag( json_flag_PSEUDOPOD_GRASP ) || + ( !has_effect( effect_natural_stance ) && + !unarmed_attack() ) ) ) { hit -= 2.0f; } @@ -777,9 +788,15 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, d.mult_damage( 0.7 ); } // being prone affects how much leverage you can use to deal damage - if( is_on_ground() ) { + // quadrupeds don't mind as much, tentacles and goo-limbs even less + if( is_on_ground() ) { + if( has_flag( json_flag_PSEUDOPOD_GRASP ) ) { + d.mult_damage( 0.8 ); + } d.mult_damage( 0.3 ); - } else if( is_crouching() ) { + } else if( is_crouching() && ( ( !has_effect( effect_natural_stance ) && + !unarmed_attack() ) || + !has_flag( json_flag_PSEUDOPOD_GRASP ) ) ) { d.mult_damage( 0.8 ); } @@ -950,7 +967,10 @@ int Character::get_total_melee_stamina_cost( const item *weap ) const { const int mod_sta = get_standard_stamina_cost( weap ); const int melee = round( get_skill_level( skill_melee ) ); - const int stance_malus = is_on_ground() ? 50 : ( is_crouching() ? 20 : 0 ); + // Quadrupeds don't mind crouching, squids and slimes hardly care about even being prone + const int stance_malus = ( is_on_ground() && + !has_flag( json_flag_PSEUDOPOD_GRASP ) ) ? 50 : ( ( !has_flag( json_flag_PSEUDOPOD_GRASP ) || + ( !has_effect( effect_natural_stance ) && !unarmed_attack() ) ) && is_crouching() ? 20 : 0 ); return std::min( -50, mod_sta + melee - stance_malus ); } @@ -1040,11 +1060,14 @@ int stumble( Character &u, const item_location &weap ) if( !weap || u.has_trait( trait_DEFT ) ) { return 0; } - + item cur_weap = weap ? *weap : null_item_reference(); units::mass str_mod = u.get_arm_str() * 10_gram; + // Ceph and Slime mutants still need good posture to prevent stumbling if( u.is_on_ground() ) { str_mod /= 4; - } else if( u.is_crouching() ) { + // but quadrupeds fight naturally on all fours + } else if( u.is_crouching() && ( !u.has_effect( effect_natural_stance ) && + !u.unarmed_attack() ) ) { str_mod /= 2; } @@ -1295,6 +1318,8 @@ static void roll_melee_damage_internal( const Character &u, const damage_type_id ( !u.natural_attack_restricted_on( sub_bodypart_id( "leg_hip_r" ) ) ); } else if( attack_vector == "HEAD" ) { bp_unrestricted = !u.natural_attack_restricted_on( bodypart_id( "head" ) ); + } else if( attack_vector == "MOUTH" ) { + bp_unrestricted = !u.natural_attack_restricted_on( bodypart_id( "mouth" ) ); } else if( attack_vector == "TORSO" ) { bp_unrestricted = !u.natural_attack_restricted_on( bodypart_id( "torso" ) ); } else { @@ -2740,10 +2765,15 @@ int Character::attack_speed( const item &weap ) const move_cost += ma_move_cost; move_cost *= mutation_value( "attackcost_modifier" ); - if( is_on_ground() ) { - move_cost *= 4.0; - } else if( is_crouching() ) { + if( has_flag( json_flag_PSEUDOPOD_GRASP ) ) { + move_cost *= 1.5; + } else { + move_cost *= 4.0; + } + } else if( is_crouching() && ( !has_flag( json_flag_PSEUDOPOD_GRASP ) || + ( !has_effect( effect_natural_stance ) && + !unarmed_attack() ) ) ) { move_cost *= 1.5; } diff --git a/src/morale_types.cpp b/src/morale_types.cpp index a7333c3db1d82..9988b9b77b733 100644 --- a/src/morale_types.cpp +++ b/src/morale_types.cpp @@ -92,6 +92,7 @@ const morale_type MORALE_TREE_COMMUNION( "morale_tree_communion" ); const morale_type MORALE_VEGETARIAN( "morale_vegetarian" ); const morale_type MORALE_VOMITED( "morale_vomited" ); const morale_type MORALE_WET( "morale_wet" ); + static const morale_type morale_accomplishment( "morale_accomplishment" ); static const morale_type morale_antifruit( "morale_antifruit" ); static const morale_type morale_antijunk( "morale_antijunk" ); diff --git a/src/mutation.cpp b/src/mutation.cpp index 72459ee3c84f1..e9a778efe2981 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -70,6 +70,7 @@ static const trait_id trait_BURROW( "BURROW" ); static const trait_id trait_BURROWLARGE( "BURROWLARGE" ); static const trait_id trait_CHAOTIC_BAD( "CHAOTIC_BAD" ); static const trait_id trait_DEX_ALPHA( "DEX_ALPHA" ); +static const trait_id trait_ECHOLOCATION( "ECHOLOCATION" ); static const trait_id trait_GASTROPOD_EXTREMITY2( "GASTROPOD_EXTREMITY2" ); static const trait_id trait_GASTROPOD_EXTREMITY3( "GASTROPOD_EXTREMITY3" ); static const trait_id trait_GLASSJAW( "GLASSJAW" ); @@ -876,6 +877,9 @@ void Character::activate_mutation( const trait_id &mut ) blossoms(); tdata.powered = false; return; + } else if( mut == trait_ECHOLOCATION ) { + echo_pulse(); + deactivate_mutation( mut ); } else if( mut == trait_TREE_COMMUNION || mut == trait_ARVORE_FOREST_MAPPING ) { tdata.powered = false; // Check for adjacent trees. diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 09635de41946e..366164d795218 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -5294,5 +5294,7 @@ bool outfit::adjust_worn( npc &guy ) void npc::set_movement_mode( const move_mode_id &new_mode ) { + // Enchantments based on move modes can stack inappropriately without a recalc here + recalculate_enchantment_cache(); move_mode = new_mode; } diff --git a/src/ranged.cpp b/src/ranged.cpp index 9205dabb49995..9c6b28779d599 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -110,6 +110,7 @@ static const damage_type_id damage_cut( "cut" ); static const efftype_id effect_downed( "downed" ); static const efftype_id effect_hit_by_player( "hit_by_player" ); static const efftype_id effect_on_roof( "on_roof" ); +static const efftype_id effect_quadruped_full( "quadruped_full" ); static const fault_id fault_gun_blackpowder( "fault_gun_blackpowder" ); static const fault_id fault_gun_chamber_spent( "fault_gun_chamber_spent" ); @@ -547,7 +548,8 @@ double Creature::ranged_target_size() const { double stance_factor = 1.0; if( const Character *character = this->as_character() ) { - if( character->is_crouching() ) { + if( character->is_crouching() || ( character->has_effect( effect_quadruped_full ) && + character->is_running() ) ) { stance_factor = 0.6; } else if( character->is_prone() ) { stance_factor = 0.25; diff --git a/src/sounds.cpp b/src/sounds.cpp index fe296333eaf63..d33f51f613a13 100644 --- a/src/sounds.cpp +++ b/src/sounds.cpp @@ -92,6 +92,7 @@ static const itype_id fuel_type_muscle( "muscle" ); static const itype_id fuel_type_wind( "wind" ); static const itype_id itype_weapon_fire_suppressed( "weapon_fire_suppressed" ); +static const json_character_flag json_flag_HEARING_PROTECTION( "HEARING_PROTECTION" ); static const json_character_flag json_flag_PAIN_IMMUNE( "PAIN_IMMUNE" ); static const material_id material_bone( "bone" ); @@ -218,6 +219,7 @@ std::string enum_to_string( sounds::sound_t data ) switch ( data ) { case sounds::sound_t::background: return "background"; case sounds::sound_t::weather: return "weather"; + case sounds::sound_t::sensory: return "sensory"; case sounds::sound_t::music: return "music"; case sounds::sound_t::movement: return "movement"; case sounds::sound_t::speech: return "speech"; @@ -288,6 +290,7 @@ static bool is_provocative( sounds::sound_t category ) switch( category ) { case sounds::sound_t::background: case sounds::sound_t::weather: + case sounds::sound_t::sensory: case sounds::sound_t::music: case sounds::sound_t::activity: case sounds::sound_t::destructive_activity: @@ -509,6 +512,7 @@ static bool describe_sound( sounds::sound_t category, bool from_player_position return false; case sounds::sound_t::background: case sounds::sound_t::weather: + case sounds::sound_t::sensory: case sounds::sound_t::music: // detailed music descriptions are printed in iuse::play_music case sounds::sound_t::movement: @@ -527,6 +531,7 @@ static bool describe_sound( sounds::sound_t category, bool from_player_position switch( category ) { case sounds::sound_t::background: case sounds::sound_t::weather: + case sounds::sound_t::sensory: case sounds::sound_t::music: case sounds::sound_t::movement: case sounds::sound_t::activity: @@ -564,9 +569,11 @@ void sounds::process_sound_markers( Character *you ) // The felt volume of a sound is not affected by negative multipliers, such as already // deafened players or players with sub-par hearing to begin with. - const int felt_volume = static_cast( raw_volume * std::min( 1.0f, - volume_multiplier ) ) - distance_to_sound; - + int felt_volume = static_cast( raw_volume * std::min( 1.0f, + volume_multiplier ) ) - distance_to_sound; + if( you->has_flag( json_flag_HEARING_PROTECTION ) ) { + felt_volume /= 2; + } // Deafening is based on the felt volume, as a player may be too deaf to // hear the deafening sound but still suffer additional hearing loss. const bool is_sound_deafening = rng( felt_volume / 2, felt_volume ) >= 150; @@ -707,18 +714,35 @@ void sounds::process_sound_markers( Character *you ) } // Place footstep markers. - if( pos == you->pos() || you->sees( pos ) ) { - // If we are or can see the source, don't draw a marker. + if( pos == you->pos() || ( you->sees( pos ) && ( sound.category != sound_t::sensory ) ) ) { + // If we are or can see the source, don't draw a marker, except for sonar etc continue; } int err_offset; + if( ( heard_volume + distance_to_sound ) / distance_to_sound < 2 ) { - err_offset = 3; + err_offset = rng( 0, 3 ); } else if( ( heard_volume + distance_to_sound ) / distance_to_sound < 3 ) { - err_offset = 2; + err_offset = rng( 0, 2 ); } else { - err_offset = 1; + err_offset = rng( 0, 1 ); + } + + // Echolocation has to be fairly precise or it's worse than useless. + // However, it is never perfect. + if( sound.category == sound_t::sensory ) { + if( ( heard_volume + distance_to_sound ) / distance_to_sound < 2 ) { + err_offset = rng( 0, 3 ); + } else if( ( heard_volume + distance_to_sound ) / distance_to_sound < 3 ) { + err_offset = rng( 0, 2 ); + } else { + if( one_in( 3 ) ) { + err_offset = rng( 0, 1 ); + } else { + err_offset = 0; + } + } } // If Z-coordinate is different, draw even when you can see the source @@ -726,9 +750,10 @@ void sounds::process_sound_markers( Character *you ) // Enumerate the valid points the player *cannot* see. // Unless the source is on a different z-level, then any point is fine + // Also show sensory sounds like SONAR even if we can see the point. std::vector unseen_points; for( const tripoint &newp : get_map().points_in_radius( pos, err_offset ) ) { - if( diff_z || !you->sees( newp ) ) { + if( diff_z || sound.category == sound_t::sensory || !you->sees( newp ) ) { unseen_points.emplace_back( newp ); } } diff --git a/src/sounds.h b/src/sounds.h index cf4d164ae76a0..3975683d76b3f 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -23,6 +23,7 @@ namespace sounds enum class sound_t : int { background = 0, weather, + sensory, // Sonar etc. Ensures this sound will usually get a visual marker so the player can see it. music, movement, speech, diff --git a/src/trap.cpp b/src/trap.cpp index 5b2dee98a3c1b..a77de9344aa7c 100644 --- a/src/trap.cpp +++ b/src/trap.cpp @@ -21,6 +21,7 @@ #include "rng.h" #include "string_formatter.h" +static const flag_id json_flag_ECHOLOCATION_DETECTABLE( "ECHOLOCATION_DETECTABLE" ); static const flag_id json_flag_SONAR_DETECTABLE( "SONAR_DETECTABLE" ); static const proficiency_id proficiency_prof_spotting( "prof_spotting" ); @@ -246,11 +247,20 @@ bool trap::is_trivial_to_spot() const return visibility <= 0 && !is_always_invisible(); } +// SONAR refers to ground-penetrating sonar and detects traps buried in the ground bool trap::detected_by_ground_sonar() const { return has_flag( json_flag_SONAR_DETECTABLE ); } +// Echolocation refers to both bat-style echolocation and underwater SONAR, and +// detects traps which are solid and unburied objects, aboveground or underwater. +// Isn't fine enough to detect very small traps ie caltrops +bool trap::detected_by_echolocation() const +{ + return has_flag( json_flag_ECHOLOCATION_DETECTABLE ); +} + bool trap::detect_trap( const tripoint &pos, const Character &p ) const { // * Buried landmines, the silent killer, have a visibility of 10. diff --git a/src/trap.h b/src/trap.h index d435046120b8e..518d9d423ea27 100644 --- a/src/trap.h +++ b/src/trap.h @@ -239,6 +239,10 @@ struct trap { * Whether this kind of trap will be detected by ground sonar (e.g. via the bionic). */ bool detected_by_ground_sonar() const; + /** + * Whether this kind of trap will be detected by regular sonar ( it is not buried and it's a solid object ). + */ + bool detected_by_echolocation() const; /** Player has not yet seen the trap and returns the variable chance, at this moment, of whether the trap is seen or not. */ bool detect_trap( const tripoint &pos, const Character &p ) const; diff --git a/tools/spell_checker/dictionary.txt b/tools/spell_checker/dictionary.txt index 115bf98aedffe..53c6c83ef6072 100644 --- a/tools/spell_checker/dictionary.txt +++ b/tools/spell_checker/dictionary.txt @@ -376,6 +376,7 @@ boomin boonie booo booorrrring +boop bootable bootup boozeberry @@ -515,6 +516,7 @@ cere cerium cervine cestus +ch chachalaca chainmail chambering @@ -537,6 +539,7 @@ chestpiece chestplate chestplates chestwrap +chhk chicharrones chickenbot chickenwire @@ -551,6 +554,8 @@ chitin chitinous chitinworking chk +chkch +chkchh chlorination cholla chonker @@ -2302,6 +2307,7 @@ pictograms pictographic pidgeon piezomechanical +pii pileus pinita pinnata @@ -3098,6 +3104,7 @@ themm therizinosaurus thermochemistry thermoplastics +thermoreceptors theropod thescelosaurus thicknesses