diff --git a/src/lang/english.txt b/src/lang/english.txt index 80834dfceb..eef5c23806 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4950,6 +4950,7 @@ STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Weight: STR_VEHICLE_INFO_TRAIN_LENGTH :{BLACK}Train length {LTBLUE}{DECIMAL} tile{P "" s} {STRING4} STR_VEHICLE_INFO_WEIGHT_RATIOS :{BLACK}Power / weight: {LTBLUE}{POWER_WEIGHT_RATIO} {BLACK} Max. T.E / weight: {LTBLUE}{FORCE_WEIGHT_RATIO} STR_VEHICLE_INFO_FULL_WEIGHT_WITH_RATIOS :{BLACK}Full weight: {LTBLUE}{WEIGHT_SHORT} {STRING2} +STR_VEHICLE_INFO_MAX_SPEED_LOADED :{BLACK}Max. speed (full): {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit this year: {LTBLUE}{CURRENCY_LONG} (last year: {CURRENCY_LONG}) STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR_LIFETIME :{STRING2} (lifetime: {CURRENCY_LONG}) diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 2fe10c3ca0..f9e56542a1 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3959,7 +3959,7 @@ bool AfterLoadGame() AfterLoadTraceRestrict(); AfterLoadTemplateVehiclesUpdate(); - if (SlXvIsFeaturePresent(XSLFI_TEMPLATE_REPLACEMENT, 1, 5)) { + if (SlXvIsFeaturePresent(XSLFI_TEMPLATE_REPLACEMENT, 1, 7)) { AfterLoadTemplateVehiclesUpdateProperties(); } diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 136b12606c..684f25f39c 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -100,7 +100,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_REVERSE_AT_WAYPOINT, XSCF_NULL, 1, 1, "reverse_at_waypoint", nullptr, nullptr, nullptr }, { XSLFI_VEH_LIFETIME_PROFIT, XSCF_NULL, 1, 1, "veh_lifetime_profit", nullptr, nullptr, nullptr }, { XSLFI_LINKGRAPH_DAY_SCALE, XSCF_NULL, 1, 1, "linkgraph_day_scale", nullptr, nullptr, nullptr }, - { XSLFI_TEMPLATE_REPLACEMENT, XSCF_NULL, 7, 7, "template_replacement", nullptr, nullptr, "TRPL,TMPL" }, + { XSLFI_TEMPLATE_REPLACEMENT, XSCF_NULL, 8, 8, "template_replacement", nullptr, nullptr, "TRPL,TMPL" }, { XSLFI_MORE_RAIL_TYPES, XSCF_NULL, 0, 1, "more_rail_types", nullptr, nullptr, nullptr }, { XSLFI_CARGO_TYPE_ORDERS, XSCF_NULL, 3, 3, "cargo_type_orders", nullptr, nullptr, "ORDX,VEOX" }, { XSLFI_EXTENDED_GAMELOG, XSCF_NULL, 1, 1, "extended_gamelog", nullptr, nullptr, nullptr }, diff --git a/src/saveload/tbtr_template_veh_sl.cpp b/src/saveload/tbtr_template_veh_sl.cpp index 58c3c621df..d2af9a3d4f 100644 --- a/src/saveload/tbtr_template_veh_sl.cpp +++ b/src/saveload/tbtr_template_veh_sl.cpp @@ -40,6 +40,7 @@ const SaveLoad* GTD() { SLE_VAR(TemplateVehicle, empty_weight, SLE_UINT32), SLE_CONDVAR_X(TemplateVehicle, full_weight, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 6)), SLE_VAR(TemplateVehicle, max_te, SLE_UINT32), + SLE_CONDVAR_X(TemplateVehicle, air_drag, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 8)), SLE_CONDVAR_X(TemplateVehicle, ctrl_flags, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 7)), @@ -146,6 +147,7 @@ void AfterLoadTemplateVehiclesUpdateProperties() tv->empty_weight = gcache->cached_weight; tv->full_weight = gcache->cached_weight + full_cargo_weight; tv->max_te = gcache->cached_max_te; + tv->air_drag = gcache->cached_air_drag; delete t; } cur_company.Restore(); diff --git a/src/tbtr_template_gui_create.cpp b/src/tbtr_template_gui_create.cpp index 00d0b3c97f..7893e5eaa8 100644 --- a/src/tbtr_template_gui_create.cpp +++ b/src/tbtr_template_gui_create.cpp @@ -340,6 +340,11 @@ public: } DrawString(8, r.right, y, STR_VEHICLE_INFO_FULL_WEIGHT_WITH_RATIOS); } + if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) { + y += FONT_HEIGHT_NORMAL; + SetDParam(0, GetTrainEstimatedMaxAchievableSpeed(this->virtual_train, gcache->cached_weight + full_cargo_weight, this->virtual_train->GetDisplayMaxSpeed())); + DrawString(8, r.right, y, STR_VEHICLE_INFO_MAX_SPEED_LOADED); + } /* Draw cargo summary */ CargoArray cargo_caps; for (const Train *tmp = this->virtual_train; tmp != nullptr; tmp = tmp->Next()) { diff --git a/src/tbtr_template_gui_main.cpp b/src/tbtr_template_gui_main.cpp index eda053bb19..c9fae86ca9 100644 --- a/src/tbtr_template_gui_main.cpp +++ b/src/tbtr_template_gui_main.cpp @@ -763,6 +763,11 @@ public: } DrawString(8, r.right, top, STR_VEHICLE_INFO_FULL_WEIGHT_WITH_RATIOS); } + if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) { + top += FONT_HEIGHT_NORMAL; + SetDParam(0, GetTemplateVehicleEstimatedMaxAchievableSpeed(tmp, tmp->full_weight, tmp->max_speed)); + DrawString(8, r.right, top, STR_VEHICLE_INFO_MAX_SPEED_LOADED); + } /* Draw cargo summary */ top += ScaleGUITrad(26); diff --git a/src/tbtr_template_vehicle.h b/src/tbtr_template_vehicle.h index a5d4e2192d..90b732ced7 100644 --- a/src/tbtr_template_vehicle.h +++ b/src/tbtr_template_vehicle.h @@ -111,6 +111,7 @@ public: uint32 empty_weight; uint32 full_weight; uint32 max_te; + uint32 air_drag; uint32 ctrl_flags; ///< See: TemplateVehicleControlFlags @@ -218,4 +219,6 @@ short DeleteTemplateReplacementsByGroupID(GroupID); void ReindexTemplateReplacements(); +int GetTemplateVehicleEstimatedMaxAchievableSpeed(const TemplateVehicle *tv, const int mass, const int speed_cap); + #endif /* TEMPLATE_VEH_H */ diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp index 731d095394..d90d00410a 100644 --- a/src/tbtr_template_vehicle_func.cpp +++ b/src/tbtr_template_vehicle_func.cpp @@ -169,6 +169,7 @@ void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicle *prev tmp->empty_weight = std::max(gcache->cached_weight - cargo_weight, 1); tmp->full_weight = std::max(gcache->cached_weight + full_cargo_weight - cargo_weight, 1); tmp->max_te = gcache->cached_max_te; + tmp->air_drag = gcache->cached_air_drag; } virt->GetImage(DIR_W, EIT_IN_DEPOT, &tmp->sprite_seq); @@ -490,3 +491,17 @@ void UpdateAllTemplateVehicleImages() _template_vehicle_images_valid = true; } + +int GetTemplateVehicleEstimatedMaxAchievableSpeed(const TemplateVehicle *tv, const int mass, const int speed_cap) +{ + int max_speed = 0; + int acceleration; + + do + { + max_speed++; + acceleration = GetTrainRealisticAccelerationAtSpeed(max_speed, mass, tv->power, tv->max_te, tv->air_drag, tv->railtype); + } while (acceleration > 0 && max_speed < speed_cap); + + return max_speed; +} diff --git a/src/train.h b/src/train.h index dd2b2734f4..29317db1f2 100644 --- a/src/train.h +++ b/src/train.h @@ -493,6 +493,7 @@ inline int GetTrainStopLocation(StationID station_id, TileIndex tile, Train *v, return GetTrainStopLocation(station_id, tile, v, update_train_state, station_ahead, station_length, v->x_pos, v->y_pos); } +int GetTrainRealisticAccelerationAtSpeed(const int speed, const int mass, const uint32 cached_power, const uint32 max_te, const uint32 air_drag, const RailType railtype); int GetTrainEstimatedMaxAchievableSpeed(const Train *train, const int mass, const int speed_cap); #endif /* TRAIN_H */ diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 6cf27b064b..3b64f9723a 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -6920,12 +6920,12 @@ void TrainBrakesOverheatedBreakdown(Vehicle *v) t->breakdown_severity = 0; } -static int GetTrainRealisticAccelerationAtSpeed(const Train *train, const int speed, const int mass) +int GetTrainRealisticAccelerationAtSpeed(const int speed, const int mass, const uint32 cached_power, const uint32 max_te, const uint32 air_drag, const RailType railtype) { - const int64 power = train->gcache.cached_power * 746ll; + const int64 power = cached_power * 746ll; int64 resistance = 0; - const bool maglev = (GetRailTypeInfo(train->railtype)->acceleration_type == 2); + const bool maglev = (GetRailTypeInfo(railtype)->acceleration_type == 2); if (!maglev) { /* Static resistance plus rolling friction. */ @@ -6935,9 +6935,8 @@ static int GetTrainRealisticAccelerationAtSpeed(const Train *train, const int sp const int area = 14; - resistance += (area * train->gcache.cached_air_drag * speed * speed) / 1000; + resistance += (area * air_drag * speed * speed) / 1000; - uint32 max_te = train->gcache.cached_max_te; // [N] int64 force; if (speed > 0) { @@ -6973,7 +6972,7 @@ int GetTrainEstimatedMaxAchievableSpeed(const Train *train, const int mass, cons do { max_speed++; - acceleration = GetTrainRealisticAccelerationAtSpeed(train, max_speed, mass); + acceleration = GetTrainRealisticAccelerationAtSpeed(max_speed, mass, train->gcache.cached_power, train->gcache.cached_max_te, train->gcache.cached_air_drag, train->railtype); } while (acceleration > 0 && max_speed < speed_cap); return max_speed;