1
0
Fork 0

Compare commits

...

13 Commits

Author SHA1 Message Date
Peter Nelson 0972d3373f
Change: Add support for different horizontal graph scales. 2025-07-18 22:28:09 +01:00
Peter Nelson 9a106c4af4
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-18 22:28:09 +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
Loïc Guilloux 1b01a0636c
Fix #14362, 4b677e8256: Don't crash old scripts doing silly instantiation (#14394) 2025-07-17 13:30:33 +02:00
nikolas bccbd64037
Fix: GL error typo (#14376) 2025-07-17 07:18:35 +01:00
Ivan Pravdin 434163aa31
Fix #14277: Aircraft can land when Zeppeliner in the runway (#14317) 2025-07-17 07:26:57 +02:00
translators 55605ae8f2 Update: Translations from eints
english (au): 1 change by krysclarke
catalan: 1 change by J0anJosep
portuguese: 8 changes by jcteotonio
2025-07-17 04:45:55 +00:00
Jonathan G Rennison 7f792e9c5f
Codefix: Spelling error in name of GetGRFStringTextStackParameters (#14447) 2025-07-16 09:21:25 -04:00
translators 6b6caa6fa8 Update: Translations from eints
chinese (traditional): 1 change by KogentaSan
greek: 1 change by gh658804
hungarian: 1 change by vargaviktor
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
catalan: 49 changes by J0anJosep
portuguese: 2 changes by jcteotonio
portuguese (brazilian): 1 change by pasantoro
polish: 1 change by pAter-exe
2025-07-16 04:46:46 +00:00
Peter Nelson 67e56391c7
Fix #8167: No error sub-message when trying to clear protected buildings. (#14444) 2025-07-14 23:23:15 +01:00
Peter Nelson e015e3ecc3
Codefix 3fde611012: AirportMovingDataFlag should be `enum class` (#14435)
`AirportMovingDataFlag` was changed to use `enum class` naming style, but wasn't actually changed to be `enum class`.
2025-07-14 23:22:51 +01:00
Henry Wilson 8330957a4d Codechange: Remove manual memory management from IcuStringIterator 2025-07-14 23:55:24 +02:00
41 changed files with 701 additions and 97 deletions

View File

@ -36,3 +36,11 @@ AITown.FoundTown <- function(tile, size, city, layout, name) { return AITown.Fou
AIVehicle.SetNameCompat14 <- AIVehicle.SetName; AIVehicle.SetNameCompat14 <- AIVehicle.SetName;
AIVehicle.SetName <- function(id, name) { return AIVehicle.SetNameCompat14(id, AICompat14.Text(name)); } AIVehicle.SetName <- function(id, name) { return AIVehicle.SetNameCompat14(id, AICompat14.Text(name)); }
AIObject.constructorCompat14 <- AIObject.constructor;
foreach(name, object in CompatScriptRootTable) {
if (type(object) != "class") continue;
if (!object.rawin("constructor")) continue;
if (object.constructor != AIObject.constructorCompat14) continue;
object.constructor <- function() : (name) { AILog.Error("'" + name + "' is not instantiable"); }
}

View File

@ -81,3 +81,11 @@ GSTown.FoundTown <- function(tile, size, city, layout, name) { return GSTown.Fou
GSVehicle.SetNameCompat14 <- GSVehicle.SetName; GSVehicle.SetNameCompat14 <- GSVehicle.SetName;
GSVehicle.SetName <- function(id, name) { return GSVehicle.SetNameCompat14(id, GSCompat14.Text(name)); } GSVehicle.SetName <- function(id, name) { return GSVehicle.SetNameCompat14(id, GSCompat14.Text(name)); }
GSObject.constructorCompat14 <- GSObject.constructor;
foreach(name, object in CompatScriptRootTable) {
if (type(object) != "class") continue;
if (!object.rawin("constructor")) continue;
if (object.constructor != GSObject.constructorCompat14) continue;
object.constructor <- function() : (name) { GSLog.Error("'" + name + "' is not instantiable"); }
}

View File

@ -1125,6 +1125,15 @@ static bool AircraftController(Aircraft *v)
} }
if (amd.flags.Test(AirportMovingDataFlag::Land)) { if (amd.flags.Test(AirportMovingDataFlag::Land)) {
if (st->airport.blocks.Test(AirportBlock::Zeppeliner)) {
/* Zeppeliner blocked the runway, abort landing */
v->state = FLYING;
UpdateAircraftCache(v);
SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlightLevel(v));
v->pos = v->previous_pos;
continue;
}
if (st->airport.tile == INVALID_TILE) { if (st->airport.tile == INVALID_TILE) {
/* Airport has been removed, abort the landing procedure */ /* Airport has been removed, abort the landing procedure */
v->state = FLYING; v->state = FLYING;
@ -1782,6 +1791,11 @@ static void AirportClearBlock(const Aircraft *v, const AirportFTAClass *apc)
if (apc->layout[v->previous_pos].blocks != apc->layout[v->pos].blocks) { if (apc->layout[v->previous_pos].blocks != apc->layout[v->pos].blocks) {
Station *st = Station::Get(v->targetairport); Station *st = Station::Get(v->targetairport);
if (st->airport.blocks.Test(AirportBlock::Zeppeliner) &&
apc->layout[v->previous_pos].blocks == AirportBlock::RunwayIn) {
return;
}
st->airport.blocks.Reset(apc->layout[v->previous_pos].blocks); st->airport.blocks.Reset(apc->layout[v->previous_pos].blocks);
} }
} }

View File

@ -44,7 +44,7 @@ enum AirportTypes : uint8_t {
}; };
/** Flags for airport movement data. */ /** Flags for airport movement data. */
enum AirportMovingDataFlag : uint8_t { enum class AirportMovingDataFlag : uint8_t {
NoSpeedClamp, ///< No speed restrictions. NoSpeedClamp, ///< No speed restrictions.
Takeoff, ///< Takeoff movement. Takeoff, ///< Takeoff movement.
SlowTurn, ///< Turn slowly (mostly used in the air). SlowTurn, ///< Turn slowly (mostly used in the air).
@ -127,6 +127,7 @@ enum class AirportBlock : uint8_t {
/* end of new blocks */ /* end of new blocks */
Nothing = 30, Nothing = 30,
Zeppeliner = 62, ///< Block for the zeppeliner disaster vehicle.
AirportClosed = 63, ///< Dummy block for indicating a closed airport. AirportClosed = 63, ///< Dummy block for indicating a closed airport.
}; };
using AirportBlocks = EnumBitSet<AirportBlock, uint64_t>; using AirportBlocks = EnumBitSet<AirportBlock, uint64_t>;

View File

@ -215,7 +215,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z)
/** /**
* Zeppeliner handling, v->state states: * Zeppeliner handling, v->state states:
* 0: Zeppeliner initialization has found a small airport, go there and crash * 0: Zeppeliner initialization has found an airport, go there and crash
* 1: Create crash and animate falling down for extra dramatic effect * 1: Create crash and animate falling down for extra dramatic effect
* 2: Create more smoke and leave debris on ground * 2: Create more smoke and leave debris on ground
* 2: Clear the runway after some time and remove crashed zeppeliner * 2: Clear the runway after some time and remove crashed zeppeliner
@ -263,7 +263,7 @@ static bool DisasterTick_Zeppeliner(DisasterVehicle *v)
if (IsValidTile(v->tile) && IsAirportTile(v->tile)) { if (IsValidTile(v->tile) && IsAirportTile(v->tile)) {
Station *st = Station::GetByTile(v->tile); Station *st = Station::GetByTile(v->tile);
st->airport.blocks.Reset(AirportBlock::RunwayIn); st->airport.blocks.Reset({AirportBlock::Zeppeliner, AirportBlock::RunwayIn});
AI::NewEvent(GetTileOwner(v->tile), new ScriptEventDisasterZeppelinerCleared(st->index)); AI::NewEvent(GetTileOwner(v->tile), new ScriptEventDisasterZeppelinerCleared(st->index));
} }
@ -300,7 +300,7 @@ static bool DisasterTick_Zeppeliner(DisasterVehicle *v)
} }
if (IsValidTile(v->tile) && IsAirportTile(v->tile)) { if (IsValidTile(v->tile) && IsAirportTile(v->tile)) {
Station::GetByTile(v->tile)->airport.blocks.Set(AirportBlock::RunwayIn); Station::GetByTile(v->tile)->airport.blocks.Reset({AirportBlock::Zeppeliner, AirportBlock::RunwayIn});
} }
return true; return true;
@ -722,14 +722,14 @@ typedef void DisasterInitProc();
/** /**
* Zeppeliner which crashes on a small airport if one found, * Zeppeliner which crashes on an airport if one found,
* otherwise crashes on a random tile * otherwise crashes on a random tile
*/ */
static void Disaster_Zeppeliner_Init() static void Disaster_Zeppeliner_Init()
{ {
if (!Vehicle::CanAllocateItem(2)) return; if (!Vehicle::CanAllocateItem(2)) return;
/* Pick a random place, unless we find a small airport */ /* Pick a random place, unless we find an airport */
int x = TileX(RandomTile()) * TILE_SIZE + TILE_SIZE / 2; int x = TileX(RandomTile()) * TILE_SIZE + TILE_SIZE / 2;
for (const Station *st : Station::Iterate()) { for (const Station *st : Station::Iterate()) {

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); uint amount = std::min(num_pieces, 0xFFFFu - it->waiting);
it->waiting += amount; it->waiting += amount;
it->GetOrCreateHistory()[THIS_MONTH].accepted += amount;
it->last_accepted = TimerGameEconomy::date; it->last_accepted = TimerGameEconomy::date;
num_pieces -= amount; num_pieces -= amount;
accepted += amount; accepted += amount;

View File

@ -8,6 +8,7 @@
/** @file graph_gui.cpp GUI that shows performance graphs. */ /** @file graph_gui.cpp GUI that shows performance graphs. */
#include "stdafx.h" #include "stdafx.h"
#include <ranges>
#include "misc/history_func.hpp" #include "misc/history_func.hpp"
#include "graph_gui.h" #include "graph_gui.h"
#include "window_gui.h" #include "window_gui.h"
@ -174,6 +175,7 @@ protected:
static const int GRAPH_PAYMENT_RATE_STEPS = 20; ///< Number of steps on Payment rate graph. static const int GRAPH_PAYMENT_RATE_STEPS = 20; ///< Number of steps on Payment rate graph.
static const int PAYMENT_GRAPH_X_STEP_DAYS = 10; ///< X-axis step label for cargo payment rates "Days in transit". static const int PAYMENT_GRAPH_X_STEP_DAYS = 10; ///< X-axis step label for cargo payment rates "Days in transit".
static const int PAYMENT_GRAPH_X_STEP_SECONDS = 20; ///< X-axis step label for cargo payment rates "Seconds in transit". static const int PAYMENT_GRAPH_X_STEP_SECONDS = 20; ///< X-axis step label for cargo payment rates "Seconds in transit".
static const int ECONOMY_YEAR_MINUTES = 12; ///< Minutes per economic year.
static const int ECONOMY_QUARTER_MINUTES = 3; ///< Minutes per economic quarter. static const int ECONOMY_QUARTER_MINUTES = 3; ///< Minutes per economic quarter.
static const int ECONOMY_MONTH_MINUTES = 1; ///< Minutes per economic month. static const int ECONOMY_MONTH_MINUTES = 1; ///< Minutes per economic month.
@ -182,8 +184,27 @@ protected:
static const int MIN_GRAPH_NUM_LINES_Y = 9; ///< Minimal number of horizontal lines to draw. 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. 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. struct GraphScale {
uint64_t excluded_range = 0; ///< bitmask of ranges that should not be displayed. StringID label = STR_NULL;
uint8_t month_increment = 0;
int16_t x_values_increment = 0;
};
static inline constexpr GraphScale MONTHLY_SCALE_WALLCLOCK[] = {
{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},
{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.
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_on_x_axis = 0;
uint8_t num_vert_lines = GRAPH_NUM_MONTHS; uint8_t num_vert_lines = GRAPH_NUM_MONTHS;
@ -210,19 +231,28 @@ protected:
}; };
std::vector<DataSet> data{}; std::vector<DataSet> data{};
std::span<const StringID> ranges = {}; std::span<const StringID> ranges{};
std::span<const GraphScale> scales{};
uint8_t selected_scale = 0;
uint8_t highlight_data = UINT8_MAX; ///< Data set that should be highlighted, or UINT8_MAX for none. uint8_t highlight_data = UINT8_MAX; ///< Data set that should be highlighted, or UINT8_MAX for none.
uint8_t highlight_range = UINT8_MAX; ///< Data range that should be highlighted, or UINT8_MAX for none. 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. bool highlight_state = false; ///< Current state of highlight, toggled every TIMER_BLINK_INTERVAL period.
template <typename Tprojection> struct BaseFiller {
struct Filler {
DataSet &dataset; ///< Dataset to fill. 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. 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 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; }
}; };
/** /**
@ -609,24 +639,34 @@ protected:
this->SetDirty(); this->SetDirty();
}}; }};
void UpdateMatrixSize(WidgetID widget, Dimension &size, Dimension &resize, auto labels)
{
size = {};
for (const StringID &str : labels) {
size = maxdim(size, GetStringBoundingBox(str, FS_SMALL));
}
size.width += WidgetDimensions::scaled.framerect.Horizontal();
size.height += WidgetDimensions::scaled.framerect.Vertical();
/* Set fixed height for number of ranges. */
size.height *= static_cast<uint>(std::size(labels));
resize.width = 0;
resize.height = 0;
this->GetWidget<NWidgetCore>(widget)->SetMatrixDimension(1, ClampTo<uint32_t>(std::size(labels)));
}
public: public:
void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
{ {
switch (widget) { switch (widget) {
case WID_GRAPH_RANGE_MATRIX: case WID_GRAPH_RANGE_MATRIX:
for (const StringID &str : this->ranges) { this->UpdateMatrixSize(widget, size, resize, this->ranges);
size = maxdim(size, GetStringBoundingBox(str, FS_SMALL)); break;
}
size.width += WidgetDimensions::scaled.framerect.Horizontal(); case WID_GRAPH_SCALE_MATRIX:
size.height += WidgetDimensions::scaled.framerect.Vertical(); this->UpdateMatrixSize(widget, size, resize, this->scales | std::views::transform(&GraphScale::label));
/* Set fixed height for number of ranges. */
size.height *= static_cast<uint>(std::size(this->ranges));
resize.width = 0;
resize.height = 0;
this->GetWidget<NWidgetCore>(WID_GRAPH_RANGE_MATRIX)->SetMatrixDimension(1, ClampTo<uint32_t>(std::size(this->ranges)));
break; break;
case WID_GRAPH_GRAPH: { case WID_GRAPH_GRAPH: {
@ -675,13 +715,17 @@ public:
uint index = 0; uint index = 0;
Rect line = r.WithHeight(line_height); Rect line = r.WithHeight(line_height);
for (const auto &str : this->ranges) { 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 */ /* Redraw frame if lowered */
if (lowered) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered); if (lowered) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered);
const Rect text = line.Shrink(WidgetDimensions::scaled.framerect); 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); line = line.Translate(0, line_height);
++index; ++index;
@ -689,6 +733,21 @@ public:
break; break;
} }
case WID_GRAPH_SCALE_MATRIX: {
uint line_height = GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical();
uint8_t selected_month_increment = this->scales[this->selected_scale].month_increment;
Rect line = r.WithHeight(line_height);
for (const auto &scale : this->scales) {
/* Redraw frame if selected */
if (selected_month_increment == scale.month_increment) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered);
DrawString(line.Shrink(WidgetDimensions::scaled.framerect), scale.label, TC_BLACK, SA_CENTER, false, FS_SMALL);
line = line.Translate(0, line_height);
}
break;
}
default: break; default: break;
} }
} }
@ -704,11 +763,24 @@ public:
case WID_GRAPH_RANGE_MATRIX: { case WID_GRAPH_RANGE_MATRIX: {
int row = GetRowFromWidget(pt.y, widget, 0, GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical()); 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); ToggleBit(this->excluded_range, row);
this->SetDirty(); this->SetDirty();
break; break;
} }
case WID_GRAPH_SCALE_MATRIX: {
int row = GetRowFromWidget(pt.y, widget, 0, GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical());
const auto &scale = this->scales[row];
if (this->selected_scale != row) {
this->selected_scale = row;
this->month_increment = scale.month_increment;
this->x_values_increment = scale.x_values_increment;
this->InvalidateData();
}
break;
}
default: break; default: break;
} }
} }
@ -1115,6 +1187,7 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
{ {
this->CreateNestedTree(); this->CreateNestedTree();
this->excluded_range = this->masked_range;
this->cargo_types = this->GetCargoTypes(number); this->cargo_types = this->GetCargoTypes(number);
this->vscroll = this->GetScrollbar(WID_GRAPH_MATRIX_SCROLLBAR); this->vscroll = this->GetScrollbar(WID_GRAPH_MATRIX_SCROLLBAR);
@ -1608,7 +1681,9 @@ CompanyID PerformanceRatingDetailWindow::company = CompanyID::Invalid();
struct IndustryProductionGraphWindow : BaseCargoGraphWindow { struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
static inline constexpr StringID RANGE_LABELS[] = { static inline constexpr StringID RANGE_LABELS[] = {
STR_GRAPH_INDUSTRY_RANGE_PRODUCED, 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{}; static inline CargoTypes excluded_cargo_types{};
@ -1623,13 +1698,27 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
this->draw_dates = !TimerGameEconomy::UsingWallclockUnits(); this->draw_dates = !TimerGameEconomy::UsingWallclockUnits();
this->ranges = RANGE_LABELS; 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); 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 GetCargoTypes(WindowNumber window_number) const override
{ {
CargoTypes cargo_types{}; CargoTypes cargo_types{};
const Industry *i = Industry::Get(window_number); 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) { for (const auto &p : i->produced) {
if (IsValidCargoType(p.cargo)) SetBit(cargo_types, p.cargo); if (IsValidCargoType(p.cargo)) SetBit(cargo_types, p.cargo);
} }
@ -1643,14 +1732,14 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
std::string GetWidgetString(WidgetID widget, StringID stringid) const override 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); return this->Window::GetWidgetString(widget, stringid);
} }
void UpdateStatistics(bool initialize) override void UpdateStatistics(bool initialize) override
{ {
int mo = TimerGameEconomy::month - this->num_vert_lines; int mo = (TimerGameEconomy::month / this->month_increment - this->num_vert_lines) * this->month_increment;
auto yr = TimerGameEconomy::year; auto yr = TimerGameEconomy::year;
while (mo < 0) { while (mo < 0) {
yr--; yr--;
@ -1688,7 +1777,34 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
transported.dash = 2; transported.dash = 2;
auto transported_filler = Filler{transported, &Industry::ProducedHistory::transported}; auto transported_filler = Filler{transported, &Industry::ProducedHistory::transported};
FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->valid_history, 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) {
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, this->selected_scale, accepted_filler, waiting_filler);
} else {
FillFromHistory<GRAPH_NUM_MONTHS>(*a.history, i->valid_history, this->selected_scale, accepted_filler, waiting_filler);
}
} }
this->SetDirty(); this->SetDirty();
@ -1708,7 +1824,7 @@ static constexpr NWidgetPart _nested_industry_production_widgets[] = {
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GRAPH_GRAPH), SetMinimalSize(495, 0), SetFill(1, 1), SetResize(1, 1), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GRAPH_GRAPH), SetMinimalSize(495, 0), SetFill(1, 1), SetResize(1, 1),
NWidget(NWID_VERTICAL), NWidget(NWID_VERTICAL),
NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), 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(WWT_MATRIX, COLOUR_BROWN, WID_GRAPH_RANGE_MATRIX), SetFill(1, 0), SetResize(0, 0), SetMatrixDataTip(1, 0, STR_GRAPH_TOGGLE_RANGE),
NWidget(NWID_SPACER), SetMinimalSize(0, 4), 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_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(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_GRAPH_DISABLE_CARGOES), SetStringTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0),
@ -1717,6 +1833,8 @@ static constexpr NWidgetPart _nested_industry_production_widgets[] = {
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(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), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_GRAPH_MATRIX_SCROLLBAR),
EndContainer(), 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_SELECT_SCALE),
NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1),
EndContainer(), EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1), NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1),

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 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 { struct AcceptedCargo {
CargoType cargo = 0; ///< Cargo type CargoType cargo = 0; ///< Cargo type
uint16_t waiting = 0; ///< Amount of cargo waiting to processed 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 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>; using ProducedCargoes = std::vector<ProducedCargo>;
@ -151,7 +168,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
*/ */
inline const AcceptedCargo &GetAccepted(size_t slot) const 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; return slot < this->accepted.size() ? this->accepted[slot] : empty;
} }

