From ea17d8e67009ed34af8164acef9176fd23884499 Mon Sep 17 00:00:00 2001 From: Dillon Matchett Date: Mon, 8 May 2023 18:42:52 -0300 Subject: [PATCH] Mutators for EOCs (#65539) * Mutator EOCs * Update data/mods/TEST_DATA/EOC.json Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- data/mods/TEST_DATA/EOC.json | 15 +++++++++++++++ doc/NPCs.md | 12 ++++++++++++ src/condition.cpp | 26 ++++++++++++++++++++++++-- src/condition.h | 2 ++ src/dialogue_helpers.cpp | 3 +++ src/dialogue_helpers.h | 1 + tests/eoc_test.cpp | 17 +++++++++++++++++ 7 files changed, 74 insertions(+), 2 deletions(-) diff --git a/data/mods/TEST_DATA/EOC.json b/data/mods/TEST_DATA/EOC.json index d08ffceadfb37..50f4fb5ea6ff6 100644 --- a/data/mods/TEST_DATA/EOC.json +++ b/data/mods/TEST_DATA/EOC.json @@ -63,6 +63,21 @@ "condition": { "expects_vars": [ "npctalk_var_key1", "npctalk_var_key2", "npctalk_var_key3" ] }, "effect": [ { "math": [ "key1", "=", "_key1" ] }, { "math": [ "key2", "=", "_key2" ] }, { "math": [ "key3", "=", "_key3" ] } ] }, + { + "type": "effect_on_condition", + "id": "EOC_mutator_test", + "effect": [ + { "set_string_var": "mon_zombie", "target_var": { "context_val": "temp" } }, + { + "set_string_var": { "mutator": "mon_faction", "mtype_id": "mon_zombie" }, + "target_var": { "global_val": "key1" } + }, + { + "set_string_var": { "mutator": "mon_faction", "mtype_id": { "context_val": "temp" } }, + "target_var": { "global_val": "key2" } + } + ] + }, { "type": "effect_on_condition", "id": "EOC_math_test_context", diff --git a/doc/NPCs.md b/doc/NPCs.md index 6df248c799abf..95f274ee12d0c 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -1238,6 +1238,18 @@ Example: ] ``` +### Mutators +`mutators`: take in an ammount of data and provide you with a relevant string. This can be used to get information about items, monsters, etc. from the id, or other data. Mutators can be used anywhere that a string [variable object](#variable-object) can be used. Mutators take the form: +```json +{ "mutator": "MUTATOR_NAME", "REQUIRED_KEY1": "REQUIRED_VALUE1", ..., "REQUIRED_KEYn": "REQUIRED_VALUEn" } +``` + +#### List Of Mutators +Mutator Name | Required Keys | Description +--- | --- | --- +`"mon_faction"` | `mtype_id`: String or [variable object](#variable-object). | Returns the faction of the monster with mtype_id. + + ### Compare Numbers and Arithmetics *`arithmetic` and `compare_num` are deprecated in the long term. See [Math](#math) for the replacement.* diff --git a/src/condition.cpp b/src/condition.cpp index 1348aca1a1e64..b9b89675a50d0 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -226,8 +226,14 @@ str_or_var get_str_or_var( const JsonValue &jv, const std::string &member, bool if( jv.test_string() ) { ret_val.str_val = jv.get_string(); } else if( jv.test_object() ) { - ret_val.var_val = read_var_info( jv.get_object() ); - ret_val.default_val = default_val; + const JsonObject &jo = jv.get_object(); + if( jo.has_member( "mutator" ) ) { + // if we have a mutator then process that here. + ret_val.function = conditional_t::get_get_string( jo ); + } else { + ret_val.var_val = read_var_info( jo ); + ret_val.default_val = default_val; + } } else if( required ) { jv.throw_error( "No valid value for " + member ); } else { @@ -1410,6 +1416,22 @@ void conditional_t::set_math( const JsonObject &jo, const std::string_view membe }; } +template +std::function conditional_t::get_get_string( J const &jo ) +{ + if( jo.get_string( "mutator" ) == "mon_faction" ) { + str_or_var mtypeid = get_str_or_var( jo.get_member( "mtype_id" ), "mtype_id" ); + return [mtypeid]( const dialogue & d ) { + return static_cast( mtypeid.evaluate( d ) )->default_faction.str(); + }; + } + + jo.throw_error( "unrecognized string mutator in " + jo.str() ); + return []( const dialogue & ) { + return "INVALID"; + }; +} + template // NOLINTNEXTLINE(readability-function-cognitive-complexity): not my problem!! std::function conditional_t::get_get_dbl( J const &jo ) diff --git a/src/condition.h b/src/condition.h index ccde086299a65..f4184fbe9e159 100644 --- a/src/condition.h +++ b/src/condition.h @@ -197,6 +197,8 @@ struct conditional_t { void set_compare_num( const JsonObject &jo, std::string_view member ); void set_math( const JsonObject &jo, std::string_view member ); template + static std::function get_get_string( J const &jo ); + template static std::function get_get_dbl( J const &jo ); static std::function get_get_dbl( const std::string &value, const JsonObject &jo ); diff --git a/src/dialogue_helpers.cpp b/src/dialogue_helpers.cpp index 58b925d69c4ef..f7bace702cd39 100644 --- a/src/dialogue_helpers.cpp +++ b/src/dialogue_helpers.cpp @@ -39,6 +39,9 @@ std::string read_var_value( const var_info &info, const dialogue &d ) std::string str_or_var::evaluate( dialogue const &d ) const { + if( function.has_value() ) { + return function.value()( d ); + } if( str_val.has_value() ) { return str_val.value(); } diff --git a/src/dialogue_helpers.h b/src/dialogue_helpers.h index 4baa453a5e81a..d7ddf77e23a51 100644 --- a/src/dialogue_helpers.h +++ b/src/dialogue_helpers.h @@ -141,6 +141,7 @@ struct str_or_var { std::optional str_val; std::optional var_val; std::optional default_val; + std::optional> function; std::string evaluate( dialogue const &d ) const; }; diff --git a/tests/eoc_test.cpp b/tests/eoc_test.cpp index 8a5754b1057af..9ebade8919b21 100644 --- a/tests/eoc_test.cpp +++ b/tests/eoc_test.cpp @@ -33,6 +33,7 @@ static const effect_on_condition_id effect_on_condition_EOC_math_var( "EOC_math_var" ); static const effect_on_condition_id effect_on_condition_EOC_math_weighted_list( "EOC_math_weighted_list" ); +static const effect_on_condition_id effect_on_condition_EOC_mutator_test( "EOC_mutator_test" ); static const effect_on_condition_id effect_on_condition_EOC_run_with_test( "EOC_run_with_test" ); static const effect_on_condition_id effect_on_condition_EOC_run_with_test_expects_fail( "EOC_run_with_test_expects_fail" ); @@ -232,6 +233,22 @@ TEST_CASE( "EOC_context_test", "[eoc][math_parser]" ) CHECK( d.get_value( "npctalk_var_simple" ).empty() ); } +TEST_CASE( "EOC_mutator_test", "[eoc][math_parser]" ) +{ + clear_avatar(); + clear_map(); + + dialogue d( get_talker_for( get_avatar() ), std::make_unique() ); + global_variables &globvars = get_globals(); + globvars.clear_global_values(); + + REQUIRE( globvars.get_global_value( "npctalk_var_key1" ).empty() ); + REQUIRE( globvars.get_global_value( "npctalk_var_key2" ).empty() ); + CHECK( effect_on_condition_EOC_mutator_test->activate( d ) ); + CHECK( globvars.get_global_value( "npctalk_var_key1" ) == "zombie" ); + CHECK( globvars.get_global_value( "npctalk_var_key2" ) == "zombie" ); +} + TEST_CASE( "EOC_activity_ongoing", "[eoc][timed_event]" ) { clear_avatar();