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(); }
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; }
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; }
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(); }
turret_data vehicle::turret_query( const tripoint &pos ) { auto res = get_parts( pos, "TURRET" ); return !res.empty() ? turret_query( *res.front() ) : turret_data(); }
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; }