diff --git a/data/json/monsters/mammal.json b/data/json/monsters/mammal.json index e3efb7f4b738..60c32f01e09f 100644 --- a/data/json/monsters/mammal.json +++ b/data/json/monsters/mammal.json @@ -1848,7 +1848,7 @@ "fear_triggers": [ "FIRE" ], "death_function": [ "NORMAL" ], "regenerates": 10, - "regeneration_modifiers": [ [ "onfire", -0.5 ], [ "corroding", -0.4 ] ], + "regeneration_modifiers": [ { "effect": "onfire", "base_mod": -0.3, "scaling_mod": -0.1 }, { "effect": "corroding", "base_mod": -0.4 } ], "regen_morale": true, "flags": [ "ATTACKMON", "BLEED", "BORES", "CAN_DIG", "HEARS", "KEENNOSE", "PATH_AVOID_DANGER_1", "SMELLS", "WARM" ], "//": "Reinsert GOODHEARING when z-level tunneling is possible." diff --git a/data/json/monsters/misc.json b/data/json/monsters/misc.json index f4e00411f92c..997d28e5ef98 100644 --- a/data/json/monsters/misc.json +++ b/data/json/monsters/misc.json @@ -20,7 +20,7 @@ "harvest": "exempt", "death_function": [ "MELT" ], "regenerates": 50, - "regeneration_modifiers": [ [ "onfire", -0.5 ], [ "corroding", -0.8 ] ], + "regeneration_modifiers": [ { "effect": "onfire", "base_mod": -0.3, "scaling_mod": -0.15 }, { "effect": "corroding", "base_mod": -0.8 } ], "flags": [ "IMMOBILE", "NOT_HALLUCINATION", "FILTHY" ] }, { diff --git a/data/json/monsters/mutant_human.json b/data/json/monsters/mutant_human.json index bb2f5b8b1c68..905754ddc6f3 100644 --- a/data/json/monsters/mutant_human.json +++ b/data/json/monsters/mutant_human.json @@ -74,7 +74,7 @@ "death_drops": "mon_mutant_experimental_death_drops", "upgrades": { "half_life": 50, "into": "mon_mutant_evolved" }, "regenerates": 1, - "regeneration_modifiers": [ [ "onfire", -1.0 ], [ "corroding", -1.0 ] ], + "regeneration_modifiers": [ { "effect": "onfire", "base_mod": -1.0 }, { "effect": "corroding", "base_mod": -1.0 } ], "regen_morale": true, "flags": [ "SEES", "HEARS", "SMELLS", "KEENNOSE", "WARM", "BLEED", "BASHES", "PATH_AVOID_DANGER_2" ] }, @@ -113,7 +113,7 @@ ], "death_drops": "mon_mutant_evolved_death_drops", "regenerates": 1, - "regeneration_modifiers": [ [ "onfire", -1.0 ], [ "corroding", -1.0 ] ], + "regeneration_modifiers": [ { "effect": "onfire", "base_mod": -1.0 }, { "effect": "corroding", "base_mod": -1.0 } ], "regen_morale": true, "flags": [ "SEES", diff --git a/data/json/monsters/nether.json b/data/json/monsters/nether.json index 4656782e2afc..cb9363593eb1 100644 --- a/data/json/monsters/nether.json +++ b/data/json/monsters/nether.json @@ -733,7 +733,7 @@ "special_attacks": [ [ "PARROT", 40 ] ], "death_function": [ "MELT" ], "regenerates": 50, - "regeneration_modifiers": [ [ "onfire", -0.5 ] ], + "regeneration_modifiers": [ { "effect": "onfire", "base_mod": -0.3, "scaling_mod": -0.15 } ], "regen_morale": true, "flags": [ "SEES", "SMELLS", "SWIMS", "PLASTIC", "SLUDGEPROOF", "ACID_BLOOD", "ACIDPROOF", "NOHEAD", "ABSORBS_SPLITS", "NOGIB" ] }, diff --git a/data/json/monsters/slugs.json b/data/json/monsters/slugs.json index 2b3ed22660aa..ee4122a3c6ee 100644 --- a/data/json/monsters/slugs.json +++ b/data/json/monsters/slugs.json @@ -27,7 +27,7 @@ "harvest": "exempt", "death_function": [ "MELT" ], "regenerates": 50, - "regeneration_modifiers": [ [ "onfire", -0.6 ], [ "corroding", -0.3 ] ], + "regeneration_modifiers": [ { "effect": "onfire", "base_mod": -0.3, "scaling_mod": -0.2 }, { "effect": "corroding", "base_mod": -0.3 } ], "flags": [ "NOHEAD", "SEES", "POISON", "HEARS", "SMELLS", "SLUDGEPROOF", "SLUDGETRAIL", "SWIMS", "FLAMMABLE", "NOGIB" ] }, { diff --git a/data/json/monsters/zed_fusion.json b/data/json/monsters/zed_fusion.json index 9d398d2a6aeb..eaae1e7bc51d 100644 --- a/data/json/monsters/zed_fusion.json +++ b/data/json/monsters/zed_fusion.json @@ -60,7 +60,7 @@ }, "death_function": [ "NORMAL" ], "regenerates": 1, - "regeneration_modifiers": [ [ "onfire", -1 ], [ "corroding", -1 ] ], + "regeneration_modifiers": [ { "effect": "onfire", "base_mod": -1.0 }, { "effect": "corroding", "base_mod": -1.0 } ], "flags": [ "SEES", "HEARS", diff --git a/doc/MONSTERS.md b/doc/MONSTERS.md index 6edaff92d51f..05dca7d49e0e 100644 --- a/doc/MONSTERS.md +++ b/doc/MONSTERS.md @@ -257,6 +257,13 @@ What field the monster emits and how often it does so. Time duration can use str Number of hitpoints regenerated per turn. +## "regeneration_modifiers" +( array of objects consisting of effect, base_mod (float) and scaling_mod (float), optional ) +"regeneration_modifiers": [ { "effect": "on_fire", "base_mod": -0.3, "scaling_mod": -0.15 } ], + +What effects (if any) affect the monster's regeneration positively/negatively. +The mods stack additively (Intensity 2 on_fire produces a multiplier of 0.45) but are applied multiplicatively. + ## "regenerates_in_dark" (boolean, optional) diff --git a/src/monster.cpp b/src/monster.cpp index 9aabc3f10ce0..18a6c9946708 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -2530,18 +2530,23 @@ void monster::process_effects_internal() //If this monster has the ability to heal in combat, do it now. int regeneration_amount = type->regenerates; + float regen_multiplier = 0; //Apply effect-triggered regeneration modifiers for( const auto ®eneration_modifier : type->regeneration_modifiers ) { if( has_effect( regeneration_modifier.first ) ) { - regeneration_amount *= 1 + regeneration_modifier.second; + effect &e = get_effect( regeneration_modifier.first ); + regen_multiplier = 1.00 + regeneration_modifier.second.base_modifier + + ( e.get_intensity() - 1 ) * regeneration_modifier.second.scale_modifier; + regeneration_amount = round( regeneration_amount * regen_multiplier ); } } //Prevent negative regeneration if( regeneration_amount < 0 ) { regeneration_amount = 0; } - const int healed_amount = heal( regeneration_amount ); - if( healed_amount > 0 && one_in( 2 ) ) { + const int healed_amount = heal( round( regeneration_amount ) ); + if( healed_amount > 0 && one_in( 2 ) && g->u.sees( *this ) ) { + add_msg( m_debug, ( "Regen: %s" ), healed_amount ); std::string healing_format_string; if( healed_amount >= 50 ) { healing_format_string = _( "The %s is visibly regenerating!" ); diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 0b1785494a75..641f58cdf4f1 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -1152,22 +1152,22 @@ void mtype::remove_special_attacks( const JsonObject &jo, const std::string &mem } } -void mtype::add_regeneration_modifier( JsonArray inner, const std::string & ) +void mtype::add_regeneration_modifier( JsonObject inner, const std::string & ) { - const std::string effect_name = inner.get_string( 0 ); + const std::string effect_name = inner.get_string( "effect" ); const efftype_id effect( effect_name ); //TODO: if invalid effect, throw error // inner.throw_error( "Invalid regeneration_modifiers" ); if( regeneration_modifiers.count( effect ) > 0 ) { regeneration_modifiers.erase( effect ); - if( test_mode ) { - debugmsg( "%s specifies more than one regeneration modifer for effect %s, ignoring all but the last", - id.c_str(), effect_name ); - } + debugmsg( "%s specifies more than one regeneration modifer for effect %s, ignoring all but the last", + id.c_str(), effect_name ); } - float amount = inner.get_float( 1 ); - regeneration_modifiers.emplace( effect, amount ); + const float base_mod = inner.get_float( "base_mod", 0.0f ); + const float scaling_mod = inner.get_float( "scaling_mod", 0.0f ); + + regeneration_modifiers.emplace( effect, regen_modifier{ base_mod, scaling_mod } ); } void mtype::add_regeneration_modifiers( const JsonObject &jo, const std::string &member, @@ -1178,13 +1178,13 @@ void mtype::add_regeneration_modifiers( const JsonObject &jo, const std::string } for( const JsonValue entry : jo.get_array( member ) ) { - if( entry.test_array() ) { - add_regeneration_modifier( entry.get_array(), src ); + if( entry.test_object() ) { + add_regeneration_modifier( entry.get_object(), src ); // TODO: add support for regeneration_modifer objects //} else if ( entry.test_object() ) { // add_regeneration_modifier( entry.get_object(), src ); } else { - entry.throw_error( "array element is not an array " ); + entry.throw_error( "array element is not an object " ); } } } diff --git a/src/mtype.h b/src/mtype.h index 7431a56aed41..8796bd434639 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -200,6 +200,11 @@ struct mon_effect_data { chance( nchance ), permanent( perm ) {} }; +struct regen_modifier { + float base_modifier; + float scale_modifier; +}; + struct mtype { private: friend class MonsterGenerator; @@ -229,7 +234,7 @@ struct mtype { void remove_regeneration_modifiers( const JsonObject &jo, const std::string &member_name, const std::string &src ); - void add_regeneration_modifier( JsonArray inner, const std::string &src ); + void add_regeneration_modifier( JsonObject inner, const std::string &src ); public: mtype_id id; @@ -267,7 +272,7 @@ struct mtype { // Number of hitpoints regenerated per turn. int regenerates = 0; // Effects that can modify regeneration - std::map regeneration_modifiers; + std::map regeneration_modifiers; // Monster regenerates very quickly in poorly lit tiles. bool regenerates_in_dark = false; // Will stop fleeing if at max hp, and regen anger and morale.