void put_into_vehicle_or_drop( Character &c, item_drop_reason reason, const std::list<item> &items, const tripoint &where, bool force_ground ) { const cata::optional<vpart_reference> vp = g->m.veh_at( where ).part_with_feature( "CARGO", false ); if( vp && !force_ground ) { put_into_vehicle( c, reason, items, vp->vehicle(), vp->part_index() ); return; } drop_on_map( c, reason, items, where ); }
// I'd love to have this not duplicate so much code from Pickup::pick_one_up(), // but I don't see a clean way to do that. static void move_items( player &p, const tripoint &src, bool from_vehicle, const tripoint &dest, bool to_vehicle, std::list<int> &indices, std::list<int> &quantities ) { tripoint source = src + p.pos(); tripoint destination = dest + p.pos(); int s_cargo = -1; vehicle *s_veh = nullptr; // load vehicle information if requested if( from_vehicle ) { const cata::optional<vpart_reference> vp = g->m.veh_at( source ).part_with_feature( "CARGO", false ); assert( vp ); s_veh = &vp->vehicle(); s_cargo = vp->part_index(); assert( s_cargo >= 0 ); } while( p.moves > 0 && !indices.empty() ) { int index = indices.back(); int quantity = quantities.back(); indices.pop_back(); quantities.pop_back(); item *temp_item = from_vehicle ? g->m.item_from( s_veh, s_cargo, index ) : g->m.item_from( source, index ); if( temp_item == nullptr ) { continue; // No such item. } item leftovers = *temp_item; if( quantity != 0 && temp_item->count_by_charges() ) { // Reinserting leftovers happens after item removal to avoid stacking issues. leftovers.charges = temp_item->charges - quantity; if( leftovers.charges > 0 ) { temp_item->charges = quantity; } } else { leftovers.charges = 0; } // Check that we can pick it up. if( !temp_item->made_of_from_type( LIQUID ) ) { // This is for hauling across zlevels, remove when going up and down stairs // is no longer teleportation int distance = src.z == dest.z ? std::max( rl_dist( src, dest ), 1 ) : 1; p.mod_moves( -Pickup::cost_to_move_item( p, *temp_item ) * distance ); if( to_vehicle ) { put_into_vehicle_or_drop( p, item_drop_reason::deliberate, { *temp_item }, destination ); } else { drop_on_map( p, item_drop_reason::deliberate, { *temp_item }, destination ); } // Remove from map or vehicle. if( from_vehicle ) { s_veh->remove_item( s_cargo, index ); } else { g->m.i_rem( source, index ); } } // If we didn't pick up a whole stack, put the remainder back where it came from. if( leftovers.charges > 0 ) { bool to_map = !from_vehicle; if( !to_map ) { to_map = !s_veh->add_item( s_cargo, leftovers ); } if( to_map ) { g->m.add_item_or_charges( source, leftovers ); } } } }
void activity_on_turn_wear() { // Wear activity has source square, bools indicating source type, // indices of items on map or position of items in inventory, and quantities of same. tripoint source = g->u.activity.placement + g->u.pos(); bool from_inventory = g->u.activity.values[0]; bool from_vehicle = g->u.activity.values[1]; // load vehicle information if requested int s_cargo = -1; vehicle *s_veh = nullptr; if( from_vehicle ) { const cata::optional<vpart_reference> vp = g->m.veh_at( source ).part_with_feature( "CARGO", false ); assert( vp ); s_veh = &vp->vehicle(); s_cargo = vp->part_index(); assert( s_cargo >= 0 ); } std::list<int> indices; std::list<int> quantities; if( g->u.activity.values.size() % 2 != 0 ) { debugmsg( "ACT_WEAR started with uneven number of values." ); g->u.cancel_activity(); return; } else { // Note i = 2, skipping first 2 elements. for( size_t i = 2; i < g->u.activity.values.size(); i += 2 ) { indices.push_back( g->u.activity.values[i] ); quantities.push_back( g->u.activity.values[ i + 1 ] ); } } g->u.cancel_activity(); while( g->u.moves > 0 && !indices.empty() ) { int index = indices.back(); int quantity = quantities.back(); indices.pop_back(); quantities.pop_back(); if( from_inventory ) { if( g->u.wear( index ) ) { if( --quantity > 0 ) { indices.push_back( index ); quantities.push_back( quantity ); } } } else { item *temp_item = from_vehicle ? g->m.item_from( s_veh, s_cargo, index ) : g->m.item_from( source, index ); if( temp_item == nullptr ) { continue; // No such item. } // On successful wear remove from map or vehicle. if( g->u.wear_item( *temp_item ) ) { if( from_vehicle ) { s_veh->remove_item( s_cargo, index ); } else { g->m.i_rem( source, index ); } } } } // If there are items left, we ran out of moves, so make a new activity with the remainder. if( !indices.empty() ) { g->u.assign_activity( activity_id( "ACT_WEAR" ) ); g->u.activity.placement = source - g->u.pos(); g->u.activity.values.push_back( from_inventory ); g->u.activity.values.push_back( from_vehicle ); while( !indices.empty() ) { g->u.activity.values.push_back( indices.front() ); indices.pop_front(); g->u.activity.values.push_back( quantities.front() ); quantities.pop_front(); } } }
bool Pickup::do_pickup( const tripoint &pickup_target_arg, bool from_vehicle, std::list<int> &indices, std::list<int> &quantities, bool autopickup ) { bool got_water = false; int cargo_part = -1; vehicle *veh = nullptr; bool weight_is_okay = ( g->u.weight_carried() <= g->u.weight_capacity() ); bool volume_is_okay = ( g->u.volume_carried() <= g->u.volume_capacity() ); bool offered_swap = false; // Convert from player-relative to map-relative. tripoint pickup_target = pickup_target_arg + g->u.pos(); // Map of items picked up so we can output them all at the end and // merge dropping items with the same name. PickupMap mapPickup; if( from_vehicle ) { const cata::optional<vpart_reference> vp = g->m.veh_at( pickup_target ).part_with_feature( "CARGO", false ); veh = &vp->vehicle(); cargo_part = vp->part_index(); } bool problem = false; while( !problem && g->u.moves >= 0 && !indices.empty() ) { // Pulling from the back of the (in-order) list of indices insures // that we pull from the end of the vector. int index = indices.back(); int quantity = quantities.back(); // Whether we pick the item up or not, we're done trying to do so, // so remove it from the list. indices.pop_back(); quantities.pop_back(); item *target = nullptr; if( from_vehicle ) { target = g->m.item_from( veh, cargo_part, index ); } else { target = g->m.item_from( pickup_target, index ); } if( target == nullptr ) { continue; // No such item. } problem = !pick_one_up( pickup_target, *target, veh, cargo_part, index, quantity, got_water, offered_swap, mapPickup, autopickup ); } if( !mapPickup.empty() ) { show_pickup_message( mapPickup ); } if( got_water ) { add_msg( m_info, _( "You can't pick up a liquid!" ) ); } if( weight_is_okay && g->u.weight_carried() > g->u.weight_capacity() ) { add_msg( m_bad, _( "You're overburdened!" ) ); } if( volume_is_okay && g->u.volume_carried() > g->u.volume_capacity() ) { add_msg( m_bad, _( "You struggle to carry such a large volume!" ) ); } return !problem; }
// I'd love to have this not duplicate so much code from Pickup::pick_one_up(), // but I don't see a clean way to do that. static void move_items( const tripoint &src, bool from_vehicle, const tripoint &dest, bool to_vehicle, std::list<int> &indices, std::list<int> &quantities ) { tripoint source = src + g->u.pos(); tripoint destination = dest + g->u.pos(); int s_cargo, d_cargo; // oui oui, mon frere s_cargo = d_cargo = -1; vehicle *s_veh, *d_veh; // 2diva4me s_veh = d_veh = nullptr; // load vehicle information if requested if( from_vehicle ) { const cata::optional<vpart_reference> vp = g->m.veh_at( source ).part_with_feature( "CARGO", false ); assert( vp ); s_veh = &vp->vehicle(); s_cargo = vp->part_index(); assert( s_cargo >= 0 ); } if( to_vehicle ) { const cata::optional<vpart_reference> vp = g->m.veh_at( destination ).part_with_feature( "CARGO", false ); assert( vp ); d_veh = &vp->vehicle(); d_cargo = vp->part_index(); assert( d_cargo >= 0 ); } while( g->u.moves > 0 && !indices.empty() ) { int index = indices.back(); int quantity = quantities.back(); indices.pop_back(); quantities.pop_back(); item *temp_item = from_vehicle ? g->m.item_from( s_veh, s_cargo, index ) : g->m.item_from( source, index ); if( temp_item == nullptr ) { continue; // No such item. } item leftovers = *temp_item; if( quantity != 0 && temp_item->count_by_charges() ) { // Reinserting leftovers happens after item removal to avoid stacking issues. leftovers.charges = temp_item->charges - quantity; if( leftovers.charges > 0 ) { temp_item->charges = quantity; } } else { leftovers.charges = 0; } // Check that we can pick it up. if( !temp_item->made_of( LIQUID ) ) { g->u.mod_moves( -Pickup::cost_to_move_item( g->u, *temp_item ) ); if( to_vehicle ) { put_into_vehicle_or_drop( g->u, { *temp_item }, destination ); } else { drop_on_map( g->u, { *temp_item }, destination ); } // Remove from map or vehicle. if( from_vehicle ) { s_veh->remove_item( s_cargo, index ); } else { g->m.i_rem( source, index ); } } // If we didn't pick up a whole stack, put the remainder back where it came from. if( leftovers.charges > 0 ) { bool to_map = !from_vehicle; if( !to_map ) { to_map = !s_veh->add_item( s_cargo, leftovers ); } if( to_map ) { g->m.add_item_or_charges( source, leftovers ); } } } }