Skip to content

Commit

Permalink
Merge pull request CleverRaven#72862 from anothersimulacrum/EOC-profi…
Browse files Browse the repository at this point in the history
…ciency

By default, EOCs train proficiencies normally
  • Loading branch information
Maleclypse authored Apr 8, 2024
2 parents ea8f34c + 812a5e3 commit 28db304
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 13 deletions.
11 changes: 8 additions & 3 deletions data/json/npcs/TALK_TEST.json
Original file line number Diff line number Diff line change
Expand Up @@ -1210,17 +1210,22 @@
{
"text": "Sets Test Proficiency learning done to 12 hours total.",
"topic": "TALK_DONE",
"effect": { "math": [ "u_proficiency('prof_test', 'format': 'time_spent')", "=", "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')", "=", "-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')", "=", "time('24h')" ] }
"effect": { "math": [ "u_proficiency('prof_test', 'format': 'time_spent', 'direct': true)", "=", "time('24h')" ] }
},
{
"text": "Learns Test Proficiency for 1h",
"topic": "TALK_DONE",
"effect": { "math": [ "u_proficiency('prof_test', 'format': 'time_spent')", "+=", "time('1h')" ] }
}
]
},
Expand Down
8 changes: 4 additions & 4 deletions data/mods/TEST_DATA/EOC.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)", "=", "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')", "=", "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')", "=", "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')", "=", "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)" ] }
]
Expand Down
2 changes: 1 addition & 1 deletion doc/NPCs.md
Original file line number Diff line number Diff line change
Expand Up @@ -1352,7 +1352,7 @@ _some functions support array arguments or kwargs, denoted with square brackets
| moon_phase() ||| N/A<br/>(global) | Returns current phase of the Moon. <pre>MOON_NEW = 0,<br/>WAXING_CRESCENT = 1,<br/>HALF_MOON_WAXING = 2,<br/>WAXING_GIBBOUS = 3,<br/>FULL = 4,<br/>WANING_GIBBOUS = 5,<br/>HALF_MOON_WANING = 6,<br/>WANING_CRESCENT = 7 |
| num_input(`s`/`v`,`d`/`v`) ||| N/A<br/>(global) | Prompt the player for a number.<br/>Arguments are Prompt text, Default Value:<br/>`"math": [ "u_value_to_set", "=", "num_input('Playstyle Perks Cost?', 4)" ]`|
| pain() ||| u, n | Return or set pain<br/> Example:<br/>`{ "math": [ "n_pain()", "=", "u_pain() + 9000" ] }`|
| proficiency(`s`/`v`) ||| u, n | Return or set proficiency<br/>Argument is proficiency ID.<br/><br/> Optional kwargs:<br/>`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).<br/><br/>Example:<br/>`{ "math": [ "u_proficiency('prof_intro_chemistry', 'format': 'percent')", "=", "50" ] }`|
| proficiency(`s`/`v`) ||| u, n | Return or set proficiency<br/>Argument is proficiency ID.<br/><br/> Optional kwargs:<br/>`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).<br/>`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.<br/><br/>Example:<br/>`{ "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.<br/>Argument is school ID.<br/><br/>Example:<br/>`"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.<br/>Argument is school ID.<br/><br/>Example:<br/>`{ "math": [ "u_school_level_adjustment('MAGUS')", "+=", "3"] }`|
| skill(`s`/`v`) ||| u, n | Return or set skill level<br/><br/>Example:<br/>`"condition": { "math": [ "u_skill('driving')", ">=", "5"] }`<br/>`"condition": { "math": [ "u_skill(someskill)", ">=", "5"] }`|
Expand Down
2 changes: 1 addition & 1 deletion src/character_proficiency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void Character::set_proficiency_practice( const proficiency_id &id, const time_d
return;
}

_proficiencies->practice( id, amount, 0.f, std::nullopt );
_proficiencies->set_time_practiced( id, amount );
}

std::vector<proficiency_id> Character::proficiencies_offered_to( const Character *guy ) const
Expand Down
24 changes: 22 additions & 2 deletions src/math_parser_diag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ bool is_beta( char scope )
}
}

constexpr bool is_true( double dbl )
{
return dbl >= 1 || float_equals( dbl, 1 );
}

