1
0
Fork 0

Compare commits

...

8 Commits

Author SHA1 Message Date
Oliver Bechstein-Rumble 8cfdb139c6
Merge 71ac8d508b into 2cdd50f40e 2025-07-20 13:32:28 +00:00
Peter Nelson 2cdd50f40e
Fix 03f5f7145f: Wrong colour used when string POP_COLOURs back to initial colour. (#14468)
Fixing ellipsis colour broke the PUSH_COLOUR/POP_COLOUR system, reverting to the last used colour instead of the initial colour.
2025-07-20 14:30:18 +01:00
Peter Nelson 56942a15c7 Add: Industry accepted and waiting history graphs.
Records amount of cargo accepted, and a rolling average of the waiting amount.

Average waiting samples the waiting amount once per day for each industry, spread out over an economy day.
2025-07-20 14:03:54 +01:00
Peter Nelson 5eeda026a4 Codechange: Allow unused graph ranges to be masked. 2025-07-20 14:03:54 +01:00
Peter Nelson edc5b8ea1f
Fix #14464: Invalid string parameter in scenario editor when unable to build industry. (#14465)
Resolved by removing the Build Industry command callback. This was used to display an error message in the scenario editor, however an error is already automatically displayed.
2025-07-20 14:03:29 +01:00
OllieBechstein 71ac8d508b Fix coding style to better conform to the guidelines 2025-06-19 22:34:08 +02:00
OllieBechstein d6222cd5d7 Merge remote-tracking branch 'upstream/master' 2025-06-19 21:57:09 +02:00
OllieBechstein a87144d669 Added a variable in settings_gui that can remember the previous gui scale that was set. This means that toggling the auto scale on and then off will revert the scale to it's previous value. 2025-06-19 21:57:00 +02:00
16 changed files with 190 additions and 50 deletions

View File

@ -1067,6 +1067,7 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoType cargo_type, uint
uint amount = std::min(num_pieces, 0xFFFFu - it->waiting);
it->waiting += amount;
it->GetOrCreateHistory()[THIS_MONTH].accepted += amount;
it->last_accepted = TimerGameEconomy::date;
num_pieces -= amount;
accepted += amount;

View File

@ -580,10 +580,11 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
const uint shadow_offset = ScaleGUITrad(1);
auto draw_line = [&](const ParagraphLayouter::Line &line, bool do_shadow, int left, int min_x, int max_x, bool truncation, TextColour &last_colour) {
auto draw_line = [&](const ParagraphLayouter::Line &line, bool do_shadow, int left, int min_x, int max_x, bool truncation, TextColour initial_colour) {
const DrawPixelInfo *dpi = _cur_dpi;
int dpi_left = dpi->left;
int dpi_right = dpi->left + dpi->width - 1;
TextColour last_colour = initial_colour;
for (int run_index = 0; run_index < line.CountRuns(); run_index++) {
const ParagraphLayouter::VisualRun &run = line.GetVisualRun(run_index);
@ -593,13 +594,10 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
FontCache *fc = f->fc;
TextColour colour = f->colour;
if (colour == TC_INVALID || HasFlag(last_colour, TC_FORCED)) {
colour = last_colour;
} else {
if (colour == TC_INVALID || HasFlag(initial_colour, TC_FORCED)) colour = initial_colour;
bool colour_has_shadow = (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
/* Update the last colour for the truncation ellipsis. */
last_colour = colour;
}
bool colour_has_shadow = (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
if (do_shadow && (!fc->GetDrawGlyphShadow() || !colour_has_shadow)) continue;
SetColourRemap(do_shadow ? TC_BLACK : colour);
@ -625,16 +623,16 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
GfxMainBlitter(sprite, begin_x + (do_shadow ? shadow_offset : 0), top + (do_shadow ? shadow_offset : 0), BlitterMode::ColourRemap);
}
}
return last_colour;
};
/* Draw shadow, then foreground */
for (bool do_shadow : {true, false}) {
TextColour last_colour = default_colour;
draw_line(line, do_shadow, left - offset_x, min_x, max_x, truncation, last_colour);
TextColour colour = draw_line(line, do_shadow, left - offset_x, min_x, max_x, truncation, default_colour);
if (truncation) {
int x = (_current_text_dir == TD_RTL) ? left : (right - truncation_width);
draw_line(*truncation_layout->front(), do_shadow, x, INT32_MIN, INT32_MAX, false, last_colour);
draw_line(*truncation_layout->front(), do_shadow, x, INT32_MIN, INT32_MAX, false, colour);
}
}

View File

@ -182,8 +182,9 @@ protected:
static const int MIN_GRAPH_NUM_LINES_Y = 9; ///< Minimal number of horizontal lines to draw.
static const int MIN_GRID_PIXEL_SIZE = 20; ///< Minimum distance between graph lines.
uint64_t excluded_data = 0; ///< bitmask of the datasets that shouldn't be displayed.
uint64_t excluded_range = 0; ///< bitmask of ranges that should not be displayed.
uint64_t excluded_data = 0; ///< bitmask of datasets hidden by the player.
uint64_t excluded_range = 0; ///< bitmask of ranges hidden by the player.
uint64_t masked_range = 0; ///< bitmask of ranges that are not available for the current data.
uint8_t num_on_x_axis = 0;
uint8_t num_vert_lines = GRAPH_NUM_MONTHS;
@ -216,13 +217,20 @@ protected:
uint8_t highlight_range = UINT8_MAX; ///< Data range that should be highlighted, or UINT8_MAX for none.
bool highlight_state = false; ///< Current state of highlight, toggled every TIMER_BLINK_INTERVAL period.
template <typename Tprojection>
struct Filler {
struct BaseFiller {
DataSet &dataset; ///< Dataset to fill.
inline void MakeZero(uint i) const { this->dataset.values[i] = 0; }
inline void MakeInvalid(uint i) const { this->dataset.values[i] = INVALID_DATAPOINT; }
};
template <typename Tprojection>
struct Filler : BaseFiller {
const Tprojection &proj; ///< Projection to apply.
constexpr Filler(DataSet &dataset, const Tprojection &proj) : BaseFiller(dataset), proj(proj) {}
inline void Fill(uint i, const auto &data) const { this->dataset.values[i] = std::invoke(this->proj, data); }
inline void MakeInvalid(uint i) const { this->dataset.values[i] = INVALID_DATAPOINT; }
};
/**
@ -675,13 +683,17 @@ public:
uint index = 0;
Rect line = r.WithHeight(line_height);
for (const auto &str : this->ranges) {
bool lowered = !HasBit(this->excluded_range, index);
bool lowered = !HasBit(this->excluded_range, index) && !HasBit(this->masked_range, index);
/* Redraw frame if lowered */
if (lowered) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered);
const Rect text = line.Shrink(WidgetDimensions::scaled.framerect);
DrawString(text, str, TC_BLACK, SA_CENTER, false, FS_SMALL);
DrawString(text, str, (this->highlight_state && this->highlight_range == index) ? TC_WHITE : TC_BLACK, SA_CENTER, false, FS_SMALL);
if (HasBit(this->masked_range, index)) {
GfxFillRect(line.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(COLOUR_BROWN, SHADE_DARKER), FILLRECT_CHECKER);
}
line = line.Translate(0, line_height);
++index;
@ -704,6 +716,7 @@ public:
case WID_GRAPH_RANGE_MATRIX: {
int row = GetRowFromWidget(pt.y, widget, 0, GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical());
if (HasBit(this->masked_range, row)) break;
ToggleBit(this->excluded_range, row);
this->SetDirty();
break;
@ -1115,6 +1128,7 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
{
this->CreateNestedTree();
this->excluded_range = this->masked_range;
this->cargo_types = this->GetCargoTypes(number);
this->vscroll = this->GetScrollbar(WID_GRAPH_MATRIX_SCROLLBAR);
@ -1608,7 +1622,9 @@ CompanyID PerformanceRatingDetailWindow::company = CompanyID::Invalid();
struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
static inline constexpr StringID RANGE_LABELS[] = {
STR_GRAPH_INDUSTRY_RANGE_PRODUCED,
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED,
STR_GRAPH_INDUSTRY_RANGE_DELIVERED,
STR_GRAPH_INDUSTRY_RANGE_WAITING,
};
static inline CargoTypes excluded_cargo_types{};
@ -1623,6 +1639,10 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
this->draw_dates = !TimerGameEconomy::UsingWallclockUnits();
this->ranges = RANGE_LABELS;
const Industry *i = Industry::Get(window_number);
if (!i->IsCargoProduced()) this->masked_range = (1U << 0) | (1U << 1);
if (!i->IsCargoAccepted()) this->masked_range = (1U << 2) | (1U << 3);
this->InitializeWindow(window_number, STR_GRAPH_LAST_24_MINUTES_TIME_LABEL);
}
@ -1630,6 +1650,9 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
{
CargoTypes cargo_types{};
const Industry *i = Industry::Get(window_number);
for (const auto &a : i->accepted) {
if (IsValidCargoType(a.cargo)) SetBit(cargo_types, a.cargo);
}
for (const auto &p : i->produced) {
if (IsValidCargoType(p.cargo)) SetBit(cargo_types, p.cargo);
}
@ -1643,7 +1666,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
{
if (widget == WID_GRAPH_CAPTION) return GetString(STR_GRAPH_INDUSTRY_PRODUCTION_CAPTION, this->window_number);
if (widget == WID_GRAPH_CAPTION) return GetString(STR_GRAPH_INDUSTRY_CAPTION, this->window_number);
return this->Window::GetWidgetString(widget, stringid);
}
@ -1691,6 +1714,33 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->valid_history, produced_filler, transported_filler);
}
for (const auto &a : i->accepted) {
if (!IsValidCargoType(a.cargo)) continue;
const CargoSpec *cs = CargoSpec::Get(a.cargo);
this->data.reserve(this->data.size() + 2);
DataSet &accepted = this->data.emplace_back();
accepted.colour = cs->legend_colour;
accepted.exclude_bit = cs->Index();
accepted.range_bit = 2;
accepted.dash = 1;
auto accepted_filler = Filler{accepted, &Industry::AcceptedHistory::accepted};
DataSet &waiting = this->data.emplace_back();
waiting.colour = cs->legend_colour;
waiting.exclude_bit = cs->Index();
waiting.range_bit = 3;
waiting.dash = 4;
auto waiting_filler = Filler{waiting, &Industry::AcceptedHistory::waiting};
if (a.history == nullptr) {
FillFromEmpty<GRAPH_NUM_MONTHS>(i->valid_history, accepted_filler, waiting_filler);
} else {
FillFromHistory<GRAPH_NUM_MONTHS>(*a.history, i->valid_history, accepted_filler, waiting_filler);
}
}
this->SetDirty();
}
};

View File

@ -77,10 +77,27 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
HistoryData<ProducedHistory> history{}; ///< History of cargo produced and transported for this month and 24 previous months
};
struct AcceptedHistory {
uint16_t accepted = 0; /// Total accepted.
uint16_t waiting = 0; /// Average waiting.
};
struct AcceptedCargo {
CargoType cargo = 0; ///< Cargo type
uint16_t waiting = 0; ///< Amount of cargo waiting to processed
uint32_t accumulated_waiting = 0; ///< Accumulated waiting total over the last month, used to calculate average.
TimerGameEconomy::Date last_accepted{}; ///< Last day cargo was accepted by this industry
std::unique_ptr<HistoryData<AcceptedHistory>> history{}; ///< History of accepted and waiting cargo.
/**
* Get history data, creating it if necessary.
* @return Accepted history data.
*/
inline HistoryData<AcceptedHistory> &GetOrCreateHistory()
{
if (this->history == nullptr) this->history = std::make_unique<HistoryData<AcceptedHistory>>();
return *this->history;
}
};
using ProducedCargoes = std::vector<ProducedCargo>;
@ -151,7 +168,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
*/
inline const AcceptedCargo &GetAccepted(size_t slot) const
{
static const AcceptedCargo empty{INVALID_CARGO, 0, {}};
static const AcceptedCargo empty{INVALID_CARGO, 0, 0, {}, {}};
return slot < this->accepted.size() ? this->accepted[slot] : empty;
}

