Add wallclock time settings
This commit is contained in:
@@ -113,7 +113,7 @@ static int32_t ClickChangeDateCheat(int32_t p1, int32_t p2)
|
|||||||
/* Change the date. */
|
/* Change the date. */
|
||||||
CalTime::Detail::SetDate(new_date, CalTime::CurDateFract());
|
CalTime::Detail::SetDate(new_date, CalTime::CurDateFract());
|
||||||
|
|
||||||
{
|
if (!EconTime::UsingWallclockUnits()) {
|
||||||
EconTime::Date new_econ_date = new_date.base();
|
EconTime::Date new_econ_date = new_date.base();
|
||||||
EconTime::DateFract new_econ_date_fract = CalTime::CurDateFract();
|
EconTime::DateFract new_econ_date_fract = CalTime::CurDateFract();
|
||||||
|
|
||||||
|
36
src/date.cpp
36
src/date.cpp
@@ -246,21 +246,37 @@ CalTime::Date CalTime::ConvertYMDToDate(CalTime::Year year, CalTime::Month month
|
|||||||
|
|
||||||
EconTime::YearMonthDay EconTime::ConvertDateToYMD(EconTime::Date date)
|
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());
|
CalTime::YearMonthDay ymd = CalTime::ConvertDateToYMD(date.base());
|
||||||
return { ymd.year.base(), ymd.month, ymd.day };
|
return { ymd.year.base(), ymd.month, ymd.day };
|
||||||
}
|
}
|
||||||
|
|
||||||
EconTime::Date EconTime::ConvertYMDToDate(EconTime::Year year, EconTime::Month month, EconTime::Day 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();
|
return CalTime::ConvertYMDToDate(year.base(), month, day).base();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EconTime::UsingWallclockUnits(bool newgame)
|
bool EconTime::UsingWallclockUnits(bool newgame)
|
||||||
{
|
{
|
||||||
/* Always return false (for now) */
|
if (newgame) return (_settings_newgame.economy.timekeeping_units == TKU_WALLCLOCK);
|
||||||
return false;
|
|
||||||
|
return (_settings_game.economy.timekeeping_units == TKU_WALLCLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Functions used by the IncreaseDate function */
|
/** Functions used by the IncreaseDate function */
|
||||||
@@ -397,6 +413,18 @@ static void OnNewEconomyDay()
|
|||||||
|
|
||||||
static void IncreaseCalendarDate()
|
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++;
|
CalTime::Detail::now.cal_date_fract++;
|
||||||
if (CalTime::Detail::now.cal_date_fract < DAY_TICKS) return;
|
if (CalTime::Detail::now.cal_date_fract < DAY_TICKS) return;
|
||||||
CalTime::Detail::now.cal_date_fract = 0;
|
CalTime::Detail::now.cal_date_fract = 0;
|
||||||
|
@@ -124,7 +124,7 @@ struct SetDateWindow : Window {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WID_SD_YEAR:
|
case WID_SD_YEAR:
|
||||||
SetDParamMaxValue(0, this->max_year.base());
|
SetDParamMaxValue(0, this->max_year);
|
||||||
d = maxdim(d, GetStringBoundingBox(STR_JUST_INT));
|
d = maxdim(d, GetStringBoundingBox(STR_JUST_INT));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -176,6 +176,10 @@ struct CalTime : public DateDetail::BaseTime<struct CalendarTimeTag> {
|
|||||||
static State NewState(Year year);
|
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 const YearMonthDay &CurYMD() { return Detail::now.cal_ymd; }
|
||||||
static inline Year CurYear() { return Detail::now.cal_ymd.year; }
|
static inline Year CurYear() { return Detail::now.cal_ymd.year; }
|
||||||
static inline Month CurMonth() { return Detail::now.cal_ymd.month; }
|
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> {
|
struct EconTime : public DateDetail::BaseTime<struct EconTimeTag> {
|
||||||
|
using ParentBaseTime = DateDetail::BaseTime<struct EconTimeTag>;
|
||||||
|
|
||||||
/* Use a state struct to make backup/restore/init simpler */
|
/* Use a state struct to make backup/restore/init simpler */
|
||||||
struct State {
|
struct State {
|
||||||
YearMonthDay econ_ymd;
|
YearMonthDay econ_ymd;
|
||||||
Date econ_date;
|
Date econ_date;
|
||||||
DateFract econ_date_fract;
|
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 */
|
/* Use a detail struct/namespace to more easily control writes */
|
||||||
struct Detail {
|
struct Detail {
|
||||||
static State now;
|
static State now;
|
||||||
|
|
||||||
static void SetDate(Date date, DateFract fract);
|
static void SetDate(Date date, DateFract fract);
|
||||||
static State NewState(Year year);
|
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 const YearMonthDay &CurYMD() { return Detail::now.econ_ymd; }
|
||||||
static inline Year CurYear() { return Detail::now.econ_ymd.year; }
|
static inline Year CurYear() { return Detail::now.econ_ymd.year; }
|
||||||
static inline Month CurMonth() { return Detail::now.econ_ymd.month; }
|
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);
|
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 {
|
namespace DateDetail {
|
||||||
|
@@ -158,7 +158,9 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
|
|||||||
|
|
||||||
if (reset_date) {
|
if (reset_date) {
|
||||||
CalTime::Detail::SetDate(CalTime::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
|
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);
|
EconTime::Detail::SetDate(CalTime::CurDate().base(), 0);
|
||||||
}
|
}
|
||||||
InitializeOldNames();
|
InitializeOldNames();
|
||||||
|
@@ -431,6 +431,7 @@ uint32_t IndustriesScopeResolver::GetCountAndDistanceOfClosestInstance(byte para
|
|||||||
case 0xB3: return this->industry->construction_type; // Construction type
|
case 0xB3: return this->industry->construction_type; // Construction type
|
||||||
case 0xB4: {
|
case 0xB4: {
|
||||||
EconTime::Date *latest = std::max_element(this->industry->last_cargo_accepted_at, endof(this->industry->last_cargo_accepted_at));
|
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)
|
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
|
* Clamp the service interval to the correct min/max. The actual min/max values
|
||||||
* depend on whether it's in percent or days.
|
* depend on whether it's in days, minutes, or percent.
|
||||||
* @param interval proposed service interval
|
* @param interval The proposed service interval.
|
||||||
* @return Clamped 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)
|
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 MIN_SERVINT_DAYS = 30;
|
||||||
static const uint MAX_SERVINT_DAYS = 800;
|
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 DEF_SERVINT_PERCENT = 50;
|
||||||
static const uint MIN_SERVINT_PERCENT = 5;
|
static const uint MIN_SERVINT_PERCENT = 5;
|
||||||
static const uint MAX_SERVINT_PERCENT = 90;
|
static const uint MAX_SERVINT_PERCENT = 90;
|
||||||
|
@@ -873,6 +873,11 @@ bool AfterLoadGame()
|
|||||||
* must be done before loading sprites as some newgrfs check it */
|
* must be done before loading sprites as some newgrfs check it */
|
||||||
CalTime::Detail::SetDate(CalTime::CurDate(), CalTime::CurDateFract());
|
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)) {
|
if (SlXvIsFeaturePresent(XSLFI_VARIABLE_DAY_LENGTH, 5) || !IsSavegameVersionBefore(SLV_ECONOMY_DATE)) {
|
||||||
EconTime::Detail::SetDate(EconTime::CurDate(), EconTime::CurDateFract());
|
EconTime::Detail::SetDate(EconTime::CurDate(), EconTime::CurDateFract());
|
||||||
} else {
|
} else {
|
||||||
|
@@ -1079,6 +1079,12 @@ static void UpdateAllServiceInterval(int32_t new_value)
|
|||||||
vds->servint_roadveh = DEF_SERVINT_PERCENT;
|
vds->servint_roadveh = DEF_SERVINT_PERCENT;
|
||||||
vds->servint_aircraft = DEF_SERVINT_PERCENT;
|
vds->servint_aircraft = DEF_SERVINT_PERCENT;
|
||||||
vds->servint_ships = 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 {
|
} else {
|
||||||
/* Service intervals are in days. */
|
/* Service intervals are in days. */
|
||||||
vds->servint_trains = DEF_SERVINT_DAYS_TRAINS;
|
vds->servint_trains = DEF_SERVINT_DAYS_TRAINS;
|
||||||
@@ -1127,6 +1133,85 @@ static void UpdateServiceInterval(VehicleType type, int32_t new_value)
|
|||||||
SetWindowClassesDirty(WC_VEHICLE_DETAILS);
|
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)
|
static void TrainAccelerationModelChanged(int32_t new_value)
|
||||||
{
|
{
|
||||||
for (Train *t : Train::Iterate()) {
|
for (Train *t : Train::Iterate()) {
|
||||||
|
@@ -2432,6 +2432,8 @@ static SettingsContainer &GetSettingsTree()
|
|||||||
{
|
{
|
||||||
SettingsPage *time = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_TIME));
|
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("game_creation.ending_year"));
|
||||||
time->Add(new SettingEntry("gui.pause_on_newgame"));
|
time->Add(new SettingEntry("gui.pause_on_newgame"));
|
||||||
time->Add(new SettingEntry("gui.fast_forward_speed_limit"));
|
time->Add(new SettingEntry("gui.fast_forward_speed_limit"));
|
||||||
|
@@ -64,6 +64,12 @@ enum IndustryDensity {
|
|||||||
ID_END, ///< Number of industry density settings.
|
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. */
|
/** Possible values for "use_relay_service" setting. */
|
||||||
enum UseRelayService : uint8_t {
|
enum UseRelayService : uint8_t {
|
||||||
URS_NEVER = 0,
|
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
|
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 allow_town_bridges; ///< towns are allowed to build bridges
|
||||||
bool infrastructure_maintenance; ///< enable monthly maintenance fee for owner infrastructure
|
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 town_cargo_scale; ///< scale cargo production of towns by this percentage.
|
||||||
uint16_t industry_cargo_scale; ///< scale cargo production of industries 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.
|
CargoScalingMode town_cargo_scale_mode; ///< scaling mode for town cargo.
|
||||||
@@ -890,7 +898,7 @@ struct GameSettings {
|
|||||||
|
|
||||||
uint8_t EffectiveDayLengthFactor() const
|
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)) {
|
if (IsInsideMM(pos, 0, cap)) {
|
||||||
/* Displays the two offered towns */
|
/* Displays the two offered towns */
|
||||||
SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::Gui);
|
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);
|
DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_OFFERED_FROM_TO);
|
||||||
}
|
}
|
||||||
pos++;
|
pos++;
|
||||||
@@ -181,7 +189,15 @@ struct SubsidyListWindow : Window {
|
|||||||
if (IsInsideMM(pos, 0, cap)) {
|
if (IsInsideMM(pos, 0, cap)) {
|
||||||
SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::Gui);
|
SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::Gui);
|
||||||
SetDParam(7, s->awarded);
|
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 */
|
/* Displays the two connected stations */
|
||||||
DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_SUBSIDISED_FROM_TO);
|
DrawString(tr.left, tr.right, tr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_SUBSIDISED_FROM_TO);
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
[pre-amble]
|
[pre-amble]
|
||||||
static void TownFoundingChanged(int32_t new_value);
|
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 InvalidateCompanyWindow(int32_t new_value);
|
||||||
static void DayLengthChanged(int32_t new_value);
|
static void DayLengthChanged(int32_t new_value);
|
||||||
static bool CheckSharingRail(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); }
|
post_cb = [](auto) { InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); }
|
||||||
cat = SC_BASIC
|
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]
|
[SDT_VAR]
|
||||||
var = economy.town_cargo_scale
|
var = economy.town_cargo_scale
|
||||||
type = SLE_UINT16
|
type = SLE_UINT16
|
||||||
flags = SF_PATCH
|
|
||||||
def = 100
|
def = 100
|
||||||
min = 1
|
min = 1
|
||||||
max = 5000
|
max = 5000
|
||||||
@@ -720,7 +749,6 @@ guiproc = TownCargoScaleGUI
|
|||||||
[SDT_VAR]
|
[SDT_VAR]
|
||||||
var = economy.industry_cargo_scale
|
var = economy.industry_cargo_scale
|
||||||
type = SLE_UINT16
|
type = SLE_UINT16
|
||||||
flags = SF_PATCH
|
|
||||||
def = 100
|
def = 100
|
||||||
min = 5
|
min = 5
|
||||||
max = 3000
|
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 DrawShipDetails(const Vehicle *v, const Rect &r);
|
||||||
extern void DrawAircraftDetails(const Aircraft *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_DEFAULT,
|
||||||
STR_VEHICLE_DETAILS_DAYS,
|
STR_VEHICLE_DETAILS_DAYS,
|
||||||
STR_VEHICLE_DETAILS_PERCENT,
|
STR_VEHICLE_DETAILS_PERCENT,
|
||||||
INVALID_STRING_ID,
|
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. */
|
/** Class for managing the vehicle details window. */
|
||||||
struct VehicleDetailsWindow : Window {
|
struct VehicleDetailsWindow : Window {
|
||||||
TrainDetailsWindowTabs tab; ///< For train vehicles: which tab is displayed.
|
TrainDetailsWindowTabs tab; ///< For train vehicles: which tab is displayed.
|
||||||
@@ -3024,9 +3031,10 @@ struct VehicleDetailsWindow : Window {
|
|||||||
|
|
||||||
case WID_VD_SERVICE_INTERVAL_DROPDOWN: {
|
case WID_VD_SERVICE_INTERVAL_DROPDOWN: {
|
||||||
Dimension d{0, 0};
|
Dimension d{0, 0};
|
||||||
StringID *strs = _service_interval_dropdown;
|
for (const StringID *strs : {_service_interval_dropdown_calendar, _service_interval_dropdown_wallclock}) {
|
||||||
while (*strs != INVALID_STRING_ID) {
|
while (*strs != INVALID_STRING_ID) {
|
||||||
d = maxdim(d, GetStringBoundingBox(*strs++));
|
d = maxdim(d, GetStringBoundingBox(*strs++));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
d.width += padding.width;
|
d.width += padding.width;
|
||||||
d.height += padding.height;
|
d.height += padding.height;
|
||||||
@@ -3036,7 +3044,17 @@ struct VehicleDetailsWindow : Window {
|
|||||||
|
|
||||||
case WID_VD_SERVICING_INTERVAL:
|
case WID_VD_SERVICING_INTERVAL:
|
||||||
SetDParamMaxValue(0, MAX_SERVINT_DAYS); // Roughly the maximum 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(
|
size->width = std::max(
|
||||||
GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT).width,
|
GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT).width,
|
||||||
GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS).width
|
GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS).width
|
||||||
@@ -3264,8 +3282,22 @@ struct VehicleDetailsWindow : Window {
|
|||||||
case WID_VD_SERVICING_INTERVAL: {
|
case WID_VD_SERVICING_INTERVAL: {
|
||||||
/* Draw service interval text */
|
/* Draw service interval text */
|
||||||
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
|
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
|
||||||
|
|
||||||
SetDParam(0, v->GetServiceInterval());
|
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)),
|
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);
|
v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS);
|
||||||
break;
|
break;
|
||||||
@@ -3288,9 +3320,10 @@ struct VehicleDetailsWindow : Window {
|
|||||||
WID_VD_INCREASE_SERVICING_INTERVAL,
|
WID_VD_INCREASE_SERVICING_INTERVAL,
|
||||||
WID_VD_DECREASE_SERVICING_INTERVAL);
|
WID_VD_DECREASE_SERVICING_INTERVAL);
|
||||||
|
|
||||||
StringID str = v->ServiceIntervalIsCustom() ?
|
StringID str =
|
||||||
(v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_PERCENT : STR_VEHICLE_DETAILS_DAYS) :
|
!v->ServiceIntervalIsCustom() ? STR_VEHICLE_DETAILS_DEFAULT :
|
||||||
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->GetWidget<NWidgetCore>(WID_VD_SERVICE_INTERVAL_DROPDOWN)->widget_data = str;
|
||||||
|
|
||||||
this->DrawWidgets();
|
this->DrawWidgets();
|
||||||
@@ -3301,8 +3334,13 @@ struct VehicleDetailsWindow : Window {
|
|||||||
switch (widget) {
|
switch (widget) {
|
||||||
case WID_VD_INCREASE_SERVICING_INTERVAL: // increase int
|
case WID_VD_INCREASE_SERVICING_INTERVAL: // increase int
|
||||||
case WID_VD_DECREASE_SERVICING_INTERVAL: { // decrease int
|
case WID_VD_DECREASE_SERVICING_INTERVAL: { // decrease int
|
||||||
int mod = _ctrl_pressed ? 5 : 10;
|
|
||||||
const Vehicle *v = Vehicle::Get(this->window_number);
|
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 = (widget == WID_VD_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
|
||||||
mod = GetServiceIntervalClamped(mod + v->GetServiceInterval(), v->ServiceIntervalIsPercent());
|
mod = GetServiceIntervalClamped(mod + v->GetServiceInterval(), v->ServiceIntervalIsPercent());
|
||||||
@@ -3314,7 +3352,9 @@ struct VehicleDetailsWindow : Window {
|
|||||||
|
|
||||||
case WID_VD_SERVICE_INTERVAL_DROPDOWN: {
|
case WID_VD_SERVICE_INTERVAL_DROPDOWN: {
|
||||||
const Vehicle *v = Vehicle::Get(this->window_number);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user