1
0
Fork 0

Compare commits

..

5 Commits

Author SHA1 Message Date
Peter Nelson e1fe203e8a
Merge b24ceb27f5 into a8650c6b06 2025-07-19 22:51:24 +00:00
Peter Nelson b24ceb27f5
Change: Add support for different horizontal graph scales. 2025-07-19 16:03:06 +01:00
Peter Nelson 7feaac5391
Codechange: Extend industry cargo history to 24 years.
Monthly data is stored for the current 24 months.
Quarterly data is stored for a further 2-6 years.
Yearly data is stored for a further 6-24 years.
2025-07-19 16:03:05 +01:00
Peter Nelson db7dd4b03f
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-17 18:32:21 +01:00
Peter Nelson d56312d344
Codechange: Allow unused graph ranges to be masked. 2025-07-17 18:32:21 +01:00
8 changed files with 107 additions and 49 deletions

View File

@ -580,11 +580,10 @@ 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 initial_colour) {
auto draw_line = [&](const ParagraphLayouter::Line &line, bool do_shadow, int left, int min_x, int max_x, bool truncation, TextColour &last_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);
@ -594,10 +593,13 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
FontCache *fc = f->fc;
TextColour colour = f->colour;
if (colour == TC_INVALID || HasFlag(initial_colour, TC_FORCED)) colour = initial_colour;
if (colour == TC_INVALID || HasFlag(last_colour, TC_FORCED)) {
colour = last_colour;
} else {
/* Update the last colour for the truncation ellipsis. */
last_colour = colour;
}
bool colour_has_shadow = (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
/* Update the last colour for the truncation ellipsis. */
last_colour = colour;
if (do_shadow && (!fc->GetDrawGlyphShadow() || !colour_has_shadow)) continue;
SetColourRemap(do_shadow ? TC_BLACK : colour);
@ -623,16 +625,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 colour = draw_line(line, do_shadow, left - offset_x, min_x, max_x, truncation, default_colour);
TextColour last_colour = default_colour;
draw_line(line, do_shadow, left - offset_x, min_x, max_x, truncation, last_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, colour);
draw_line(*truncation_layout->front(), do_shadow, x, INT32_MIN, INT32_MAX, false, last_colour);
}
}

View File

@ -188,19 +188,18 @@ protected:
StringID label = STR_NULL;
uint8_t month_increment = 0;
int16_t x_values_increment = 0;
const HistoryRange *history_range = nullptr;
};
static inline constexpr GraphScale MONTHLY_SCALE_WALLCLOCK[] = {
{STR_GRAPH_LAST_24_MINUTES_TIME_LABEL, HISTORY_MONTH.total_division, ECONOMY_MONTH_MINUTES, &HISTORY_MONTH},
{STR_GRAPH_LAST_72_MINUTES_TIME_LABEL, HISTORY_QUARTER.total_division, ECONOMY_QUARTER_MINUTES, &HISTORY_QUARTER},
{STR_GRAPH_LAST_288_MINUTES_TIME_LABEL, HISTORY_YEAR.total_division, ECONOMY_YEAR_MINUTES, &HISTORY_YEAR},
{STR_GRAPH_LAST_24_MINUTES_TIME_LABEL, HISTORY_MONTH.total_division, ECONOMY_MONTH_MINUTES},
{STR_GRAPH_LAST_72_MINUTES_TIME_LABEL, HISTORY_QUARTER.total_division, ECONOMY_QUARTER_MINUTES},
{STR_GRAPH_LAST_288_MINUTES_TIME_LABEL, HISTORY_YEAR.total_division, ECONOMY_YEAR_MINUTES},
};
static inline constexpr GraphScale MONTHLY_SCALE_CALENDAR[] = {
{STR_GRAPH_LAST_24_MONTHS, HISTORY_MONTH.total_division, ECONOMY_MONTH_MINUTES, &HISTORY_MONTH},
{STR_GRAPH_LAST_24_QUARTERS, HISTORY_QUARTER.total_division, ECONOMY_QUARTER_MINUTES, &HISTORY_QUARTER},
{STR_GRAPH_LAST_24_YEARS, HISTORY_YEAR.total_division, ECONOMY_YEAR_MINUTES, &HISTORY_YEAR},
{STR_GRAPH_LAST_24_MONTHS, HISTORY_MONTH.total_division, ECONOMY_MONTH_MINUTES},
{STR_GRAPH_LAST_24_QUARTERS, HISTORY_QUARTER.total_division, ECONOMY_QUARTER_MINUTES},
{STR_GRAPH_LAST_24_YEARS, HISTORY_YEAR.total_division, ECONOMY_YEAR_MINUTES},
};
uint64_t excluded_data = 0; ///< bitmask of datasets hidden by the player.
@ -1778,7 +1777,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
transported.dash = 2;
auto transported_filler = Filler{transported, &Industry::ProducedHistory::transported};
FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->valid_history, *this->scales[this->selected_scale].history_range, produced_filler, transported_filler);
FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->valid_history, this->selected_scale, produced_filler, transported_filler);
}
for (const auto &a : i->accepted) {
@ -1802,9 +1801,9 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
auto waiting_filler = Filler{waiting, &Industry::AcceptedHistory::waiting};
if (a.history == nullptr) {
FillFromEmpty<GRAPH_NUM_MONTHS>(i->valid_history, *this->scales[this->selected_scale].history_range, accepted_filler, waiting_filler);
FillFromEmpty<GRAPH_NUM_MONTHS>(i->valid_history, this->selected_scale, accepted_filler, waiting_filler);
} else {
FillFromHistory<GRAPH_NUM_MONTHS>(*a.history, i->valid_history, *this->scales[this->selected_scale].history_range, accepted_filler, waiting_filler);
FillFromHistory<GRAPH_NUM_MONTHS>(*a.history, i->valid_history, this->selected_scale, accepted_filler, waiting_filler);
}
}