template<typename T>
constexpr std::string_view _str_type_of()
{
Expand Down Expand Up @@ -1195,13 +1200,18 @@ std::function<void( dialogue &, double )> proficiency_ass( char scope,
std::vector<diag_value> const &params, diag_kwargs const &kwargs )
{
diag_value fmt_val( std::string{"time_spent"} );
diag_value direct_val( 0.0 );
if( kwargs.count( "format" ) != 0 ) {
fmt_val = *kwargs.at( "format" );
}
return [prof_value = params[0], fmt_val, beta = is_beta( scope )]( dialogue const & d,
if( kwargs.count( "direct" ) != 0 ) {
direct_val = *kwargs.at( "direct" );
}
return [prof_value = params[0], fmt_val, direct_val, beta = is_beta( scope )]( dialogue const & d,
double val ) {
proficiency_id prof( prof_value.str( d ) );
std::string const format = fmt_val.str( d );
bool const direct = is_true( direct_val.dbl( d ) );
int to_write = 0;
if( format == "percent" ) {
to_write = to_turns<int>( prof->time_to_learn() * val ) / 100;
Expand All @@ -1215,7 +1225,17 @@ std::function<void( dialogue &, double )> proficiency_ass( char scope,
}
to_write = val;
}
d.actor( beta )->set_proficiency_practiced_time( prof, to_write );
int before = to_turns<int>( d.actor( beta )->proficiency_practiced_time( prof ) );
int learned = to_write - before;
if( !direct && learned < 0 ) {
debugmsg( "For proficiency %s in dialogue, trying to learn negative without direct", prof.str() );
return 0;
}
if( !direct ) {
d.actor( beta )->train_proficiency_for( prof, learned );
} else {
d.actor( beta )->set_proficiency_practiced_time( prof, to_write );
}
return 0;
};
}
Expand Down
4 changes: 3 additions & 1 deletion src/math_parser_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,12 @@ constexpr double e_v = 2.7182818284590452354;
#endif
} // namespace math_constants

constexpr std::array<math_const, 3> constants{
constexpr std::array<math_const, 5> 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<std::string_view> tokenize( std::string_view str, std::string_view separators,
Expand Down
1 change: 1 addition & 0 deletions src/talker.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ class talker
return 0_seconds;
}
virtual void set_proficiency_practiced_time( const proficiency_id &, int ) {}
virtual void train_proficiency_for( const proficiency_id &, int ) {}
virtual std::vector<skill_id> skills_offered_to( const talker & ) const {
return {};
}
Expand Down
5 changes: 5 additions & 0 deletions src/talker_character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,11 @@ void talker_character::set_proficiency_practiced_time( const proficiency_id &pro
me_chr->set_proficiency_practiced_time( prof, turns );
}

void talker_character::train_proficiency_for( const proficiency_id &prof, int turns )
{
me_chr->practice_proficiency( prof, time_duration::from_seconds<int>( turns ) );
}

bool talker_character_const::has_effect( const efftype_id &effect_id, const bodypart_id &bp ) const
{
return me_chr_const->has_effect( effect_id, bp );
Expand Down
1 change: 1 addition & 0 deletions src/talker_character.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ class talker_character: public talker_cloner<talker_character, talker_character_
void set_spell_level( const spell_id &, int ) override;
void set_spell_exp( const spell_id &, int ) override;
void set_proficiency_practiced_time( const proficiency_id &prof, int turns ) override;
void train_proficiency_for( const proficiency_id &prof, int turns ) override;
void mutate( const int &highest_cat_chance, const bool &use_vitamins ) override;
void mutate_category( const mutation_category_id &mut_cat, const bool &use_vitamins ) override;
void mutate_towards( const trait_id &trait, const mutation_category_id &mut_cat,
Expand Down
52 changes: 51 additions & 1 deletion tests/npc_talk_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,7 @@ TEST_CASE( "npc_arithmetic", "[npc_talk]" )
Character &player_character = get_avatar();

d.add_topic( "TALK_TEST_ARITHMETIC" );
gen_response_lines( d, 31 );
gen_response_lines( d, 32 );

calendar::turn = calendar::turn_zero;
REQUIRE( calendar::turn == time_point( 0 ) );
Expand Down Expand Up @@ -1468,6 +1468,8 @@ TEST_CASE( "npc_arithmetic", "[npc_talk]" )
// "Sets Test Proficiency learning done to 24h."
effects = d.responses[30].success;
effects.apply( d );
add_msg( m_bad, "%s: %g", proficiency_prof_test.str(),
player_character.get_proficiency_practice( proficiency_prof_test ) );
CHECK( player_character.has_proficiency( proficiency_prof_test ) == true );
proficiencies_vector = player_character.learning_proficiencies();
CHECK( std::count( proficiencies_vector.begin(),
Expand All @@ -1492,6 +1494,54 @@ TEST_CASE( "npc_arithmetic", "[npc_talk]" )
proficiencies_vector.end(),
proficiency_prof_test ) == 0 );


// Proficency learning without 'direct': true is impacted by focus
const auto prof_xp = [&player_character]() {
return to_seconds<int>( player_character.get_proficiency_practiced_time( proficiency_prof_test ) );
};

// For 100 focus
player_character.set_focus( 100 );
// No starting XP
REQUIRE( prof_xp() == 0 );

// "Learns Test Proficiency for 1h"
effects = d.responses[31].success;
effects.apply( d );

int amt_100 = prof_xp();
CAPTURE( amt_100 );

CHECK( player_character.has_proficiency( proficiency_prof_test ) == false );
proficiencies_vector = player_character.learning_proficiencies();
CHECK( std::count( proficiencies_vector.begin(),
proficiencies_vector.end(),
proficiency_prof_test ) == 1 );

// Reset progress
player_character.set_proficiency_practice( proficiency_prof_test, 0_seconds );
REQUIRE( prof_xp() == 0 );

// For 5 focus
player_character.set_focus( 5 );

// "Learns Test Proficiency for 1h"
effects = d.responses[31].success;
effects.apply( d );

int amt_5 = prof_xp();
CAPTURE( amt_5 );

CHECK( player_character.has_proficiency( proficiency_prof_test ) == false );
proficiencies_vector = player_character.learning_proficiencies();
CHECK( std::count( proficiencies_vector.begin(),
proficiencies_vector.end(),
proficiency_prof_test ) == 1 );

// Simply check that they're less, don't need to get any fancier
CHECK( amt_5 < amt_100 );


// Teardown
player_character.remove_value( var_name );
}
Expand Down

0 comments on commit 28db304

Please sign in to comment.