View File

@ -1245,6 +1245,10 @@ void OnTick_Industry()
for (Industry *i : Industry::Iterate()) {
ProduceIndustryGoods(i);
if ((TimerGameTick::counter + i->index) % Ticks::DAY_TICKS == 0) {
for (auto &a : i->accepted) a.accumulated_waiting += a.waiting;
}
}
}
@ -2505,6 +2509,14 @@ static void UpdateIndustryStatistics(Industry *i)
RotateHistory(p.history);
}
}
for (auto &a : i->accepted) {
if (!IsValidCargoType(a.cargo)) continue;
if (a.history == nullptr) continue;
(*a.history)[THIS_MONTH].waiting = GetAndResetAccumulatedAverage<uint16_t>(a.accumulated_waiting);
RotateHistory(*a.history);
}
}
/**

View File

@ -27,6 +27,4 @@ DEF_CMD_TRAIT(CMD_INDUSTRY_SET_EXCLUSIVITY, CmdIndustrySetExclusivity, CommandFl
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_TEXT, CmdIndustrySetText, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_PRODUCTION, CmdIndustrySetProduction, CommandFlag::Deity, CMDT_OTHER_MANAGEMENT)
void CcBuildIndustry(Commands cmd, const CommandCost &result, TileIndex tile, IndustryType indtype, uint32_t, bool, uint32_t);
#endif /* INDUSTRY_CMD_H */

