Add wallclock time settings

pull/661/head
Jonathan G Rennison 4 months ago
parent 58f8971f17
commit a48e15dce0

@ -113,7 +113,7 @@ static int32_t ClickChangeDateCheat(int32_t p1, int32_t p2)
/* Change the date. */
CalTime::Detail::SetDate(new_date, CalTime::CurDateFract());
{
if (!EconTime::UsingWallclockUnits()) {
EconTime::Date new_econ_date = new_date.base();
EconTime::DateFract new_econ_date_fract = CalTime::CurDateFract();

@ -246,21 +246,37 @@ CalTime::Date CalTime::ConvertYMDToDate(CalTime::Year year, CalTime::Month month
EconTime::YearMonthDay EconTime::ConvertDateToYMD(EconTime::Date date)
{
/* Process the same as calendar time (for now) */
if (EconTime::UsingWallclockUnits()) {
/* If we're using wallclock units, economy months have 30 days and an economy year has 360 days. */
EconTime::YearMonthDay ymd;
ymd.year =date.base() / EconTime::DAYS_IN_ECONOMY_WALLCLOCK_YEAR;
ymd.month = (date.base() % EconTime::DAYS_IN_ECONOMY_WALLCLOCK_YEAR) / EconTime::DAYS_IN_ECONOMY_WALLCLOCK_MONTH;
ymd.day = date.base() % EconTime::DAYS_IN_ECONOMY_WALLCLOCK_MONTH;
return ymd;
}
/* Process the same as calendar time */
CalTime::YearMonthDay ymd = CalTime::ConvertDateToYMD(date.base());
return { ymd.year.base(), ymd.month, ymd.day };
}
EconTime::Date EconTime::ConvertYMDToDate(EconTime::Year year, EconTime::Month month, EconTime::Day day)
{
/* Process the same as calendar time (for now) */
if (EconTime::UsingWallclockUnits()) {
/* If we're using wallclock units, economy months have 30 days and an economy year has 360 days. */
const int total_months = (year.base() * MONTHS_IN_YEAR) + month;
return (total_months * EconTime::DAYS_IN_ECONOMY_WALLCLOCK_MONTH) + day - 1; // Day is 1-indexed but Date is 0-indexed, hence the - 1.
}
/* Process the same as calendar time */
return CalTime::ConvertYMDToDate(year.base(), month, day).base();
}
bool EconTime::UsingWallclockUnits(bool newgame)
{
/* Always return false (for now) */
return false;
if (newgame) return (_settings_newgame.economy.timekeeping_units == TKU_WALLCLOCK);
return (_settings_game.economy.timekeeping_units == TKU_WALLCLOCK);
}
/** Functions used by the IncreaseDate function */
@ -397,6 +413,18 @@ static void OnNewEconomyDay()
static void IncreaseCalendarDate()
{
/* If calendar day progress is frozen, don't try to advance time. */
if (_settings_game.economy.minutes_per_calendar_year == CalTime::FROZEN_MINUTES_PER_YEAR) return;
/* If we are using a non-default calendar progression speed, we need to check the sub_date_fract before updating date_fract. */
if (_settings_game.economy.minutes_per_calendar_year != CalTime::DEF_MINUTES_PER_YEAR) {
CalTime::Detail::now.sub_date_fract++;
/* Check if we are ready to increment date_fract */
if (CalTime::Detail::now.sub_date_fract < (DAY_TICKS * _settings_game.economy.minutes_per_calendar_year) / CalTime::DEF_MINUTES_PER_YEAR) return;
}
CalTime::Detail::now.sub_date_fract = 0;
CalTime::Detail::now.cal_date_fract++;
if (CalTime::Detail::now.cal_date_fract < DAY_TICKS) return;
CalTime::Detail::now.cal_date_fract = 0;

@ -124,7 +124,7 @@ struct SetDateWindow : Window {
break;
case WID_SD_YEAR:
SetDParamMaxValue(0, this->max_year.base());
SetDParamMaxValue(0, this->max_year);
d = maxdim(d, GetStringBoundingBox(STR_JUST_INT));
break;
}

@ -176,6 +176,10 @@ struct CalTime : public DateDetail::BaseTime<struct CalendarTimeTag> {
static State NewState(Year year);
};
static constexpr int DEF_MINUTES_PER_YEAR = 12;
static constexpr int FROZEN_MINUTES_PER_YEAR = 0;
static constexpr int MAX_MINUTES_PER_YEAR = 10080; // One week of real time. The actual max that doesn't overflow TimerGameCalendar::sub_date_fract is 10627, but this is neater.
static inline const YearMonthDay &CurYMD() { return Detail::now.cal_ymd; }
static inline Year CurYear() { return Detail::now.cal_ymd.year; }
static inline Month CurMonth() { return Detail::now.cal_ymd.month; }
@ -213,20 +217,42 @@ struct CalTime : public DateDetail::BaseTime<struct CalendarTimeTag> {
};
struct EconTime : public DateDetail::BaseTime<struct EconTimeTag> {
using ParentBaseTime = DateDetail::BaseTime<struct EconTimeTag>;
/* Use a state struct to make backup/restore/init simpler */
struct State {
YearMonthDay econ_ymd;
Date econ_date;
DateFract econ_date_fract;
};
static constexpr int DAYS_IN_ECONOMY_WALLCLOCK_YEAR = 360; ///< Days in an economy year, when in wallclock timekeeping mode.
static constexpr int DAYS_IN_ECONOMY_WALLCLOCK_MONTH = 30; ///< Days in an economy month, when in wallclock timekeeping mode.
/* Use a detail struct/namespace to more easily control writes */
struct Detail {
static State now;
static void SetDate(Date date, DateFract fract);
static State NewState(Year year);
/**
* Calculate the date of the first day of a given year.
* @param year the year to get the first day of.
* @return the date (when using wallclock 30-day months).
*/
static constexpr Date DateAtStartOfWallclockModeYear(Year year)
{
return DAYS_IN_ECONOMY_WALLCLOCK_YEAR * year.base();
}
};
/**
* The offset in days from the '_date == 0' till
* 'ConvertYMDToDate(ORIGINAL_BASE_YEAR, 0, 1)', when using wallclock 30-day months
*/
static constexpr Date DAYS_TILL_ORIGINAL_BASE_YEAR_WALLCLOCK_MODE = DAYS_IN_ECONOMY_WALLCLOCK_YEAR * ORIGINAL_BASE_YEAR.base();
static inline const YearMonthDay &CurYMD() { return Detail::now.econ_ymd; }
static inline Year CurYear() { return Detail::now.econ_ymd.year; }
static inline Month CurMonth() { return Detail::now.econ_ymd.month; }
@ -244,6 +270,17 @@ struct EconTime : public DateDetail::BaseTime<struct EconTimeTag> {
}
static bool UsingWallclockUnits(bool newgame = false);
/**
* Calculate the date of the first day of a given year.
* @param year the year to get the first day of.
* @return the date.
*/
static inline Date DateAtStartOfYear(Year year)
{
if (UsingWallclockUnits()) return Detail::DateAtStartOfWallclockModeYear(year);
return ParentBaseTime::Detail::DateAtStartOfCalendarYear(year);
}
};
namespace DateDetail {

@ -158,7 +158,9 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
if (reset_date) {
CalTime::Detail::SetDate(CalTime::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
{
if (EconTime::UsingWallclockUnits()) {
EconTime::Detail::SetDate(EconTime::DAYS_TILL_ORIGINAL_BASE_YEAR_WALLCLOCK_MODE, 0);
} else {
EconTime::Detail::SetDate(CalTime::CurDate().base(), 0);
}
InitializeOldNames();

@ -431,6 +431,7 @@ uint32_t IndustriesScopeResolver::GetCountAndDistanceOfClosestInstance(byte para
case 0xB3: return this->industry->construction_type; // Construction type
case 0xB4: {
EconTime::Date *latest = std::max_element(this->industry->last_cargo_accepted_at, endof(this->industry->last_cargo_accepted_at));
if (EconTime::UsingWallclockUnits()) return ClampTo<uint16_t>((*latest) - EconTime::DAYS_TILL_ORIGINAL_BASE_YEAR_WALLCLOCK_MODE);
return ClampTo<uint16_t>((*latest) - EconTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date last cargo accepted since 1920 (in days)
}
}

@ -2962,13 +2962,21 @@ void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indic
/**
* Clamp the service interval to the correct min/max. The actual min/max values
* depend on whether it's in percent or days.
* @param interval proposed service interval
* @return Clamped service interval
* depend on whether it's in days, minutes, or percent.
* @param interval The proposed service interval.
* @param ispercent Whether the interval is a percent.
* @return The service interval clamped to use the chosen units.
*/
uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
{
return ispercent ? Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
/* Service intervals are in percents. */
if (ispercent) return Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT);
/* Service intervals are in minutes. */
if (EconTime::UsingWallclockUnits(_game_mode == GM_MENU)) return Clamp(interval, MIN_SERVINT_MINUTES, MAX_SERVINT_MINUTES);
/* Service intervals are in days. */
return Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
}
/**

@ -42,6 +42,13 @@ static const uint DEF_SERVINT_DAYS_SHIPS = 360;
static const uint MIN_SERVINT_DAYS = 30;
static const uint MAX_SERVINT_DAYS = 800;
static const uint DEF_SERVINT_MINUTES_TRAINS = 5;
static const uint DEF_SERVINT_MINUTES_ROADVEH = 5;
static const uint DEF_SERVINT_MINUTES_AIRCRAFT = 3;
static const uint DEF_SERVINT_MINUTES_SHIPS = 12;
static const uint MIN_SERVINT_MINUTES = 1;
static const uint MAX_SERVINT_MINUTES = 30;
static const uint DEF_SERVINT_PERCENT = 50;
static const uint MIN_SERVINT_PERCENT = 5;
static const uint MAX_SERVINT_PERCENT = 90;

@ -873,6 +873,11 @@ bool AfterLoadGame()
* must be done before loading sprites as some newgrfs check it */
CalTime::Detail::SetDate(CalTime::CurDate(), CalTime::CurDateFract());
/* Only new games can use wallclock units. */
if (SlXvIsFeatureMissing(XSLFI_VARIABLE_DAY_LENGTH, 5) && IsSavegameVersionBefore(SLV_ECONOMY_MODE_TIMEKEEPING_UNITS)) {
_settings_game.economy.timekeeping_units = TKU_CALENDAR;
}
if (SlXvIsFeaturePresent(XSLFI_VARIABLE_DAY_LENGTH, 5) || !IsSavegameVersionBefore(SLV_ECONOMY_DATE)) {
EconTime::Detail::SetDate(EconTime::CurDate(), EconTime::CurDateFract());
} else {

@ -1079,6 +1079,12 @@ static void UpdateAllServiceInterval(int32_t new_value)
vds->servint_roadveh = DEF_SERVINT_PERCENT;
vds->servint_aircraft = DEF_SERVINT_PERCENT;
vds->servint_ships = DEF_SERVINT_PERCENT;
} else if (EconTime::UsingWallclockUnits(_game_mode == GM_MENU)) {
/* Service intervals are in minutes. */
vds->servint_trains = DEF_SERVINT_MINUTES_TRAINS;
vds->servint_roadveh = DEF_SERVINT_MINUTES_ROADVEH;
vds->servint_aircraft = DEF_SERVINT_MINUTES_AIRCRAFT;
vds->servint_ships = DEF_SERVINT_MINUTES_SHIPS;
} else {
/* Service intervals are in days. */
vds->servint_trains = DEF_SERVINT_DAYS_TRAINS;
@ -1127,6 +1133,85 @@ static void UpdateServiceInterval(VehicleType type, int32_t new_value)
SetWindowClassesDirty(WC_VEHICLE_DETAILS);
}
/**
* Callback for when the player changes the timekeeping units.
* @param Unused.
*/
static void ChangeTimekeepingUnits(int32_t)
{
/* If service intervals are in time units (calendar days or real-world minutes), reset them to the correct defaults. */
if (!_settings_client.company.vehicle.servint_ispercent) {
UpdateAllServiceInterval(0);
}
/* If we are using calendar timekeeping, "minutes per year" must be default. */
if (_game_mode == GM_MENU && !EconTime::UsingWallclockUnits(true)) {
_settings_newgame.economy.minutes_per_calendar_year = CalTime::DEF_MINUTES_PER_YEAR;
}
InvalidateWindowClassesData(WC_GAME_OPTIONS, 0);
/* It is possible to change these units in Scenario Editor. We must set the economy date appropriately. */
if (_game_mode == GM_EDITOR) {
EconTime::Date new_economy_date;
EconTime::DateFract new_economy_date_fract;
if (EconTime::UsingWallclockUnits()) {
/* If the new mode is wallclock units, set the economy year back to 1. */
new_economy_date = EconTime::DAYS_TILL_ORIGINAL_BASE_YEAR_WALLCLOCK_MODE;
new_economy_date_fract = 0;
} else {
/* If the new mode is calendar units, sync the economy year with the calendar year. */
new_economy_date = CalTime::CurDate().base();
new_economy_date_fract = CalTime::CurDateFract();
}
/* If you open a savegame as a scenario, there may already be link graphs and/or vehicles. These use economy date. */
LinkGraphSchedule::instance.ShiftDates(new_economy_date - EconTime::CurDate());
ShiftVehicleDates(new_economy_date - EconTime::CurDate());
/* Only change the date after changing cached values above. */
EconTime::Detail::SetDate(new_economy_date, new_economy_date_fract);
UpdateOrderUIOnDateChange();
}
UpdateEffectiveDayLengthFactor();
}
/**
* Callback after the player changes the minutes per year.
* @param new_value The intended new value of the setting, used for clamping.
*/
static void ChangeMinutesPerYear(int32_t new_value)
{
/* We don't allow setting Minutes Per Year below default, unless it's to 0 for frozen calendar time. */
if (new_value < CalTime::DEF_MINUTES_PER_YEAR) {
int clamped;
/* If the new value is 1, we're probably at 0 and trying to increase the value, so we should jump up to default. */
if (new_value == 1) {
clamped = CalTime::DEF_MINUTES_PER_YEAR;
} else {
clamped = CalTime::FROZEN_MINUTES_PER_YEAR;
}
/* Override the setting with the clamped value. */
if (_game_mode == GM_MENU) {
_settings_newgame.economy.minutes_per_calendar_year = clamped;
} else {
_settings_game.economy.minutes_per_calendar_year = clamped;
}
}
/* If the setting value is not the default, force the game to use wallclock timekeeping units.
* This can only happen in the menu, since the pre_cb ensures this setting can only be changed there, or if we're already using wallclock units.
*/
if (_game_mode == GM_MENU && (_settings_newgame.economy.minutes_per_calendar_year != CalTime::DEF_MINUTES_PER_YEAR)) {
_settings_newgame.economy.timekeeping_units = TKU_WALLCLOCK;
InvalidateWindowClassesData(WC_GAME_OPTIONS, 0);
}
}
static void TrainAccelerationModelChanged(int32_t new_value)
{
for (Train *t : Train::Iterate()) {

@ -2432,6 +2432,8 @@ static SettingsContainer &GetSettingsTree()
{
SettingsPage *time = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_TIME));
{
time->Add(new SettingEntry("economy.timekeeping_units"));
time->Add(new SettingEntry("economy.minutes_per_calendar_year"));
time->Add(new SettingEntry("game_creation.ending_year"));
time->Add(new SettingEntry("gui.pause_on_newgame"));
time->Add(new SettingEntry("gui.fast_forward_speed_limit"));

@ -64,6 +64,12 @@ enum IndustryDensity {
ID_END, ///< Number of industry density settings.
};
/** Possible values for the "timekeeping_units" setting. */
enum TimekeepingUnits : uint8_t {
TKU_CALENDAR = 0,
TKU_WALLCLOCK,
};
/** Possible values for "use_relay_service" setting. */
enum UseRelayService : uint8_t {
URS_NEVER = 0,
@ -763,6 +769,8 @@ struct EconomySettings {
uint8_t town_max_road_slope; ///< maximum number of consecutive sloped road tiles which towns are allowed to build
bool allow_town_bridges; ///< towns are allowed to build bridges
bool infrastructure_maintenance; ///< enable monthly maintenance fee for owner infrastructure
TimekeepingUnits timekeeping_units; ///< time units to use for the game economy, either calendar or wallclock
uint16_t minutes_per_calendar_year; ///< minutes per calendar year. Special value 0 means that calendar time is frozen.
uint16_t town_cargo_scale; ///< scale cargo production of towns by this percentage.
uint16_t industry_cargo_scale; ///< scale cargo production of industries by this percentage.
CargoScalingMode town_cargo_scale_mode; ///< scaling mode for town cargo.
@ -890,7 +898,7 @@ struct GameSettings {
uint8_t EffectiveDayLengthFactor() const
{
return this->economy.day_length_factor;
return this->economy.timekeeping_units == TKU_CALENDAR ? this->economy.day_length_factor : 1;
}
};

@ -157,7 +157,15 @@ struct SubsidyListWindow : Window {
if (IsInsideMM(pos, 0, cap)) {
/* Displays the two offered towns */
SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::Gui);
SetDParam(7, EconTime::CurDate() - EconTime::CurDay() + s->remaining * 32);
/* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
if (EconTime::UsingWallclockUnits()) {
SetDParam(7, STR_SUBSIDIES_OFFERED_EXPIRY_TIME);
SetDParam(8, s->remaining + 1); // We get the rest of the current economy month for free, since the expiration is checked on each new month.
} else {
SetDParam(7, STR_SUBSIDIES_OFFERED_EXPIRY_DATE);
SetDParam(8, EconTime::CurDate() - EconTime::CurDay() + s->remaining * 32);
}
DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_OFFERED_FROM_TO);
}
pos++;
@ -181,7 +189,15 @@ struct SubsidyListWindow : Window {
if (IsInsideMM(pos, 0, cap)) {
SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::Gui);
SetDParam(7, s->awarded);
SetDParam(8, EconTime::CurDate() - EconTime::CurDay() + s->remaining * 32);
/* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
if (EconTime::UsingWallclockUnits()) {
SetDParam(8, STR_SUBSIDIES_SUBSIDISED_EXPIRY_TIME);
SetDParam(9, s->remaining);
}
else {
SetDParam(8, STR_SUBSIDIES_SUBSIDISED_EXPIRY_DATE);
SetDParam(9, EconTime::CurDate() - EconTime::CurDay() + s->remaining * 32);
}
/* Displays the two connected stations */
DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_SUBSIDISED_FROM_TO);

@ -9,6 +9,8 @@
[pre-amble]
static void TownFoundingChanged(int32_t new_value);
static void ChangeTimekeepingUnits(int32_t new_value);
static void ChangeMinutesPerYear(int32_t new_value);
static void InvalidateCompanyWindow(int32_t new_value);
static void DayLengthChanged(int32_t new_value);
static bool CheckSharingRail(int32_t &new_value);
@ -702,10 +704,37 @@ strhelp = STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT
post_cb = [](auto) { InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); }
cat = SC_BASIC
[SDT_VAR]
var = economy.timekeeping_units
type = SLE_UINT8
flags = SF_GUI_DROPDOWN | SF_NEWGAME_ONLY | SF_SCENEDIT_TOO
def = TKU_CALENDAR
min = TKU_CALENDAR
max = TKU_WALLCLOCK
str = STR_CONFIG_SETTING_TIMEKEEPING_UNITS
strval = STR_CONFIG_SETTING_TIMEKEEPING_UNITS_CALENDAR
strhelp = STR_CONFIG_SETTING_TIMEKEEPING_UNITS_HELPTEXT
post_cb = ChangeTimekeepingUnits
cat = SC_BASIC
[SDT_VAR]
var = economy.minutes_per_calendar_year
type = SLE_UINT16
flags = SF_GUI_0_IS_SPECIAL
def = CalTime::DEF_MINUTES_PER_YEAR
min = CalTime::FROZEN_MINUTES_PER_YEAR
max = CalTime::MAX_MINUTES_PER_YEAR
interval = 1
str = STR_CONFIG_SETTING_MINUTES_PER_YEAR
strhelp = STR_CONFIG_SETTING_MINUTES_PER_YEAR_HELPTEXT
strval = STR_CONFIG_SETTING_MINUTES_PER_YEAR_VALUE
pre_cb = [](auto) { return _game_mode == GM_MENU || _settings_game.economy.timekeeping_units == 1; }
post_cb = ChangeMinutesPerYear
cat = SC_BASIC
[SDT_VAR]
var = economy.town_cargo_scale
type = SLE_UINT16
flags = SF_PATCH
def = 100
min = 1
max = 5000
@ -720,7 +749,6 @@ guiproc = TownCargoScaleGUI
[SDT_VAR]
var = economy.industry_cargo_scale
type = SLE_UINT16
flags = SF_PATCH
def = 100
min = 5
max = 3000

@ -2819,13 +2819,20 @@ extern void DrawRoadVehDetails(const Vehicle *v, const Rect &r);
extern void DrawShipDetails(const Vehicle *v, const Rect &r);
extern void DrawAircraftDetails(const Aircraft *v, const Rect &r);
static StringID _service_interval_dropdown[] = {
static StringID _service_interval_dropdown_calendar[] = {
STR_VEHICLE_DETAILS_DEFAULT,
STR_VEHICLE_DETAILS_DAYS,
STR_VEHICLE_DETAILS_PERCENT,
INVALID_STRING_ID,
};
static StringID _service_interval_dropdown_wallclock[] = {
STR_VEHICLE_DETAILS_DEFAULT,
STR_VEHICLE_DETAILS_MINUTES,
STR_VEHICLE_DETAILS_PERCENT,
INVALID_STRING_ID,
};
/** Class for managing the vehicle details window. */
struct VehicleDetailsWindow : Window {
TrainDetailsWindowTabs tab; ///< For train vehicles: which tab is displayed.
@ -3024,9 +3031,10 @@ struct VehicleDetailsWindow : Window {
case WID_VD_SERVICE_INTERVAL_DROPDOWN: {
Dimension d{0, 0};
StringID *strs = _service_interval_dropdown;
while (*strs != INVALID_STRING_ID) {
d = maxdim(d, GetStringBoundingBox(*strs++));
for (const StringID *strs : {_service_interval_dropdown_calendar, _service_interval_dropdown_wallclock}) {
while (*strs != INVALID_STRING_ID) {
d = maxdim(d, GetStringBoundingBox(*strs++));
}
}
d.width += padding.width;
d.height += padding.height;
@ -3036,7 +3044,17 @@ struct VehicleDetailsWindow : Window {
case WID_VD_SERVICING_INTERVAL:
SetDParamMaxValue(0, MAX_SERVINT_DAYS); // Roughly the maximum interval
SetDParamMaxValue(1, CalTime::MAX_YEAR.base() * DAYS_IN_YEAR); // Roughly the maximum year
/* Do we show the last serviced value as a date or minutes since service? */
if (EconTime::UsingWallclockUnits()) {
SetDParam(1, STR_VEHICLE_DETAILS_LAST_SERVICE_MINUTES_AGO);
/* Vehicle was last serviced at year 0, and we're at max year */
SetDParamMaxValue(2, MONTHS_IN_YEAR * EconTime::MAX_YEAR.base());
} else {
SetDParam(1, STR_VEHICLE_DETAILS_LAST_SERVICE_DATE);
/* Vehicle was last serviced at year 0, and we're at max year */
SetDParamMaxValue(2, EconTime::DateAtStartOfYear(EconTime::MAX_YEAR));
}
size->width = std::max(
GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT).width,
GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS).width
@ -3264,8 +3282,22 @@ struct VehicleDetailsWindow : Window {
case WID_VD_SERVICING_INTERVAL: {
/* Draw service interval text */
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
SetDParam(0, v->GetServiceInterval());
SetDParam(1, v->date_of_last_service);
/* We're using wallclock units. Show minutes since last serviced. */
if (EconTime::UsingWallclockUnits()) {
int minutes_since_serviced = (EconTime::CurDate() - v->date_of_last_service).base() / EconTime::DAYS_IN_ECONOMY_WALLCLOCK_MONTH;
SetDParam(1, STR_VEHICLE_DETAILS_LAST_SERVICE_MINUTES_AGO);
SetDParam(2, minutes_since_serviced);
DrawString(tr.left, tr.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)),
v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_MINUTES);
break;
}
/* We're using calendar dates. Show the date of last service. */
SetDParam(1, STR_VEHICLE_DETAILS_LAST_SERVICE_DATE);
SetDParam(2, v->date_of_last_service);
DrawString(tr.left, tr.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)),
v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS);
break;
@ -3288,9 +3320,10 @@ struct VehicleDetailsWindow : Window {
WID_VD_INCREASE_SERVICING_INTERVAL,
WID_VD_DECREASE_SERVICING_INTERVAL);
StringID str = v->ServiceIntervalIsCustom() ?
(v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_PERCENT : STR_VEHICLE_DETAILS_DAYS) :
STR_VEHICLE_DETAILS_DEFAULT;
StringID str =
!v->ServiceIntervalIsCustom() ? STR_VEHICLE_DETAILS_DEFAULT :
v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_PERCENT :
EconTime::UsingWallclockUnits() ? STR_VEHICLE_DETAILS_MINUTES : STR_VEHICLE_DETAILS_DAYS;
this->GetWidget<NWidgetCore>(WID_VD_SERVICE_INTERVAL_DROPDOWN)->widget_data = str;
this->DrawWidgets();
@ -3301,8 +3334,13 @@ struct VehicleDetailsWindow : Window {
switch (widget) {
case WID_VD_INCREASE_SERVICING_INTERVAL: // increase int
case WID_VD_DECREASE_SERVICING_INTERVAL: { // decrease int
int mod = _ctrl_pressed ? 5 : 10;
const Vehicle *v = Vehicle::Get(this->window_number);
int mod;
if (!v->ServiceIntervalIsPercent() && EconTime::UsingWallclockUnits()) {
mod = _ctrl_pressed ? 1 : 5;
} else {
mod = _ctrl_pressed ? 5 : 10;
}
mod = (widget == WID_VD_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
mod = GetServiceIntervalClamped(mod + v->GetServiceInterval(), v->ServiceIntervalIsPercent());
@ -3314,7 +3352,9 @@ struct VehicleDetailsWindow : Window {
case WID_VD_SERVICE_INTERVAL_DROPDOWN: {
const Vehicle *v = Vehicle::Get(this->window_number);
ShowDropDownMenu(this, _service_interval_dropdown, v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? 2 : 1) : 0, widget, 0, 0, 0, DDSF_LOST_FOCUS);
ShowDropDownMenu(this,
EconTime::UsingWallclockUnits() ? _service_interval_dropdown_wallclock : _service_interval_dropdown_calendar,
v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? 2 : 1) : 0, widget, 0, 0, 0, DDSF_LOST_FOCUS);
break;
}

Loading…
Cancel
Save