mirror of https://github.com/OpenTTD/OpenTTD
Add: Town cargo history graphs.
parent
b24ceb27f5
commit
09347cc5b6
|
@ -27,6 +27,7 @@
|
|||
#include "timer/timer_game_economy.h"
|
||||
#include "zoom_func.h"
|
||||
#include "industry.h"
|
||||
#include "town.h"
|
||||
|
||||
#include "widgets/graph_widget.h"
|
||||
|
||||
|
@ -1858,6 +1859,148 @@ void ShowIndustryProductionGraph(WindowNumber window_number)
|
|||
AllocateWindowDescFront<IndustryProductionGraphWindow>(_industry_production_desc, window_number);
|
||||
}
|
||||
|
||||
struct TownCargoGraphWindow : BaseCargoGraphWindow {
|
||||
static inline constexpr StringID RANGE_LABELS[] = {
|
||||
STR_GRAPH_TOWN_RANGE_PRODUCED,
|
||||
STR_GRAPH_TOWN_RANGE_TRANSPORTED,
|
||||
};
|
||||
|
||||
static inline CargoTypes excluded_cargo_types{};
|
||||
|
||||
TownCargoGraphWindow(WindowDesc &desc, WindowNumber window_number) : BaseCargoGraphWindow(desc, STR_JUST_COMMA)
|
||||
{
|
||||
this->num_on_x_axis = GRAPH_NUM_MONTHS;
|
||||
this->num_vert_lines = GRAPH_NUM_MONTHS;
|
||||
this->month_increment = 1;
|
||||
this->x_values_reversed = true;
|
||||
this->x_values_increment = ECONOMY_MONTH_MINUTES;
|
||||
this->draw_dates = !TimerGameEconomy::UsingWallclockUnits();
|
||||
this->ranges = RANGE_LABELS;
|
||||
|
||||
this->InitializeWindow(window_number, STR_GRAPH_LAST_24_MINUTES_TIME_LABEL);
|
||||
}
|
||||
|
||||
void OnInit() override
|
||||
{
|
||||
this->BaseCargoGraphWindow::OnInit();
|
||||
|
||||
this->scales = TimerGameEconomy::UsingWallclockUnits() ? MONTHLY_SCALE_WALLCLOCK : MONTHLY_SCALE_CALENDAR;
|
||||
}
|
||||
|
||||
CargoTypes GetCargoTypes(WindowNumber window_number) const override
|
||||
{
|
||||
CargoTypes cargo_types{};
|
||||
const Town *t = Town::Get(window_number);
|
||||
for (const auto &s : t->supplied) {
|
||||
if (IsValidCargoType(s.cargo)) SetBit(cargo_types, s.cargo);
|
||||
}
|
||||
return cargo_types;
|
||||
}
|
||||
|
||||
CargoTypes &GetExcludedCargoTypes() const override
|
||||
{
|
||||
return TownCargoGraphWindow::excluded_cargo_types;
|
||||
}
|
||||
|
||||
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
|
||||
{
|
||||
if (widget == WID_GRAPH_CAPTION) return GetString(STR_GRAPH_TOWN_CARGO_CAPTION, this->window_number);
|
||||
|
||||
return this->Window::GetWidgetString(widget, stringid);
|
||||
}
|
||||
|
||||
void UpdateStatistics(bool initialize) override
|
||||
{
|
||||
int mo = TimerGameEconomy::month - this->num_vert_lines;
|
||||
auto yr = TimerGameEconomy::year;
|
||||
while (mo < 0) {
|
||||
yr--;
|
||||
mo += 12;
|
||||
}
|
||||
|
||||
if (!initialize && this->excluded_data == this->GetExcludedCargoTypes() && this->num_on_x_axis == this->num_vert_lines && this->year == yr && this->month == mo) {
|
||||
/* There's no reason to get new stats */
|
||||
return;
|
||||
}
|
||||
|
||||
this->excluded_data = this->GetExcludedCargoTypes();
|
||||
this->year = yr;
|
||||
this->month = mo;
|
||||
|
||||
const Town *t = Town::Get(this->window_number);
|
||||
|
||||
this->data.clear();
|
||||
for (const auto &s : t->supplied) {
|
||||
if (!IsValidCargoType(s.cargo)) continue;
|
||||
const CargoSpec *cs = CargoSpec::Get(s.cargo);
|
||||
|
||||
this->data.reserve(this->data.size() + 2);
|
||||
|
||||
DataSet &produced = this->data.emplace_back();
|
||||
produced.colour = cs->legend_colour;
|
||||
produced.exclude_bit = cs->Index();
|
||||
produced.range_bit = 0;
|
||||
|
||||
DataSet &transported = this->data.emplace_back();
|
||||
transported.colour = cs->legend_colour;
|
||||
transported.exclude_bit = cs->Index();
|
||||
transported.range_bit = 1;
|
||||
transported.dash = 2;
|
||||
|
||||
FillFromHistory<GRAPH_NUM_MONTHS>(s.history, t->valid_history, this->selected_scale, Filler{produced, &Town::SuppliedHistory::production}, Filler{transported, &Town::SuppliedHistory::transported});
|
||||
}
|
||||
|
||||
this->SetDirty();
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr NWidgetPart _nested_town_cargo_graph_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
|
||||
NWidget(WWT_CAPTION, COLOUR_BROWN, WID_GRAPH_CAPTION),
|
||||
NWidget(WWT_SHADEBOX, COLOUR_BROWN),
|
||||
NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
|
||||
NWidget(WWT_STICKYBOX, COLOUR_BROWN),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PANEL, COLOUR_BROWN, WID_GRAPH_BACKGROUND), SetMinimalSize(568, 128),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GRAPH_GRAPH), SetMinimalSize(495, 0), SetFill(1, 1), SetResize(1, 1),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1),
|
||||
NWidget(WWT_MATRIX, COLOUR_BROWN, WID_GRAPH_RANGE_MATRIX), SetFill(1, 0), SetResize(0, 0), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(0, 4),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_GRAPH_ENABLE_CARGOES), SetStringTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_GRAPH_DISABLE_CARGOES), SetStringTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(0, 4),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_MATRIX, COLOUR_BROWN, WID_GRAPH_MATRIX), SetFill(1, 0), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_GRAPH_MATRIX_SCROLLBAR),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_GRAPH_MATRIX_SCROLLBAR),
|
||||
EndContainer(),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(0, 4),
|
||||
NWidget(WWT_MATRIX, COLOUR_BROWN, WID_GRAPH_SCALE_MATRIX), SetFill(1, 0), SetResize(0, 0), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1),
|
||||
EndContainer(),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_TEXT, INVALID_COLOUR, WID_GRAPH_FOOTER), SetFill(1, 0), SetResize(1, 0), SetPadding(2, 0, 2, 0), SetTextStyle(TC_BLACK, FS_SMALL), SetAlignment(SA_CENTER),
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_BROWN, WID_GRAPH_RESIZE), SetResizeWidgetTypeTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _town_cargo_graph_desc(
|
||||
WDP_AUTO, "graph_town_cargo", 0, 0,
|
||||
WC_TOWN_CARGO_GRAPH, WC_TOWN_VIEW,
|
||||
{},
|
||||
_nested_town_cargo_graph_widgets
|
||||
);
|
||||
|
||||
void ShowTownCargoGraph(WindowNumber window_number)
|
||||
{
|
||||
AllocateWindowDescFront<TownCargoGraphWindow>(_town_cargo_graph_desc, window_number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a vertical list of panels for outputting score details.
|
||||
* @return Panel with performance details.
|
||||
|
|
|
@ -20,5 +20,6 @@ void ShowCompanyValueGraph();
|
|||
void ShowCargoPaymentRates();
|
||||
void ShowPerformanceRatingDetail();
|
||||
void ShowIndustryProductionGraph(WindowNumber window_number);
|
||||
void ShowTownCargoGraph(WindowNumber window_number);
|
||||
|
||||
#endif /* GRAPH_GUI_H */
|
||||
|
|
|
@ -648,6 +648,10 @@ STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED :Transported
|
|||
STR_GRAPH_INDUSTRY_RANGE_DELIVERED :Delivered
|
||||
STR_GRAPH_INDUSTRY_RANGE_WAITING :Waiting
|
||||
|
||||
STR_GRAPH_TOWN_CARGO_CAPTION :{WHITE}{TOWN} - Cargo History
|
||||
STR_GRAPH_TOWN_RANGE_PRODUCED :Supply
|
||||
STR_GRAPH_TOWN_RANGE_TRANSPORTED :Transported
|
||||
|
||||
STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show detailed performance ratings
|
||||
|
||||
# Graph key window
|
||||
|
@ -3702,6 +3706,8 @@ STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centre t
|
|||
STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Local Authority
|
||||
STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Show information on local authority
|
||||
STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Change town name
|
||||
STR_TOWN_VIEW_CARGO_GRAPH :Cargo Graph
|
||||
STR_TOWN_VIEW_CARGO_GRAPH_TOOLTIP :Show graph of town's cargo history
|
||||
|
||||
STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Expand
|
||||
STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Increase size of town
|
||||
|
|
|
@ -15,6 +15,15 @@
|
|||
|
||||
#include "safeguards.h"
|
||||
|
||||
template <typename Tproj>
|
||||
static uint16_t TownHistoryHelper(const Town *t, CargoLabel label, uint period, Tproj proj)
|
||||
{
|
||||
auto it = t->GetCargoSupplied(GetCargoTypeByLabel(label));
|
||||
if (it == std::end(t->supplied)) return 0;
|
||||
|
||||
return ClampTo<uint16_t>(std::invoke(proj, it->history[period]));
|
||||
}
|
||||
|
||||
/* virtual */ uint32_t TownScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
|
||||
{
|
||||
if (this->t == nullptr) {
|
||||
|
@ -22,7 +31,6 @@
|
|||
return UINT_MAX;
|
||||
}
|
||||
|
||||
CargoType cargo_type;
|
||||
switch (variable) {
|
||||
/* Larger towns */
|
||||
case 0x40:
|
||||
|
@ -87,22 +95,22 @@
|
|||
case 0xB2: return this->t->statues.base();
|
||||
case 0xB6: return ClampTo<uint16_t>(this->t->cache.num_houses);
|
||||
case 0xB9: return this->t->growth_rate / Ticks::TOWN_GROWTH_TICKS;
|
||||
case 0xBA: cargo_type = GetCargoTypeByLabel(CT_PASSENGERS); return IsValidCargoType(cargo_type) ? ClampTo<uint16_t>(this->t->supplied[cargo_type].new_max) : 0;
|
||||
case 0xBB: cargo_type = GetCargoTypeByLabel(CT_PASSENGERS); return IsValidCargoType(cargo_type) ? GB(ClampTo<uint16_t>(this->t->supplied[cargo_type].new_max), 8, 8) : 0;
|
||||
case 0xBC: cargo_type = GetCargoTypeByLabel(CT_MAIL); return IsValidCargoType(cargo_type) ? ClampTo<uint16_t>(this->t->supplied[cargo_type].new_max) : 0;
|
||||
case 0xBD: cargo_type = GetCargoTypeByLabel(CT_MAIL); return IsValidCargoType(cargo_type) ? GB(ClampTo<uint16_t>(this->t->supplied[cargo_type].new_max), 8, 8) : 0;
|
||||
case 0xBE: cargo_type = GetCargoTypeByLabel(CT_PASSENGERS); return IsValidCargoType(cargo_type) ? ClampTo<uint16_t>(this->t->supplied[cargo_type].new_act) : 0;
|
||||
case 0xBF: cargo_type = GetCargoTypeByLabel(CT_PASSENGERS); return IsValidCargoType(cargo_type) ? GB(ClampTo<uint16_t>(this->t->supplied[cargo_type].new_act), 8, 8) : 0;
|
||||
case 0xC0: cargo_type = GetCargoTypeByLabel(CT_MAIL); return IsValidCargoType(cargo_type) ? ClampTo<uint16_t>(this->t->supplied[cargo_type].new_act) : 0;
|
||||
case 0xC1: cargo_type = GetCargoTypeByLabel(CT_MAIL); return IsValidCargoType(cargo_type) ? GB(ClampTo<uint16_t>(this->t->supplied[cargo_type].new_act), 8, 8) : 0;
|
||||
case 0xC2: cargo_type = GetCargoTypeByLabel(CT_PASSENGERS); return IsValidCargoType(cargo_type) ? ClampTo<uint16_t>(this->t->supplied[cargo_type].old_max) : 0;
|
||||
case 0xC3: cargo_type = GetCargoTypeByLabel(CT_PASSENGERS); return IsValidCargoType(cargo_type) ? GB(ClampTo<uint16_t>(this->t->supplied[cargo_type].old_max), 8, 8) : 0;
|
||||
case 0xC4: cargo_type = GetCargoTypeByLabel(CT_MAIL); return IsValidCargoType(cargo_type) ? ClampTo<uint16_t>(this->t->supplied[cargo_type].old_max) : 0;
|
||||
case 0xC5: cargo_type = GetCargoTypeByLabel(CT_MAIL); return IsValidCargoType(cargo_type) ? GB(ClampTo<uint16_t>(this->t->supplied[cargo_type].old_max), 8, 8) : 0;
|
||||
case 0xC6: cargo_type = GetCargoTypeByLabel(CT_PASSENGERS); return IsValidCargoType(cargo_type) ? ClampTo<uint16_t>(this->t->supplied[cargo_type].old_act) : 0;
|
||||
case 0xC7: cargo_type = GetCargoTypeByLabel(CT_PASSENGERS); return IsValidCargoType(cargo_type) ? GB(ClampTo<uint16_t>(this->t->supplied[cargo_type].old_act), 8, 8) : 0;
|
||||
case 0xC8: cargo_type = GetCargoTypeByLabel(CT_MAIL); return IsValidCargoType(cargo_type) ? ClampTo<uint16_t>(this->t->supplied[cargo_type].old_act) : 0;
|
||||
case 0xC9: cargo_type = GetCargoTypeByLabel(CT_MAIL); return IsValidCargoType(cargo_type) ? GB(ClampTo<uint16_t>(this->t->supplied[cargo_type].old_act), 8, 8) : 0;
|
||||
case 0xBA: return TownHistoryHelper(this->t, CT_PASSENGERS, THIS_MONTH, &Town::SuppliedHistory::production);
|
||||
case 0xBB: return TownHistoryHelper(this->t, CT_PASSENGERS, THIS_MONTH, &Town::SuppliedHistory::production) >> 8;
|
||||
case 0xBC: return TownHistoryHelper(this->t, CT_MAIL, THIS_MONTH, &Town::SuppliedHistory::production);
|
||||
case 0xBD: return TownHistoryHelper(this->t, CT_MAIL, THIS_MONTH, &Town::SuppliedHistory::production) >> 8;
|
||||
case 0xBE: return TownHistoryHelper(this->t, CT_PASSENGERS, THIS_MONTH, &Town::SuppliedHistory::transported);
|
||||
case 0xBF: return TownHistoryHelper(this->t, CT_PASSENGERS, THIS_MONTH, &Town::SuppliedHistory::transported) >> 8;
|
||||
case 0xC0: return TownHistoryHelper(this->t, CT_MAIL, THIS_MONTH, &Town::SuppliedHistory::transported);
|
||||
case 0xC1: return TownHistoryHelper(this->t, CT_MAIL, THIS_MONTH, &Town::SuppliedHistory::transported) >> 8;
|
||||
case 0xC2: return TownHistoryHelper(this->t, CT_PASSENGERS, LAST_MONTH, &Town::SuppliedHistory::production);
|
||||
case 0xC3: return TownHistoryHelper(this->t, CT_PASSENGERS, LAST_MONTH, &Town::SuppliedHistory::production) >> 8;
|
||||
case 0xC4: return TownHistoryHelper(this->t, CT_MAIL, LAST_MONTH, &Town::SuppliedHistory::production);
|
||||
case 0xC5: return TownHistoryHelper(this->t, CT_MAIL, LAST_MONTH, &Town::SuppliedHistory::production) >> 8;
|
||||
case 0xC6: return TownHistoryHelper(this->t, CT_PASSENGERS, LAST_MONTH, &Town::SuppliedHistory::transported);
|
||||
case 0xC7: return TownHistoryHelper(this->t, CT_PASSENGERS, LAST_MONTH, &Town::SuppliedHistory::transported) >> 8;
|
||||
case 0xC8: return TownHistoryHelper(this->t, CT_MAIL, LAST_MONTH, &Town::SuppliedHistory::transported);
|
||||
case 0xC9: return TownHistoryHelper(this->t, CT_MAIL, LAST_MONTH, &Town::SuppliedHistory::transported) >> 8;
|
||||
case 0xCA: return this->t->GetPercentTransported(GetCargoTypeByLabel(CT_PASSENGERS));
|
||||
case 0xCB: return this->t->GetPercentTransported(GetCargoTypeByLabel(CT_MAIL));
|
||||
case 0xCC: return this->t->received[TAE_FOOD].new_act;
|
||||
|
|
|
@ -564,6 +564,9 @@ static void ReadTTDPatchFlags(LoadgameState &ls)
|
|||
Debug(oldloader, 3, "Vehicle-multiplier is set to {} ({} vehicles)", ls.vehicle_multiplier, ls.vehicle_multiplier * 850);
|
||||
}
|
||||
|
||||
static std::array<Town::SuppliedHistory, 2> _old_pass_supplied{};
|
||||
static std::array<Town::SuppliedHistory, 2> _old_mail_supplied{};
|
||||
|
||||
static const OldChunks town_chunk[] = {
|
||||
OCL_SVAR( OC_TILE, Town, xy ),
|
||||
OCL_NULL( 2 ), ///< population, no longer in use
|
||||
|
@ -592,14 +595,14 @@ static const OldChunks town_chunk[] = {
|
|||
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Town, growth_rate ),
|
||||
|
||||
/* Slots 0 and 2 are passengers and mail respectively for old saves. */
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[0].new_max ),
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[2].new_max ),
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[0].new_act ),
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[2].new_act ),
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[0].old_max ),
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[2].old_max ),
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[0].old_act ),
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[2].old_act ),
|
||||
OCL_VAR( OC_FILE_U16 | OC_VAR_U32, 1, &_old_pass_supplied[THIS_MONTH].production ),
|
||||
OCL_VAR( OC_FILE_U16 | OC_VAR_U32, 1, &_old_mail_supplied[THIS_MONTH].production ),
|
||||
OCL_VAR( OC_FILE_U16 | OC_VAR_U32, 1, &_old_pass_supplied[THIS_MONTH].transported ),
|
||||
OCL_VAR( OC_FILE_U16 | OC_VAR_U32, 1, &_old_mail_supplied[THIS_MONTH].transported ),
|
||||
OCL_VAR( OC_FILE_U16 | OC_VAR_U32, 1, &_old_pass_supplied[LAST_MONTH].production ),
|
||||
OCL_VAR( OC_FILE_U16 | OC_VAR_U32, 1, &_old_mail_supplied[LAST_MONTH].production ),
|
||||
OCL_VAR( OC_FILE_U16 | OC_VAR_U32, 1, &_old_pass_supplied[LAST_MONTH].transported ),
|
||||
OCL_VAR( OC_FILE_U16 | OC_VAR_U32, 1, &_old_mail_supplied[LAST_MONTH].transported ),
|
||||
|
||||
OCL_NULL( 2 ), ///< pct_pass_transported / pct_mail_transported, now computed on the fly
|
||||
|
||||
|
@ -626,6 +629,13 @@ static bool LoadOldTown(LoadgameState &ls, int num)
|
|||
/* 0x10B6 is auto-generated name, others are custom names */
|
||||
t->townnametype = t->townnametype == 0x10B6 ? 0x20C1 : t->townnametype + 0x2A00;
|
||||
}
|
||||
/* Passengers and mail were always treated as slots 0 and 2 in older saves. */
|
||||
auto &pass = t->supplied.emplace_back(0);
|
||||
pass.history[LAST_MONTH] = _old_pass_supplied[LAST_MONTH];
|
||||
pass.history[THIS_MONTH] = _old_pass_supplied[THIS_MONTH];
|
||||
auto &mail = t->supplied.emplace_back(2);
|
||||
mail.history[LAST_MONTH] = _old_mail_supplied[LAST_MONTH];
|
||||
mail.history[THIS_MONTH] = _old_mail_supplied[THIS_MONTH];
|
||||
} else {
|
||||
delete t;
|
||||
}
|
||||
|
|
|
@ -406,6 +406,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.
|
||||
SLV_TOWN_SUPPLY_HISTORY, ///< 358 PR#..... Town supply history.
|
||||
|
||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||
};
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "../landscape.h"
|
||||
#include "../subsidy_func.h"
|
||||
#include "../strings_func.h"
|
||||
#include "../misc/history_func.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
|
@ -112,7 +113,8 @@ void UpdateHousesAndTowns()
|
|||
RebuildTownCaches();
|
||||
}
|
||||
|
||||
class SlTownSupplied : public DefaultSaveLoadHandler<SlTownSupplied, Town> {
|
||||
|
||||
class SlTownOldSupplied : public DefaultSaveLoadHandler<SlTownOldSupplied, Town> {
|
||||
public:
|
||||
static inline const SaveLoad description[] = {
|
||||
SLE_CONDVAR(TransportedCargoStat<uint32_t>, old_max, SLE_UINT32, SLV_165, SL_MAX_VERSION),
|
||||
|
@ -134,23 +136,64 @@ public:
|
|||
return SlGetStructListLength(NUM_CARGO);
|
||||
}
|
||||
|
||||
void Save(Town *t) const override
|
||||
{
|
||||
SlSetStructListLength(std::size(t->supplied));
|
||||
for (auto &supplied : t->supplied) {
|
||||
SlObject(&supplied, this->GetDescription());
|
||||
}
|
||||
}
|
||||
|
||||
void Load(Town *t) const override
|
||||
{
|
||||
size_t num_cargo = this->GetNumCargo();
|
||||
for (size_t i = 0; i < num_cargo; i++) {
|
||||
SlObject(&t->supplied[i], this->GetLoadDescription());
|
||||
TransportedCargoStat<uint32_t> cargo_stat;
|
||||
SlObject(&cargo_stat, this->GetLoadDescription());
|
||||
|
||||
/* Ignore empty statistics. */
|
||||
if (cargo_stat.new_act == 0 && cargo_stat.new_max == 0 && cargo_stat.old_act == 0 && cargo_stat.old_max == 0) continue;
|
||||
|
||||
auto &s = t->supplied.emplace_back(static_cast<CargoType>(i));
|
||||
s.history[LAST_MONTH].production = cargo_stat.old_max;
|
||||
s.history[LAST_MONTH].transported = cargo_stat.old_act;
|
||||
s.history[THIS_MONTH].production = cargo_stat.new_max;
|
||||
s.history[THIS_MONTH].transported = cargo_stat.new_act;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SlTownSuppliedHistory : public DefaultSaveLoadHandler<SlTownSuppliedHistory, Town::SuppliedCargo> {
|
||||
public:
|
||||
static inline const SaveLoad description[] = {
|
||||
SLE_VAR(Town::SuppliedHistory, production, SLE_UINT32),
|
||||
SLE_VAR(Town::SuppliedHistory, transported, SLE_UINT32),
|
||||
};
|
||||
static inline const SaveLoadCompatTable compat_description = {};
|
||||
|
||||
void Save(Town::SuppliedCargo *p) const override
|
||||
{
|
||||
SlSetStructListLength(p->history.size());
|
||||
|
||||
for (auto &h : p->history) {
|
||||
SlObject(&h, this->GetDescription());
|
||||
}
|
||||
}
|
||||
|
||||
void Load(Town::SuppliedCargo *p) const override
|
||||
{
|
||||
size_t len = SlGetStructListLength(p->history.size());
|
||||
|
||||
for (auto &h : p->history) {
|
||||
if (--len > p->history.size()) break; // unsigned so wraps after hitting zero.
|
||||
SlObject(&h, this->GetDescription());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SlTownSupplied : public VectorSaveLoadHandler<SlTownSupplied, Town, Town::SuppliedCargo> {
|
||||
public:
|
||||
inline static const SaveLoad description[] = {
|
||||
SLE_VAR(Town::SuppliedCargo, cargo, SLE_UINT8),
|
||||
SLEG_STRUCTLIST("history", SlTownSuppliedHistory),
|
||||
};
|
||||
inline const static SaveLoadCompatTable compat_description = {};
|
||||
|
||||
std::vector<Town::SuppliedCargo> &GetVector(Town *t) const override { return t->supplied; }
|
||||
};
|
||||
|
||||
class SlTownReceived : public DefaultSaveLoadHandler<SlTownReceived, Town> {
|
||||
public:
|
||||
static inline const SaveLoad description[] = {
|
||||
|
@ -205,6 +248,9 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static std::array<Town::SuppliedHistory, 2> _old_pass_supplied{};
|
||||
static std::array<Town::SuppliedHistory, 2> _old_mail_supplied{};
|
||||
|
||||
static const SaveLoad _town_desc[] = {
|
||||
SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
||||
SLE_CONDVAR(Town, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
||||
|
@ -226,22 +272,22 @@ static const SaveLoad _town_desc[] = {
|
|||
SLE_CONDARR(Town, unwanted, SLE_INT8, MAX_COMPANIES, SLV_104, SL_MAX_VERSION),
|
||||
|
||||
/* Slots 0 and 2 are passengers and mail respectively for old saves. */
|
||||
SLE_CONDVARNAME(Town, supplied[0].old_max, "supplied[CT_PASSENGERS].old_max", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLE_CONDVARNAME(Town, supplied[0].old_max, "supplied[CT_PASSENGERS].old_max", SLE_UINT32, SLV_9, SLV_165),
|
||||
SLE_CONDVARNAME(Town, supplied[2].old_max, "supplied[CT_MAIL].old_max", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLE_CONDVARNAME(Town, supplied[2].old_max, "supplied[CT_MAIL].old_max", SLE_UINT32, SLV_9, SLV_165),
|
||||
SLE_CONDVARNAME(Town, supplied[0].new_max, "supplied[CT_PASSENGERS].new_max", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLE_CONDVARNAME(Town, supplied[0].new_max, "supplied[CT_PASSENGERS].new_max", SLE_UINT32, SLV_9, SLV_165),
|
||||
SLE_CONDVARNAME(Town, supplied[2].new_max, "supplied[CT_MAIL].new_max", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLE_CONDVARNAME(Town, supplied[2].new_max, "supplied[CT_MAIL].new_max", SLE_UINT32, SLV_9, SLV_165),
|
||||
SLE_CONDVARNAME(Town, supplied[0].old_act, "supplied[CT_PASSENGERS].old_act", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLE_CONDVARNAME(Town, supplied[0].old_act, "supplied[CT_PASSENGERS].old_act", SLE_UINT32, SLV_9, SLV_165),
|
||||
SLE_CONDVARNAME(Town, supplied[2].old_act, "supplied[CT_MAIL].old_act", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLE_CONDVARNAME(Town, supplied[2].old_act, "supplied[CT_MAIL].old_act", SLE_UINT32, SLV_9, SLV_165),
|
||||
SLE_CONDVARNAME(Town, supplied[0].new_act, "supplied[CT_PASSENGERS].new_act", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLE_CONDVARNAME(Town, supplied[0].new_act, "supplied[CT_PASSENGERS].new_act", SLE_UINT32, SLV_9, SLV_165),
|
||||
SLE_CONDVARNAME(Town, supplied[2].new_act, "supplied[CT_MAIL].new_act", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLE_CONDVARNAME(Town, supplied[2].new_act, "supplied[CT_MAIL].new_act", SLE_UINT32, SLV_9, SLV_165),
|
||||
SLEG_CONDVAR("supplied[CT_PASSENGERS].old_max", _old_pass_supplied[LAST_MONTH].production, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLEG_CONDVAR("supplied[CT_PASSENGERS].old_max", _old_pass_supplied[LAST_MONTH].production, SLE_UINT32, SLV_9, SLV_165),
|
||||
SLEG_CONDVAR( "supplied[CT_MAIL].old_max", _old_mail_supplied[LAST_MONTH].production, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLEG_CONDVAR( "supplied[CT_MAIL].old_max", _old_mail_supplied[LAST_MONTH].production, SLE_UINT32, SLV_9, SLV_165),
|
||||
SLEG_CONDVAR("supplied[CT_PASSENGERS].new_max", _old_pass_supplied[THIS_MONTH].production, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLEG_CONDVAR("supplied[CT_PASSENGERS].new_max", _old_pass_supplied[THIS_MONTH].production, SLE_UINT32, SLV_9, SLV_165),
|
||||
SLEG_CONDVAR( "supplied[CT_MAIL].new_max", _old_mail_supplied[THIS_MONTH].production, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLEG_CONDVAR( "supplied[CT_MAIL].new_max", _old_mail_supplied[THIS_MONTH].production, SLE_UINT32, SLV_9, SLV_165),
|
||||
SLEG_CONDVAR("supplied[CT_PASSENGERS].old_act", _old_pass_supplied[LAST_MONTH].transported, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLEG_CONDVAR("supplied[CT_PASSENGERS].old_act", _old_pass_supplied[LAST_MONTH].transported, SLE_UINT32, SLV_9, SLV_165),
|
||||
SLEG_CONDVAR( "supplied[CT_MAIL].old_act", _old_mail_supplied[LAST_MONTH].transported, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLEG_CONDVAR( "supplied[CT_MAIL].old_act", _old_mail_supplied[LAST_MONTH].transported, SLE_UINT32, SLV_9, SLV_165),
|
||||
SLEG_CONDVAR("supplied[CT_PASSENGERS].new_act", _old_pass_supplied[THIS_MONTH].transported, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLEG_CONDVAR("supplied[CT_PASSENGERS].new_act", _old_pass_supplied[THIS_MONTH].transported, SLE_UINT32, SLV_9, SLV_165),
|
||||
SLEG_CONDVAR( "supplied[CT_MAIL].new_act", _old_mail_supplied[THIS_MONTH].transported, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
|
||||
SLEG_CONDVAR( "supplied[CT_MAIL].new_act", _old_mail_supplied[THIS_MONTH].transported, SLE_UINT32, SLV_9, SLV_165),
|
||||
|
||||
SLE_CONDVARNAME(Town, received[TAE_FOOD].old_act, "received[TE_FOOD].old_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
|
||||
SLE_CONDVARNAME(Town, received[TAE_WATER].old_act, "received[TE_WATER].old_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
|
||||
|
@ -268,10 +314,12 @@ static const SaveLoad _town_desc[] = {
|
|||
|
||||
SLE_CONDVAR(Town, larger_town, SLE_BOOL, SLV_56, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Town, layout, SLE_UINT8, SLV_113, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Town, valid_history, SLE_UINT64, SLV_TOWN_SUPPLY_HISTORY, SL_MAX_VERSION),
|
||||
|
||||
SLE_CONDREFVECTOR(Town, psa_list, REF_STORAGE, SLV_161, SL_MAX_VERSION),
|
||||
|
||||
SLEG_CONDSTRUCTLIST("supplied", SlTownSupplied, SLV_165, SL_MAX_VERSION),
|
||||
SLEG_CONDSTRUCTLIST("supplied", SlTownOldSupplied, SLV_165, SLV_TOWN_SUPPLY_HISTORY),
|
||||
SLEG_CONDSTRUCTLIST("supplied", SlTownSupplied, SLV_TOWN_SUPPLY_HISTORY, SL_MAX_VERSION),
|
||||
SLEG_CONDSTRUCTLIST("received", SlTownReceived, SLV_165, SL_MAX_VERSION),
|
||||
SLEG_CONDSTRUCTLIST("acceptance_matrix", SlTownAcceptanceMatrix, SLV_166, SLV_REMOVE_TOWN_CARGO_CACHE),
|
||||
};
|
||||
|
@ -303,6 +351,20 @@ struct CITYChunkHandler : ChunkHandler {
|
|||
Town *t = new (TownID(index)) Town();
|
||||
SlObject(t, slt);
|
||||
|
||||
if (IsSavegameVersionBefore(SLV_165)) {
|
||||
/* Passengers and mail were always treated as slots 0 and 2 in older saves. */
|
||||
auto &pass = t->supplied.emplace_back(0);
|
||||
pass.history[LAST_MONTH] = _old_pass_supplied[LAST_MONTH];
|
||||
pass.history[THIS_MONTH] = _old_pass_supplied[THIS_MONTH];
|
||||
auto &mail = t->supplied.emplace_back(2);
|
||||
mail.history[LAST_MONTH] = _old_mail_supplied[LAST_MONTH];
|
||||
mail.history[THIS_MONTH] = _old_mail_supplied[THIS_MONTH];
|
||||
}
|
||||
|
||||
if (IsSavegameVersionBefore(SLV_TOWN_SUPPLY_HISTORY)) {
|
||||
t->valid_history = 1U << LAST_MONTH;
|
||||
}
|
||||
|
||||
if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_END) && GetStringTab(t->townnametype) != TEXT_TAB_OLD_CUSTOM) {
|
||||
SlErrorCorrupt("Invalid town name generator");
|
||||
}
|
||||
|
|
|
@ -93,7 +93,10 @@
|
|||
|
||||
const Town *t = ::Town::Get(town_id);
|
||||
|
||||
return t->supplied[cargo_type].old_max;
|
||||
auto it = t->GetCargoSupplied(cargo_type);
|
||||
if (it == std::end(t->supplied)) return 0;
|
||||
|
||||
return it->history[LAST_MONTH].production;
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptTown::GetLastMonthSupplied(TownID town_id, CargoType cargo_type)
|
||||
|
@ -103,7 +106,10 @@
|
|||
|
||||
const Town *t = ::Town::Get(town_id);
|
||||
|
||||
return t->supplied[cargo_type].old_act;
|
||||
auto it = t->GetCargoSupplied(cargo_type);
|
||||
if (it == std::end(t->supplied)) return 0;
|
||||
|
||||
return it->history[LAST_MONTH].transported;
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptTown::GetLastMonthTransportedPercentage(TownID town_id, CargoType cargo_type)
|
||||
|
|
47
src/town.h
47
src/town.h
|
@ -10,6 +10,7 @@
|
|||
#ifndef TOWN_H
|
||||
#define TOWN_H
|
||||
|
||||
#include "misc/history_type.hpp"
|
||||
#include "viewport_type.h"
|
||||
#include "timer/timer_game_tick.h"
|
||||
#include "town_map.h"
|
||||
|
@ -74,16 +75,56 @@ struct Town : TownPool::PoolItem<&_town_pool> {
|
|||
uint8_t exclusive_counter = 0; ///< months till the exclusivity expires
|
||||
TypedIndexContainer<std::array<int16_t, MAX_COMPANIES>, CompanyID> ratings{}; ///< ratings of each company for this town
|
||||
|
||||
std::array<TransportedCargoStat<uint32_t>, NUM_CARGO> supplied{}; ///< Cargo statistics about supplied cargo.
|
||||
struct SuppliedHistory {
|
||||
uint32_t production = 0; ///< Total produced
|
||||
uint32_t transported = 0; ///< Total transported
|
||||
|
||||
uint8_t PctTransported() const
|
||||
{
|
||||
if (this->production == 0) return 0;
|
||||
return ClampTo<uint8_t>(this->transported * 256 / this->production);
|
||||
}
|
||||
};
|
||||
|
||||
struct SuppliedCargo {
|
||||
CargoType cargo = INVALID_CARGO;
|
||||
HistoryData<SuppliedHistory> history{};
|
||||
|
||||
SuppliedCargo() = default;
|
||||
SuppliedCargo(CargoType cargo) : cargo(cargo) {}
|
||||
};
|
||||
|
||||
using SuppliedCargoes = std::vector<SuppliedCargo>;
|
||||
|
||||
SuppliedCargoes supplied{}; ///< Cargo statistics about supplied cargo.
|
||||
std::array<TransportedCargoStat<uint16_t>, NUM_TAE> received{}; ///< Cargo statistics about received cargotypes.
|
||||
std::array<uint32_t, NUM_TAE> goal{}; ///< Amount of cargo required for the town to grow.
|
||||
ValidHistoryMask valid_history = 0; ///< Mask of valid history records.
|
||||
|
||||
EncodedString text{}; ///< General text with additional information.
|
||||
|
||||
inline SuppliedCargo &GetOrCreateCargoSupplied(CargoType cargo)
|
||||
{
|
||||
assert(IsValidCargoType(cargo));
|
||||
auto it = std::ranges::lower_bound(this->supplied, cargo, std::less{}, &SuppliedCargo::cargo);
|
||||
if (it == std::end(this->supplied) || it->cargo != cargo) it = this->supplied.emplace(it, cargo);
|
||||
return *it;
|
||||
}
|
||||
|
||||
inline SuppliedCargoes::const_iterator GetCargoSupplied(CargoType cargo) const
|
||||
{
|
||||
if (!IsValidCargoType(cargo)) return std::end(this->supplied);
|
||||
auto it = std::ranges::lower_bound(this->supplied, cargo, std::less{}, &SuppliedCargo::cargo);
|
||||
if (it == std::end(this->supplied) || it->cargo != cargo) return std::end(supplied);
|
||||
return it;
|
||||
}
|
||||
|
||||
inline uint8_t GetPercentTransported(CargoType cargo_type) const
|
||||
{
|
||||
if (!IsValidCargoType(cargo_type)) return 0;
|
||||
return this->supplied[cargo_type].old_act * 256 / (this->supplied[cargo_type].old_max + 1);
|
||||
auto it = this->GetCargoSupplied(cargo_type);
|
||||
if (it == std::end(this->supplied)) return 0;
|
||||
|
||||
return it->history[LAST_MONTH].PctTransported();
|
||||
}
|
||||
|
||||
StationList stations_near{}; ///< NOSAVE: List of nearby stations.
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
/** @file town_cmd.cpp Handling of town tiles. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "misc/history_type.hpp"
|
||||
#include "misc/history_func.hpp"
|
||||
#include "road.h"
|
||||
#include "road_internal.h" /* Cleaning up road bits */
|
||||
#include "road_cmd.h"
|
||||
|
@ -114,6 +116,7 @@ Town::~Town()
|
|||
/* Delete town authority window
|
||||
* and remove from list of sorted towns */
|
||||
CloseWindowById(WC_TOWN_VIEW, this->index);
|
||||
CloseWindowById(WC_TOWN_CARGO_GRAPH, this->index);
|
||||
|
||||
#ifdef WITH_ASSERT
|
||||
/* Check no industry is related to us. */
|
||||
|
@ -536,10 +539,12 @@ static void TownGenerateCargo(Town *t, CargoType cargo, uint amount, StationFind
|
|||
|
||||
/* Scale by cargo scale setting. */
|
||||
amount = ScaleByCargoScale(amount, true);
|
||||
if (amount == 0) return;
|
||||
|
||||
/* Actually generate cargo and update town statistics. */
|
||||
t->supplied[cargo].new_max += amount;
|
||||
t->supplied[cargo].new_act += MoveGoodsToStation(cargo, amount, {t->index, SourceType::Town}, stations.GetStations());;
|
||||
auto &supplied = t->GetOrCreateCargoSupplied(cargo);
|
||||
supplied.history[THIS_MONTH].production += amount;
|
||||
supplied.history[THIS_MONTH].transported += MoveGoodsToStation(cargo, amount, {t->index, SourceType::Town}, stations.GetStations());;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2004,10 +2009,19 @@ void UpdateTownRadius(Town *t)
|
|||
void UpdateTownMaxPass(Town *t)
|
||||
{
|
||||
for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_PASSENGERS]) {
|
||||
t->supplied[cs->Index()].old_max = ScaleByCargoScale(t->cache.population >> 3, true);
|
||||
uint32_t production = ScaleByCargoScale(t->cache.population >> 3, true);
|
||||
if (production == 0) continue;
|
||||
|
||||
auto &supplied = t->GetOrCreateCargoSupplied(cs->Index());
|
||||
supplied.history[LAST_MONTH].production = production;
|
||||
}
|
||||
|
||||
for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_MAIL]) {
|
||||
t->supplied[cs->Index()].old_max = ScaleByCargoScale(t->cache.population >> 4, true);
|
||||
uint32_t production = ScaleByCargoScale(t->cache.population >> 4, true);
|
||||
if (production == 0) continue;
|
||||
|
||||
auto &supplied = t->GetOrCreateCargoSupplied(cs->Index());
|
||||
supplied.history[LAST_MONTH].production = production;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4058,6 +4072,15 @@ CommandCost CheckforTownRating(DoCommandFlags flags, Town *t, TownRatingCheckTyp
|
|||
return CommandCost();
|
||||
}
|
||||
|
||||
template <>
|
||||
Town::SuppliedHistory SumHistory(std::span<const Town::SuppliedHistory> history)
|
||||
{
|
||||
uint32_t production = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &s) { return r + s.production; });
|
||||
uint32_t transported = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &s) { return r + s.transported; });
|
||||
auto count = std::size(history);
|
||||
return {.production = ClampTo<uint16_t>(production / count), .transported = ClampTo<uint16_t>(transported / count)};
|
||||
}
|
||||
|
||||
static const IntervalTimer<TimerGameEconomy> _economy_towns_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::TOWN}, [](auto)
|
||||
{
|
||||
for (Town *t : Town::Iterate()) {
|
||||
|
@ -4074,8 +4097,10 @@ static const IntervalTimer<TimerGameEconomy> _economy_towns_monthly({TimerGameEc
|
|||
if (t->unwanted[c->index] > 0) t->unwanted[c->index]--;
|
||||
}
|
||||
|
||||
UpdateValidHistory(t->valid_history, TimerGameEconomy::month);
|
||||
|
||||
/* Update cargo statistics. */
|
||||
for (auto &supplied : t->supplied) supplied.NewMonth();
|
||||
for (auto &s : t->supplied) RotateHistory(s.history, t->valid_history, TimerGameEconomy::month);
|
||||
for (auto &received : t->received) received.NewMonth();
|
||||
|
||||
UpdateTownGrowth(t);
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "timer/timer_window.h"
|
||||
#include "zoom_func.h"
|
||||
#include "hotkeys.h"
|
||||
#include "graph_gui.h"
|
||||
|
||||
#include "widgets/town_widget.h"
|
||||
|
||||
|
@ -400,7 +401,12 @@ public:
|
|||
for (auto tpe : {TPE_PASSENGERS, TPE_MAIL}) {
|
||||
for (const CargoSpec *cs : CargoSpec::town_production_cargoes[tpe]) {
|
||||
CargoType cargo_type = cs->Index();
|
||||
DrawString(tr, GetString(str_last_period, 1ULL << cargo_type, this->town->supplied[cargo_type].old_act, this->town->supplied[cargo_type].old_max));
|
||||
auto it = this->town->GetCargoSupplied(cargo_type);
|
||||
if (it == std::end(this->town->supplied)) {
|
||||
DrawString(tr, GetString(str_last_period, 1ULL << cargo_type, 0, 0));
|
||||
} else {
|
||||
DrawString(tr, GetString(str_last_period, 1ULL << cargo_type, it->history[LAST_MONTH].transported, it->history[LAST_MONTH].production));
|
||||
}
|
||||
tr.top += GetCharacterHeight(FS_NORMAL);
|
||||
}
|
||||
}
|
||||
|
@ -503,6 +509,11 @@ public:
|
|||
case WID_TV_DELETE: // delete town - only available on Scenario editor
|
||||
Command<CMD_DELETE_TOWN>::Post(STR_ERROR_TOWN_CAN_T_DELETE, static_cast<TownID>(this->window_number));
|
||||
break;
|
||||
|
||||
case WID_TV_GRAPH: {
|
||||
ShowTownCargoGraph(this->window_number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,6 +629,7 @@ static constexpr NWidgetPart _nested_town_game_view_widgets[] = {
|
|||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(40, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_GRAPH), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_CARGO_GRAPH, STR_TOWN_VIEW_CARGO_GRAPH_TOOLTIP),
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
|
||||
EndContainer(),
|
||||
};
|
||||
|
|
|
@ -45,6 +45,7 @@ enum TownViewWidgets : WidgetID {
|
|||
WID_TV_EXPAND_BUILDINGS, ///< Expand number of buildings this town (scenario editor only).
|
||||
WID_TV_EXPAND_ROADS, ///< Expand roads of this town (scenario editor only).
|
||||
WID_TV_DELETE, ///< Delete this town (scenario editor only).
|
||||
WID_TV_GRAPH,
|
||||
};
|
||||
|
||||
/** Widgets of the #FoundTownWindow class. */
|
||||
|
|
|
@ -582,6 +582,12 @@ enum WindowClass : uint16_t {
|
|||
*/
|
||||
WC_INDUSTRY_PRODUCTION,
|
||||
|
||||
/**
|
||||
* Town cargo history graph; %Window numbers:
|
||||
* - #TownID = #GraphWidgets
|
||||
*/
|
||||
WC_TOWN_CARGO_GRAPH,
|
||||
|
||||
/**
|
||||
* Company infrastructure overview; %Window numbers:
|
||||
* - #CompanyID = #CompanyInfrastructureWidgets
|
||||
|
|
Loading…
Reference in New Issue