diff --git a/src/lang/english.txt b/src/lang/english.txt index eba78574a4..cdb9746c78 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4965,6 +4965,9 @@ STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Empty STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} from {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} from {STATION} (x{NUM}) +STR_VEHICLE_DETAILS_TRAIN_TOTAL_WEIGHT :{BLACK}Total weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}(empty) - {LTBLUE}{WEIGHT_SHORT} {BLACK}(loaded) +STR_VEHICLE_DETAILS_TRAIN_MAX_SPEED :{BLACK}Max. speed: {LTBLUE}{VELOCITY} {BLACK}(empty) - {LTBLUE}{VELOCITY} {BLACK}(loaded) + STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Cargo STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Show details of cargo carried STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Information diff --git a/src/lang/german.txt b/src/lang/german.txt index 880ecdd4a6..1561c796a8 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -4821,6 +4821,9 @@ STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Leer STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} von {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} von {STATION} (x{NUM}) +STR_VEHICLE_DETAILS_TRAIN_TOTAL_WEIGHT :{BLACK}Gesamtgewicht: {LTBLUE}{WEIGHT_SHORT} {BLACK}(leer) – {LTBLUE}{WEIGHT_SHORT} {BLACK}(beladen) +STR_VEHICLE_DETAILS_TRAIN_MAX_SPEED :{BLACK}Max. Geschwindigkeit: {LTBLUE}{VELOCITY} {BLACK}(leer) - {LTBLUE}{VELOCITY} {BLACK}(beladen) + STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Fracht STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Zeige Einzelheiten zur geladenen Fracht STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Information diff --git a/src/train.h b/src/train.h index 6fd5186dd6..ee831d1f79 100644 --- a/src/train.h +++ b/src/train.h @@ -267,7 +267,7 @@ public: return const_cast(const_cast(this)->GetStationLoadingVehicle()); } - inline uint16 GetCargoWeight(uint cargo_amount) const + uint16 GetCargoWeight(uint cargo_amount) const { if (cargo_amount > 0) { return (CargoSpec::Get(this->cargo_type)->weight * cargo_amount * FreightWagonMult(this->cargo_type)) / 16; @@ -276,6 +276,36 @@ public: } } + /** + * Allows to know the weight value that this vehicle will use (excluding cargo). + * @return Weight value from the engine in tonnes. + */ + uint16 GetWeightWithoutCargo() const + { + uint16 weight = 0; + + /* Vehicle weight is not added for articulated parts. */ + if (!this->IsArticulatedPart()) { + weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight); + } + + /* Powered wagons have extra weight added. */ + if (HasBit(this->flags, VRF_POWEREDWAGON)) { + weight += RailVehInfo(this->gcache.first_engine)->pow_wag_weight; + } + + return weight; + } + + /** + * Allows to know the weight value that this vehicle will use (cargo only). + * @return Weight value from the engine in tonnes. + */ + uint16 GetCargoWeight() const + { + return this->GetCargoWeight(this->cargo.StoredCount()); + } + protected: // These functions should not be called outside acceleration code. /** * Gets the speed a broken down train (low speed breakdown) is limited to. @@ -327,36 +357,6 @@ protected: // These functions should not be called outside acceleration code. return 0; } - /** - * Allows to know the weight value that this vehicle will use (excluding cargo). - * @return Weight value from the engine in tonnes. - */ - inline uint16 GetWeightWithoutCargo() const - { - uint16 weight = 0; - - /* Vehicle weight is not added for articulated parts. */ - if (!this->IsArticulatedPart()) { - weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight); - } - - /* Powered wagons have extra weight added. */ - if (HasBit(this->flags, VRF_POWEREDWAGON)) { - weight += RailVehInfo(this->gcache.first_engine)->pow_wag_weight; - } - - return weight; - } - - /** - * Allows to know the weight value that this vehicle will use (cargo only). - * @return Weight value from the engine in tonnes. - */ - inline uint16 GetCargoWeight() const - { - return this->GetCargoWeight(this->cargo.StoredCount()); - } - /** * Allows to know the weight value that this vehicle will use. * @return Weight value from the engine in tonnes. diff --git a/src/train_gui.cpp b/src/train_gui.cpp index 51b50e4e25..6985c01d5b 100644 --- a/src/train_gui.cpp +++ b/src/train_gui.cpp @@ -390,7 +390,12 @@ int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab) for (CargoID i = 0; i < NUM_CARGO; i++) { if (max_cargo[i] > 0) num++; // only count carriages that the train has } - num++; // needs one more because first line is description string + + if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) { + num += 5; // needs five more because first line is description string and we have the weight and speed info and the feeder share + } else { + num += 2; // needs one more because first line is description string and we have the feeder share + } } else { for (const Train *v = Train::Get(veh_id); v != nullptr; v = v->GetNextVehicle()) { GetCargoSummaryOfArticulatedVehicle(v, &_cargo_summary); @@ -405,6 +410,65 @@ int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab) return num; } +int GetAcceleration(const Train *train, const int speed, const int mass) +{ + const int64 power = train->gcache.cached_power * 746ll; + int64 resistance = 0; + + const bool maglev = (GetRailTypeInfo(train->railtype)->acceleration_type == 2); + + if (!maglev) { + /* Static resistance plus rolling friction. */ + resistance = 10 * mass; + resistance += mass * (15 * (512 + speed) / 512); + } + + const int area = 14; + + resistance += (area * train->gcache.cached_air_drag * speed * speed) / 1000; + + uint32 max_te = train->gcache.cached_max_te; // [N] + int64 force; + + if (speed > 0) { + if (!maglev) { + /* Conversion factor from km/h to m/s is 5/18 to get [N] in the end. */ + force = power * 18 / (speed * 5); + + if (force > static_cast(max_te)) { + force = max_te; + } + } else { + force = power / 25; + } + } else { + force = (!maglev) ? std::min(max_te, power) : power; + force = std::max(force, (mass * 8) + resistance); + } + + /* Easy way out when there is no acceleration. */ + if (force == resistance) return 0; + + int acceleration = ClampToI32((force - resistance) / (mass * 4)); + acceleration = force < resistance ? std::min(-1, acceleration) : std::max(1, acceleration); + + return acceleration; +} + +int GetMaxSpeed(const Train *train, const int mass, const int speed_cap) +{ + int max_speed = 0; + int acceleration; + + do + { + max_speed++; + acceleration = GetAcceleration(train, max_speed, mass); + } while (acceleration > 0 && max_speed < speed_cap); + + return max_speed; +} + /** * Draw the details for the given vehicle at the given position * @@ -512,19 +576,49 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po CargoArray act_cargo; CargoArray max_cargo; Money feeder_share = 0; + int empty_weight = 0; + int loaded_weight = 0; for (const Vehicle *u = v; u != nullptr; u = u->Next()) { + const Train *train = Train::From(u); + const auto weight_without_cargo = train->GetWeightWithoutCargo(); act_cargo[u->cargo_type] += u->cargo.StoredCount(); max_cargo[u->cargo_type] += u->cargo_cap; feeder_share += u->cargo.FeederShare(); + empty_weight += weight_without_cargo; + loaded_weight += weight_without_cargo + train->GetCargoWeight(train->cargo_cap); } - /* draw total cargo tab */ - DrawString(left, right, y + text_y_offset, STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT); - y += line_height; + if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) { + const int empty_max_speed = GetMaxSpeed(v, empty_weight, v->GetDisplayMaxSpeed()); + const int loaded_max_speed = GetMaxSpeed(v, loaded_weight, v->GetDisplayMaxSpeed()); + + if (--vscroll_pos < 0 && vscroll_pos >= -vscroll_cap) { + SetDParam(0, empty_weight); + SetDParam(1, loaded_weight); + DrawString(left, right, y + text_y_offset, STR_VEHICLE_DETAILS_TRAIN_TOTAL_WEIGHT); + y += line_height; + } + + if (--vscroll_pos < 0 && vscroll_pos >= -vscroll_cap) { + SetDParam(0, empty_max_speed); + SetDParam(1, loaded_max_speed); + DrawString(left, right, y + text_y_offset, STR_VEHICLE_DETAILS_TRAIN_MAX_SPEED); + y += line_height; + } + + if (--vscroll_pos < 0 && vscroll_pos >= -vscroll_cap) { + y += line_height; + } + } + + if (--vscroll_pos < 0 && vscroll_pos >= -vscroll_cap) { + DrawString(left, right, y + text_y_offset, STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT); + y += line_height; + } for (CargoID i = 0; i < NUM_CARGO; i++) { - if (max_cargo[i] > 0 && --vscroll_pos < 0 && vscroll_pos > -vscroll_cap) { + if (max_cargo[i] > 0 && --vscroll_pos < 0 && vscroll_pos >= -vscroll_cap) { SetDParam(0, i); // {CARGO} #1 SetDParam(1, act_cargo[i]); // {CARGO} #2 SetDParam(2, i); // {SHORTCARGO} #1 @@ -534,7 +628,16 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po y += line_height; } } - SetDParam(0, feeder_share); - DrawString(left, right, y + text_y_offset, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE); + + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { + act_cargo[u->cargo_type] += u->cargo.StoredCount(); + max_cargo[u->cargo_type] += u->cargo_cap; + feeder_share += u->cargo.FeederShare(); + } + + if (--vscroll_pos < 0 && vscroll_pos >= -vscroll_cap) { + SetDParam(0, feeder_share); + DrawString(left, right, y + text_y_offset, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE); + } } }