View File

@ -257,25 +257,6 @@ void SortIndustryTypes()
std::sort(_sorted_industry_types.begin(), _sorted_industry_types.end(), IndustryTypeNameSorter);
}
/**
* Command callback. In case of failure to build an industry, show an error message.
* @param result Result of the command.
* @param tile Tile where the industry is placed.
* @param indtype Industry type.
*/
void CcBuildIndustry(Commands, const CommandCost &result, TileIndex tile, IndustryType indtype, uint32_t, bool, uint32_t)
{
if (result.Succeeded()) return;
if (indtype < NUM_INDUSTRYTYPES) {
const IndustrySpec *indsp = GetIndustrySpec(indtype);
if (indsp->enabled) {
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUILD_HERE, indsp->name),
GetEncodedString(result.GetErrorMessage()), WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
}
}
}
static constexpr NWidgetPart _nested_build_industry_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
@ -745,7 +726,7 @@ public:
AutoRestoreBackup backup_generating_world(_generating_world, true);
AutoRestoreBackup backup_ignore_industry_restritions(_ignore_industry_restrictions, true);
Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, &CcBuildIndustry, tile, this->selected_type, layout_index, false, seed);
Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed);
} else {
success = Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed);
}
@ -845,7 +826,7 @@ public:
nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ScaleZoomGUI(ZoomLevel::Industry));
const Industry *i = Industry::Get(window_number);
if (!i->IsCargoProduced()) this->DisableWidget(WID_IV_GRAPH);
if (!i->IsCargoProduced() && !i->IsCargoAccepted()) this->DisableWidget(WID_IV_GRAPH);
this->InvalidateData();
}
@ -1242,7 +1223,7 @@ static constexpr NWidgetPart _nested_industry_view_widgets[] = {
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_DISPLAY), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_GRAPH), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_VIEW_PRODUCTION_GRAPH, STR_INDUSTRY_VIEW_PRODUCTION_GRAPH_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_GRAPH), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_VIEW_CARGO_GRAPH, STR_INDUSTRY_VIEW_CARGO_GRAPH_TOOLTIP),
NWidget(WWT_RESIZEBOX, COLOUR_CREAM),
EndContainer(),
};

