Skip to content

Commit 17550dc

Browse files
authored
Merge pull request #85135 from ShnitzelX2/multi-build-activity-actor-3
Move ACT_MULTIPLE_BUILD, ACT_FETCH_REQUIRED, ACT_MULTIPLE_CONSTRUCTION to activity_actors
2 parents 3d6546c + 9978377 commit 17550dc

14 files changed

+386
-115
lines changed

data/json/player_activities.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"based_on": "neither",
5252
"can_resume": false,
5353
"multi_activity": true,
54+
"fetch_items_to_zone": false,
5455
"auto_needs": true
5556
},
5657
{
@@ -199,6 +200,7 @@
199200
"based_on": "neither",
200201
"can_resume": false,
201202
"multi_activity": true,
203+
"fetch_items_to_zone": false,
202204
"auto_needs": true
203205
},
204206
{

src/activity_actor.cpp

Lines changed: 206 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <queue>
1616
#include <set>
1717
#include <string>
18+
#include <tuple>
1819
#include <unordered_set>
1920
#include <utility>
2021
#include <vector>
@@ -190,8 +191,10 @@ static const activity_id ACT_MILK( "ACT_MILK" );
190191
static const activity_id ACT_MOP( "ACT_MOP" );
191192
static const activity_id ACT_MOVE_ITEMS( "ACT_MOVE_ITEMS" );
192193
static const activity_id ACT_MOVE_LOOT( "ACT_MOVE_LOOT" );
194+
static const activity_id ACT_MULTIPLE_BUTCHER( "ACT_MULTIPLE_BUTCHER" );
193195
static const activity_id ACT_MULTIPLE_CHOP_PLANKS( "ACT_MULTIPLE_CHOP_PLANKS" );
194196
static const activity_id ACT_MULTIPLE_CHOP_TREES( "ACT_MULTIPLE_CHOP_TREES" );
197+
static const activity_id ACT_MULTIPLE_CONSTRUCTION( "ACT_MULTIPLE_CONSTRUCTION" );
195198
static const activity_id ACT_MULTIPLE_CRAFT( "ACT_MULTIPLE_CRAFT" );
196199
static const activity_id ACT_MULTIPLE_DIS( "ACT_MULTIPLE_DIS" );
197200
static const activity_id ACT_MULTIPLE_FARM( "ACT_MULTIPLE_FARM" );
@@ -4763,10 +4766,13 @@ std::optional<requirement_id> multi_zone_activity_actor::multi_activity_requirem
47634766

47644767
void multi_zone_activity_actor::do_turn( player_activity &act, Character &you )
47654768
{
4769+
activity_id prior_act = get_type();
47664770
simulate_turn( act, you, false );
47674771
// If this activity still exists, end it
4768-
if( !act.is_null() && act.is_multi_type() ) {
4769-
act.set_to_null();
4772+
if( !act.is_null() && ( prior_act == you.activity.id() ) ) {
4773+
// Nuke the current activity, leaving the backlog alone
4774+
// No multi_zone_activity_actor functions will be called from this point, so `this` can be nullptr
4775+
you.activity = player_activity();
47704776
}
47714777
}
47724778

@@ -4784,19 +4790,16 @@ bool multi_zone_activity_actor::simulate_turn( player_activity &act, Character &
47844790
// now loop through the work-spot tiles and judge whether its worth traveling to it yet
47854791
// or if we need to fetch something first.
47864792

4787-
// check: if a fetch activity was assigned but there's nothing to fetch, restore previous activity from backlog
4793+
// check: if a fetch activity was assigned but there's nothing to fetch, end fetch activity (restoring backlog)
47884794
// may cause infinite loop if something goes wrong
4789-
//TODO: check whether a fetch activity should be assigned before it is
4795+
// TODO: this could be moved to a multi_zone_activity_actor virtual function for post-location checking
47904796
if( current_activity == ACT_FETCH_REQUIRED && src_sorted.empty() ) {
47914797
// remind what you failed to fetch
47924798
if( !check_only ) {
4793-
if( !you.backlog.empty() ) {
4794-
player_activity &act_prev = you.backlog.front();
4795-
if( !act_prev.str_values.empty() && you.as_npc() ) {
4796-
you.as_npc()->job.fetch_history[act_prev.str_values.back()] = calendar::turn;
4797-
}
4798-
}
4799+
fetch_required_activity_actor *as_fetch = static_cast<fetch_required_activity_actor *>( this );
4800+
as_fetch->set_npc_fetch_history( you );
47994801
}
4802+
act.set_to_null();
48004803
return true;
48014804
}
48024805

@@ -4834,7 +4837,9 @@ bool multi_zone_activity_actor::simulate_turn( player_activity &act, Character &
48344837
continue;
48354838
}
48364839

4837-
//route to destination if needed
4840+
// route to destination if needed
4841+
// this stores a destination_activity that is resumed via
4842+
// can_resume_with_internal() in Character::assign_activity()
48384843
std::optional<bool> route_result = multi_activity_actor::route(
48394844
you, current_act_copy, src_bub, req_fail_reason, check_only );
48404845
if( !route_result ) {
@@ -4972,18 +4977,16 @@ requirement_check_result multi_zone_activity_actor::check_requirements( Characte
49724977
bool tool_pickup = multi_activity_actor::activity_reason_picks_up_tools( reason );
49734978
// is it even worth fetching anything if there isn't enough nearby?
49744979
if( !multi_activity_actor::are_requirements_nearby( tool_pickup ? loot_zone_spots : combined_spots,
4975-
what_we_need, you,
4976-
act_id, tool_pickup, src_loc ) ) {
4980+
what_we_need, you, act_id, tool_pickup, src_loc ) ) {
4981+
const tripoint_bub_ms you_pos_bub = you.pos_bub();
49774982
if( zone ) {
4978-
you.add_msg_player_or_npc( m_info,
4979-
_( "The required items are not available to complete the %s task at zone %s." ), act_id.c_str(),
4980-
zone->get_name(),
4981-
_( "The required items are not available to complete the %s task at zone %s." ), act_id.c_str(),
4982-
zone->get_name() );
4983+
add_msg_if_player_sees( you_pos_bub, m_info, string_format(
4984+
_( "The required items are not available to complete the %s task at zone %s." ),
4985+
act_id.c_str(), zone->get_name() ) );
49834986
} else {
4984-
you.add_msg_player_or_npc( m_info,
4985-
_( "The required items are not available to complete the %s task." ), act_id.c_str(),
4986-
_( "The required items are not available to complete the %s task." ), act_id.c_str() );
4987+
add_msg_if_player_sees( you_pos_bub, m_info, string_format(
4988+
_( "The required items are not available to complete the %s task." ),
4989+
act_id.c_str() ) );
49874990
}
49884991
//TODO: this is hacky, move it
49894992
if( reason == do_activity_reason::NEEDS_VEH_DECONST ||
@@ -4993,21 +4996,137 @@ requirement_check_result multi_zone_activity_actor::check_requirements( Characte
49934996
return requirement_check_result::SKIP_LOCATION;
49944997
} else {
49954998
if( !check_only ) {
4996-
return multi_activity_actor::fetch_requirements( you, what_we_need, act_id,
4997-
act_info, src, src_loc, src_set );
4999+
return fetch_requirements( you, what_we_need, act_info, src, src_loc, src_set );
49985000
}
49995001
return requirement_check_result::RETURN_EARLY;
50005002
}
50015003
}
50025004
return requirement_check_result::SKIP_LOCATION_NO_MATCH;
50035005
}
50045006

5007+
bool multi_zone_activity_actor::can_resume_with_internal( const activity_actor &,
5008+
const Character & ) const
5009+
{
5010+
return true;
5011+
}
5012+
5013+
requirement_check_result multi_zone_activity_actor::fetch_requirements( Character &you,
5014+
requirement_id what_we_need, activity_reason_info &act_info, const tripoint_abs_ms &src,
5015+
const tripoint_bub_ms &src_loc, const std::unordered_set<tripoint_abs_ms> &src_set )
5016+
{
5017+
5018+
map &here = get_map();
5019+
5020+
if( you.as_npc() && you.as_npc()->job.fetch_history.count( what_we_need.str() ) != 0 &&
5021+
you.as_npc()->job.fetch_history[what_we_need.str()] == calendar::turn ) {
5022+
// this may be a failed fetch already. Quit task to avoid infinite loop.
5023+
you.activity = player_activity();
5024+
you.backlog.clear();
5025+
multi_activity_actor::check_npc_revert( you );
5026+
return requirement_check_result::SKIP_LOCATION;
5027+
}
5028+
// come back here after successfully fetching your stuff
5029+
std::vector<tripoint_bub_ms> local_src_set;
5030+
local_src_set.reserve( src_set.size() );
5031+
for( const tripoint_abs_ms &elem : src_set ) {
5032+
local_src_set.push_back( here.get_bub( elem ) );
5033+
}
5034+
std::vector<tripoint_bub_ms> candidates;
5035+
for( const tripoint_bub_ms &point_elem :
5036+
here.points_in_radius( src_loc, PICKUP_RANGE - 1, 0 ) ) {
5037+
// we don't want to place the components where they could interfere with our ( or someone else's ) construction spots
5038+
if( ( std::find( local_src_set.begin(), local_src_set.end(),
5039+
point_elem ) != local_src_set.end() ) || !here.can_put_items_ter_furn( point_elem ) ) {
5040+
continue;
5041+
}
5042+
candidates.push_back( point_elem );
5043+
}
5044+
if( candidates.empty() ) {
5045+
you.activity = player_activity();
5046+
you.backlog.clear();
5047+
multi_activity_actor::check_npc_revert( you );
5048+
return requirement_check_result::SKIP_LOCATION_NO_LOCATION;
5049+
}
5050+
5051+
you.assign_activity( fetch_required_activity_actor( what_we_need, act_info.reason, here.get_abs(
5052+
candidates[std::max( 0, static_cast<int>( candidates.size() / 2 ) )] ), src ) );
5053+
return requirement_check_result::RETURN_EARLY;
5054+
}
5055+
50055056
void multi_zone_activity_actor::serialize( JsonOut &jsout ) const
50065057
{
50075058
jsout.start_object();
50085059
jsout.end_object();
50095060
}
50105061

5062+
activity_reason_info fetch_required_activity_actor::multi_activity_can_do(
5063+
Character &you, const tripoint_bub_ms &src_loc )
5064+
{
5065+
return multi_activity_actor::fetch_can_do( ACT_FETCH_REQUIRED, you,
5066+
src_loc );
5067+
}
5068+
5069+
void fetch_required_activity_actor::set_npc_fetch_history( Character &you )
5070+
{
5071+
if( !fetch_requirements.is_empty() && you.as_npc() ) {
5072+
you.as_npc()->job.fetch_history[fetch_requirements.str()] = calendar::turn;
5073+
}
5074+
}
5075+
5076+
bool fetch_required_activity_actor::fetch_activity_valid( const Character &you ) const
5077+
{
5078+
if( you.backlog.empty() ) {
5079+
debugmsg( "fetch activity assigned without a corresponding multi-activity" );
5080+
return false;
5081+
}
5082+
return true;
5083+
}
5084+
5085+
std::unordered_set<tripoint_abs_ms> fetch_required_activity_actor::multi_activity_locations(
5086+
Character &you )
5087+
{
5088+
map &here = get_map();
5089+
std::unordered_set<tripoint_abs_ms> src_set;
5090+
5091+
// get the right zones for the items in the requirements.
5092+
// we previously checked if the items are nearby before we set the fetch task
5093+
// but we will check again later, to be sure nothings changed.
5094+
std::vector<std::tuple<tripoint_bub_ms, itype_id, int>> mental_map =
5095+
requirements_map( you, MAX_VIEW_DISTANCE );
5096+
for( const auto &elem : mental_map ) {
5097+
const tripoint_bub_ms &elem_point = std::get<0>( elem );
5098+
src_set.insert( here.get_abs( elem_point ) );
5099+
}
5100+
multi_activity_actor::prune_dangerous_field_locations( src_set );
5101+
5102+
return src_set;
5103+
}
5104+
5105+
bool fetch_required_activity_actor::multi_activity_do( Character &you,
5106+
const activity_reason_info &act_info,
5107+
const tripoint_abs_ms &, const tripoint_bub_ms &src_loc )
5108+
{
5109+
const do_activity_reason &reason = act_info.reason;
5110+
5111+
if( reason == do_activity_reason::CAN_DO_FETCH ) {
5112+
if( fetch_activity( you, src_loc, ACT_FETCH_REQUIRED, MAX_VIEW_DISTANCE ) ) {
5113+
if( !you.is_npc() ) {
5114+
// Npcs will automatically start the next thing in the backlog, players need to be manually prompted
5115+
// Because some player activities are necessarily not marked as auto-resume.
5116+
activity_handlers::resume_for_multi_activities( you );
5117+
}
5118+
return false;
5119+
}
5120+
}
5121+
return true;
5122+
}
5123+
5124+
std::unique_ptr<activity_actor> fetch_required_activity_actor::deserialize( JsonValue & )
5125+
{
5126+
fetch_required_activity_actor actor;
5127+
return actor.clone();
5128+
}
5129+
50115130
std::unique_ptr<activity_actor> multi_mine_activity_actor::deserialize( JsonValue & )
50125131
{
50135132
multi_mine_activity_actor actor;
@@ -8114,6 +8233,40 @@ std::unique_ptr<activity_actor> build_construction_activity_actor::deserialize(
81148233
return actor.clone();
81158234
}
81168235

8236+
activity_reason_info multi_build_construction_activity_actor::multi_activity_can_do(
8237+
Character &you, const tripoint_bub_ms &src_loc )
8238+
{
8239+
return multi_activity_actor::construction_can_do( ACT_MULTIPLE_CONSTRUCTION, you,
8240+
src_loc );
8241+
}
8242+
8243+
std::optional<requirement_id> multi_build_construction_activity_actor::multi_activity_requirements(
8244+
Character &you,
8245+
activity_reason_info &act_info, const tripoint_bub_ms &src_loc, const zone_data * )
8246+
{
8247+
return multi_activity_actor::construction_requirements( you, act_info, src_loc );
8248+
}
8249+
8250+
std::unordered_set<tripoint_abs_ms>
8251+
multi_build_construction_activity_actor::multi_activity_locations(
8252+
Character &you )
8253+
{
8254+
return multi_activity_actor::construction_locations( you, get_type() );
8255+
}
8256+
8257+
bool multi_build_construction_activity_actor::multi_activity_do( Character &you,
8258+
const activity_reason_info &act_info,
8259+
const tripoint_abs_ms &src, const tripoint_bub_ms &src_loc )
8260+
{
8261+
return multi_activity_actor::construction_do( you, act_info, src, src_loc );
8262+
}
8263+
8264+
std::unique_ptr<activity_actor> multi_build_construction_activity_actor::deserialize( JsonValue & )
8265+
{
8266+
multi_build_construction_activity_actor actor;
8267+
return actor.clone();
8268+
}
8269+
81178270
void reel_cable_activity_actor::start( player_activity &act, Character & )
81188271
{
81198272
act.moves_total = moves_total;
@@ -12259,6 +12412,33 @@ std::unique_ptr<activity_actor> butchery_activity_actor::deserialize( JsonValue
1225912412
return actor.clone();
1226012413
}
1226112414

12415+
activity_reason_info multi_butchery_activity_actor::multi_activity_can_do(
12416+
Character &you, const tripoint_bub_ms &src_loc )
12417+
{
12418+
return multi_activity_actor::butcher_can_do( ACT_MULTIPLE_BUTCHER, you,
12419+
src_loc );
12420+
}
12421+
12422+
std::optional<requirement_id> multi_butchery_activity_actor::multi_activity_requirements(
12423+
Character &you,
12424+
activity_reason_info &act_info, const tripoint_bub_ms &src_loc, const zone_data * )
12425+
{
12426+
return multi_activity_actor::butcher_requirements( you, act_info, src_loc );
12427+
}
12428+
12429+
bool multi_butchery_activity_actor::multi_activity_do( Character &you,
12430+
const activity_reason_info &act_info,
12431+
const tripoint_abs_ms &src, const tripoint_bub_ms &src_loc )
12432+
{
12433+
return multi_activity_actor::butcher_do( you, act_info, src, src_loc );
12434+
}
12435+
12436+
std::unique_ptr<activity_actor> multi_butchery_activity_actor::deserialize( JsonValue & )
12437+
{
12438+
multi_butchery_activity_actor actor;
12439+
return actor.clone();
12440+
}
12441+
1226212442
void wait_activity_actor::start( player_activity &act, Character & )
1226312443
{
1226412444
act.moves_total = to_moves<int>( initial_wait_time );
@@ -12897,6 +13077,7 @@ deserialize_functions = {
1289713077
{ ACT_DROP, &drop_activity_actor::deserialize },
1289813078
{ ACT_E_FILE, &efile_activity_actor::deserialize },
1289913079
{ ACT_EBOOKSAVE, &ebooksave_activity_actor::deserialize },
13080+
{ ACT_FETCH_REQUIRED, &fetch_required_activity_actor::deserialize },
1290013081
{ ACT_FIELD_DRESS, &butchery_activity_actor::deserialize },
1290113082
{ ACT_FIRSTAID, &firstaid_activity_actor::deserialize },
1290213083
{ ACT_FISH, &fish_activity_actor::deserialize },
@@ -12926,8 +13107,10 @@ deserialize_functions = {
1292613107
{ ACT_MOP, &mop_activity_actor::deserialize },
1292713108
{ ACT_MOVE_ITEMS, &move_items_activity_actor::deserialize },
1292813109
{ ACT_MOVE_LOOT, &zone_sort_activity_actor::deserialize },
13110+
{ ACT_MULTIPLE_BUTCHER, &multi_butchery_activity_actor::deserialize },
1292913111
{ ACT_MULTIPLE_CHOP_PLANKS, &multi_chop_planks_activity_actor::deserialize },
1293013112
{ ACT_MULTIPLE_CHOP_TREES, &multi_chop_trees_activity_actor::deserialize },
13113+
{ ACT_MULTIPLE_CONSTRUCTION, &multi_build_construction_activity_actor::deserialize },
1293113114
{ ACT_MULTIPLE_CRAFT, &multi_craft_activity_actor::deserialize },
1293213115
{ ACT_MULTIPLE_DIS, &multi_disassemble_activity_actor::deserialize },
1293313116
{ ACT_MULTIPLE_FARM, &multi_farm_activity_actor::deserialize },

0 commit comments

Comments
 (0)