From 090656bd7f6da2190c2c34cf4cb9b54646c1c1b5 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 24 Feb 2024 23:35:20 +0000 Subject: [PATCH] Adjust handling of year display in wallclock mode and company inauguration years See: #657 --- src/cheat_gui.cpp | 1 + src/company_base.h | 9 ++++++++- src/company_cmd.cpp | 2 ++ src/company_gui.cpp | 6 +++--- src/console_cmds.cpp | 6 ++++-- src/date.cpp | 9 +++++++++ src/date_type.h | 9 +++++++++ src/economy.cpp | 2 +- src/misc.cpp | 2 ++ src/network/network_admin.cpp | 2 +- src/saveload/afterload.cpp | 20 +++++++++++++++++++- src/settings.cpp | 1 + src/sl/company_sl.cpp | 2 ++ src/sl/extended_ver_sl.cpp | 2 +- src/sl/misc_sl.cpp | 2 ++ src/toolbar_gui.cpp | 15 ++++++++++----- 16 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index e5af55b599..001ff52a93 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -120,6 +120,7 @@ static int32_t ClickChangeDateCheat(int32_t p1, int32_t p2) /* Shift cached dates. */ LinkGraphSchedule::instance.ShiftDates(new_econ_date - EconTime::CurDate()); ShiftVehicleDates(new_econ_date - EconTime::CurDate()); + EconTime::Detail::period_display_offset -= (p1 - EconTime::CurYear().base()); EconTime::Detail::SetDate(new_econ_date, new_econ_date_fract); UpdateOrderUIOnDateChange(); diff --git a/src/company_base.h b/src/company_base.h index 23a486da3c..1664c4a1ae 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -89,6 +89,8 @@ struct CompanyProperties { std::array share_owners; ///< Owners of the shares of the company. #INVALID_OWNER if nobody has bought them yet. CalTime::Year inaugurated_year; ///< Year of starting the company. + int32_t display_inaugurated_period;///< Wallclock display period of starting the company. + YearDelta age_years; ///< Number of economy years that the company has been operational. byte months_of_bankruptcy; ///< Number of months that the company is unable to pay its debts CompanyID bankrupt_last_asked; ///< Which company was most recently asked about buying it? @@ -123,9 +125,14 @@ struct CompanyProperties { CompanyProperties() : name_2(0), name_1(0), president_name_1(0), president_name_2(0), face(0), money(0), money_fraction(0), current_loan(0), max_loan(COMPANY_MAX_LOAN_DEFAULT), colour(COLOUR_BEGIN), - block_preview(0), location_of_HQ(0), last_build_coordinate(0), share_owners(), inaugurated_year(0), + block_preview(0), location_of_HQ(0), last_build_coordinate(0), share_owners(), inaugurated_year(0), display_inaugurated_period(0), age_years(0), months_of_bankruptcy(0), bankrupt_last_asked(INVALID_COMPANY), bankrupt_flags(CBRF_NONE), bankrupt_asked(0), bankrupt_timeout(0), bankrupt_value(0), terraform_limit(0), clear_limit(0), tree_limit(0), purchase_land_limit(0), build_object_limit(0), is_ai(false), engine_renew_list(nullptr) {} + + int32_t InauguratedDisplayYear() const + { + return EconTime::UsingWallclockUnits() ? this->display_inaugurated_period : this->inaugurated_year.base(); + } }; struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index f1cdaa43a9..16b3cb3d10 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -636,6 +636,7 @@ Company *DoStartupNewCompany(DoStartupNewCompanyFlag flags, CompanyID company) c->avail_railtypes = GetCompanyRailTypes(c->index); c->avail_roadtypes = GetCompanyRoadTypes(c->index); c->inaugurated_year = CalTime::CurYear(); + c->display_inaugurated_period = EconTime::Detail::WallClockYearToDisplay(EconTime::CurYear()); /* If starting a player company in singleplayer and a favorite company manager face is selected, choose it. Otherwise, use a random face. * In a network game, we'll choose the favorite face later in CmdCompanyCtrl to sync it to all clients. */ @@ -864,6 +865,7 @@ void CompaniesYearlyLoop() /* Move expenses to previous years. */ std::rotate(std::rbegin(c->yearly_expenses), std::rbegin(c->yearly_expenses) + 1, std::rend(c->yearly_expenses)); c->yearly_expenses[0] = {}; + c->age_years++; SetWindowDirty(WC_FINANCES, c->index); } diff --git a/src/company_gui.cpp b/src/company_gui.cpp index b7ac049257..090ad984ea 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -424,10 +424,10 @@ struct CompanyFinancesWindow : Window { case WID_CF_EXPS_PRICE2: case WID_CF_EXPS_PRICE3: { const Company *c = Company::Get((CompanyID)this->window_number); - YearDelta age = std::min(CalTime::CurYear() - c->inaugurated_year, 2); + YearDelta age = std::min(c->age_years, 2); int wid_offset = widget - WID_CF_EXPS_PRICE1; if (wid_offset <= age.base()) { - DrawYearColumn(r, CalTime::CurYear().base() - (age.base() - wid_offset), c->yearly_expenses[age.base() - wid_offset]); + DrawYearColumn(r, EconTime::YearToDisplay(EconTime::CurYear().base() - (age.base() - wid_offset)), c->yearly_expenses[age.base() - wid_offset]); } break; } @@ -2595,7 +2595,7 @@ struct CompanyWindow : Window break; case WID_C_DESC_INAUGURATION: - SetDParam(0, Company::Get((CompanyID)this->window_number)->inaugurated_year); + SetDParam(0, Company::Get((CompanyID)this->window_number)->InauguratedDisplayYear()); break; case WID_C_DESC_COMPANY_VALUE: diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 23d5b189f3..c88d4b1ad7 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2008,9 +2008,9 @@ DEF_CONSOLE_CMD(ConCompanies) password_state = _network_company_states[c->index].password.empty() ? "unprotected" : "protected"; } - IConsolePrintF(CC_INFO, "#:%d(%s) Company Name: '%s' Year Founded: %d Money: " OTTD_PRINTF64 " Loan: " OTTD_PRINTF64 " Value: " OTTD_PRINTF64 " (T:%d, R:%d, P:%d, S:%d) %s", + IConsolePrintF(CC_INFO, "#:%d(%s) Company Name: '%s' Year Founded: %d Age: %d Money: " OTTD_PRINTF64 " Loan: " OTTD_PRINTF64 " Value: " OTTD_PRINTF64 " (T:%d, R:%d, P:%d, S:%d) %s", c->index + 1, GetStringPtr(STR_COLOUR_DARK_BLUE + _company_colours[c->index]), company_name.c_str(), - c->inaugurated_year.base(), (int64_t)c->money, (int64_t)c->current_loan, (int64_t)CalculateCompanyValue(c), + c->InauguratedDisplayYear(), c->age_years.base(), (int64_t)c->money, (int64_t)c->current_loan, (int64_t)CalculateCompanyValue(c), c->group_all[VEH_TRAIN].num_vehicle, c->group_all[VEH_ROAD].num_vehicle, c->group_all[VEH_AIRCRAFT].num_vehicle, @@ -2693,6 +2693,8 @@ DEF_CONSOLE_CMD(ConGetFullDate) IConsolePrintF(CC_DEFAULT, "Calendar Date: %04d-%02d-%02d (%d), fract: %i, sub_fract: %i", CalTime::CurYear().base(), CalTime::CurMonth() + 1, CalTime::CurDay(), CalTime::CurDate().base(), CalTime::CurDateFract(), CalTime::Detail::now.sub_date_fract); IConsolePrintF(CC_DEFAULT, "Economy Date: %04d-%02d-%02d (%d), fract: %i, tick skip: %i", EconTime::CurYear().base(), EconTime::CurMonth() + 1, EconTime::CurDay(), EconTime::CurDate().base(), EconTime::CurDateFract(), TickSkipCounter()); + IConsolePrintF(CC_DEFAULT, "Period display offset: %d", EconTime::Detail::period_display_offset.base()); + IConsolePrintF(CC_DEFAULT, "Elapsed years: %d", EconTime::Detail::years_elapsed.base()); IConsolePrintF(CC_DEFAULT, "Tick counter: " OTTD_PRINTF64, _tick_counter); IConsolePrintF(CC_DEFAULT, "Tick counter (scaled): " OTTD_PRINTF64, _scaled_tick_counter); IConsolePrintF(CC_DEFAULT, "State ticks: " OTTD_PRINTF64 " (offset: " OTTD_PRINTF64 ")", _state_ticks.base(), DateDetail::_state_ticks_offset.base()); diff --git a/src/date.cpp b/src/date.cpp index 798d9ef855..44a6bbc60a 100644 --- a/src/date.cpp +++ b/src/date.cpp @@ -34,6 +34,8 @@ uint32_t _quit_after_days; ///< Quit after this many days of run CalTime::State CalTime::Detail::now; EconTime::State EconTime::Detail::now; +YearDelta EconTime::Detail::years_elapsed; +YearDelta EconTime::Detail::period_display_offset; namespace DateDetail { StateTicksDelta _state_ticks_offset; ///< Offset to add when calculating a StateTicks value from an economy date, date fract and tick skip counter @@ -111,6 +113,11 @@ EconTime::State EconTime::Detail::NewState(EconTime::Year year) return state; } +int32_t EconTime::Detail::WallClockYearToDisplay(EconTime::Year year) +{ + return (year + EconTime::Detail::period_display_offset).base(); +} + StateTicks GetStateTicksFromDateWithoutOffset(EconTime::Date date, EconTime::DateFract date_fract) { return ((int64_t)(EconTime::DateToDateTicks(date, date_fract).base()) * DayLengthFactor()) + TickSkipCounter(); @@ -379,6 +386,7 @@ static void OnNewCalendarYear() */ static void OnNewEconomyYear() { + EconTime::Detail::years_elapsed++; CompaniesYearlyLoop(); VehiclesYearlyLoop(); TownsYearlyLoop(); @@ -386,6 +394,7 @@ static void OnNewEconomyYear() /* check if we reached the maximum year, decrement dates by a year */ if (EconTime::CurYear() == EconTime::MAX_YEAR + 1) { + EconTime::Detail::period_display_offset++; EconTime::Detail::now.econ_ymd.year--; int days_this_year = EconTime::IsLeapYear(EconTime::Detail::now.econ_ymd.year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR; EconTime::Detail::now.econ_date -= days_this_year; diff --git a/src/date_type.h b/src/date_type.h index 4b1e1b9650..2321a0e34d 100644 --- a/src/date_type.h +++ b/src/date_type.h @@ -240,9 +240,12 @@ struct EconTime : public DateDetail::BaseTime { /* Use a detail struct/namespace to more easily control writes */ struct Detail { static State now; + static YearDelta years_elapsed; + static YearDelta period_display_offset; static void SetDate(Date date, DateFract fract); static State NewState(Year year); + static int32_t WallClockYearToDisplay(Year year); /** * Calculate the date of the first day of a given year. @@ -289,6 +292,12 @@ struct EconTime : public DateDetail::BaseTime { if (UsingWallclockUnits()) return Detail::DateAtStartOfWallclockModeYear(year); return ParentBaseTime::Detail::DateAtStartOfCalendarYear(year); } + + static inline int32_t YearToDisplay(Year year) + { + if (UsingWallclockUnits()) return Detail::WallClockYearToDisplay(year); + return year.base(); + } }; namespace DateDetail { diff --git a/src/economy.cpp b/src/economy.cpp index 958fff3112..57b96f8991 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -2532,7 +2532,7 @@ CommandCost CmdBuyShareInCompany(TileIndex tile, DoCommandFlag flags, uint32_t p if (c == nullptr || !_settings_game.economy.allow_shares || _current_company == target_company) return CMD_ERROR; /* Protect new companies from hostile takeovers */ - if (CalTime::CurYear() - c->inaugurated_year < _settings_game.economy.min_years_for_shares) return_cmd_error(STR_ERROR_PROTECTED); + if (c->age_years < _settings_game.economy.min_years_for_shares) return_cmd_error(STR_ERROR_PROTECTED); /* Those lines are here for network-protection (clients can be slow) */ if (GetAmountOwnedBy(c, COMPANY_SPECTATOR) == 0) return cost; diff --git a/src/misc.cpp b/src/misc.cpp index 88f0c0cad6..5904e5d6c3 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -130,6 +130,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin _pause_countdown = 0; _game_speed = 100; CalTime::Detail::now.sub_date_fract = 0; + EconTime::Detail::years_elapsed = 0; _tick_counter = 0; DateDetail::_tick_skip_counter = 0; _scaled_tick_counter = 0; @@ -168,6 +169,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin } else { EconTime::Detail::SetDate(CalTime::CurDate().base(), 0); } + EconTime::Detail::period_display_offset = 1 - EconTime::CurYear(); InitializeOldNames(); } else { RecalculateStateTicksOffset(); diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index 9f36225825..2f003dc540 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -330,7 +330,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company p->Send_string(GetString(STR_PRESIDENT_NAME)); p->Send_uint8 (c->colour); p->Send_bool (NetworkCompanyIsPassworded(c->index)); - p->Send_uint32(c->inaugurated_year.base()); + p->Send_uint32(c->InauguratedDisplayYear()); p->Send_bool (c->is_ai); p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 5912a8fec2..88436783f8 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -279,6 +279,8 @@ static void InitializeWindowsAndCaches() * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */ if (_file_to_saveload.abstract_ftype == FT_SCENARIO && c->inaugurated_year != CalTime::MIN_YEAR) { c->inaugurated_year = CalTime::CurYear(); + c->display_inaugurated_period = EconTime::Detail::WallClockYearToDisplay(EconTime::CurYear()); + c->age_years = 0; } } @@ -1830,7 +1832,7 @@ bool AfterLoadGame() for (Waypoint *wp : Waypoint::Iterate()) wp->build_date += CalTime::DAYS_TILL_ORIGINAL_BASE_YEAR.AsDelta(); for (Engine *e : Engine::Iterate()) e->intro_date += CalTime::DAYS_TILL_ORIGINAL_BASE_YEAR.AsDelta(); for (Company *c : Company::Iterate()) c->inaugurated_year += CalTime::ORIGINAL_BASE_YEAR.AsDelta(); - for (Industry *i : Industry::Iterate()) i->last_prod_year += CalTime::ORIGINAL_BASE_YEAR.AsDelta(); + for (Industry *i : Industry::Iterate()) i->last_prod_year += EconTime::ORIGINAL_BASE_YEAR.AsDelta(); for (Vehicle *v : Vehicle::Iterate()) { v->date_of_last_service += EconTime::DAYS_TILL_ORIGINAL_BASE_YEAR.AsDelta(); @@ -1838,6 +1840,22 @@ bool AfterLoadGame() } } + if (SlXvIsFeatureMissing(XSLFI_VARIABLE_DAY_LENGTH, 6)) { + EconTime::Detail::years_elapsed = EconTime::CurYear().base() - 1; + EconTime::Detail::period_display_offset = 0; + for (Company *c : Company::Iterate()) { + if (SlXvIsFeaturePresent(XSLFI_VARIABLE_DAY_LENGTH, 5, 5)) { + /* inaugurated_year is calendar time in XSLFI_VARIABLE_DAY_LENGTH version 5 */ + c->age_years = std::max(0, CalTime::CurYear() - c->inaugurated_year); + c->display_inaugurated_period = EconTime::Detail::WallClockYearToDisplay(c->inaugurated_year.base() + EconTime::CurYear().base() - CalTime::CurYear().base()); + } else { + c->age_years = std::max(0, EconTime::CurYear().base() - c->inaugurated_year.base()); + c->display_inaugurated_period = EconTime::Detail::WallClockYearToDisplay(c->inaugurated_year.base()); + c->inaugurated_year += CalTime::CurYear().base() - EconTime::CurYear().base(); + } + } + } + /* From 32 on we save the industry who made the farmland. * To give this prettiness to old savegames, we remove all farmfields and * plant new ones. */ diff --git a/src/settings.cpp b/src/settings.cpp index cdd6adc620..e8af1f544e 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1268,6 +1268,7 @@ static void ChangeTimekeepingUnits(int32_t) /* If the new mode is calendar units, sync the economy date with the calendar date. */ new_economy_date = CalTime::CurDate().base(); new_economy_date_fract = CalTime::CurDateFract(); + EconTime::Detail::period_display_offset -= (CalTime::CurYear().base() - EconTime::CurYear().base()); } /* Update link graphs and vehicles, as these include stored economy dates. */ diff --git a/src/sl/company_sl.cpp b/src/sl/company_sl.cpp index cfd25c5a56..61c42578ab 100644 --- a/src/sl/company_sl.cpp +++ b/src/sl/company_sl.cpp @@ -276,6 +276,8 @@ static const SaveLoad _company_desc[] = { SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_UINT32, SLV_6, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_CONDVAR_X(CompanyProperties, display_inaugurated_period, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 6)), + SLE_CONDVAR_X(CompanyProperties, age_years, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 6)), SLE_ARR(CompanyProperties, share_owners, SLE_UINT8, 4), diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index afd2e75665..542e9e02d4 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -103,7 +103,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_VEHICLE_REPAIR_COST, XSCF_NULL, 2, 2, "vehicle_repair_cost", nullptr, nullptr, nullptr }, { XSLFI_ENH_VIEWPORT_PLANS, XSCF_IGNORABLE_ALL, 4, 4, "enh_viewport_plans", nullptr, nullptr, "PLAN" }, { XSLFI_INFRA_SHARING, XSCF_NULL, 2, 2, "infra_sharing", nullptr, nullptr, "CPDP" }, - { XSLFI_VARIABLE_DAY_LENGTH, XSCF_NULL, 5, 5, "variable_day_length", nullptr, nullptr, nullptr }, + { XSLFI_VARIABLE_DAY_LENGTH, XSCF_NULL, 6, 6, "variable_day_length", nullptr, nullptr, nullptr }, { XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 2, 2, "order_occupancy", nullptr, nullptr, nullptr }, { XSLFI_MORE_COND_ORDERS, XSCF_NULL, 17, 17, "more_cond_orders", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_LARGE_MAP, XSCF_NULL, 0, 1, "extra_large_map", nullptr, nullptr, nullptr }, diff --git a/src/sl/misc_sl.cpp b/src/sl/misc_sl.cpp index 26ced7ca91..784e7299bd 100644 --- a/src/sl/misc_sl.cpp +++ b/src/sl/misc_sl.cpp @@ -125,6 +125,8 @@ static const NamedSaveLoad _date_desc[] = { NSLT("economy_date", SLEG_CONDVAR_X(EconTime::Detail::now.econ_date, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 5))), NSLT("economy_date_fract", SLEG_CONDVAR_X(EconTime::Detail::now.econ_date_fract, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 5))), NSLT("calendar_sub_date_fract", SLEG_CONDVAR_X(CalTime::Detail::now.sub_date_fract, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 5))), + NSLT("economy_years_elapsed", SLEG_CONDVAR_X(EconTime::Detail::years_elapsed, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 6))), + NSLT("period_display_offset", SLEG_CONDVAR_X(EconTime::Detail::period_display_offset, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 6))), }; static const NamedSaveLoad _date_check_desc[] = { diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 935c98de3b..9a4b8486d6 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1258,14 +1258,19 @@ void SetStartingYear(CalTime::Year year) { _settings_game.game_creation.starting_year = Clamp(year, CalTime::MIN_YEAR, CalTime::MAX_YEAR); CalTime::Date new_date = CalTime::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); - EconTime::Date new_economy_date = new_date.base(); - /* If you open a savegame as scenario there may already be link graphs.*/ - LinkGraphSchedule::instance.ShiftDates(new_economy_date - EconTime::CurDate()); - ShiftVehicleDates(new_economy_date - EconTime::CurDate()); + if (EconTime::UsingWallclockUnits()) { + EconTime::Date new_economy_date = new_date.base(); + + /* If you open a savegame as scenario there may already be link graphs.*/ + LinkGraphSchedule::instance.ShiftDates(new_economy_date - EconTime::CurDate()); + ShiftVehicleDates(new_economy_date - EconTime::CurDate()); + EconTime::Detail::period_display_offset -= (year.base() - EconTime::CurYear().base()); + + EconTime::Detail::SetDate(new_economy_date, 0); + } CalTime::Detail::SetDate(new_date, 0); - EconTime::Detail::SetDate(new_economy_date, 0); UpdateOrderUIOnDateChange(); }