View File

@ -634,9 +634,11 @@ STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Display
STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Toggle graph of this cargo type
STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING}
STR_GRAPH_INDUSTRY_PRODUCTION_CAPTION :{WHITE}{INDUSTRY} - Production History
STR_GRAPH_INDUSTRY_CAPTION :{WHITE}{INDUSTRY} - Cargo History
STR_GRAPH_INDUSTRY_RANGE_PRODUCED :Produced
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED :Transported
STR_GRAPH_INDUSTRY_RANGE_DELIVERED :Delivered
STR_GRAPH_INDUSTRY_RANGE_WAITING :Waiting
STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show detailed performance ratings
@ -4024,8 +4026,8 @@ STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Producti
STR_INDUSTRY_VIEW_PRODUCTION_LAST_MINUTE_TITLE :{BLACK}Production last minute:
STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{RAW_STRING}{BLACK} ({COMMA}% transported)
STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centre the main view on industry location. Ctrl+Click to open a new viewport on industry location
STR_INDUSTRY_VIEW_PRODUCTION_GRAPH :{BLACK}Production Graph
STR_INDUSTRY_VIEW_PRODUCTION_GRAPH_TOOLTIP :{BLACK}Shows the graph of industry production history
STR_INDUSTRY_VIEW_CARGO_GRAPH :{BLACK}Cargo Graph
STR_INDUSTRY_VIEW_CARGO_GRAPH_TOOLTIP :{BLACK}Shows the graph of industry cargo history
STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Production level: {YELLOW}{COMMA}%
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}The industry has announced imminent closure!

