mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-04 06:00:15 +00:00
Feature: Setting for minutes per calendar year (#11428)
This commit is contained in:
parent
be8ed26db6
commit
21581b6ab3
@ -1487,6 +1487,13 @@ STR_CONFIG_SETTING_TIMEKEEPING_UNITS_HELPTEXT :Select the time
|
||||
STR_CONFIG_SETTING_TIMEKEEPING_UNITS_CALENDAR :Calendar
|
||||
STR_CONFIG_SETTING_TIMEKEEPING_UNITS_WALLCLOCK :Wallclock
|
||||
|
||||
STR_CONFIG_SETTING_MINUTES_PER_YEAR :Minutes per year: {STRING2}
|
||||
STR_CONFIG_SETTING_MINUTES_PER_YEAR_HELPTEXT :Choose the number of minutes in a calendar year. The default is 12 minutes. Set to 0 to stop calendar time from changing. This setting does not affect the economic simulation of the game, and is only available when using wallclock timekeeping.
|
||||
|
||||
STR_CONFIG_SETTING_MINUTES_PER_YEAR_VALUE :{NUM}
|
||||
###setting-zero-is-special
|
||||
STR_CONFIG_SETTING_MINUTES_PER_YEAR_FROZEN :0 (calendar time frozen)
|
||||
|
||||
STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Autorenew vehicle when it gets old: {STRING2}
|
||||
STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :When enabled, a vehicle nearing its end of life gets automatically replaced when the renew conditions are fulfilled
|
||||
|
||||
|
@ -1472,11 +1472,12 @@ void StateGameLoop()
|
||||
|
||||
BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP);
|
||||
AnimateAnimatedTiles();
|
||||
TimerManager<TimerGameCalendar>::Elapsed(1);
|
||||
if (TimerManager<TimerGameCalendar>::Elapsed(1)) {
|
||||
RunVehicleCalendarDayProc();
|
||||
}
|
||||
TimerManager<TimerGameEconomy>::Elapsed(1);
|
||||
TimerManager<TimerGameTick>::Elapsed(1);
|
||||
RunTileLoop();
|
||||
RunVehicleCalendarDayProc();
|
||||
CallVehicleTicks();
|
||||
CallLandscapeTick();
|
||||
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP);
|
||||
|
@ -88,6 +88,7 @@ static const SaveLoad _date_desc[] = {
|
||||
SLEG_CONDVAR("tick_counter", TimerGameTick::counter, SLE_UINT64, SLV_U64_TICK_COUNTER, SL_MAX_VERSION),
|
||||
SLEG_CONDVAR("economy_date", TimerGameEconomy::date, SLE_INT32, SLV_ECONOMY_DATE, SL_MAX_VERSION),
|
||||
SLEG_CONDVAR("economy_date_fract", TimerGameEconomy::date_fract, SLE_UINT16, SLV_ECONOMY_DATE, SL_MAX_VERSION),
|
||||
SLEG_CONDVAR("calendar_sub_date_fract", TimerGameCalendar::sub_date_fract, SLE_UINT16, SLV_CALENDAR_SUB_DATE_FRACT, SL_MAX_VERSION),
|
||||
SLEG_CONDVAR("age_cargo_skip_counter", _age_cargo_skip_counter, SLE_UINT8, SL_MIN_VERSION, SLV_162),
|
||||
SLEG_CONDVAR("cur_tileloop_tile", _cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
||||
SLEG_CONDVAR("cur_tileloop_tile", _cur_tileloop_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
||||
|
@ -370,6 +370,7 @@ enum SaveLoadVersion : uint16_t {
|
||||
SLV_WATER_REGION_EVAL_SIMPLIFIED, ///< 325 PR#11750 Simplified Water Region evaluation.
|
||||
SLV_ECONOMY_DATE, ///< 326 PR#10700 Split calendar and economy timers and dates.
|
||||
SLV_ECONOMY_MODE_TIMEKEEPING_UNITS, ///< 327 PR#11341 Mode to display economy measurements in wallclock units.
|
||||
SLV_CALENDAR_SUB_DATE_FRACT, ///< 328 PR#11428 Add sub_date_fract to measure calendar days.
|
||||
|
||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||
};
|
||||
|
@ -2213,6 +2213,7 @@ 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"));
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "news_func.h"
|
||||
#include "window_func.h"
|
||||
#include "company_func.h"
|
||||
#include "timer/timer_game_calendar.h"
|
||||
#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
|
||||
#define HAS_TRUETYPE_FONT
|
||||
#include "fontcache.h"
|
||||
@ -500,9 +501,48 @@ static void ChangeTimekeepingUnits(int32_t)
|
||||
UpdateAllServiceInterval(0);
|
||||
}
|
||||
|
||||
/* If we are using calendar timekeeping, "minutes per year" must be default. */
|
||||
if (!TimerGameEconomy::UsingWallclockUnits(true)) {
|
||||
_settings_newgame.economy.minutes_per_calendar_year = CalendarTime::DEF_MINUTES_PER_YEAR;
|
||||
}
|
||||
|
||||
InvalidateWindowClassesData(WC_GAME_OPTIONS, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 < CalendarTime::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 = CalendarTime::DEF_MINUTES_PER_YEAR;
|
||||
} else {
|
||||
clamped = CalendarTime::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 != CalendarTime::DEF_MINUTES_PER_YEAR)) {
|
||||
_settings_newgame.economy.timekeeping_units = TKU_WALLCLOCK;
|
||||
InvalidateWindowClassesData(WC_GAME_OPTIONS, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-callback check when trying to change the timetable mode. This is locked to Seconds when using wallclock units.
|
||||
* @param Unused.
|
||||
|
@ -558,6 +558,7 @@ struct EconomySettings {
|
||||
bool allow_town_level_crossings; ///< towns are allowed to build level crossings
|
||||
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.
|
||||
};
|
||||
|
||||
struct LinkGraphSettings {
|
||||
|
@ -10,6 +10,7 @@
|
||||
[pre-amble]
|
||||
static void TownFoundingChanged(int32_t new_value);
|
||||
static void ChangeTimekeepingUnits(int32_t new_value);
|
||||
static void ChangeMinutesPerYear(int32_t new_value);
|
||||
|
||||
static const SettingVariant _economy_settings_table[] = {
|
||||
[post-amble]
|
||||
@ -294,3 +295,18 @@ 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 | SF_NO_NETWORK
|
||||
def = CalendarTime::DEF_MINUTES_PER_YEAR
|
||||
min = CalendarTime::FROZEN_MINUTES_PER_YEAR
|
||||
max = CalendarTime::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
|
||||
|
@ -32,6 +32,7 @@ TimerGameCalendar::Year TimerGameCalendar::year = {};
|
||||
TimerGameCalendar::Month TimerGameCalendar::month = {};
|
||||
TimerGameCalendar::Date TimerGameCalendar::date = {};
|
||||
TimerGameCalendar::DateFract TimerGameCalendar::date_fract = {};
|
||||
uint16_t TimerGameCalendar::sub_date_fract = {};
|
||||
|
||||
/**
|
||||
* Converts a Date to a Year, Month & Day.
|
||||
@ -93,28 +94,42 @@ void TimeoutTimer<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed trigge
|
||||
}
|
||||
|
||||
template<>
|
||||
void TimerManager<TimerGameCalendar>::Elapsed([[maybe_unused]] TimerGameCalendar::TElapsed delta)
|
||||
bool TimerManager<TimerGameCalendar>::Elapsed([[maybe_unused]] TimerGameCalendar::TElapsed delta)
|
||||
{
|
||||
assert(delta == 1);
|
||||
|
||||
if (_game_mode == GM_MENU) return;
|
||||
if (_game_mode == GM_MENU) return false;
|
||||
|
||||
/* If calendar day progress is frozen, don't try to advance time. */
|
||||
if (_settings_game.economy.minutes_per_calendar_year == CalendarTime::FROZEN_MINUTES_PER_YEAR) return false;
|
||||
|
||||
/* 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 != CalendarTime::DEF_MINUTES_PER_YEAR) {
|
||||
TimerGameCalendar::sub_date_fract++;
|
||||
|
||||
/* Check if we are ready to increment date_fract */
|
||||
if (TimerGameCalendar::sub_date_fract < (Ticks::DAY_TICKS * _settings_game.economy.minutes_per_calendar_year) / CalendarTime::DEF_MINUTES_PER_YEAR) return false;
|
||||
}
|
||||
|
||||
TimerGameCalendar::date_fract++;
|
||||
if (TimerGameCalendar::date_fract < Ticks::DAY_TICKS) return;
|
||||
TimerGameCalendar::date_fract = 0;
|
||||
|
||||
/* increase day counter */
|
||||
/* Check if we entered a new day. */
|
||||
if (TimerGameCalendar::date_fract < Ticks::DAY_TICKS) return true;
|
||||
TimerGameCalendar::date_fract = 0;
|
||||
TimerGameCalendar::sub_date_fract = 0;
|
||||
|
||||
/* Increase day counter. */
|
||||
TimerGameCalendar::date++;
|
||||
|
||||
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
|
||||
|
||||
/* check if we entered a new month? */
|
||||
/* Check if we entered a new month. */
|
||||
bool new_month = ymd.month != TimerGameCalendar::month;
|
||||
|
||||
/* check if we entered a new year? */
|
||||
/* Check if we entered a new year. */
|
||||
bool new_year = ymd.year != TimerGameCalendar::year;
|
||||
|
||||
/* update internal variables before calling the daily/monthly/yearly loops */
|
||||
/* Update internal variables before calling the daily/monthly/yearly loops. */
|
||||
TimerGameCalendar::month = ymd.month;
|
||||
TimerGameCalendar::year = ymd.year;
|
||||
|
||||
@ -137,7 +152,7 @@ void TimerManager<TimerGameCalendar>::Elapsed([[maybe_unused]] TimerGameCalendar
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we reached the maximum year, decrement dates by a year */
|
||||
/* If we reached the maximum year, decrement dates by a year. */
|
||||
if (TimerGameCalendar::year == CalendarTime::MAX_YEAR + 1) {
|
||||
int days_this_year;
|
||||
|
||||
@ -145,6 +160,8 @@ void TimerManager<TimerGameCalendar>::Elapsed([[maybe_unused]] TimerGameCalendar
|
||||
days_this_year = TimerGameCalendar::IsLeapYear(TimerGameCalendar::year) ? CalendarTime::DAYS_IN_LEAP_YEAR : CalendarTime::DAYS_IN_YEAR;
|
||||
TimerGameCalendar::date -= days_this_year;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WITH_ASSERT
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
static Month month; ///< Current month (0..11).
|
||||
static Date date; ///< Current date in days (day counter).
|
||||
static DateFract date_fract; ///< Fractional part of the day.
|
||||
static uint16_t sub_date_fract; ///< Subpart of date_fract that we use when calendar days are slower than economy days.
|
||||
|
||||
static YearMonthDay ConvertDateToYMD(Date date);
|
||||
static Date ConvertYMDToDate(Year year, Month month, Day day);
|
||||
@ -42,6 +43,11 @@ public:
|
||||
/**
|
||||
* Storage class for Calendar time constants.
|
||||
*/
|
||||
class CalendarTime : public TimerGameConst<struct Calendar> {};
|
||||
class CalendarTime : public TimerGameConst<struct Calendar> {
|
||||
public:
|
||||
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.
|
||||
};
|
||||
|
||||
#endif /* TIMER_GAME_CALENDAR_H */
|
||||
|
@ -121,14 +121,14 @@ void TimeoutTimer<TimerGameEconomy>::Elapsed(TimerGameEconomy::TElapsed trigger)
|
||||
}
|
||||
|
||||
template<>
|
||||
void TimerManager<TimerGameEconomy>::Elapsed([[maybe_unused]] TimerGameEconomy::TElapsed delta)
|
||||
bool TimerManager<TimerGameEconomy>::Elapsed([[maybe_unused]] TimerGameEconomy::TElapsed delta)
|
||||
{
|
||||
assert(delta == 1);
|
||||
|
||||
if (_game_mode == GM_MENU) return;
|
||||
if (_game_mode == GM_MENU) return false;
|
||||
|
||||
TimerGameEconomy::date_fract++;
|
||||
if (TimerGameEconomy::date_fract < Ticks::DAY_TICKS) return;
|
||||
if (TimerGameEconomy::date_fract < Ticks::DAY_TICKS) return true;
|
||||
TimerGameEconomy::date_fract = 0;
|
||||
|
||||
/* increase day counter */
|
||||
@ -187,6 +187,8 @@ void TimerManager<TimerGameEconomy>::Elapsed([[maybe_unused]] TimerGameEconomy::
|
||||
for (Vehicle *v : Vehicle::Iterate()) v->ShiftDates(-days_this_year);
|
||||
for (LinkGraph *lg : LinkGraph::Iterate()) lg->ShiftDates(-days_this_year);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WITH_ASSERT
|
||||
|
@ -54,11 +54,13 @@ void TimeoutTimer<TimerGameRealtime>::Elapsed(TimerGameRealtime::TElapsed delta)
|
||||
}
|
||||
|
||||
template<>
|
||||
void TimerManager<TimerGameRealtime>::Elapsed(TimerGameRealtime::TElapsed delta)
|
||||
bool TimerManager<TimerGameRealtime>::Elapsed(TimerGameRealtime::TElapsed delta)
|
||||
{
|
||||
for (auto timer : TimerManager<TimerGameRealtime>::GetTimers()) {
|
||||
timer->Elapsed(delta);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WITH_ASSERT
|
||||
|
@ -51,13 +51,15 @@ void TimeoutTimer<TimerGameTick>::Elapsed(TimerGameTick::TElapsed delta)
|
||||
}
|
||||
|
||||
template<>
|
||||
void TimerManager<TimerGameTick>::Elapsed(TimerGameTick::TElapsed delta)
|
||||
bool TimerManager<TimerGameTick>::Elapsed(TimerGameTick::TElapsed delta)
|
||||
{
|
||||
TimerGameTick::counter++;
|
||||
|
||||
for (auto timer : TimerManager<TimerGameTick>::GetTimers()) {
|
||||
timer->Elapsed(delta);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WITH_ASSERT
|
||||
|
@ -78,8 +78,9 @@ public:
|
||||
* Call the Elapsed() method of all active timers.
|
||||
*
|
||||
* @param value The amount of time that has elapsed.
|
||||
* @return True iff time has progressed.
|
||||
*/
|
||||
static void Elapsed(TElapsed value);
|
||||
static bool Elapsed(TElapsed value);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -49,7 +49,7 @@ void TimeoutTimer<TimerWindow>::Elapsed(TimerWindow::TElapsed delta)
|
||||
}
|
||||
|
||||
template<>
|
||||
void TimerManager<TimerWindow>::Elapsed(TimerWindow::TElapsed delta)
|
||||
bool TimerManager<TimerWindow>::Elapsed(TimerWindow::TElapsed delta)
|
||||
{
|
||||
/* Make a temporary copy of the timers, as a timer's callback might add/remove other timers. */
|
||||
auto timers = TimerManager<TimerWindow>::GetTimers();
|
||||
@ -57,6 +57,8 @@ void TimerManager<TimerWindow>::Elapsed(TimerWindow::TElapsed delta)
|
||||
for (auto timer : timers) {
|
||||
timer->Elapsed(delta);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WITH_ASSERT
|
||||
|
Loading…
Reference in New Issue
Block a user