Ejemplo n.º 1
0
bool game::grabbed_veh_move( const tripoint &dp )
{
    const optional_vpart_position grabbed_vehicle_vp = m.veh_at( u.pos() + u.grab_point );
    if( !grabbed_vehicle_vp ) {
        add_msg( m_info, _( "No vehicle at grabbed point." ) );
        u.grab( OBJECT_NONE );
        return false;
    }
    vehicle *grabbed_vehicle = &grabbed_vehicle_vp->vehicle();
    const int grabbed_part = grabbed_vehicle_vp->part_index();

    const vehicle *veh_under_player = veh_pointer_or_null( m.veh_at( u.pos() ) );
    if( grabbed_vehicle == veh_under_player ) {
        u.grab_point = -dp;
        return false;
    }

    tripoint dp_veh = -u.grab_point;
    const tripoint prev_grab = u.grab_point;
    tripoint next_grab = u.grab_point;

    bool zigzag = false;

    if( dp == prev_grab ) {
        // We are pushing in the direction of vehicle
        dp_veh = dp;
    } else if( abs( dp.x + dp_veh.x ) != 2 && abs( dp.y + dp_veh.y ) != 2 ) {
        // Not actually moving the vehicle, don't do the checks
        u.grab_point = -( dp + dp_veh );
        return false;
    } else if( ( dp.x == prev_grab.x || dp.y == prev_grab.y ) &&
               next_grab.x != 0 && next_grab.y != 0 ) {
        // Zig-zag (or semi-zig-zag) pull: player is diagonal to vehicle
        // and moves away from it, but not directly away
        dp_veh.x = ( dp.x == -dp_veh.x ) ? 0 : dp_veh.x;
        dp_veh.y = ( dp.y == -dp_veh.y ) ? 0 : dp_veh.y;

        next_grab = -dp_veh;
        zigzag = true;
    } else {
        // We are pulling the vehicle
        next_grab = -dp;
    }

    // Make sure the mass and pivot point are correct
    grabbed_vehicle->invalidate_mass();

    //vehicle movement: strength check
    int mc = 0;
    int str_req = ( grabbed_vehicle->total_mass() / 25_kilogram ); //strength required to move vehicle.

    //if vehicle is rollable we modify str_req based on a function of movecost per wheel.

    // Vehicle just too big to grab & move; 41-45 lets folks have a bit of a window
    // (Roughly 1.1K kg = danger zone; cube vans are about the max)
    if( str_req > 45 ) {
        add_msg( m_info, _( "The %s is too bulky for you to move by hand." ),
                 grabbed_vehicle->name );
        return true; // No shoving around an RV.
    }

    const auto &wheel_indices = grabbed_vehicle->wheelcache;
    if( grabbed_vehicle->valid_wheel_config() ) {
        //determine movecost for terrain touching wheels
        const tripoint vehpos = grabbed_vehicle->global_pos3();
        for( int p : wheel_indices ) {
            const tripoint wheel_pos = vehpos + grabbed_vehicle->parts[p].precalc[0];
            const int mapcost = m.move_cost( wheel_pos, grabbed_vehicle );
            mc += ( str_req / wheel_indices.size() ) * mapcost;
        }
        //set strength check threshold
        //if vehicle has many or only one wheel (shopping cart), it is as if it had four.
        if( wheel_indices.size() > 4 || wheel_indices.size() == 1 ) {
            str_req = mc / 4 + 1;
        } else {
            str_req = mc / wheel_indices.size() + 1;
        }
    } else {
        str_req++;
        //if vehicle has no wheels str_req make a noise.
        if( str_req <= u.get_str() ) {
            sounds::sound( grabbed_vehicle->global_pos3(), str_req * 2, sounds::sound_t::movement,
                           _( "a scraping noise." ), true, "misc", "scraping" );
        }
    }

    //final strength check and outcomes
    ///\EFFECT_STR determines ability to drag vehicles
    if( str_req <= u.get_str() ) {
        //calculate exertion factor and movement penalty
        ///\EFFECT_STR increases speed of dragging vehicles
        u.moves -= 100 * str_req / std::max( 1, u.get_str() );
        const int ex = dice( 1, 3 ) - 1 + str_req;
        if( ex > u.get_str() ) {
            add_msg( m_bad, _( "You strain yourself to move the %s!" ), grabbed_vehicle->name );
            u.moves -= 200;
            u.mod_pain( 1 );
        } else if( ex == u.get_str() ) {
            u.moves -= 200;
            add_msg( _( "It takes some time to move the %s." ), grabbed_vehicle->name );
        }
    } else {
        u.moves -= 100;
        add_msg( m_bad, _( "You lack the strength to move the %s" ), grabbed_vehicle->name );
        return true;
    }

    std::string blocker_name = _( "errors in movement code" );
    const auto get_move_dir = [&]( const tripoint & dir, const tripoint & from ) {
        tileray mdir;

        mdir.init( dir.x, dir.y );
        grabbed_vehicle->turn( mdir.dir() - grabbed_vehicle->face.dir() );
        grabbed_vehicle->face = grabbed_vehicle->turn_dir;
        grabbed_vehicle->precalc_mounts( 1, mdir.dir(), grabbed_vehicle->pivot_point() );

        // Grabbed part has to stay at distance 1 to the player
        // and in roughly the same direction.
        const tripoint new_part_pos = grabbed_vehicle->global_pos3() +
                                      grabbed_vehicle->parts[ grabbed_part ].precalc[ 1 ];
        const tripoint expected_pos = u.pos() + dp + from;
        const tripoint actual_dir = expected_pos - new_part_pos;

        // Set player location to illegal value so it can't collide with vehicle.
        const tripoint player_prev = u.pos();
        u.setpos( tripoint_zero );
        std::vector<veh_collision> colls;
        const bool failed = grabbed_vehicle->collision( colls, actual_dir, true );
        u.setpos( player_prev );
        if( !colls.empty() ) {
            blocker_name = colls.front().target_name;
        }
        return failed ? tripoint_zero : actual_dir;
    };

    // First try the move as intended
    // But if that fails and the move is a zig-zag, try to recover:
    // Try to place the vehicle in the position player just left rather than "flattening" the zig-zag
    tripoint final_dp_veh = get_move_dir( dp_veh, next_grab );
    if( final_dp_veh == tripoint_zero && zigzag ) {
        final_dp_veh = get_move_dir( -prev_grab, -dp );
        next_grab = -dp;
    }

    if( final_dp_veh == tripoint_zero ) {
        add_msg( _( "The %s collides with %s." ), grabbed_vehicle->name, blocker_name );
        u.grab_point = prev_grab;
        return true;
    }

    u.grab_point = next_grab;

    tripoint gp = grabbed_vehicle->global_pos3();
    grabbed_vehicle = m.displace_vehicle( gp, final_dp_veh );

    if( grabbed_vehicle == nullptr ) {
        debugmsg( "Grabbed vehicle disappeared" );
        return false;
    }

    for( int p : wheel_indices ) {
        if( one_in( 2 ) ) {
            tripoint wheel_p = grabbed_vehicle->global_part_pos3( grabbed_part );
            grabbed_vehicle->handle_trap( wheel_p, p );
        }
    }

    return false;

}
Ejemplo n.º 2
0
void inventory::form_from_map( map &m, const tripoint &origin, int range, bool assign_invlet,
                               bool clear_path )
{
    items.clear();
    for( const tripoint &p : m.points_in_radius( origin, range ) ) {
        // can not reach this -> can not access its contents
        if( clear_path ) {
            if( origin != p && !m.clear_path( origin, p, range, 1, 100 ) ) {
                continue;
            }
        }
        if( m.has_furn( p ) ) {
            const furn_t &f = m.furn( p ).obj();
            const itype *type = f.crafting_pseudo_item_type();
            if( type != nullptr ) {
                const itype *ammo = f.crafting_ammo_item_type();
                item furn_item( type, calendar::turn, 0 );
                furn_item.item_tags.insert( "PSEUDO" );
                furn_item.charges = ammo ? count_charges_in_list( ammo, m.i_at( p ) ) : 0;
                add_item( furn_item );
            }
        }
        if( m.accessible_items( p ) ) {
            for( auto &i : m.i_at( p ) ) {
                if( !i.made_of( LIQUID ) ) {
                    add_item( i, false, assign_invlet );
                }
            }
        }
        // Kludges for now!
        if( m.has_nearby_fire( p, 0 ) ) {
            item fire( "fire", 0 );
            fire.charges = 1;
            add_item( fire );
        }
        // Handle any water from infinite map sources.
        item water = m.water_from( p );
        if( !water.is_null() ) {
            add_item( water );
        }
        // kludge that can probably be done better to check specifically for toilet water to use in
        // crafting
        if( m.furn( p ).obj().examine == &iexamine::toilet ) {
            // get water charges at location
            auto toilet = m.i_at( p );
            auto water = toilet.end();
            for( auto candidate = toilet.begin(); candidate != toilet.end(); ++candidate ) {
                if( candidate->typeId() == "water" ) {
                    water = candidate;
                    break;
                }
            }
            if( water != toilet.end() && water->charges > 0 ) {
                add_item( *water );
            }
        }

        // keg-kludge
        if( m.furn( p ).obj().examine == &iexamine::keg ) {
            auto liq_contained = m.i_at( p );
            for( auto &i : liq_contained ) {
                if( i.made_of( LIQUID ) ) {
                    add_item( i );
                }
            }
        }

        // WARNING: The part below has a bug that's currently quite minor
        // When a vehicle has multiple faucets in range, available water is
        //  multiplied by the number of faucets.
        // Same thing happens for all other tools and resources, but not cargo
        const optional_vpart_position vp = m.veh_at( p );
        if( !vp ) {
            continue;
        }
        vehicle *const veh = &vp->vehicle();

        //Adds faucet to kitchen stuff; may be horribly wrong to do such....
        //ShouldBreak into own variable
        const cata::optional<vpart_reference> kpart = vp.part_with_feature( "KITCHEN", true );
        const cata::optional<vpart_reference> faupart = vp.part_with_feature( "FAUCET", true );
        const cata::optional<vpart_reference> weldpart = vp.part_with_feature( "WELDRIG", true );
        const cata::optional<vpart_reference> craftpart = vp.part_with_feature( "CRAFTRIG", true );
        const cata::optional<vpart_reference> forgepart = vp.part_with_feature( "FORGE", true );
        const cata::optional<vpart_reference> kilnpart = vp.part_with_feature( "KILN", true );
        const cata::optional<vpart_reference> chempart = vp.part_with_feature( "CHEMLAB", true );
        const cata::optional<vpart_reference> cargo = vp.part_with_feature( "CARGO", true );

        if( cargo ) {
            const auto items = veh->get_items( cargo->part_index() );
            *this += std::list<item>( items.begin(), items.end() );
        }

        if( faupart ) {
            for( const auto &it : veh->fuels_left() ) {
                item fuel( it.first, 0 );
                if( fuel.made_of( LIQUID ) ) {
                    fuel.charges = it.second;
                    add_item( fuel );
                }
            }
        }

        if( kpart ) {
            item hotplate( "hotplate", 0 );
            hotplate.charges = veh->fuel_left( "battery", true );
            hotplate.item_tags.insert( "PSEUDO" );
            add_item( hotplate );

            item pot( "pot", 0 );
            pot.item_tags.insert( "PSEUDO" );
            add_item( pot );
            item pan( "pan", 0 );
            pan.item_tags.insert( "PSEUDO" );
            add_item( pan );
        }
        if( weldpart ) {
            item welder( "welder", 0 );
            welder.charges = veh->fuel_left( "battery", true );
            welder.item_tags.insert( "PSEUDO" );
            add_item( welder );

            item soldering_iron( "soldering_iron", 0 );
            soldering_iron.charges = veh->fuel_left( "battery", true );
            soldering_iron.item_tags.insert( "PSEUDO" );
            add_item( soldering_iron );
        }
        if( craftpart ) {
            item vac_sealer( "vac_sealer", 0 );
            vac_sealer.charges = veh->fuel_left( "battery", true );
            vac_sealer.item_tags.insert( "PSEUDO" );
            add_item( vac_sealer );

            item dehydrator( "dehydrator", 0 );
            dehydrator.charges = veh->fuel_left( "battery", true );
            dehydrator.item_tags.insert( "PSEUDO" );
            add_item( dehydrator );

            item food_processor( "food_processor", 0 );
            food_processor.charges = veh->fuel_left( "battery", true );
            food_processor.item_tags.insert( "PSEUDO" );
            add_item( food_processor );

            item press( "press", 0 );
            press.charges = veh->fuel_left( "battery", true );
            press.item_tags.insert( "PSEUDO" );
            add_item( press );
        }
        if( forgepart ) {
            item forge( "forge", 0 );
            forge.charges = veh->fuel_left( "battery", true );
            forge.item_tags.insert( "PSEUDO" );
            add_item( forge );
        }
        if( kilnpart ) {
            item kiln( "kiln", 0 );
            kiln.charges = veh->fuel_left( "battery", true );
            kiln.item_tags.insert( "PSEUDO" );
            add_item( kiln );
        }
        if( chempart ) {
            item hotplate( "hotplate", 0 );
            hotplate.charges = veh->fuel_left( "battery", true );
            hotplate.item_tags.insert( "PSEUDO" );
            add_item( hotplate );

            item chemistry_set( "chemistry_set", 0 );
            chemistry_set.charges = veh->fuel_left( "battery", true );
            chemistry_set.item_tags.insert( "PSEUDO" );
            add_item( chemistry_set );
        }
    }
}