View File

@ -11,6 +11,8 @@
#define HISTORY_FUNC_HPP
#include "../core/bitmath_func.hpp"
#include "../core/math_func.hpp"
#include "../timer/timer_game_economy.h"
#include "history_type.hpp"
/**
@ -34,6 +36,19 @@ void RotateHistory(HistoryData<T> &history)
history[THIS_MONTH] = {};
}
/**
* Get an average value for the previous month, as reset for the next month.
* @param total Accrued total to average. Will be reset to zero.
* @return Average value for the month.
*/
template <typename T, typename Taccrued>
T GetAndResetAccumulatedAverage(Taccrued &total)
{
T result = ClampTo<T>(total / std::max(1U, TimerGameEconomy::days_since_last_month));
total = 0;
return result;
}
/**
* Fill some data with historical data.
* @param history Historical data to fill from.
@ -53,4 +68,21 @@ void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_histo
}
}
/**
* Fill some data with empty records.
* @param valid_history Mask of valid history records.
* @param fillers Fillers to fill with history data.
*/
template <uint N, typename... Tfillers>
void FillFromEmpty(ValidHistoryMask valid_history, Tfillers... fillers)
{
for (uint i = 0; i != N; ++i) {
if (HasBit(valid_history, N - i)) {
(fillers.MakeZero(i), ...);
} else {
(fillers.MakeInvalid(i), ...);
}
}
}
#endif /* HISTORY_FUNC_HPP */

View File