View File

@ -27,4 +27,6 @@ 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,6 +257,25 @@ 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),
@ -726,7 +745,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, tile, this->selected_type, layout_index, false, seed);
Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, &CcBuildIndustry, 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);
}

View File

@ -38,7 +38,7 @@ void UpdateValidHistory(ValidHistoryMask &valid_history, uint cur_month)
UpdateValidHistory(valid_history, HISTORY_YEAR, cur_month);
}
bool IsValidHistory(ValidHistoryMask valid_history, const HistoryRange &hr, uint age)
static bool IsValidHistory(ValidHistoryMask valid_history, const HistoryRange &hr, uint age)
{
if (hr.hr == nullptr) {
if (age < hr.periods) {
@ -58,4 +58,14 @@ bool IsValidHistory(ValidHistoryMask valid_history, const HistoryRange &hr, uint
return false;
}
bool IsValidHistory(ValidHistoryMask valid_history, uint period, uint age)
{
switch (period) {
case 0: return IsValidHistory(valid_history, HISTORY_MONTH, age);
case 1: return IsValidHistory(valid_history, HISTORY_QUARTER, age);
case 2: return IsValidHistory(valid_history, HISTORY_YEAR, age);
default: NOT_REACHED();
}
}
#endif /* HISTORY_CPP */

View File

@ -16,7 +16,7 @@
#include "history_type.hpp"
void UpdateValidHistory(ValidHistoryMask &valid_history, uint cur_month);
bool IsValidHistory(ValidHistoryMask valid_history, const HistoryRange &hr, uint age);
bool IsValidHistory(ValidHistoryMask valid_history, uint period, uint age);
/**
* Sum history data elements.
@ -100,20 +100,40 @@ bool GetHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, c
NOT_REACHED();
}
/**
* Get history data for the specified period and age within that period.
* @param history History data to extract from.
* @param valid_history Mask of valid history records.
* @param period Period to get.
* @param age Age of data to get.
* @param[out] result Variable to store historical value for period and age.
* @return True if the value is valid.
*/
template <typename T>
bool GetHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, uint period, uint age, T &result)
{
switch (period) {
case 0: return GetHistory(history, valid_history, HISTORY_MONTH, age, result);
case 1: return GetHistory(history, valid_history, HISTORY_QUARTER, age, result);
case 2: return GetHistory(history, valid_history, HISTORY_YEAR, age, result);
default: NOT_REACHED();
}
}
/**
* Fill some data with historical data.
* @param history Historical data to fill from.
* @param valid_history Mask of valid history records.
* @param hr History range to fill with.
* @param period Period (monthly, quarterly, yearly) to fill with.
* @param fillers Fillers to fill with history data.
*/
template <uint N, typename T, typename... Tfillers>
void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, const HistoryRange &hr, Tfillers... fillers)
void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, uint period, Tfillers... fillers)
{
T result{};
T data{};
for (uint i = 0; i != N; ++i) {
if (GetHistory(history, valid_history, hr, N - i - 1, result)) {
(fillers.Fill(i, result), ...);
if (GetHistory(history, valid_history, period, N - i - 1, data)) {
(fillers.Fill(i, data), ...);
} else {
(fillers.MakeInvalid(i), ...);
}
@ -123,14 +143,14 @@ void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_histo
/**
* Fill some data with empty records.
* @param valid_history Mask of valid history records.
* @param hr History range to fill with.
* @param period Period (monthly, quarterly, yearly) to fill with.
* @param fillers Fillers to fill with history data.
*/
template <uint N, typename... Tfillers>
void FillFromEmpty(ValidHistoryMask valid_history, const HistoryRange &hr, Tfillers... fillers)
void FillFromEmpty(ValidHistoryMask valid_history, uint period, Tfillers... fillers)
{
for (uint i = 0; i != N; ++i) {
if (IsValidHistory(valid_history, hr, N - i - 1)) {
if (IsValidHistory(valid_history, period, N - i - 1)) {
(fillers.MakeZero(i), ...);
} else {
(fillers.MakeInvalid(i), ...);

View File

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

View File

@ -26,15 +26,20 @@ uint16_t SumHistory(std::span<const uint16_t> history)
/**
* Helper to get history records and return the value, instead returning its validity.
* @param history History data to extract from.
* @param hr History range to get.
* @param period Period to get.
* @param age Age of data to get.
* @return Historical value for the period and age.
*/
template <typename T>
T GetHistory(const HistoryData<T> &history, const HistoryRange &hr, uint age)
T GetHistory(const HistoryData<T> &history, uint period, uint age)
{
T result;
GetHistory(history, 0, hr, age, result);
switch (period) {
case 0: GetHistory(history, 0, HISTORY_MONTH, age, result); break;
case 1: GetHistory(history, 0, HISTORY_QUARTER, age, result); break;
case 2: GetHistory(history, 0, HISTORY_YEAR, age, result); break;
default: NOT_REACHED();
}
return result;
}
@ -58,26 +63,26 @@ TEST_CASE("History Rotation and Reporting tests")
* for years: 6 + 15 + 24 + 33 = 78, 42 + 51 + 60 + 69 = 222...
*/
for (uint j = 0; j < HISTORY_PERIODS; ++j) {
CHECK(GetHistory(history, HISTORY_MONTH, j) == (( 1 * 1 + 1) / 2) + 1 * 1 * j);
CHECK(GetHistory(history, HISTORY_QUARTER, j) == (( 3 * 3 + 3) / 2) + 3 * 3 * j);
CHECK(GetHistory(history, HISTORY_YEAR, j) == ((12 * 12 + 12) / 2) + 12 * 12 * j);
CHECK(GetHistory(history, 0, j) == (( 1 * 1 + 1) / 2) + 1 * 1 * j);
CHECK(GetHistory(history, 1, j) == (( 3 * 3 + 3) / 2) + 3 * 3 * j);
CHECK(GetHistory(history, 2, j) == ((12 * 12 + 12) / 2) + 12 * 12 * j);
}
/* Double-check quarter history matches summed month history. */
CHECK(GetHistory(history, HISTORY_MONTH, 0) + GetHistory(history, HISTORY_MONTH, 1) + GetHistory(history, HISTORY_MONTH, 2) == GetHistory(history, HISTORY_QUARTER, 0));
CHECK(GetHistory(history, HISTORY_MONTH, 3) + GetHistory(history, HISTORY_MONTH, 4) + GetHistory(history, HISTORY_MONTH, 5) == GetHistory(history, HISTORY_QUARTER, 1));
CHECK(GetHistory(history, HISTORY_MONTH, 6) + GetHistory(history, HISTORY_MONTH, 7) + GetHistory(history, HISTORY_MONTH, 8) == GetHistory(history, HISTORY_QUARTER, 2));
CHECK(GetHistory(history, HISTORY_MONTH, 9) + GetHistory(history, HISTORY_MONTH, 10) + GetHistory(history, HISTORY_MONTH, 11) == GetHistory(history, HISTORY_QUARTER, 3));
CHECK(GetHistory(history, HISTORY_MONTH, 12) + GetHistory(history, HISTORY_MONTH, 13) + GetHistory(history, HISTORY_MONTH, 14) == GetHistory(history, HISTORY_QUARTER, 4));
CHECK(GetHistory(history, HISTORY_MONTH, 15) + GetHistory(history, HISTORY_MONTH, 16) + GetHistory(history, HISTORY_MONTH, 17) == GetHistory(history, HISTORY_QUARTER, 5));
CHECK(GetHistory(history, HISTORY_MONTH, 18) + GetHistory(history, HISTORY_MONTH, 19) + GetHistory(history, HISTORY_MONTH, 20) == GetHistory(history, HISTORY_QUARTER, 6));
CHECK(GetHistory(history, HISTORY_MONTH, 21) + GetHistory(history, HISTORY_MONTH, 22) + GetHistory(history, HISTORY_MONTH, 23) == GetHistory(history, HISTORY_QUARTER, 7));
CHECK(GetHistory(history, 0, 0) + GetHistory(history, 0, 1) + GetHistory(history, 0, 2) == GetHistory(history, 1, 0));
CHECK(GetHistory(history, 0, 3) + GetHistory(history, 0, 4) + GetHistory(history, 0, 5) == GetHistory(history, 1, 1));
CHECK(GetHistory(history, 0, 6) + GetHistory(history, 0, 7) + GetHistory(history, 0, 8) == GetHistory(history, 1, 2));
CHECK(GetHistory(history, 0, 9) + GetHistory(history, 0, 10) + GetHistory(history, 0, 11) == GetHistory(history, 1, 3));
CHECK(GetHistory(history, 0, 12) + GetHistory(history, 0, 13) + GetHistory(history, 0, 14) == GetHistory(history, 1, 4));
CHECK(GetHistory(history, 0, 15) + GetHistory(history, 0, 16) + GetHistory(history, 0, 17) == GetHistory(history, 1, 5));
CHECK(GetHistory(history, 0, 18) + GetHistory(history, 0, 19) + GetHistory(history, 0, 20) == GetHistory(history, 1, 6));
CHECK(GetHistory(history, 0, 21) + GetHistory(history, 0, 22) + GetHistory(history, 0, 23) == GetHistory(history, 1, 7));
/* Double-check year history matches summed quarter history. */
CHECK(GetHistory(history, HISTORY_QUARTER, 0) + GetHistory(history, HISTORY_QUARTER, 1) + GetHistory(history, HISTORY_QUARTER, 2) + GetHistory(history, HISTORY_QUARTER, 3) == GetHistory(history, HISTORY_YEAR, 0));
CHECK(GetHistory(history, HISTORY_QUARTER, 4) + GetHistory(history, HISTORY_QUARTER, 5) + GetHistory(history, HISTORY_QUARTER, 6) + GetHistory(history, HISTORY_QUARTER, 7) == GetHistory(history, HISTORY_YEAR, 1));
CHECK(GetHistory(history, HISTORY_QUARTER, 8) + GetHistory(history, HISTORY_QUARTER, 9) + GetHistory(history, HISTORY_QUARTER, 10) + GetHistory(history, HISTORY_QUARTER, 11) == GetHistory(history, HISTORY_YEAR, 2));
CHECK(GetHistory(history, HISTORY_QUARTER, 12) + GetHistory(history, HISTORY_QUARTER, 13) + GetHistory(history, HISTORY_QUARTER, 14) + GetHistory(history, HISTORY_QUARTER, 15) == GetHistory(history, HISTORY_YEAR, 3));
CHECK(GetHistory(history, HISTORY_QUARTER, 16) + GetHistory(history, HISTORY_QUARTER, 17) + GetHistory(history, HISTORY_QUARTER, 18) + GetHistory(history, HISTORY_QUARTER, 19) == GetHistory(history, HISTORY_YEAR, 4));
CHECK(GetHistory(history, HISTORY_QUARTER, 20) + GetHistory(history, HISTORY_QUARTER, 21) + GetHistory(history, HISTORY_QUARTER, 22) + GetHistory(history, HISTORY_QUARTER, 23) == GetHistory(history, HISTORY_YEAR, 5));
CHECK(GetHistory(history, 1, 0) + GetHistory(history, 1, 1) + GetHistory(history, 1, 2) + GetHistory(history, 1, 3) == GetHistory(history, 2, 0));
CHECK(GetHistory(history, 1, 4) + GetHistory(history, 1, 5) + GetHistory(history, 1, 6) + GetHistory(history, 1, 7) == GetHistory(history, 2, 1));
CHECK(GetHistory(history, 1, 8) + GetHistory(history, 1, 9) + GetHistory(history, 1, 10) + GetHistory(history, 1, 11) == GetHistory(history, 2, 2));
CHECK(GetHistory(history, 1, 12) + GetHistory(history, 1, 13) + GetHistory(history, 1, 14) + GetHistory(history, 1, 15) == GetHistory(history, 2, 3));
CHECK(GetHistory(history, 1, 16) + GetHistory(history, 1, 17) + GetHistory(history, 1, 18) + GetHistory(history, 1, 19) == GetHistory(history, 2, 4));
CHECK(GetHistory(history, 1, 20) + GetHistory(history, 1, 21) + GetHistory(history, 1, 22) + GetHistory(history, 1, 23) == GetHistory(history, 2, 5));
}