Skip to content

Commit

Permalink
Synchronize training between teacher and students
Browse files Browse the repository at this point in the history
  • Loading branch information
dseguin committed Oct 6, 2021
1 parent a39dd4e commit 9815097
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 12 deletions.
3 changes: 2 additions & 1 deletion data/json/player_activities.json
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@
"type": "activity_type",
"activity_level": "ACTIVE_EXERCISE",
"verb": "teaching",
"based_on": "speed"
"based_on": "speed",
"no_resume": true
},
{
"id": "ACT_SOCIALIZE",
Expand Down
1 change: 1 addition & 0 deletions doc/NPCs.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ Effect | Description
`lead_to_safety` | The NPC will gain the LEAD attitude and give your character the mission of reaching safety.
`start_training` | The NPC will train your character in a skill or martial art. NOTE: the code currently requires that you initiate training by directing the player through `"topic": "TALK_TRAIN"` where the thing to be trained is selected. Initiating training outside of "TALK_TRAIN" will give an error.
`start_training_npc` | The NPC will accept training from the player in a skill or martial art.
`start_training_seminar` | Opens a dialog to select which characters will participate in the training seminar hosted by this NPC.
`companion_mission: role_string` | The NPC will offer you a list of missions for your allied NPCs, depending on the NPC's role.
`basecamp_mission` | The NPC will offer you a list of missions for your allied NPCs, depending on the local basecamp.
`bionic_install` | The NPC installs a bionic from your character's inventory onto your character, using very high skill, and charging you according to the operation's difficulty.
Expand Down
23 changes: 23 additions & 0 deletions src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2033,6 +2033,29 @@ void activity_handlers::teach_finish( player_activity *act, Character *you )

void activity_handlers::train_finish( player_activity *act, Character *you )
{
const std::vector<npc *> teachlist = g->get_npcs_if( [act]( const npc & n ) {
return n.getID().get_value() == act->index;
} );
Character *teacher = &get_player_character();
if( !teachlist.empty() ) {
teacher = teachlist.front();
}
if( teacher->activity.id() == ACT_TRAIN_TEACHER ) {
bool all_students_done = true;
g->get_npcs_if( [&]( const npc & n ) {
for( int st_id : teacher->activity.values ) {
if( n.getID().get_value() == st_id && n.activity.id() == ACT_TRAIN ) {
all_students_done = false;
break;
}
}
return false;
} );
if( all_students_done ) {
teacher->cancel_activity();
}
}

const skill_id sk( act->name );
if( sk.is_valid() ) {
const Skill &skill = sk.obj();
Expand Down
18 changes: 18 additions & 0 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,24 @@ bool game::cancel_activity_query( const std::string &text )
}
g->invalidate_main_ui_adaptor();
if( query_yn( "%s %s", text, u.activity.get_stop_phrase() ) ) {
if( u.activity.id() == activity_id( "ACT_TRAIN_TEACHER" ) ) {
for( npc &n : all_npcs() ) {
// Also cancel activities for students
for( const int st_id : u.activity.values ) {
if( n.getID().get_value() == st_id ) {
n.cancel_activity();
}
}
}
u.remove_effect( efftype_id( "asked_to_train" ) );
} else if( u.activity.id() == activity_id( "ACT_TRAIN" ) ) {
for( npc &n : all_npcs() ) {
// If the player is the only student, cancel the teacher's activity
if( n.getID().get_value() == u.activity.index && n.activity.values.size() == 1 ) {
n.cancel_activity();
}
}
}
u.cancel_activity();
u.clear_destination();
u.resume_backlog_activity();
Expand Down
9 changes: 5 additions & 4 deletions src/npctalk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ time_duration calc_skill_training_time( const npc &p, const skill_id &skill )
time_duration calc_skill_training_time_char( const Character &teacher, const Character &student,
const skill_id &skill )
{
return 1_minutes + 30_seconds * student.get_skill_level( skill ) -
1_seconds * teacher.get_skill_level( skill );
return 1_hours + 30_minutes * student.get_skill_level( skill ) -
1_minutes * teacher.get_skill_level( skill );
}

int calc_skill_training_cost( const npc &p, const skill_id &skill )
Expand All @@ -151,13 +151,14 @@ int calc_skill_training_cost_char( const Character &teacher, const Character &st

time_duration calc_proficiency_training_time( const proficiency_id &proficiency )
{
return std::min( 15_minutes, get_player_character().proficiency_training_needed( proficiency ) );
const Character &c = get_player_character();
return calc_proficiency_training_time( c, c, proficiency );
}

time_duration calc_proficiency_training_time( const Character &, const Character &student,
const proficiency_id &proficiency )
{
return std::min( 15_minutes, student.proficiency_training_needed( proficiency ) );
return std::min( 30_minutes, student.proficiency_training_needed( proficiency ) );
}

int calc_proficiency_training_cost( const Character &teacher, const Character &student,
Expand Down
14 changes: 7 additions & 7 deletions src/npctalk_funcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1123,8 +1123,8 @@ void talk_function::start_training_gen( Character &teacher, std::vector<Characte
debugmsg( "start_training with no valid skill or style set" );
return;
}
// use the slowest and most expensive option
cost = std::max( cost, tmp_cost );
// use the slowest common denominator and combine cost
cost += tmp_cost;
time = std::max( time, tmp_time );
}

Expand All @@ -1139,16 +1139,16 @@ void talk_function::start_training_gen( Character &teacher, std::vector<Characte
return;
}
}
player_activity act = player_activity( ACT_TRAIN, to_moves<int>( time ),
teacher.getID().get_value(), 0, name );
player_activity tact = player_activity( ACT_TRAIN_TEACHER, to_moves<int>( time ),
teacher.getID().get_value(), 0, name );
act.values.push_back( expert_multiplier );
tact.values.push_back( expert_multiplier );
teacher.assign_activity( tact );
for( Character *student : students ) {
player_activity act = player_activity( ACT_TRAIN, to_moves<int>( time ),
teacher.getID().get_value(), 0, name );
act.values.push_back( expert_multiplier );
student->assign_activity( act );
tact.values.push_back( student->getID().get_value() );
}
teacher.assign_activity( tact );

teacher.add_effect( effect_asked_to_train, 6_hours );
}
Expand Down

0 comments on commit 9815097

Please sign in to comment.