From 50d05b74c2988a569504792d3f892da0909c23c1 Mon Sep 17 00:00:00 2001 From: ipcyborg Date: Thu, 19 Sep 2019 15:32:02 +0300 Subject: [PATCH 1/2] Simplify generic activity by splitting to basic functions. Const reference in function parameters. Less use of `auto` when appropriate. --- src/activity_item_handling.cpp | 668 ++++++++++++++++++--------------- 1 file changed, 371 insertions(+), 297 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 9bf6934a32bd7..57fa85a73b3e6 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -65,6 +65,9 @@ const quality_id LIFT( "LIFT" ); const trap_str_id tr_firewood_source( "tr_firewood_source" ); const trap_str_id tr_unfinished_construction( "tr_unfinished_construction" ); +//Generic activity: maximum search distance for zones, constructions, etc. +const int ACTIVITY_SEARCH_DISTANCE = 60; + /** Activity-associated item */ struct act_item { const item *it; /// Pointer to the inventory item @@ -935,7 +938,7 @@ static void vehicle_activity( player &p, const tripoint src_loc, int vpindex, ch p.activity_vehicle_part_index = -1; } -static void move_item( player &p, item &it, int quantity, const tripoint &src, +static void move_item( player &p, item &it, const int quantity, const tripoint &src, const tripoint &dest, vehicle *src_veh, int src_part, activity_id activity_to_restore = activity_id::NULL_ID() ) { @@ -1146,8 +1149,8 @@ static std::string random_string( size_t length ) } static bool are_requirements_nearby( const std::vector &loot_spots, - const requirement_id &needed_things, player &p, const activity_id activity_to_restore, - bool in_loot_zones ) + const requirement_id &needed_things, player &p, const activity_id &activity_to_restore, + const bool in_loot_zones ) { zone_manager &mgr = zone_manager::get_manager(); inventory temp_inv; @@ -1222,7 +1225,7 @@ static bool has_skill_for_vehicle_work( std::map required_skills, } static activity_reason_info can_do_activity_there( const activity_id &act, player &p, - const tripoint &src_loc ) + const tripoint &src_loc, const int distance = ACTIVITY_SEARCH_DISTANCE ) { // see activity_handlers.h cant_do_activity_reason enums zone_manager &mgr = zone_manager::get_manager(); @@ -1435,7 +1438,7 @@ static activity_reason_info can_do_activity_there( const activity_id &act, playe return activity_reason_info::fail( NO_ZONE ); } if( act == activity_id( "ACT_TIDY_UP" ) ) { - if( mgr.has_near( z_loot_unsorted, g->m.getabs( src_loc ), 60 ) ) { + if( mgr.has_near( z_loot_unsorted, g->m.getabs( src_loc ), distance ) ) { return activity_reason_info::ok( CAN_DO_FETCH ); } return activity_reason_info::fail( NO_ZONE ); @@ -1517,7 +1520,8 @@ static activity_reason_info can_do_activity_there( const activity_id &act, playe return activity_reason_info::fail( NO_ZONE ); } -static std::vector> requirements_map( player &p ) +static std::vector> requirements_map( player &p, + const int distance = ACTIVITY_SEARCH_DISTANCE ) { const requirement_data things_to_fetch = requirement_id( p.backlog.front().str_values[0] ).obj(); const activity_id activity_to_restore = p.backlog.front().id(); @@ -1541,12 +1545,13 @@ static std::vector> requirements_map( player std::vector already_there_spots; std::vector combined_spots; std::map total_map; - for( const auto elem : g->m.points_in_radius( g->m.getlocal( p.backlog.front().placement ), + for( const tripoint &elem : g->m.points_in_radius( g->m.getlocal( p.backlog.front().placement ), PICKUP_RANGE - 1 ) ) { already_there_spots.push_back( elem ); combined_spots.push_back( elem ); } - for( const tripoint elem : mgr.get_point_set_loot( g->m.getabs( p.pos() ), 60, p.is_npc() ) ) { + for( const tripoint &elem : mgr.get_point_set_loot( g->m.getabs( p.pos() ), distance, + p.is_npc() ) ) { // if there is a loot zone thats already near the work spot, we dont want it to be added twice. if( std::find( already_there_spots.begin(), already_there_spots.end(), elem ) != already_there_spots.end() ) { @@ -1576,9 +1581,9 @@ static std::vector> requirements_map( player } // a vector of every item in every tile that matches any part of the requirements. // will be filtered for amounts/charges afterwards. - for( tripoint point_elem : pickup_task ? loot_spots : combined_spots ) { + for( const tripoint &point_elem : pickup_task ? loot_spots : combined_spots ) { std::map temp_map; - for( auto &stack_elem : g->m.i_at( point_elem ) ) { + for( const item &stack_elem : g->m.i_at( point_elem ) ) { for( std::vector &elem : req_comps ) { for( item_comp &comp_elem : elem ) { if( comp_elem.type == stack_elem.typeId() ) { @@ -1630,7 +1635,7 @@ static std::vector> requirements_map( player } } } - for( auto map_elem : temp_map ) { + for( const auto &map_elem : temp_map ) { total_map[map_elem.first] += map_elem.second; // if its a construction/crafting task, we can discount any items already near the work spot. // we dont need to fetch those, they will be used automatically in the construction. @@ -1646,9 +1651,9 @@ static std::vector> requirements_map( player } // Ok we now have a list of all the items that match the requirements, their points, and a quantity for each one. // we need to consolidate them, and winnow it down to the minimum required counts, instead of all matching. - for( std::vector &elem : req_comps ) { + for( const std::vector &elem : req_comps ) { bool line_found = false; - for( item_comp &comp_elem : elem ) { + for( const item_comp &comp_elem : elem ) { if( line_found || comp_elem.count <= 0 ) { break; } @@ -1704,9 +1709,9 @@ static std::vector> requirements_map( player } } } - for( std::vector &elem : tool_comps ) { + for( const std::vector &elem : tool_comps ) { bool line_found = false; - for( tool_comp &comp_elem : elem ) { + for( const tool_comp &comp_elem : elem ) { if( line_found || comp_elem.count <= 0 ) { break; } @@ -1762,9 +1767,9 @@ static std::vector> requirements_map( player } } } - for( std::vector &elem : quality_comps ) { + for( const std::vector &elem : quality_comps ) { bool line_found = false; - for( quality_requirement &comp_elem : elem ) { + for( const quality_requirement &comp_elem : elem ) { if( line_found || comp_elem.count <= 0 ) { break; } @@ -1841,13 +1846,14 @@ static void construction_activity( player &p, const zone_data *zone, const tripo p.activity.placement = g->m.getabs( src_loc ); } -static bool tidy_activity( player &p, const tripoint src_loc, activity_id activity_to_restore ) +static bool tidy_activity( player &p, const tripoint &src_loc, + const activity_id &activity_to_restore, const int distance = ACTIVITY_SEARCH_DISTANCE ) { auto &mgr = zone_manager::get_manager(); tripoint loot_abspos = g->m.getabs( src_loc ); tripoint loot_src_lot; - if( mgr.has_near( z_loot_unsorted, loot_abspos, 60 ) ) { - const auto &zone_src_set = mgr.get_near( zone_type_id( "LOOT_UNSORTED" ), loot_abspos, 60 ); + if( mgr.has_near( z_loot_unsorted, loot_abspos, distance ) ) { + const auto &zone_src_set = mgr.get_near( zone_type_id( "LOOT_UNSORTED" ), loot_abspos, distance ); const auto &zone_src_sorted = get_sorted_tiles_by_distance( loot_abspos, zone_src_set ); // Find the nearest unsorted zone to dump objects at for( auto &src_elem : zone_src_sorted ) { @@ -1892,12 +1898,14 @@ static bool tidy_activity( player &p, const tripoint src_loc, activity_id activi return true; } -static void fetch_activity( player &p, const tripoint src_loc, activity_id activity_to_restore ) +static void fetch_activity( player &p, const tripoint &src_loc, + const activity_id &activity_to_restore, const int distance = ACTIVITY_SEARCH_DISTANCE ) { if( !g->m.can_put_items_ter_furn( g->m.getlocal( p.backlog.front().coords.back() ) ) ) { return; } - const std::vector> mental_map_2 = requirements_map( p ); + const std::vector> mental_map_2 = requirements_map( p, + distance ); int pickup_count = 1; auto items_there = g->m.i_at( src_loc ); vehicle *src_veh = nullptr; @@ -1924,12 +1932,13 @@ static void fetch_activity( player &p, const tripoint src_loc, activity_id activ } } } - for( auto it = items_there.begin(); it != items_there.end(); it++ ) { + for( auto item_iter = items_there.begin(); item_iter != items_there.end(); item_iter++ ) { + item &it = *item_iter; for( auto elem : mental_map_2 ) { - if( std::get<0>( elem ) == src_loc && it->typeId() == std::get<1>( elem ) ) { + if( std::get<0>( elem ) == src_loc && it.typeId() == std::get<1>( elem ) ) { // construction/crafting tasks want the requred item moved near the work spot. if( !p.backlog.empty() && p.backlog.front().id() == activity_id( "ACT_MULTIPLE_CONSTRUCTION" ) ) { - move_item( p, *it, it->count_by_charges() ? std::get<2>( elem ) : 1, src_loc, + move_item( p, it, it.count_by_charges() ? std::get<2>( elem ) : 1, src_loc, g->m.getlocal( p.backlog.front().coords.back() ), src_veh, src_part, activity_to_restore ); return; // other tasks want the tool picked up @@ -1940,24 +1949,24 @@ static void fetch_activity( player &p, const tripoint src_loc, activity_id activ p.backlog.front().id() == activity_id( "ACT_MULTIPLE_BUTCHER" ) || p.backlog.front().id() == activity_id( "ACT_MULTIPLE_CHOP_TREES" ) || p.backlog.front().id() == activity_id( "ACT_MULTIPLE_FISH" ) ) ) { - if( it->volume() > volume_allowed || it->weight() > weight_allowed ) { + if( it.volume() > volume_allowed || it.weight() > weight_allowed ) { continue; } - item leftovers = *it; + item leftovers = it; - if( pickup_count != 1 && it->count_by_charges() ) { + if( pickup_count != 1 && it.count_by_charges() ) { // Reinserting leftovers happens after item removal to avoid stacking issues. - leftovers.charges = it->charges - pickup_count; + leftovers.charges = it.charges - pickup_count; if( leftovers.charges > 0 ) { - it->charges = pickup_count; + it.charges = pickup_count; } } else { leftovers.charges = 0; } - it->set_var( "activity_var", p.name ); - p.i_add( *it ); - picked_up = it->tname(); - items_there.erase( it ); + it.set_var( "activity_var", p.name ); + p.i_add( it ); + picked_up = it.tname(); + items_there.erase( item_iter ); // If we didn't pick up a whole stack, put the remainder back where it came from. if( leftovers.charges > 0 ) { g->m.add_item_or_charges( src_loc, leftovers ); @@ -1976,7 +1985,8 @@ static void fetch_activity( player &p, const tripoint src_loc, activity_id activ } } -static bool butcher_corpse_activity( player &p, tripoint src_loc, do_activity_reason reason ) +static bool butcher_corpse_activity( player &p, const tripoint &src_loc, + const do_activity_reason &reason ) { map_stack items = g->m.i_at( src_loc ); for( auto &elem : items ) { @@ -1995,7 +2005,7 @@ static bool butcher_corpse_activity( player &p, tripoint src_loc, do_activity_re return false; } -static item *best_quality_item( player &p, quality_id qual ) +static item *best_quality_item( player &p, const quality_id &qual ) { std::vector qual_inv = p.items_with( [qual]( const item & itm ) { return itm.has_quality( qual ); @@ -2009,7 +2019,7 @@ static item *best_quality_item( player &p, quality_id qual ) return best_qual; } -static bool chop_plank_activity( player &p, tripoint src_loc ) +static bool chop_plank_activity( player &p, const tripoint &src_loc ) { item *best_qual = best_quality_item( p, quality_id( "AXE" ) ); if( !best_qual ) { @@ -2031,8 +2041,6 @@ static bool chop_plank_activity( player &p, tripoint src_loc ) void activity_on_turn_move_loot( player_activity &act, player &p ) { - const int search_range = 60; - enum activity_stage : int { INIT = 0, //Initial stage THINK, //Think about what to do first: choose destination @@ -2054,7 +2062,7 @@ void activity_on_turn_move_loot( player_activity &act, player &p ) } if( stage == INIT ) { - act.coord_set = mgr.get_near( zone_type_id( "LOOT_UNSORTED" ), abspos, search_range ); + act.coord_set = mgr.get_near( zone_type_id( "LOOT_UNSORTED" ), abspos, ACTIVITY_SEARCH_DISTANCE ); stage = THINK; } @@ -2201,7 +2209,8 @@ void activity_on_turn_move_loot( player_activity &act, player &p ) vehicle *this_veh = it->second ? src_veh : nullptr; const int this_part = it->second ? src_part : -1; - const zone_type_id id = mgr.get_near_zone_type_for_item( thisitem, abspos, search_range ); + const zone_type_id id = mgr.get_near_zone_type_for_item( thisitem, abspos, + ACTIVITY_SEARCH_DISTANCE ); // checks whether the item is already on correct loot zone or not // if it is, we can skip such item, if not we move the item to correct pile @@ -2210,7 +2219,8 @@ void activity_on_turn_move_loot( player_activity &act, player &p ) continue; } - const std::unordered_set &dest_set = mgr.get_near( id, abspos, search_range, &thisitem ); + const std::unordered_set &dest_set = mgr.get_near( id, abspos, ACTIVITY_SEARCH_DISTANCE, + &thisitem ); for( const tripoint &dest : dest_set ) { const tripoint &dest_loc = g->m.getlocal( dest ); @@ -2312,26 +2322,23 @@ static void check_npc_revert( player &p ) } } -void generic_multi_activity_handler( player_activity &act, player &p ) +/** Determine all locations for this generic activity */ +/** Returns locations */ +static std::unordered_set generic_multi_activity_locations( player &p, + const activity_id &act_id ) { - // First get the things that are activity-agnostic. - zone_manager &mgr = zone_manager::get_manager(); - const tripoint abspos = g->m.getabs( p.pos() ); - // NOLINTNEXTLINE(performance-unnecessary-copy-initialization) - activity_id activity_to_restore = act.id(); - const tripoint localpos = p.pos(); bool dark_capable = false; - // the set of target work spots - potentally after we have fetched required tools. std::unordered_set src_set; - // we may need a list of all constructions later. - const std::vector &list_constructions = get_constructions(); - // Nuke the current activity, leaving the backlog alone - p.activity = player_activity(); - // now we setup the target spots based on whch activity is occuring - if( activity_to_restore == activity_id( "ACT_TIDY_UP" ) ) { + + zone_manager &mgr = zone_manager::get_manager(); + const tripoint localpos = p.pos(); + const tripoint abspos = g->m.getabs( localpos ); + + if( act_id == activity_id( "ACT_TIDY_UP" ) ) { dark_capable = true; tripoint unsorted_spot; - for( const tripoint elem : g->m.points_in_radius( g->m.getlocal( abspos ), 60 ) ) { + for( const tripoint &elem : g->m.points_in_radius( g->m.getlocal( abspos ), + ACTIVITY_SEARCH_DISTANCE ) ) { if( mgr.has( zone_type_id( z_loot_unsorted ), g->m.getabs( elem ) ) ) { // it already has a unsorted loot spot, and therefore dont need to go and pick up items there. if( unsorted_spot == tripoint_zero ) { @@ -2339,7 +2346,7 @@ void generic_multi_activity_handler( player_activity &act, player &p ) } continue; } - for( const auto &stack_elem : g->m.i_at( elem ) ) { + for( const item &stack_elem : g->m.i_at( elem ) ) { if( stack_elem.has_var( "activity_var" ) && stack_elem.get_var( "activity_var", "" ) == p.name ) { const furn_t &f = g->m.furn( elem ).obj(); if( !f.has_flag( "PLANT" ) ) { @@ -2350,28 +2357,29 @@ void generic_multi_activity_handler( player_activity &act, player &p ) } } if( src_set.empty() && unsorted_spot != tripoint_zero ) { - for( auto inv_elem : p.inv_dump() ) { + for( const item *inv_elem : p.inv_dump() ) { if( inv_elem->has_var( "activity_var" ) ) { - // we've gone to tidy up all the thngs lying around, now tidy up the things we picked up. + // we've gone to tidy up all the things lying around, now tidy up the things we picked up. src_set.insert( g->m.getabs( unsorted_spot ) ); break; } } } } - if( activity_to_restore == activity_id( "ACT_VEHICLE_DECONSTRUCTION" ) ) { - src_set = mgr.get_near( zone_type_id( "VEHICLE_DECONSTRUCT" ), abspos, 60 ); + if( act_id == activity_id( "ACT_VEHICLE_DECONSTRUCTION" ) ) { + src_set = mgr.get_near( zone_type_id( "VEHICLE_DECONSTRUCT" ), abspos, ACTIVITY_SEARCH_DISTANCE ); } - if( activity_to_restore == activity_id( "ACT_VEHICLE_REPAIR" ) ) { - src_set = mgr.get_near( zone_type_id( "VEHICLE_REPAIR" ), abspos, 60 ); + if( act_id == activity_id( "ACT_VEHICLE_REPAIR" ) ) { + src_set = mgr.get_near( zone_type_id( "VEHICLE_REPAIR" ), abspos, ACTIVITY_SEARCH_DISTANCE ); } - if( activity_to_restore == activity_id( "ACT_MULTIPLE_CHOP_TREES" ) ) { - src_set = mgr.get_near( zone_type_id( "CHOP_TREES" ), abspos, 60 ); + if( act_id == activity_id( "ACT_MULTIPLE_CHOP_TREES" ) ) { + src_set = mgr.get_near( zone_type_id( "CHOP_TREES" ), abspos, ACTIVITY_SEARCH_DISTANCE ); } // multiple construction will form a list of targets based on blueprint zones and unfinished constructions - if( activity_to_restore == activity_id( "ACT_MULTIPLE_CONSTRUCTION" ) ) { - src_set = mgr.get_near( zone_type_id( "CONSTRUCTION_BLUEPRINT" ), abspos, 60 ); - for( const tripoint &elem : g->m.points_in_radius( localpos, 40 ) ) { + if( act_id == activity_id( "ACT_MULTIPLE_CONSTRUCTION" ) ) { + src_set = mgr.get_near( zone_type_id( "CONSTRUCTION_BLUEPRINT" ), abspos, + ACTIVITY_SEARCH_DISTANCE ); + for( const tripoint &elem : g->m.points_in_radius( localpos, ACTIVITY_SEARCH_DISTANCE ) ) { partial_con *pc = g->m.partial_con_at( elem ); if( pc ) { src_set.insert( g->m.getabs( elem ) ); @@ -2379,42 +2387,43 @@ void generic_multi_activity_handler( player_activity &act, player &p ) } // farming activies encompass tilling, planting, harvesting. } - if( activity_to_restore == activity_id( "ACT_MULTIPLE_FARM" ) ) { - src_set = mgr.get_near( zone_type_id( "FARM_PLOT" ), abspos, 60 ); + if( act_id == activity_id( "ACT_MULTIPLE_FARM" ) ) { + src_set = mgr.get_near( zone_type_id( "FARM_PLOT" ), abspos, ACTIVITY_SEARCH_DISTANCE ); // fetch required will always be following on from a previous activity } - if( activity_to_restore == activity_id( "ACT_FETCH_REQUIRED" ) ) { + if( act_id == activity_id( "ACT_FETCH_REQUIRED" ) ) { dark_capable = true; // get the right zones for the items in the requirements. // we previously checked if the items are nearby before we set the fetch task // but we will check again later, to be sure nothings changed. - std::vector> mental_map = requirements_map( p ); - for( auto elem : mental_map ) { - tripoint elem_point = std::get<0>( elem ); + std::vector> mental_map = requirements_map( p, + ACTIVITY_SEARCH_DISTANCE ); + for( const auto &elem : mental_map ) { + const tripoint &elem_point = std::get<0>( elem ); src_set.insert( g->m.getabs( elem_point ) ); } } - if( activity_to_restore == activity_id( "ACT_MULTIPLE_BUTCHER" ) ) { - src_set = mgr.get_near( zone_type_id( "LOOT_CORPSE" ), abspos, 60 ); + if( act_id == activity_id( "ACT_MULTIPLE_BUTCHER" ) ) { + src_set = mgr.get_near( zone_type_id( "LOOT_CORPSE" ), abspos, ACTIVITY_SEARCH_DISTANCE ); } - if( activity_to_restore == activity_id( "ACT_MULTIPLE_CHOP_PLANKS" ) ) { + if( act_id == activity_id( "ACT_MULTIPLE_CHOP_PLANKS" ) ) { // we want to chop logs so get loot wood spots - src_set = mgr.get_near( zone_type_id( "LOOT_WOOD" ), abspos, 60 ); + src_set = mgr.get_near( zone_type_id( "LOOT_WOOD" ), abspos, ACTIVITY_SEARCH_DISTANCE ); } - if( activity_to_restore == activity_id( "ACT_MULTIPLE_FISH" ) ) { - src_set = mgr.get_near( zone_type_id( "FISHING_SPOT" ), abspos, 60 ); + if( act_id == activity_id( "ACT_MULTIPLE_FISH" ) ) { + src_set = mgr.get_near( zone_type_id( "FISHING_SPOT" ), abspos, ACTIVITY_SEARCH_DISTANCE ); } // prune the set to remove tiles that are never gonna work out. const bool pre_dark_check = src_set.empty(); for( auto it2 = src_set.begin(); it2 != src_set.end(); ) { // remove dangerous tiles - tripoint set_pt = g->m.getlocal( *it2 ); + const tripoint set_pt = g->m.getlocal( *it2 ); if( g->m.dangerous_field_at( set_pt ) ) { it2 = src_set.erase( it2 ); // remove tiles in darkness, if we arent lit-up ourselves } else if( !dark_capable && p.fine_detail_vision_mod( set_pt ) > 4.0 ) { it2 = src_set.erase( it2 ); - } else if( activity_to_restore == activity_id( "ACT_MULTIPLE_FISH" ) ) { + } else if( act_id == activity_id( "ACT_MULTIPLE_FISH" ) ) { const ter_id terrain_id = g->m.ter( set_pt ); if( !terrain_id.obj().has_flag( TFLAG_DEEP_WATER ) ) { it2 = src_set.erase( it2 ); @@ -2429,6 +2438,274 @@ void generic_multi_activity_handler( player_activity &act, player &p ) if( !pre_dark_check && post_dark_check ) { p.add_msg_if_player( m_info, _( "It is too dark to do this activity." ) ); } + return src_set; +} + +/** Check if this activity can not be done immidiately because it has some requirements */ +/** Returns true if this multi activity may be processed further */ +static bool generic_multi_activity_check_requirement( player &p, const activity_id &act_id, + activity_reason_info &act_info, + const tripoint &src, const tripoint &src_loc, const std::unordered_set &src_set ) +{ + const tripoint abspos = g->m.getabs( p.pos() ); + zone_manager &mgr = zone_manager::get_manager(); + const std::vector &list_constructions = get_constructions(); + + bool &can_do_it = act_info.can_do; + const do_activity_reason &reason = act_info.reason; + const zone_data *zone = mgr.get_zone_at( src ); + + const bool needs_to_be_in_zone = act_id == activity_id( "ACT_FETCH_REQUIRED" ) || + act_id == activity_id( "ACT_MULTIPLE_FARM" ) || + act_id == activity_id( "ACT_MULTIPLE_BUTCHER" ) || + act_id == activity_id( "ACT_MULTIPLE_CHOP_PLANKS" ) || + act_id == activity_id( "ACT_MULTIPLE_CHOP_TREES" ) || + act_id == activity_id( "ACT_VEHICLE_DECONSTRUCTION" ) || + act_id == activity_id( "ACT_VEHICLE_REPAIR" ) || + act_id == activity_id( "ACT_MULTIPLE_FISH" ) || + ( act_id == activity_id( "ACT_MULTIPLE_CONSTRUCTION" ) && + !g->m.partial_con_at( src_loc ) ); + // some activities require the target tile to be part of a zone. + // tidy up activity dosnt - it wants things that may not be in a zone already - things that may have been left lying around. + if( needs_to_be_in_zone && !zone ) { + can_do_it = false; + return true; + } + if( can_do_it ) { + return true; + } + if( reason == DONT_HAVE_SKILL || reason == NO_ZONE || reason == ALREADY_DONE || + reason == BLOCKING_TILE || reason == UNKNOWN_ACTIVITY ) { + // we can discount this tile, the work can't be done. + if( reason == DONT_HAVE_SKILL ) { + p.add_msg_if_player( m_info, _( "You don't have the skill for this task." ) ); + } else if( reason == BLOCKING_TILE ) { + p.add_msg_if_player( m_info, _( "There is something blocking the location for this task." ) ); + } + return true; + } else if( reason == NO_COMPONENTS || reason == NEEDS_PLANTING || + reason == NEEDS_TILLING || reason == NEEDS_CHOPPING || reason == NEEDS_BUTCHERING || + reason == NEEDS_BIG_BUTCHERING || reason == NEEDS_VEH_DECONST || reason == NEEDS_VEH_REPAIR || + reason == NEEDS_TREE_CHOPPING || + reason == NEEDS_FISHING ) { + // we can do it, but we need to fetch some stuff first + // before we set the task to fetch components - is it even worth it? are the components anywhere? + requirement_id what_we_need; + std::vector loot_zone_spots; + std::vector combined_spots; + for( const tripoint &elem : mgr.get_point_set_loot( abspos, ACTIVITY_SEARCH_DISTANCE, + p.is_npc() ) ) { + loot_zone_spots.push_back( elem ); + combined_spots.push_back( elem ); + } + for( const tripoint &elem : g->m.points_in_radius( src_loc, PICKUP_RANGE - 1 ) ) { + combined_spots.push_back( elem ); + } + if( ( reason == NO_COMPONENTS || reason == NO_COMPONENTS_PREREQ || + reason == NO_COMPONENTS_PREREQ_2 ) && + act_id == activity_id( "ACT_MULTIPLE_CONSTRUCTION" ) ) { + if( !act_info.con_idx ) { + debugmsg( "no construction selected" ); + return true; + } + // its a construction and we need the components. + const construction &built_chosen = list_constructions[ *act_info.con_idx ]; + what_we_need = built_chosen.requirements; + } else if( reason == NEEDS_VEH_DECONST || reason == NEEDS_VEH_REPAIR ) { + const vehicle *veh = veh_pointer_or_null( g->m.veh_at( src_loc ) ); + // we already checked this in can_do_activity() but check again just incase. + if( !veh ) { + p.activity_vehicle_part_index = 1; + return true; + } + const vpart_info &vpinfo = veh->part_info( p.activity_vehicle_part_index ); + requirement_data reqs; + if( reason == NEEDS_VEH_DECONST ) { + reqs = vpinfo.removal_requirements(); + } else if( reason == NEEDS_VEH_REPAIR ) { + reqs = vpinfo.repair_requirements(); + } + const std::string ran_str = random_string( 10 ); + const requirement_id req_id( ran_str ); + requirement_data::save_requirement( reqs, req_id ); + what_we_need = req_id; + } else if( reason == NEEDS_TILLING || reason == NEEDS_PLANTING || reason == NEEDS_CHOPPING || + reason == NEEDS_BUTCHERING || reason == NEEDS_BIG_BUTCHERING || reason == NEEDS_TREE_CHOPPING || + reason == NEEDS_FISHING ) { + std::vector> requirement_comp_vector; + std::vector> quality_comp_vector; + std::vector> tool_comp_vector; + if( reason == NEEDS_TILLING ) { + quality_comp_vector.push_back( std::vector { quality_requirement( quality_id( "DIG" ), 1, 1 ) } ); + } else if( reason == NEEDS_CHOPPING || reason == NEEDS_TREE_CHOPPING ) { + quality_comp_vector.push_back( std::vector { quality_requirement( quality_id( "AXE" ), 1, 1 ) } ); + } else if( reason == NEEDS_PLANTING ) { + requirement_comp_vector.push_back( std::vector { item_comp( itype_id( dynamic_cast + ( zone->get_options() ).get_seed() ), 1 ) + } ); + } else if( reason == NEEDS_BUTCHERING || reason == NEEDS_BIG_BUTCHERING ) { + quality_comp_vector.push_back( std::vector { quality_requirement( quality_id( "BUTCHER" ), 1, 1 ) } ); + if( reason == NEEDS_BIG_BUTCHERING ) { + quality_comp_vector.push_back( std::vector { quality_requirement( quality_id( "SAW_M" ), 1, 1 ), quality_requirement( quality_id( "SAW_W" ), 1, 1 ) } ); + } + + } else if( reason == NEEDS_FISHING ) { + quality_comp_vector.push_back( std::vector {quality_requirement( quality_id( "FISHING" ), 1, 1 )} ); + } + // ok, we need a shovel/hoe/axe/etc + // this is an activity that only requires this one tool, so we will fetch and wield it. + requirement_data reqs_data = requirement_data( tool_comp_vector, quality_comp_vector, + requirement_comp_vector ); + const std::string ran_str = random_string( 10 ); + const requirement_id req_id( ran_str ); + requirement_data::save_requirement( reqs_data, req_id ); + what_we_need = req_id; + } + bool tool_pickup = reason == NEEDS_TILLING || reason == NEEDS_PLANTING || + reason == NEEDS_CHOPPING || reason == NEEDS_BUTCHERING || reason == NEEDS_BIG_BUTCHERING || + reason == NEEDS_TREE_CHOPPING || reason == NEEDS_VEH_DECONST || reason == NEEDS_VEH_REPAIR; + // is it even worth fetching anything if there isnt enough nearby? + if( !are_requirements_nearby( tool_pickup ? loot_zone_spots : combined_spots, what_we_need, p, + act_id, tool_pickup ) ) { + p.add_msg_if_player( m_info, _( "The required items are not available to complete this task." ) ); + if( reason == NEEDS_VEH_DECONST || reason == NEEDS_VEH_REPAIR ) { + p.activity_vehicle_part_index = -1; + } + return true; + } else { + p.backlog.push_front( act_id ); + p.assign_activity( activity_id( "ACT_FETCH_REQUIRED" ) ); + player_activity &act_prev = p.backlog.front(); + act_prev.str_values.push_back( what_we_need.str() ); + act_prev.values.push_back( reason ); + // come back here after succesfully fetching your stuff + std::vector candidates; + if( act_prev.coords.empty() ) { + std::vector local_src_set; + for( const tripoint &elem : src_set ) { + local_src_set.push_back( g->m.getlocal( elem ) ); + } + std::vector candidates; + for( const tripoint &point_elem : g->m.points_in_radius( src_loc, PICKUP_RANGE - 1 ) ) { + // we dont want to place the components where they could interfere with our ( or someone elses ) construction spots + if( ( std::find( local_src_set.begin(), local_src_set.end(), + point_elem ) != local_src_set.end() ) || !g->m.can_put_items_ter_furn( point_elem ) ) { + continue; + } + candidates.push_back( point_elem ); + } + if( candidates.empty() ) { + p.activity = player_activity(); + p.backlog.clear(); + check_npc_revert( p ); + return false; + } + act_prev.coords.push_back( g->m.getabs( candidates[std::max( 0, + static_cast( candidates.size() / 2 ) )] ) ); + } + act_prev.placement = src; + return false; + } + } + return true; +} + +/** Do activity at this location */ +/** Returns true if this multi activity may be processed further */ +static bool generic_multi_activity_do( player &p, const activity_id &act_id, + const activity_reason_info &act_info, + const tripoint &src, const tripoint &src_loc ) +{ + zone_manager &mgr = zone_manager::get_manager(); + const std::vector &list_constructions = get_constructions(); + + const do_activity_reason &reason = act_info.reason; + const zone_data *zone = mgr.get_zone_at( src ); + + // something needs to be done, now we are there. + // it was here earlier, in the space of one turn, maybe it got harvested by someone else. + if( reason == NEEDS_HARVESTING && g->m.has_flag_furn( "GROWTH_HARVEST", src_loc ) ) { + iexamine::harvest_plant( p, src_loc, true ); + } else if( reason == NEEDS_TILLING && g->m.has_flag( "PLOWABLE", src_loc ) && + p.has_quality( quality_id( "DIG" ), 1 ) && !g->m.has_furn( src_loc ) ) { + p.assign_activity( activity_id( "ACT_CHURN" ), 18000, -1 ); + p.backlog.push_front( act_id ); + p.activity.placement = src; + return false; + } else if( reason == NEEDS_PLANTING && g->m.has_flag_ter_or_furn( "PLANTABLE", src_loc ) ) { + if( !plant_activity( p, zone, src_loc ) ) { + return true; + } + } else if( reason == NEEDS_CHOPPING && p.has_quality( quality_id( "AXE" ), 1 ) ) { + if( chop_plank_activity( p, src_loc ) ) { + p.backlog.push_front( act_id ); + return false; + } + } else if( reason == NEEDS_BUTCHERING || reason == NEEDS_BIG_BUTCHERING ) { + p.backlog.push_front( act_id ); + if( butcher_corpse_activity( p, src_loc, reason ) ) { + return false; + } + } else if( reason == CAN_DO_CONSTRUCTION || reason == CAN_DO_PREREQ ) { + if( g->m.partial_con_at( src_loc ) ) { + p.backlog.push_front( act_id ); + p.assign_activity( activity_id( "ACT_BUILD" ) ); + p.activity.placement = src; + return false; + } + construction_activity( p, zone, src_loc, act_info, list_constructions, act_id ); + return false; + } else if( reason == CAN_DO_FETCH && act_id == activity_id( "ACT_TIDY_UP" ) ) { + if( !tidy_activity( p, src_loc, act_id, ACTIVITY_SEARCH_DISTANCE ) ) { + return false; + } + } else if( reason == CAN_DO_FETCH && act_id == activity_id( "ACT_FETCH_REQUIRED" ) ) { + fetch_activity( p, src_loc, act_id, ACTIVITY_SEARCH_DISTANCE ); + // Npcs will automatically start the next thing in the backlog, players need to be manually prompted + // Because some player activities are necessarily not marked as auto-resume. + activity_handlers::resume_for_multi_activities( p ); + return false; + } else if( reason == NEEDS_TREE_CHOPPING && p.has_quality( quality_id( "AXE" ), 1 ) ) { + p.backlog.push_front( act_id ); + if( chop_tree_activity( p, src_loc ) ) { + return false; + } + } else if( reason == NEEDS_FISHING && p.has_quality( quality_id( "FISHING" ), 1 ) ) { + p.backlog.push_front( act_id ); + // we dont want to keep repeating the fishing activity, just piggybacking on this functions structure to find requirements. + p.activity = player_activity(); + item *best_rod = best_quality_item( p, quality_id( "FISHING" ) ); + p.assign_activity( activity_id( "ACT_FISH" ), to_moves( 5_hours ), 0, + p.get_item_position( best_rod ), best_rod->tname() ); + p.activity.coord_set = g->get_fishable_locations( ACTIVITY_SEARCH_DISTANCE, src_loc ); + return false; + } else if( reason == NEEDS_VEH_DECONST ) { + p.backlog.push_front( act_id ); + vehicle_activity( p, src_loc, p.activity_vehicle_part_index, 'o' ); + p.activity_vehicle_part_index = -1; + return false; + } else if( reason == NEEDS_VEH_REPAIR ) { + p.backlog.push_front( act_id ); + vehicle_activity( p, src_loc, p.activity_vehicle_part_index, 'r' ); + p.activity_vehicle_part_index = -1; + return false; + } + return true; +} + +void generic_multi_activity_handler( player_activity &act, player &p ) +{ + const tripoint abspos = g->m.getabs( p.pos() ); + // NOLINTNEXTLINE(performance-unnecessary-copy-initialization) + activity_id activity_to_restore = act.id(); + + // Nuke the current activity, leaving the backlog alone + p.activity = player_activity(); + + // now we setup the target spots based on whch activity is occuring + // the set of target work spots - potentally after we have fetched required tools. + std::unordered_set src_set = generic_multi_activity_locations( p, activity_to_restore ); + // now we have our final set of points std::vector src_sorted = get_sorted_tiles_by_distance( abspos, src_set ); // now loop through the work-spot tiles and judge whether its worth travelling to it yet @@ -2454,157 +2731,18 @@ void generic_multi_activity_handler( player_activity &act, player &p ) return; } activity_reason_info act_info = can_do_activity_there( activity_to_restore, p, - src_loc ); - const bool &can_do_it = act_info.can_do; - const do_activity_reason &reason = act_info.reason; - const zone_data *zone = mgr.get_zone_at( src ); - const bool needs_to_be_in_zone = activity_to_restore == activity_id( "ACT_FETCH_REQUIRED" ) || - activity_to_restore == activity_id( "ACT_MULTIPLE_FARM" ) || - activity_to_restore == activity_id( "ACT_MULTIPLE_BUTCHER" ) || - activity_to_restore == activity_id( "ACT_MULTIPLE_CHOP_PLANKS" ) || - activity_to_restore == activity_id( "ACT_MULTIPLE_CHOP_TREES" ) || - activity_to_restore == activity_id( "ACT_VEHICLE_DECONSTRUCTION" ) || - activity_to_restore == activity_id( "ACT_VEHICLE_REPAIR" ) || - activity_to_restore == activity_id( "ACT_MULTIPLE_FISH" ) || - ( activity_to_restore == activity_id( "ACT_MULTIPLE_CONSTRUCTION" ) && - !g->m.partial_con_at( src_loc ) ); - // some activities require the target tile to be part of a zone. - // tidy up activity dosnt - it wants things that may not be in a zone already - things that may have been left lying around. - if( needs_to_be_in_zone && !zone ) { - continue; + src_loc, ACTIVITY_SEARCH_DISTANCE ); + //check activity requirement + if( !generic_multi_activity_check_requirement( p, activity_to_restore, act_info, src, src_loc, + src_set ) ) { + return; } - if( ( !can_do_it ) && ( reason == DONT_HAVE_SKILL || reason == NO_ZONE || reason == ALREADY_DONE || - reason == BLOCKING_TILE || reason == UNKNOWN_ACTIVITY ) ) { - // we can discount this tile, the work can't be done. - if( reason == DONT_HAVE_SKILL ) { - p.add_msg_if_player( m_info, _( "You don't have the skill for this task." ) ); - } else if( reason == BLOCKING_TILE ) { - p.add_msg_if_player( m_info, _( "There is something blocking the location for this task." ) ); - } + //skip this location if doing activity here is impossible + if( !act_info.can_do ) { continue; - } else if( ( !can_do_it ) && ( reason == NO_COMPONENTS || reason == NEEDS_PLANTING || - reason == NEEDS_TILLING || reason == NEEDS_CHOPPING || reason == NEEDS_BUTCHERING || - reason == NEEDS_BIG_BUTCHERING || reason == NEEDS_VEH_DECONST || reason == NEEDS_VEH_REPAIR || - reason == NEEDS_TREE_CHOPPING || - reason == NEEDS_FISHING ) ) { - // we can do it, but we need to fetch some stuff first - // before we set the task to fetch components - is it even worth it? are the components anywhere? - requirement_id what_we_need; - std::vector loot_zone_spots; - std::vector combined_spots; - for( const tripoint elem : mgr.get_point_set_loot( abspos, 60, p.is_npc() ) ) { - loot_zone_spots.push_back( elem ); - combined_spots.push_back( elem ); - } - for( const tripoint elem : g->m.points_in_radius( src_loc, PICKUP_RANGE - 1 ) ) { - combined_spots.push_back( elem ); - } - if( ( reason == NO_COMPONENTS || reason == NO_COMPONENTS_PREREQ || - reason == NO_COMPONENTS_PREREQ_2 ) && - activity_to_restore == activity_id( "ACT_MULTIPLE_CONSTRUCTION" ) ) { - if( !act_info.con_idx ) { - debugmsg( "no construction selected" ); - continue; - } - // its a construction and we need the components. - const construction &built_chosen = list_constructions[ *act_info.con_idx ]; - what_we_need = built_chosen.requirements; - } else if( reason == NEEDS_VEH_DECONST || reason == NEEDS_VEH_REPAIR ) { - vehicle *veh = veh_pointer_or_null( g->m.veh_at( src_loc ) ); - // we already checked this in can_do_activity() but check again just incase. - if( !veh ) { - p.activity_vehicle_part_index = -1; - continue; - } - const vpart_info &vpinfo = veh->part_info( p.activity_vehicle_part_index ); - requirement_data reqs; - if( reason == NEEDS_VEH_DECONST ) { - reqs = vpinfo.removal_requirements(); - } else if( reason == NEEDS_VEH_REPAIR ) { - reqs = vpinfo.repair_requirements(); - } - const std::string ran_str = random_string( 10 ); - const requirement_id req_id( ran_str ); - requirement_data::save_requirement( reqs, req_id ); - what_we_need = req_id; - } else if( reason == NEEDS_TILLING || reason == NEEDS_PLANTING || reason == NEEDS_CHOPPING || - reason == NEEDS_BUTCHERING || reason == NEEDS_BIG_BUTCHERING || reason == NEEDS_TREE_CHOPPING || - reason == NEEDS_FISHING ) { - std::vector> requirement_comp_vector; - std::vector> quality_comp_vector; - std::vector> tool_comp_vector; - if( reason == NEEDS_TILLING ) { - quality_comp_vector.push_back( std::vector { quality_requirement( quality_id( "DIG" ), 1, 1 ) } ); - } else if( reason == NEEDS_CHOPPING || reason == NEEDS_TREE_CHOPPING ) { - quality_comp_vector.push_back( std::vector { quality_requirement( quality_id( "AXE" ), 1, 1 ) } ); - } else if( reason == NEEDS_PLANTING ) { - requirement_comp_vector.push_back( std::vector { item_comp( itype_id( dynamic_cast - ( zone->get_options() ).get_seed() ), 1 ) - } ); - } else if( reason == NEEDS_BUTCHERING || reason == NEEDS_BIG_BUTCHERING ) { - quality_comp_vector.push_back( std::vector { quality_requirement( quality_id( "BUTCHER" ), 1, 1 ) } ); - if( reason == NEEDS_BIG_BUTCHERING ) { - quality_comp_vector.push_back( std::vector { quality_requirement( quality_id( "SAW_M" ), 1, 1 ), quality_requirement( quality_id( "SAW_W" ), 1, 1 ) } ); - } - - } else if( reason == NEEDS_FISHING ) { - quality_comp_vector.push_back( std::vector {quality_requirement( quality_id( "FISHING" ), 1, 1 )} ); - } - // ok, we need a shovel/hoe/axe/etc - // this is an activity that only requires this one tool, so we will fetch and wield it. - requirement_data reqs_data = requirement_data( tool_comp_vector, quality_comp_vector, - requirement_comp_vector ); - const std::string ran_str = random_string( 10 ); - const requirement_id req_id( ran_str ); - requirement_data::save_requirement( reqs_data, req_id ); - what_we_need = req_id; - } - bool tool_pickup = reason == NEEDS_TILLING || reason == NEEDS_PLANTING || - reason == NEEDS_CHOPPING || reason == NEEDS_BUTCHERING || reason == NEEDS_BIG_BUTCHERING || - reason == NEEDS_TREE_CHOPPING || reason == NEEDS_VEH_DECONST || reason == NEEDS_VEH_REPAIR; - // is it even worth fetching anything if there isnt enough nearby? - if( !are_requirements_nearby( tool_pickup ? loot_zone_spots : combined_spots, what_we_need, p, - activity_to_restore, tool_pickup ) ) { - p.add_msg_if_player( m_info, _( "The required items are not available to complete this task." ) ); - if( reason == NEEDS_VEH_DECONST || reason == NEEDS_VEH_REPAIR ) { - p.activity_vehicle_part_index = -1; - } - continue; - } else { - p.backlog.push_front( activity_to_restore ); - p.assign_activity( activity_id( "ACT_FETCH_REQUIRED" ) ); - p.backlog.front().str_values.push_back( what_we_need.str() ); - p.backlog.front().values.push_back( reason ); - // come back here after succesfully fetching your stuff - std::vector candidates; - if( p.backlog.front().coords.empty() ) { - std::vector local_src_set; - for( const auto elem : src_set ) { - local_src_set.push_back( g->m.getlocal( elem ) ); - } - std::vector candidates; - for( const auto point_elem : g->m.points_in_radius( src_loc, PICKUP_RANGE - 1 ) ) { - // we dont want to place the components where they could interfere with our ( or someone elses ) construction spots - if( ( std::find( local_src_set.begin(), local_src_set.end(), - point_elem ) != local_src_set.end() ) || !g->m.can_put_items_ter_furn( point_elem ) ) { - continue; - } - candidates.push_back( point_elem ); - } - if( candidates.empty() ) { - p.activity = player_activity(); - p.backlog.clear(); - check_npc_revert( p ); - return; - } - p.backlog.front().coords.push_back( g->m.getabs( candidates[std::max( 0, - static_cast( candidates.size() / 2 ) )] ) ); - } - p.backlog.front().placement = src; - - return; - } } + + //move to location is required? if( square_dist( p.pos(), src_loc ) > 1 ) { // not adjacent std::vector route = route_adjacent( p, src_loc ); @@ -2625,72 +2763,8 @@ void generic_multi_activity_handler( player_activity &act, player &p ) p.set_destination( route, player_activity( activity_to_restore ) ); return; } - // something needs to be done, now we are there. - // it was here earlier, in the space of one turn, maybe it got harvested by someone else. - if( reason == NEEDS_HARVESTING && g->m.has_flag_furn( "GROWTH_HARVEST", src_loc ) ) { - iexamine::harvest_plant( p, src_loc, true ); - } else if( reason == NEEDS_TILLING && g->m.has_flag( "PLOWABLE", src_loc ) && - p.has_quality( quality_id( "DIG" ), 1 ) && !g->m.has_furn( src_loc ) ) { - p.assign_activity( activity_id( "ACT_CHURN" ), 18000, -1 ); - p.backlog.push_front( activity_to_restore ); - p.activity.placement = src; - return; - } else if( reason == NEEDS_PLANTING && g->m.has_flag_ter_or_furn( "PLANTABLE", src_loc ) ) { - if( !plant_activity( p, zone, src_loc ) ) { - continue; - } - } else if( reason == NEEDS_CHOPPING && p.has_quality( quality_id( "AXE" ), 1 ) ) { - if( chop_plank_activity( p, src_loc ) ) { - p.backlog.push_front( activity_to_restore ); - return; - } - } else if( reason == NEEDS_BUTCHERING || reason == NEEDS_BIG_BUTCHERING ) { - p.backlog.push_front( activity_to_restore ); - if( butcher_corpse_activity( p, src_loc, reason ) ) { - return; - } - } else if( reason == CAN_DO_CONSTRUCTION || reason == CAN_DO_PREREQ ) { - if( g->m.partial_con_at( src_loc ) ) { - p.backlog.push_front( activity_to_restore ); - p.assign_activity( activity_id( "ACT_BUILD" ) ); - p.activity.placement = src; - return; - } - construction_activity( p, zone, src_loc, act_info, list_constructions, activity_to_restore ); - return; - } else if( reason == CAN_DO_FETCH && activity_to_restore == activity_id( "ACT_TIDY_UP" ) ) { - if( !tidy_activity( p, src_loc, activity_to_restore ) ) { - return; - } - } else if( reason == CAN_DO_FETCH && activity_to_restore == activity_id( "ACT_FETCH_REQUIRED" ) ) { - fetch_activity( p, src_loc, activity_to_restore ); - // Npcs will automatically start the next thing in the backlog, players need to be manually prompted - // Because some player activities are necessarily not marked as auto-resume. - activity_handlers::resume_for_multi_activities( p ); - return; - } else if( reason == NEEDS_TREE_CHOPPING && p.has_quality( quality_id( "AXE" ), 1 ) ) { - p.backlog.push_front( activity_to_restore ); - if( chop_tree_activity( p, src_loc ) ) { - return; - } - } else if( reason == NEEDS_FISHING && p.has_quality( quality_id( "FISHING" ), 1 ) ) { - p.backlog.push_front( activity_to_restore ); - // we dont want to keep repeating the fishing activity, just piggybacking on this functions structure to find requirements. - p.activity = player_activity(); - item *best_rod = best_quality_item( p, quality_id( "FISHING" ) ); - p.assign_activity( activity_id( "ACT_FISH" ), to_moves( 5_hours ), 0, - p.get_item_position( best_rod ), best_rod->tname() ); - p.activity.coord_set = g->get_fishable_locations( 60, src_loc ); - return; - } else if( reason == NEEDS_VEH_DECONST ) { - p.backlog.push_front( activity_to_restore ); - vehicle_activity( p, src_loc, p.activity_vehicle_part_index, 'o' ); - p.activity_vehicle_part_index = -1; - return; - } else if( reason == NEEDS_VEH_REPAIR ) { - p.backlog.push_front( activity_to_restore ); - vehicle_activity( p, src_loc, p.activity_vehicle_part_index, 'r' ); - p.activity_vehicle_part_index = -1; + //do the activity and continue if possible + if( !generic_multi_activity_do( p, activity_to_restore, act_info, src, src_loc ) ) { return; } } From 2db0bfd5b1072bf21947a6a9e4ed71e8460dc390 Mon Sep 17 00:00:00 2001 From: ipcyborg Date: Thu, 19 Sep 2019 15:39:43 +0300 Subject: [PATCH 2/2] Fixed typo --- src/activity_item_handling.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 57fa85a73b3e6..f4aa13a269016 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2441,7 +2441,7 @@ static std::unordered_set generic_multi_activity_locations( player &p, return src_set; } -/** Check if this activity can not be done immidiately because it has some requirements */ +/** Check if this activity can not be done immediately because it has some requirements */ /** Returns true if this multi activity may be processed further */ static bool generic_multi_activity_check_requirement( player &p, const activity_id &act_id, activity_reason_info &act_info,