diff --git a/data/json/npcs/TALK_TEST.json b/data/json/npcs/TALK_TEST.json index 75779c4b9e256..c3ebc235753e6 100644 --- a/data/json/npcs/TALK_TEST.json +++ b/data/json/npcs/TALK_TEST.json @@ -1210,17 +1210,17 @@ { "text": "Sets Test Proficiency learning done to 12 hours total.", "topic": "TALK_DONE", - "effect": { "math": [ "u_proficiency('prof_test', 'format': 'time_spent', 'direct': 'true')", "=", "time('12h')" ] } + "effect": { "math": [ "u_proficiency('prof_test', 'format': 'time_spent', 'direct': true)", "=", "time('12h')" ] } }, { "text": "Sets Test Proficiency learning done to -1.", "topic": "TALK_DONE", - "effect": { "math": [ "u_proficiency('prof_test', 'format': 'time_spent', 'direct': 'true')", "=", "-1" ] } + "effect": { "math": [ "u_proficiency('prof_test', 'format': 'time_spent', 'direct': true)", "=", "-1" ] } }, { "text": "Sets Test Proficiency learning done to 24h.", "topic": "TALK_DONE", - "effect": { "math": [ "u_proficiency('prof_test', 'format': 'time_spent', 'direct': 'true')", "=", "time('24h')" ] } + "effect": { "math": [ "u_proficiency('prof_test', 'format': 'time_spent', 'direct': true)", "=", "time('24h')" ] } }, { "text": "Learns Test Proficiency for 1h", diff --git a/data/mods/TEST_DATA/EOC.json b/data/mods/TEST_DATA/EOC.json index 1cb8566f9135f..fdb4692462f8f 100644 --- a/data/mods/TEST_DATA/EOC.json +++ b/data/mods/TEST_DATA/EOC.json @@ -338,15 +338,15 @@ "effect": [ { "set_string_var": "prof_test", "target_var": { "global_val": "prof_id" } }, { "math": [ "key_total_time_required", "=", "u_proficiency(prof_id, 'format': 'total_time_required')" ] }, - { "math": [ "u_proficiency(prof_id, 'direct': 'true')", "=", "50" ] }, + { "math": [ "u_proficiency(prof_id, 'direct': true)", "=", "50" ] }, { "math": [ "key_time_spent_50", "=", "u_proficiency(prof_id)" ] }, - { "math": [ "u_proficiency(prof_id, 'format': 'percent', 'direct': 'true')", "=", "50" ] }, + { "math": [ "u_proficiency(prof_id, 'format': 'percent', 'direct': true)", "=", "50" ] }, { "math": [ "key_percent_50", "=", "u_proficiency(prof_id, 'format': 'percent')" ] }, { "math": [ "key_percent_50_turn", "=", "u_proficiency(prof_id)" ] }, - { "math": [ "u_proficiency(prof_id, 'format': 'permille', 'direct': 'true')", "=", "50" ] }, + { "math": [ "u_proficiency(prof_id, 'format': 'permille', 'direct': true)", "=", "50" ] }, { "math": [ "key_permille_50", "=", "u_proficiency(prof_id, 'format': 'permille')" ] }, { "math": [ "key_permille_50_turn", "=", "u_proficiency(prof_id)" ] }, - { "math": [ "u_proficiency(prof_id, 'format': 'time_left', 'direct': 'true')", "=", "50" ] }, + { "math": [ "u_proficiency(prof_id, 'format': 'time_left', 'direct': true)", "=", "50" ] }, { "math": [ "key_time_left_50", "=", "u_proficiency(prof_id, 'format': 'time_left')" ] }, { "math": [ "key_time_left_50_turn", "=", "u_proficiency(prof_id)" ] } ] diff --git a/doc/NPCs.md b/doc/NPCs.md index 9590151e45579..b163f4f59dde5 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -1352,7 +1352,7 @@ _some functions support array arguments or kwargs, denoted with square brackets | moon_phase() | ✅ | ❌ | N/A
(global) | Returns current phase of the Moon.
MOON_NEW = 0,
WAXING_CRESCENT = 1,
HALF_MOON_WAXING = 2,
WAXING_GIBBOUS = 3,
FULL = 4,
WANING_GIBBOUS = 5,
HALF_MOON_WANING = 6,
WANING_CRESCENT = 7 | | num_input(`s`/`v`,`d`/`v`) | ✅ | ❌ | N/A
(global) | Prompt the player for a number.
Arguments are Prompt text, Default Value:
`"math": [ "u_value_to_set", "=", "num_input('Playstyle Perks Cost?', 4)" ]`| | pain() | ✅ | ✅ | u, n | Return or set pain
Example:
`{ "math": [ "n_pain()", "=", "u_pain() + 9000" ] }`| -| proficiency(`s`/`v`) | ✅ | ✅ | u, n | Return or set proficiency
Argument is proficiency ID.

Optional kwargs:
`format`: `s` - `percent` return or set how many percent done the learning is. `permille` does likewise for permille. `time_spent` return or set total time spent. `time_left` return or set the remaining time. `total_time_required` return total time required to train a given proficiency (read only).
`direct`: `s` - `false` (default) perform the adjustment by practicing the proficiency for the given amount of time. This will likely result in different values than specified. `true` perform the adjustment directly, bypassing other factors that may affect it.

Example:
`{ "math": [ "u_proficiency('prof_intro_chemistry', 'format': 'percent')", "=", "50" ] }`| +| proficiency(`s`/`v`) | ✅ | ✅ | u, n | Return or set proficiency
Argument is proficiency ID.

Optional kwargs:
`format`: `s` - `percent` return or set how many percent done the learning is. `permille` does likewise for permille. `time_spent` return or set total time spent. `time_left` return or set the remaining time. `total_time_required` return total time required to train a given proficiency (read only).
`direct`: `true`/`false`/`d` - false (default) perform the adjustment by practicing the proficiency for the given amount of time. This will likely result in different values than specified. `true` perform the adjustment directly, bypassing other factors that may affect it.

Example:
`{ "math": [ "u_proficiency('prof_intro_chemistry', 'format': 'percent')", "=", "50" ] }`| | school_level(`s`/`v`) | ✅ | ❌ | u, n | Return the highest level of spells known of that school.
Argument is school ID.

Example:
`"condition": { "math": [ "u_school_level('MAGUS')", ">=", "3"] }`| | school_level_adjustment(`s`/`v`) | ✅ | ✅ | u, n | Return or set temporary caster level adjustment. Only useable by EoCs that trigger on the event `opens_spellbook`. Old values will be reset to 0 before the event triggers. To avoid overwriting values from other EoCs, it is recommended to adjust the values here with `+=` or `-=` instead of setting it to an absolute value.
Argument is school ID.

Example:
`{ "math": [ "u_school_level_adjustment('MAGUS')", "+=", "3"] }`| | skill(`s`/`v`) | ✅ | ✅ | u, n | Return or set skill level

Example:
`"condition": { "math": [ "u_skill('driving')", ">=", "5"] }`
`"condition": { "math": [ "u_skill(someskill)", ">=", "5"] }`| diff --git a/src/math_parser_diag.cpp b/src/math_parser_diag.cpp index 0d57e8e4987de..146395375a472 100644 --- a/src/math_parser_diag.cpp +++ b/src/math_parser_diag.cpp @@ -66,6 +66,11 @@ bool is_beta( char scope ) } } +constexpr bool is_true( double dbl ) +{ + return dbl >= 1 || float_equals( dbl, 1 ); +} + template constexpr std::string_view _str_type_of() { @@ -1195,7 +1200,7 @@ std::function proficiency_ass( char scope, std::vector const ¶ms, diag_kwargs const &kwargs ) { diag_value fmt_val( std::string{"time_spent"} ); - diag_value direct_val( std::string{"false"} ); + diag_value direct_val( 0.0 ); if( kwargs.count( "format" ) != 0 ) { fmt_val = *kwargs.at( "format" ); } @@ -1206,7 +1211,7 @@ std::function proficiency_ass( char scope, double val ) { proficiency_id prof( prof_value.str( d ) ); std::string const format = fmt_val.str( d ); - std::string direct = direct_val.str( d ); + bool const direct = is_true( direct_val.dbl( d ) ); int to_write = 0; if( format == "percent" ) { to_write = to_turns( prof->time_to_learn() * val ) / 100; @@ -1222,14 +1227,11 @@ std::function proficiency_ass( char scope, } int before = to_turns( d.actor( beta )->proficiency_practiced_time( prof ) ); int learned = to_write - before; - if( direct != "true" && direct != "false" ) { - debugmsg( R"(Unknown direct value "%s" for proficiency, assuming "false")", direct ); - direct = "false"; - } else if( direct == "false" && learned < 0 ) { + if( !direct && learned < 0 ) { debugmsg( "For proficiency %s in dialogue, trying to learn negative without direct", prof.str() ); return 0; } - if( direct == "false" ) { + if( !direct ) { d.actor( beta )->train_proficiency_for( prof, learned ); } else { d.actor( beta )->set_proficiency_practiced_time( prof, to_write ); diff --git a/src/math_parser_func.h b/src/math_parser_func.h index a205790f76b9c..6c3a6febaed6e 100644 --- a/src/math_parser_func.h +++ b/src/math_parser_func.h @@ -171,10 +171,12 @@ constexpr double e_v = 2.7182818284590452354; #endif } // namespace math_constants -constexpr std::array constants{ +constexpr std::array constants{ math_const{ "π", math_constants::pi_v }, math_const{ "pi", math_constants::pi_v }, math_const{ "e", math_constants::e_v }, + math_const{ "true", 1 }, + math_const{ "false", 0 }, }; std::vector tokenize( std::string_view str, std::string_view separators, diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index f1b6e9ccc69b0..5c581c9e77bc7 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -1495,7 +1495,7 @@ TEST_CASE( "npc_arithmetic", "[npc_talk]" ) proficiency_prof_test ) == 0 ); - // Proficency learning without 'direct': 'true' is impacted by focus + // Proficency learning without 'direct': true is impacted by focus const auto prof_xp = [&player_character]() { return to_seconds( player_character.get_proficiency_practiced_time( proficiency_prof_test ) ); };