@ -79,7 +79,6 @@ static constexpr auto _callback_tuple = std::make_tuple(
&CcCreateGroup,
&CcFoundRandomTown,
&CcRoadStop,
&CcBuildIndustry,
&CcStartStopVehicle,
&CcGame,
&CcAddVehicleNewGroup

View File

@ -19,12 +19,50 @@
static OldPersistentStorage _old_ind_persistent_storage;
class SlIndustryAcceptedHistory : public DefaultSaveLoadHandler<SlIndustryAcceptedHistory, Industry::AcceptedCargo> {
public:
static inline const SaveLoad description[] = {
SLE_VAR(Industry::AcceptedHistory, accepted, SLE_UINT16),
SLE_VAR(Industry::AcceptedHistory, waiting, SLE_UINT16),
};
static inline const SaveLoadCompatTable compat_description = _industry_produced_history_sl_compat;
void Save(Industry::AcceptedCargo *a) const override
{
if (!IsValidCargoType(a->cargo) || a->history == nullptr) {
/* Don't save any history if cargo slot isn't used. */
SlSetStructListLength(0);
return;
}
SlSetStructListLength(a->history->size());
for (auto &h : *a->history) {
SlObject(&h, this->GetDescription());
}
}
void Load(Industry::AcceptedCargo *a) const override
{
size_t len = SlGetStructListLength(UINT32_MAX);
if (len == 0) return;
auto &history = a->GetOrCreateHistory();
for (auto &h : history) {
if (--len > history.size()) break; // unsigned so wraps after hitting zero.
SlObject(&h, this->GetDescription());
}
}
};
class SlIndustryAccepted : public VectorSaveLoadHandler<SlIndustryAccepted, Industry, Industry::AcceptedCargo, INDUSTRY_NUM_INPUTS> {
public:
static inline const SaveLoad description[] = {
SLE_VAR(Industry::AcceptedCargo, cargo, SLE_UINT8),
SLE_VAR(Industry::AcceptedCargo, waiting, SLE_UINT16),
SLE_VAR(Industry::AcceptedCargo, last_accepted, SLE_INT32),
SLE_CONDVAR(Industry::AcceptedCargo, accumulated_waiting, SLE_UINT32, SLV_INDUSTRY_ACCEPTED_HISTORY, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("history", SlIndustryAcceptedHistory, SLV_INDUSTRY_ACCEPTED_HISTORY, SL_MAX_VERSION),
};
static inline const SaveLoadCompatTable compat_description = _industry_accepts_sl_compat;

View File

@ -858,7 +858,7 @@ static bool LoadOldIndustry(LoadgameState &ls, int num)
if (i->location.tile != 0) {
/* Copy data from old fixed arrays to industry. */
std::copy(std::begin(_old_accepted), std::end(_old_accepted), std::back_inserter(i->accepted));
std::move(std::begin(_old_accepted), std::end(_old_accepted), std::back_inserter(i->accepted));
std::copy(std::begin(_old_produced), std::end(_old_produced), std::back_inserter(i->produced));
i->town = RemapTown(i->location.tile);

View File

@ -405,6 +405,7 @@ enum SaveLoadVersion : uint16_t {
SLV_FACE_STYLES, ///< 355 PR#14319 Addition of face styles, replacing gender and ethnicity.
SLV_INDUSTRY_NUM_VALID_HISTORY, ///< 356 PR#14416 Store number of valid history records for industries.
SLV_INDUSTRY_ACCEPTED_HISTORY, ///< 357 PR#14321 Add per-industry history of cargo delivered and waiting.
SL_MAX_VERSION, ///< Highest possible saveload version
};

View File

@ -418,6 +418,7 @@ struct GameOptionsWindow : Window {
GameSettings *opt = nullptr;
bool reload = false;
int gui_scale = 0;
static inline int previous_gui_scale = 0; ///< Previous GUI scale.
static inline WidgetID active_tab = WID_GO_TAB_GENERAL;
GameOptionsWindow(WindowDesc &desc) : Window(desc), filter_editbox(50), gui_scale(_gui_scale)
@ -1065,9 +1066,13 @@ struct GameOptionsWindow : Window {
case WID_GO_GUI_SCALE_AUTO:
{
if (_gui_scale_cfg == -1) {
_gui_scale_cfg = _gui_scale;
_gui_scale_cfg = previous_gui_scale; // Store the previous GUI scale value
this->SetWidgetLoweredState(WID_GO_GUI_SCALE_AUTO, false);
if (AdjustGUIZoom(false))
ReInitAllWindows(true);
this->gui_scale = _gui_scale;
} else {
previous_gui_scale = _gui_scale; // Set the previous GUI scale value as the current one
_gui_scale_cfg = -1;
this->SetWidgetLoweredState(WID_GO_GUI_SCALE_AUTO, true);
if (AdjustGUIZoom(false)) ReInitAllWindows(true);

View File

@ -37,6 +37,7 @@ TimerGameEconomy::Year TimerGameEconomy::year = {};
TimerGameEconomy::Month TimerGameEconomy::month = {};
TimerGameEconomy::Date TimerGameEconomy::date = {};
TimerGameEconomy::DateFract TimerGameEconomy::date_fract = {};
uint TimerGameEconomy::days_since_last_month = {};
/**
* Converts a Date to a Year, Month & Day.
@ -133,6 +134,7 @@ bool TimerManager<TimerGameEconomy>::Elapsed([[maybe_unused]] TimerGameEconomy::
/* increase day counter */
TimerGameEconomy::date++;
++TimerGameEconomy::days_since_last_month;
TimerGameEconomy::YearMonthDay ymd = TimerGameEconomy::ConvertDateToYMD(TimerGameEconomy::date);
@ -177,6 +179,8 @@ bool TimerManager<TimerGameEconomy>::Elapsed([[maybe_unused]] TimerGameEconomy::
}
}
if (new_month) TimerGameEconomy::days_since_last_month = 0;
/* check if we reached the maximum year, decrement dates by a year */
if (TimerGameEconomy::year == EconomyTime::MAX_YEAR + 1) {
TimerGameEconomy::year--;

View File

@ -37,6 +37,8 @@ public:
static Date date; ///< Current date in days (day counter).
static DateFract date_fract; ///< Fractional part of the day.
static uint days_since_last_month; ///< Number of days that have elapsed since the last month.
static YearMonthDay ConvertDateToYMD(Date date);
static Date ConvertYMDToDate(Year year, Month month, Day day);
static void SetDate(Date date, DateFract fract);