// Algorithm goes as follows: // Clear map // Spawn a vehicle // Set its fuel up to some percentage - remember exact fuel counts that were set here // Drive it for a while, always moving it back to start point every turn to avoid it going off the bubble // When moving back, record the sum of the tiles moved so far // Repeat that for a set number of turns or until all fuel is drained // Compare saved percentage (set before) to current percentage // Rescale the recorded number of tiles based on fuel percentage left // (ie. 0% fuel left means no scaling, 50% fuel left means double the effective distance) // Return the rescaled number long test_efficiency( const vproto_id &veh_id, int &expected_mass, const ter_id &terrain, const int reset_velocity_turn, const long target_distance, const bool smooth_stops = false, const bool test_mass = true ) { long min_dist = target_distance * 0.99; long max_dist = target_distance * 1.01; clear_game( terrain ); const tripoint map_starting_point( 60, 60, 0 ); vehicle *veh_ptr = g->m.add_vehicle( veh_id, map_starting_point, -90, 0, 0 ); REQUIRE( veh_ptr != nullptr ); if( veh_ptr == nullptr ) { return 0; } vehicle &veh = *veh_ptr; // Remove all items from cargo to normalize weight. for( const vpart_reference vp : veh.get_all_parts() ) { while( veh.remove_item( vp.part_index(), 0 ) ); vp.part().ammo_consume( vp.part().ammo_remaining(), vp.pos() ); } for( const vpart_reference vp : veh.get_avail_parts( "OPENABLE" ) ) { veh.close( vp.part_index() ); } veh.refresh_insides(); if( test_mass ) { CHECK( to_gram( veh.total_mass() ) == expected_mass ); } expected_mass = to_gram( veh.total_mass() ); veh.check_falling_or_floating(); REQUIRE( !veh.is_in_water() ); const auto &starting_fuel = set_vehicle_fuel( veh, fuel_level ); // This is ugly, but improves accuracy: compare the result of fuel approx function // rather than the amount of fuel we actually requested const float starting_fuel_per = fuel_percentage_left( veh, starting_fuel ); REQUIRE( std::abs( starting_fuel_per - 1.0f ) < 0.001f ); const tripoint starting_point = veh.global_pos3(); veh.tags.insert( "IN_CONTROL_OVERRIDE" ); veh.engine_on = true; const int target_velocity = std::min( 70 * 100, veh.safe_ground_velocity( false ) ); veh.cruise_velocity = target_velocity; // If we aren't testing repeated cold starts, start the vehicle at cruising velocity. // Otherwise changing the amount of fuel in the tank perturbs the test results. if( reset_velocity_turn == -1 ) { veh.velocity = target_velocity; } int reset_counter = 0; long tiles_travelled = 0; int cycles_left = cycle_limit; bool accelerating = true; CHECK( veh.safe_velocity() > 0 ); while( veh.engine_on && veh.safe_velocity() > 0 && cycles_left > 0 ) { cycles_left--; g->m.vehmove(); veh.idle( true ); // If the vehicle starts skidding, the effects become random and test is RUINED REQUIRE( !veh.skidding ); for( const tripoint &pos : veh.get_points() ) { REQUIRE( g->m.ter( pos ) ); } // How much it moved tiles_travelled += square_dist( starting_point, veh.global_pos3() ); // Bring it back to starting point to prevent it from leaving the map const tripoint displacement = starting_point - veh.global_pos3(); tripoint veh_pos = veh.global_pos3(); g->m.displace_vehicle( veh_pos, displacement ); if( reset_velocity_turn < 0 ) { continue; } reset_counter++; if( reset_counter > reset_velocity_turn ) { if( smooth_stops ) { accelerating = !accelerating; veh.cruise_velocity = accelerating ? target_velocity : 0; } else { veh.velocity = 0; veh.last_turn = 0; veh.of_turn_carry = 0; } reset_counter = 0; } } float fuel_left = fuel_percentage_left( veh, starting_fuel ); REQUIRE( starting_fuel_per - fuel_left > 0.0001f ); const float fuel_percentage_used = fuel_level * ( starting_fuel_per - fuel_left ); long adjusted_tiles_travelled = tiles_travelled / fuel_percentage_used; if( target_distance >= 0 ) { CHECK( adjusted_tiles_travelled >= min_dist ); CHECK( adjusted_tiles_travelled <= max_dist ); } return adjusted_tiles_travelled; }
// Algorithm goes as follows: // Clear map // Spawn a vehicle // Set its fuel up to some percentage - remember exact fuel counts that were set here // Drive it for a while, always moving it back to start point every turn to avoid it going off the bubble // When moving back, record the sum of the tiles moved so far // Repeat that for a set number of turns or until all fuel is drained // Compare saved percentage (set before) to current percentage // Rescale the recorded number of tiles based on fuel percentage left // (ie. 0% fuel left means no scaling, 50% fuel left means double the effective distance) // Return the rescaled number long test_efficiency( const vproto_id &veh_id, const ter_id &terrain, int reset_velocity_turn, long target_distance, bool smooth_stops = false ) { long min_dist = target_distance * 0.99; long max_dist = target_distance * 1.01; clear_game( terrain ); const tripoint map_starting_point( 60, 60, 0 ); vehicle *veh_ptr = g->m.add_vehicle( veh_id, map_starting_point, -90, 100, 0 ); REQUIRE( veh_ptr != nullptr ); if( veh_ptr == nullptr ) { return 0; } vehicle &veh = *veh_ptr; // Remove all items from cargo to normalize weight. for( size_t p = 0; p < veh.parts.size(); p++ ) { auto &pt = veh.parts[ p ]; while( veh.remove_item( p, 0 ) ); } const auto &starting_fuel = set_vehicle_fuel( veh, fuel_level ); // This is ugly, but improves accuracy: compare the result of fuel approx function // rather than the amount of fuel we actually requested const float starting_fuel_per = fuel_percentage_left( veh, starting_fuel ); REQUIRE( std::abs( starting_fuel_per - 1.0f ) < 0.001f ); const tripoint starting_point = veh.global_pos3(); veh.tags.insert( "IN_CONTROL_OVERRIDE" ); veh.engine_on = true; veh.cruise_velocity = veh.safe_velocity(); // If we aren't testing repeated cold starts, start the vehicle at cruising velocity. // Otherwise changing the amount of fuel in the tank perturbs the test results. if( reset_velocity_turn == -1 ) { veh.velocity = veh.cruise_velocity; } int reset_counter = 0; long tiles_travelled = 0; int turn_count = 0; int cycles_left = cycle_limit; bool accelerating = true; CHECK( veh.safe_velocity() > 0 ); while( veh.engine_on && veh.safe_velocity() > 0 && cycles_left > 0 ) { cycles_left--; g->m.vehmove(); veh.idle( true ); // If the vehicle starts skidding, the effects become random and test is RUINED REQUIRE( !veh.skidding ); // How much it moved tiles_travelled += square_dist( starting_point, veh.global_pos3() ); // Bring it back to starting point to prevent it from leaving the map const tripoint displacement = starting_point - veh.global_pos3(); tripoint veh_pos = veh.global_pos3(); g->m.displace_vehicle( veh_pos, displacement ); if( reset_velocity_turn < 0 ) { continue; } reset_counter++; if( reset_counter > reset_velocity_turn ) { if( smooth_stops ) { accelerating = !accelerating; veh.cruise_velocity = accelerating ? veh.safe_velocity() : 0; } else { veh.velocity = 0; veh.last_turn = 0; veh.of_turn_carry = 0; } reset_counter = 0; } } float fuel_left = fuel_percentage_left( veh, starting_fuel ); REQUIRE( starting_fuel_per - fuel_left > 0.0001f ); float fuel_percentage_used = fuel_level * ( starting_fuel_per - fuel_left ); long adjusted_tiles_travelled = tiles_travelled / fuel_percentage_used; if( target_distance >= 0 ) { CHECK( adjusted_tiles_travelled >= min_dist ); CHECK( adjusted_tiles_travelled <= max_dist ); } return adjusted_tiles_travelled; }