diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index f3ba7d7756..66e5b99331 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -30,12 +30,11 @@ void GroundVehicle::PowerChanged() uint16 max_track_speed = v->GetDisplayMaxSpeed(); for (const T *u = v; u != NULL; u = u->Next()) { - uint32 current_power = u->GetPower(); + uint32 current_power = u->GetPower() + u->GetPoweredPartPower(u); total_power += current_power; /* Only powered parts add tractive effort. */ if (current_power > 0) max_te += u->GetWeight() * u->GetTractiveEffort(); - total_power += u->GetPoweredPartPower(v); number_of_parts++; /* Get minimum max speed for this track. */ @@ -43,8 +42,6 @@ void GroundVehicle::PowerChanged() if (track_speed > 0) max_track_speed = min(max_track_speed, track_speed); } - this->acc_cache.cached_axle_resistance = 60 * number_of_parts; - byte air_drag; byte air_drag_value = v->GetAirDrag(); @@ -87,11 +84,14 @@ void GroundVehicle::CargoChanged() for (T *u = T::From(this); u != NULL; u = u->Next()) { uint32 current_weight = u->GetWeight(); weight += current_weight; - u->acc_cache.cached_slope_resistance = current_weight * u->GetSlopeSteepness(); + /* Slope steepness is in percent, result in N. */ + u->acc_cache.cached_slope_resistance = current_weight * u->GetSlopeSteepness() * 100; } /* Store consist weight in cache. */ this->acc_cache.cached_weight = max(1, weight); + /* Friction in bearings and other mechanical parts is 0.1% of the weight (result in N). */ + this->acc_cache.cached_axle_resistance = 10 * weight; /* Now update vehicle power (tractive effort is dependent on weight). */ this->PowerChanged(); @@ -106,7 +106,7 @@ int GroundVehicle::GetAcceleration() const { /* Templated class used for function calls for performance reasons. */ const T *v = T::From(this); - int32 speed = v->GetCurrentSpeed(); + int32 speed = v->GetCurrentSpeed(); // [km/h-ish] /* Weight is stored in tonnes. */ int32 mass = this->acc_cache.cached_weight; @@ -120,16 +120,15 @@ int GroundVehicle::GetAcceleration() const const int area = v->GetAirDragArea(); if (!maglev) { - resistance = (13 * mass) / 10; - resistance += this->acc_cache.cached_axle_resistance; - resistance += (v->GetRollingFriction() * mass * speed) / 1000; - resistance += (area * this->acc_cache.cached_air_drag * speed * speed) / 10000; - } else { - resistance += (area * this->acc_cache.cached_air_drag * speed * speed) / 20000; + /* Static resistance plus rolling friction. */ + resistance = this->acc_cache.cached_axle_resistance; + resistance += mass * v->GetRollingFriction(); } + /* Air drag; the air drag coefficient is in an arbitrary NewGRF-unit, + * so we need some magic conversion factor. */ + resistance += (area * this->acc_cache.cached_air_drag * speed * speed) / 500; resistance += this->GetSlopeResistance(); - resistance *= 4; //[N] /* This value allows to know if the vehicle is accelerating or braking. */ AccelStatus mode = v->GetAccelerationStatus(); @@ -138,9 +137,8 @@ int GroundVehicle::GetAcceleration() const int force; if (speed > 0) { if (!maglev) { - force = power / speed; //[N] - force *= 22; - force /= 10; + /* Conversion factor from km/h to m/s is 5/18 to get [N] in the end. */ + force = power * 18 / (speed * 5); if (mode == AS_ACCEL && force > max_te) force = max_te; } else { force = power / 25; diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp index 77822abc9c..e518e183fa 100644 --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -30,12 +30,12 @@ struct AccelerationCache { uint32 cached_weight; ///< Total weight of the consist. uint32 cached_slope_resistance; ///< Resistance caused by weight when this vehicle part is at a slope. uint32 cached_max_te; ///< Maximum tractive effort of consist. + uint16 cached_axle_resistance; ///< Resistance caused by the axles of the vehicle. /* Cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */ + uint16 cached_max_track_speed; ///< Maximum consist speed limited by track type. uint32 cached_power; ///< Total power of the consist. uint32 cached_air_drag; ///< Air drag coefficient of the vehicle. - uint16 cached_axle_resistance; ///< Resistance caused by the axles of the vehicle. - uint16 cached_max_track_speed; ///< Maximum consist speed limited by track type. }; /** Ground vehicle flags. */ diff --git a/src/roadveh.h b/src/roadveh.h index 96a86bafa7..faaadab355 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -217,11 +217,11 @@ protected: // These functions should not be called outside acceleration code. /** * Gets the area used for calculating air drag. - * @return Area of the engine. + * @return Area of the engine in m^2. */ FORCEINLINE byte GetAirDragArea() const { - return 60; + return 6; } /** @@ -244,21 +244,25 @@ protected: // These functions should not be called outside acceleration code. /** * Calculates the current speed of this vehicle. - * @return Current speed in mph. + * @return Current speed in km/h-ish. */ FORCEINLINE uint16 GetCurrentSpeed() const { - return this->cur_speed * 10 / 32; + return this->cur_speed / 2; } /** * Returns the rolling friction coefficient of this vehicle. - * @return Rolling friction coefficient in [1e-3]. + * @return Rolling friction coefficient in [1e-4]. */ FORCEINLINE uint32 GetRollingFriction() const { - /* Trams have a slightly greater friction coefficient than trains. The rest of road vehicles have bigger values. */ - return (this->roadtype == ROADTYPE_TRAM) ? 50 : 75; + /* Trams have a slightly greater friction coefficient than trains. + * The rest of road vehicles have bigger values. */ + uint32 coeff = (this->roadtype == ROADTYPE_TRAM) ? 40 : 75; + /* The friction coefficient increases with speed in a way that + * it doubles at 128 km/h, triples at 256 km/h and so on. */ + return coeff * (128 + this->GetCurrentSpeed()) / 128; } /** @@ -276,7 +280,7 @@ protected: // These functions should not be called outside acceleration code. */ FORCEINLINE uint32 GetSlopeSteepness() const { - return 20 * _settings_game.vehicle.roadveh_slope_steepness; // 1% slope * slope steepness + return _settings_game.vehicle.roadveh_slope_steepness; } /** diff --git a/src/train.h b/src/train.h index b334c0b92f..d407c48eec 100644 --- a/src/train.h +++ b/src/train.h @@ -438,11 +438,12 @@ protected: // These functions should not be called outside acceleration code. /** * Gets the area used for calculating air drag. - * @return Area of the engine. + * @return Area of the engine in m^2. */ FORCEINLINE byte GetAirDragArea() const { - return 120; + /* Air drag is higher in tunnels due to the limited cross-section. */ + return (this->track == TRACK_BIT_WORMHOLE && this->vehstatus & VS_HIDDEN) ? 28 : 14; } /** @@ -465,20 +466,24 @@ protected: // These functions should not be called outside acceleration code. /** * Calculates the current speed of this vehicle. - * @return Current speed in mph. + * @return Current speed in km/h-ish. */ FORCEINLINE uint16 GetCurrentSpeed() const { - return this->cur_speed * 10 / 16; + return this->cur_speed; } /** * Returns the rolling friction coefficient of this vehicle. - * @return Rolling friction coefficient in [1e-3]. + * @return Rolling friction coefficient in [1e-4]. */ FORCEINLINE uint32 GetRollingFriction() const { - return 35; + /* Rolling friction for steel on steel is between 0.1% and 0.2%, + * but we use a higher value here to get better game-play results. + * The friction coefficient increases with speed in a way that + * it doubles at 512 km/h, triples at 1024 km/h and so on. */ + return 30 * (512 + this->GetCurrentSpeed()) / 512; } /** @@ -496,7 +501,7 @@ protected: // These functions should not be called outside acceleration code. */ FORCEINLINE uint32 GetSlopeSteepness() const { - return 20 * _settings_game.vehicle.train_slope_steepness; // 1% slope * slope steepness + return _settings_game.vehicle.train_slope_steepness; } /**