View File

@ -1245,6 +1245,10 @@ void OnTick_Industry()
for (Industry *i : Industry::Iterate()) { for (Industry *i : Industry::Iterate()) {
ProduceIndustryGoods(i); ProduceIndustryGoods(i);
if ((TimerGameTick::counter + i->index) % Ticks::DAY_TICKS == 0) {
for (auto &a : i->accepted) a.accumulated_waiting += a.waiting;
}
} }
} }
@ -1838,7 +1842,7 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false); p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
} }
UpdateValidHistory(i->valid_history); UpdateValidHistory(i->valid_history, TimerGameEconomy::month);
} }
if (indspec->callback_mask.Test(IndustryCallbackMask::DecideColour)) { if (indspec->callback_mask.Test(IndustryCallbackMask::DecideColour)) {
@ -2490,21 +2494,48 @@ void GenerateIndustries()
_industry_builder.Reset(); _industry_builder.Reset();
} }
template <>
Industry::ProducedHistory SumHistory(std::span<const Industry::ProducedHistory> history)
{
uint32_t production = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.production; });
uint32_t transported = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.transported; });
auto count = std::size(history);
return {.production = ClampTo<uint16_t>(production / count), .transported = ClampTo<uint16_t>(transported / count)};
}
template <>
Industry::AcceptedHistory SumHistory(std::span<const Industry::AcceptedHistory> history)
{
uint32_t accepted = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.accepted; });
uint32_t waiting = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.waiting; });;
auto count = std::size(history);
return {.accepted = ClampTo<uint16_t>(accepted / count), .waiting = ClampTo<uint16_t>(waiting / count)};
}
/** /**
* Monthly update of industry statistics. * Monthly update of industry statistics.
* @param i Industry to update. * @param i Industry to update.
*/ */
static void UpdateIndustryStatistics(Industry *i) static void UpdateIndustryStatistics(Industry *i)
{ {
UpdateValidHistory(i->valid_history); auto month = TimerGameEconomy::month;
UpdateValidHistory(i->valid_history, month);
for (auto &p : i->produced) { for (auto &p : i->produced) {
if (IsValidCargoType(p.cargo)) { if (IsValidCargoType(p.cargo)) {
if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year; if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;
RotateHistory(p.history); RotateHistory(p.history, i->valid_history, month);
} }
} }
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, i->valid_history, month);
}
} }
/** /**

View File

@ -845,7 +845,7 @@ public:
nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ScaleZoomGUI(ZoomLevel::Industry)); nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ScaleZoomGUI(ZoomLevel::Industry));
const Industry *i = Industry::Get(window_number); 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(); this->InvalidateData();
} }
@ -1242,7 +1242,7 @@ static constexpr NWidgetPart _nested_industry_view_widgets[] = {
EndContainer(), EndContainer(),
NWidget(NWID_HORIZONTAL), 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_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), NWidget(WWT_RESIZEBOX, COLOUR_CREAM),
EndContainer(), EndContainer(),
}; };

View File

@ -5002,6 +5002,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}O terren
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Terreno inclinado na direção errada STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Terreno inclinado na direção errada
STR_ERROR_CAN_T_DO_THIS :{WHITE}Não é possível fazer isto... STR_ERROR_CAN_T_DO_THIS :{WHITE}Não é possível fazer isto...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}A construção precisa ser demolida primeiro STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}A construção precisa ser demolida primeiro
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... construção é protegida
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Não é possível limpar esta área... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Não é possível limpar esta área...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... local não adequado STR_ERROR_SITE_UNSUITABLE :{WHITE}... local não adequado
STR_ERROR_ALREADY_BUILT :{WHITE}... já construído STR_ERROR_ALREADY_BUILT :{WHITE}... já construído

View File

@ -268,6 +268,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}any{
STR_UNITS_PERIODS :{NUM}{NBSP}període{P "" s} STR_UNITS_PERIODS :{NUM}{NBSP}període{P "" s}
STR_LIST_SEPARATOR :,{SPACE} STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings # Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filtre: STR_LIST_FILTER_TITLE :{BLACK}Filtre:
@ -286,7 +287,7 @@ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Tanca la
STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Títol de la finestra: arrossegueu el títol per desplaçar la finestra. STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Títol de la finestra: arrossegueu el títol per desplaçar la finestra.
STR_TOOLTIP_SHADE :{BLACK}Ombra de la finestra: mostra només la barra de títol. STR_TOOLTIP_SHADE :{BLACK}Ombra de la finestra: mostra només la barra de títol.
STR_TOOLTIP_DEBUG :{BLACK}Mostra la informació de depuració NewGRF STR_TOOLTIP_DEBUG :{BLACK}Mostra la informació de depuració NewGRF
STR_TOOLTIP_DEFSIZE :{BLACK}Redimensiona la finestra a la mida predeterminada. Ctrl+Clic desa la mida actual com a predeterminada. STR_TOOLTIP_DEFSIZE :{BLACK}Redimensiona la finestra a la mida predeterminada. Amb Ctrl+Clic, es desa la mida actual com a predeterminada. Amb Ctrl+doble clic, es restableix als valors per defecte.
STR_TOOLTIP_STICKY :{BLACK}Marca aquesta finestra com a no eliminable per la tecla «Tanca totes les finestres». Ctrl+Clic per desar també l'estat predeterminat. STR_TOOLTIP_STICKY :{BLACK}Marca aquesta finestra com a no eliminable per la tecla «Tanca totes les finestres». Ctrl+Clic per desar també l'estat predeterminat.
STR_TOOLTIP_RESIZE :{BLACK}Clica i arrossega per redimensionar aquesta finestra STR_TOOLTIP_RESIZE :{BLACK}Clica i arrossega per redimensionar aquesta finestra
STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Commuta entre la mida gran i petita de la finestra STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Commuta entre la mida gran i petita de la finestra
@ -1108,7 +1109,7 @@ STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :Informació add
STR_GAME_OPTIONS_ONLINE_CONTENT :Descarrega contingut STR_GAME_OPTIONS_ONLINE_CONTENT :Descarrega contingut
STR_GAME_OPTIONS_ONLINE_CONTENT_TOOLTIP :Comprova si hi ha continguts nous o actualitzats per a descarregar. STR_GAME_OPTIONS_ONLINE_CONTENT_TOOLTIP :Comprova si hi ha continguts nous o actualitzats per a descarregar.
STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE :{LTBLUE}(no s'han instal·lat complements per a interactuar amb plataformes socials) STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE :(no s'han instal·lat complements per a interactuar amb plataformes socials)
STR_GAME_OPTIONS_SOCIAL_PLUGIN_TITLE :{STRING} ({STRING}) STR_GAME_OPTIONS_SOCIAL_PLUGIN_TITLE :{STRING} ({STRING})
STR_GAME_OPTIONS_SOCIAL_PLUGIN_PLATFORM :Plataforma: STR_GAME_OPTIONS_SOCIAL_PLUGIN_PLATFORM :Plataforma:
@ -1226,7 +1227,7 @@ STR_CITY_APPROVAL_PERMISSIVE :Permissiva (les
STR_WARNING_NO_SUITABLE_AI :{WHITE}No hi ha cap IA disponible...{}Podeu descarregar-ne a través del «Contingut en línia». STR_WARNING_NO_SUITABLE_AI :{WHITE}No hi ha cap IA disponible...{}Podeu descarregar-ne a través del «Contingut en línia».
# Settings tree in the Game Options window # Settings tree in the Game Options window
STR_CONFIG_SETTING_FILTER_TITLE :{G=Masculin}{BLACK}Filtre: STR_CONFIG_SETTING_FILTER_TITLE :{G=Masculin}Filtre:
STR_CONFIG_SETTING_EXPAND_ALL :Desplega-ho tot STR_CONFIG_SETTING_EXPAND_ALL :Desplega-ho tot
STR_CONFIG_SETTING_COLLAPSE_ALL :Plega-ho tot STR_CONFIG_SETTING_COLLAPSE_ALL :Plega-ho tot
STR_CONFIG_SETTING_RESET_ALL :Restableix tots els valors STR_CONFIG_SETTING_RESET_ALL :Restableix tots els valors
@ -1302,6 +1303,9 @@ STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Tipus d'interè
STR_CONFIG_SETTING_RUNNING_COSTS :Costos d'utilització: {STRING} STR_CONFIG_SETTING_RUNNING_COSTS :Costos d'utilització: {STRING}
STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Fixa el nivell de manteniment i els costos d'utilització dels vehicles i infraestructures STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Fixa el nivell de manteniment i els costos d'utilització dels vehicles i infraestructures
###length 3 ###length 3
STR_CONFIG_SETTING_RUNNING_COSTS_LOW :Baix
STR_CONFIG_SETTING_RUNNING_COSTS_MEDIUM :Mitjà
STR_CONFIG_SETTING_RUNNING_COSTS_HIGH :Alt
STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Ritme de construcció: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Ritme de construcció: {STRING}
STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Limita la quantitat d'accions de construcció per part de les IA STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Limita la quantitat d'accions de construcció per part de les IA
@ -1324,6 +1328,9 @@ STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED :Sense subsidis
STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Costos de construcció: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Costos de construcció: {STRING}
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Fixa el nivell de construcció i els preus de compra STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Fixa el nivell de construcció i els preus de compra
###length 3 ###length 3
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_LOW :Baix
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_MEDIUM :Mitjà
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HIGH :Alt
STR_CONFIG_SETTING_RECESSIONS :Recessions: {STRING} STR_CONFIG_SETTING_RECESSIONS :Recessions: {STRING}
STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Si està activat, poden haver recessions periòdicament. Durant una recessió, tota la producció és significativament més baixa, tornant al nivell previ quan s'acabi el període de recessió. STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Si està activat, poden haver recessions periòdicament. Durant una recessió, tota la producció és significativament més baixa, tornant al nivell previ quan s'acabi el període de recessió.
@ -2079,9 +2086,9 @@ STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :La classe de c
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Mode de distribució per altres classes de càrrega: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Mode de distribució per altres classes de càrrega: {STRING}
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"Asimètric" vol dir que quantitats arbitràries de càrrega poden ser enviades en qualsevol sentit. "Manual" significa que no s'aplicarà cap distribució automàtica a aquestes càrregues. STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"Asimètric" vol dir que quantitats arbitràries de càrrega poden ser enviades en qualsevol sentit. "Manual" significa que no s'aplicarà cap distribució automàtica a aquestes càrregues.
###length 3 ###length 3
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manual STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :Manual
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asimètric STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :Asimètric
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :simètric STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :Simètric
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Precisió de la distribució: {STRING} STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Precisió de la distribució: {STRING}
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Com més alt el valor indicat, més temps de processador requerirà el càlcul del graf de distribució. Si requereix massa temps podeu notar ralentització. Si indiqueu un valor baix, però, la distribució serà poc acurada, i us podeu trobar que la càrrega no és enviada als llocs que espereu. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Com més alt el valor indicat, més temps de processador requerirà el càlcul del graf de distribució. Si requereix massa temps podeu notar ralentització. Si indiqueu un valor baix, però, la distribució serà poc acurada, i us podeu trobar que la càrrega no és enviada als llocs que espereu.
@ -2331,16 +2338,19 @@ STR_FACE_SIMPLE_TOOLTIP :{BLACK}Selecci
STR_FACE_LOAD :{BLACK}Carrega STR_FACE_LOAD :{BLACK}Carrega
STR_FACE_LOAD_TOOLTIP :{BLACK}Carrega la cara preferida STR_FACE_LOAD_TOOLTIP :{BLACK}Carrega la cara preferida
STR_FACE_LOAD_DONE :{WHITE}S'ha carregat la cara personalitzada des de l'arxiu de configuració de l'OpenTTD. STR_FACE_LOAD_DONE :{WHITE}S'ha carregat la cara personalitzada des de l'arxiu de configuració de l'OpenTTD.
STR_FACE_FACECODE :{BLACK}Número de la cara STR_FACE_FACECODE :{BLACK}Codi de la cara
STR_FACE_FACECODE_TOOLTIP :{BLACK}Veure i/o assigna el número de la cara del president STR_FACE_FACECODE_TOOLTIP :{BLACK}Veure i/o assigna el codi de la cara del president
STR_FACE_FACECODE_CAPTION :{WHITE}Veure i/o assigna el número de la cara del president STR_FACE_FACECODE_CAPTION :{WHITE}Veure i/o assigna el codi de la cara del president
STR_FACE_FACECODE_SET :{WHITE}El número de la nova cara ha estat assignat STR_FACE_FACECODE_SET :{WHITE}S'ha assignat el codi de la nova cara del president.
STR_FACE_FACECODE_ERR :{WHITE}No s'ha pogut assignar el número de cara del president - ha de ser un nombre entre 0 i 4,294,967,295! STR_FACE_FACECODE_ERR :{WHITE}No s'ha pogut assignar el codi de cara del president - ha de ser una etiqueta i nombre vàlids.
STR_FACE_SAVE :{BLACK}Desa STR_FACE_SAVE :{BLACK}Desa
STR_FACE_SAVE_TOOLTIP :{BLACK}Desa la cara preferida STR_FACE_SAVE_TOOLTIP :{BLACK}Desa la cara preferida
STR_FACE_SAVE_DONE :{WHITE}Es desarà aquesta cara personalitzada a l'arxiu de configuració de l'OpenTTD. STR_FACE_SAVE_DONE :{WHITE}Es desarà aquesta cara personalitzada a l'arxiu de configuració de l'OpenTTD.
STR_FACE_SETTING_TOGGLE :{STRING} {ORANGE}{STRING}
STR_FACE_SETTING_NUMERIC :{STRING} {ORANGE}{NUM} / {NUM}
STR_FACE_YES :Sí STR_FACE_YES :Sí
STR_FACE_NO :No STR_FACE_NO :No
STR_FACE_STYLE :Estil:
STR_FACE_HAIR :Cabell: STR_FACE_HAIR :Cabell:
STR_FACE_EYEBROWS :Celles: STR_FACE_EYEBROWS :Celles:
STR_FACE_EYECOLOUR :Color dels ulls: STR_FACE_EYECOLOUR :Color dels ulls:
@ -2813,6 +2823,10 @@ STR_PICKER_MODE_USED_TOOLTIP :Commuta entre m
STR_PICKER_MODE_SAVED :Desats STR_PICKER_MODE_SAVED :Desats
STR_PICKER_MODE_SAVED_TOOLTIP :Commuta entre mostrar tots o bé només els elements desats. STR_PICKER_MODE_SAVED_TOOLTIP :Commuta entre mostrar tots o bé només els elements desats.
STR_PICKER_PREVIEW_SHRINK :
STR_PICKER_PREVIEW_SHRINK_TOOLTIP :Redueix l'alçària de les vistes prèvies. Amb Ctrl+clic, es redueix fins al mínim.
STR_PICKER_PREVIEW_EXPAND :+
STR_PICKER_PREVIEW_EXPAND_TOOLTIP :Augmenta l'alçària de les vistes prèvies. Amb Ctrl+clic, s'augmenta fins al màxim.
STR_PICKER_STATION_CLASS_TOOLTIP :Trieu quina classe d'estació voleu veure. STR_PICKER_STATION_CLASS_TOOLTIP :Trieu quina classe d'estació voleu veure.
STR_PICKER_STATION_TYPE_TOOLTIP :Trieu quin tipus d'estació voleu construir. Amb Ctrl+clic, s'afegeix o es trau l'element de la llista de desats. STR_PICKER_STATION_TYPE_TOOLTIP :Trieu quin tipus d'estació voleu construir. Amb Ctrl+clic, s'afegeix o es trau l'element de la llista de desats.
@ -3053,6 +3067,11 @@ STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Seleccio
STR_FOUND_TOWN_CITY :{BLACK}Ciutat STR_FOUND_TOWN_CITY :{BLACK}Ciutat
STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Les ciutats creixen més ràpid que els pobles{}Depenent de la configuració, són més grans quan es funden STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Les ciutats creixen més ràpid que els pobles{}Depenent de la configuració, són més grans quan es funden
STR_FOUND_TOWN_EXPAND_MODE :{YELLOW}Expansió de la població:
STR_FOUND_TOWN_EXPAND_BUILDINGS :Edificis
STR_FOUND_TOWN_EXPAND_BUILDINGS_TOOLTIP :Augmenta el nombre d'edificis de les poblacions.
STR_FOUND_TOWN_EXPAND_ROADS :Carreteres
STR_FOUND_TOWN_EXPAND_ROADS_TOOLTIP :Augmenta el nombre de carreteres de la població.
STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Disposició de les carreteres de la població: STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Disposició de les carreteres de la població:
STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP :{BLACK}Selecciona la disposició de les carreteres utilitzades per a aquesta població STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP :{BLACK}Selecciona la disposició de les carreteres utilitzades per a aquesta població
@ -3677,6 +3696,10 @@ STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Canvia e
STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Eixampla STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Eixampla
STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Incrementa la mida de la població STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Incrementa la mida de la població
STR_TOWN_VIEW_EXPAND_BUILDINGS_BUTTON :{BLACK}Expandeix els edificis
STR_TOWN_VIEW_EXPAND_BUILDINGS_TOOLTIP :{BLACK}Augmenta el nombre d'edificis de la població.
STR_TOWN_VIEW_EXPAND_ROADS_BUTTON :{BLACK}Expandeix les carreteres
STR_TOWN_VIEW_EXPAND_ROADS_TOOLTIP :{BLACK}Augmenta el nombre de carreteres de la població.
STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Esborra STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Esborra
STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Esborra totalment aquesta població STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Esborra totalment aquesta població
@ -4415,10 +4438,10 @@ STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Mostra l
STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Mostra les ordres de l'avió. Ctrl+Clic per mostrar l'horari de l'avió STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Mostra les ordres de l'avió. Ctrl+Clic per mostrar l'horari de l'avió
###length VEHICLE_TYPES ###length VEHICLE_TYPES
STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del tren STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del tren. Amb Ctrl+clic, es mostra el grup del tren.
STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del vehicle STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del vehicle. Amb Ctrl+clic, es mostra el grup del vehicle.
STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del vaixell STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del vaixell. Amb Ctrl+clic, es mostra el grup del vaixell.
STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls de l'avió STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls de l'aeronau. Amb Ctrl+clic, es mostra el grup de l'aeronau.
###length VEHICLE_TYPES ###length VEHICLE_TYPES
STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP :{BLACK}Acció actual del tren - Feu clic per parar-lo o engegar-lo. STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP :{BLACK}Acció actual del tren - Feu clic per parar-lo o engegar-lo.
@ -4742,14 +4765,15 @@ STR_TIMETABLE_TOOLTIP :{BLACK}Horari -
STR_TIMETABLE_NO_TRAVEL :Sense viatge STR_TIMETABLE_NO_TRAVEL :Sense viatge
STR_TIMETABLE_NOT_TIMETABLEABLE :Viatge (automàtic; programat per la següent ordre manual) STR_TIMETABLE_NOT_TIMETABLEABLE :Viatge (automàtic; programat per la següent ordre manual)
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Viatge (fora d'horari) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Viatge (fora d'horari)
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Viatja (sense horari) com a molt a {VELOCITY}
STR_TIMETABLE_TRAVEL_FOR :Viatge a {STRING} STR_TIMETABLE_TRAVEL_FOR :Viatge a {STRING}
STR_TIMETABLE_TRAVEL_FOR_SPEED :Viatja durant {STRING} com a molt a {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_SPEED :Viatja durant {STRING} com a molt a {VELOCITY}
STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Viatja (durant {STRING}, sense horari) STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Viatja (durant {STRING}, sense horari)
STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Viatja (durant {STRING}, sense horari) com a molt a {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Viatja (durant {STRING}, sense horari) com a molt a {VELOCITY}
STR_TIMETABLE_STAY_FOR_ESTIMATED :{SPACE}(quedar-s'hi durant {STRING}, sense horari) STR_TIMETABLE_STAY_FOR_ESTIMATED :{SPACE}(quedar-s'hi durant {STRING}, sense horari)
STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :{SPACE}(viatja durant {STRING}, sense horari) STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :{SPACE}(viatja durant {STRING}, sense horari)
STR_TIMETABLE_STAY_FOR :i estigues {STRING} STR_TIMETABLE_STAY_FOR :{SPACE}i estigues {STRING}
STR_TIMETABLE_AND_TRAVEL_FOR :i viatge per {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :{SPACE}i viatja durant {STRING}
STR_TIMETABLE_APPROX_TIME :{BLACK}L'horari trigara aproximadament {STRING} a completar-se. STR_TIMETABLE_APPROX_TIME :{BLACK}L'horari trigara aproximadament {STRING} a completar-se.
STR_TIMETABLE_TOTAL_TIME :{BLACK}L'horari tardarà {STRING} a complir-se STR_TIMETABLE_TOTAL_TIME :{BLACK}L'horari tardarà {STRING} a complir-se
@ -4978,6 +5002,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Es neces
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Terreny inclinat en direcció incorrecta STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Terreny inclinat en direcció incorrecta
STR_ERROR_CAN_T_DO_THIS :{WHITE}Això no es pot fer... STR_ERROR_CAN_T_DO_THIS :{WHITE}Això no es pot fer...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}L'edifici s'ha d'enderrocar primer STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}L'edifici s'ha d'enderrocar primer
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... l'edifici està protegit
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}No es pot netejar aquesta àrea... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}No es pot netejar aquesta àrea...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... lloc inadequat STR_ERROR_SITE_UNSUITABLE :{WHITE}... lloc inadequat
STR_ERROR_ALREADY_BUILT :{WHITE}... ja construït STR_ERROR_ALREADY_BUILT :{WHITE}... ja construït
@ -5897,3 +5922,11 @@ STR_SHIP :{BLACK}{SHIP}
STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY})
STR_BADGE_NAME_LIST :{STRING}: {GOLD}{STRING} STR_BADGE_NAME_LIST :{STRING}: {GOLD}{STRING}
STR_BADGE_CONFIG_MENU_TOOLTIP :Obre la configuració d'insígnies
STR_BADGE_CONFIG_RESET :Restableix
STR_BADGE_CONFIG_ICONS :{WHITE}Icones d'insígnies
STR_BADGE_CONFIG_FILTERS :{WHITE}Filtres d'insígnies
STR_BADGE_CONFIG_PREVIEW :Imatge de previsualització
STR_BADGE_CONFIG_NAME :Nom
STR_BADGE_FILTER_ANY_LABEL :Qualsevol {STRING}
STR_BADGE_FILTER_IS_LABEL :{STRING} és {STRING}

View File

@ -622,6 +622,14 @@ STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Company
STR_GRAPH_LAST_24_MINUTES_TIME_LABEL :{TINY_FONT}{BLACK}Last 24 minutes STR_GRAPH_LAST_24_MINUTES_TIME_LABEL :{TINY_FONT}{BLACK}Last 24 minutes
STR_GRAPH_LAST_72_MINUTES_TIME_LABEL :{TINY_FONT}{BLACK}Last 72 minutes STR_GRAPH_LAST_72_MINUTES_TIME_LABEL :{TINY_FONT}{BLACK}Last 72 minutes
STR_GRAPH_LAST_288_MINUTES_TIME_LABEL :{TINY_FONT}{BLACK}Last 288 minutes
STR_GRAPH_LAST_24_MONTHS :{TINY_FONT}{BLACK}2 years (monthly)
STR_GRAPH_LAST_24_QUARTERS :{TINY_FONT}{BLACK}6 years (quarterly)
STR_GRAPH_LAST_24_YEARS :{TINY_FONT}{BLACK}24 years (yearly)
STR_GRAPH_TOGGLE_RANGE :Toggle graph for this data range
STR_GRAPH_SELECT_SCALE :Change horizontal scale of graph
STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Cargo Payment Rates STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Cargo Payment Rates
STR_GRAPH_CARGO_PAYMENT_RATES_DAYS :{TINY_FONT}{BLACK}Days in transit STR_GRAPH_CARGO_PAYMENT_RATES_DAYS :{TINY_FONT}{BLACK}Days in transit
@ -634,9 +642,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_TOGGLE_CARGO :{BLACK}Toggle graph of this cargo type
STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} 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_PRODUCED :Produced
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED :Transported 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 STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show detailed performance ratings
@ -4024,8 +4034,8 @@ STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Producti
STR_INDUSTRY_VIEW_PRODUCTION_LAST_MINUTE_TITLE :{BLACK}Production last minute: 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_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_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_CARGO_GRAPH :{BLACK}Cargo Graph
STR_INDUSTRY_VIEW_PRODUCTION_GRAPH_TOOLTIP :{BLACK}Shows the graph of industry production history 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_PRODUCTION_LEVEL :{BLACK}Production level: {YELLOW}{COMMA}%
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}The industry has announced imminent closure! STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}The industry has announced imminent closure!
@ -5001,6 +5011,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Flat lan
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land sloped in wrong direction STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land sloped in wrong direction
STR_ERROR_CAN_T_DO_THIS :{WHITE}Can't do this... STR_ERROR_CAN_T_DO_THIS :{WHITE}Can't do this...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Building must be demolished first STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Building must be demolished first
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... building is protected
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Can't clear this area... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Can't clear this area...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... site unsuitable STR_ERROR_SITE_UNSUITABLE :{WHITE}... site unsuitable
STR_ERROR_ALREADY_BUILT :{WHITE}... already built STR_ERROR_ALREADY_BUILT :{WHITE}... already built

View File

@ -5001,6 +5001,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Flat lan
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land sloped in wrong direction STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land sloped in wrong direction
STR_ERROR_CAN_T_DO_THIS :{WHITE}Can't do this... STR_ERROR_CAN_T_DO_THIS :{WHITE}Can't do this...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Building must be demolished first STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Building must be demolished first
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... building is protected
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Can't clear this area... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Can't clear this area...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... site unsuitable STR_ERROR_SITE_UNSUITABLE :{WHITE}... site unsuitable
STR_ERROR_ALREADY_BUILT :{WHITE}... already built STR_ERROR_ALREADY_BUILT :{WHITE}... already built

View File

@ -5001,6 +5001,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Tarvitaa
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Maa viettää väärään suuntaan. STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Maa viettää väärään suuntaan.
STR_ERROR_CAN_T_DO_THIS :{WHITE}Ei onnistu... STR_ERROR_CAN_T_DO_THIS :{WHITE}Ei onnistu...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Rakennus täytyy purkaa ensin. STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Rakennus täytyy purkaa ensin.
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}… rakennus on suojattu
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Aluetta ei voi tyhjentää... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Aluetta ei voi tyhjentää...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... maasto on sopimaton STR_ERROR_SITE_UNSUITABLE :{WHITE}... maasto on sopimaton
STR_ERROR_ALREADY_BUILT :{WHITE}... se on jo rakennettu STR_ERROR_ALREADY_BUILT :{WHITE}... se on jo rakennettu

View File

@ -5102,6 +5102,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Απαι
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Το έδαφος έχει λάθος κλίση STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Το έδαφος έχει λάθος κλίση
STR_ERROR_CAN_T_DO_THIS :{WHITE}Αυτό δεν γίνεται... STR_ERROR_CAN_T_DO_THIS :{WHITE}Αυτό δεν γίνεται...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Το κτίριο πρέπει πρώτα να κατεδαφιστεί STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Το κτίριο πρέπει πρώτα να κατεδαφιστεί
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... το κτίριο προστατεύεται
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Είναι αδύνατο να καθαριστεί αυτή η περιοχή... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Είναι αδύνατο να καθαριστεί αυτή η περιοχή...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... ακατάλληλη περιοχή STR_ERROR_SITE_UNSUITABLE :{WHITE}... ακατάλληλη περιοχή
STR_ERROR_ALREADY_BUILT :{WHITE}... ήδη κατασκευασμένο STR_ERROR_ALREADY_BUILT :{WHITE}... ήδη κατασκευασμένο

View File

@ -330,6 +330,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}év
STR_UNITS_PERIODS :{NUM}{NBSP}időszak STR_UNITS_PERIODS :{NUM}{NBSP}időszak
STR_LIST_SEPARATOR :,{SPACE} STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings # Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Szűrő kifejezés: STR_LIST_FILTER_TITLE :{BLACK}Szűrő kifejezés:

View File

@ -5387,6 +5387,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Wymagany
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Teren pochylony w złym kierunku STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Teren pochylony w złym kierunku
STR_ERROR_CAN_T_DO_THIS :{WHITE}Nie można tego zrobić... STR_ERROR_CAN_T_DO_THIS :{WHITE}Nie można tego zrobić...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Należy najpierw zburzyć budynek STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Należy najpierw zburzyć budynek
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... budynek jest chroniony
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Nie można wyczyścić terenu... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Nie można wyczyścić terenu...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... nieodpowiednie miejsce STR_ERROR_SITE_UNSUITABLE :{WHITE}... nieodpowiednie miejsce
STR_ERROR_ALREADY_BUILT :{WHITE}... już zbudowano STR_ERROR_ALREADY_BUILT :{WHITE}... już zbudowano

View File

@ -647,7 +647,7 @@ STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Alternar
# Company league window # Company league window
STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Classificação de Empresas STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Classificação de Empresas
STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} “{STRING}”
STR_COMPANY_LEAGUE_COMPANY_RANK :{YELLOW}#{NUM} STR_COMPANY_LEAGUE_COMPANY_RANK :{YELLOW}#{NUM}
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Engenheiro STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Engenheiro
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Gestor de Tráfego STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Gestor de Tráfego
@ -3441,20 +3441,20 @@ STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Mudar al
STR_GENERATION_WORLD :{WHITE}A Gerar Mundo... STR_GENERATION_WORLD :{WHITE}A Gerar Mundo...
STR_GENERATION_ABORT :{BLACK}Cancelar STR_GENERATION_ABORT :{BLACK}Cancelar
STR_GENERATION_ABORT_CAPTION :{WHITE}Cancelar criação do mundo STR_GENERATION_ABORT_CAPTION :{WHITE}Cancelar criação do mundo
STR_GENERATION_ABORT_MESSAGE :{YELLOW}Quer mesmo cancelar a criação? STR_GENERATION_ABORT_MESSAGE :{YELLOW}Quer mesmo cancelar o processo de geração?
STR_GENERATION_PROGRESS :{WHITE}{NUM}% completo STR_GENERATION_PROGRESS :{WHITE}{NUM}% completo
STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM}
STR_GENERATION_WORLD_GENERATION :{BLACK}A gerar mundo STR_GENERATION_WORLD_GENERATION :{BLACK}A gerar mundo
STR_GENERATION_LANDSCAPE_GENERATION :{BLACK}Geração de paisagem STR_GENERATION_LANDSCAPE_GENERATION :{BLACK}A gerar paisagem
STR_GENERATION_RIVER_GENERATION :{BLACK}A gerar rios STR_GENERATION_RIVER_GENERATION :{BLACK}A gerar rios
STR_GENERATION_CLEARING_TILES :{BLACK}A gerar zonas rochosas e montanhosas STR_GENERATION_CLEARING_TILES :{BLACK}A gerar zonas rochosas e montanhosas
STR_GENERATION_TOWN_GENERATION :{BLACK}Geração de localidades STR_GENERATION_TOWN_GENERATION :{BLACK}A gerar localidades
STR_GENERATION_INDUSTRY_GENERATION :{BLACK}Geração de indústrias STR_GENERATION_INDUSTRY_GENERATION :{BLACK}A gerar indústrias
STR_GENERATION_OBJECT_GENERATION :{BLACK}Geração inamovível STR_GENERATION_OBJECT_GENERATION :{BLACK}A gerar objetos
STR_GENERATION_TREE_GENERATION :{BLACK}A gerar árvores STR_GENERATION_TREE_GENERATION :{BLACK}A gerar árvores
STR_GENERATION_SETTINGUP_GAME :{BLACK}Definindo jogo STR_GENERATION_SETTINGUP_GAME :{BLACK}A configurar jogo
STR_GENERATION_PREPARING_TILELOOP :{BLACK}A preparar o terreno STR_GENERATION_PREPARING_TILELOOP :{BLACK}A preparar o terreno
STR_GENERATION_PREPARING_SCRIPT :{BLACK}Script a correr STR_GENERATION_PREPARING_SCRIPT :{BLACK}A correr script
STR_GENERATION_PREPARING_GAME :{BLACK}A preparar jogo STR_GENERATION_PREPARING_GAME :{BLACK}A preparar jogo
STR_TOWN_DATA_ERROR_LOAD_FAILED :{WHITE}Falha ao carregar dados da localidade STR_TOWN_DATA_ERROR_LOAD_FAILED :{WHITE}Falha ao carregar dados da localidade
@ -5002,6 +5002,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}É neces
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Terreno inclinado na direcção incorrecta STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Terreno inclinado na direcção incorrecta
STR_ERROR_CAN_T_DO_THIS :{WHITE}Não é possível fazer isto... STR_ERROR_CAN_T_DO_THIS :{WHITE}Não é possível fazer isto...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}O edifício deve ser demolido primeiro STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}O edifício deve ser demolido primeiro
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... o edifício está protegido
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Não é possível limpar esta área... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Não é possível limpar esta área...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... sítio inadequado STR_ERROR_SITE_UNSUITABLE :{WHITE}... sítio inadequado
STR_ERROR_ALREADY_BUILT :{WHITE}... já está construído STR_ERROR_ALREADY_BUILT :{WHITE}... já está construído

View File

@ -5188,6 +5188,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Необ
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Неверный уклон земли STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Неверный уклон земли
STR_ERROR_CAN_T_DO_THIS :{WHITE}Это невозможно... STR_ERROR_CAN_T_DO_THIS :{WHITE}Это невозможно...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Сначала снесите здания STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Сначала снесите здания
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... это здание защищено от изменений
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Невозможно расчистить данный участок... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Невозможно расчистить данный участок...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... неподходящее место STR_ERROR_SITE_UNSUITABLE :{WHITE}... неподходящее место
STR_ERROR_ALREADY_BUILT :{WHITE}... уже построено STR_ERROR_ALREADY_BUILT :{WHITE}... уже построено

View File

@ -5001,6 +5001,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}需要
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}地面斜坡方向不對 STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}地面斜坡方向不對
STR_ERROR_CAN_T_DO_THIS :{WHITE}不能執行以下動作... STR_ERROR_CAN_T_DO_THIS :{WHITE}不能執行以下動作...
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}必須先摧毀建築物 STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}必須先摧毀建築物
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}……建築物受到保護
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}不能清除這個地段... STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}不能清除這個地段...
STR_ERROR_SITE_UNSUITABLE :{WHITE}... 地點不適合 STR_ERROR_SITE_UNSUITABLE :{WHITE}... 地點不適合
STR_ERROR_ALREADY_BUILT :{WHITE}……經已建成 STR_ERROR_ALREADY_BUILT :{WHITE}……經已建成

View File

@ -8,6 +8,7 @@ add_files(
getoptdata.cpp getoptdata.cpp
getoptdata.h getoptdata.h
hashtable.hpp hashtable.hpp
history.cpp
history_func.hpp history_func.hpp
history_type.hpp history_type.hpp
lrucache.hpp lrucache.hpp

View File

@ -0,0 +1,71 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file history.cpp Implementation of functions for storing historical data. */
#ifndef HISTORY_CPP
#define HISTORY_CPP
#include "../stdafx.h"
#include "../core/bitmath_func.hpp"
#include "history_type.hpp"
#include "history_func.hpp"
#include "../safeguards.h"
static void UpdateValidHistory(ValidHistoryMask &valid_history, const HistoryRange &hr, uint cur_month)
{
if (cur_month % hr.total_division != 0) return;
if (hr.division != 1 && !HasBit(valid_history, hr.first - hr.division)) return;
SB(valid_history, hr.first, hr.records, GB(valid_history, hr.first, hr.records) << 1ULL | 1ULL);
}
/**
* Update mask of valid records.
* @param[in,out] valid_history Valid history records.
* @param age Current economy month.
*/
void UpdateValidHistory(ValidHistoryMask &valid_history, uint cur_month)
{
UpdateValidHistory(valid_history, HISTORY_MONTH, cur_month);
UpdateValidHistory(valid_history, HISTORY_QUARTER, cur_month);
UpdateValidHistory(valid_history, HISTORY_YEAR, cur_month);
}
static bool IsValidHistory(ValidHistoryMask valid_history, const HistoryRange &hr, uint age)
{
if (hr.hr == nullptr) {
if (age < hr.periods) {
uint slot = hr.first + age;
return HasBit(valid_history, slot);
}
} else {
if (age * hr.division < static_cast<uint>(hr.hr->periods - hr.division)) {
uint start = age * hr.division + ((TimerGameEconomy::month / hr.hr->division) % hr.division);
return IsValidHistory(valid_history, *hr.hr, start/* + hr.division - 1*/);
}
if (age < hr.periods) {
uint slot = hr.first + age - ((hr.hr->periods / hr.division) - 1);
return HasBit(valid_history, slot);
}
}
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

@ -11,16 +11,22 @@
#define HISTORY_FUNC_HPP #define HISTORY_FUNC_HPP
#include "../core/bitmath_func.hpp" #include "../core/bitmath_func.hpp"
#include "../core/math_func.hpp"
#include "../timer/timer_game_economy.h"
#include "history_type.hpp" #include "history_type.hpp"
void UpdateValidHistory(ValidHistoryMask &valid_history, uint cur_month);
bool IsValidHistory(ValidHistoryMask valid_history, uint period, uint age);
/** /**
* Update mask of valid history records. * Sum history data elements.
* @param[in,out] valid_history Valid history records. * @note The summation should prevent overflowing, and perform transformations relevant to the type of data.
* @tparam T type of history data element.
* @param history History elements to sum.
* @return Sum of history elements.
*/ */
inline void UpdateValidHistory(ValidHistoryMask &valid_history) template <typename T>
{ T SumHistory(typename std::span<const T> history);
SB(valid_history, LAST_MONTH, HISTORY_RECORDS - LAST_MONTH, GB(valid_history, LAST_MONTH, HISTORY_RECORDS - LAST_MONTH) << 1ULL | 1ULL);
}
/** /**
* Rotate history. * Rotate history.
@ -28,24 +34,105 @@ inline void UpdateValidHistory(ValidHistoryMask &valid_history)
* @param history Historical data to rotate. * @param history Historical data to rotate.
*/ */
template <typename T> template <typename T>
void RotateHistory(HistoryData<T> &history) void RotateHistory(HistoryData<T> &history, ValidHistoryMask valid_history, const HistoryRange &hr, uint cur_month)
{ {
std::rotate(std::rbegin(history), std::rbegin(history) + 1, std::rend(history)); if (cur_month % hr.total_division != 0) return;
history[THIS_MONTH] = {};
std::move_backward(std::next(std::begin(history), hr.first), std::next(std::begin(history), hr.last - 1), std::next(std::begin(history), hr.last));
if (hr.division == 1) {
history[hr.first] = history[hr.first - 1];
} else if (HasBit(valid_history, hr.first - hr.division)) {
auto first = std::next(std::begin(history), hr.first - hr.division);
auto last = std::next(first, hr.division);
history[hr.first] = SumHistory<T>(std::span{first, last});
}
}
template <typename T>
void RotateHistory(HistoryData<T> &history, ValidHistoryMask valid_history, uint cur_month)
{
RotateHistory(history, valid_history, HISTORY_MONTH, cur_month);
RotateHistory(history, valid_history, HISTORY_QUARTER, cur_month);
RotateHistory(history, valid_history, HISTORY_YEAR, cur_month);
history.front() = {};
}
/**
* 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;
}
template <typename T>
bool GetHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, const HistoryRange &hr, uint age, T &result)
{
if (hr.hr == nullptr) {
if (age < hr.periods) {
uint slot = hr.first + age;
result = history[slot];
return HasBit(valid_history, slot);
}
} else {
if (age * hr.division < static_cast<uint>(hr.hr->periods - hr.division)) {
bool is_valid = false;
std::array<T, HISTORY_MAX_DIVISION> tmp_result; // No need to clear as we fill every element we use.
uint start = age * hr.division + ((TimerGameEconomy::month / hr.hr->division) % hr.division);
for (auto i = start; i != start + hr.division; ++i) {
is_valid |= GetHistory(history, valid_history, *hr.hr, i, tmp_result[i - start]);
}
result = SumHistory<T>(std::span{std::begin(tmp_result), hr.division});
return is_valid;
}
if (age < hr.periods) {
uint slot = hr.first + age - ((hr.hr->periods / hr.division) - 1);
result = history[slot];
return HasBit(valid_history, slot);
}
}
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. * Fill some data with historical data.
* @param history Historical data to fill from. * @param history Historical data to fill from.
* @param valid_history Mask of valid history records. * @param valid_history Mask of valid history records.
* @param period Period (monthly, quarterly, yearly) to fill with.
* @param fillers Fillers to fill with history data. * @param fillers Fillers to fill with history data.
*/ */
template <uint N, typename T, typename... Tfillers> template <uint N, typename T, typename... Tfillers>
void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, Tfillers... fillers) void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, uint period, Tfillers... fillers)
{ {
T data{};
for (uint i = 0; i != N; ++i) { for (uint i = 0; i != N; ++i) {
if (HasBit(valid_history, N - i)) { if (GetHistory(history, valid_history, period, N - i - 1, data)) {
auto &data = history[N - i];
(fillers.Fill(i, data), ...); (fillers.Fill(i, data), ...);
} else { } else {
(fillers.MakeInvalid(i), ...); (fillers.MakeInvalid(i), ...);
@ -53,4 +140,22 @@ void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_histo
} }
} }
/**
* Fill some data with empty records.
* @param valid_history Mask of valid history records.
* @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, uint period, Tfillers... fillers)
{
for (uint i = 0; i != N; ++i) {
if (IsValidHistory(valid_history, period, N - i - 1)) {
(fillers.MakeZero(i), ...);
} else {
(fillers.MakeInvalid(i), ...);
}
}
}
#endif /* HISTORY_FUNC_HPP */ #endif /* HISTORY_FUNC_HPP */

View File

@ -10,7 +10,40 @@
#ifndef HISTORY_TYPE_HPP #ifndef HISTORY_TYPE_HPP
#define HISTORY_TYPE_HPP #define HISTORY_TYPE_HPP
static constexpr uint8_t HISTORY_RECORDS = 25; #include "../stdafx.h"
static constexpr uint8_t HISTORY_PERIODS = 24;
struct HistoryRange {
const HistoryRange *hr;
const uint8_t periods; ///< Number of periods for this range.
const uint8_t records; ///< Number of records needed for this range.
const uint8_t first; ///< Index of first element in history data.
const uint8_t last; ///< Index of last element in history data.
const uint8_t division; ///< Number of divisions of the previous history range.
const uint8_t total_division; ///< Number of divisions of the initial history range.
explicit constexpr HistoryRange(uint8_t periods) :
hr(nullptr), periods(periods), records(this->periods), first(1), last(this->first + this->records), division(1), total_division(1)
{
}
constexpr HistoryRange(const HistoryRange &hr, uint8_t division, uint8_t periods) :
hr(&hr), periods(periods), records(this->periods - ((hr.periods / division) - 1)), first(hr.last), last(this->first + this->records),
division(division), total_division(division * hr.total_division)
{
}
};
static constexpr HistoryRange HISTORY_MONTH{HISTORY_PERIODS};
static constexpr HistoryRange HISTORY_QUARTER{HISTORY_MONTH, 3, HISTORY_PERIODS};
static constexpr HistoryRange HISTORY_YEAR{HISTORY_QUARTER, 4, HISTORY_PERIODS};
/** Maximum number of divisions from previous history range. */
static constexpr uint8_t HISTORY_MAX_DIVISION = std::max({HISTORY_MONTH.division, HISTORY_QUARTER.division, HISTORY_YEAR.division});
/** Total number of records require for all history data. */
static constexpr uint8_t HISTORY_RECORDS = HISTORY_YEAR.last;
static constexpr uint8_t THIS_MONTH = 0; static constexpr uint8_t THIS_MONTH = 0;
static constexpr uint8_t LAST_MONTH = 1; static constexpr uint8_t LAST_MONTH = 1;

View File

@ -476,7 +476,7 @@ CommandCost GetErrorMessageFromLocationCallbackResult(uint16_t cb_res, std::span
/* If this error isn't for the local player then it won't be seen, so don't bother encoding anything. */ /* If this error isn't for the local player then it won't be seen, so don't bother encoding anything. */
if (IsLocalCompany()) { if (IsLocalCompany()) {
StringID stringid = GetGRFStringID(grffile->grfid, text_id); StringID stringid = GetGRFStringID(grffile->grfid, text_id);
auto params = GetGRFSringTextStackParameters(grffile, stringid, textstack); auto params = GetGRFStringTextStackParameters(grffile, stringid, textstack);
res.SetEncodedMessage(GetEncodedStringWithArgs(stringid, params)); res.SetEncodedMessage(GetEncodedStringWithArgs(stringid, params));
} }

View File

@ -973,7 +973,7 @@ static void HandleNewGRFStringControlCodes(std::string_view str, TextRefStack &s
* @param textstack Text parameter stack. * @param textstack Text parameter stack.
* @returns Parameters for GRF string. * @returns Parameters for GRF string.
*/ */
std::vector<StringParameter> GetGRFSringTextStackParameters(const GRFFile *grffile, StringID stringid, std::span<const int32_t> textstack) std::vector<StringParameter> GetGRFStringTextStackParameters(const GRFFile *grffile, StringID stringid, std::span<const int32_t> textstack)
{ {
if (stringid == INVALID_STRING_ID) return {}; if (stringid == INVALID_STRING_ID) return {};
@ -998,6 +998,6 @@ std::vector<StringParameter> GetGRFSringTextStackParameters(const GRFFile *grffi
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, std::span<const int32_t> textstack) std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, std::span<const int32_t> textstack)
{ {
StringID stringid = GetGRFStringID(grffile->grfid, grfstringid); StringID stringid = GetGRFStringID(grffile->grfid, grfstringid);
auto params = GetGRFSringTextStackParameters(grffile, stringid, textstack); auto params = GetGRFStringTextStackParameters(grffile, stringid, textstack);
return GetStringWithArgs(stringid, params); return GetStringWithArgs(stringid, params);
} }

View File

@ -28,7 +28,7 @@ void AddGRFTextToList(GRFTextWrapper &list, std::string_view text_to_add);
bool CheckGrfLangID(uint8_t lang_id, uint8_t grf_version); bool CheckGrfLangID(uint8_t lang_id, uint8_t grf_version);
std::vector<StringParameter> GetGRFSringTextStackParameters(const struct GRFFile *grffile, StringID stringid, std::span<const int32_t> textstack); std::vector<StringParameter> GetGRFStringTextStackParameters(const struct GRFFile *grffile, StringID stringid, std::span<const int32_t> textstack);
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, std::span<const int32_t> textstack); std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, std::span<const int32_t> textstack);
#endif /* NEWGRF_TEXT_H */ #endif /* NEWGRF_TEXT_H */

View File

@ -19,12 +19,50 @@
static OldPersistentStorage _old_ind_persistent_storage; 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> { class SlIndustryAccepted : public VectorSaveLoadHandler<SlIndustryAccepted, Industry, Industry::AcceptedCargo, INDUSTRY_NUM_INPUTS> {
public: public:
static inline const SaveLoad description[] = { static inline const SaveLoad description[] = {
SLE_VAR(Industry::AcceptedCargo, cargo, SLE_UINT8), SLE_VAR(Industry::AcceptedCargo, cargo, SLE_UINT8),
SLE_VAR(Industry::AcceptedCargo, waiting, SLE_UINT16), SLE_VAR(Industry::AcceptedCargo, waiting, SLE_UINT16),
SLE_VAR(Industry::AcceptedCargo, last_accepted, SLE_INT32), 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; 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) { if (i->location.tile != 0) {
/* Copy data from old fixed arrays to industry. */ /* 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)); std::copy(std::begin(_old_produced), std::end(_old_produced), std::back_inserter(i->produced));
i->town = RemapTown(i->location.tile); 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_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_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 SL_MAX_VERSION, ///< Highest possible saveload version
}; };

View File

@ -130,6 +130,13 @@ bool ScriptInstance::LoadCompatibilityScripts(Subdirectory dir, std::span<const
ScriptLog::Info(fmt::format("Downgrading API to be compatible with version {}", this->api_version)); ScriptLog::Info(fmt::format("Downgrading API to be compatible with version {}", this->api_version));
HSQUIRRELVM vm = this->engine->GetVM();
sq_pushroottable(vm);
sq_pushstring(vm, "CompatScriptRootTable");
sq_pushroottable(vm);
sq_newslot(vm, -3, SQFalse);
sq_pop(vm, 1);
/* Downgrade the API till we are the same version as the script. The last /* Downgrade the API till we are the same version as the script. The last
* entry in the list is always the current version, so skip that one. */ * entry in the list is always the current version, so skip that one. */
for (auto it = std::rbegin(api_versions) + 1; it != std::rend(api_versions); ++it) { for (auto it = std::rbegin(api_versions) + 1; it != std::rend(api_versions); ++it) {
@ -138,6 +145,11 @@ bool ScriptInstance::LoadCompatibilityScripts(Subdirectory dir, std::span<const
if (*it == this->api_version) break; if (*it == this->api_version) break;
} }
sq_pushroottable(vm);
sq_pushstring(vm, "CompatScriptRootTable");
sq_deleteslot(vm, -2, SQFalse);
sq_pop(vm, 1);
return true; return true;
} }

View File

@ -607,28 +607,25 @@ bool ConvertHexToBytes(std::string_view hex, std::span<uint8_t> bytes)
/** String iterator using ICU as a backend. */ /** String iterator using ICU as a backend. */
class IcuStringIterator : public StringIterator class IcuStringIterator : public StringIterator
{ {
icu::BreakIterator *char_itr; ///< ICU iterator for characters. std::unique_ptr<icu::BreakIterator> char_itr; ///< ICU iterator for characters.
icu::BreakIterator *word_itr; ///< ICU iterator for words. std::unique_ptr<icu::BreakIterator> word_itr; ///< ICU iterator for words.
std::vector<UChar> utf16_str; ///< UTF-16 copy of the string. std::vector<UChar> utf16_str; ///< UTF-16 copy of the string.
std::vector<size_t> utf16_to_utf8; ///< Mapping from UTF-16 code point position to index in the UTF-8 source string. std::vector<size_t> utf16_to_utf8; ///< Mapping from UTF-16 code point position to index in the UTF-8 source string.
public: public:
IcuStringIterator() : char_itr(nullptr), word_itr(nullptr) IcuStringIterator()
{ {
UErrorCode status = U_ZERO_ERROR; UErrorCode status = U_ZERO_ERROR;
this->char_itr = icu::BreakIterator::createCharacterInstance(icu::Locale(_current_language != nullptr ? _current_language->isocode : "en"), status); auto locale = icu::Locale(_current_language != nullptr ? _current_language->isocode : "en");
this->word_itr = icu::BreakIterator::createWordInstance(icu::Locale(_current_language != nullptr ? _current_language->isocode : "en"), status); this->char_itr.reset(icu::BreakIterator::createCharacterInstance(locale, status));
this->word_itr.reset(icu::BreakIterator::createWordInstance(locale, status));
this->utf16_str.push_back('\0'); this->utf16_str.push_back('\0');
this->utf16_to_utf8.push_back(0); this->utf16_to_utf8.push_back(0);
} }
~IcuStringIterator() override ~IcuStringIterator() override = default;
{
delete this->char_itr;
delete this->word_itr;
}
void SetString(std::string_view s) override void SetString(std::string_view s) override
{ {

View File

@ -3,6 +3,7 @@ add_test_files(
bitmath_func.cpp bitmath_func.cpp
enum_over_optimisation.cpp enum_over_optimisation.cpp
flatset_type.cpp flatset_type.cpp
history_func.cpp
landscape_partial_pixel_z.cpp landscape_partial_pixel_z.cpp
math_func.cpp math_func.cpp
mock_environment.h mock_environment.h

View File

@ -0,0 +1,87 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file history_func.cpp Test functionality for misc/history_func. */
#include "../stdafx.h"
#include "../3rdparty/catch2/catch.hpp"
#include "../misc/history_type.hpp"
#include "../misc/history_func.hpp"
#include "../safeguards.h"
template <>
uint16_t SumHistory(std::span<const uint16_t> history)
{
uint32_t total = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const uint16_t &value) { return r + value; });
return ClampTo<uint16_t>(total);
}
/**
* Helper to get history records and return the value, instead returning its validity.
* @param history History data to extract from.
* @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, uint period, uint age)
{
T 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;
}
TEST_CASE("History Rotation and Reporting tests")
{
HistoryData<uint16_t> history{};
uint64_t valid_history = 0;
/* Fill the history with decreasing data points for 24 years of history. This ensures that no data period should
* contain the same value as another period. */
uint16_t i = 12 * HISTORY_PERIODS;
for (uint date = 1; date <= 12 * HISTORY_PERIODS; ++date, --i) {
history[THIS_MONTH] = i;
RotateHistory(history, valid_history, date % 12);
}
/* With the decreasing sequence, the expected value is triangle number (x*x+n)/2 and the square of the total divisions.
* for quarters: 1 + 2 + 3 = 6, 4 + 5 + 6 = 15, 7 + 8 + 9 = 24, 10 + 11 + 12 = 33
* 13 + 14 + 15 = 42, 16 + 17 + 18 = 51, 19 + 20 + 21 = 60, 22 + 23 + 24 = 69...
* for years: 6 + 15 + 24 + 33 = 78, 42 + 51 + 60 + 69 = 222...
*/
for (uint j = 0; j < HISTORY_PERIODS; ++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, 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, 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));
}

View File

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

View File

@ -37,6 +37,8 @@ public:
static Date date; ///< Current date in days (day counter). static Date date; ///< Current date in days (day counter).
static DateFract date_fract; ///< Fractional part of the day. 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 YearMonthDay ConvertDateToYMD(Date date);
static Date ConvertYMDToDate(Year year, Month month, Day day); static Date ConvertYMDToDate(Year year, Month month, Day day);
static void SetDate(Date date, DateFract fract); static void SetDate(Date date, DateFract fract);

View File

@ -710,7 +710,7 @@ static void TileLoop_Town(TileIndex tile)
static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlags flags) static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlags flags)
{ {
if (flags.Test(DoCommandFlag::Auto)) return CommandCost(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); if (flags.Test(DoCommandFlag::Auto)) return CommandCost(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
if (!CanDeleteHouse(tile)) return CMD_ERROR; if (!CanDeleteHouse(tile)) return CommandCost(STR_ERROR_BUILDING_IS_PROTECTED);
const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
@ -724,7 +724,7 @@ static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlags flags)
if (!_cheats.magic_bulldozer.value && !flags.Test(DoCommandFlag::NoTestTownRating)) { if (!_cheats.magic_bulldozer.value && !flags.Test(DoCommandFlag::NoTestTownRating)) {
/* NewGRFs can add indestructible houses. */ /* NewGRFs can add indestructible houses. */
if (rating > RATING_MAXIMUM) { if (rating > RATING_MAXIMUM) {
return CommandCost(CMD_ERROR); return CommandCost(STR_ERROR_BUILDING_IS_PROTECTED);
} }
/* If town authority controls removal, check the company's rating. */ /* If town authority controls removal, check the company's rating. */
if (rating > t->ratings[_current_company] && _settings_game.difficulty.town_council_tolerance != TOWN_COUNCIL_PERMISSIVE) { if (rating > t->ratings[_current_company] && _settings_game.difficulty.town_council_tolerance != TOWN_COUNCIL_PERMISSIVE) {

View File

@ -118,7 +118,7 @@ std::optional<std::string_view> VideoDriver_SDL_OpenGL::AllocateContext()
} }
this->gl_context = SDL_GL_CreateContext(this->sdl_window); this->gl_context = SDL_GL_CreateContext(this->sdl_window);
if (this->gl_context == nullptr) return "SDL2: Can't active GL context"; if (this->gl_context == nullptr) return "SDL2: Can't activate GL context";
ToggleVsync(_video_vsync); ToggleVsync(_video_vsync);

View File

@ -1541,7 +1541,7 @@ std::optional<std::string_view> VideoDriver_Win32OpenGL::AllocateContext()
rc = wglCreateContext(this->dc); rc = wglCreateContext(this->dc);
if (rc == nullptr) return "Can't create OpenGL context"; if (rc == nullptr) return "Can't create OpenGL context";
} }
if (!wglMakeCurrent(this->dc, rc)) return "Can't active GL context"; if (!wglMakeCurrent(this->dc, rc)) return "Can't activate GL context";
this->ToggleVsync(_video_vsync); this->ToggleVsync(_video_vsync);

View File

@ -37,6 +37,7 @@ enum GraphWidgets : WidgetID {
WID_GRAPH_MATRIX_SCROLLBAR,///< Cargo list scrollbar. WID_GRAPH_MATRIX_SCROLLBAR,///< Cargo list scrollbar.
WID_GRAPH_RANGE_MATRIX, ///< Range list. WID_GRAPH_RANGE_MATRIX, ///< Range list.
WID_GRAPH_SCALE_MATRIX, ///< Horizontal axis scale list.
WID_PHG_DETAILED_PERFORMANCE, ///< Detailed performance. WID_PHG_DETAILED_PERFORMANCE, ///< Detailed performance.
}; };