Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Feature: Setting to loop the same year forever #8749

wants to merge 10 commits into from


Copy link

@2TallTyler 2TallTyler commented Feb 26, 2021

Motivation / Problem

The goal of this PR is to add an option to freeze technological progress in a chosen year, by failing to advance the year after December 31st. While this can be faked using the cheat menu or “Vehicles never expire,” both are tedious and the latter doesn’t affect the introduction of new houses, towns building newer roadtypes, and other NewGRFs which progress through time.

The ability to remain in a certain year (really a period of time, but commonly a year) is often requested by players who want to explore a certain period in history without the frustration or immersion-breaking of the aforementioned hacks. Transport Fever 2 includes a setting to repeat a certain year forever, to support this style of play. I see several new opportunities in offering this game mode:

  • Early-year games such as the American Wild West can actually reach a late-game network size and bank account without cheating time and money — without this, by the time a large network can be built, the era is long past.
  • Industry sets can be designed for this mode without regard to supporting realistic technological progression, and can offer industry chains which were phased out long ago. Imagine sending ships to hunt whales, delivering coal to gasworks for town gas production, and harvesting ice from frozen lakes to ship around the world. Currently, the NewGRF author can either choose to force these industries to close, frustrating the player, or keep them around forever, which feels silly.
  • Players who want to build in one time period and not have to worry about vehicle and tech upgrades can do so, without having to start their game in the future or use the aforementioned hacks. Many transport simulator games, like Cities in Motion, Cities: Skylines, Mini Metro, and Airport CEO; train simulators like Trainz, Derail Valley, Train Sim World, and MSTS; and logistics games like Factorio, Satisfactory, and Rise of Industry do not have history progression and let the player focus on other things.


#7938 proposed a “groundhog year” but did not consider the many potential side effects of looping a gameplay year. This PR is my attempt to address these and either make the necessary changes or confirm that no change is required. Thanks to those who participated in #8384 (especially @andythenorth) to suggest potential issues.

This also adds a "game year" which functions like the repeating years in Transport Fever 2, displaying a counter of how many years have passed since the game started. This means graphs, the company finance window, etc., still provide useful information.

There is plenty yet to be done, but I figure it's good to start the conversation before I get too far down rabbitholes like changing how time is measured. 🙂 This change to _game_year is the area where I'm least confident in my work. Please see the "Help needed" section in Limitations.

For the sake of reviews, I’ve tried to organize my changes into logical commits. We can squash later before merging.

Modified to work with looped years:

  • Implemented #7938 to add a game setting, loop the year, and add a boolean which tells if the current year is looping. Note that the first time through the looped year is not considered a loop.
  • Reorganized OnNewYear() to prevent calling:
    • Semaphore signal introduction date
    • End game chart
    • Switch to Euro
  • Changing the year using cheats resets year_is_looping to false
  • Inflation is not applied during looped years
  • Don’t age engines (life cycle of vehicle types, not individual vehicles), introduce new engines, or show vehicle previews in looped years

Modified to use _game_year:

_game_year is a counter which measures how many years have passed in the current game.

  • Company inaugurated year and age, including requirements to purchase shares and send money
  • Secondary industry closure mechanic (1/16 chance of closing after 5 years of no production)
  • Added restart_game_length to network config, to restart game after some number of years (including looped years)

Tested, no change needed:

  • Attempting to pass MAX_YEAR by changing the date in the cheat menu is not possible, since this doesn’t touch MAX_YEAR at all (unlike the original PR).
  • Vehicle age is counted in days and calculated to years, so years don’t affect:
    • Vehicle aging, reliability, breakdowns
    • Vehicle autorenew
  • Newspapers, disasters, vanilla industries with date restrictions (Oil Wells, Oil Rigs), NewGRF airport availability, bridge availability, and house availability simply check the current year and have no issues with a looped year.
  • Subsidies and town funded growth use counters which are decremented each month (note: subsidies display the wrong end date, but work fine)
  • Loan interest isn’t affected by time, not even when inflation is enabled
  • Town rating is updated in the monthly loop, which doesn’t touch years.


