diff --git a/data/mods/TEST_DATA/EOC.json b/data/mods/TEST_DATA/EOC.json index 24ed549820a4b..b91527e9f607b 100644 --- a/data/mods/TEST_DATA/EOC.json +++ b/data/mods/TEST_DATA/EOC.json @@ -183,8 +183,12 @@ "type": "effect_on_condition", "id": "EOC_run_until_test", "effect": [ - { "set_condition": "to_test", "condition": { "math": [ "u_context", "<", "10" ] } }, - { "run_eoc_until": "EOC_until_nested", "condition": "to_test" } + { "math": [ "u_context", "=", "0" ] }, + { + "run_eoc_until": "EOC_until_nested", + "condition": { "math": [ "u_context", "<", "10000" ] }, + "iteration": 10000 + } ] }, { diff --git a/doc/EFFECT_ON_CONDITION.md b/doc/EFFECT_ON_CONDITION.md index 773430a263dcd..64fd9489de990 100644 --- a/doc/EFFECT_ON_CONDITION.md +++ b/doc/EFFECT_ON_CONDITION.md @@ -2153,8 +2153,8 @@ Run EoC multiple times, until specific condition would be met | Syntax | Optionality | Value | Info | | --- | --- | --- | --- | | "run_eoc_until" | **mandatory** | string or [variable object](#variable-object) | EoC that would be run multiple times | -| "condition" | **mandatory** | string or [variable object](#variable-object) | name of condition, that would be checked; doesn't support inline condition, so it should be specified in `set_condition` somewhere before the effect; **condition should return "false" to terminate the loop** | -| "iteration" | optional | int or [variable object](#variable-object) | default 100; amount of iteration, that is allowed to run; if amount of iteration exceed this number, EoC is stopped, and game sends the error message | +| "condition" | optional | [dialogue condition](#dialogue-conditions) | default a condition that always return true; **condition should return "false" to terminate the loop** | +| "iteration" | optional | int or [variable object](#variable-object) | default 100; max amount of iteration, that is allowed to run; if the condition always returns true, the EOC will run for this number of iterations.| ##### Valid talkers: @@ -2169,15 +2169,27 @@ Run EoC multiple times, until specific condition would be met "type": "effect_on_condition", "id": "EOC_run_until", "effect": [ - { "set_condition": "to_test", "condition": { "math": [ "my_variable", "<", "10" ] } }, - { "run_eoc_until": "EOC_until_nested", "condition": "to_test" } + { "run_eoc_until": "EOC_until_nested", "condition": { "math": [ "my_variable", "<", "10" ] } } ] }, { "type": "effect_on_condition", "id": "EOC_until_nested", "effect": [ { "u_spawn_item": "knife_combat" }, { "math": [ "my_variable", "++" ] } ] + } +``` +A loop of 10 iterations. +```json + { + "type": "effect_on_condition", + "id": "EOC_run_until", + "effect": { "run_eoc_until": "EOC_until_nested", "iteration": 10 } }, + { + "type": "effect_on_condition", + "id": "EOC_until_nested", + "effect": { "u_message": "!!!" } + } ``` ## Character effects diff --git a/src/effect_on_condition.cpp b/src/effect_on_condition.cpp index 682ff649ce6cc..cd3b19b1704d9 100644 --- a/src/effect_on_condition.cpp +++ b/src/effect_on_condition.cpp @@ -292,14 +292,16 @@ void effect_on_conditions::process_reactivate() g->queued_global_effect_on_conditions, d ); } -bool effect_on_condition::activate( dialogue &d ) const +bool effect_on_condition::activate( dialogue &d, bool require_callstack_check ) const { bool retval = false; - d.amend_callstack( "EOC: " + id.str() ); - if( d.get_callstack().size() > 5000 ) { - if( query_yn( string_format( _( "Possible infinite loop in eoc %s. Stop execution?" ), - id.str() ) ) ) { - return false; + if( require_callstack_check ) { + d.amend_callstack( "EOC: " + id.str() ); + if( d.get_callstack().size() > 5000 ) { + if( query_yn( string_format( _( "Possible infinite loop in eoc %s. Stop execution?" ), + id.str() ) ) ) { + return false; + } } } // each version needs a copy of the dialogue to pass down diff --git a/src/effect_on_condition.h b/src/effect_on_condition.h index 958f4e7a2545a..06742d03a8394 100644 --- a/src/effect_on_condition.h +++ b/src/effect_on_condition.h @@ -59,7 +59,7 @@ struct effect_on_condition { bool has_false_effect = false; event_type required_event; duration_or_var recurrence; - bool activate( dialogue &d ) const; + bool activate( dialogue &d, bool require_callstack_check = true ) const; bool check_deactivate( dialogue &d ) const; bool test_condition( dialogue &d ) const; void apply_true_effects( dialogue &d ) const; diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 3ce5638875e67..100f85a501cf5 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -4867,30 +4867,24 @@ talk_effect_fun_t::func f_run_eocs( const JsonObject &jo, std::string_view membe talk_effect_fun_t::func f_run_eoc_until( const JsonObject &jo, std::string_view member ) { effect_on_condition_id eoc = effect_on_conditions::load_inline_eoc( jo.get_member( member ), "" ); + std::function cond; + read_condition( jo, "condition", cond, true ); // The default result of this condition is true - str_or_var condition = get_str_or_var( jo.get_member( "condition" ), "condition" ); - - dbl_or_var iteration_count = get_dbl_or_var( jo, "iteration_count", false, 100 ); - - return [eoc, condition, iteration_count]( dialogue & d ) { - auto itt = d.get_conditionals().find( condition.evaluate( d ) ); - if( itt == d.get_conditionals().end() ) { - debugmsg( string_format( "No condition with the name %s", condition.evaluate( d ) ) ); - return; - } + dbl_or_var iteration_count = get_dbl_or_var( jo, "iteration", false, 100 ); + return [eoc, cond, iteration_count]( dialogue & d ) { int max_iteration = iteration_count.evaluate( d ); int curr_iteration = 0; - - while( itt->second( d ) ) { + // Amend the eoc to the callstack before the iteration. + // In the interation, the eoc doesn't need to be amended repeatedly in activate(). + d.amend_callstack( "EOC: " + eoc->id.str() ); + while( cond( d ) ) { curr_iteration++; if( curr_iteration > max_iteration ) { - debugmsg( string_format( "EOC loop ran for more instances than the max allowed: %d. Exiting loop.", - max_iteration ) ); break; } - eoc->activate( d ); + eoc->activate( d, false ); } }; } diff --git a/tests/eoc_test.cpp b/tests/eoc_test.cpp index 2fd9dcfd14d1b..866d0c85d1fcb 100644 --- a/tests/eoc_test.cpp +++ b/tests/eoc_test.cpp @@ -860,7 +860,7 @@ TEST_CASE( "EOC_run_until_test", "[eoc]" ) REQUIRE( globvars.get_global_value( "npctalk_var_key1" ).empty() ); CHECK( effect_on_condition_EOC_run_until_test->activate( d ) ); - CHECK( std::stod( globvars.get_global_value( "npctalk_var_key1" ) ) == Approx( 10 ) ); + CHECK( std::stod( globvars.get_global_value( "npctalk_var_key1" ) ) == Approx( 10000 ) ); } TEST_CASE( "EOC_run_with_test_expects", "[eoc]" )