Skip to content

Commit

Permalink
Refactor start_training_gen() to process many Characters
Browse files Browse the repository at this point in the history
WIP towards group training
  • Loading branch information
dseguin committed Sep 20, 2021
1 parent 3df2dba commit b8e9ae6
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 103 deletions.
80 changes: 61 additions & 19 deletions src/npctalk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,16 @@ time_duration calc_skill_training_time_char( const Character &teacher, const Cha

int calc_skill_training_cost( const npc &p, const skill_id &skill )
{
if( p.is_player_ally() ) {
return 0;
}
return calc_skill_training_cost_char( get_player_character(), skill );
return calc_skill_training_cost_char( p, get_player_character(), skill );
}

int calc_skill_training_cost_char( const Character &student, const skill_id &skill )
int calc_skill_training_cost_char( const Character &teacher, const Character &student,
const skill_id &skill )
{
if( ( student.is_npc() && teacher.is_avatar() ) ||
( teacher.is_npc() && static_cast<const npc &>( teacher ).is_player_ally() ) ) {
return 0;
}
int skill_level = student.get_knowledge_level( skill );
return 1000 * ( 1 + skill_level ) * ( 1 + skill_level );
}
Expand All @@ -149,53 +151,93 @@ time_duration calc_proficiency_training_time( const proficiency_id &proficiency
return std::min( 15_minutes, get_player_character().proficiency_training_needed( proficiency ) );
}

int calc_proficiency_training_cost( const proficiency_id &proficiency )
time_duration calc_proficiency_training_time( const Character &, const Character &student,
const proficiency_id &proficiency )
{
return to_seconds<int>( calc_proficiency_training_time( proficiency ) );
return std::min( 15_minutes, student.proficiency_training_needed( proficiency ) );
}

int calc_proficiency_training_cost( const npc &p, const proficiency_id &proficiency )
int calc_proficiency_training_cost( const Character &teacher, const Character &student,
const proficiency_id &proficiency )
{
if( p.is_player_ally() ) {
if( ( student.is_npc() && teacher.is_avatar() ) ||
( teacher.is_npc() && static_cast<const npc &>( teacher ).is_player_ally() ) ) {
return 0;
}
return to_seconds<int>( calc_proficiency_training_time( proficiency ) );
}

return calc_proficiency_training_cost( proficiency );
int calc_proficiency_training_cost( const npc &p, const proficiency_id &proficiency )
{
return calc_proficiency_training_cost( p, get_player_character(), proficiency );
}


time_duration calc_ma_style_training_time( const npc &, const matype_id & /* id */ )
time_duration calc_ma_style_training_time( const npc &p, const matype_id &id )
{
return calc_ma_style_training_time( /*p, get_player_character()*/ );
return calc_ma_style_training_time( p, get_player_character(), id );
}

// TODO: all styles cost the same and take the same time to train,
// maybe add values to the ma_style class to makes this variable
// TODO: maybe move this function into the ma_style class? Or into the NPC class?
time_duration calc_ma_style_training_time( /*const Character &teacher, const Character &student*/ )
time_duration calc_ma_style_training_time( const Character &, const Character &,
const matype_id & )
{
return 30_minutes;
}

int calc_ma_style_training_cost( const npc &p, const matype_id & /* id */ )
int calc_ma_style_training_cost( const npc &p, const matype_id &id )
{
return calc_ma_style_training_cost( p, get_player_character(), id );
}

int calc_ma_style_training_cost( const Character &teacher, const Character &student,
const matype_id & )
{
if( p.is_player_ally() ) {
if( ( student.is_npc() && teacher.is_avatar() ) ||
( teacher.is_npc() && static_cast<const npc &>( teacher ).is_player_ally() ) ) {
return 0;
}
return calc_ma_style_training_cost( /*p, get_player_character()*/ );
return 800;
}

int calc_ma_style_training_cost( /*const Character &teacher, const Character &student*/ )
// quicker to learn with instruction as opposed to books.
// if this is a known spell, then there is a set time to gain some exp.
// if player doesn't know this spell, then the NPC will teach all of it
// which takes max 6 hours, min 3 hours.
// TODO: a system for NPCs to train new stuff in bits and pieces
// and remember the progress.
time_duration calc_spell_training_time( const Character &, const Character &student,
const spell_id &id )
{
return 800;
if( student.magic->knows_spell( id ) ) {
return 1_hours;
} else {
const int time_int = student.magic->time_to_learn_spell( student, id ) / 50;
return time_duration::from_seconds( clamp( time_int, 7200, 21600 ) );
}
}

int npc::calc_spell_training_cost( const bool knows, int difficulty, int level )
{
if( is_player_ally() ) {
return 0;
}
return calc_spell_training_cost_gen( knows, difficulty, level );
return ::calc_spell_training_cost_gen( knows, difficulty, level );
}

int calc_spell_training_cost( const Character &teacher, const Character &student,
const spell_id &id )
{
if( ( student.is_npc() && teacher.is_avatar() ) ||
( teacher.is_npc() && static_cast<const npc &>( teacher ).is_player_ally() ) ) {
return 0;
}
const spell &temp_spell = teacher.magic->get_spell( id );
const bool knows = student.magic->knows_spell( id );
return calc_spell_training_cost_gen( knows, temp_spell.get_difficulty(),
temp_spell.get_level() );
}

int calc_spell_training_cost_gen( const bool knows, int difficulty, int level )
Expand Down
24 changes: 17 additions & 7 deletions src/npctalk.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ void drop_stolen_item( npc & );
void lead_to_safety( npc & );
void start_training( npc & );
void start_training_npc( npc & );
void start_training_gen( Character &teacher, Character &student, teach_domain &d );
void start_training_gen( Character &teacher, std::vector<Character *> &student, teach_domain &d );

void wake_up( npc & );
void copy_npc_rules( npc &p );
Expand All @@ -113,15 +113,25 @@ 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 );
int calc_skill_training_cost( const npc &p, const skill_id &skill );
int calc_skill_training_cost_char( const Character &student, const skill_id &skill );
int calc_skill_training_cost_char( const Character &teacher, const Character &student,
const skill_id &skill );
time_duration calc_proficiency_training_time( const proficiency_id &proficiency );
time_duration calc_proficiency_training_time( const Character &teacher, const Character &student,
const proficiency_id &proficiency );
int calc_proficiency_training_cost( const npc &p, const proficiency_id &proficiency );
int calc_proficiency_training_cost( const proficiency_id &proficiency );
time_duration calc_ma_style_training_time( const npc &, const matype_id & /* id */ );
time_duration calc_ma_style_training_time( /*const Character &teacher, const Character &student*/ );
int calc_ma_style_training_cost( const npc &p, const matype_id & /* id */ );
int calc_ma_style_training_cost( /*const Character &teacher, const Character &student*/ );
int calc_proficiency_training_cost( const Character &teacher, const Character &student,
const proficiency_id &proficiency );
time_duration calc_ma_style_training_time( const npc &p, const matype_id &id );
time_duration calc_ma_style_training_time( const Character &teacher, const Character &student,
const matype_id &id );
int calc_ma_style_training_cost( const npc &p, const matype_id &id );
int calc_ma_style_training_cost( const Character &teacher, const Character &student,
const matype_id &id );
time_duration calc_spell_training_time( const Character &teacher, const Character &student,
const spell_id &id );
int calc_spell_training_cost_gen( const bool knows, int difficulty, int level );
int calc_spell_training_cost( const Character &teacher, const Character &student,
const spell_id &id );

const json_talk_topic *get_talk_topic( const std::string &id );

Expand Down
134 changes: 57 additions & 77 deletions src/npctalk_funcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,9 @@ void talk_function::start_training_npc( npc &p )
d.style = p.chatbin.style;
d.spell = p.chatbin.dialogue_spell;
d.prof = p.chatbin.proficiency;
start_training_gen( get_player_character(), p, d );
std::vector<Character *> students;
students.push_back( &p );
start_training_gen( get_player_character(), students, d );
}

void talk_function::start_training( npc &p )
Expand All @@ -1001,100 +1003,78 @@ void talk_function::start_training( npc &p )
d.style = p.chatbin.style;
d.spell = p.chatbin.dialogue_spell;
d.prof = p.chatbin.proficiency;
start_training_gen( p, get_player_character(), d );
std::vector<Character *> students;
students.push_back( &get_player_character() );
start_training_gen( p, students, d );
}

