diff --git a/data/json/effects_on_condition/computer_eocs.json b/data/json/effects_on_condition/computer_eocs.json
index 99444938c5e06..6e7fa07b72ecd 100644
--- a/data/json/effects_on_condition/computer_eocs.json
+++ b/data/json/effects_on_condition/computer_eocs.json
@@ -48,13 +48,7 @@
"type": "effect_on_condition",
"id": "EOC_CHECK_MAP_CACHE",
"//": "todo: make it not reveal fungal towers and such? would require edits in reveal_map code, to accept blacklist of locations?",
- "condition": {
- "or": [
- { "compare_string": [ "has", { "npc_val": "map_cache" } ] },
- { "compare_string": [ "lack", { "npc_val": "map_cache" } ] },
- { "compare_string": [ "read", { "npc_val": "map_cache" } ] }
- ]
- },
+ "condition": { "or": [ { "compare_string": [ { "npc_val": "map_cache" }, "has", "lack", "read" ] } ] },
"false_effect": [ { "npc_add_var": "map_cache", "possible_values": [ "has", "lack" ] }, { "run_eocs": "EOC_CHECK_MAP_CACHE" } ],
"effect": [
{
diff --git a/data/json/effects_on_condition/nether_eocs/portal_storm_effect_on_condition.json b/data/json/effects_on_condition/nether_eocs/portal_storm_effect_on_condition.json
index 2fb293cd8e30e..6fe5428a3c4b1 100644
--- a/data/json/effects_on_condition/nether_eocs/portal_storm_effect_on_condition.json
+++ b/data/json/effects_on_condition/nether_eocs/portal_storm_effect_on_condition.json
@@ -1335,18 +1335,23 @@
{ "u_has_items": { "item": "nre_recorder", "charges": 1 } },
{
"or": [
- { "compare_string": [ "mon_hound_tindalos", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_darkman", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_zombie_phase_shrike", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_swarm_structure", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_better_half", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_hallucinator", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_archunk_strong", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_void_spider", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_XEDRA_officer", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_eigenspectre_3", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_eigenspectre_4", { "context_val": "victim_type" } ] },
- { "compare_string": [ "mon_living_vector", { "context_val": "victim_type" } ] }
+ {
+ "compare_string": [
+ { "context_val": "victim_type" },
+ "mon_hound_tindalos",
+ "mon_darkman",
+ "mon_zombie_phase_shrike",
+ "mon_swarm_structure",
+ "mon_better_half",
+ "mon_hallucinator",
+ "mon_archunk_strong",
+ "mon_void_spider",
+ "mon_XEDRA_officer",
+ "mon_eigenspectre_3",
+ "mon_eigenspectre_4",
+ "mon_living_vector"
+ ]
+ }
]
}
]
diff --git a/data/json/effects_on_condition/nether_eocs/vitrification_effect_on_condition.json b/data/json/effects_on_condition/nether_eocs/vitrification_effect_on_condition.json
index 93d909bbf5cc6..24bd25ad60a87 100644
--- a/data/json/effects_on_condition/nether_eocs/vitrification_effect_on_condition.json
+++ b/data/json/effects_on_condition/nether_eocs/vitrification_effect_on_condition.json
@@ -22,9 +22,14 @@
},
{
"type": "effect_on_condition",
- "id": "EOC_vitrified_farm_entry",
+ "id": "EOC_vitrified_farm_entry_event",
"eoc_type": "EVENT",
"required_event": "avatar_enters_omt",
+ "effect": [ { "run_eocs": "EOC_vitrified_farm_entry" } ]
+ },
+ {
+ "type": "effect_on_condition",
+ "id": "EOC_vitrified_farm_entry",
"condition": {
"and": [
{ "or": [ { "u_at_om_location": "unvitrified_farm_0" }, { "u_at_om_location": "unvitrified_orchard" } ] },
@@ -41,6 +46,12 @@
}
]
},
+ "false_effect": [
+ {
+ "if": { "not": { "u_has_trait": "NOT_GLASS" } },
+ "then": { "run_eocs": [ "EOC_vitrified_farm_entry" ], "time_in_future": "1 seconds" }
+ }
+ ],
"effect": [
{
"place_override": { "global_val": "place_name", "default_str": "Quiet Farmhouse" },
diff --git a/data/json/effects_on_condition/npc_eocs/generic_npc_eocs.json b/data/json/effects_on_condition/npc_eocs/generic_npc_eocs.json
index 768d765cf5e59..be83d7d05a8f4 100644
--- a/data/json/effects_on_condition/npc_eocs/generic_npc_eocs.json
+++ b/data/json/effects_on_condition/npc_eocs/generic_npc_eocs.json
@@ -386,20 +386,23 @@
"eoc_type": "EVENT",
"required_event": "avatar_moves",
"condition": "u_is_underwater",
+ "//": "I would assume that Mycus spores are a bit sticky to keep them from coming off, so this has a chance to be removed instead of a guarantee.",
"effect": [
{
- "run_eocs": {
- "id": "EOC_REMOVE_HARD_THINGS_CHECK",
- "global": false,
- "eoc_type": "EVENT",
- "required_event": "avatar_moves",
- "condition": { "x_in_y_chance": { "x": 1, "y": 10 } },
- "//": "I would assume that Mycus spores are a bit sticky to keep them from coming off, so this has a chance to be removed instead of a garuntee.",
- "effect": [ { "u_lose_effect": "spores" } ]
- }
+ "if": { "and": [ { "u_has_effect": "spores" }, { "x_in_y_chance": { "x": 1, "y": 10 } } ] },
+ "then": [
+ { "u_message": "You scrub your body extensively, and spores are finally gone.", "type": "good" },
+ { "u_lose_effect": "spores" }
+ ]
+ },
+ {
+ "if": { "u_has_effect": "boomered" },
+ "then": [ { "u_message": "You wash the bile from your face.", "type": "good" }, { "u_lose_effect": "boomered" } ]
},
- { "u_lose_effect": "boomered" },
- { "u_lose_effect": "corroding" }
+ {
+ "if": { "u_has_effect": "corroding" },
+ "then": [ { "u_message": "You wash the acid from your body.", "type": "good" }, { "u_lose_effect": "corroding" } ]
+ }
]
},
{
diff --git a/data/mods/TEST_DATA/effect_on_condition.json b/data/mods/TEST_DATA/effect_on_condition.json
index 4392085e23847..67baea0281c22 100644
--- a/data/mods/TEST_DATA/effect_on_condition.json
+++ b/data/mods/TEST_DATA/effect_on_condition.json
@@ -163,5 +163,48 @@
{ "set_string_var": "mixin fail alpha", "target_var": { "global_val": "alpha_name" } },
{ "set_string_var": "mixin fail beta", "target_var": { "global_val": "beta_name" } }
]
+ },
+ {
+ "type": "effect_on_condition",
+ "id": "EOC_compare_string_test",
+ "effect": [
+ { "if": { "compare_string": [ "yes", "yes" ] }, "then": { "math": [ "eoc_compare_string_test_1", "++" ] } },
+ { "if": { "compare_string": [ "yes", "no" ] }, "else": { "math": [ "eoc_compare_string_test_2", "++" ] } },
+ {
+ "if": { "compare_string": [ "yes", "yes", "yes" ] },
+ "then": { "math": [ "eoc_compare_string_test_3", "++" ] }
+ },
+ {
+ "if": { "compare_string": [ "yes", "yes", "no" ] },
+ "then": { "math": [ "eoc_compare_string_test_4", "++" ] }
+ },
+ { "if": { "compare_string": [ "yes", "no", "eh" ] }, "else": { "math": [ "eoc_compare_string_test_5", "++" ] } }
+ ]
+ },
+ {
+ "type": "effect_on_condition",
+ "id": "EOC_compare_string_match_all_test",
+ "effect": [
+ {
+ "if": { "compare_string_match_all": [ "yes", "yes" ] },
+ "then": { "math": [ "eoc_compare_string_match_all_test_1", "++" ] }
+ },
+ {
+ "if": { "compare_string_match_all": [ "yes", "no" ] },
+ "else": { "math": [ "eoc_compare_string_match_all_test_2", "++" ] }
+ },
+ {
+ "if": { "compare_string_match_all": [ "yes", "yes", "yes" ] },
+ "then": { "math": [ "eoc_compare_string_match_all_test_3", "++" ] }
+ },
+ {
+ "if": { "compare_string_match_all": [ "yes", "yes", "no" ] },
+ "else": { "math": [ "eoc_compare_string_match_all_test_4", "++" ] }
+ },
+ {
+ "if": { "compare_string_match_all": [ "yes", "no", "eh" ] },
+ "else": { "math": [ "eoc_compare_string_match_all_test_5", "++" ] }
+ }
+ ]
}
]
diff --git a/doc/EFFECT_ON_CONDITION.md b/doc/EFFECT_ON_CONDITION.md
index 8516b37059ef9..12ce2cb340d94 100644
--- a/doc/EFFECT_ON_CONDITION.md
+++ b/doc/EFFECT_ON_CONDITION.md
@@ -555,8 +555,8 @@ checks this var exists
```
### `compare_string`
-- type: pair of strings or [variable objects](#variable-object)
-- Compare two strings, and return true if strings are equal
+- type: array of strings or [variable objects](#variable-object)
+- Compare all strings, and return true if at least two of them match
#### Examples
checks if `victim_type` is `mon_zombie_phase_shrike`
@@ -569,6 +569,42 @@ checks is `victim_type` has `zombie` faction
{ "compare_string": [ "zombie", { "mutator": "mon_faction", "mtype_id": { "context_val": "victim_type" } } ] }
```
+Check if victim_type is any in the list
+```json
+"compare_string": [
+ { "context_val": "victim_type" },
+ "mon_hound_tindalos",
+ "mon_darkman",
+ "mon_zombie_phase_shrike",
+ "mon_swarm_structure",
+ "mon_better_half",
+ "mon_hallucinator",
+ "mon_archunk_strong",
+ "mon_void_spider",
+ "mon_XEDRA_officer",
+ "mon_eigenspectre_3",
+ "mon_eigenspectre_4",
+ "mon_living_vector"
+]
+```
+
+Check if `map_cache` contain value `has`, `lack` or `read`
+```json
+{ "compare_string": [ { "npc_val": "map_cache" }, "has", "lack", "read" ] }
+```
+
+### `compare_string_match_all`
+- type: array of strings or [variable objects](#variable-object)
+- Compare all strings, and return true if all of them match
+- For two strings the check is same as compare_string
+
+#### Examples
+
+Check if two variables are `yes`
+```json
+"compare_string": [ "yes", { "context_val": "some_context_should_be_yes" }, { "context_val": "some_another_context_also_should_be_yes" } ]
+```
+
### `u_profession`
- type: string or [variable object](#variable-object)
- Return true if player character has the given profession id or its "hobby" subtype
@@ -1358,7 +1394,7 @@ Every event EOC passes context vars with each of their key value pairs that the
| activates_mininuke | Triggers when any character arms a mininuke | { "character", `character_id` } | character / NONE |
| administers_mutagen | | { "character", `character_id` },
{ "technique", `mutagen_technique` }, | character / NONE |
| angers_amigara_horrors | Triggers when amigara horrors are spawned as part of a mine finale | NONE | avatar / NONE |
-| avatar_enters_omt | | { "pos", `tripoint` },
{ "oter_id", `oter_id` }, | avatar / NONE |
+| avatar_enters_omt | Triggers when player crosses the overmap boundary, including when player spawns | { "pos", `tripoint` },
{ "oter_id", `oter_id` }, | avatar / NONE |
| avatar_moves | | { "mount", `mtype_id` },
{ "terrain", `ter_id` },
{ "movement_mode", `move_mode_id` },
{ "underwater", `bool` },
{ "z", `int` }, | avatar / NONE |
| avatar_dies | | NONE | avatar / NONE |
| awakes_dark_wyrms | Triggers when `pedestal_wyrm` examine action is used | NONE | avatar / NONE |
diff --git a/src/condition.cpp b/src/condition.cpp
index e629dee38a9db..d4c49108b3f2a 100644
--- a/src/condition.cpp
+++ b/src/condition.cpp
@@ -1829,26 +1829,42 @@ conditional_t::func f_has_faction_trust( const JsonObject &jo, std::string_view
conditional_t::func f_compare_string( const JsonObject &jo, std::string_view member )
{
- str_or_var first;
- str_or_var second;
- JsonArray objects = jo.get_array( member );
- if( objects.size() != 2 ) {
- jo.throw_error( "incorrect number of values. Expected 2 in " + jo.str() );
- }
+ // return true if at least two strings match, OR
- if( objects.has_object( 0 ) ) {
- first = get_str_or_var( objects.next_value(), member, true );
- } else {
- first.str_val = objects.next_string();
+ std::vector values;
+ for( JsonValue jv : jo.get_array( member ) ) {
+ values.emplace_back( get_str_or_var( jv, member ) );
}
- if( objects.has_object( 1 ) ) {
- second = get_str_or_var( objects.next_value(), member, true );
- } else {
- second.str_val = objects.next_string();
+
+ return [values]( const_dialogue const & d ) {
+ std::unordered_set seen_values;
+ for( const str_or_var &val : values ) {
+ std::string evaluated_value = val.evaluate( d );
+ if( seen_values.count( evaluated_value ) > 0 ) {
+ return true;
+ }
+ seen_values.insert( evaluated_value );
+ }
+ return false;
+ };
+}
+
+conditional_t::func f_compare_string_match_all( const JsonObject &jo, std::string_view member )
+{
+ // return true if all strings match, AND
+ std::vector values;
+ for( JsonValue jv : jo.get_array( member ) ) {
+ values.emplace_back( get_str_or_var( jv, member ) );
}
- return [first, second]( const_dialogue const & d ) {
- return first.evaluate( d ) == second.evaluate( d );
+ return [values]( const_dialogue const & d ) {
+ std::string first_value = values[0].evaluate( d );
+ for( size_t i = 1; i < values.size(); ++i ) {
+ if( values[i].evaluate( d ) != first_value ) {
+ return false;
+ }
+ }
+ return true;
};
}
@@ -2628,6 +2644,7 @@ parsers = {
{"u_has_faction_trust", jarg::member | jarg::array, &conditional_fun::f_has_faction_trust },
{"math", jarg::member, &conditional_fun::f_math },
{"compare_string", jarg::member, &conditional_fun::f_compare_string },
+ {"compare_string_match_all", jarg::member, &conditional_fun::f_compare_string_match_all },
{"get_condition", jarg::member, &conditional_fun::f_get_condition },
{"test_eoc", jarg::member, &conditional_fun::f_test_eoc },
};
diff --git a/tests/eoc_test.cpp b/tests/eoc_test.cpp
index 3c2918c1c7a86..9bdca70916404 100644
--- a/tests/eoc_test.cpp
+++ b/tests/eoc_test.cpp
@@ -34,6 +34,10 @@ static const effect_on_condition_id effect_on_condition_EOC_attack_test( "EOC_at
static const effect_on_condition_id
effect_on_condition_EOC_combat_mutator_test( "EOC_combat_mutator_test" );
static const effect_on_condition_id
+effect_on_condition_EOC_compare_string_match_all_test( "EOC_compare_string_match_all_test" );
+static const effect_on_condition_id
+effect_on_condition_EOC_compare_string_test( "EOC_compare_string_test" );
+static const effect_on_condition_id
effect_on_condition_EOC_increment_var_var( "EOC_increment_var_var" );
static const effect_on_condition_id
effect_on_condition_EOC_item_activate_test( "EOC_item_activate_test" );
@@ -1414,6 +1418,49 @@ TEST_CASE( "EOC_string_test", "[eoc]" )
CHECK( get_avatar().get_value( "key3" ) == "nest4" );
}
+TEST_CASE( "EOC_compare_string_test", "[eoc]" )
+{
+ 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( "eoc_compare_string_test_1" ).empty() );
+ REQUIRE( globvars.get_global_value( "eoc_compare_string_test_2" ).empty() );
+ REQUIRE( globvars.get_global_value( "eoc_compare_string_test_3" ).empty() );
+ REQUIRE( globvars.get_global_value( "eoc_compare_string_test_4" ).empty() );
+ REQUIRE( globvars.get_global_value( "eoc_compare_string_test_5" ).empty() );
+
+ CHECK( effect_on_condition_EOC_compare_string_test->activate( d ) );
+
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_test_1" ) ) == Approx( 1 ) );
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_test_2" ) ) == Approx( 1 ) );
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_test_3" ) ) == Approx( 1 ) );
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_test_4" ) ) == Approx( 1 ) );
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_test_5" ) ) == Approx( 1 ) );
+
+ REQUIRE( globvars.get_global_value( "eoc_compare_string_match_all_test_1" ).empty() );
+ REQUIRE( globvars.get_global_value( "eoc_compare_string_match_all_test_2" ).empty() );
+ REQUIRE( globvars.get_global_value( "eoc_compare_string_match_all_test_3" ).empty() );
+ REQUIRE( globvars.get_global_value( "eoc_compare_string_match_all_test_4" ).empty() );
+ REQUIRE( globvars.get_global_value( "eoc_compare_string_match_all_test_5" ).empty() );
+
+ CHECK( effect_on_condition_EOC_compare_string_match_all_test->activate( d ) );
+
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_match_all_test_1" ) ) == Approx(
+ 1 ) );
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_match_all_test_2" ) ) == Approx(
+ 1 ) );
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_match_all_test_3" ) ) == Approx(
+ 1 ) );
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_match_all_test_4" ) ) == Approx(
+ 1 ) );
+ CHECK( std::stod( globvars.get_global_value( "eoc_compare_string_match_all_test_5" ) ) == Approx(
+ 1 ) );
+}
+
TEST_CASE( "EOC_run_eocs", "[eoc]" )
{
clear_avatar();