Skip to content

Commit

Permalink
Infrastructure: NPC -> Character crafting get_crafting_helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
Brambor committed Oct 15, 2023
1 parent 8387988 commit be30264
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 85 deletions.
21 changes: 11 additions & 10 deletions src/activity_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1679,27 +1679,28 @@ bool read_activity_actor::player_read( avatar &you )
std::vector<std::string> cant_learn;

std::vector<Character *> learners;
for( npc *npc_learner : you.get_crafting_helpers() ) {
const book_mastery mastery = npc_learner->get_book_mastery( *book );
const bool morale_req = npc_learner->fun_to_read( *book ) || npc_learner->has_morale_to_read();
for( Character *learner : you.get_crafting_helpers() ) {
const book_mastery mastery = learner->get_book_mastery( *book );
const bool morale_req = learner->fun_to_read( *book ) || learner->has_morale_to_read();

if( npc_learner->is_deaf() && npc_learner != reader ) {
if( learner->is_deaf() && learner != reader ) {
continue;
}

if( // fun readers
( mastery == book_mastery::MASTERED && npc_learner->fun_to_read( *book ) ) ||
( mastery == book_mastery::MASTERED && learner->fun_to_read( *book ) )
// reading for experience
( mastery == book_mastery::LEARNING && morale_req ) ) {
learners.push_back( npc_learner->as_character() );
|| ( mastery == book_mastery::LEARNING && morale_req )
) {
learners.push_back( learner );
}
}

// caller should check if player
// can understand the book
learners.push_back( you.as_character() );

// NPCs can move while learning from a book
// Characters can move while learning from a book
// Check ID of all learners to avoid
// getting stuck in an infinite loop
bool learner_left = true;
Expand All @@ -1722,8 +1723,8 @@ bool read_activity_actor::player_read( avatar &you )
book->mark_chapter_as_read( *learner );
if( reading_for_skill ) {
if( !learner->is_avatar() ) {
const time_duration npc_read_time = you.time_to_read( *book, *reader, learner );
penalty = static_cast<double>( moves_total ) / to_moves<int>( npc_read_time );
const time_duration read_time = you.time_to_read( *book, *reader, learner );
penalty = static_cast<double>( moves_total ) / to_moves<int>( read_time );
}
} else {
continue; // reading for fun
Expand Down
2 changes: 1 addition & 1 deletion src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2691,7 +2691,7 @@ void activity_handlers::view_recipe_do_turn( player_activity *act, Character *yo
recipe_id id( act->name );
std::string itname;
const inventory &inven = you->crafting_inventory();
const std::vector<npc *> &helpers = you->get_crafting_helpers();
const std::vector<Character *> &helpers = you->get_crafting_helpers();
if( act->index != 0 ) {
// act->name is recipe_id
itname = id->result_name();
Expand Down
33 changes: 17 additions & 16 deletions src/avatar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,11 +461,11 @@ bool avatar::read( item_location &book, item_location ereader )
const std::string skill_name = skill ? skill.obj().name() : "";

// Find NPCs to join the study session:
std::map<npc *, std::string> learners;
std::map<Character *, std::string> learners;
//reading only for fun
std::map<npc *, std::string> fun_learners;
std::map<npc *, std::string> nonlearners;
for( npc *elem : get_crafting_helpers() ) {
std::map<Character *, std::string> fun_learners;
std::map<Character *, std::string> nonlearners;
for( Character *elem : get_crafting_helpers() ) {
const book_mastery mastery = elem->get_book_mastery( *book );
const bool morale_req = elem->fun_to_read( *book ) || elem->has_morale_to_read();

Expand Down Expand Up @@ -506,21 +506,22 @@ bool avatar::read( item_location &book, item_location ereader )
uilist menu;

// Some helpers to reduce repetition:
auto length = []( const std::pair<npc *, std::string> &elem ) {
auto length = []( const std::pair<Character *, std::string> &elem ) {
return utf8_width( elem.first->disp_name() ) + utf8_width( elem.second );
};

auto max_length = [&length]( const std::map<npc *, std::string> &m ) {
auto max_length = [&length]( const std::map<Character *, std::string> &m ) {
auto max_ele = std::max_element( m.begin(),
m.end(), [&length]( const std::pair<npc *, std::string> &left,
const std::pair<npc *, std::string> &right ) {
m.end(), [&length]( const std::pair<Character *, std::string> &left,
const std::pair<Character *, std::string> &right ) {
return length( left ) < length( right );
} );
return max_ele == m.end() ? 0 : length( *max_ele );
};

auto get_text =
[&]( const std::map<npc *, std::string> &m, const std::pair<npc *, std::string> &elem ) {
auto get_text = [&]( const std::map<Character *, std::string> &m,
const std::pair<Character *, std::string> &elem
) {
const int lvl = elem.first->get_knowledge_level( skill );
const std::string lvl_text = skill ? string_format( _( " | current level: %d" ), lvl ) : "";
const std::string name_text = elem.first->disp_name() + elem.second;
Expand Down Expand Up @@ -551,23 +552,23 @@ bool avatar::read( item_location &book, item_location ereader )
}

if( !learners.empty() ) {
add_header( _( "Read until this NPC gains a level:" ) );
for( const std::pair<npc *const, std::string> &elem : learners ) {
add_header( _( "Read until this Character gains a level:" ) );
for( const std::pair<Character *const, std::string> &elem : learners ) {
menu.addentry( 2 + elem.first->getID().get_value(), true, -1,
get_text( learners, elem ) );
}
}

if( !fun_learners.empty() ) {
add_header( _( "Reading for fun:" ) );
for( const std::pair<npc *const, std::string> &elem : fun_learners ) {
for( const std::pair<Character *const, std::string> &elem : fun_learners ) {
menu.addentry( -1, false, -1, get_text( fun_learners, elem ) );
}
}

if( !nonlearners.empty() ) {
add_header( _( "Not participating:" ) );
for( const std::pair<npc *const, std::string> &elem : nonlearners ) {
for( const std::pair<Character *const, std::string> &elem : nonlearners ) {
menu.addentry( -1, false, -1, get_text( nonlearners, elem ) );
}
}
Expand Down Expand Up @@ -620,15 +621,15 @@ bool avatar::read( item_location &book, item_location ereader )
add_msg( m_info, _( "%s studies with you." ), learners.begin()->first->disp_name() );
} else if( !learners.empty() ) {
const std::string them = enumerate_as_string( learners.begin(),
learners.end(), [&]( const std::pair<npc *, std::string> &elem ) {
learners.end(), [&]( const std::pair<Character *, std::string> &elem ) {
return elem.first->disp_name();
} );
add_msg( m_info, _( "%s study with you." ), them );
}

// Don't include the reader as it would be too redundant.
std::set<std::string> readers;
for( const std::pair<npc *const, std::string> &elem : fun_learners ) {
for( const std::pair<Character *const, std::string> &elem : fun_learners ) {
if( elem.first != reader ) {
readers.insert( elem.first->disp_name() );
}
Expand Down
15 changes: 7 additions & 8 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11568,7 +11568,7 @@ const Character *Character::get_book_reader( const item &book,
return nullptr;
}

// Check for conditions that disqualify us only if no NPCs can read to us
// Check for conditions that disqualify us only if no other Characters can read to us
if( condition & read_condition_result::ILLITERATE ) {
reasons.emplace_back( is_avatar() ? _( "You're illiterate!" ) : string_format(
_( "%s is illiterate!" ), disp_name() ) );
Expand All @@ -11588,17 +11588,17 @@ const Character *Character::get_book_reader( const item &book,
return nullptr;
}

//Check for NPCs to read for you, negates Illiterate and Far Sighted
//The fastest-reading NPC is chosen
//Check for other Characters to read for you, negates Illiterate and Far Sighted
//The fastest-reading Character is chosen
if( is_deaf() ) {
reasons.emplace_back( _( "Maybe someone could read that to you, but you're deaf!" ) );
return nullptr;
}

time_duration time_taken = time_duration::from_turns( INT_MAX );
auto candidates = get_crafting_helpers();
std::vector<Character *> candidates = get_crafting_helpers();

for( const npc *elem : candidates ) {
for( const Character *elem : candidates ) {
// Check for disqualifying factors:
condition = elem->check_read_condition( book );
if( condition & read_condition_result::ILLITERATE ) {
Expand Down Expand Up @@ -11847,9 +11847,8 @@ int Character::get_lift_str() const
int Character::get_lift_assist() const
{
int result = 0;
const std::vector<npc *> helpers = get_crafting_helpers();
for( const npc *np : helpers ) {
result += np->get_lift_str();
for( const Character *guy : get_crafting_helpers() ) {
result += guy->get_lift_str();
}
return result;
}
Expand Down
14 changes: 7 additions & 7 deletions src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -3363,9 +3363,9 @@ class Character : public Creature, public visitable
int last_batch;

// Returns true if the character knows the recipe, is near a book or device
// providing the recipe or a nearby NPC knows it.
// providing the recipe or a nearby Character knows it.
bool has_recipe( const recipe *r, const inventory &crafting_inv,
const std::vector<npc *> &helpers ) const;
const std::vector<Character *> &helpers ) const;
bool knows_recipe( const recipe *rec ) const;
void learn_recipe( const recipe *rec );
void forget_recipe( const recipe *rec );
Expand All @@ -3384,12 +3384,12 @@ class Character : public Creature, public visitable
/** Returns all recipes that are known from the books inside ereaders (either in inventory or nearby). */
recipe_subset get_recipes_from_ebooks( const inventory &crafting_inv ) const;
/**
* Returns all available recipes (from books and npc companions)
* Return all available recipes (from books and companions)
* @param crafting_inv Current available items to craft
* @param helpers List of NPCs that could help with crafting.
* @param helpers List of Characters that could help with crafting.
*/
recipe_subset get_available_recipes( const inventory &crafting_inv,
const std::vector<npc *> *helpers = nullptr ) const;
const std::vector<Character *> *helpers = nullptr ) const;
/**
* Returns the set of book types in crafting_inv that provide the
* given recipe.
Expand Down Expand Up @@ -3475,8 +3475,8 @@ class Character : public Creature, public visitable
*/
bool can_continue_craft( item &craft );
bool can_continue_craft( item &craft, const requirement_data &continue_reqs );
/** Returns nearby NPCs ready and willing to help with crafting. */
std::vector<npc *> get_crafting_helpers() const;
/** Return nearby Characters ready and willing to help with crafting. */
std::vector<Character *> get_crafting_helpers() const;
int get_num_crafting_helpers( int max ) const;
/**
* Handle skill gain for player and followers during crafting.
Expand Down
13 changes: 6 additions & 7 deletions src/character_crafting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include "inventory.h"
#include "item.h"
#include "itype.h"
#include "npc.h"
#include "pimpl.h"
#include "recipe.h"
#include "recipe_dictionary.h"
Expand All @@ -19,7 +18,7 @@
#include "value_ptr.h"

bool Character::has_recipe( const recipe *r, const inventory &crafting_inv,
const std::vector<npc *> &helpers ) const
const std::vector<Character *> &helpers ) const
{
return knows_recipe( r ) || get_available_recipes( crafting_inv, &helpers ).contains( r );
}
Expand Down Expand Up @@ -159,18 +158,18 @@ recipe_subset Character::get_recipes_from_ebooks( const inventory &crafting_inv
}

recipe_subset Character::get_available_recipes( const inventory &crafting_inv,
const std::vector<npc *> *helpers ) const
const std::vector<Character *> *helpers ) const
{
recipe_subset res( get_learned_recipes() );
res.include( get_recipes_from_books( crafting_inv ) );
res.include( get_recipes_from_ebooks( crafting_inv ) );

if( helpers != nullptr ) {
for( npc *np : *helpers ) {
for( Character *guy : *helpers ) {
// Directly form the helper's inventory
res.include( get_recipes_from_books( *np->inv ) );
res.include( get_recipes_from_books( *guy->inv ) );
// Being told what to do
res.include_if( np->get_learned_recipes(), [ this ]( const recipe & r ) {
res.include_if( guy->get_learned_recipes(), [ this ]( const recipe & r ) {
return get_knowledge_level( r.skill_used ) >= static_cast<int>( r.get_difficulty(
*this ) * 0.8f ); // Skilled enough to understand
} );
Expand Down Expand Up @@ -204,6 +203,6 @@ std::set<itype_id> Character::get_books_for_recipe( const inventory &crafting_in

int Character::get_num_crafting_helpers( int max ) const
{
std::vector<npc *> helpers = get_crafting_helpers();
std::vector<Character *> helpers = get_crafting_helpers();
return std::min( max, static_cast<int>( helpers.size() ) );
}
10 changes: 5 additions & 5 deletions src/construction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,10 +1072,10 @@ void complete_construction( Character *you )
};

award_xp( *you );
// Friendly NPCs gain exp from assisting or watching...
// TODO: NPCs watching other NPCs do stuff and learning from it
// Other friendly Characters gain exp from assisting or watching...
// TODO: Characters watching other Characters do stuff and learning from it
if( you->is_avatar() ) {
for( npc *&elem : get_avatar().get_crafting_helpers() ) {
for( Character *elem : get_avatar().get_crafting_helpers() ) {
if( elem->meets_skill_requirements( built ) ) {
add_msg( m_info, _( "%s assists you with the work…" ), elem->get_name() );
} else {
Expand Down Expand Up @@ -1148,7 +1148,7 @@ void complete_construction( Character *you )
// This comes after clearing the activity, in case the function interrupts
// activities
built.post_special( terp, *you );
// npcs will automatically resume backlog, players wont.
// Players will not automatically resume backlog, other Characters will.
if( you->is_avatar() && !you->backlog.empty() &&
you->backlog.front().id() == ACT_MULTIPLE_CONSTRUCTION ) {
you->backlog.clear();
Expand Down Expand Up @@ -2057,7 +2057,7 @@ int construction::adjusted_time() const
int final_time = time;
int assistants = 0;

for( npc *&elem : get_avatar().get_crafting_helpers() ) {
for( Character *elem : get_avatar().get_crafting_helpers() ) {
if( elem->meets_skill_requirements( *this ) ) {
assistants++;
}
Expand Down
Loading

0 comments on commit be30264

Please sign in to comment.