void talk_function::start_training_gen( Character &teacher, Character &student, teach_domain &d )
void talk_function::start_training_gen( Character &teacher, std::vector<Character *> &students,
teach_domain &d )
{
int cost;
int cost = 0;
time_duration time = 0_turns;
std::string name;
const skill_id &skill = d.skill;
const matype_id &style = d.style;
const spell_id &sp_id = d.spell;
const proficiency_id &proficiency = d.prof;
int expert_multiplier = 1;
if( skill != skill_id() &&
student.get_knowledge_level( skill ) < teacher.get_knowledge_level( skill ) ) {
if( teacher.is_npc() && student.is_avatar() ) {
cost = calc_skill_training_cost( static_cast<npc &>( teacher ), skill );
} else if( student.is_npc() && teacher.is_avatar() ) {
cost = 0;
} else {
cost = calc_skill_training_cost_char( student, skill );
}
time = calc_skill_training_time_char( teacher, student, skill );
name = skill.str();
} else if( style != matype_id() &&
!student.martial_arts_data->has_martialart( style ) ) {
if( teacher.is_npc() && student.is_avatar() ) {
cost = calc_ma_style_training_cost( static_cast<npc &>( teacher ), style );
time = calc_ma_style_training_time( static_cast<npc &>( teacher ), style );
} else if( student.is_npc() && teacher.is_avatar() ) {
cost = 0;
time = calc_ma_style_training_time( /*teacher, student*/ );
} else {
cost = calc_ma_style_training_cost( /*teacher, student*/ );
time = calc_ma_style_training_time( /*teacher, student*/ );
}
name = style.str();
// already checked if can learn this spell in npctalk.cpp
} else if( sp_id != spell_id() ) {
const spell &temp_spell = teacher.magic->get_spell( sp_id );
const bool knows = student.magic->knows_spell( sp_id );
if( teacher.is_npc() && student.is_avatar() ) {
cost = static_cast<npc &>( teacher ).calc_spell_training_cost( knows,
temp_spell.get_difficulty(), temp_spell.get_level() );
} else if( student.is_npc() && teacher.is_avatar() ) {
cost = 0;
} else {
cost = calc_spell_training_cost_gen( knows, temp_spell.get_difficulty(),
temp_spell.get_level() );
bool player_is_student = false;

for( Character *student : students ) {
if( student->is_avatar() ) {
player_is_student = true;
}
name = temp_spell.id().str();
expert_multiplier = knows ? temp_spell.get_level() -
student.magic->get_spell( sp_id ).get_level() : 1;
// quicker to learn with instruction as opposed to books.
// if this is a known spell, then there is a set time to gain some exp.
// if player doesn't know this spell, then the NPC will teach all of it
// which takes max 6 hours, min 3 hours.
// TODO: a system for NPCs to train new stuff in bits and pieces
// and remember the progress.
if( knows ) {
time = 1_hours;
int tmp_cost = 0;
time_duration tmp_time = 0_turns;
if( skill != skill_id() &&
student->get_knowledge_level( skill ) < teacher.get_knowledge_level( skill ) ) {
tmp_cost = calc_skill_training_cost_char( teacher, *student, skill );
tmp_time = calc_skill_training_time_char( teacher, *student, skill );
name = skill.str();
} else if( style != matype_id() &&
!student->martial_arts_data->has_martialart( style ) ) {
tmp_cost = calc_ma_style_training_cost( teacher, *student, style );
tmp_time = calc_ma_style_training_time( teacher, *student, style );
name = style.str();
} else if( sp_id != spell_id() ) {
// already checked if can learn this spell in npctalk.cpp
tmp_cost = calc_spell_training_cost( teacher, *student, sp_id );
tmp_time = calc_spell_training_time( teacher, *student, sp_id );
name = sp_id.str();
const spell &temp_spell = teacher.magic->get_spell( sp_id );
const bool knows = student->magic->knows_spell( sp_id );
expert_multiplier = knows ? temp_spell.get_level() -
student->magic->get_spell( sp_id ).get_level() : 1;
} else if( proficiency != proficiency_id() ) {
tmp_cost = calc_proficiency_training_cost( teacher, *student, proficiency );
tmp_time = calc_proficiency_training_time( teacher, *student, proficiency );
name = proficiency.str();
} else {
const int time_int = student.magic->time_to_learn_spell( student, sp_id ) / 50;
time = time_duration::from_seconds( clamp( time_int, 7200, 21600 ) );
debugmsg( "start_training with no valid skill or style set" );
return;
}

} else if( proficiency != proficiency_id() ) {
name = proficiency.str();
if( teacher.is_npc() && student.is_avatar() ) {
cost = calc_proficiency_training_cost( static_cast<npc &>( teacher ), proficiency );
} else if( student.is_npc() && teacher.is_avatar() ) {
cost = 0;
} else {
cost = calc_proficiency_training_cost( proficiency );
// use the slowest and most expensive option
cost = std::max( cost, tmp_cost );
time = std::max( time, tmp_time );
}

if( !teacher.is_avatar() ) {
npc &p = static_cast<npc &>( teacher );
mission *miss = p.chatbin.mission_selected;
const character_id &pid = get_player_character().getID();
if( player_is_student && miss != nullptr &&
miss->get_assigned_player_id() == pid && miss->is_complete( pid ) ) {
clear_mission( p );
} else if( !npc_trading::pay_npc( p, cost ) ) {
return;
}
time = calc_proficiency_training_time( proficiency );
} else {
debugmsg( "start_training with no valid skill or style set" );
return;
}

npc &p = static_cast<npc &>( teacher.is_avatar() ? student : teacher );
mission *miss = p.chatbin.mission_selected;
if( miss != nullptr && miss->get_assigned_player_id() == student.getID() &&
miss->is_complete( student.getID() ) ) {
clear_mission( p );
} else if( !npc_trading::pay_npc( p, cost ) ) {
return;
}
player_activity act = player_activity( ACT_TRAIN, to_moves<int>( time ),
teacher.getID().get_value(), 0, name );
act.values.push_back( expert_multiplier );
if( !teacher.is_avatar() && !student.is_avatar() ) {
student.assign_activity( act );
if( !teacher.is_avatar() && !player_is_student ) {
teacher.assign_activity( act );
} else {
get_player_character().assign_activity( act );
}
Expand Down

0 comments on commit b8e9ae6

Please sign in to comment.