From c76090d3ef9186834f34c34de256a3adb0e47238 Mon Sep 17 00:00:00 2001 From: bombasticSlacks Date: Wed, 27 Jul 2022 19:28:44 -0300 Subject: [PATCH] kind of working --- data/json/player_activities.json | 3 +- src/activity_actor.cpp | 328 +++++++++++++++++++++++++++++++ src/activity_actor_definitions.h | 29 +++ src/activity_handlers.cpp | 7 - src/activity_handlers.h | 7 +- src/activity_item_handling.cpp | 266 +------------------------ src/handle_action.cpp | 4 +- 7 files changed, 372 insertions(+), 272 deletions(-) diff --git a/data/json/player_activities.json b/data/json/player_activities.json index bf16ef881cc75..beec23976dbd1 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -479,7 +479,8 @@ "type": "activity_type", "activity_level": "MODERATE_EXERCISE", "verb": "unloading loot", - "based_on": "neither" + "based_on": "neither", + "multi_activity": true }, { "id": "ACT_FETCH_REQUIRED", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 87360befe73f4..de4654fa1c8cc 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -136,6 +136,7 @@ static const activity_id ACT_TENT_DECONSTRUCT( "ACT_TENT_DECONSTRUCT" ); static const activity_id ACT_TENT_PLACE( "ACT_TENT_PLACE" ); static const activity_id ACT_TRY_SLEEP( "ACT_TRY_SLEEP" ); static const activity_id ACT_UNLOAD( "ACT_UNLOAD" ); +static const activity_id ACT_UNLOAD_LOOT( "ACT_UNLOAD_LOOT" ); static const activity_id ACT_WEAR( "ACT_WEAR" ); static const activity_id ACT_WIELD( "ACT_WIELD" ); static const activity_id ACT_WORKOUT_ACTIVE( "ACT_WORKOUT_ACTIVE" ); @@ -208,6 +209,12 @@ static const ter_str_id ter_t_underbrush_harvested_winter( "t_underbrush_harvest static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" ); +static const zone_type_id zone_type_LOOT_IGNORE( "LOOT_IGNORE" ); +static const zone_type_id zone_type_LOOT_IGNORE_FAVORITES( "LOOT_IGNORE_FAVORITES" ); +static const zone_type_id zone_type_zone_disassemble( "zone_disassemble" ); +static const zone_type_id zone_type_zone_strip( "zone_strip" ); +static const zone_type_id zone_type_zone_unload_all( "zone_unload_all" ); + std::string activity_actor::get_progress_message( const player_activity &act ) const { if( act.moves_total > 0 ) { @@ -6004,6 +6011,326 @@ std::unique_ptr mop_activity_actor::deserialize( JsonValue &jsin return actor.clone(); } + +void unload_loot_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + + jsout.member( "moves", moves ); + + jsout.end_object(); +} + +std::unique_ptr unload_loot_activity_actor::deserialize( JsonValue &jsin ) +{ + unload_loot_activity_actor actor( {} ); + + JsonObject data = jsin.get_object(); + + data.read( "moves", actor.moves ); + + return actor.clone(); +} + +void unload_loot_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = moves; + act.moves_left = moves; +} + +void unload_loot_activity_actor::finish( player_activity &act, Character &who ) +{ + act.set_to_null(); +} + +static void move_item( Character &you, item &it, const int quantity, const tripoint &src, + const tripoint &dest, vehicle *src_veh, int src_part ) +{ + item leftovers = it; + + if( quantity != 0 && it.count_by_charges() ) { + // Reinserting leftovers happens after item removal to avoid stacking issues. + leftovers.charges = it.charges - quantity; + if( leftovers.charges > 0 ) { + it.charges = quantity; + } + } else { + leftovers.charges = 0; + } + + map &here = get_map(); + // Check that we can pick it up. + if( !it.made_of_from_type( phase_id::LIQUID ) ) { + you.mod_moves( -activity_handlers::move_cost( it, src, dest ) ); + + put_into_vehicle_or_drop( you, item_drop_reason::deliberate, { it }, dest ); + // Remove from map or vehicle. + if( src_veh ) { + src_veh->remove_item( src_part, &it ); + } else { + here.i_rem( src, &it ); + } + } + + // If we didn't pick up a whole stack, put the remainder back where it came from. + if( leftovers.charges > 0 ) { + if( src_veh ) { + if( !src_veh->add_item( src_part, leftovers ) ) { + debugmsg( "SortLoot: Source vehicle failed to receive leftover charges." ); + } + } else { + here.add_item_or_charges( src, leftovers ); + } + } +} + +void unload_loot_activity_actor::do_turn( player_activity &act, Character &you ) +{ + enum activity_stage : int { + //Initial stage + INIT = 0, + //Think about what to do first: choose destination + THINK, + //Do activity + DO, + }; + + faction const *fac = you.get_faction(); + faction_id fac_id = fac == nullptr ? faction_id() : fac->id; + + map &here = get_map(); + const tripoint_abs_ms abspos = you.get_location(); + zone_manager &mgr = zone_manager::get_manager(); + if( here.check_vehicle_zones( here.get_abs_sub().z() ) ) { + mgr.cache_vzones(); + } + + if( stage == INIT ) { + // TODO: fix point types + coord_set.clear(); + for( const tripoint_abs_ms &p : + mgr.get_near( zone_type_zone_unload_all, abspos, ACTIVITY_SEARCH_DISTANCE, nullptr, + fac_id ) ) { + coord_set.insert( p.raw() ); + } + + for( const tripoint_abs_ms &p : + mgr.get_near( zone_type_zone_strip, abspos, ACTIVITY_SEARCH_DISTANCE, nullptr, + fac_id ) ) { + coord_set.insert( p.raw() ); + } + stage = THINK; + } + + if( stage == THINK ) { + //initialize num_processed + num_processed = 0; + // TODO: fix point types + std::vector src_set; + for( const tripoint &p : coord_set ) { + src_set.emplace_back( tripoint_abs_ms( p ) ); + } + // sort source tiles by distance + const auto &src_sorted = get_sorted_tiles_by_distance( abspos, src_set ); + + for( const tripoint_abs_ms &src : src_sorted ) { + // TODO: fix point types + placement = src.raw(); + coord_set.erase( src.raw() ); + + const tripoint &src_loc = here.getlocal( src ); + if( !here.inbounds( src_loc ) ) { + if( !here.inbounds( you.pos() ) ) { + // p is implicitly an NPC that has been moved off the map, so reset the activity + // and unload them + you.cancel_activity(); + you.assign_activity( ACT_UNLOAD_LOOT ); + you.set_moves( 0 ); + g->reload_npcs(); + return; + } + std::vector route; + route = here.route( you.pos(), src_loc, you.get_pathfinding_settings(), + you.get_path_avoid() ); + if( route.empty() ) { + // can't get there, can't do anything, skip it + continue; + } + stage = DO; + you.set_destination( route, act ); + you.activity.set_to_null(); + return; + } + + // skip tiles in IGNORE zone and tiles on fire + // (to prevent taking out wood off the lit brazier) + // and inaccessible furniture, like filled charcoal kiln + if( mgr.has( zone_type_LOOT_IGNORE, src, fac_id ) || + here.get_field( src_loc, fd_fire ) != nullptr || + !here.can_put_items_ter_furn( src_loc ) ) { + continue; + } + + //nothing to sort? + const cata::optional vp = here.veh_at( src_loc ).part_with_feature( "CARGO", + false ); + if( ( !vp || vp->vehicle().get_items( vp->part_index() ).empty() ) + && here.i_at( src_loc ).empty() ) { + continue; + } + + bool is_adjacent_or_closer = square_dist( you.pos(), src_loc ) <= 1; + // before we unload any item, check if player is at or + // adjacent to the loot source tile + if( !is_adjacent_or_closer ) { + std::vector route; + bool adjacent = false; + + // get either direct route or route to nearest adjacent tile if + // source tile is impassable + if( here.passable( src_loc ) ) { + route = here.route( you.pos(), src_loc, you.get_pathfinding_settings(), + you.get_path_avoid() ); + } else { + // impassable source tile (locker etc.), + // get route to nearest adjacent tile instead + route = route_adjacent( you, src_loc ); + adjacent = true; + } + + // check if we found path to source / adjacent tile + if( route.empty() ) { + add_msg( m_info, _( "%s can't reach the source tile." ), + you.disp_name() ); + continue; + } + + // shorten the route to adjacent tile, if necessary + if( !adjacent ) { + route.pop_back(); + } + + // set the destination and restart activity after player arrives there + // we don't need to check for safe mode, + // activity will be restarted only if + // player arrives on destination tile + stage = DO; + you.set_destination( route, act ); + you.activity.set_to_null(); + return; + } + stage = DO; + break; + } + } + if( stage == DO ) { + // TODO: fix point types + const tripoint_abs_ms src( placement ); + const tripoint src_loc = here.getlocal( src ); + + bool is_adjacent_or_closer = square_dist( you.pos(), src_loc ) <= 1; + // before we move any item, check if player is at or + // adjacent to the loot source tile + if( !is_adjacent_or_closer ) { + stage = THINK; + return; + } + + // the boolean in this pair being true indicates the item is from a vehicle storage space + auto items = std::vector>(); + vehicle *src_veh; + int src_part; + + //Check source for cargo part + //map_stack and vehicle_stack are different types but inherit from item_stack + // TODO: use one for loop + if( const cata::optional vp = here.veh_at( src_loc ).part_with_feature( "CARGO", + false ) ) { + src_veh = &vp->vehicle(); + src_part = vp->part_index(); + for( item &it : src_veh->get_items( src_part ) ) { + items.emplace_back( &it, true ); + } + } else { + src_veh = nullptr; + src_part = -1; + } + for( item &it : here.i_at( src_loc ) ) { + items.emplace_back( &it, false ); + } + + //Skip items that have already been processed + for( auto it = items.begin() + num_processed; it < items.end(); ++it ) { + ++num_processed; + item &thisitem = *it->first; + + // skip unpickable liquid + if( thisitem.made_of_from_type( phase_id::LIQUID ) ) { + continue; + } + + // skip favorite items in ignore favorite zones + if( thisitem.is_favorite && mgr.has( zone_type_LOOT_IGNORE_FAVORITES, src, fac_id ) ) { + continue; + } + + // Only if it's from a vehicle do we use the vehicle source location information. + vehicle *this_veh = it->second ? src_veh : nullptr; + const int this_part = it->second ? src_part : -1; + + // if this item isn't going anywhere and its not sealed + // check if it is in a unload zone or a strip corpse zone + // then we should unload it and see what is inside + if( mgr.has_near( zone_type_zone_unload_all, abspos, 1, fac_id ) || + ( mgr.has_near( zone_type_zone_strip, abspos, 1, fac_id ) && it->first->is_corpse() ) ) { + if( you.rate_action_unload( *it->first ) == hint_rating::good && + !it->first->any_pockets_sealed() ) { + for( item *contained : it->first->all_items_top( item_pocket::pocket_type::CONTAINER ) ) { + // no liquids don't want to spill stuff + if( !contained->made_of( phase_id::LIQUID ) && !contained->made_of( phase_id::GAS ) ) { + move_item( you, *contained, contained->count(), src_loc, src_loc, this_veh, this_part ); + it->first->remove_item( *contained ); + } + } + for( item *contained : it->first->all_items_top( item_pocket::pocket_type::MAGAZINE ) ) { + // no liquids don't want to spill stuff + if( !contained->made_of( phase_id::LIQUID ) && !contained->made_of( phase_id::GAS ) ) { + move_item( you, *contained, contained->count(), src_loc, src_loc, this_veh, this_part ); + it->first->remove_item( *contained ); + } + } + for( item *contained : it->first->all_items_top( item_pocket::pocket_type::MAGAZINE_WELL ) ) { + // no liquids don't want to spill stuff + if( !contained->made_of( phase_id::LIQUID ) && !contained->made_of( phase_id::GAS ) ) { + move_item( you, *contained, contained->count(), src_loc, src_loc, this_veh, this_part ); + it->first->remove_item( *contained ); + } + } + // after dumping items go back to start of activity loop + // so that can re-assess the items in the tile + return; + } + } + + if( you.moves <= 0 ) { + return; + } + } + + //this location is sorted + stage = THINK; + return; + } + + // If we got here without restarting the activity, it means we're done + add_msg( m_info, _( "%s sorted out every item possible." ), you.disp_name( false, true ) ); + if( you.is_npc() ) { + npc *guy = dynamic_cast( &you ); + guy->revert_after_activity(); + } + act.set_to_null(); +} + namespace activity_actors { @@ -6061,6 +6388,7 @@ deserialize_functions = { { ACT_TENT_PLACE, &tent_placement_activity_actor::deserialize }, { ACT_TRY_SLEEP, &try_sleep_activity_actor::deserialize }, { ACT_UNLOAD, &unload_activity_actor::deserialize }, + { ACT_UNLOAD_LOOT, &unload_loot_activity_actor::deserialize }, { ACT_WEAR, &wear_activity_actor::deserialize }, { ACT_WIELD, &wield_activity_actor::deserialize}, { ACT_WORKOUT_ACTIVE, &workout_activity_actor::deserialize }, diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index 49d1aa347463e..34a9905931e6f 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -1843,4 +1843,33 @@ class mop_activity_actor : public activity_actor int moves; }; +class unload_loot_activity_actor : public activity_actor +{ + public: + unload_loot_activity_actor() = default; + explicit unload_loot_activity_actor( int moves ) : moves( moves ) {} + + activity_id get_type() const override { + return activity_id( "ACT_UNLOAD_LOOT" ); + } + + void start( player_activity &act, Character &who ) override; + void do_turn( player_activity &act, Character &you ) override; + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonValue &jsin ); + + private: + int moves; + int num_processed; + int stage; + std::unordered_set coord_set; + tripoint placement; +}; + #endif // CATA_SRC_ACTIVITY_ACTOR_DEFINITIONS_H diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 7ff23d1dfd8a6..aced06b48812a 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -158,7 +158,6 @@ static const activity_id ACT_TRAIN( "ACT_TRAIN" ); static const activity_id ACT_TRAIN_TEACHER( "ACT_TRAIN_TEACHER" ); static const activity_id ACT_TRAVELLING( "ACT_TRAVELLING" ); static const activity_id ACT_TREE_COMMUNION( "ACT_TREE_COMMUNION" ); -static const activity_id ACT_UNLOAD_LOOT( "ACT_UNLOAD_LOOT" ); static const activity_id ACT_VEHICLE( "ACT_VEHICLE" ); static const activity_id ACT_VEHICLE_DECONSTRUCTION( "ACT_VEHICLE_DECONSTRUCTION" ); static const activity_id ACT_VEHICLE_REPAIR( "ACT_VEHICLE_REPAIR" ); @@ -245,7 +244,6 @@ activity_handlers::do_turn_functions = { { ACT_CONSUME_FUEL_MENU, consume_fuel_menu_do_turn }, { ACT_VIEW_RECIPE, view_recipe_do_turn }, { ACT_MOVE_LOOT, move_loot_do_turn }, - { ACT_UNLOAD_LOOT, unload_loot_do_turn }, { ACT_ADV_INVENTORY, adv_inventory_do_turn }, { ACT_ARMOR_LAYERS, armor_layers_do_turn }, { ACT_ATM, atm_do_turn }, @@ -2587,11 +2585,6 @@ void activity_handlers::move_loot_do_turn( player_activity *act, Character *you activity_on_turn_move_loot( *act, *you ); } -void activity_handlers::unload_loot_do_turn( player_activity *act, Character *you ) -{ - activity_on_turn_unload_loot( *act, *you ); -} - void activity_handlers::adv_inventory_do_turn( player_activity *, Character *you ) { you->cancel_activity(); diff --git a/src/activity_handlers.h b/src/activity_handlers.h index 5c166ebb17aa4..f4335909dc6cb 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -125,7 +125,6 @@ int butcher_time_to_cut( Character &you, const item &corpse_item, butcher_type a // activity_item_handling.cpp void activity_on_turn_drop(); void activity_on_turn_move_loot( player_activity &act, Character &you ); -void activity_on_turn_unload_loot( player_activity &act, Character &you ); //return true if there is an activity that can be done potentially, return false if no work can be found. bool generic_multi_activity_handler( player_activity &act, Character &you, bool check_only = false ); @@ -195,7 +194,6 @@ void study_spell_do_turn( player_activity *act, Character *you ); void tidy_up_do_turn( player_activity *act, Character *you ); void travel_do_turn( player_activity *act, Character *you ); void tree_communion_do_turn( player_activity *act, Character *you ); -void unload_loot_do_turn( player_activity *act, Character *you ); void vehicle_deconstruction_do_turn( player_activity *act, Character *you ); void vehicle_repair_do_turn( player_activity *act, Character *you ); void vibe_do_turn( player_activity *act, Character *you ); @@ -240,6 +238,11 @@ void wait_stamina_finish( player_activity *act, Character *you ); void wait_weather_finish( player_activity *act, Character *you ); void washing_finish( player_activity *act, Character *you ); +int move_cost( const item &it, const tripoint &src, const tripoint &dest ); +int move_cost_cart( const item &it, const tripoint &src, const tripoint &dest, + const units::volume &capacity ); +int move_cost_inv( const item &it, const tripoint &src, const tripoint &dest ); + // defined in activity_handlers.cpp extern const std::map< activity_id, std::function > finish_functions; diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 58c9f31efa34c..17a40d5c7b7a3 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -85,7 +85,6 @@ static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); static const activity_id ACT_TIDY_UP( "ACT_TIDY_UP" ); -static const activity_id ACT_UNLOAD_LOOT( "ACT_UNLOAD_LOOT" ); static const activity_id ACT_VEHICLE( "ACT_VEHICLE" ); static const activity_id ACT_VEHICLE_DECONSTRUCTION( "ACT_VEHICLE_DECONSTRUCTION" ); static const activity_id ACT_VEHICLE_REPAIR( "ACT_VEHICLE_REPAIR" ); @@ -534,7 +533,8 @@ static double get_capacity_fraction( int capacity, int volume ) return fr; } -static int move_cost_inv( const item &it, const tripoint &src, const tripoint &dest ) +int activity_handlers::move_cost_inv( const item &it, const tripoint &src, + const tripoint &dest ) { // to prevent potentially ridiculous number const int MAX_COST = 500; @@ -567,8 +567,8 @@ static int move_cost_inv( const item &it, const tripoint &src, const tripoint &d return std::min( pickup_cost + drop_cost + move_cost, MAX_COST ); } -static int move_cost_cart( const item &it, const tripoint &src, const tripoint &dest, - const units::volume &capacity ) +int activity_handlers::move_cost_cart( const item &it, const tripoint &src, + const tripoint &dest, const units::volume &capacity ) { // to prevent potentially ridiculous number const int MAX_COST = 500; @@ -595,7 +595,7 @@ static int move_cost_cart( const item &it, const tripoint &src, const tripoint & return std::min( pickup_cost + drop_cost + move_cost, MAX_COST ); } -static int move_cost( const item &it, const tripoint &src, const tripoint &dest ) +int activity_handlers::move_cost( const item &it, const tripoint &src, const tripoint &dest ) { avatar &player_character = get_avatar(); if( player_character.get_grab_type() == object_type::VEHICLE ) { @@ -693,7 +693,7 @@ static void move_item( Character &you, item &it, const int quantity, const tripo map &here = get_map(); // Check that we can pick it up. if( !it.made_of_from_type( phase_id::LIQUID ) ) { - you.mod_moves( -move_cost( it, src, dest ) ); + you.mod_moves( -activity_handlers::move_cost( it, src, dest ) ); if( activity_to_restore == ACT_TIDY_UP ) { it.erase_var( "activity_var" ); } else if( activity_to_restore == ACT_FETCH_REQUIRED ) { @@ -2295,259 +2295,6 @@ void activity_on_turn_move_loot( player_activity &act, Character &you ) you.activity.set_to_null(); } -void activity_on_turn_unload_loot( player_activity &act, Character &you ) -{ - enum activity_stage : int { - //Initial stage - INIT = 0, - //Think about what to do first: choose destination - THINK, - //Do activity - DO, - }; - - int &stage = act.index; - //Prepare activity stage - if( stage < 0 ) { - stage = INIT; - //num_processed - act.values.push_back( 0 ); - } - int &num_processed = act.values[0]; - - map &here = get_map(); - const tripoint_abs_ms abspos = you.get_location(); - zone_manager &mgr = zone_manager::get_manager(); - if( here.check_vehicle_zones( here.get_abs_sub().z() ) ) { - mgr.cache_vzones(); - } - - if( stage == INIT ) { - // TODO: fix point types - act.coord_set.clear(); - for( const tripoint_abs_ms &p : - mgr.get_near( zone_type_zone_unload_all, abspos, ACTIVITY_SEARCH_DISTANCE, nullptr, - _fac_id( you ) ) ) { - act.coord_set.insert( p.raw() ); - } - - for( const tripoint_abs_ms &p : - mgr.get_near( zone_type_zone_strip, abspos, ACTIVITY_SEARCH_DISTANCE, nullptr, - _fac_id( you ) ) ) { - act.coord_set.insert( p.raw() ); - } - stage = THINK; - } - - if( stage == THINK ) { - //initialize num_processed - num_processed = 0; - // TODO: fix point types - std::vector src_set; - for( const tripoint &p : act.coord_set ) { - src_set.emplace_back( tripoint_abs_ms( p ) ); - } - // sort source tiles by distance - const auto &src_sorted = get_sorted_tiles_by_distance( abspos, src_set ); - - for( const tripoint_abs_ms &src : src_sorted ) { - // TODO: fix point types - act.placement = src.raw(); - act.coord_set.erase( src.raw() ); - - const tripoint &src_loc = here.getlocal( src ); - if( !here.inbounds( src_loc ) ) { - if( !here.inbounds( you.pos() ) ) { - // p is implicitly an NPC that has been moved off the map, so reset the activity - // and unload them - you.cancel_activity(); - you.assign_activity( ACT_UNLOAD_LOOT ); - you.set_moves( 0 ); - g->reload_npcs(); - return; - } - std::vector route; - route = here.route( you.pos(), src_loc, you.get_pathfinding_settings(), - you.get_path_avoid() ); - if( route.empty() ) { - // can't get there, can't do anything, skip it - continue; - } - stage = DO; - you.set_destination( route, act ); - you.activity.set_to_null(); - return; - } - - // skip tiles in IGNORE zone and tiles on fire - // (to prevent taking out wood off the lit brazier) - // and inaccessible furniture, like filled charcoal kiln - if( mgr.has( zone_type_LOOT_IGNORE, src, _fac_id( you ) ) || - here.get_field( src_loc, fd_fire ) != nullptr || - !here.can_put_items_ter_furn( src_loc ) ) { - continue; - } - - //nothing to sort? - const cata::optional vp = here.veh_at( src_loc ).part_with_feature( "CARGO", - false ); - if( ( !vp || vp->vehicle().get_items( vp->part_index() ).empty() ) - && here.i_at( src_loc ).empty() ) { - continue; - } - - bool is_adjacent_or_closer = square_dist( you.pos(), src_loc ) <= 1; - // before we unload any item, check if player is at or - // adjacent to the loot source tile - if( !is_adjacent_or_closer ) { - std::vector route; - bool adjacent = false; - - // get either direct route or route to nearest adjacent tile if - // source tile is impassable - if( here.passable( src_loc ) ) { - route = here.route( you.pos(), src_loc, you.get_pathfinding_settings(), - you.get_path_avoid() ); - } else { - // impassable source tile (locker etc.), - // get route to nearest adjacent tile instead - route = route_adjacent( you, src_loc ); - adjacent = true; - } - - // check if we found path to source / adjacent tile - if( route.empty() ) { - add_msg( m_info, _( "%s can't reach the source tile." ), - you.disp_name() ); - continue; - } - - // shorten the route to adjacent tile, if necessary - if( !adjacent ) { - route.pop_back(); - } - - // set the destination and restart activity after player arrives there - // we don't need to check for safe mode, - // activity will be restarted only if - // player arrives on destination tile - stage = DO; - you.set_destination( route, act ); - you.activity.set_to_null(); - return; - } - stage = DO; - break; - } - } - if( stage == DO ) { - // TODO: fix point types - const tripoint_abs_ms src( act.placement ); - const tripoint src_loc = here.getlocal( src ); - - bool is_adjacent_or_closer = square_dist( you.pos(), src_loc ) <= 1; - // before we move any item, check if player is at or - // adjacent to the loot source tile - if( !is_adjacent_or_closer ) { - stage = THINK; - return; - } - - // the boolean in this pair being true indicates the item is from a vehicle storage space - auto items = std::vector>(); - vehicle *src_veh; - int src_part; - - //Check source for cargo part - //map_stack and vehicle_stack are different types but inherit from item_stack - // TODO: use one for loop - if( const cata::optional vp = here.veh_at( src_loc ).part_with_feature( "CARGO", - false ) ) { - src_veh = &vp->vehicle(); - src_part = vp->part_index(); - for( item &it : src_veh->get_items( src_part ) ) { - items.emplace_back( &it, true ); - } - } else { - src_veh = nullptr; - src_part = -1; - } - for( item &it : here.i_at( src_loc ) ) { - items.emplace_back( &it, false ); - } - - //Skip items that have already been processed - for( auto it = items.begin() + num_processed; it < items.end(); ++it ) { - ++num_processed; - item &thisitem = *it->first; - - // skip unpickable liquid - if( thisitem.made_of_from_type( phase_id::LIQUID ) ) { - continue; - } - - // skip favorite items in ignore favorite zones - if( thisitem.is_favorite && mgr.has( zone_type_LOOT_IGNORE_FAVORITES, src, _fac_id( you ) ) ) { - continue; - } - - // Only if it's from a vehicle do we use the vehicle source location information. - vehicle *this_veh = it->second ? src_veh : nullptr; - const int this_part = it->second ? src_part : -1; - - // if this item isn't going anywhere and its not sealed - // check if it is in a unload zone or a strip corpse zone - // then we should unload it and see what is inside - if( mgr.has_near( zone_type_zone_unload_all, abspos, 1, _fac_id( you ) ) || - ( mgr.has_near( zone_type_zone_strip, abspos, 1, _fac_id( you ) ) && it->first->is_corpse() ) ) { - if( you.rate_action_unload( *it->first ) == hint_rating::good && - !it->first->any_pockets_sealed() ) { - for( item *contained : it->first->all_items_top( item_pocket::pocket_type::CONTAINER ) ) { - // no liquids don't want to spill stuff - if( !contained->made_of( phase_id::LIQUID ) && !contained->made_of( phase_id::GAS ) ) { - move_item( you, *contained, contained->count(), src_loc, src_loc, this_veh, this_part ); - it->first->remove_item( *contained ); - } - } - for( item *contained : it->first->all_items_top( item_pocket::pocket_type::MAGAZINE ) ) { - // no liquids don't want to spill stuff - if( !contained->made_of( phase_id::LIQUID ) && !contained->made_of( phase_id::GAS ) ) { - move_item( you, *contained, contained->count(), src_loc, src_loc, this_veh, this_part ); - it->first->remove_item( *contained ); - } - } - for( item *contained : it->first->all_items_top( item_pocket::pocket_type::MAGAZINE_WELL ) ) { - // no liquids don't want to spill stuff - if( !contained->made_of( phase_id::LIQUID ) && !contained->made_of( phase_id::GAS ) ) { - move_item( you, *contained, contained->count(), src_loc, src_loc, this_veh, this_part ); - it->first->remove_item( *contained ); - } - } - // after dumping items go back to start of activity loop - // so that can re-assess the items in the tile - return; - } - } - - if( you.moves <= 0 ) { - return; - } - } - - //this location is sorted - stage = THINK; - return; - } - - // If we got here without restarting the activity, it means we're done - add_msg( m_info, _( "%s sorted out every item possible." ), you.disp_name( false, true ) ); - if( you.is_npc() ) { - npc *guy = dynamic_cast( &you ); - guy->revert_after_activity(); - } - you.activity.set_to_null(); -} - static int chop_moves( Character &you, item *it ) { // quality of tool @@ -3295,7 +3042,6 @@ bool generic_multi_activity_handler( player_activity &act, Character &you, bool if( activity_to_restore != ACT_TIDY_UP && activity_to_restore != ACT_MULTIPLE_MOP && activity_to_restore != ACT_MOVE_LOOT && - activity_to_restore != ACT_UNLOAD_LOOT && activity_to_restore != ACT_FETCH_REQUIRED && you.fine_detail_vision_mod( you.pos() ) > 4.0 ) { you.add_msg_if_player( m_info, _( "It is too dark to work here." ) ); diff --git a/src/handle_action.cpp b/src/handle_action.cpp index e72f1a74e151b..6b3088216717a 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -106,7 +106,6 @@ static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); static const activity_id ACT_PULP( "ACT_PULP" ); static const activity_id ACT_SPELLCASTING( "ACT_SPELLCASTING" ); -static const activity_id ACT_UNLOAD_LOOT( "ACT_UNLOAD_LOOT" ); static const activity_id ACT_VEHICLE_DECONSTRUCTION( "ACT_VEHICLE_DECONSTRUCTION" ); static const activity_id ACT_VEHICLE_REPAIR( "ACT_VEHICLE_REPAIR" ); static const activity_id ACT_WAIT( "ACT_WAIT" ); @@ -1368,7 +1367,8 @@ static void loot() player_character.assign_activity( ACT_MOVE_LOOT ); break; case UnloadLoot: - player_character.assign_activity( ACT_UNLOAD_LOOT ); + player_character.assign_activity( + player_activity( unload_loot_activity_actor() ) ); break; case FertilizePlots: player_character.assign_activity( ACT_FERTILIZE_PLOT );