예제 #1
0
bool vehicle::turrets_aim()
{
    // reload all turrets and clear any existing targets
    auto opts = turrets();
    for( auto e : opts ) {
        turret_reload( *e );
        e->target.first  = tripoint_min;
        e->target.second = tripoint_min;
    }

    // find radius of a circle centered at u encompassing all points turrets can aim at
    int range = std::accumulate( opts.begin(), opts.end(), 0, [&]( const int lhs,
    const vehicle_part * e ) {
        if( turret_query( *e ) != turret_status::ready ) {
            return lhs;
        }

        tripoint pos = global_part_pos3( *e );
        const int rng = e->base.gun_range();

        int res = 0;
        res = std::max( res, rl_dist( g->u.pos(), { pos.x + rng, pos.y, pos.z } ) );
        res = std::max( res, rl_dist( g->u.pos(), { pos.x - rng, pos.y, pos.z } ) );
        res = std::max( res, rl_dist( g->u.pos(), { pos.x, pos.y + rng, pos.z } ) );
        res = std::max( res, rl_dist( g->u.pos(), { pos.x, pos.y - rng, pos.z } ) );
        return std::max( lhs, res );
    } );

    // fake gun item to aim
    item pointer( "vehicle_pointer" );
    pointer.set_curammo( "pointer_fake_ammo" );
    pointer.ammo_data()->ammo->range = range;

    tripoint pos = g->u.pos();
    std::vector<tripoint> trajectory;

    if( opts.empty() ) {
        add_msg( m_warning, _( "Can't aim turrets: all turrets are offline" ) );
    } else {
        trajectory = g->pl_target_ui( pos, range, &pointer, TARGET_MODE_TURRET );
        g->draw_ter();
    }

    if( !trajectory.empty() ) {
        // set target for any turrets in range
        for( auto e : turrets( trajectory.back() ) ) {
            e->target.second = trajectory.back();
        }
        ///\EFFECT_INT speeds up aiming of vehicle turrets
        g->u.moves = std::min( 0, g->u.moves - 100 + ( 5 * g->u.int_cur ) );
    }

    for( auto e : opts ) {
        turret_unload( *e );
    }

    return !trajectory.empty();
}
예제 #2
0
std::vector<vehicle_part *> vehicle::turrets( const tripoint &target )
{
    std::vector<vehicle_part *> res = turrets();
    // exclude turrets not ready to fire or where target is out of range
    res.erase( std::remove_if( res.begin(), res.end(), [&]( const vehicle_part * e ) {
        return turret_query( *e ).query() != turret_data::status::ready ||
               rl_dist( global_part_pos3( *e ), target ) > e->base.gun_range();
    } ), res.end() );
    return res;
}
예제 #3
0
int vehicle::turret_fire( vehicle_part &pt )
{
    int shots = 0;

    item &gun = pt.base;
    if( !gun.is_gun() ) {
        return false;
    }

    turret_reload( pt );

    switch( turret_query( pt ) ) {
        case turret_status::no_ammo:
            add_msg( m_bad, string_format( _( "The %s is out of ammo." ), pt.name().c_str() ).c_str() );
            break;

        case turret_status::no_power:
            add_msg( m_bad, string_format( _( "The %s is not powered." ), pt.name().c_str() ).c_str() );
            break;

        case turret_status::ready: {
            // Clone the shooter and place them at turret on roof
            auto shooter = g->u;
            shooter.setpos( global_part_pos3( pt ) );
            shooter.add_effect( effect_on_roof, 1 );
            shooter.recoil = abs( velocity ) / 100 / 4;

            tripoint pos = shooter.pos();
            auto trajectory = g->pl_target_ui( pos, gun.gun_range(), &gun, TARGET_MODE_TURRET_MANUAL );
            g->draw_ter();

            if( !trajectory.empty() ) {
                auto mode = gun.gun_current_mode();
                shots = shooter.fire_gun( trajectory.back(), mode.qty, *mode );
            }
            break;
        }

        default:
            debugmsg( "unknown turret status" );
            break;
    }

    turret_unload( pt );
    drain( fuel_type_battery, gun.get_gun_ups_drain() * shots );

    return shots;
}
예제 #4
0
bool vehicle::turrets_aim()
{
    // reload all turrets and clear any existing targets
    auto opts = turrets();
    for( auto e : opts ) {
        e->target.first  = tripoint_min;
        e->target.second = tripoint_min;
    }

    // find radius of a circle centered at u encompassing all points turrets can aim at
    int range = std::accumulate( opts.begin(), opts.end(), 0, [&]( const int lhs, vehicle_part * e ) {

        const auto gun = turret_query( *e );
        if( gun.query() != turret_data::status::ready ) {
            return lhs;
        }

        tripoint pos = global_part_pos3( *e );
        const int rng = gun.range();

        int res = 0;
        res = std::max( res, rl_dist( g->u.pos(), { pos.x + rng, pos.y, pos.z } ) );
        res = std::max( res, rl_dist( g->u.pos(), { pos.x - rng, pos.y, pos.z } ) );
        res = std::max( res, rl_dist( g->u.pos(), { pos.x, pos.y + rng, pos.z } ) );
        res = std::max( res, rl_dist( g->u.pos(), { pos.x, pos.y - rng, pos.z } ) );
        return std::max( lhs, res );
    } );

    if( opts.empty() ) {
        add_msg( m_warning, _( "Can't aim turrets: all turrets are offline" ) );
        return false;
    }

    tripoint pos = g->u.pos();
    std::vector<tripoint> trajectory = g->pl_target_ui( TARGET_MODE_TURRET, nullptr, range );

    if( !trajectory.empty() ) {
        // set target for any turrets in range
        for( auto e : turrets( trajectory.back() ) ) {
            e->target.second = trajectory.back();
        }
        ///\EFFECT_INT speeds up aiming of vehicle turrets
        g->u.moves = std::min( 0, g->u.moves - 100 + ( 5 * g->u.int_cur ) );
    }

    return !trajectory.empty();
}
예제 #5
0
turret_data vehicle::turret_query( const tripoint &pos )
{
    auto res = get_parts( pos, "TURRET" );
    return !res.empty() ? turret_query( *res.front() ) : turret_data();
}
예제 #6
0
int vehicle::automatic_fire_turret( vehicle_part &pt )
{
    auto gun = turret_query( pt );
    if( gun.query() != turret_data::status::ready ) {
        return 0;
    }

    tripoint pos = global_part_pos3( pt );

    npc tmp;
    tmp.set_fake( true );
    tmp.name = rmp_format( _( "<veh_player>The %s" ), pt.name().c_str() );
    tmp.set_skill_level( gun.base()->gun_skill(), 8 );
    tmp.set_skill_level( skill_id( "gun" ), 4 );
    tmp.recoil = abs( velocity ) / 100 / 4;
    tmp.setpos( pos );
    tmp.str_cur = 16;
    tmp.dex_cur = 8;
    tmp.per_cur = 12;
    // Assume vehicle turrets are friendly to the player.
    tmp.attitude = NPCATT_FOLLOW;

    int area = aoe_size( gun.ammo_effects() );
    if( area > 0 ) {
        area += area == 1 ? 1 : 2; // Pad a bit for less friendly fire
    }

    tripoint targ = pos;
    auto &target = pt.target;
    if( target.first == target.second ) {
        // Manual target not set, find one automatically
        const bool u_see = g->u.sees( pos );
        int boo_hoo;

        // @todo calculate chance to hit and cap range based upon this
        int range = std::min( gun.range(), 12 );
        Creature *auto_target = tmp.auto_find_hostile_target( range, boo_hoo, area );
        if( auto_target == nullptr ) {
            if( u_see && boo_hoo ) {
                add_msg( m_warning, ngettext( "%s points in your direction and emits an IFF warning beep.",
                                              "%s points in your direction and emits %d annoyed sounding beeps.",
                                              boo_hoo ),
                         tmp.name.c_str(), boo_hoo );
            }
            return 0;
        }

        targ = auto_target->pos();
    } else if( target.first != target.second ) {
        // Target set manually
        // Make sure we didn't move between aiming and firing (it's a bug if we did)
        if( targ != target.first ) {
            target.second = target.first;
            return 0;
        }

        targ = target.second;
        // Remove the target
        target.second = target.first;
    } else {
        // Shouldn't happen
        target.first = target.second;
        return 0;
    }

    auto shots = gun.fire( tmp, targ );

    if( g->u.sees( pos ) && shots ) {
        add_msg( _( "The %1$s fires its %2$s!" ), name.c_str(), pt.name().c_str() );
    }

    return shots;
}