Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPC worker downtime - wandering and sitting on chairs #37330

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/activity_item_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
struct construction_category;

void cancel_aim_processing();

//Generic activity: maximum search distance for zones, constructions, etc.
const int ACTIVITY_SEARCH_DISTANCE = 60;

Expand Down Expand Up @@ -1477,7 +1476,8 @@ static activity_reason_info can_do_activity_there( const activity_id &act, playe
return activity_reason_info::fail( NO_ZONE );
}
if( act == ACT_TIDY_UP ) {
if( mgr.has_near( z_loot_unsorted, g->m.getabs( src_loc ), distance ) ) {
if( mgr.has_near( z_loot_unsorted, g->m.getabs( src_loc ), distance ) ||
mgr.has_near( z_camp_storage, g->m.getabs( src_loc ), distance ) ) {
return activity_reason_info::ok( CAN_DO_FETCH );
}
return activity_reason_info::fail( NO_ZONE );
Expand Down Expand Up @@ -1565,6 +1565,22 @@ static activity_reason_info can_do_activity_there( const activity_id &act, playe
return activity_reason_info::fail( NO_ZONE );
}

static void add_basecamp_storage_to_loot_zone_list( zone_manager &mgr, const tripoint &src_loc,
player &p, std::vector<tripoint> &loot_zone_spots, std::vector<tripoint> &combined_spots )
{
if( npc *const guy = dynamic_cast<npc *>( &p ) ) {
if( guy->is_assigned_to_camp() &&
mgr.has_near( z_camp_storage, g->m.getabs( src_loc ), ACTIVITY_SEARCH_DISTANCE ) ) {
std::unordered_set<tripoint> bc_storage_set = mgr.get_near( zone_type_id( "CAMP_STORAGE" ),
g->m.getabs( src_loc ), ACTIVITY_SEARCH_DISTANCE );
for( const tripoint &elem : bc_storage_set ) {
loot_zone_spots.push_back( g->m.getlocal( elem ) );
combined_spots.push_back( g->m.getlocal( elem ) );
}
}
}
}

static std::vector<std::tuple<tripoint, itype_id, int>> requirements_map( player &p,
const int distance = ACTIVITY_SEARCH_DISTANCE )
{
Expand Down Expand Up @@ -1617,6 +1633,7 @@ static std::vector<std::tuple<tripoint, itype_id, int>> requirements_map( player
combined_spots.push_back( elem );
}
}
add_basecamp_storage_to_loot_zone_list( mgr, src_loc, p, loot_spots, combined_spots );
// if the requirements arent available, then stop.
if( !are_requirements_nearby( pickup_task ? loot_spots : combined_spots, things_to_fetch_id, p,
activity_to_restore, pickup_task, src_loc ) ) {
Expand Down Expand Up @@ -2450,7 +2467,7 @@ static std::unordered_set<tripoint> generic_multi_activity_locations( player &p,
}
}
zone_type_id zone_type = get_zone_for_act( tripoint_zero, mgr, act_id );
if( act_id != ACT_FETCH_REQUIRED ) {
if( act_id != ACT_FETCH_REQUIRED && act_id != ACT_TIDY_UP ) {
src_set = mgr.get_near( zone_type_id( zone_type ), abspos, ACTIVITY_SEARCH_DISTANCE );
// multiple construction will form a list of targets based on blueprint zones and unfinished constructions
if( act_id == ACT_MULTIPLE_CONSTRUCTION ) {
Expand Down Expand Up @@ -2565,6 +2582,8 @@ static bool generic_multi_activity_check_requirement( player &p, const activity_
for( const tripoint &elem : g->m.points_in_radius( src_loc, PICKUP_RANGE - 1 ) ) {
combined_spots.push_back( elem );
}
add_basecamp_storage_to_loot_zone_list( mgr, src_loc, p, loot_zone_spots, combined_spots );

if( ( reason == NO_COMPONENTS || reason == NO_COMPONENTS_PREREQ ||
reason == NO_COMPONENTS_PREREQ_2 ) &&
act_id == ACT_MULTIPLE_CONSTRUCTION ) {
Expand Down
19 changes: 14 additions & 5 deletions src/basecamp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,11 +479,17 @@ void basecamp::reset_camp_workers()
}
}

void basecamp::add_assignee( character_id id )
{
assigned_npcs.push_back( overmap_buffer.find_npc( id ) );
}

void basecamp::validate_assignees()
{
for( auto it2 = assigned_npcs.begin(); it2 != assigned_npcs.end(); ) {
auto ptr = *it2;
if( ptr->mission != NPC_MISSION_ASSIGNED_CAMP || ptr->global_omt_location() != omt_pos ||
// new workers have no job yet, so dont discount them until after theyve chosen one.
if( !ptr->has_job() || !ptr->within_boundaries_of_camp() ||
ptr->has_companion_mission() ) {
it2 = assigned_npcs.erase( it2 );
} else {
Expand All @@ -498,10 +504,13 @@ void basecamp::validate_assignees()
if( std::find( assigned_npcs.begin(), assigned_npcs.end(), npc_to_add ) != assigned_npcs.end() ) {
continue;
} else {
if( npc_to_add->global_omt_location() == omt_pos &&
npc_to_add->mission == NPC_MISSION_ASSIGNED_CAMP &&
!npc_to_add->has_companion_mission() ) {
assigned_npcs.push_back( npc_to_add );
for( int x2 = omt_pos.x - 3; x2 < omt_pos.x + 3; x2++ ) {
for( int y2 = omt_pos.y - 3; y2 < omt_pos.y + 3; y2++ ) {
if( tripoint( x2, y2, omt_pos.z ) == npc_to_add->global_omt_location() && npc_to_add->has_job() &&
!npc_to_add->has_companion_mission() ) {
assigned_npcs.push_back( npc_to_add );
}
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/basecamp.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ class basecamp

void combat_mission_return( const std::string &miss );
void validate_assignees();
void add_assignee( character_id id );
std::vector<npc_ptr> get_npcs_assigned();
// Save/load
void serialize( JsonOut &json ) const;
Expand Down
15 changes: 9 additions & 6 deletions src/faction_camp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1590,6 +1590,7 @@ void basecamp::job_assignment_ui()
ctxt.register_action( "ANY_INPUT" );
ctxt.register_action( "CONFIRM" );
ctxt.register_action( "QUIT" );
validate_assignees();
while( true ) {
werase( w_jobs );
// create a list of npcs stationed at this camp
Expand Down Expand Up @@ -1622,13 +1623,15 @@ void basecamp::job_assignment_ui()
}
if( selection < stationed_npcs.size() ) {
std::string job_description;
if( cur_npc && cur_npc->has_job() ) {
// get the current NPCs job
job_description = npc_job_name( cur_npc->get_job() );
} else {
job_description = _( "No particular job" );
if( cur_npc ) {
if( cur_npc->has_job() ) {
// get the current NPCs job
job_description = npc_job_name( cur_npc->get_job() );
} else {
debugmsg( "npc %s is assigned to work at the camp but has no role", cur_npc->name );
}
mvwprintz( w_jobs, point( 46, 3 ), c_light_gray, job_description );
}
mvwprintz( w_jobs, point( 46, 3 ), c_light_gray, job_description );
} else {
mvwprintz( w_jobs, point( 46, 4 ), c_light_red, no_npcs );
}
Expand Down
54 changes: 49 additions & 5 deletions src/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1317,7 +1317,11 @@ void npc::mutiny()
// feel for you, but also reduces their respect for you.
my_fac->likes_u = std::max( 0, my_fac->likes_u / 2 + 10 );
my_fac->respects_u -= 5;
g->remove_npc_follower( getID() );
set_fac( faction_id( "amf" ) );
remove_job();
chatbin.first_topic = "TALK_STRANGER_NEUTRAL";
set_attitude( NPCATT_NULL );
say( _( "<follower_mutiny> Adios, motherfucker!" ), sounds::sound_t::order );
if( seen ) {
my_fac->known_by_u = true;
Expand Down Expand Up @@ -1974,13 +1978,50 @@ bool npc::is_leader() const
return attitude == NPCATT_LEAD;
}

bool npc::within_boundaries_of_camp() const
{
const int x = global_omt_location().x;
const int y = global_omt_location().y;
for( int x2 = x - 3; x2 < x + 3; x2++ ) {
for( int y2 = y - 3; y2 < y + 3; y2++ ) {
cata::optional<basecamp *> bcp = overmap_buffer.find_camp( point( x2, y2 ) );
if( bcp ) {
return true;
}
}
}
return false;
}

bool npc::is_assigned_to_camp() const
{
cata::optional<basecamp *> bcp = overmap_buffer.find_camp( global_omt_location().xy() );
if( has_companion_mission() || !has_job() ) {
return false;
}
cata::optional<basecamp *> bcp = cata::nullopt;
const int x = global_omt_location().x;
const int y = global_omt_location().y;
for( int x2 = x - 3; x2 < x + 3; x2++ ) {
for( int y2 = y - 3; y2 < y + 3; y2++ ) {
bcp = overmap_buffer.find_camp( point( x2, y2 ) );
if( bcp ) {
break;
}
}
if( bcp ) {
break;
}
}
if( !bcp ) {
return false;
}
return !has_companion_mission() && mission == NPC_MISSION_ASSIGNED_CAMP;
std::vector<npc_ptr> assigned_npcs = ( *bcp )->get_npcs_assigned();
for( const npc_ptr guy : assigned_npcs ) {
if( guy->getID() == getID() ) {
return true;
}
}
return false;
}

bool npc::is_enemy() const
Expand Down Expand Up @@ -2548,6 +2589,7 @@ std::string npc_job_id( npc_job job )
{ NPCJOB_HUSBANDRY, "NPCJOB_HUSBANDRY" },
{ NPCJOB_HUNTING, "NPCJOB_HUNTING" },
{ NPCJOB_FORAGING, "NPCJOB_FORAGING" },
{ NPCJOB_NOJOB, "NPCJOB_NOJOB "},
};
const auto &iter = npc_job_ids.find( job );
if( iter == npc_job_ids.end() ) {
Expand All @@ -2561,7 +2603,7 @@ std::string npc_job_id( npc_job job )
std::vector<std::string> all_jobs()
{
std::vector<std::string> ret;
for( int i = 0; i < NPCJOB_END; i++ ) {
for( int i = 0; i < NPCJOB_NOJOB; i++ ) {
ret.push_back( npc_job_name( static_cast<npc_job>( i ) ) );
}
return ret;
Expand Down Expand Up @@ -2594,6 +2636,8 @@ std::string npc_job_name( npc_job job )
return _( "Hunting and fishing - Currently only fishing is enabled" );
case NPCJOB_FORAGING:
return _( "Gathering edibles - Currently only a placeholder" );
case NPCJOB_NOJOB:
return _( "Not working" );
default:
break;
}
Expand Down Expand Up @@ -3158,12 +3202,12 @@ void npc::set_job( npc_job new_job )

bool npc::has_job() const
{
return job != NPCJOB_NULL;
return job != NPCJOB_NOJOB;
}

void npc::remove_job()
{
job = NPCJOB_NULL;
job = NPCJOB_NOJOB;
}

npc_attitude npc::get_attitude() const
Expand Down
12 changes: 8 additions & 4 deletions src/npc.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ enum npc_job : int {
NPCJOB_HUSBANDRY, // feeding animals, shearing sheep, collecting eggs/milk, training animals
NPCJOB_HUNTING, // hunting for meat ( this is currently handled by off-screen companion_mission )
NPCJOB_FORAGING, // foraging for edibles ( this is currently handled by off-screen companion_mission ) currently placeholder
NPCJOB_NOJOB, // not working
NPCJOB_END
};

Expand Down Expand Up @@ -160,8 +161,7 @@ enum npc_mission : int {
NPC_MISSION_GUARD, // Assigns an non-allied NPC to remain in place
NPC_MISSION_GUARD_PATROL, // Assigns a non-allied NPC to guard and investigate
NPC_MISSION_ACTIVITY, // Perform a player_activity until it is complete
NPC_MISSION_TRAVELLING,
NPC_MISSION_ASSIGNED_CAMP, // this npc is assigned to a camp.
NPC_MISSION_TRAVELLING
};

struct npc_companion_mission {
Expand Down Expand Up @@ -878,6 +878,7 @@ class npc : public player
bool is_guarding() const;
// Has a guard patrol mission
bool is_patrolling() const;
bool within_boundaries_of_camp() const;
bool is_assigned_to_camp() const;
/** is performing a player_activity */
bool has_player_activity() const;
Expand Down Expand Up @@ -1108,6 +1109,8 @@ class npc : public player
void move_away_from( const tripoint &p, bool no_bash_atk = false,
std::set<tripoint> *nomove = nullptr );
void move_away_from( const std::vector<sphere> &spheres, bool no_bashing = false );
// workers at camp relaxing/wandering
void worker_downtime();
// Same as if the player pressed '.'
void move_pause();

Expand Down Expand Up @@ -1227,7 +1230,7 @@ class npc : public player

private:
npc_attitude attitude; // What we want to do to the player
npc_job job = NPCJOB_NULL; // what is our job at camp
npc_job job = NPCJOB_NOJOB; // what is our job at camp
npc_attitude previous_attitude = NPCATT_NULL;
bool known_to_u = false; // Does the player know this NPC?
/**
Expand Down Expand Up @@ -1266,13 +1269,14 @@ class npc : public player
int last_seen_player_turn; // Timeout to forgetting
tripoint wanted_item_pos; // The square containing an item we want
tripoint guard_pos; // These are the local coordinates that a guard will return to inside of their goal tripoint
tripoint chair_pos = no_goal_point; // This is the spot the NPC wants to move to to sit and relax.
cata::optional<tripoint> base_location; // our faction base location in OMT coords.
/**
* Global overmap terrain coordinate, where we want to get to
* if no goal exist, this is no_goal_point.
*/
tripoint goal;
tripoint wander_pos; // Not actually used (should be: wander there when you hear a sound)
tripoint wander_pos = no_goal_point;
int wander_time;
item *known_stolen_item = nullptr; // the item that the NPC wants the player to drop or barter for.
/**
Expand Down
Loading