Help needed:

  • Did I add the savegame upgrade properly?
  • How does LoadNewGRF (in newgrf.cpp) use the year? I don’t understand this.
  • Does the new company inaugurated_game_year need to be sent to network clients, along with the old inaugurated_year?
  • What other considerations are required for _game_year in network games?

Testing needed:

  • Vehicles don’t seem to disappear from the purchase menu, even when they become available mid-year (you can test with the Class ET in Danish Trains, which becomes available 2000/07/02), unless I use the console commands resetengines or reload_newgrfs. This needs more testing to confirm.
  • NewGRF and Game Script can both check the year. This opens up potential side effects but can’t possibly be in scope for this PR. I suggest making the game_year_counter variable visible to them as an alternative way to measure time. Can anyone thing of specific examples where this could break things?

To Do:

  • Switch to showing the game_year instead of the actual year when the year is looping (all are functional, but display the wrong date):
    • Graphs
    • Company finance window
    • Timetable dates
    • Date in status bar
    • Subsidy expiration date

Checklist for review

Some things are not automated, and forgotten often. This list is a reminder for the reviewers.

  • The bug fix is important enough to be backported? (label: 'backport requested')
  • This PR affects the save game format? (label 'savegame upgrade')
  • This PR affects the GS/AI API? (label 'needs review: Script API')
    • ai_changelog.hpp, gs_changelog.hpp need updating.
    • The compatibility wrappers (compat_*.nut) need updating.
  • This PR affects the NewGRF API? (label 'needs review: NewGRF')
Copy link

@James103 James103 commented Feb 26, 2021

  • Can anyone thing of specific examples where this could break things?

For example, AI/GS that print the current date to the game log would also loop. In-game day calculations used by some AI/GS to tell how long an action took (such as building a new route or a player finishing a goal) can produce values much lower than normal (or even negative) if the _cur_date is reduced due to it being a loop year.

Copy link

@LC-Zorg LC-Zorg commented Mar 10, 2021

As an additional cheat option, it would be quite interesting. :) I don't think it's worth it to refine this PR so much. In my opinion, it would be enough to use the current date-changing mechanism. The only inconvenience with using Ctrl + Alt + C is that the company will not be included in the best results list. Here, however, the company will never reach the indicated year and if it does, it will be a cheat. ;)
As an additional game mode, I would not see it. Such rolling one year is too strange. I would much prefer slowing down the time, even 1/1440, where one day would be one minute.

src/company_base.h Outdated Show resolved Hide resolved
@@ -76,7 +76,8 @@ struct CompanyProperties {

Owner share_owners[4]; ///< Owners of the 4 shares of the company. #INVALID_OWNER if nobody has bought them yet.

Year inaugurated_year; ///< Year of starting the company.
Year inaugurated_year; ///< Year of starting the company, n .
GameYear inaugurated_game_year; ///< Game year when the company was started
Copy link

@perezdidac perezdidac Apr 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the difference between inaugurated_year and inaugurated_game_year?

Copy link
Member Author

@2TallTyler 2TallTyler Apr 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Year is the actual calendar year; GameYear is the number of years since the current game began (counting up from 0).

src/date.cpp Show resolved Hide resolved
Copy link

@nielsmh nielsmh commented Apr 16, 2021

This is essentially a daylength patch, and I personally don't like the approach of looping years , so I'd be against this approach on its basic principle. In particular because it will make it difficult to implement a different approach to daylength/changing the rate of technological progression later on, since there would suddenly be two alternative ways of achieving the same thing. That would be both confusing for players, and a burden on code maintenance.

Copy link
Member Author

@2TallTyler 2TallTyler commented Apr 19, 2021

It achieves some of the same goals as daylength, yes, although I don't think the daylength I've seen implemented in JGRPP can keep the same year forever. I suppose with a high enough day length, this is still effectively possible.

My goal was to follow the Transport Fever 2 method of decoupling technological progress from the game world without changing how fast things happen in the game world (including economy things like cargo production, running cost charges, etc). However, I recognize that changing the actual day length (and not just how fast the years change) is a primary reason some players use the feature in JGRPP. I'll defer to that approach.

@2TallTyler 2TallTyler closed this Apr 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

5 participants