diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index d2092a0927..f090e8827c 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -192,7 +192,7 @@ GroundVehicleAcceleration GroundVehicle::GetAcceleration() /* This value allows to know if the vehicle is accelerating or braking. */ AccelStatus mode = v->GetAccelerationStatus(); - const int braking_power = power; + int braking_power = power; /* handle breakdown power reduction */ uint32 max_te = this->gcache.cached_max_te; // [N] @@ -225,6 +225,10 @@ GroundVehicleAcceleration GroundVehicle::GetAcceleration() braking_force = force; } + if (Type == VEH_TRAIN && _settings_game.vehicle.train_braking_model == TBM_REALISTIC) { + braking_power += (Train::From(this)->gcache.cached_total_length * (int64)RBC_BRAKE_POWER_PER_LENGTH); + } + /* If power is 0 because of a breakdown, we make the force 0 if accelerating */ if (Type == VEH_TRAIN && mode == AS_ACCEL && HasBit(Train::From(this)->flags, VRF_BREAKDOWN_POWER) && power == 0) { force = 0; @@ -265,7 +269,7 @@ GroundVehicleAcceleration GroundVehicle::GetAcceleration() /* Assume that every part of a train is braked, not just the engine. * Exceptionally heavy freight trains should still have a sensible braking distance. * The total braking force is generally larger than the total tractive force. */ - braking_accel = ClampToI32((-braking_force - resistance - (this->gcache.cached_total_length * 300)) / mass); + braking_accel = ClampToI32((-braking_force - resistance - (Train::From(this)->gcache.cached_total_length * (int64)RBC_BRAKE_FORCE_PER_LENGTH)) / (mass * 4)); /* Defensive driving: prevent ridiculously fast deceleration. * -130 corresponds to a braking distance of about 6.2 tiles from 160 km/h. */ diff --git a/src/train.h b/src/train.h index f18c73a250..2d9363050e 100644 --- a/src/train.h +++ b/src/train.h @@ -71,6 +71,11 @@ enum ConsistChangeFlags { }; DECLARE_ENUM_AS_BIT_SET(ConsistChangeFlags) +enum RealisticBrakingConstants { + RBC_BRAKE_FORCE_PER_LENGTH = 1600, ///< Additional force-based brake force per unit of train length + RBC_BRAKE_POWER_PER_LENGTH = 15000, ///< Additional power-based brake force per unit of train length (excludes maglevs) +}; + byte FreightWagonMult(CargoID cargo); void CheckTrainsLengths(); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 275687d3d2..5ced14876b 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -797,24 +797,24 @@ static int GetRealisticBrakingSpeedForDistance(const TrainDecelerationStats &sta /* calculate speed at which braking would be sufficient */ uint weight = stats.t->gcache.cached_weight; - int64 power_w = stats.t->gcache.cached_power * 746ll; - int64 min_braking_force = (stats.t->gcache.cached_total_length * 300) + stats.t->gcache.cached_axle_resistance + (weight * 16); + int64 power_w = (stats.t->gcache.cached_power * 746ll) + (stats.t->gcache.cached_total_length * (int64)RBC_BRAKE_POWER_PER_LENGTH); + int64 min_braking_force = (stats.t->gcache.cached_total_length * (int64)RBC_BRAKE_FORCE_PER_LENGTH) + stats.t->gcache.cached_axle_resistance + (weight * 16); /* F = (7/8) * (F_min + ((power_w * 18) / (5 * v))) - * v^2 = sloped_ke + F * s / m - * let k = sloped_ke + ((7 * F_min * s) / (8 * m)) - * v^3 - k * v - (7 * 18 * power_w * s) / (5 * 8 * m) = 0 + * v^2 = sloped_ke + F * s / (4 * m) + * let k = sloped_ke + ((7 * F_min * s) / (8 * 4 * m)) + * v^3 - k * v - (7 * 18 * power_w * s) / (5 * 8 * 4 * m) = 0 * v^3 + p * v + q = 0 * where: p = -k - * q = -(7 * 18 * power_w * s) / (5 * 8 * m) + * q = -(7 * 18 * power_w * s) / (5 * 8 * 4 * m) * * v = cbrt(-q / 2 + sqrt((q^2 / 4) - (k^3 / 27))) + cbrt(-q / 2 - sqrt((q^2 / 4) - (k^3 / 27))) - * let r = - q / 2 = (7 * 9 * power_w * s) / (5 * 8 * m) + * let r = - q / 2 = (7 * 9 * power_w * s) / (5 * 8 * 4 * m) * let l = k / 3 * v = cbrt(r + sqrt(r^2 - l^3)) + cbrt(r - sqrt(r^2 - l^3)) */ int64 l = (sloped_ke + ((7 * min_braking_force * (int64)distance) / (8 * weight))) / 3; - int64 r = (7 * 9 * power_w * (int64)distance) / (40 * weight); + int64 r = (7 * 9 * power_w * (int64)distance) / (160 * weight); int64 sqrt_factor = (r * r) - (l * l * l); if (sqrt_factor >= 0) { int64 part = IntSqrt64(sqrt_factor); @@ -1083,7 +1083,7 @@ void Train::UpdateAcceleration() int acceleration_type = this->GetAccelerationType(); bool maglev = (acceleration_type == 2); int64 power_w = power * 746ll; - int64 min_braking_force = this->gcache.cached_total_length * 300; + int64 min_braking_force = this->gcache.cached_total_length * (int64)RBC_BRAKE_FORCE_PER_LENGTH; if (!maglev) { /* From GroundVehicle::GetAcceleration() * force = power * 18 / (speed * 5); @@ -1102,12 +1102,13 @@ void Train::UpdateAcceleration() */ int evaluation_speed = this->vcache.cached_max_speed; int area = 14; + int64 power_b = power_w + ((int64)this->gcache.cached_total_length * RBC_BRAKE_POWER_PER_LENGTH); if (this->gcache.cached_air_drag > 0) { - uint64 v_3 = 1800 * (uint64)power_w / (area * this->gcache.cached_air_drag); + uint64 v_3 = 1800 * (uint64)power_b / (area * this->gcache.cached_air_drag); evaluation_speed = std::min(evaluation_speed, IntCbrt(v_3)); } if (evaluation_speed > 0) { - min_braking_force += power_w * 18 / (evaluation_speed * 5); + min_braking_force += power_b * 18 / (evaluation_speed * 5); min_braking_force += (area * this->gcache.cached_air_drag * evaluation_speed * evaluation_speed) / 1000; } @@ -1122,7 +1123,7 @@ void Train::UpdateAcceleration() min_braking_force += power_w / 25; } min_braking_force -= (min_braking_force >> 3); // Slightly underestimate braking for defensive driving purposes - this->tcache.cached_uncapped_decel = Clamp(min_braking_force / weight, 1, UINT16_MAX); + this->tcache.cached_uncapped_decel = Clamp(min_braking_force / (weight * 4), 1, UINT16_MAX); this->tcache.cached_deceleration = Clamp(this->tcache.cached_uncapped_decel, 1, GetTrainRealisticBrakingTargetDecelerationLimit(acceleration_type)); break; }