1
0
Fork 0

Compare commits

...

9 Commits

Author SHA1 Message Date
Peter Nelson 7aa7c2e85b
Merge b9eac1ee78 into b82ffa3542 2025-07-20 22:00:06 +00:00
Peter Nelson b82ffa3542
Codechange: Decouple glyph map from SpriteFontCache instances. (#14449)
This makes the map independent from the SpriteFontCache instances.
2025-07-20 22:58:43 +01:00
Peter Nelson 8e2df7809b
Codechange: Add distinct type to hold pixel drawing colour. (#14457)
This is used for individual pixels as well as line drawing.
2025-07-20 22:57:55 +01:00
Jonathan G Rennison 821784004d Fix: [Linkgraph] Incorrect NodeID to StationID conversion for EraseFlows 2025-07-20 16:07:11 +02:00
Jonathan G Rennison f0447d59d4 Codechange: Use StationID as StationIDStack Titem type 2025-07-20 16:06:03 +02:00
Jonathan G Rennison cbdd358ae8 Codechange: Allow SmallStack Titem type to be non-structural 2025-07-20 16:06:03 +02:00
Peter Nelson b9eac1ee78
Codechange: Use StrongType and StrongBitSet for CargoType(s). 2025-06-28 21:52:39 +01:00
Peter Nelson 329a2da122
Codechange: Add StrongBitSet helper to simplify making a bitset from a StrongType. 2025-06-28 21:50:56 +01:00
Peter Nelson 98430f99d1
Codechange: Add parameterless Flip() method to BaseBitSet.
This allows flipping all valid bits.
2025-06-28 21:50:56 +01:00
120 changed files with 733 additions and 684 deletions

View File

@ -117,12 +117,12 @@ static inline std::pair<CargoType, uint16_t> GetVehicleDefaultCapacity(EngineID
static inline CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type) static inline CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type)
{ {
const Engine *e = Engine::Get(engine); const Engine *e = Engine::Get(engine);
if (!e->CanCarryCargo()) return 0; if (!e->CanCarryCargo()) return {};
CargoTypes cargoes = e->info.refit_mask; CargoTypes cargoes = e->info.refit_mask;
if (include_initial_cargo_type) { if (include_initial_cargo_type) {
SetBit(cargoes, e->GetDefaultCargoType()); cargoes.Set(e->GetDefaultCargoType());
} }
return cargoes; return cargoes;
@ -165,11 +165,11 @@ CargoArray GetCapacityOfArticulatedParts(EngineID engine)
*/ */
CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine) CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine)
{ {
CargoTypes cargoes = 0; CargoTypes cargoes{};
const Engine *e = Engine::Get(engine); const Engine *e = Engine::Get(engine);
if (auto [cargo, cap] = GetVehicleDefaultCapacity(engine); IsValidCargoType(cargo) && cap > 0) { if (auto [cargo, cap] = GetVehicleDefaultCapacity(engine); IsValidCargoType(cargo) && cap > 0) {
SetBit(cargoes, cargo); cargoes.Set(cargo);
} }
if (!e->IsGroundVehicle()) return cargoes; if (!e->IsGroundVehicle()) return cargoes;
@ -181,7 +181,7 @@ CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine)
if (artic_engine == EngineID::Invalid()) break; if (artic_engine == EngineID::Invalid()) break;
if (auto [cargo, cap] = GetVehicleDefaultCapacity(artic_engine); IsValidCargoType(cargo) && cap > 0) { if (auto [cargo, cap] = GetVehicleDefaultCapacity(artic_engine); IsValidCargoType(cargo) && cap > 0) {
SetBit(cargoes, cargo); cargoes.Set(cargo);
} }
} }
@ -224,7 +224,7 @@ void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type,
const Engine *e = Engine::Get(engine); const Engine *e = Engine::Get(engine);
CargoTypes veh_cargoes = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type); CargoTypes veh_cargoes = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type);
*union_mask = veh_cargoes; *union_mask = veh_cargoes;
*intersection_mask = (veh_cargoes != 0) ? veh_cargoes : ALL_CARGOTYPES; *intersection_mask = veh_cargoes.Any() ? veh_cargoes : ALL_CARGOTYPES;
if (!e->IsGroundVehicle()) return; if (!e->IsGroundVehicle()) return;
if (!e->info.callback_mask.Test(VehicleCallbackMask::ArticEngine)) return; if (!e->info.callback_mask.Test(VehicleCallbackMask::ArticEngine)) return;
@ -234,8 +234,8 @@ void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type,
if (artic_engine == EngineID::Invalid()) break; if (artic_engine == EngineID::Invalid()) break;
veh_cargoes = GetAvailableVehicleCargoTypes(artic_engine, include_initial_cargo_type); veh_cargoes = GetAvailableVehicleCargoTypes(artic_engine, include_initial_cargo_type);
*union_mask |= veh_cargoes; union_mask->Set(veh_cargoes);
if (veh_cargoes != 0) *intersection_mask &= veh_cargoes; if (veh_cargoes.Any()) *intersection_mask = *intersection_mask & veh_cargoes;
} }
} }
@ -261,12 +261,12 @@ CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial
*/ */
CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoType *cargo_type) CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoType *cargo_type)
{ {
CargoTypes cargoes = 0; CargoTypes cargoes{};
CargoType first_cargo = INVALID_CARGO; CargoType first_cargo = INVALID_CARGO;
do { do {
if (IsValidCargoType(v->cargo_type) && v->GetEngine()->CanCarryCargo()) { if (IsValidCargoType(v->cargo_type) && v->GetEngine()->CanCarryCargo()) {
SetBit(cargoes, v->cargo_type); cargoes.Set(v->cargo_type);
if (!IsValidCargoType(first_cargo)) first_cargo = v->cargo_type; if (!IsValidCargoType(first_cargo)) first_cargo = v->cargo_type;
if (first_cargo != v->cargo_type) { if (first_cargo != v->cargo_type) {
if (cargo_type != nullptr) { if (cargo_type != nullptr) {
@ -299,24 +299,24 @@ void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection); GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection);
CargoArray purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type); CargoArray purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type);
CargoTypes real_refit_union = 0; CargoTypes real_refit_union{};
CargoTypes real_refit_intersection = ALL_CARGOTYPES; CargoTypes real_refit_intersection = ALL_CARGOTYPES;
CargoTypes real_default_cargoes = 0; CargoTypes real_default_cargoes{};
do { do {
CargoTypes refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true); CargoTypes refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true);
real_refit_union |= refit_mask; real_refit_union.Set(refit_mask);
if (refit_mask != 0) real_refit_intersection &= refit_mask; if (refit_mask.Any()) real_refit_intersection = real_refit_intersection & refit_mask;
assert(v->cargo_type < NUM_CARGO); assert(v->cargo_type < NUM_CARGO);
if (v->cargo_cap > 0) SetBit(real_default_cargoes, v->cargo_type); if (v->cargo_cap > 0) real_default_cargoes.Set(v->cargo_type);
v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr;
} while (v != nullptr); } while (v != nullptr);
/* Check whether the vehicle carries more cargoes than expected */ /* Check whether the vehicle carries more cargoes than expected */
bool carries_more = false; bool carries_more = false;
for (CargoType cargo_type : SetCargoBitIterator(real_default_cargoes)) { for (CargoType cargo_type : real_default_cargoes) {
if (purchase_default_capacity[cargo_type] == 0) { if (purchase_default_capacity[cargo_type] == 0) {
carries_more = true; carries_more = true;
break; break;

View File

@ -47,7 +47,7 @@ static bool EnginesHaveCargoInCommon(EngineID engine_a, EngineID engine_b)
{ {
CargoTypes available_cargoes_a = GetUnionOfArticulatedRefitMasks(engine_a, true); CargoTypes available_cargoes_a = GetUnionOfArticulatedRefitMasks(engine_a, true);
CargoTypes available_cargoes_b = GetUnionOfArticulatedRefitMasks(engine_b, true); CargoTypes available_cargoes_b = GetUnionOfArticulatedRefitMasks(engine_b, true);
return (available_cargoes_a == 0 || available_cargoes_b == 0 || (available_cargoes_a & available_cargoes_b) != 0); return available_cargoes_a.None() || available_cargoes_b.None() || available_cargoes_a.Any(available_cargoes_b);
} }
/** /**
@ -189,8 +189,8 @@ static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, EngineID engine_ty
if (!o.IsRefit() || o.IsAutoRefit()) continue; if (!o.IsRefit() || o.IsAutoRefit()) continue;
CargoType cargo_type = o.GetRefitCargo(); CargoType cargo_type = o.GetRefitCargo();
if (!HasBit(union_refit_mask_a, cargo_type)) continue; if (!union_refit_mask_a.Test(cargo_type)) continue;
if (!HasBit(union_refit_mask_b, cargo_type)) return false; if (!union_refit_mask_b.Test(cargo_type)) return false;
} }
return true; return true;
@ -213,7 +213,7 @@ static int GetIncompatibleRefitOrderIdForAutoreplace(const Vehicle *v, EngineID
for (VehicleOrderID i = 0; i < orders->GetNumOrders(); i++) { for (VehicleOrderID i = 0; i < orders->GetNumOrders(); i++) {
const Order *o = orders->GetOrderAt(i); const Order *o = orders->GetOrderAt(i);
if (!o->IsRefit()) continue; if (!o->IsRefit()) continue;
if (!HasBit(union_refit_mask, o->GetRefitCargo())) return i; if (!union_refit_mask.Test(o->GetRefitCargo())) return i;
} }
return -1; return -1;
@ -233,11 +233,11 @@ static CargoType GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, boo
CargoTypes available_cargo_types, union_mask; CargoTypes available_cargo_types, union_mask;
GetArticulatedRefitMasks(engine_type, true, &union_mask, &available_cargo_types); GetArticulatedRefitMasks(engine_type, true, &union_mask, &available_cargo_types);
if (union_mask == 0) return CARGO_NO_REFIT; // Don't try to refit an engine with no cargo capacity if (union_mask.None()) return CARGO_NO_REFIT; // Don't try to refit an engine with no cargo capacity
CargoType cargo_type; CargoType cargo_type;
CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type); CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type);
if (!HasAtMostOneBit(cargo_mask)) { if (!HasAtMostOneBit(cargo_mask.base())) {
CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(engine_type); CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(engine_type);
if ((cargo_mask & new_engine_default_cargoes) == cargo_mask) { if ((cargo_mask & new_engine_default_cargoes) == cargo_mask) {
return CARGO_NO_REFIT; // engine_type is already a mixed cargo type which matches the incoming vehicle by default, no refit required return CARGO_NO_REFIT; // engine_type is already a mixed cargo type which matches the incoming vehicle by default, no refit required
@ -257,12 +257,12 @@ static CargoType GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, boo
for (v = v->First(); v != nullptr; v = v->Next()) { for (v = v->First(); v != nullptr; v = v->Next()) {
if (!v->GetEngine()->CanCarryCargo()) continue; if (!v->GetEngine()->CanCarryCargo()) continue;
/* Now we found a cargo type being carried on the train and we will see if it is possible to carry to this one */ /* Now we found a cargo type being carried on the train and we will see if it is possible to carry to this one */
if (HasBit(available_cargo_types, v->cargo_type)) return v->cargo_type; if (available_cargo_types.Test(v->cargo_type)) return v->cargo_type;
} }
return CARGO_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one return CARGO_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one
} else { } else {
if (!HasBit(available_cargo_types, cargo_type)) return INVALID_CARGO; // We can't refit the vehicle to carry the cargo we want if (!available_cargo_types.Test(cargo_type)) return INVALID_CARGO; // We can't refit the vehicle to carry the cargo we want
if (part_of_chain && !VerifyAutoreplaceRefitForOrders(v, engine_type)) return INVALID_CARGO; // Some refit orders lose their effect if (part_of_chain && !VerifyAutoreplaceRefitForOrders(v, engine_type)) return INVALID_CARGO; // Some refit orders lose their effect

View File

@ -321,19 +321,19 @@ void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height,
Debug(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal); Debug(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal);
} }
void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8_t colour) void Blitter_32bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
{ {
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour); *((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour.p);
/* Set the colour in the anim-buffer too, if we are rendering to the screen */ /* Set the colour in the anim-buffer too, if we are rendering to the screen */
if (_screen_disable_anim) return; if (_screen_disable_anim) return;
this->anim_buf[this->ScreenToAnimOffset((uint32_t *)video) + x + y * this->anim_buf_pitch] = colour | (DEFAULT_BRIGHTNESS << 8); this->anim_buf[this->ScreenToAnimOffset((uint32_t *)video) + x + y * this->anim_buf_pitch] = colour.p | (DEFAULT_BRIGHTNESS << 8);
} }
void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
{ {
const Colour c = LookupColourInPalette(colour); const Colour c = LookupColourInPalette(colour.p);
if (_screen_disable_anim) { if (_screen_disable_anim) {
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) { this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
@ -341,7 +341,7 @@ void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
}); });
} else { } else {
uint16_t * const offset_anim_buf = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)video); uint16_t * const offset_anim_buf = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)video);
const uint16_t anim_colour = colour | (DEFAULT_BRIGHTNESS << 8); const uint16_t anim_colour = colour.p | (DEFAULT_BRIGHTNESS << 8);
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) { this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
*((Colour *)video + x + y * _screen.pitch) = c; *((Colour *)video + x + y * _screen.pitch) = c;
offset_anim_buf[x + y * this->anim_buf_pitch] = anim_colour; offset_anim_buf[x + y * this->anim_buf_pitch] = anim_colour;
@ -349,7 +349,7 @@ void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
} }
} }
void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8_t colour) void Blitter_32bppAnim::DrawRect(void *video, int width, int height, PixelColour colour)
{ {
if (_screen_disable_anim) { if (_screen_disable_anim) {
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */ /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
@ -357,7 +357,7 @@ void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8_t col
return; return;
} }
Colour colour32 = LookupColourInPalette(colour); Colour colour32 = LookupColourInPalette(colour.p);
uint16_t *anim_line = this->ScreenToAnimOffset((uint32_t *)video) + this->anim_buf; uint16_t *anim_line = this->ScreenToAnimOffset((uint32_t *)video) + this->anim_buf;
do { do {
@ -367,7 +367,7 @@ void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8_t col
for (int i = width; i > 0; i--) { for (int i = width; i > 0; i--) {
*dst = colour32; *dst = colour32;
/* Set the colour in the anim-buffer too */ /* Set the colour in the anim-buffer too */
*anim = colour | (DEFAULT_BRIGHTNESS << 8); *anim = colour.p | (DEFAULT_BRIGHTNESS << 8);
dst++; dst++;
anim++; anim++;
} }

View File

@ -34,9 +34,9 @@ public:
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override; void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
void SetPixel(void *video, int x, int y, uint8_t colour) override; void SetPixel(void *video, int x, int y, PixelColour colour) override;
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) override; void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash) override;
void DrawRect(void *video, int width, int height, uint8_t colour) override; void DrawRect(void *video, int width, int height, PixelColour colour) override;
void CopyFromBuffer(void *video, const void *src, int width, int height) override; void CopyFromBuffer(void *video, const void *src, int width, int height) override;
void CopyToBuffer(const void *video, void *dst, int width, int height) override; void CopyToBuffer(const void *video, void *dst, int width, int height) override;
void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override; void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override;

View File

@ -18,22 +18,22 @@ void *Blitter_32bppBase::MoveTo(void *video, int x, int y)
return (uint32_t *)video + x + y * _screen.pitch; return (uint32_t *)video + x + y * _screen.pitch;
} }
void Blitter_32bppBase::SetPixel(void *video, int x, int y, uint8_t colour) void Blitter_32bppBase::SetPixel(void *video, int x, int y, PixelColour colour)
{ {
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour); *((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour.p);
} }
void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
{ {
const Colour c = LookupColourInPalette(colour); const Colour c = LookupColourInPalette(colour.p);
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) { this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
*((Colour *)video + x + y * _screen.pitch) = c; *((Colour *)video + x + y * _screen.pitch) = c;
}); });
} }
void Blitter_32bppBase::DrawRect(void *video, int width, int height, uint8_t colour) void Blitter_32bppBase::DrawRect(void *video, int width, int height, PixelColour colour)
{ {
Colour colour32 = LookupColourInPalette(colour); Colour colour32 = LookupColourInPalette(colour.p);
do { do {
Colour *dst = (Colour *)video; Colour *dst = (Colour *)video;

View File

@ -19,9 +19,9 @@ class Blitter_32bppBase : public Blitter {
public: public:
uint8_t GetScreenDepth() override { return 32; } uint8_t GetScreenDepth() override { return 32; }
void *MoveTo(void *video, int x, int y) override; void *MoveTo(void *video, int x, int y) override;
void SetPixel(void *video, int x, int y, uint8_t colour) override; void SetPixel(void *video, int x, int y, PixelColour colour) override;
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) override; void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash) override;
void DrawRect(void *video, int width, int height, uint8_t colour) override; void DrawRect(void *video, int width, int height, PixelColour colour) override;
void CopyFromBuffer(void *video, const void *src, int width, int height) override; void CopyFromBuffer(void *video, const void *src, int width, int height) override;
void CopyToBuffer(const void *video, void *dst, int width, int height) override; void CopyToBuffer(const void *video, void *dst, int width, int height) override;
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override; void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;

View File

@ -27,7 +27,7 @@ static FBlitter_40bppAnim iFBlitter_40bppAnim;
static const Colour _black_colour(0, 0, 0); static const Colour _black_colour(0, 0, 0);
void Blitter_40bppAnim::SetPixel(void *video, int x, int y, uint8_t colour) void Blitter_40bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
{ {
if (_screen_disable_anim) { if (_screen_disable_anim) {
Blitter_32bppOptimized::SetPixel(video, x, y, colour); Blitter_32bppOptimized::SetPixel(video, x, y, colour);
@ -35,11 +35,11 @@ void Blitter_40bppAnim::SetPixel(void *video, int x, int y, uint8_t colour)
size_t y_offset = static_cast<size_t>(y) * _screen.pitch; size_t y_offset = static_cast<size_t>(y) * _screen.pitch;
*((Colour *)video + x + y_offset) = _black_colour; *((Colour *)video + x + y_offset) = _black_colour;
VideoDriver::GetInstance()->GetAnimBuffer()[((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + x + y_offset] = colour; VideoDriver::GetInstance()->GetAnimBuffer()[((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + x + y_offset] = colour.p;
} }
} }
void Blitter_40bppAnim::DrawRect(void *video, int width, int height, uint8_t colour) void Blitter_40bppAnim::DrawRect(void *video, int width, int height, PixelColour colour)
{ {
if (_screen_disable_anim) { if (_screen_disable_anim) {
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */ /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
@ -56,7 +56,7 @@ void Blitter_40bppAnim::DrawRect(void *video, int width, int height, uint8_t col
for (int i = width; i > 0; i--) { for (int i = width; i > 0; i--) {
*dst = _black_colour; *dst = _black_colour;
*anim = colour; *anim = colour.p;
dst++; dst++;
anim++; anim++;
} }
@ -65,7 +65,7 @@ void Blitter_40bppAnim::DrawRect(void *video, int width, int height, uint8_t col
} while (--height); } while (--height);
} }
void Blitter_40bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) void Blitter_40bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
{ {
if (_screen_disable_anim) { if (_screen_disable_anim) {
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */ /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
@ -78,7 +78,7 @@ void Blitter_40bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) { this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
*((Colour *)video + x + y * _screen.pitch) = _black_colour; *((Colour *)video + x + y * _screen.pitch) = _black_colour;
*(anim + x + y * _screen.pitch) = colour; *(anim + x + y * _screen.pitch) = colour.p;
}); });
} }

View File

@ -18,9 +18,9 @@
class Blitter_40bppAnim : public Blitter_32bppOptimized { class Blitter_40bppAnim : public Blitter_32bppOptimized {
public: public:
void SetPixel(void *video, int x, int y, uint8_t colour) override; void SetPixel(void *video, int x, int y, PixelColour colour) override;
void DrawRect(void *video, int width, int height, uint8_t colour) override; void DrawRect(void *video, int width, int height, PixelColour colour) override;
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) override; void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash) override;
void CopyFromBuffer(void *video, const void *src, int width, int height) override; void CopyFromBuffer(void *video, const void *src, int width, int height) override;
void CopyToBuffer(const void *video, void *dst, int width, int height) override; void CopyToBuffer(const void *video, void *dst, int width, int height) override;
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override; void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;

View File

@ -29,23 +29,23 @@ void *Blitter_8bppBase::MoveTo(void *video, int x, int y)
return (uint8_t *)video + x + y * _screen.pitch; return (uint8_t *)video + x + y * _screen.pitch;
} }
void Blitter_8bppBase::SetPixel(void *video, int x, int y, uint8_t colour) void Blitter_8bppBase::SetPixel(void *video, int x, int y, PixelColour colour)
{ {
*((uint8_t *)video + x + y * _screen.pitch) = colour; *((uint8_t *)video + x + y * _screen.pitch) = colour.p;
} }
void Blitter_8bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) void Blitter_8bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
{ {
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) { this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
*((uint8_t *)video + x + y * _screen.pitch) = colour; *((uint8_t *)video + x + y * _screen.pitch) = colour.p;
}); });
} }
void Blitter_8bppBase::DrawRect(void *video, int width, int height, uint8_t colour) void Blitter_8bppBase::DrawRect(void *video, int width, int height, PixelColour colour)
{ {
std::byte *p = static_cast<std::byte *>(video); std::byte *p = static_cast<std::byte *>(video);
do { do {
std::fill_n(p, width, static_cast<std::byte>(colour)); std::fill_n(p, width, static_cast<std::byte>(colour.p));
p += _screen.pitch; p += _screen.pitch;
} while (--height); } while (--height);
} }

View File

@ -18,9 +18,9 @@ public:
uint8_t GetScreenDepth() override { return 8; } uint8_t GetScreenDepth() override { return 8; }
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override; void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
void *MoveTo(void *video, int x, int y) override; void *MoveTo(void *video, int x, int y) override;
void SetPixel(void *video, int x, int y, uint8_t colour) override; void SetPixel(void *video, int x, int y, PixelColour colour) override;
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) override; void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash) override;
void DrawRect(void *video, int width, int height, uint8_t colour) override; void DrawRect(void *video, int width, int height, PixelColour colour) override;
void CopyFromBuffer(void *video, const void *src, int width, int height) override; void CopyFromBuffer(void *video, const void *src, int width, int height) override;
void CopyToBuffer(const void *video, void *dst, int width, int height) override; void CopyToBuffer(const void *video, void *dst, int width, int height) override;
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override; void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;

View File

@ -95,18 +95,18 @@ public:
* @param video The destination pointer (video-buffer). * @param video The destination pointer (video-buffer).
* @param x The x position within video-buffer. * @param x The x position within video-buffer.
* @param y The y position within video-buffer. * @param y The y position within video-buffer.
* @param colour A 8bpp mapping colour. * @param colour A pixel colour.
*/ */
virtual void SetPixel(void *video, int x, int y, uint8_t colour) = 0; virtual void SetPixel(void *video, int x, int y, PixelColour colour) = 0;
/** /**
* Make a single horizontal line in a single colour on the video-buffer. * Make a single horizontal line in a single colour on the video-buffer.
* @param video The destination pointer (video-buffer). * @param video The destination pointer (video-buffer).
* @param width The length of the line. * @param width The length of the line.
* @param height The height of the line. * @param height The height of the line.
* @param colour A 8bpp mapping colour. * @param colour A pixel colour.
*/ */
virtual void DrawRect(void *video, int width, int height, uint8_t colour) = 0; virtual void DrawRect(void *video, int width, int height, PixelColour colour) = 0;
/** /**
* Draw a line with a given colour. * Draw a line with a given colour.
@ -117,11 +117,11 @@ public:
* @param y2 The y coordinate to where the lines goes. * @param y2 The y coordinate to where the lines goes.
* @param screen_width The width of the screen you are drawing in (to avoid buffer-overflows). * @param screen_width The width of the screen you are drawing in (to avoid buffer-overflows).
* @param screen_height The height of the screen you are drawing in (to avoid buffer-overflows). * @param screen_height The height of the screen you are drawing in (to avoid buffer-overflows).
* @param colour A 8bpp mapping colour. * @param colour A pixel colour.
* @param width Line width. * @param width Line width.
* @param dash Length of dashes for dashed lines. 0 means solid line. * @param dash Length of dashes for dashed lines. 0 means solid line.
*/ */
virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash = 0) = 0; virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash = 0) = 0;
/** /**
* Copy from a buffer to the screen. * Copy from a buffer to the screen.

View File

@ -20,9 +20,9 @@ public:
void DrawColourMappingRect(void *, int, int, PaletteID) override {}; void DrawColourMappingRect(void *, int, int, PaletteID) override {};
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override; Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
void *MoveTo(void *, int, int) override { return nullptr; }; void *MoveTo(void *, int, int) override { return nullptr; };
void SetPixel(void *, int, int, uint8_t) override {}; void SetPixel(void *, int, int, PixelColour) override {};
void DrawRect(void *, int, int, uint8_t) override {}; void DrawRect(void *, int, int, PixelColour) override {};
void DrawLine(void *, int, int, int, int, int, int, uint8_t, int, int) override {}; void DrawLine(void *, int, int, int, int, int, int, PixelColour, int, int) override {};
void CopyFromBuffer(void *, const void *, int, int) override {}; void CopyFromBuffer(void *, const void *, int, int) override {};
void CopyToBuffer(const void *, void *, int, int) override {}; void CopyToBuffer(const void *, void *, int, int) override {};
void CopyImageToBuffer(const void *, void *, int, int, int) override {}; void CopyImageToBuffer(const void *, void *, int, int, int) override {};

View File

@ -60,8 +60,8 @@ public:
void DrawWidget(const Rect &r, WidgetID) const override void DrawWidget(const Rect &r, WidgetID) const override
{ {
GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE); GfxFillRect(r.left, r.top, r.right, r.bottom, PixelColour{4}, FILLRECT_OPAQUE);
GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER); GfxFillRect(r.left, r.top, r.right, r.bottom, PixelColour{0}, FILLRECT_CHECKER);
} }
}; };
@ -385,10 +385,10 @@ bool HandleBootstrap()
/* Initialise the palette. The biggest step is 'faking' some recolour sprites. /* Initialise the palette. The biggest step is 'faking' some recolour sprites.
* This way the mauve and gray colours work and we can show the user interface. */ * This way the mauve and gray colours work and we can show the user interface. */
GfxInitPalettes(); GfxInitPalettes();
static const int offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 }; static const uint8_t offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 };
for (Colours i = COLOUR_BEGIN; i != COLOUR_END; i++) { for (Colours i = COLOUR_BEGIN; i != COLOUR_END; i++) {
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) { for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
SetColourGradient(i, j, offsets[i] + j); SetColourGradient(i, j, PixelColour(offsets[i] + j));
} }
} }

View File

@ -546,7 +546,7 @@ static bool CargoAndEngineFilter(const GUIEngineListItem *item, const CargoType
return Engine::Get(item->engine_id)->GetPower() != 0; return Engine::Get(item->engine_id)->GetPower() != 0;
} else { } else {
CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(item->engine_id, true) & _standard_cargo_mask; CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(item->engine_id, true) & _standard_cargo_mask;
return (cargo_type == CargoFilterCriteria::CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cargo_type)); return (cargo_type == CargoFilterCriteria::CF_NONE ? refit_mask.None() : refit_mask.Test(cargo_type));
} }
} }
@ -557,7 +557,7 @@ static GUIEngineList::FilterFunction * const _engine_filter_funcs[] = {
static uint GetCargoWeight(const CargoArray &cap, VehicleType vtype) static uint GetCargoWeight(const CargoArray &cap, VehicleType vtype)
{ {
uint weight = 0; uint weight = 0;
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
if (cap[cargo] != 0) { if (cap[cargo] != 0) {
if (vtype == VEH_TRAIN) { if (vtype == VEH_TRAIN) {
weight += CargoSpec::Get(cargo)->WeightOfNUnitsInTrain(cap[cargo]); weight += CargoSpec::Get(cargo)->WeightOfNUnitsInTrain(cap[cargo]);
@ -956,7 +956,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right; int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
int sprite_width = sprite_left + sprite_right; int sprite_width = sprite_left + sprite_right;
int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width); int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width);
int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL); PixelColour linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
auto badge_column_widths = badge_classes.GetColumnWidths(); auto badge_column_widths = badge_classes.GetColumnWidths();
@ -1261,10 +1261,10 @@ struct BuildVehicleWindow : Window {
StringID GetCargoFilterLabel(CargoType cargo_type) const StringID GetCargoFilterLabel(CargoType cargo_type) const
{ {
switch (cargo_type) { switch (cargo_type.base()) {
case CargoFilterCriteria::CF_ANY: return STR_PURCHASE_INFO_ALL_TYPES; case CargoFilterCriteria::CF_ANY.base(): return STR_PURCHASE_INFO_ALL_TYPES;
case CargoFilterCriteria::CF_ENGINES: return STR_PURCHASE_INFO_ENGINES_ONLY; case CargoFilterCriteria::CF_ENGINES.base(): return STR_PURCHASE_INFO_ENGINES_ONLY;
case CargoFilterCriteria::CF_NONE: return STR_PURCHASE_INFO_NONE; case CargoFilterCriteria::CF_NONE.base(): return STR_PURCHASE_INFO_NONE;
default: return CargoSpec::Get(cargo_type)->name; default: return CargoSpec::Get(cargo_type)->name;
} }
} }
@ -1274,7 +1274,7 @@ struct BuildVehicleWindow : Window {
{ {
/* Set the last cargo filter criteria. */ /* Set the last cargo filter criteria. */
this->cargo_filter_criteria = _engine_sort_last_cargo_criteria[this->vehicle_type]; this->cargo_filter_criteria = _engine_sort_last_cargo_criteria[this->vehicle_type];
if (this->cargo_filter_criteria < NUM_CARGO && !HasBit(_standard_cargo_mask, this->cargo_filter_criteria)) this->cargo_filter_criteria = CargoFilterCriteria::CF_ANY; if (this->cargo_filter_criteria < NUM_CARGO && !_standard_cargo_mask.Test(this->cargo_filter_criteria)) this->cargo_filter_criteria = CargoFilterCriteria::CF_ANY;
this->eng_list.SetFilterFuncs(_engine_filter_funcs); this->eng_list.SetFilterFuncs(_engine_filter_funcs);
this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY); this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY);
@ -1570,20 +1570,20 @@ struct BuildVehicleWindow : Window {
DropDownList list; DropDownList list;
/* Add item for disabling filtering. */ /* Add item for disabling filtering. */
list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY)); list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY.base()));
/* Specific filters for trains. */ /* Specific filters for trains. */
if (this->vehicle_type == VEH_TRAIN) { if (this->vehicle_type == VEH_TRAIN) {
/* Add item for locomotives only in case of trains. */ /* Add item for locomotives only in case of trains. */
list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ENGINES), CargoFilterCriteria::CF_ENGINES)); list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ENGINES), CargoFilterCriteria::CF_ENGINES.base()));
/* Add item for vehicles not carrying anything, e.g. train engines. /* Add item for vehicles not carrying anything, e.g. train engines.
* This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */ * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE)); list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE.base()));
} }
/* Add cargos */ /* Add cargos */
Dimension d = GetLargestCargoIconSize(); Dimension d = GetLargestCargoIconSize();
for (const CargoSpec *cs : _sorted_standard_cargo_specs) { for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index())); list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index().base()));
} }
return list; return list;
@ -1675,7 +1675,7 @@ struct BuildVehicleWindow : Window {
break; break;
case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu
ShowDropDownList(this, this->BuildCargoDropDownList(), this->cargo_filter_criteria, widget); ShowDropDownList(this, this->BuildCargoDropDownList(), this->cargo_filter_criteria.base(), widget);
break; break;
case WID_BV_CONFIGURE_BADGES: case WID_BV_CONFIGURE_BADGES:
@ -1884,7 +1884,7 @@ struct BuildVehicleWindow : Window {
case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria
if (this->cargo_filter_criteria != index) { if (this->cargo_filter_criteria != index) {
this->cargo_filter_criteria = index; this->cargo_filter_criteria = static_cast<CargoType>(index);
_engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter_criteria; _engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter_criteria;
/* deactivate filter if criteria is 'Show All', activate it otherwise */ /* deactivate filter if criteria is 'Show All', activate it otherwise */
this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY); this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY);

View File

@ -12,15 +12,19 @@
#include "core/enum_type.hpp" #include "core/enum_type.hpp"
#include "core/strong_typedef_type.hpp" #include "core/strong_typedef_type.hpp"
#include "core/strong_bitset_type.hpp"
#include "core/convertible_through_base.hpp" #include "core/convertible_through_base.hpp"
/** Globally unique label of a cargo type. */ /** Globally unique label of a cargo type. */
using CargoLabel = StrongType::Typedef<uint32_t, struct CargoLabelTag, StrongType::Compare>; using CargoLabel = StrongType::Typedef<uint32_t, struct CargoLabelTag, StrongType::Compare>;
static constexpr uint NUM_ORIGINAL_CARGO = 12; ///< Original number of cargo types.
static constexpr uint NUM_CARGO = 64; ///< Maximum number of cargo types in a game.
/** /**
* Cargo slots to indicate a cargo type within a game. * Cargo slots to indicate a cargo type within a game.
*/ */
using CargoType = uint8_t; using CargoType = StrongType::Typedef<uint8_t, struct CargoTypeTag, StrongType::Compare, StrongType::Integer>;
/** /**
* Available types of cargo * Available types of cargo
@ -71,14 +75,11 @@ static constexpr CargoLabel CT_NONE = CT_PASSENGERS;
static constexpr CargoLabel CT_INVALID{UINT32_MAX}; ///< Invalid cargo type. static constexpr CargoLabel CT_INVALID{UINT32_MAX}; ///< Invalid cargo type.
static const CargoType NUM_ORIGINAL_CARGO = 12; ///< Original number of cargo types.
static const CargoType NUM_CARGO = 64; ///< Maximum number of cargo types in a game.
/* CARGO_AUTO_REFIT and CARGO_NO_REFIT are stored in save-games for refit-orders, so should not be changed. */ /* CARGO_AUTO_REFIT and CARGO_NO_REFIT are stored in save-games for refit-orders, so should not be changed. */
static const CargoType CARGO_AUTO_REFIT = 0xFD; ///< Automatically choose cargo type when doing auto refitting. static constexpr CargoType CARGO_AUTO_REFIT{0xFD}; ///< Automatically choose cargo type when doing auto refitting.
static const CargoType CARGO_NO_REFIT = 0xFE; ///< Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-renew). static constexpr CargoType CARGO_NO_REFIT{0xFE}; ///< Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-renew).
static const CargoType INVALID_CARGO = UINT8_MAX; static constexpr CargoType INVALID_CARGO{UINT8_MAX};
/** Mixed cargo types for definitions with cargo that can vary depending on climate. */ /** Mixed cargo types for definitions with cargo that can vary depending on climate. */
enum MixedCargoType : uint8_t { enum MixedCargoType : uint8_t {
@ -92,25 +93,25 @@ enum MixedCargoType : uint8_t {
* These are used by user interface code only and must not be assigned to any entity. Not all values are valid for every UI filter. * These are used by user interface code only and must not be assigned to any entity. Not all values are valid for every UI filter.
*/ */
namespace CargoFilterCriteria { namespace CargoFilterCriteria {
static constexpr CargoType CF_ANY = NUM_CARGO; ///< Show all items independent of carried cargo (i.e. no filtering) static constexpr CargoType CF_ANY{NUM_CARGO}; ///< Show all items independent of carried cargo (i.e. no filtering)
static constexpr CargoType CF_NONE = NUM_CARGO + 1; ///< Show only items which do not carry cargo (e.g. train engines) static constexpr CargoType CF_NONE{NUM_CARGO + 1}; ///< Show only items which do not carry cargo (e.g. train engines)
static constexpr CargoType CF_ENGINES = NUM_CARGO + 2; ///< Show only engines (for rail vehicles only) static constexpr CargoType CF_ENGINES{NUM_CARGO + 2}; ///< Show only engines (for rail vehicles only)
static constexpr CargoType CF_FREIGHT = NUM_CARGO + 3; ///< Show only vehicles which carry any freight (non-passenger) cargo static constexpr CargoType CF_FREIGHT{NUM_CARGO + 3}; ///< Show only vehicles which carry any freight (non-passenger) cargo
static constexpr CargoType CF_NO_RATING = NUM_CARGO + 4; ///< Show items with no rating (station list) static constexpr CargoType CF_NO_RATING{NUM_CARGO + 4}; ///< Show items with no rating (station list)
static constexpr CargoType CF_SELECT_ALL = NUM_CARGO + 5; ///< Select all items (station list) static constexpr CargoType CF_SELECT_ALL{NUM_CARGO + 5}; ///< Select all items (station list)
static constexpr CargoType CF_EXPAND_LIST = NUM_CARGO + 6; ///< Expand list to show all items (station list) static constexpr CargoType CF_EXPAND_LIST{NUM_CARGO + 6}; ///< Expand list to show all items (station list)
}; };
/** Test whether cargo type is not INVALID_CARGO */ /** Test whether cargo type is not INVALID_CARGO */
inline bool IsValidCargoType(CargoType cargo) { return cargo != INVALID_CARGO; } inline bool IsValidCargoType(CargoType cargo) { return cargo != INVALID_CARGO; }
typedef uint64_t CargoTypes; using CargoTypes = StrongBitSet<CargoType, uint64_t>;
static const CargoTypes ALL_CARGOTYPES = (CargoTypes)UINT64_MAX; static constexpr CargoTypes ALL_CARGOTYPES{UINT64_MAX};
/** Class for storing amounts of cargo */ /** Class for storing amounts of cargo */
struct CargoArray : std::array<uint, NUM_CARGO> { struct CargoArray : TypedIndexContainer<std::array<uint, NUM_CARGO>, CargoType> {
/** /**
* Get the sum of all cargo amounts. * Get the sum of all cargo amounts.
* @return The sum. * @return The sum.

View File

@ -63,7 +63,7 @@ inline CargoMonitorID EncodeCargoIndustryMonitor(CompanyID company, CargoType ct
uint32_t ret = 0; uint32_t ret = 0;
SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, ind.base()); SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, ind.base());
SetBit(ret, CCB_IS_INDUSTRY_BIT); SetBit(ret, CCB_IS_INDUSTRY_BIT);
SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype); SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype.base());
SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company.base()); SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company.base());
return ret; return ret;
} }
@ -82,7 +82,7 @@ inline CargoMonitorID EncodeCargoTownMonitor(CompanyID company, CargoType ctype,
uint32_t ret = 0; uint32_t ret = 0;
SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, town.base()); SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, town.base());
SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype); SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype.base());
SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company.base()); SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company.base());
return ret; return ret;
} }
@ -104,7 +104,7 @@ inline CompanyID DecodeMonitorCompany(CargoMonitorID num)
*/ */
inline CargoType DecodeMonitorCargoType(CargoMonitorID num) inline CargoType DecodeMonitorCargoType(CargoMonitorID num)
{ {
return GB(num, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH); return static_cast<CargoType>(GB(num, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH));
} }
/** /**

View File

@ -410,7 +410,7 @@ void VehicleCargoList::AgeCargo()
return (accepted && cp->first_station != current_station) ? MTA_DELIVER : MTA_KEEP; return (accepted && cp->first_station != current_station) ? MTA_DELIVER : MTA_KEEP;
} else if (cargo_next == current_station) { } else if (cargo_next == current_station) {
return MTA_DELIVER; return MTA_DELIVER;
} else if (next_station.Contains(cargo_next.base())) { } else if (next_station.Contains(cargo_next)) {
return MTA_KEEP; return MTA_KEEP;
} else { } else {
return MTA_TRANSFER; return MTA_TRANSFER;
@ -470,7 +470,7 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
new_shares.ChangeShare(current_station, INT_MIN); new_shares.ChangeShare(current_station, INT_MIN);
StationIDStack excluded = next_station; StationIDStack excluded = next_station;
while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) { while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) {
new_shares.ChangeShare(StationID{excluded.Pop()}, INT_MIN); new_shares.ChangeShare(excluded.Pop(), INT_MIN);
} }
if (new_shares.GetShares()->empty()) { if (new_shares.GetShares()->empty()) {
cargo_next = StationID::Invalid(); cargo_next = StationID::Invalid();
@ -743,7 +743,7 @@ uint StationCargoList::ShiftCargo(Taction action, StationIDStack next, bool incl
{ {
uint max_move = action.MaxMove(); uint max_move = action.MaxMove();
while (!next.IsEmpty()) { while (!next.IsEmpty()) {
this->ShiftCargo(action, StationID{next.Pop()}); this->ShiftCargo(action, next.Pop());
if (action.MaxMove() == 0) break; if (action.MaxMove() == 0) break;
} }
if (include_invalid && action.MaxMove() > 0) { if (include_invalid && action.MaxMove() > 0) {
@ -853,7 +853,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac
*/ */
uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge) uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
{ {
return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid.base(), false); return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid, false);
} }
/* /*

View File

@ -555,7 +555,7 @@ public:
inline bool HasCargoFor(StationIDStack next) const inline bool HasCargoFor(StationIDStack next) const
{ {
while (!next.IsEmpty()) { while (!next.IsEmpty()) {
if (this->packets.find(StationID{next.Pop()}) != this->packets.end()) return true; if (this->packets.find(next.Pop()) != this->packets.end()) return true;
} }
/* Packets for StationID::Invalid() can go anywhere. */ /* Packets for StationID::Invalid() can go anywhere. */
return this->packets.find(StationID::Invalid()) != this->packets.end(); return this->packets.find(StationID::Invalid()) != this->packets.end();

View File

@ -21,7 +21,7 @@
#include "safeguards.h" #include "safeguards.h"
CargoSpec CargoSpec::array[NUM_CARGO]; TypedIndexContainer<std::array<CargoSpec, NUM_CARGO>, CargoType> CargoSpec::array{};
std::array<std::vector<const CargoSpec *>, NUM_TPE> CargoSpec::town_production_cargoes{}; std::array<std::vector<const CargoSpec *>, NUM_TPE> CargoSpec::town_production_cargoes{};
/** /**
@ -63,7 +63,7 @@ void SetupCargoForClimate(LandscapeType l)
{ {
assert(to_underlying(l) < std::size(_default_climate_cargo)); assert(to_underlying(l) < std::size(_default_climate_cargo));
_cargo_mask = 0; _cargo_mask.Reset();
_default_cargo_labels.clear(); _default_cargo_labels.clear();
_climate_dependent_cargo_labels.fill(CT_INVALID); _climate_dependent_cargo_labels.fill(CT_INVALID);
_climate_independent_cargo_labels.fill(CT_INVALID); _climate_independent_cargo_labels.fill(CT_INVALID);
@ -92,9 +92,9 @@ void SetupCargoForClimate(LandscapeType l)
*insert = std::visit(visitor{}, cl); *insert = std::visit(visitor{}, cl);
if (insert->IsValid()) { if (insert->IsValid()) {
SetBit(_cargo_mask, insert->Index()); _cargo_mask.Set(insert->Index());
_default_cargo_labels.push_back(insert->label); _default_cargo_labels.push_back(insert->label);
_climate_dependent_cargo_labels[insert->Index()] = insert->label; _climate_dependent_cargo_labels[insert->Index().base()] = insert->label;
_climate_independent_cargo_labels[insert->bitnum] = insert->label; _climate_independent_cargo_labels[insert->bitnum] = insert->label;
} }
++insert; ++insert;
@ -186,7 +186,7 @@ SpriteID CargoSpec::GetCargoIcon() const
return sprite; return sprite;
} }
std::array<uint8_t, NUM_CARGO> _sorted_cargo_types; ///< Sort order of cargoes by cargo type. TypedIndexContainer<std::array<uint8_t, NUM_CARGO>, CargoType> _sorted_cargo_types; ///< Sort order of cargoes by cargo type.
std::vector<const CargoSpec *> _sorted_cargo_specs; ///< Cargo specifications sorted alphabetically by name. std::vector<const CargoSpec *> _sorted_cargo_specs; ///< Cargo specifications sorted alphabetically by name.
std::span<const CargoSpec *> _sorted_standard_cargo_specs; ///< Standard cargo specifications sorted alphabetically by name. std::span<const CargoSpec *> _sorted_standard_cargo_specs; ///< Standard cargo specifications sorted alphabetically by name.
@ -238,14 +238,14 @@ void InitializeSortedCargoSpecs()
} }
/* Count the number of standard cargos and fill the mask. */ /* Count the number of standard cargos and fill the mask. */
_standard_cargo_mask = 0; _standard_cargo_mask.Reset();
uint8_t nb_standard_cargo = 0; uint8_t nb_standard_cargo = 0;
for (const auto &cargo : _sorted_cargo_specs) { for (const auto &cargo : _sorted_cargo_specs) {
assert(cargo->town_production_effect != INVALID_TPE); assert(cargo->town_production_effect != INVALID_TPE);
CargoSpec::town_production_cargoes[cargo->town_production_effect].push_back(cargo); CargoSpec::town_production_cargoes[cargo->town_production_effect].push_back(cargo);
if (cargo->classes.Test(CargoClass::Special)) break; if (cargo->classes.Test(CargoClass::Special)) break;
nb_standard_cargo++; nb_standard_cargo++;
SetBit(_standard_cargo_mask, cargo->Index()); _standard_cargo_mask.Set(cargo->Index());
} }
/* _sorted_standard_cargo_specs is a subset of _sorted_cargo_specs. */ /* _sorted_standard_cargo_specs is a subset of _sorted_cargo_specs. */

View File

@ -74,8 +74,8 @@ static const uint TOWN_PRODUCTION_DIVISOR = 256;
struct CargoSpec { struct CargoSpec {
CargoLabel label; ///< Unique label of the cargo type. CargoLabel label; ///< Unique label of the cargo type.
uint8_t bitnum = INVALID_CARGO_BITNUM; ///< Cargo bit number, is #INVALID_CARGO_BITNUM for a non-used spec. uint8_t bitnum = INVALID_CARGO_BITNUM; ///< Cargo bit number, is #INVALID_CARGO_BITNUM for a non-used spec.
uint8_t legend_colour; PixelColour legend_colour;
uint8_t rating_colour; PixelColour rating_colour;
uint8_t weight; ///< Weight of a single unit of this cargo type in 1/16 ton (62.5 kg). uint8_t weight; ///< Weight of a single unit of this cargo type in 1/16 ton (62.5 kg).
uint16_t multiplier = 0x100; ///< Capacity multiplier for vehicles. (8 fractional bits) uint16_t multiplier = 0x100; ///< Capacity multiplier for vehicles. (8 fractional bits)
CargoClasses classes; ///< Classes of this cargo type. @see CargoClass CargoClasses classes; ///< Classes of this cargo type. @see CargoClass
@ -107,7 +107,7 @@ struct CargoSpec {
*/ */
inline CargoType Index() const inline CargoType Index() const
{ {
return this - CargoSpec::array; return static_cast<CargoType>(this - CargoSpec::array.data());
} }
/** /**
@ -126,7 +126,7 @@ struct CargoSpec {
*/ */
static inline size_t GetArraySize() static inline size_t GetArraySize()
{ {
return lengthof(CargoSpec::array); return std::size(CargoSpec::array);
} }
/** /**
@ -134,9 +134,9 @@ struct CargoSpec {
* @param index ID of cargo * @param index ID of cargo
* @pre index is a valid cargo type * @pre index is a valid cargo type
*/ */
static inline CargoSpec *Get(size_t index) static inline CargoSpec *Get(CargoType index)
{ {
assert(index < lengthof(CargoSpec::array)); assert(index.base() < std::size(CargoSpec::array));
return &CargoSpec::array[index]; return &CargoSpec::array[index];
} }
@ -165,12 +165,12 @@ struct CargoSpec {
}; };
bool operator==(const Iterator &other) const { return this->index == other.index; } bool operator==(const Iterator &other) const { return this->index == other.index; }
CargoSpec * operator*() const { return CargoSpec::Get(this->index); } CargoSpec * operator*() const { return CargoSpec::Get(CargoType{static_cast<CargoType::BaseType>(this->index)}); }
Iterator & operator++() { this->index++; this->ValidateIndex(); return *this; } Iterator & operator++() { this->index++; this->ValidateIndex(); return *this; }
private: private:
size_t index; size_t index;
void ValidateIndex() { while (this->index < CargoSpec::GetArraySize() && !(CargoSpec::Get(this->index)->IsValid())) this->index++; } void ValidateIndex() { while (this->index < CargoSpec::GetArraySize() && !(**this)->IsValid()) this->index++; }
}; };
/* /*
@ -195,7 +195,7 @@ struct CargoSpec {
static std::array<std::vector<const CargoSpec *>, NUM_TPE> town_production_cargoes; static std::array<std::vector<const CargoSpec *>, NUM_TPE> town_production_cargoes;
private: private:
static CargoSpec array[NUM_CARGO]; ///< Array holding all CargoSpecs static TypedIndexContainer<std::array<CargoSpec, NUM_CARGO>, CargoType> array; ///< Array holding all CargoSpecs
static inline std::map<CargoLabel, CargoType> label_map{}; ///< Translation map from CargoLabel to Cargo type. static inline std::map<CargoLabel, CargoType> label_map{}; ///< Translation map from CargoLabel to Cargo type.
friend void SetupCargoForClimate(LandscapeType l); friend void SetupCargoForClimate(LandscapeType l);
@ -223,7 +223,7 @@ inline CargoType GetCargoTypeByLabel(CargoLabel label)
Dimension GetLargestCargoIconSize(); Dimension GetLargestCargoIconSize();
void InitializeSortedCargoSpecs(); void InitializeSortedCargoSpecs();
extern std::array<uint8_t, NUM_CARGO> _sorted_cargo_types; extern TypedIndexContainer<std::array<uint8_t, NUM_CARGO>, CargoType> _sorted_cargo_types;
extern std::vector<const CargoSpec *> _sorted_cargo_specs; extern std::vector<const CargoSpec *> _sorted_cargo_specs;
extern std::span<const CargoSpec *> _sorted_standard_cargo_specs; extern std::span<const CargoSpec *> _sorted_standard_cargo_specs;
@ -238,8 +238,6 @@ inline bool IsCargoInClass(CargoType cargo, CargoClasses cc)
return CargoSpec::Get(cargo)->classes.Any(cc); return CargoSpec::Get(cargo)->classes.Any(cc);
} }
using SetCargoBitIterator = SetBitIterator<CargoType, CargoTypes>;
/** Comparator to sort CargoType by according to desired order. */ /** Comparator to sort CargoType by according to desired order. */
struct CargoTypeComparator { struct CargoTypeComparator {
bool operator() (const CargoType &lhs, const CargoType &rhs) const { return _sorted_cargo_types[lhs] < _sorted_cargo_types[rhs]; } bool operator() (const CargoType &lhs, const CargoType &rhs) const { return _sorted_cargo_types[lhs] < _sorted_cargo_types[rhs]; }

View File

@ -152,8 +152,8 @@ void SetLocalCompany(CompanyID new_company)
*/ */
TextColour GetDrawStringCompanyColour(CompanyID company) TextColour GetDrawStringCompanyColour(CompanyID company)
{ {
if (!Company::IsValidID(company)) return (TextColour)GetColourGradient(COLOUR_WHITE, SHADE_NORMAL) | TC_IS_PALETTE_COLOUR; if (!Company::IsValidID(company)) return GetColourGradient(COLOUR_WHITE, SHADE_NORMAL).ToTextColour();
return (TextColour)GetColourGradient(_company_colours[company], SHADE_NORMAL) | TC_IS_PALETTE_COLOUR; return GetColourGradient(_company_colours[company], SHADE_NORMAL).ToTextColour();
} }
/** /**

View File

@ -544,7 +544,7 @@ bool IsValidConsoleColour(TextColour c)
* colour gradient, so it must be one of those. */ * colour gradient, so it must be one of those. */
c &= ~TC_IS_PALETTE_COLOUR; c &= ~TC_IS_PALETTE_COLOUR;
for (Colours i = COLOUR_BEGIN; i < COLOUR_END; i++) { for (Colours i = COLOUR_BEGIN; i < COLOUR_END; i++) {
if (GetColourGradient(i, SHADE_NORMAL) == c) return true; if (GetColourGradient(i, SHADE_NORMAL).p == c) return true;
} }
return false; return false;

View File

@ -29,6 +29,7 @@ add_files(
string_consumer.hpp string_consumer.hpp
string_inplace.cpp string_inplace.cpp
string_inplace.hpp string_inplace.hpp
strong_bitset_type.hpp
strong_typedef_type.hpp strong_typedef_type.hpp
utf8.cpp utf8.cpp
utf8.hpp utf8.hpp

View File

@ -108,6 +108,16 @@ public:
return static_cast<Timpl&>(*this); return static_cast<Timpl&>(*this);
} }
/**
* Flip all bits.
* @returns The bit set
*/
inline constexpr Timpl &Flip()
{
this->data ^= Tmask;
return static_cast<Timpl&>(*this);
}
/** /**
* Flip the value-th bit. * Flip the value-th bit.
* @param value Bit to flip. * @param value Bit to flip.

View File

@ -113,13 +113,14 @@ struct SmallStackItem {
* index types of the same length. * index types of the same length.
* @tparam Titem Value type to be used. * @tparam Titem Value type to be used.
* @tparam Tindex Index type to use for the pool. * @tparam Tindex Index type to use for the pool.
* @tparam Tinvalid Invalid item to keep at the bottom of each stack. * @tparam Tinvalid_value Value to construct invalid item to keep at the bottom of each stack.
* @tparam Tgrowth_step Growth step for pool. * @tparam Tgrowth_step Growth step for pool.
* @tparam Tmax_size Maximum size for pool. * @tparam Tmax_size Maximum size for pool.
*/ */
template <typename Titem, typename Tindex, Titem Tinvalid, Tindex Tgrowth_step, Tindex Tmax_size> template <typename Titem, typename Tindex, auto Tinvalid_value, Tindex Tgrowth_step, Tindex Tmax_size>
class SmallStack : public SmallStackItem<Titem, Tindex> { class SmallStack : public SmallStackItem<Titem, Tindex> {
public: public:
static constexpr Titem Tinvalid{Tinvalid_value};
typedef SmallStackItem<Titem, Tindex> Item; typedef SmallStackItem<Titem, Tindex> Item;

View File

@ -0,0 +1,42 @@
/*
* 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 strong_bitset_type.hpp Type helper for making a BitSet out of a Strong Typedef. */
#ifndef STRONG_BITSET_TYPE_HPP
#define STRONG_BITSET_TYPE_HPP
#include "base_bitset_type.hpp"
/**
* Strong bit set.
* @tparam Tvalue_type Type of values to wrap.
* @tparam Tstorage Storage type required to hold values.
*/
template <typename Tvalue_type, typename Tstorage, Tstorage Tmask = std::numeric_limits<Tstorage>::max()>
class StrongBitSet : public BaseBitSet<StrongBitSet<Tvalue_type, Tstorage, Tmask>, Tvalue_type, Tstorage> {
public:
constexpr StrongBitSet() : BaseClass() {}
constexpr StrongBitSet(Tvalue_type value) : BaseClass() { this->Set(value); }
explicit constexpr StrongBitSet(Tstorage data) : BaseClass(data) {}
constexpr StrongBitSet(std::initializer_list<const Tvalue_type> values) : BaseClass()
{
for (const Tvalue_type &value : values) {
this->Set(value);
}
}
static constexpr size_t DecayValueType(Tvalue_type value) { return value.base(); }
constexpr auto operator <=>(const StrongBitSet &) const noexcept = default;
private:
using BaseClass = BaseBitSet<StrongBitSet<Tvalue_type, Tstorage, Tmask>, Tvalue_type, Tstorage, Tmask>;
};
#endif /* STRONG_BITSET_TYPE_HPP */

View File

@ -413,7 +413,7 @@ struct DepotWindow : Window {
*/ */
if (this->type == VEH_TRAIN && _consistent_train_width != 0) { if (this->type == VEH_TRAIN && _consistent_train_width != 0) {
int w = ScaleSpriteTrad(2 * _consistent_train_width); int w = ScaleSpriteTrad(2 * _consistent_train_width);
int col = GetColourGradient(wid->colour, SHADE_NORMAL); PixelColour col = GetColourGradient(wid->colour, SHADE_NORMAL);
Rect image = ir.Indent(this->header_width, rtl).Indent(this->count_width, !rtl); Rect image = ir.Indent(this->header_width, rtl).Indent(this->count_width, !rtl);
int first_line = w + (-this->hscroll->GetPosition()) % w; int first_line = w + (-this->hscroll->GetPosition()) % w;
if (rtl) { if (rtl) {

View File

@ -37,8 +37,8 @@ public:
void Draw(const Rect &full, const Rect &, bool, int, Colours bg_colour) const override void Draw(const Rect &full, const Rect &, bool, int, Colours bg_colour) const override
{ {
uint8_t c1 = GetColourGradient(bg_colour, SHADE_DARK); PixelColour c1 = GetColourGradient(bg_colour, SHADE_DARK);
uint8_t c2 = GetColourGradient(bg_colour, SHADE_LIGHTEST); PixelColour c2 = GetColourGradient(bg_colour, SHADE_LIGHTEST);
int mid = CentreBounds(full.top, full.bottom, 0); int mid = CentreBounds(full.top, full.bottom, 0);
GfxFillRect(full.left, mid - WidgetDimensions::scaled.bevel.bottom, full.right, mid - 1, c1); GfxFillRect(full.left, mid - WidgetDimensions::scaled.bevel.bottom, full.right, mid - 1, c1);

View File

@ -1101,7 +1101,7 @@ static Money DeliverGoods(int num_pieces, CargoType cargo_type, StationID dest,
uint accepted_ind = DeliverGoodsToIndustry(st, cargo_type, num_pieces, src.type == SourceType::Industry ? src.ToIndustryID() : IndustryID::Invalid(), company->index); uint accepted_ind = DeliverGoodsToIndustry(st, cargo_type, num_pieces, src.type == SourceType::Industry ? src.ToIndustryID() : IndustryID::Invalid(), company->index);
/* If this cargo type is always accepted, accept all */ /* If this cargo type is always accepted, accept all */
uint accepted_total = HasBit(st->always_accepted, cargo_type) ? num_pieces : accepted_ind; uint accepted_total = st->always_accepted.Test(cargo_type) ? num_pieces : accepted_ind;
/* Update station statistics */ /* Update station statistics */
if (accepted_total > 0) { if (accepted_total > 0) {
@ -1394,7 +1394,7 @@ struct PrepareRefitAction
bool operator()(const Vehicle *v) bool operator()(const Vehicle *v)
{ {
this->consist_capleft[v->cargo_type] -= v->cargo_cap - v->cargo.ReservedCount(); this->consist_capleft[v->cargo_type] -= v->cargo_cap - v->cargo.ReservedCount();
this->refit_mask |= EngInfo(v->engine_type)->refit_mask; this->refit_mask.Set(EngInfo(v->engine_type)->refit_mask);
return true; return true;
} }
}; };
@ -1487,7 +1487,7 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station
if (is_auto_refit) { if (is_auto_refit) {
/* Get a refittable cargo type with waiting cargo for next_station or StationID::Invalid(). */ /* Get a refittable cargo type with waiting cargo for next_station or StationID::Invalid(). */
new_cargo_type = v_start->cargo_type; new_cargo_type = v_start->cargo_type;
for (CargoType cargo_type : SetCargoBitIterator(refit_mask)) { for (CargoType cargo_type : refit_mask) {
if (st->goods[cargo_type].HasData() && st->goods[cargo_type].GetData().cargo.HasCargoFor(next_station)) { if (st->goods[cargo_type].HasData() && st->goods[cargo_type].GetData().cargo.HasCargoFor(next_station)) {
/* Try to find out if auto-refitting would succeed. In case the refit is allowed, /* Try to find out if auto-refitting would succeed. In case the refit is allowed,
* the returned refit capacity will be greater than zero. */ * the returned refit capacity will be greater than zero. */
@ -1646,10 +1646,10 @@ static void LoadUnloadVehicle(Vehicle *front)
bool completely_emptied = true; bool completely_emptied = true;
bool anything_unloaded = false; bool anything_unloaded = false;
bool anything_loaded = false; bool anything_loaded = false;
CargoTypes full_load_amount = 0; CargoTypes full_load_amount{};
CargoTypes cargo_not_full = 0; CargoTypes cargo_not_full{};
CargoTypes cargo_full = 0; CargoTypes cargo_full{};
CargoTypes reservation_left = 0; CargoTypes reservation_left{};
front->cur_speed = 0; front->cur_speed = 0;
@ -1780,14 +1780,14 @@ static void LoadUnloadVehicle(Vehicle *front)
if (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) { if (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
/* Remember if there are reservations left so that we don't stop /* Remember if there are reservations left so that we don't stop
* loading before they're loaded. */ * loading before they're loaded. */
SetBit(reservation_left, v->cargo_type); reservation_left.Set(v->cargo_type);
} }
/* Store whether the maximum possible load amount was loaded or not.*/ /* Store whether the maximum possible load amount was loaded or not.*/
if (loaded == cap_left) { if (loaded == cap_left) {
SetBit(full_load_amount, v->cargo_type); full_load_amount.Set(v->cargo_type);
} else { } else {
ClrBit(full_load_amount, v->cargo_type); full_load_amount.Reset(v->cargo_type);
} }
/* TODO: Regarding this, when we do gradual loading, we /* TODO: Regarding this, when we do gradual loading, we
@ -1820,9 +1820,9 @@ static void LoadUnloadVehicle(Vehicle *front)
} }
if (v->cargo.StoredCount() >= v->cargo_cap) { if (v->cargo.StoredCount() >= v->cargo_cap) {
SetBit(cargo_full, v->cargo_type); cargo_full.Set(v->cargo_type);
} else { } else {
SetBit(cargo_not_full, v->cargo_type); cargo_not_full.Set(v->cargo_type);
} }
} }
@ -1852,7 +1852,7 @@ static void LoadUnloadVehicle(Vehicle *front)
} }
/* We loaded less cargo than possible for all cargo types and it's not full /* We loaded less cargo than possible for all cargo types and it's not full
* load and we're not supposed to wait any longer: stop loading. */ * load and we're not supposed to wait any longer: stop loading. */
if (!anything_unloaded && full_load_amount == 0 && reservation_left == 0 && !(front->current_order.GetLoadType() & OLFB_FULL_LOAD) && if (!anything_unloaded && full_load_amount.None() && reservation_left.None() && !(front->current_order.GetLoadType() & OLFB_FULL_LOAD) &&
front->current_order_time >= std::max(front->current_order.GetTimetabledWait() - front->lateness_counter, 0)) { front->current_order_time >= std::max(front->current_order.GetTimetabledWait() - front->lateness_counter, 0)) {
front->vehicle_flags.Set(VehicleFlag::StopLoading); front->vehicle_flags.Set(VehicleFlag::StopLoading);
} }
@ -1866,10 +1866,10 @@ static void LoadUnloadVehicle(Vehicle *front)
/* if the aircraft carries passengers and is NOT full, then /* if the aircraft carries passengers and is NOT full, then
* continue loading, no matter how much mail is in */ * continue loading, no matter how much mail is in */
if ((front->type == VEH_AIRCRAFT && IsCargoInClass(front->cargo_type, CargoClass::Passengers) && front->cargo_cap > front->cargo.StoredCount()) || if ((front->type == VEH_AIRCRAFT && IsCargoInClass(front->cargo_type, CargoClass::Passengers) && front->cargo_cap > front->cargo.StoredCount()) ||
(cargo_not_full != 0 && (cargo_full & ~cargo_not_full) == 0)) { // There are still non-full cargoes (cargo_not_full.Any() && cargo_full.Reset(cargo_not_full).None())) { // There are still non-full cargoes
finished_loading = false; finished_loading = false;
} }
} else if (cargo_not_full != 0) { } else if (cargo_not_full.Any()) {
finished_loading = false; finished_loading = false;
} }

View File

@ -927,7 +927,7 @@ static CompanyID GetPreviewCompany(Engine *e)
/* Check whether the company uses similar vehicles */ /* Check whether the company uses similar vehicles */
for (const Vehicle *v : Vehicle::Iterate()) { for (const Vehicle *v : Vehicle::Iterate()) {
if (v->owner != c->index || v->type != e->type) continue; if (v->owner != c->index || v->type != e->type) continue;
if (!v->GetEngine()->CanCarryCargo() || !HasBit(cargomask, v->cargo_type)) continue; if (!v->GetEngine()->CanCarryCargo() || !cargomask.Test(v->cargo_type)) continue;
best_hist = c->old_economy[0].performance_history; best_hist = c->old_economy[0].performance_history;
best_company = c->index; best_company = c->index;
@ -1294,7 +1294,7 @@ bool IsEngineRefittable(EngineID engine)
if (!e->CanCarryCargo()) return false; if (!e->CanCarryCargo()) return false;
const EngineInfo *ei = &e->info; const EngineInfo *ei = &e->info;
if (ei->refit_mask == 0) return false; if (ei->refit_mask.None()) return false;
/* Are there suffixes? /* Are there suffixes?
* Note: This does not mean the suffixes are actually available for every consist at any time. */ * Note: This does not mean the suffixes are actually available for every consist at any time. */
@ -1302,9 +1302,7 @@ bool IsEngineRefittable(EngineID engine)
/* Is there any cargo except the default cargo? */ /* Is there any cargo except the default cargo? */
CargoType default_cargo = e->GetDefaultCargoType(); CargoType default_cargo = e->GetDefaultCargoType();
CargoTypes default_cargo_mask = 0; return IsValidCargoType(default_cargo) && ei->refit_mask != default_cargo;
SetBit(default_cargo_mask, default_cargo);
return IsValidCargoType(default_cargo) && ei->refit_mask != default_cargo_mask;
} }
/** /**

View File

@ -70,16 +70,6 @@ public:
*/ */
virtual int GetFontSize() const { return this->height; } virtual int GetFontSize() const { return this->height; }
/**
* Map a SpriteID to the key
* @param key The key to map to.
* @param sprite The sprite that is being mapped.
*/
virtual void SetUnicodeGlyph(char32_t key, SpriteID sprite) = 0;
/** Initialize the glyph map */
virtual void InitializeUnicodeGlyphMap() = 0;
/** Clear the font cache. */ /** Clear the font cache. */
virtual void ClearFontCache() = 0; virtual void ClearFontCache() = 0;
@ -153,20 +143,6 @@ public:
virtual bool IsBuiltInFont() = 0; virtual bool IsBuiltInFont() = 0;
}; };
/** Map a SpriteID to the font size and key */
inline void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite)
{
FontCache::Get(size)->SetUnicodeGlyph(key, sprite);
}
/** Initialize the glyph map */
inline void InitializeUnicodeGlyphMap()
{
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
FontCache::Get(fs)->InitializeUnicodeGlyphMap();
}
}
inline void ClearFontCache(FontSizes fontsizes) inline void ClearFontCache(FontSizes fontsizes)
{ {
for (FontSize fs : fontsizes) { for (FontSize fs : fontsizes) {
@ -237,4 +213,8 @@ void UninitFontCache();
bool GetFontAAState(); bool GetFontAAState();
void SetFont(FontSize fontsize, const std::string &font, uint size); void SetFont(FontSize fontsize, const std::string &font, uint size);
/* Implemented in spritefontcache.cpp */
void InitializeUnicodeGlyphMap();
void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite);
#endif /* FONTCACHE_H */ #endif /* FONTCACHE_H */

View File

@ -10,6 +10,7 @@
#include "../stdafx.h" #include "../stdafx.h"
#include "../fontcache.h" #include "../fontcache.h"
#include "../gfx_layout.h" #include "../gfx_layout.h"
#include "../string_func.h"
#include "../zoom_func.h" #include "../zoom_func.h"
#include "spritefontcache.h" #include "spritefontcache.h"
@ -31,41 +32,43 @@ static int ScaleFontTrad(int value)
return UnScaleByZoom(value * ZOOM_BASE, _font_zoom); return UnScaleByZoom(value * ZOOM_BASE, _font_zoom);
} }
/** static std::array<std::unordered_map<char32_t, SpriteID>, FS_END> _char_maps{}; ///< Glyph map for each font size.
* Create a new sprite font cache.
* @param fs The font size to create the cache for.
*/
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs)
{
this->InitializeUnicodeGlyphMap();
this->height = ScaleGUITrad(FontCache::GetDefaultFontHeight(this->fs));
this->ascender = (this->height - ScaleFontTrad(FontCache::GetDefaultFontHeight(this->fs))) / 2;
}
/** /**
* Get SpriteID associated with a character. * Get SpriteID associated with a character.
* @param key Character to find. * @param key Character to find.
* @return SpriteID for character, or 0 if not present. * @return SpriteID for character, or 0 if not present.
*/ */
SpriteID SpriteFontCache::GetUnicodeGlyph(char32_t key) static SpriteID GetUnicodeGlyph(FontSize fs, char32_t key)
{ {
const auto found = this->char_map.find(key); auto found = _char_maps[fs].find(key);
if (found == std::end(this->char_map)) return 0; if (found != std::end(_char_maps[fs])) return found->second;
return found->second; return 0;
} }
void SpriteFontCache::SetUnicodeGlyph(char32_t key, SpriteID sprite) /**
* Set the SpriteID for a unicode character.
* @param fs Font size to set.
* @param key Unicode character to set.
* @param sprite SpriteID of character.
*/
void SetUnicodeGlyph(FontSize fs, char32_t key, SpriteID sprite)
{ {
this->char_map[key] = sprite; _char_maps[fs][key] = sprite;
} }
void SpriteFontCache::InitializeUnicodeGlyphMap() /**
* Initialize the glyph map for a font size.
* This populates the glyph map with the baseset font sprites.
* @param fs Font size to initialize.
*/
void InitializeUnicodeGlyphMap(FontSize fs)
{ {
/* Clear out existing glyph map if it exists */ /* Clear out existing glyph map if it exists */
this->char_map.clear(); _char_maps[fs].clear();
SpriteID base; SpriteID base;
switch (this->fs) { switch (fs) {
default: NOT_REACHED(); default: NOT_REACHED();
case FS_MONO: // Use normal as default for mono spaced font case FS_MONO: // Use normal as default for mono spaced font
case FS_NORMAL: base = SPR_ASCII_SPACE; break; case FS_NORMAL: base = SPR_ASCII_SPACE; break;
@ -76,24 +79,45 @@ void SpriteFontCache::InitializeUnicodeGlyphMap()
for (uint i = ASCII_LETTERSTART; i < 256; i++) { for (uint i = ASCII_LETTERSTART; i < 256; i++) {
SpriteID sprite = base + i - ASCII_LETTERSTART; SpriteID sprite = base + i - ASCII_LETTERSTART;
if (!SpriteExists(sprite)) continue; if (!SpriteExists(sprite)) continue;
this->SetUnicodeGlyph(i, sprite); SetUnicodeGlyph(fs, i, sprite);
this->SetUnicodeGlyph(i + SCC_SPRITE_START, sprite); SetUnicodeGlyph(fs, i + SCC_SPRITE_START, sprite);
} }
/* Modify map to move non-standard glyphs to a better unicode codepoint. */
for (const auto &unicode_map : _default_unicode_map) { for (const auto &unicode_map : _default_unicode_map) {
uint8_t key = unicode_map.key; uint8_t key = unicode_map.key;
if (key == CLRA) { if (key == CLRA) {
/* Clear the glyph. This happens if the glyph at this code point /* Clear the glyph. This happens if the glyph at this code point
* is non-standard and should be accessed by an SCC_xxx enum * is non-standard and should be accessed by an SCC_xxx enum
* entry only. */ * entry only. */
this->SetUnicodeGlyph(unicode_map.code, 0); SetUnicodeGlyph(fs, unicode_map.code, 0);
} else { } else {
SpriteID sprite = base + key - ASCII_LETTERSTART; SpriteID sprite = base + key - ASCII_LETTERSTART;
this->SetUnicodeGlyph(unicode_map.code, sprite); SetUnicodeGlyph(fs, unicode_map.code, sprite);
} }
} }
} }
/**
* Initialize the glyph map.
*/
void InitializeUnicodeGlyphMap()
{
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
InitializeUnicodeGlyphMap(fs);
}
}
/**
* Create a new sprite font cache.
* @param fs The font size to create the cache for.
*/
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs)
{
this->height = ScaleGUITrad(FontCache::GetDefaultFontHeight(this->fs));
this->ascender = (this->height - ScaleFontTrad(FontCache::GetDefaultFontHeight(this->fs))) / 2;
}
void SpriteFontCache::ClearFontCache() void SpriteFontCache::ClearFontCache()
{ {
Layouter::ResetFontCache(this->fs); Layouter::ResetFontCache(this->fs);
@ -104,21 +128,21 @@ void SpriteFontCache::ClearFontCache()
const Sprite *SpriteFontCache::GetGlyph(GlyphID key) const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
{ {
SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH); SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH);
if (sprite == 0) sprite = this->GetUnicodeGlyph('?'); if (sprite == 0) sprite = GetUnicodeGlyph(this->fs, '?');
return GetSprite(sprite, SpriteType::Font); return GetSprite(sprite, SpriteType::Font);
} }
uint SpriteFontCache::GetGlyphWidth(GlyphID key) uint SpriteFontCache::GetGlyphWidth(GlyphID key)
{ {
SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH); SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH);
if (sprite == 0) sprite = this->GetUnicodeGlyph('?'); if (sprite == 0) sprite = GetUnicodeGlyph(this->fs, '?');
return SpriteExists(sprite) ? GetSprite(sprite, SpriteType::Font)->width + ScaleFontTrad(this->fs != FS_NORMAL ? 1 : 0) : 0; return SpriteExists(sprite) ? GetSprite(sprite, SpriteType::Font)->width + ScaleFontTrad(this->fs != FS_NORMAL ? 1 : 0) : 0;
} }
GlyphID SpriteFontCache::MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback) GlyphID SpriteFontCache::MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback)
{ {
assert(IsPrintable(key)); assert(IsPrintable(key));
SpriteID sprite = this->GetUnicodeGlyph(key); SpriteID sprite = GetUnicodeGlyph(this->fs, key);
if (sprite == 0) return 0; if (sprite == 0) return 0;
return SPRITE_GLYPH | sprite; return SPRITE_GLYPH | sprite;
} }

View File

@ -10,15 +10,12 @@
#ifndef SPRITEFONTCACHE_H #ifndef SPRITEFONTCACHE_H
#define SPRITEFONTCACHE_H #define SPRITEFONTCACHE_H
#include "../string_func.h"
#include "../fontcache.h" #include "../fontcache.h"
/** Font cache for fonts that are based on a freetype font. */ /** Font cache for fonts that are based on a freetype font. */
class SpriteFontCache : public FontCache { class SpriteFontCache : public FontCache {
public: public:
SpriteFontCache(FontSize fs); SpriteFontCache(FontSize fs);
void SetUnicodeGlyph(char32_t key, SpriteID sprite) override;
void InitializeUnicodeGlyphMap() override;
void ClearFontCache() override; void ClearFontCache() override;
const Sprite *GetGlyph(GlyphID key) override; const Sprite *GetGlyph(GlyphID key) override;
uint GetGlyphWidth(GlyphID key) override; uint GetGlyphWidth(GlyphID key) override;
@ -26,10 +23,6 @@ public:
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override; GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override;
std::string GetFontName() override { return "sprite"; } std::string GetFontName() override { return "sprite"; }
bool IsBuiltInFont() override { return true; } bool IsBuiltInFont() override { return true; }
private:
std::unordered_map<char32_t, SpriteID> char_map{}; ///< Mapping of characters to sprite IDs.
SpriteID GetUnicodeGlyph(char32_t key);
}; };
#endif /* SPRITEFONTCACHE_H */ #endif /* SPRITEFONTCACHE_H */

View File

@ -46,8 +46,6 @@ public:
TrueTypeFontCache(FontSize fs, int pixels); TrueTypeFontCache(FontSize fs, int pixels);
virtual ~TrueTypeFontCache(); virtual ~TrueTypeFontCache();
int GetFontSize() const override { return this->used_size; } int GetFontSize() const override { return this->used_size; }
void SetUnicodeGlyph(char32_t key, SpriteID sprite) override { this->parent->SetUnicodeGlyph(key, sprite); }
void InitializeUnicodeGlyphMap() override { this->parent->InitializeUnicodeGlyphMap(); }
const Sprite *GetGlyph(GlyphID key) override; const Sprite *GetGlyph(GlyphID key) override;
void ClearFontCache() override; void ClearFontCache() override;
uint GetGlyphWidth(GlyphID key) override; uint GetGlyphWidth(GlyphID key) override;

View File

@ -867,9 +867,9 @@ struct FrametimeGraphWindow : Window {
const int x_max = r.right; const int x_max = r.right;
const int y_zero = r.top + (int)this->graph_size.height; const int y_zero = r.top + (int)this->graph_size.height;
const int y_max = r.top; const int y_max = r.top;
const int c_grid = PC_DARK_GREY; const PixelColour c_grid = PC_DARK_GREY;
const int c_lines = PC_BLACK; const PixelColour c_lines = PC_BLACK;
const int c_peak = PC_DARK_RED; const PixelColour c_peak = PC_DARK_RED;
const TimingMeasurement draw_horz_scale = (TimingMeasurement)this->horizontal_scale * TIMESTAMP_PRECISION / 2; const TimingMeasurement draw_horz_scale = (TimingMeasurement)this->horizontal_scale * TIMESTAMP_PRECISION / 2;
const TimingMeasurement draw_vert_scale = (TimingMeasurement)this->vertical_scale; const TimingMeasurement draw_vert_scale = (TimingMeasurement)this->vertical_scale;
@ -959,7 +959,7 @@ struct FrametimeGraphWindow : Window {
/* If the peak value is significantly larger than the average, mark and label it */ /* If the peak value is significantly larger than the average, mark and label it */
if (points_drawn > 0 && peak_value > TIMESTAMP_PRECISION / 100 && 2 * peak_value > 3 * value_sum / points_drawn) { if (points_drawn > 0 && peak_value > TIMESTAMP_PRECISION / 100 && 2 * peak_value > 3 * value_sum / points_drawn) {
TextColour tc_peak = (TextColour)(TC_IS_PALETTE_COLOUR | c_peak); TextColour tc_peak = c_peak.ToTextColour();
GfxFillRect(peak_point.x - 1, peak_point.y - 1, peak_point.x + 1, peak_point.y + 1, c_peak); GfxFillRect(peak_point.x - 1, peak_point.y - 1, peak_point.x + 1, peak_point.y + 1, c_peak);
uint64_t value = peak_value * 1000 / TIMESTAMP_PRECISION; uint64_t value = peak_value * 1000 / TIMESTAMP_PRECISION;
int label_y = std::max(y_max, peak_point.y - GetCharacterHeight(FS_SMALL)); int label_y = std::max(y_max, peak_point.y - GetCharacterHeight(FS_SMALL));

View File

@ -113,7 +113,7 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo)
* FILLRECT_CHECKER: Like FILLRECT_OPAQUE, but only draw every second pixel (used to grey out things) * FILLRECT_CHECKER: Like FILLRECT_OPAQUE, but only draw every second pixel (used to grey out things)
* FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the rectangle currently on screen * FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the rectangle currently on screen
*/ */
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode) void GfxFillRect(int left, int top, int right, int bottom, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode)
{ {
Blitter *blitter = BlitterFactory::GetCurrentBlitter(); Blitter *blitter = BlitterFactory::GetCurrentBlitter();
const DrawPixelInfo *dpi = _cur_dpi; const DrawPixelInfo *dpi = _cur_dpi;
@ -142,17 +142,18 @@ void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectM
switch (mode) { switch (mode) {
default: // FILLRECT_OPAQUE default: // FILLRECT_OPAQUE
blitter->DrawRect(dst, right, bottom, (uint8_t)colour); blitter->DrawRect(dst, right, bottom, std::get<PixelColour>(colour));
break; break;
case FILLRECT_RECOLOUR: case FILLRECT_RECOLOUR:
blitter->DrawColourMappingRect(dst, right, bottom, GB(colour, 0, PALETTE_WIDTH)); blitter->DrawColourMappingRect(dst, right, bottom, GB(std::get<PaletteID>(colour), 0, PALETTE_WIDTH));
break; break;
case FILLRECT_CHECKER: { case FILLRECT_CHECKER: {
uint8_t bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1; uint8_t bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
PixelColour pc = std::get<PixelColour>(colour);
do { do {
for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8_t)colour); for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, pc);
dst = blitter->MoveTo(dst, 0, 1); dst = blitter->MoveTo(dst, 0, 1);
} while (--bottom > 0); } while (--bottom > 0);
break; break;
@ -209,7 +210,7 @@ static std::vector<LineSegment> MakePolygonSegments(std::span<const Point> shape
* FILLRECT_CHECKER: Fill every other pixel with the specified colour, in a checkerboard pattern. * FILLRECT_CHECKER: Fill every other pixel with the specified colour, in a checkerboard pattern.
* FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the polygon. * FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the polygon.
*/ */
void GfxFillPolygon(std::span<const Point> shape, int colour, FillRectMode mode) void GfxFillPolygon(std::span<const Point> shape, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode)
{ {
Blitter *blitter = BlitterFactory::GetCurrentBlitter(); Blitter *blitter = BlitterFactory::GetCurrentBlitter();
const DrawPixelInfo *dpi = _cur_dpi; const DrawPixelInfo *dpi = _cur_dpi;
@ -278,18 +279,20 @@ void GfxFillPolygon(std::span<const Point> shape, int colour, FillRectMode mode)
void *dst = blitter->MoveTo(dpi->dst_ptr, x1, y); void *dst = blitter->MoveTo(dpi->dst_ptr, x1, y);
switch (mode) { switch (mode) {
default: // FILLRECT_OPAQUE default: // FILLRECT_OPAQUE
blitter->DrawRect(dst, x2 - x1, 1, (uint8_t)colour); blitter->DrawRect(dst, x2 - x1, 1, std::get<PixelColour>(colour));
break; break;
case FILLRECT_RECOLOUR: case FILLRECT_RECOLOUR:
blitter->DrawColourMappingRect(dst, x2 - x1, 1, GB(colour, 0, PALETTE_WIDTH)); blitter->DrawColourMappingRect(dst, x2 - x1, 1, GB(std::get<PaletteID>(colour), 0, PALETTE_WIDTH));
break; break;
case FILLRECT_CHECKER: case FILLRECT_CHECKER: {
/* Fill every other pixel, offset such that the sum of filled pixels' X and Y coordinates is odd. /* Fill every other pixel, offset such that the sum of filled pixels' X and Y coordinates is odd.
* This creates a checkerboard effect. */ * This creates a checkerboard effect. */
PixelColour pc = std::get<PixelColour>(colour);
for (int x = (x1 + y) & 1; x < x2 - x1; x += 2) { for (int x = (x1 + y) & 1; x < x2 - x1; x += 2) {
blitter->SetPixel(dst, x, 0, (uint8_t)colour); blitter->SetPixel(dst, x, 0, pc);
} }
break; break;
}
} }
} }
@ -312,7 +315,7 @@ void GfxFillPolygon(std::span<const Point> shape, int colour, FillRectMode mode)
* @param width Width of the line. * @param width Width of the line.
* @param dash Length of dashes for dashed lines. 0 means solid line. * @param dash Length of dashes for dashed lines. 0 means solid line.
*/ */
static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash = 0) static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash = 0)
{ {
Blitter *blitter = BlitterFactory::GetCurrentBlitter(); Blitter *blitter = BlitterFactory::GetCurrentBlitter();
@ -385,7 +388,7 @@ static inline bool GfxPreprocessLine(DrawPixelInfo *dpi, int &x, int &y, int &x2
return true; return true;
} }
void GfxDrawLine(int x, int y, int x2, int y2, int colour, int width, int dash) void GfxDrawLine(int x, int y, int x2, int y2, PixelColour colour, int width, int dash)
{ {
DrawPixelInfo *dpi = _cur_dpi; DrawPixelInfo *dpi = _cur_dpi;
if (GfxPreprocessLine(dpi, x, y, x2, y2, width)) { if (GfxPreprocessLine(dpi, x, y, x2, y2, width)) {
@ -393,7 +396,7 @@ void GfxDrawLine(int x, int y, int x2, int y2, int colour, int width, int dash)
} }
} }
void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int colour) void GfxDrawLineUnscaled(int x, int y, int x2, int y2, PixelColour colour)
{ {
DrawPixelInfo *dpi = _cur_dpi; DrawPixelInfo *dpi = _cur_dpi;
if (GfxPreprocessLine(dpi, x, y, x2, y2, 1)) { if (GfxPreprocessLine(dpi, x, y, x2, y2, 1)) {
@ -434,7 +437,7 @@ void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
* ....V. * ....V.
*/ */
static const uint8_t colour = PC_WHITE; static constexpr PixelColour colour = PC_WHITE;
GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour); GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour);
GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour); GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour);
@ -455,7 +458,7 @@ void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
* @param width Width of the outline. * @param width Width of the outline.
* @param dash Length of dashes for dashed lines. 0 means solid lines. * @param dash Length of dashes for dashed lines. 0 means solid lines.
*/ */
void DrawRectOutline(const Rect &r, int colour, int width, int dash) void DrawRectOutline(const Rect &r, PixelColour colour, int width, int dash)
{ {
GfxDrawLine(r.left, r.top, r.right, r.top, colour, width, dash); GfxDrawLine(r.left, r.top, r.right, r.top, colour, width, dash);
GfxDrawLine(r.left, r.top, r.left, r.bottom, colour, width, dash); GfxDrawLine(r.left, r.top, r.left, r.bottom, colour, width, dash);
@ -477,7 +480,7 @@ static void SetColourRemap(TextColour colour)
bool raw_colour = (colour & TC_IS_PALETTE_COLOUR) != 0; bool raw_colour = (colour & TC_IS_PALETTE_COLOUR) != 0;
colour &= ~(TC_NO_SHADE | TC_IS_PALETTE_COLOUR | TC_FORCED); colour &= ~(TC_NO_SHADE | TC_IS_PALETTE_COLOUR | TC_FORCED);
_string_colourremap[1] = raw_colour ? (uint8_t)colour : _string_colourmap[colour]; _string_colourremap[1] = raw_colour ? (uint8_t)colour : _string_colourmap[colour].p;
_string_colourremap[2] = no_shade ? 0 : 1; _string_colourremap[2] = no_shade ? 0 : 1;
_colour_remap_ptr = _string_colourremap; _colour_remap_ptr = _string_colourremap;
} }
@ -637,7 +640,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
} }
if (underline) { if (underline) {
GfxFillRect(left, y + h, right, y + h + WidgetDimensions::scaled.bevel.top - 1, _string_colourremap[1]); GfxFillRect(left, y + h, right, y + h + WidgetDimensions::scaled.bevel.top - 1, PixelColour{_string_colourremap[1]});
} }
return (align & SA_HOR_MASK) == SA_RIGHT ? left : right; return (align & SA_HOR_MASK) == SA_RIGHT ? left : right;

View File

@ -103,11 +103,11 @@ bool DrawStringMultiLineWithClipping(int left, int right, int top, int bottom, s
void DrawCharCentered(char32_t c, const Rect &r, TextColour colour); void DrawCharCentered(char32_t c, const Rect &r, TextColour colour);
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode = FILLRECT_OPAQUE); void GfxFillRect(int left, int top, int right, int bottom, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode = FILLRECT_OPAQUE);
void GfxFillPolygon(std::span<const Point> shape, int colour, FillRectMode mode = FILLRECT_OPAQUE); void GfxFillPolygon(std::span<const Point> shape, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode = FILLRECT_OPAQUE);
void GfxDrawLine(int left, int top, int right, int bottom, int colour, int width = 1, int dash = 0); void GfxDrawLine(int left, int top, int right, int bottom, PixelColour colour, int width = 1, int dash = 0);
void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3); void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3);
void DrawRectOutline(const Rect &r, int colour, int width = 1, int dash = 0); void DrawRectOutline(const Rect &r, PixelColour colour, int width = 1, int dash = 0);
/* Versions of DrawString/DrawStringMultiLine that accept a Rect instead of separate left, right, top and bottom parameters. */ /* Versions of DrawString/DrawStringMultiLine that accept a Rect instead of separate left, right, top and bottom parameters. */
inline int DrawString(const Rect &r, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL) inline int DrawString(const Rect &r, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL)
@ -135,7 +135,7 @@ inline bool DrawStringMultiLineWithClipping(const Rect &r, std::string_view str,
return DrawStringMultiLineWithClipping(r.left, r.right, r.top, r.bottom, str, colour, align, underline, fontsize); return DrawStringMultiLineWithClipping(r.left, r.right, r.top, r.bottom, str, colour, align, underline, fontsize);
} }
inline void GfxFillRect(const Rect &r, int colour, FillRectMode mode = FILLRECT_OPAQUE) inline void GfxFillRect(const Rect &r, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode = FILLRECT_OPAQUE)
{ {
GfxFillRect(r.left, r.top, r.right, r.bottom, colour, mode); GfxFillRect(r.left, r.top, r.right, r.bottom, colour, mode);
} }

View File

@ -245,7 +245,6 @@ using Colour = std::conditional_t<std::endian::native == std::endian::little, Co
static_assert(sizeof(Colour) == sizeof(uint32_t)); static_assert(sizeof(Colour) == sizeof(uint32_t));
/** Available font sizes */ /** Available font sizes */
enum FontSize : uint8_t { enum FontSize : uint8_t {
FS_NORMAL, ///< Index of the normal font in the font tables. FS_NORMAL, ///< Index of the normal font in the font tables.
@ -403,4 +402,14 @@ enum StringAlignment : uint8_t {
}; };
DECLARE_ENUM_AS_BIT_SET(StringAlignment) DECLARE_ENUM_AS_BIT_SET(StringAlignment)
/** Colour for pixel/line drawing. */
struct PixelColour {
uint8_t p; ///< Palette index.
constexpr PixelColour() : p(0) {}
explicit constexpr PixelColour(uint8_t p) : p(p) {}
constexpr inline TextColour ToTextColour() const { return static_cast<TextColour>(this->p) | TC_IS_PALETTE_COLOUR; }
};
#endif /* GFX_TYPE_H */ #endif /* GFX_TYPE_H */

View File

@ -165,11 +165,11 @@ struct ValuesInterval {
struct BaseGraphWindow : Window { struct BaseGraphWindow : Window {
protected: protected:
static const int GRAPH_MAX_DATASETS = 64; static const int GRAPH_MAX_DATASETS = 64;
static const int GRAPH_BASE_COLOUR = GREY_SCALE(2); static constexpr PixelColour GRAPH_BASE_COLOUR = GREY_SCALE(2);
static const int GRAPH_GRID_COLOUR = GREY_SCALE(3); static constexpr PixelColour GRAPH_GRID_COLOUR = GREY_SCALE(3);
static const int GRAPH_AXIS_LINE_COLOUR = GREY_SCALE(1); static constexpr PixelColour GRAPH_AXIS_LINE_COLOUR = GREY_SCALE(1);
static const int GRAPH_ZERO_LINE_COLOUR = GREY_SCALE(8); static constexpr PixelColour GRAPH_ZERO_LINE_COLOUR = GREY_SCALE(8);
static const int GRAPH_YEAR_LINE_COLOUR = GREY_SCALE(5); static constexpr PixelColour GRAPH_YEAR_LINE_COLOUR = GREY_SCALE(5);
static const int GRAPH_NUM_MONTHS = 24; ///< Number of months displayed in the graph. static const int GRAPH_NUM_MONTHS = 24; ///< Number of months displayed in the graph.
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".
@ -204,7 +204,7 @@ protected:
struct DataSet { struct DataSet {
std::array<OverflowSafeInt64, GRAPH_NUM_MONTHS> values; std::array<OverflowSafeInt64, GRAPH_NUM_MONTHS> values;
uint8_t colour; PixelColour colour;
uint8_t exclude_bit; uint8_t exclude_bit;
uint8_t range_bit; uint8_t range_bit;
uint8_t dash; uint8_t dash;
@ -398,7 +398,7 @@ protected:
/* Draw the grid lines. */ /* Draw the grid lines. */
int gridline_width = WidgetDimensions::scaled.bevel.top; int gridline_width = WidgetDimensions::scaled.bevel.top;
int grid_colour = GRAPH_GRID_COLOUR; PixelColour grid_colour = GRAPH_GRID_COLOUR;
/* Don't draw the first line, as that's where the axis will be. */ /* Don't draw the first line, as that's where the axis will be. */
if (rtl) { if (rtl) {
@ -524,7 +524,7 @@ protected:
uint pointoffs1 = pointwidth / 2; uint pointoffs1 = pointwidth / 2;
uint pointoffs2 = pointwidth - pointoffs1; uint pointoffs2 = pointwidth - pointoffs1;
auto draw_dataset = [&](const DataSet &dataset, uint8_t colour) { auto draw_dataset = [&](const DataSet &dataset, PixelColour colour) {
if (HasBit(this->excluded_data, dataset.exclude_bit)) return; if (HasBit(this->excluded_data, dataset.exclude_bit)) return;
if (HasBit(this->excluded_range, dataset.range_bit)) return; if (HasBit(this->excluded_range, dataset.range_bit)) return;
@ -1132,7 +1132,7 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
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);
this->vscroll->SetCount(CountBits(this->cargo_types)); this->vscroll->SetCount(this->cargo_types.Count());
auto *wid = this->GetWidget<NWidgetCore>(WID_GRAPH_FOOTER); auto *wid = this->GetWidget<NWidgetCore>(WID_GRAPH_FOOTER);
wid->SetString(TimerGameEconomy::UsingWallclockUnits() ? footer_wallclock : footer_calendar); wid->SetString(TimerGameEconomy::UsingWallclockUnits() ? footer_wallclock : footer_calendar);
@ -1152,10 +1152,10 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
if (row >= this->vscroll->GetCount()) return std::nullopt; if (row >= this->vscroll->GetCount()) return std::nullopt;
for (const CargoSpec *cs : _sorted_cargo_specs) { for (const CargoSpec *cs : _sorted_cargo_specs) {
if (!HasBit(this->cargo_types, cs->Index())) continue; if (!this->cargo_types.Test(cs->Index())) continue;
if (row-- > 0) continue; if (row-- > 0) continue;
return cs->Index(); return cs->Index().base();
} }
return std::nullopt; return std::nullopt;
@ -1176,7 +1176,7 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
size.height = GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical(); size.height = GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical();
for (CargoType cargo_type : SetCargoBitIterator(this->cargo_types)) { for (CargoType cargo_type : this->cargo_types) {
const CargoSpec *cs = CargoSpec::Get(cargo_type); const CargoSpec *cs = CargoSpec::Get(cargo_type);
Dimension d = GetStringBoundingBox(GetString(STR_GRAPH_CARGO_PAYMENT_CARGO, cs->name)); Dimension d = GetStringBoundingBox(GetString(STR_GRAPH_CARGO_PAYMENT_CARGO, cs->name));
@ -1207,12 +1207,12 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
Rect line = r.WithHeight(this->line_height); Rect line = r.WithHeight(this->line_height);
for (const CargoSpec *cs : _sorted_cargo_specs) { for (const CargoSpec *cs : _sorted_cargo_specs) {
if (!HasBit(this->cargo_types, cs->Index())) continue; if (!this->cargo_types.Test(cs->Index())) continue;
if (pos-- > 0) continue; if (pos-- > 0) continue;
if (--max < 0) break; if (--max < 0) break;
bool lowered = !HasBit(this->excluded_data, cs->Index()); bool lowered = !HasBit(this->excluded_data, cs->Index().base());
/* Redraw frame if lowered */ /* Redraw frame if lowered */
if (lowered) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered); if (lowered) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered);
@ -1222,7 +1222,7 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
/* Cargo-colour box with outline */ /* Cargo-colour box with outline */
const Rect cargo = text.WithWidth(this->legend_width, rtl); const Rect cargo = text.WithWidth(this->legend_width, rtl);
GfxFillRect(cargo, PC_BLACK); GfxFillRect(cargo, PC_BLACK);
uint8_t pc = cs->legend_colour; PixelColour pc = cs->legend_colour;
if (this->highlight_data == cs->Index()) pc = this->highlight_state ? PC_WHITE : PC_BLACK; if (this->highlight_data == cs->Index()) pc = this->highlight_state ? PC_WHITE : PC_BLACK;
GfxFillRect(cargo.Shrink(WidgetDimensions::scaled.bevel), pc); GfxFillRect(cargo.Shrink(WidgetDimensions::scaled.bevel), pc);
@ -1239,14 +1239,14 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
case WID_GRAPH_ENABLE_CARGOES: case WID_GRAPH_ENABLE_CARGOES:
/* Remove all cargoes from the excluded lists. */ /* Remove all cargoes from the excluded lists. */
this->GetExcludedCargoTypes() = {}; this->GetExcludedCargoTypes() = {};
this->excluded_data = this->GetExcludedCargoTypes(); this->excluded_data = this->GetExcludedCargoTypes().base();
this->SetDirty(); this->SetDirty();
break; break;
case WID_GRAPH_DISABLE_CARGOES: { case WID_GRAPH_DISABLE_CARGOES: {
/* Add all cargoes to the excluded lists. */ /* Add all cargoes to the excluded lists. */
this->GetExcludedCargoTypes() = this->cargo_types; this->GetExcludedCargoTypes() = this->cargo_types;
this->excluded_data = this->GetExcludedCargoTypes(); this->excluded_data = this->GetExcludedCargoTypes().base();
this->SetDirty(); this->SetDirty();
break; break;
} }
@ -1256,11 +1256,11 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
if (row >= this->vscroll->GetCount()) return; if (row >= this->vscroll->GetCount()) return;
for (const CargoSpec *cs : _sorted_cargo_specs) { for (const CargoSpec *cs : _sorted_cargo_specs) {
if (!HasBit(this->cargo_types, cs->Index())) continue; if (!this->cargo_types.Test(cs->Index())) continue;
if (row-- > 0) continue; if (row-- > 0) continue;
ToggleBit(this->GetExcludedCargoTypes(), cs->Index()); this->GetExcludedCargoTypes().Flip(cs->Index());
this->excluded_data = this->GetExcludedCargoTypes(); this->excluded_data = this->GetExcludedCargoTypes().base();
this->SetDirty(); this->SetDirty();
break; break;
} }
@ -1332,13 +1332,13 @@ struct PaymentRatesGraphWindow : BaseCargoGraphWindow {
*/ */
void UpdatePaymentRates() void UpdatePaymentRates()
{ {
this->excluded_data = this->GetExcludedCargoTypes(); this->excluded_data = this->GetExcludedCargoTypes().base();
this->data.clear(); this->data.clear();
for (const CargoSpec *cs : _sorted_standard_cargo_specs) { for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
DataSet &dataset = this->data.emplace_back(); DataSet &dataset = this->data.emplace_back();
dataset.colour = cs->legend_colour; dataset.colour = cs->legend_colour;
dataset.exclude_bit = cs->Index(); dataset.exclude_bit = cs->Index().base();
for (uint j = 0; j != this->num_on_x_axis; j++) { for (uint j = 0; j != this->num_on_x_axis; j++) {
dataset.values[j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, cs->Index()); dataset.values[j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, cs->Index());
@ -1499,8 +1499,8 @@ struct PerformanceRatingDetailWindow : Window {
ScoreID score_type = (ScoreID)(widget - WID_PRD_SCORE_FIRST); ScoreID score_type = (ScoreID)(widget - WID_PRD_SCORE_FIRST);
/* The colours used to show how the progress is going */ /* The colours used to show how the progress is going */
int colour_done = GetColourGradient(COLOUR_GREEN, SHADE_NORMAL); PixelColour colour_done = GetColourGradient(COLOUR_GREEN, SHADE_NORMAL);
int colour_notdone = GetColourGradient(COLOUR_RED, SHADE_NORMAL); PixelColour colour_notdone = GetColourGradient(COLOUR_RED, SHADE_NORMAL);
/* Draw all the score parts */ /* Draw all the score parts */
int64_t val = _score_part[company][score_type]; int64_t val = _score_part[company][score_type];
@ -1654,7 +1654,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
if (IsValidCargoType(a.cargo)) SetBit(cargo_types, a.cargo); 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)) cargo_types.Set(p.cargo);
} }
return cargo_types; return cargo_types;
} }
@ -1680,12 +1680,12 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
mo += 12; mo += 12;
} }
if (!initialize && this->excluded_data == this->GetExcludedCargoTypes() && this->num_on_x_axis == this->num_vert_lines && this->year == yr && this->month == mo) { if (!initialize && this->excluded_data == this->GetExcludedCargoTypes().base() && this->num_on_x_axis == this->num_vert_lines && this->year == yr && this->month == mo) {
/* There's no reason to get new stats */ /* There's no reason to get new stats */
return; return;
} }
this->excluded_data = this->GetExcludedCargoTypes(); this->excluded_data = this->GetExcludedCargoTypes().base();
this->year = yr; this->year = yr;
this->month = mo; this->month = mo;
@ -1700,13 +1700,13 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
DataSet &produced = this->data.emplace_back(); DataSet &produced = this->data.emplace_back();
produced.colour = cs->legend_colour; produced.colour = cs->legend_colour;
produced.exclude_bit = cs->Index(); produced.exclude_bit = cs->Index().base();
produced.range_bit = 0; produced.range_bit = 0;
auto produced_filler = Filler{produced, &Industry::ProducedHistory::production}; auto produced_filler = Filler{produced, &Industry::ProducedHistory::production};
DataSet &transported = this->data.emplace_back(); DataSet &transported = this->data.emplace_back();
transported.colour = cs->legend_colour; transported.colour = cs->legend_colour;
transported.exclude_bit = cs->Index(); transported.exclude_bit = cs->Index().base();
transported.range_bit = 1; transported.range_bit = 1;
transported.dash = 2; transported.dash = 2;
auto transported_filler = Filler{transported, &Industry::ProducedHistory::transported}; auto transported_filler = Filler{transported, &Industry::ProducedHistory::transported};

View File

@ -305,7 +305,7 @@ private:
const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2; const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2;
const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent; const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent;
const int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL); const PixelColour linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
if (indent > 0) { if (indent > 0) {
/* Draw tree continuation lines. */ /* Draw tree continuation lines. */
@ -708,7 +708,7 @@ public:
return; return;
case WID_GL_FILTER_BY_CARGO: // Select filtering criteria dropdown menu case WID_GL_FILTER_BY_CARGO: // Select filtering criteria dropdown menu
ShowDropDownList(this, this->BuildCargoDropDownList(false), this->cargo_filter_criteria, widget); ShowDropDownList(this, this->BuildCargoDropDownList(false), this->cargo_filter_criteria.base(), widget);
break; break;
case WID_GL_ALL_VEHICLES: // All vehicles button case WID_GL_ALL_VEHICLES: // All vehicles button
@ -999,7 +999,7 @@ public:
break; break;
case WID_GL_FILTER_BY_CARGO: // Select a cargo filter criteria case WID_GL_FILTER_BY_CARGO: // Select a cargo filter criteria
this->SetCargoFilter(index); this->SetCargoFilter(static_cast<CargoType>(index));
break; break;
case WID_GL_MANAGE_VEHICLES_DROPDOWN: case WID_GL_MANAGE_VEHICLES_DROPDOWN:

View File

@ -71,7 +71,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
} }
}; };
struct ProducedCargo { struct ProducedCargo {
CargoType cargo = 0; ///< Cargo type CargoType cargo = INVALID_CARGO; ///< Cargo type
uint16_t waiting = 0; ///< Amount of cargo produced uint16_t waiting = 0; ///< Amount of cargo produced
uint8_t rate = 0; ///< Production rate uint8_t rate = 0; ///< Production rate
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
@ -83,7 +83,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
}; };
struct AcceptedCargo { struct AcceptedCargo {
CargoType cargo = 0; ///< Cargo type CargoType cargo = INVALID_CARGO; ///< 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. 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

View File

@ -464,13 +464,13 @@ static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, Ca
acceptance[cargo] += cargo_acceptance[i]; acceptance[cargo] += cargo_acceptance[i];
/* Maybe set 'always accepted' bit (if it's not set already) */ /* Maybe set 'always accepted' bit (if it's not set already) */
if (HasBit(always_accepted, cargo)) continue; if (always_accepted.Test(cargo)) continue;
/* Test whether the industry itself accepts the cargo type */ /* Test whether the industry itself accepts the cargo type */
if (ind->IsCargoAccepted(cargo)) continue; if (ind->IsCargoAccepted(cargo)) continue;
/* If the industry itself doesn't accept this cargo, set 'always accepted' bit */ /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
SetBit(always_accepted, cargo); always_accepted.Set(cargo);
} }
} }

View File

@ -1289,12 +1289,12 @@ static bool CargoFilter(const Industry * const *industry, const std::pair<CargoT
bool accepted_cargo_matches; bool accepted_cargo_matches;
switch (accepted_cargo) { switch (accepted_cargo.base()) {
case CargoFilterCriteria::CF_ANY: case CargoFilterCriteria::CF_ANY.base():
accepted_cargo_matches = true; accepted_cargo_matches = true;
break; break;
case CargoFilterCriteria::CF_NONE: case CargoFilterCriteria::CF_NONE.base():
accepted_cargo_matches = !(*industry)->IsCargoAccepted(); accepted_cargo_matches = !(*industry)->IsCargoAccepted();
break; break;
@ -1305,12 +1305,12 @@ static bool CargoFilter(const Industry * const *industry, const std::pair<CargoT
bool produced_cargo_matches; bool produced_cargo_matches;
switch (produced_cargo) { switch (produced_cargo.base()) {
case CargoFilterCriteria::CF_ANY: case CargoFilterCriteria::CF_ANY.base():
produced_cargo_matches = true; produced_cargo_matches = true;
break; break;
case CargoFilterCriteria::CF_NONE: case CargoFilterCriteria::CF_NONE.base():
produced_cargo_matches = !(*industry)->IsCargoProduced(); produced_cargo_matches = !(*industry)->IsCargoProduced();
break; break;
@ -1396,9 +1396,9 @@ protected:
StringID GetCargoFilterLabel(CargoType cargo_type) const StringID GetCargoFilterLabel(CargoType cargo_type) const
{ {
switch (cargo_type) { switch (cargo_type.base()) {
case CargoFilterCriteria::CF_ANY: return STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES; case CargoFilterCriteria::CF_ANY.base(): return STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES;
case CargoFilterCriteria::CF_NONE: return STR_INDUSTRY_DIRECTORY_FILTER_NONE; case CargoFilterCriteria::CF_NONE.base(): return STR_INDUSTRY_DIRECTORY_FILTER_NONE;
default: return CargoSpec::Get(cargo_type)->name; default: return CargoSpec::Get(cargo_type)->name;
} }
} }
@ -1776,14 +1776,14 @@ public:
DropDownList list; DropDownList list;
/* Add item for disabling filtering. */ /* Add item for disabling filtering. */
list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY)); list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY.base()));
/* Add item for industries not producing anything, e.g. power plants */ /* Add item for industries not producing anything, e.g. power plants */
list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE)); list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE.base()));
/* Add cargos */ /* Add cargos */
Dimension d = GetLargestCargoIconSize(); Dimension d = GetLargestCargoIconSize();
for (const CargoSpec *cs : _sorted_standard_cargo_specs) { for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index())); list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index().base()));
} }
return list; return list;
@ -1802,11 +1802,11 @@ public:
break; break;
case WID_ID_FILTER_BY_ACC_CARGO: // Cargo filter dropdown case WID_ID_FILTER_BY_ACC_CARGO: // Cargo filter dropdown
ShowDropDownList(this, this->BuildCargoDropDownList(), this->accepted_cargo_filter_criteria, widget); ShowDropDownList(this, this->BuildCargoDropDownList(), this->accepted_cargo_filter_criteria.base(), widget);
break; break;
case WID_ID_FILTER_BY_PROD_CARGO: // Cargo filter dropdown case WID_ID_FILTER_BY_PROD_CARGO: // Cargo filter dropdown
ShowDropDownList(this, this->BuildCargoDropDownList(), this->produced_cargo_filter_criteria, widget); ShowDropDownList(this, this->BuildCargoDropDownList(), this->produced_cargo_filter_criteria.base(), widget);
break; break;
case WID_ID_INDUSTRY_LIST: { case WID_ID_INDUSTRY_LIST: {
@ -1835,13 +1835,13 @@ public:
} }
case WID_ID_FILTER_BY_ACC_CARGO: { case WID_ID_FILTER_BY_ACC_CARGO: {
this->SetAcceptedCargoFilter(index); this->SetAcceptedCargoFilter(static_cast<CargoType>(index));
this->BuildSortIndustriesList(); this->BuildSortIndustriesList();
break; break;
} }
case WID_ID_FILTER_BY_PROD_CARGO: { case WID_ID_FILTER_BY_PROD_CARGO: {
this->SetProducedCargoFilter(index); this->SetProducedCargoFilter(static_cast<CargoType>(index));
this->BuildSortIndustriesList(); this->BuildSortIndustriesList();
break; break;
} }
@ -1986,8 +1986,8 @@ struct CargoesField {
static Dimension cargo_space; static Dimension cargo_space;
static Dimension cargo_stub; static Dimension cargo_stub;
static const int INDUSTRY_LINE_COLOUR; static const PixelColour INDUSTRY_LINE_COLOUR;
static const int CARGO_LINE_COLOUR; static const PixelColour CARGO_LINE_COLOUR;
static int small_height, normal_height; static int small_height, normal_height;
static int cargo_field_width; static int cargo_field_width;
@ -2395,8 +2395,8 @@ int CargoesField::vert_inter_industry_space; ///< Amount of space between two in
int CargoesField::blob_distance; ///< Distance of the industry legend colour from the edge of the industry box. int CargoesField::blob_distance; ///< Distance of the industry legend colour from the edge of the industry box.
const int CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box. const PixelColour CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box.
const int CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo. const PixelColour CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo.
/** A single row of #CargoesField. */ /** A single row of #CargoesField. */
struct CargoesRow { struct CargoesRow {
@ -2648,7 +2648,7 @@ struct IndustryCargoesWindow : public Window {
const IndustrySpec *indsp = GetIndustrySpec(this->ind_cargo); const IndustrySpec *indsp = GetIndustrySpec(this->ind_cargo);
return GetString(STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION, indsp->name); return GetString(STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION, indsp->name);
} else { } else {
const CargoSpec *csp = CargoSpec::Get(this->ind_cargo - NUM_INDUSTRYTYPES); const CargoSpec *csp = CargoSpec::Get(static_cast<CargoType>(this->ind_cargo - NUM_INDUSTRYTYPES));
return GetString(STR_INDUSTRY_CARGOES_CARGO_CAPTION, csp->name); return GetString(STR_INDUSTRY_CARGOES_CARGO_CAPTION, csp->name);
} }
} }
@ -2661,9 +2661,9 @@ struct IndustryCargoesWindow : public Window {
*/ */
static bool HasCommonValidCargo(const std::span<const CargoType> cargoes1, const std::span<const CargoType> cargoes2) static bool HasCommonValidCargo(const std::span<const CargoType> cargoes1, const std::span<const CargoType> cargoes2)
{ {
for (const CargoType cargo_type1 : cargoes1) { for (const CargoType &cargo_type1 : cargoes1) {
if (!IsValidCargoType(cargo_type1)) continue; if (!IsValidCargoType(cargo_type1)) continue;
for (const CargoType cargo_type2 : cargoes2) { for (const CargoType &cargo_type2 : cargoes2) {
if (cargo_type1 == cargo_type2) return true; if (cargo_type1 == cargo_type2) return true;
} }
} }
@ -2677,7 +2677,7 @@ struct IndustryCargoesWindow : public Window {
*/ */
static bool HousesCanSupply(const std::span<const CargoType> cargoes) static bool HousesCanSupply(const std::span<const CargoType> cargoes)
{ {
for (const CargoType cargo_type : cargoes) { for (const CargoType &cargo_type : cargoes) {
if (!IsValidCargoType(cargo_type)) continue; if (!IsValidCargoType(cargo_type)) continue;
TownProductionEffect tpe = CargoSpec::Get(cargo_type)->town_production_effect; TownProductionEffect tpe = CargoSpec::Get(cargo_type)->town_production_effect;
if (tpe == TPE_PASSENGERS || tpe == TPE_MAIL) return true; if (tpe == TPE_PASSENGERS || tpe == TPE_MAIL) return true;
@ -2694,7 +2694,7 @@ struct IndustryCargoesWindow : public Window {
{ {
HouseZones climate_mask = GetClimateMaskForLandscape(); HouseZones climate_mask = GetClimateMaskForLandscape();
for (const CargoType cargo_type : cargoes) { for (const CargoType &cargo_type : cargoes) {
if (!IsValidCargoType(cargo_type)) continue; if (!IsValidCargoType(cargo_type)) continue;
for (const auto &hs : HouseSpec::Specs()) { for (const auto &hs : HouseSpec::Specs()) {
@ -2875,7 +2875,7 @@ struct IndustryCargoesWindow : public Window {
*/ */
void ComputeCargoDisplay(CargoType cargo_type) void ComputeCargoDisplay(CargoType cargo_type)
{ {
this->ind_cargo = cargo_type + NUM_INDUSTRYTYPES; this->ind_cargo = cargo_type.base() + NUM_INDUSTRYTYPES;
_displayed_industries.reset(); _displayed_industries.reset();
this->fields.clear(); this->fields.clear();
@ -3088,7 +3088,7 @@ struct IndustryCargoesWindow : public Window {
DropDownList lst; DropDownList lst;
Dimension d = GetLargestCargoIconSize(); Dimension d = GetLargestCargoIconSize();
for (const CargoSpec *cs : _sorted_standard_cargo_specs) { for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
lst.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index())); lst.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index().base()));
} }
if (!lst.empty()) { if (!lst.empty()) {
int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? (int)(this->ind_cargo - NUM_INDUSTRYTYPES) : -1; int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? (int)(this->ind_cargo - NUM_INDUSTRYTYPES) : -1;
@ -3119,7 +3119,7 @@ struct IndustryCargoesWindow : public Window {
switch (widget) { switch (widget) {
case WID_IC_CARGO_DROPDOWN: case WID_IC_CARGO_DROPDOWN:
this->ComputeCargoDisplay(index); this->ComputeCargoDisplay(static_cast<CargoType>(index));
break; break;
case WID_IC_IND_DROPDOWN: case WID_IC_IND_DROPDOWN:

View File

@ -119,7 +119,7 @@ struct IndustrySpec {
IndustryLifeTypes life_type; ///< This is also known as Industry production flag, in newgrf specs IndustryLifeTypes life_type; ///< This is also known as Industry production flag, in newgrf specs
LandscapeTypes climate_availability; ///< Bitmask, giving landscape enums as bit position LandscapeTypes climate_availability; ///< Bitmask, giving landscape enums as bit position
IndustryBehaviours behaviour; ///< How this industry will behave, and how others entities can use it IndustryBehaviours behaviour; ///< How this industry will behave, and how others entities can use it
uint8_t map_colour; ///< colour used for the small map PixelColour map_colour; ///< colour used for the small map
StringID name; ///< Displayed name of the industry StringID name; ///< Displayed name of the industry
StringID new_industry_text; ///< Message appearing when the industry is built StringID new_industry_text; ///< Message appearing when the industry is built
StringID closure_text; ///< Message appearing when the industry closes StringID closure_text; ///< Message appearing when the industry closes

View File

@ -30,26 +30,26 @@
* Colours for the various "load" states of links. Ordered from "unused" to * Colours for the various "load" states of links. Ordered from "unused" to
* "overloaded". * "overloaded".
*/ */
const uint8_t LinkGraphOverlay::LINK_COLOURS[][12] = { const PixelColour LinkGraphOverlay::LINK_COLOURS[][12] = {
{ {
0x0f, 0xd1, 0xd0, 0x57, PixelColour{0x0f}, PixelColour{0xd1}, PixelColour{0xd0}, PixelColour{0x57},
0x55, 0x53, 0xbf, 0xbd, PixelColour{0x55}, PixelColour{0x53}, PixelColour{0xbf}, PixelColour{0xbd},
0xba, 0xb9, 0xb7, 0xb5 PixelColour{0xba}, PixelColour{0xb9}, PixelColour{0xb7}, PixelColour{0xb5}
}, },
{ {
0x0f, 0xd1, 0xd0, 0x57, PixelColour{0x0f}, PixelColour{0xd1}, PixelColour{0xd0}, PixelColour{0x57},
0x55, 0x53, 0x96, 0x95, PixelColour{0x55}, PixelColour{0x53}, PixelColour{0x96}, PixelColour{0x95},
0x94, 0x93, 0x92, 0x91 PixelColour{0x94}, PixelColour{0x93}, PixelColour{0x92}, PixelColour{0x91}
}, },
{ {
0x0f, 0x0b, 0x09, 0x07, PixelColour{0x0f}, PixelColour{0x0b}, PixelColour{0x09}, PixelColour{0x07},
0x05, 0x03, 0xbf, 0xbd, PixelColour{0x05}, PixelColour{0x03}, PixelColour{0xbf}, PixelColour{0xbd},
0xba, 0xb9, 0xb7, 0xb5 PixelColour{0xba}, PixelColour{0xb9}, PixelColour{0xb7}, PixelColour{0xb5}
}, },
{ {
0x0f, 0x0b, 0x0a, 0x09, PixelColour{0x0f}, PixelColour{0x0b}, PixelColour{0x0a}, PixelColour{0x09},
0x08, 0x07, 0x06, 0x05, PixelColour{0x08}, PixelColour{0x07}, PixelColour{0x06}, PixelColour{0x05},
0x04, 0x03, 0x02, 0x01 PixelColour{0x04}, PixelColour{0x03}, PixelColour{0x02}, PixelColour{0x01}
} }
}; };
@ -86,7 +86,7 @@ void LinkGraphOverlay::RebuildCache()
StationLinkMap &seen_links = this->cached_links[from]; StationLinkMap &seen_links = this->cached_links[from];
uint supply = 0; uint supply = 0;
for (CargoType cargo : SetCargoBitIterator(this->cargo_mask)) { for (CargoType cargo : this->cargo_mask) {
if (!CargoSpec::Get(cargo)->IsValid()) continue; if (!CargoSpec::Get(cargo)->IsValid()) continue;
if (!LinkGraph::IsValidID(sta->goods[cargo].link_graph)) continue; if (!LinkGraph::IsValidID(sta->goods[cargo].link_graph)) continue;
const LinkGraph &lg = *LinkGraph::Get(sta->goods[cargo].link_graph); const LinkGraph &lg = *LinkGraph::Get(sta->goods[cargo].link_graph);
@ -212,7 +212,7 @@ inline bool LinkGraphOverlay::IsLinkVisible(Point pta, Point ptb, const DrawPixe
*/ */
void LinkGraphOverlay::AddLinks(const Station *from, const Station *to) void LinkGraphOverlay::AddLinks(const Station *from, const Station *to)
{ {
for (CargoType cargo : SetCargoBitIterator(this->cargo_mask)) { for (CargoType cargo : this->cargo_mask) {
if (!CargoSpec::Get(cargo)->IsValid()) continue; if (!CargoSpec::Get(cargo)->IsValid()) continue;
const GoodsEntry &ge = from->goods[cargo]; const GoodsEntry &ge = from->goods[cargo];
if (!LinkGraph::IsValidID(ge.link_graph) || if (!LinkGraph::IsValidID(ge.link_graph) ||
@ -297,7 +297,7 @@ void LinkGraphOverlay::DrawLinks(const DrawPixelInfo *dpi) const
void LinkGraphOverlay::DrawContent(Point pta, Point ptb, const LinkProperties &cargo) const void LinkGraphOverlay::DrawContent(Point pta, Point ptb, const LinkProperties &cargo) const
{ {
uint usage_or_plan = std::min(cargo.capacity * 2 + 1, cargo.Usage()); uint usage_or_plan = std::min(cargo.capacity * 2 + 1, cargo.Usage());
int colour = LinkGraphOverlay::LINK_COLOURS[_settings_client.gui.linkgraph_colours][usage_or_plan * lengthof(LinkGraphOverlay::LINK_COLOURS[0]) / (cargo.capacity * 2 + 2)]; PixelColour colour = LinkGraphOverlay::LINK_COLOURS[_settings_client.gui.linkgraph_colours][usage_or_plan * lengthof(LinkGraphOverlay::LINK_COLOURS[0]) / (cargo.capacity * 2 + 2)];
int width = ScaleGUITrad(this->scale); int width = ScaleGUITrad(this->scale);
int dash = cargo.shared ? width * 4 : 0; int dash = cargo.shared ? width * 4 : 0;
@ -345,7 +345,7 @@ void LinkGraphOverlay::DrawStationDots(const DrawPixelInfo *dpi) const
* @param colour Colour with which the vertex will be filled. * @param colour Colour with which the vertex will be filled.
* @param border_colour Colour for the border of the vertex. * @param border_colour Colour for the border of the vertex.
*/ */
/* static */ void LinkGraphOverlay::DrawVertex(int x, int y, int size, int colour, int border_colour) /* static */ void LinkGraphOverlay::DrawVertex(int x, int y, int size, PixelColour colour, PixelColour border_colour)
{ {
size--; size--;
int w1 = size / 2; int w1 = size / 2;
@ -566,7 +566,7 @@ void LinkGraphLegendWindow::SetOverlay(std::shared_ptr<LinkGraphOverlay> overlay
} }
CargoTypes cargoes = this->overlay->GetCargoMask(); CargoTypes cargoes = this->overlay->GetCargoMask();
for (uint c = 0; c < this->num_cargo; c++) { for (uint c = 0; c < this->num_cargo; c++) {
this->SetWidgetLoweredState(WID_LGL_CARGO_FIRST + c, HasBit(cargoes, _sorted_cargo_specs[c]->Index())); this->SetWidgetLoweredState(WID_LGL_CARGO_FIRST + c, cargoes.Test(_sorted_cargo_specs[c]->Index()));
} }
} }
@ -607,7 +607,7 @@ void LinkGraphLegendWindow::DrawWidget(const Rect &r, WidgetID widget) const
DrawCompanyIcon(cid, CentreBounds(br.left, br.right, sprite_size.width), CentreBounds(br.top, br.bottom, sprite_size.height)); DrawCompanyIcon(cid, CentreBounds(br.left, br.right, sprite_size.width), CentreBounds(br.top, br.bottom, sprite_size.height));
} }
if (IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) { if (IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) {
uint8_t colour = LinkGraphOverlay::LINK_COLOURS[_settings_client.gui.linkgraph_colours][widget - WID_LGL_SATURATION_FIRST]; PixelColour colour = LinkGraphOverlay::LINK_COLOURS[_settings_client.gui.linkgraph_colours][widget - WID_LGL_SATURATION_FIRST];
GfxFillRect(br, colour); GfxFillRect(br, colour);
StringID str = STR_NULL; StringID str = STR_NULL;
if (widget == WID_LGL_SATURATION_FIRST) { if (widget == WID_LGL_SATURATION_FIRST) {
@ -669,10 +669,10 @@ void LinkGraphLegendWindow::UpdateOverlayCompanies()
*/ */
void LinkGraphLegendWindow::UpdateOverlayCargoes() void LinkGraphLegendWindow::UpdateOverlayCargoes()
{ {
CargoTypes mask = 0; CargoTypes mask{};
for (uint c = 0; c < num_cargo; c++) { for (uint c = 0; c < num_cargo; c++) {
if (!this->IsWidgetLowered(WID_LGL_CARGO_FIRST + c)) continue; if (!this->IsWidgetLowered(WID_LGL_CARGO_FIRST + c)) continue;
SetBit(mask, _sorted_cargo_specs[c]->Index()); mask.Set(_sorted_cargo_specs[c]->Index());
} }
this->overlay->SetCargoMask(mask); this->overlay->SetCargoMask(mask);
} }

View File

@ -44,7 +44,7 @@ public:
typedef std::map<StationID, StationLinkMap> LinkMap; typedef std::map<StationID, StationLinkMap> LinkMap;
typedef std::vector<std::pair<StationID, uint> > StationSupplyList; typedef std::vector<std::pair<StationID, uint> > StationSupplyList;
static const uint8_t LINK_COLOURS[][12]; static const PixelColour LINK_COLOURS[][12];
/** /**
* Create a link graph overlay for the specified window. * Create a link graph overlay for the specified window.
@ -95,7 +95,7 @@ protected:
void RebuildCache(); void RebuildCache();
static void AddStats(CargoType new_cargo, uint new_cap, uint new_usg, uint new_flow, uint32_t time, bool new_shared, LinkProperties &cargo); static void AddStats(CargoType new_cargo, uint new_cap, uint new_usg, uint new_flow, uint32_t time, bool new_shared, LinkProperties &cargo);
static void DrawVertex(int x, int y, int size, int colour, int border_colour); static void DrawVertex(int x, int y, int size, PixelColour colour, PixelColour border_colour);
}; };
void ShowLinkGraphLegend(); void ShowLinkGraphLegend();

View File

@ -42,13 +42,13 @@ LinkGraphJob::LinkGraphJob(const LinkGraph &orig) :
} }
/** /**
* Erase all flows originating at a specific node. * Erase all flows originating at a specific station.
* @param from Node to erase flows for. * @param from StationID to erase flows for.
*/ */
void LinkGraphJob::EraseFlows(NodeID from) void LinkGraphJob::EraseFlows(StationID from)
{ {
for (NodeID node_id = 0; node_id < this->Size(); ++node_id) { for (NodeID node_id = 0; node_id < this->Size(); ++node_id) {
(*this)[node_id].flows.erase(StationID{from}); (*this)[node_id].flows.erase(from);
} }
} }
@ -106,7 +106,7 @@ LinkGraphJob::~LinkGraphJob()
/* The station can have been deleted. Remove all flows originating from it then. */ /* The station can have been deleted. Remove all flows originating from it then. */
Station *st = Station::GetIfValid(from.base.station); Station *st = Station::GetIfValid(from.base.station);
if (st == nullptr) { if (st == nullptr) {
this->EraseFlows(node_id); this->EraseFlows(from.base.station);
continue; continue;
} }
@ -114,7 +114,7 @@ LinkGraphJob::~LinkGraphJob()
* sure that everything is still consistent or ignore it otherwise. */ * sure that everything is still consistent or ignore it otherwise. */
GoodsEntry &ge = st->goods[this->Cargo()]; GoodsEntry &ge = st->goods[this->Cargo()];
if (ge.link_graph != this->link_graph.index || ge.node != node_id) { if (ge.link_graph != this->link_graph.index || ge.node != node_id) {
this->EraseFlows(node_id); this->EraseFlows(from.base.station);
continue; continue;
} }
@ -136,7 +136,7 @@ LinkGraphJob::~LinkGraphJob()
/* Delete old flows for source stations which have been deleted /* Delete old flows for source stations which have been deleted
* from the new flows. This avoids flow cycles between old and * from the new flows. This avoids flow cycles between old and
* new flows. */ * new flows. */
while (!erased.IsEmpty()) geflows.erase(StationID{erased.Pop()}); while (!erased.IsEmpty()) geflows.erase(erased.Pop());
} else if ((*lg)[node_id][dest_id].last_unrestricted_update == EconomyTime::INVALID_DATE) { } else if ((*lg)[node_id][dest_id].last_unrestricted_update == EconomyTime::INVALID_DATE) {
/* Edge is fully restricted. */ /* Edge is fully restricted. */
flows.RestrictFlows(to); flows.RestrictFlows(to);

View File

@ -167,7 +167,7 @@ protected:
std::atomic<bool> job_completed = false; ///< Is the job still running. This is accessed by multiple threads and reads may be stale. std::atomic<bool> job_completed = false; ///< Is the job still running. This is accessed by multiple threads and reads may be stale.
std::atomic<bool> job_aborted = false; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale. std::atomic<bool> job_aborted = false; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
void EraseFlows(NodeID from); void EraseFlows(StationID from);
void JoinThread(); void JoinThread();
void SpawnThread(); void SpawnThread();

View File

@ -72,7 +72,7 @@ bool LinkRefresher::HandleRefit(CargoType refit_cargo)
bool any_refit = false; bool any_refit = false;
for (Vehicle *v = this->vehicle; v != nullptr; v = v->Next()) { for (Vehicle *v = this->vehicle; v != nullptr; v = v->Next()) {
const Engine *e = Engine::Get(v->engine_type); const Engine *e = Engine::Get(v->engine_type);
if (!HasBit(e->info.refit_mask, this->cargo)) { if (!e->info.refit_mask.Test(this->cargo)) {
++refit_it; ++refit_it;
continue; continue;
} }
@ -188,7 +188,7 @@ void LinkRefresher::RefreshStats(VehicleOrderID cur, VehicleOrderID next)
Station *st = Station::GetIfValid(orders[cur].GetDestination().ToStationID()); Station *st = Station::GetIfValid(orders[cur].GetDestination().ToStationID());
if (st != nullptr && next_station != StationID::Invalid() && next_station != st->index) { if (st != nullptr && next_station != StationID::Invalid() && next_station != st->index) {
Station *st_to = Station::Get(next_station); Station *st_to = Station::Get(next_station);
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
/* Refresh the link and give it a minimum capacity. */ /* Refresh the link and give it a minimum capacity. */
uint cargo_quantity = this->capacities[cargo]; uint cargo_quantity = this->capacities[cargo];
@ -260,7 +260,7 @@ void LinkRefresher::RefreshLinks(VehicleOrderID cur, VehicleOrderID next, Refres
} else if (!flags.Test(RefreshFlag::InAutorefit)) { } else if (!flags.Test(RefreshFlag::InAutorefit)) {
flags.Set(RefreshFlag::InAutorefit); flags.Set(RefreshFlag::InAutorefit);
LinkRefresher backup(*this); LinkRefresher backup(*this);
for (CargoType cargo = 0; cargo != NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
if (CargoSpec::Get(cargo)->IsValid() && this->HandleRefit(cargo)) { if (CargoSpec::Get(cargo)->IsValid() && this->HandleRefit(cargo)) {
this->RefreshLinks(cur, next, flags, num_hops); this->RefreshLinks(cur, next, flags, num_hops);
*this = backup; *this = backup;

View File

@ -221,14 +221,14 @@ struct MainWindow : Window
NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_M_VIEWPORT); NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_M_VIEWPORT);
nvp->InitializeViewport(this, TileXY(32, 32), ScaleZoomGUI(ZoomLevel::Viewport)); nvp->InitializeViewport(this, TileXY(32, 32), ScaleZoomGUI(ZoomLevel::Viewport));
this->viewport->overlay = std::make_shared<LinkGraphOverlay>(this, WID_M_VIEWPORT, 0, CompanyMask{}, 2); this->viewport->overlay = std::make_shared<LinkGraphOverlay>(this, WID_M_VIEWPORT, CargoTypes{}, CompanyMask{}, 2);
this->refresh_timeout.Reset(); this->refresh_timeout.Reset();
} }
/** Refresh the link-graph overlay. */ /** Refresh the link-graph overlay. */
void RefreshLinkGraph() void RefreshLinkGraph()
{ {
if (this->viewport->overlay->GetCargoMask() == 0 || if (this->viewport->overlay->GetCargoMask().None() ||
this->viewport->overlay->GetCompanyMask().None()) { this->viewport->overlay->GetCompanyMask().None()) {
return; return;
} }
@ -556,7 +556,7 @@ void SetupColoursAndInitialWindow()
const uint8_t *b = GetNonSprite(GetColourPalette(i), SpriteType::Recolour) + 1; const uint8_t *b = GetNonSprite(GetColourPalette(i), SpriteType::Recolour) + 1;
assert(b != nullptr); assert(b != nullptr);
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) { for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
SetColourGradient(i, j, b[0xC6 + j]); SetColourGradient(i, j, PixelColour{b[0xC6 + j]});
} }
} }

View File

@ -310,10 +310,10 @@ EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16_t internal
*/ */
CargoTypes TranslateRefitMask(uint32_t refit_mask) CargoTypes TranslateRefitMask(uint32_t refit_mask)
{ {
CargoTypes result = 0; CargoTypes result{};
for (uint8_t bit : SetBitIterator(refit_mask)) { for (uint8_t bit : SetBitIterator(refit_mask)) {
CargoType cargo = GetCargoTranslation(bit, _cur_gps.grffile, true); CargoType cargo = GetCargoTranslation(bit, _cur_gps.grffile, true);
if (IsValidCargoType(cargo)) SetBit(result, cargo); if (IsValidCargoType(cargo)) result.Set(cargo);
} }
return result; return result;
} }
@ -641,9 +641,9 @@ static CargoLabel GetActiveCargoLabel(const std::variant<CargoLabel, MixedCargoT
*/ */
static void CalculateRefitMasks() static void CalculateRefitMasks()
{ {
CargoTypes original_known_cargoes = 0; CargoTypes original_known_cargoes{};
for (CargoType cargo_type = 0; cargo_type != NUM_CARGO; ++cargo_type) { for (CargoType cargo_type{}; cargo_type != NUM_CARGO; ++cargo_type) {
if (IsDefaultCargo(cargo_type)) SetBit(original_known_cargoes, cargo_type); if (IsDefaultCargo(cargo_type)) original_known_cargoes.Set(cargo_type);
} }
for (Engine *e : Engine::Iterate()) { for (Engine *e : Engine::Iterate()) {
@ -738,13 +738,13 @@ static void CalculateRefitMasks()
} }
_gted[engine].UpdateRefittability(_gted[engine].cargo_allowed.Any()); _gted[engine].UpdateRefittability(_gted[engine].cargo_allowed.Any());
if (IsValidCargoType(ei->cargo_type)) ClrBit(_gted[engine].ctt_exclude_mask, ei->cargo_type); if (IsValidCargoType(ei->cargo_type)) _gted[engine].ctt_exclude_mask.Reset(ei->cargo_type);
} }
/* Compute refittability */ /* Compute refittability */
{ {
CargoTypes mask = 0; CargoTypes mask{};
CargoTypes not_mask = 0; CargoTypes not_mask{};
CargoTypes xor_mask = ei->refit_mask; CargoTypes xor_mask = ei->refit_mask;
/* If the original masks set by the grf are zero, the vehicle shall only carry the default cargo. /* If the original masks set by the grf are zero, the vehicle shall only carry the default cargo.
@ -754,16 +754,17 @@ static void CalculateRefitMasks()
if (_gted[engine].cargo_allowed.Any()) { if (_gted[engine].cargo_allowed.Any()) {
/* Build up the list of cargo types from the set cargo classes. */ /* Build up the list of cargo types from the set cargo classes. */
for (const CargoSpec *cs : CargoSpec::Iterate()) { for (const CargoSpec *cs : CargoSpec::Iterate()) {
if (cs->classes.Any(_gted[engine].cargo_allowed) && cs->classes.All(_gted[engine].cargo_allowed_required)) SetBit(mask, cs->Index()); if (cs->classes.Any(_gted[engine].cargo_allowed) && cs->classes.All(_gted[engine].cargo_allowed_required)) mask.Set(cs->Index());
if (cs->classes.Any(_gted[engine].cargo_disallowed)) SetBit(not_mask, cs->Index()); if (cs->classes.Any(_gted[engine].cargo_disallowed)) not_mask.Set(cs->Index());
} }
} }
ei->refit_mask = ((mask & ~not_mask) ^ xor_mask) & _cargo_mask; CargoTypes invalid_mask = CargoTypes{_cargo_mask}.Flip();
ei->refit_mask = mask.Reset(not_mask).Flip(xor_mask).Reset(invalid_mask);
/* Apply explicit refit includes/excludes. */ /* Apply explicit refit includes/excludes. */
ei->refit_mask |= _gted[engine].ctt_include_mask; ei->refit_mask.Set(_gted[engine].ctt_include_mask);
ei->refit_mask &= ~_gted[engine].ctt_exclude_mask; ei->refit_mask.Reset(_gted[engine].ctt_exclude_mask);
/* Custom refit mask callback. */ /* Custom refit mask callback. */
const GRFFile *file = _gted[e->index].defaultcargo_grf; const GRFFile *file = _gted[e->index].defaultcargo_grf;
@ -776,8 +777,8 @@ static void CalculateRefitMasks()
case CALLBACK_FAILED: case CALLBACK_FAILED:
case 0: case 0:
break; // Do nothing. break; // Do nothing.
case 1: SetBit(ei->refit_mask, cs->Index()); break; case 1: ei->refit_mask.Set(cs->Index()); break;
case 2: ClrBit(ei->refit_mask, cs->Index()); break; case 2: ei->refit_mask.Reset(cs->Index()); break;
default: ErrorUnknownCallbackResult(file->grfid, CBID_VEHICLE_CUSTOM_REFIT, callback); default: ErrorUnknownCallbackResult(file->grfid, CBID_VEHICLE_CUSTOM_REFIT, callback);
} }
@ -786,24 +787,24 @@ static void CalculateRefitMasks()
} }
/* Clear invalid cargoslots (from default vehicles or pre-NewCargo GRFs) */ /* Clear invalid cargoslots (from default vehicles or pre-NewCargo GRFs) */
if (IsValidCargoType(ei->cargo_type) && !HasBit(_cargo_mask, ei->cargo_type)) ei->cargo_type = INVALID_CARGO; if (IsValidCargoType(ei->cargo_type) && !_cargo_mask.Test(ei->cargo_type)) ei->cargo_type = INVALID_CARGO;
/* Ensure that the vehicle is either not refittable, or that the default cargo is one of the refittable cargoes. /* Ensure that the vehicle is either not refittable, or that the default cargo is one of the refittable cargoes.
* Note: Vehicles refittable to no cargo are handle differently to vehicle refittable to a single cargo. The latter might have subtypes. */ * Note: Vehicles refittable to no cargo are handle differently to vehicle refittable to a single cargo. The latter might have subtypes. */
if (!only_defaultcargo && (e->type != VEH_SHIP || e->u.ship.old_refittable) && IsValidCargoType(ei->cargo_type) && !HasBit(ei->refit_mask, ei->cargo_type)) { if (!only_defaultcargo && (e->type != VEH_SHIP || e->u.ship.old_refittable) && IsValidCargoType(ei->cargo_type) && !ei->refit_mask.Test(ei->cargo_type)) {
ei->cargo_type = INVALID_CARGO; ei->cargo_type = INVALID_CARGO;
} }
/* Check if this engine's cargo type is valid. If not, set to the first refittable /* Check if this engine's cargo type is valid. If not, set to the first refittable
* cargo type. Finally disable the vehicle, if there is still no cargo. */ * cargo type. Finally disable the vehicle, if there is still no cargo. */
if (!IsValidCargoType(ei->cargo_type) && ei->refit_mask != 0) { if (!IsValidCargoType(ei->cargo_type) && ei->refit_mask.Any()) {
/* Figure out which CTT to use for the default cargo, if it is 'first refittable'. */ /* Figure out which CTT to use for the default cargo, if it is 'first refittable'. */
const GRFFile *file = _gted[engine].defaultcargo_grf; const GRFFile *file = _gted[engine].defaultcargo_grf;
if (file == nullptr) file = e->GetGRF(); if (file == nullptr) file = e->GetGRF();
if (file != nullptr && file->grf_version >= 8 && !file->cargo_list.empty()) { if (file != nullptr && file->grf_version >= 8 && !file->cargo_list.empty()) {
/* Use first refittable cargo from cargo translation table */ /* Use first refittable cargo from cargo translation table */
uint8_t best_local_slot = UINT8_MAX; uint8_t best_local_slot = UINT8_MAX;
for (CargoType cargo_type : SetCargoBitIterator(ei->refit_mask)) { for (CargoType cargo_type : ei->refit_mask) {
uint8_t local_slot = file->cargo_map[cargo_type]; uint8_t local_slot = file->cargo_map[cargo_type];
if (local_slot < best_local_slot) { if (local_slot < best_local_slot) {
best_local_slot = local_slot; best_local_slot = local_slot;
@ -814,7 +815,7 @@ static void CalculateRefitMasks()
if (!IsValidCargoType(ei->cargo_type)) { if (!IsValidCargoType(ei->cargo_type)) {
/* Use first refittable cargo slot */ /* Use first refittable cargo slot */
ei->cargo_type = (CargoType)FindFirstBit(ei->refit_mask); ei->cargo_type = *ei->refit_mask.begin();
} }
} }
if (!IsValidCargoType(ei->cargo_type) && e->type == VEH_TRAIN && e->u.rail.railveh_type != RAILVEH_WAGON && e->u.rail.capacity == 0) { if (!IsValidCargoType(ei->cargo_type) && e->type == VEH_TRAIN && e->u.rail.railveh_type != RAILVEH_WAGON && e->u.rail.capacity == 0) {
@ -822,14 +823,14 @@ static void CalculateRefitMasks()
* Fallback to the first available instead, if the cargo type has not been changed (as indicated by * Fallback to the first available instead, if the cargo type has not been changed (as indicated by
* cargo_label not being CT_INVALID). */ * cargo_label not being CT_INVALID). */
if (GetActiveCargoLabel(ei->cargo_label) != CT_INVALID) { if (GetActiveCargoLabel(ei->cargo_label) != CT_INVALID) {
ei->cargo_type = static_cast<CargoType>(FindFirstBit(_standard_cargo_mask)); ei->cargo_type = *_standard_cargo_mask.begin();
} }
} }
if (!IsValidCargoType(ei->cargo_type)) ei->climates = {}; if (!IsValidCargoType(ei->cargo_type)) ei->climates = {};
/* Clear refit_mask for not refittable ships */ /* Clear refit_mask for not refittable ships */
if (e->type == VEH_SHIP && !e->u.ship.old_refittable) { if (e->type == VEH_SHIP && !e->u.ship.old_refittable) {
ei->refit_mask = 0; ei->refit_mask.Reset();
} }
} }
} }

View File

@ -134,7 +134,7 @@ struct GRFFile {
std::vector<GRFLabel> labels{}; ///< List of labels std::vector<GRFLabel> labels{}; ///< List of labels
std::vector<CargoLabel> cargo_list{}; ///< Cargo translation table (local ID -> label) std::vector<CargoLabel> cargo_list{}; ///< Cargo translation table (local ID -> label)
std::array<uint8_t, NUM_CARGO> cargo_map{}; ///< Inverse cargo translation table (CargoType -> local ID) TypedIndexContainer<std::array<uint8_t, NUM_CARGO>, CargoType> cargo_map{}; ///< Inverse cargo translation table (CargoType -> local ID)
std::vector<BadgeID> badge_list{}; ///< Badge translation table (local index -> global index) std::vector<BadgeID> badge_list{}; ///< Badge translation table (local index -> global index)
std::unordered_map<uint16_t, BadgeID> badge_map{}; std::unordered_map<uint16_t, BadgeID> badge_map{};

View File

@ -153,10 +153,10 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int pro
_gted[e->index].UpdateRefittability(prop == 0x1D && count != 0); _gted[e->index].UpdateRefittability(prop == 0x1D && count != 0);
if (prop == 0x1D) _gted[e->index].defaultcargo_grf = _cur_gps.grffile; if (prop == 0x1D) _gted[e->index].defaultcargo_grf = _cur_gps.grffile;
CargoTypes &ctt = prop == 0x1D ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; CargoTypes &ctt = prop == 0x1D ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
ctt = 0; ctt.Reset();
while (count--) { while (count--) {
CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile);
if (IsValidCargoType(ctype)) SetBit(ctt, ctype); if (IsValidCargoType(ctype)) ctt.Set(ctype);
} }
break; break;
} }

View File

@ -34,16 +34,16 @@ static ChangeInfoResult CargoReserveInfo(uint first, uint last, int prop, ByteRe
} }
for (uint id = first; id < last; ++id) { for (uint id = first; id < last; ++id) {
CargoSpec *cs = CargoSpec::Get(id); CargoSpec *cs = CargoSpec::Get(static_cast<CargoType>(id));
switch (prop) { switch (prop) {
case 0x08: // Bit number of cargo case 0x08: // Bit number of cargo
cs->bitnum = buf.ReadByte(); cs->bitnum = buf.ReadByte();
if (cs->IsValid()) { if (cs->IsValid()) {
cs->grffile = _cur_gps.grffile; cs->grffile = _cur_gps.grffile;
SetBit(_cargo_mask, id); _cargo_mask.Set(cs->Index());
} else { } else {
ClrBit(_cargo_mask, id); _cargo_mask.Reset(cs->Index());
} }
BuildCargoLabelMap(); BuildCargoLabelMap();
break; break;
@ -97,11 +97,11 @@ static ChangeInfoResult CargoReserveInfo(uint first, uint last, int prop, ByteRe
break; break;
case 0x13: // Colour for station rating bars case 0x13: // Colour for station rating bars
cs->rating_colour = buf.ReadByte(); cs->rating_colour = PixelColour{buf.ReadByte()};
break; break;
case 0x14: // Colour for cargo graph case 0x14: // Colour for cargo graph
cs->legend_colour = buf.ReadByte(); cs->legend_colour = PixelColour{buf.ReadByte()};
break; break;
case 0x15: // Freight status case 0x15: // Freight status

View File

@ -305,7 +305,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt
uint8_t count = buf.ReadByte(); uint8_t count = buf.ReadByte();
for (uint8_t j = 0; j < count; j++) { for (uint8_t j = 0; j < count; j++) {
CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile);
if (IsValidCargoType(cargo)) SetBit(housespec->watched_cargoes, cargo); if (IsValidCargoType(cargo)) housespec->watched_cargoes.Set(cargo);
} }
break; break;
} }

View File

@ -565,7 +565,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By
break; break;
case 0x19: // Map colour case 0x19: // Map colour
indsp->map_colour = buf.ReadByte(); indsp->map_colour = PixelColour{buf.ReadByte()};
break; break;
case 0x1A: // Special industry flags to define special behavior case 0x1A: // Special industry flags to define special behavior

View File

@ -121,7 +121,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint first, uint last, int prop, Byte
break; break;
case 0x16: // Map colour case 0x16: // Map colour
rti->map_colour = buf.ReadByte(); rti->map_colour = PixelColour{buf.ReadByte()};
break; break;
case 0x17: // Introduction date case 0x17: // Introduction date

View File

@ -109,7 +109,7 @@ static ChangeInfoResult RoadTypeChangeInfo(uint first, uint last, int prop, Byte
break; break;
case 0x16: // Map colour case 0x16: // Map colour
rti->map_colour = buf.ReadByte(); rti->map_colour = PixelColour{buf.ReadByte()};
break; break;
case 0x17: // Introduction date case 0x17: // Introduction date

View File

@ -194,10 +194,10 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B
_gted[e->index].UpdateRefittability(prop == 0x24 && count != 0); _gted[e->index].UpdateRefittability(prop == 0x24 && count != 0);
if (prop == 0x24) _gted[e->index].defaultcargo_grf = _cur_gps.grffile; if (prop == 0x24) _gted[e->index].defaultcargo_grf = _cur_gps.grffile;
CargoTypes &ctt = prop == 0x24 ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; CargoTypes &ctt = prop == 0x24 ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
ctt = 0; ctt.Reset();
while (count--) { while (count--) {
CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile);
if (IsValidCargoType(ctype)) SetBit(ctt, ctype); if (IsValidCargoType(ctype)) ctt.Set(ctype);
} }
break; break;
} }

View File

@ -173,10 +173,10 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, B
_gted[e->index].UpdateRefittability(prop == 0x1E && count != 0); _gted[e->index].UpdateRefittability(prop == 0x1E && count != 0);
if (prop == 0x1E) _gted[e->index].defaultcargo_grf = _cur_gps.grffile; if (prop == 0x1E) _gted[e->index].defaultcargo_grf = _cur_gps.grffile;
CargoTypes &ctt = prop == 0x1E ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; CargoTypes &ctt = prop == 0x1E ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
ctt = 0; ctt.Reset();
while (count--) { while (count--) {
CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile);
if (IsValidCargoType(ctype)) SetBit(ctt, ctype); if (IsValidCargoType(ctype)) ctt.Set(ctype);
} }
break; break;
} }

View File

@ -292,10 +292,10 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead
_gted[e->index].UpdateRefittability(prop == 0x2C && count != 0); _gted[e->index].UpdateRefittability(prop == 0x2C && count != 0);
if (prop == 0x2C) _gted[e->index].defaultcargo_grf = _cur_gps.grffile; if (prop == 0x2C) _gted[e->index].defaultcargo_grf = _cur_gps.grffile;
CargoTypes &ctt = prop == 0x2C ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; CargoTypes &ctt = prop == 0x2C ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
ctt = 0; ctt.Reset();
while (count--) { while (count--) {
CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile);
if (IsValidCargoType(ctype)) SetBit(ctt, ctype); if (IsValidCargoType(ctype)) ctt.Set(ctype);
} }
break; break;
} }

View File

@ -379,7 +379,7 @@ static void CargoMapSpriteGroup(ByteReader &buf, uint8_t idcount)
continue; continue;
} }
CargoSpec *cs = CargoSpec::Get(cargo_type); CargoSpec *cs = CargoSpec::Get(static_cast<CargoType>(cargo_type));
cs->grffile = _cur_gps.grffile; cs->grffile = _cur_gps.grffile;
cs->group = _cur_gps.spritegroups[groupid]; cs->group = _cur_gps.spritegroups[groupid];
} }

View File

@ -49,7 +49,7 @@ struct AnimationBase {
* @param random_animation Whether to pass random bits to the "next frame" callback. * @param random_animation Whether to pass random bits to the "next frame" callback.
* @param extra_data Custom extra callback data. * @param extra_data Custom extra callback data.
*/ */
static void AnimateTile(const Tspec *spec, Tobj *obj, TileIndex tile, bool random_animation, Textra extra_data = 0) static void AnimateTile(const Tspec *spec, Tobj *obj, TileIndex tile, bool random_animation, Textra extra_data = {})
{ {
assert(spec != nullptr); assert(spec != nullptr);
@ -128,7 +128,7 @@ struct AnimationBase {
* @param trigger What triggered this update? To be passed as parameter to the NewGRF. * @param trigger What triggered this update? To be passed as parameter to the NewGRF.
* @param extra_data Custom extra data for callback processing. * @param extra_data Custom extra data for callback processing.
*/ */
static void ChangeAnimationFrame(CallbackID cb, const Tspec *spec, Tobj *obj, TileIndex tile, uint32_t random_bits, uint32_t trigger, Textra extra_data = 0) static void ChangeAnimationFrame(CallbackID cb, const Tspec *spec, Tobj *obj, TileIndex tile, uint32_t random_bits, uint32_t trigger, Textra extra_data = {})
{ {
uint16_t callback = GetCallback(cb, random_bits, trigger, spec, obj, tile, extra_data); uint16_t callback = GetCallback(cb, random_bits, trigger, spec, obj, tile, extra_data);
if (callback == CALLBACK_FAILED) return; if (callback == CALLBACK_FAILED) return;

View File

@ -15,6 +15,7 @@
#include "sprite.h" #include "sprite.h"
#include "core/alloc_type.hpp" #include "core/alloc_type.hpp"
#include "core/convertible_through_base.hpp"
#include "command_type.h" #include "command_type.h"
#include "direction_type.h" #include "direction_type.h"
#include "company_type.h" #include "company_type.h"
@ -454,9 +455,9 @@ struct VariableGRFFileProps : GRFFilePropsBase {
* Sprite groups indexed by CargoType. * Sprite groups indexed by CargoType.
*/ */
struct CargoGRFFileProps : VariableGRFFileProps<CargoType> { struct CargoGRFFileProps : VariableGRFFileProps<CargoType> {
static constexpr CargoType SG_DEFAULT = NUM_CARGO; ///< Default type used when no more-specific cargo matches. static constexpr CargoType SG_DEFAULT{NUM_CARGO}; ///< Default type used when no more-specific cargo matches.
static constexpr CargoType SG_PURCHASE = NUM_CARGO + 1; ///< Used in purchase lists before an item exists. static constexpr CargoType SG_PURCHASE{NUM_CARGO + 1}; ///< Used in purchase lists before an item exists.
static constexpr CargoType SG_DEFAULT_NA = NUM_CARGO + 2; ///< Used only by stations and roads when no more-specific cargo matches. static constexpr CargoType SG_DEFAULT_NA{NUM_CARGO + 2}; ///< Used only by stations and roads when no more-specific cargo matches.
}; };
/** /**

View File

@ -426,7 +426,7 @@ struct NewGRFInspectWindow : Window {
{ {
switch (nip.type) { switch (nip.type) {
case NIT_INT: return GetString(STR_JUST_INT, value); case NIT_INT: return GetString(STR_JUST_INT, value);
case NIT_CARGO: return GetString(IsValidCargoType(value) ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A); case NIT_CARGO: return GetString(IsValidCargoType(static_cast<CargoType>(value)) ? CargoSpec::Get(static_cast<CargoType>(value))->name : STR_QUANTITY_N_A);
default: NOT_REACHED(); default: NOT_REACHED();
} }
} }

View File

@ -435,7 +435,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
case 0x42: { // Consist cargo information case 0x42: { // Consist cargo information
if (!HasBit(v->grf_cache.cache_valid, NCVV_CONSIST_CARGO_INFORMATION)) { if (!HasBit(v->grf_cache.cache_valid, NCVV_CONSIST_CARGO_INFORMATION)) {
std::array<uint8_t, NUM_CARGO> common_cargoes{}; TypedIndexContainer<std::array<uint8_t, NUM_CARGO>, CargoType> common_cargoes{};
uint8_t cargo_classes = 0; uint8_t cargo_classes = 0;
uint8_t user_def_data = 0; uint8_t user_def_data = 0;
@ -470,12 +470,12 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
/* Note: We have to store the untranslated cargotype in the cache as the cache can be read by different NewGRFs, /* Note: We have to store the untranslated cargotype in the cache as the cache can be read by different NewGRFs,
* which will need different translations */ * which will need different translations */
v->grf_cache.consist_cargo_information = cargo_classes | (common_cargo_type << 8) | (common_subtype << 16) | (user_def_data << 24); v->grf_cache.consist_cargo_information = cargo_classes | (common_cargo_type.base() << 8) | (common_subtype << 16) | (user_def_data << 24);
SetBit(v->grf_cache.cache_valid, NCVV_CONSIST_CARGO_INFORMATION); SetBit(v->grf_cache.cache_valid, NCVV_CONSIST_CARGO_INFORMATION);
} }
/* The cargo translation is specific to the accessing GRF, and thus cannot be cached. */ /* The cargo translation is specific to the accessing GRF, and thus cannot be cached. */
CargoType common_cargo_type = (v->grf_cache.consist_cargo_information >> 8) & 0xFF; CargoType common_cargo_type = static_cast<CargoType>(GB(v->grf_cache.consist_cargo_information, 8, 8));
/* Note: /* Note:
* - Unlike everywhere else the cargo translation table is only used since grf version 8, not 7. * - Unlike everywhere else the cargo translation table is only used since grf version 8, not 7.
@ -822,7 +822,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
case 0x36: return v->subspeed; case 0x36: return v->subspeed;
case 0x37: return v->acceleration; case 0x37: return v->acceleration;
case 0x38: break; // not implemented case 0x38: break; // not implemented
case 0x39: return v->cargo_type; case 0x39: return v->cargo_type.base();
case 0x3A: return v->cargo_cap; case 0x3A: return v->cargo_cap;
case 0x3B: return GB(v->cargo_cap, 8, 8); case 0x3B: return GB(v->cargo_cap, 8, 8);
case 0x3C: return ClampTo<uint16_t>(v->cargo.StoredCount()); case 0x3C: return ClampTo<uint16_t>(v->cargo.StoredCount());

View File

@ -36,7 +36,7 @@ struct GenericScopeResolver : public ScopeResolver {
* @param ai_callback Callback comes from the AI. * @param ai_callback Callback comes from the AI.
*/ */
GenericScopeResolver(ResolverObject &ro, bool ai_callback) GenericScopeResolver(ResolverObject &ro, bool ai_callback)
: ScopeResolver(ro), cargo_type(0), default_selection(0), src_industry(0), dst_industry(0), distance(0), : ScopeResolver(ro), cargo_type(INVALID_CARGO), default_selection(0), src_industry(0), dst_industry(0), distance(0),
event(), count(0), station_size(0), feature(GSF_INVALID), ai_callback(ai_callback) event(), count(0), station_size(0), feature(GSF_INVALID), ai_callback(ai_callback)
{ {
} }
@ -124,7 +124,7 @@ void AddGenericCallback(GrfSpecFeature feature, const GRFFile *file, const Sprit
switch (variable) { switch (variable) {
case 0x40: return this->ro.grffile->cargo_map[this->cargo_type]; case 0x40: return this->ro.grffile->cargo_map[this->cargo_type];
case 0x80: return this->cargo_type; case 0x80: return this->cargo_type.base();
case 0x81: return CargoSpec::Get(this->cargo_type)->bitnum; case 0x81: return CargoSpec::Get(this->cargo_type)->bitnum;
case 0x82: return this->default_selection; case 0x82: return this->default_selection;
case 0x83: return this->src_industry; case 0x83: return this->src_industry;

View File

@ -402,7 +402,7 @@ static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex start_ti
} }
/* Cargo triggered CB 148? */ /* Cargo triggered CB 148? */
if (HasBit(this->watched_cargo_triggers, cargo_type)) SetBit(res, 4); if (this->watched_cargo_triggers.Test(cargo_type)) SetBit(res, 4);
return res; return res;
} }
@ -739,9 +739,9 @@ void TriggerHouseAnimation_WatchedCargoAccepted(TileIndex tile, CargoTypes trigg
HouseID id = GetHouseType(tile); HouseID id = GetHouseType(tile);
const HouseSpec *hs = HouseSpec::Get(id); const HouseSpec *hs = HouseSpec::Get(id);
trigger_cargoes &= hs->watched_cargoes; trigger_cargoes = trigger_cargoes & hs->watched_cargoes;
/* None of the trigger cargoes is watched? */ /* None of the trigger cargoes is watched? */
if (trigger_cargoes == 0) return; if (trigger_cargoes.None()) return;
/* Same random value for all tiles of a multi-tile house. */ /* Same random value for all tiles of a multi-tile house. */
uint16_t r = Random(); uint16_t r = Random();

View File

@ -55,7 +55,7 @@ struct HouseResolverObject : public SpecializedResolverObject<HouseRandomTrigger
HouseResolverObject(HouseID house_id, TileIndex tile, Town *town, HouseResolverObject(HouseID house_id, TileIndex tile, Town *town,
CallbackID callback = CBID_NO_CALLBACK, uint32_t param1 = 0, uint32_t param2 = 0, CallbackID callback = CBID_NO_CALLBACK, uint32_t param1 = 0, uint32_t param2 = 0,
bool not_yet_constructed = false, uint8_t initial_random_bits = 0, CargoTypes watched_cargo_triggers = 0, int view = 0); bool not_yet_constructed = false, uint8_t initial_random_bits = 0, CargoTypes watched_cargo_triggers = {}, int view = 0);
ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, uint8_t relative = 0) override ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, uint8_t relative = 0) override
{ {
@ -105,7 +105,7 @@ void TriggerHouseAnimation_ConstructionStageChanged(TileIndex tile, bool first_c
void TriggerHouseAnimation_WatchedCargoAccepted(TileIndex tile, CargoTypes trigger_cargoes); void TriggerHouseAnimation_WatchedCargoAccepted(TileIndex tile, CargoTypes trigger_cargoes);
uint16_t GetHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, HouseID house_id, Town *town, TileIndex tile, std::span<int32_t> regs100 = {}, uint16_t GetHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, HouseID house_id, Town *town, TileIndex tile, std::span<int32_t> regs100 = {},
bool not_yet_constructed = false, uint8_t initial_random_bits = 0, CargoTypes watched_cargo_triggers = 0, int view = 0); bool not_yet_constructed = false, uint8_t initial_random_bits = 0, CargoTypes watched_cargo_triggers = {}, int view = 0);
bool CanDeleteHouse(TileIndex tile); bool CanDeleteHouse(TileIndex tile);

View File

@ -371,7 +371,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(const ResolverObject &objec
case 0x87: return this->industry->location.h;// xy dimensions case 0x87: return this->industry->location.h;// xy dimensions
case 0x88: case 0x88:
case 0x89: return this->industry->GetProduced(variable - 0x88).cargo; case 0x89: return this->industry->GetProduced(variable - 0x88).cargo.base();
case 0x8A: return this->industry->GetProduced(0).waiting; case 0x8A: return this->industry->GetProduced(0).waiting;
case 0x8B: return GB(this->industry->GetProduced(0).waiting, 8, 8); case 0x8B: return GB(this->industry->GetProduced(0).waiting, 8, 8);
case 0x8C: return this->industry->GetProduced(1).waiting; case 0x8C: return this->industry->GetProduced(1).waiting;
@ -380,7 +380,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(const ResolverObject &objec
case 0x8F: return this->industry->GetProduced(variable - 0x8E).rate; case 0x8F: return this->industry->GetProduced(variable - 0x8E).rate;
case 0x90: case 0x90:
case 0x91: case 0x91:
case 0x92: return this->industry->GetAccepted(variable - 0x90).cargo; case 0x92: return this->industry->GetAccepted(variable - 0x90).cargo.base();
case 0x93: return this->industry->prod_level; case 0x93: return this->industry->prod_level;
/* amount of cargo produced so far THIS month. */ /* amount of cargo produced so far THIS month. */
case 0x94: return this->industry->GetProduced(0).history[THIS_MONTH].production; case 0x94: return this->industry->GetProduced(0).history[THIS_MONTH].production;

View File

@ -232,7 +232,7 @@ RoadStopResolverObject::RoadStopResolverObject(const RoadStopSpec *roadstopspec,
/* Pick the first cargo that we have waiting */ /* Pick the first cargo that we have waiting */
for (const auto &[cargo, spritegroup] : roadstopspec->grf_prop.spritegroups) { for (const auto &[cargo, spritegroup] : roadstopspec->grf_prop.spritegroups) {
if (cargo < NUM_CARGO && station->goods[cargo].HasData() && station->goods[cargo].GetData().cargo.TotalCount() > 0) { if (cargo < NUM_CARGO && station->goods[cargo].HasData() && station->goods[cargo].GetData().cargo.TotalCount() > 0) {
ctype = cargo; ctype = static_cast<CargoType>(cargo);
this->root_spritegroup = spritegroup; this->root_spritegroup = spritegroup;
break; break;
} }
@ -422,18 +422,15 @@ void TriggerRoadStopRandomisation(BaseStation *st, TileIndex tile, StationRandom
/* Check the cached cargo trigger bitmask to see if we need /* Check the cached cargo trigger bitmask to see if we need
* to bother with any further processing. * to bother with any further processing.
* Note: cached_roadstop_cargo_triggers must be non-zero even for cargo-independent triggers. */ * Note: cached_roadstop_cargo_triggers must be non-zero even for cargo-independent triggers. */
if (st->cached_roadstop_cargo_triggers == 0) return; if (st->cached_roadstop_cargo_triggers.None()) return;
if (IsValidCargoType(cargo_type) && !HasBit(st->cached_roadstop_cargo_triggers, cargo_type)) return; if (IsValidCargoType(cargo_type) && !st->cached_roadstop_cargo_triggers.Test(cargo_type)) return;
st->waiting_random_triggers.Set(trigger); st->waiting_random_triggers.Set(trigger);
uint32_t whole_reseed = 0; uint32_t whole_reseed = 0;
/* Bitmask of completely empty cargo types to be matched. */ /* Bitmask of completely empty cargo types to be matched. */
CargoTypes empty_mask{}; CargoTypes not_empty_mask = (trigger == StationRandomTrigger::CargoTaken) ? GetEmptyMask(Station::From(st)).Flip() : ALL_CARGOTYPES;
if (trigger == StationRandomTrigger::CargoTaken) {
empty_mask = GetEmptyMask(Station::From(st));
}
StationRandomTriggers used_random_triggers; StationRandomTriggers used_random_triggers;
auto process_tile = [&](TileIndex cur_tile) { auto process_tile = [&](TileIndex cur_tile) {
@ -443,10 +440,10 @@ void TriggerRoadStopRandomisation(BaseStation *st, TileIndex tile, StationRandom
/* Cargo taken "will only be triggered if all of those /* Cargo taken "will only be triggered if all of those
* cargo types have no more cargo waiting." */ * cargo types have no more cargo waiting." */
if (trigger == StationRandomTrigger::CargoTaken) { if (trigger == StationRandomTrigger::CargoTaken) {
if ((ss->cargo_triggers & ~empty_mask) != 0) return; if (ss->cargo_triggers.Any(not_empty_mask)) return;
} }
if (!IsValidCargoType(cargo_type) || HasBit(ss->cargo_triggers, cargo_type)) { if (!IsValidCargoType(cargo_type) || ss->cargo_triggers.Test(cargo_type)) {
RoadStopResolverObject object(ss, st, cur_tile, INVALID_ROADTYPE, GetStationType(cur_tile), GetStationGfx(cur_tile)); RoadStopResolverObject object(ss, st, cur_tile, INVALID_ROADTYPE, GetStationType(cur_tile), GetStationGfx(cur_tile));
object.SetWaitingRandomTriggers(st->waiting_random_triggers); object.SetWaitingRandomTriggers(st->waiting_random_triggers);
@ -621,7 +618,7 @@ void DeallocateSpecFromRoadStop(BaseStation *st, uint8_t specindex)
} else { } else {
st->roadstop_speclist.clear(); st->roadstop_speclist.clear();
st->cached_roadstop_anim_triggers = {}; st->cached_roadstop_anim_triggers = {};
st->cached_roadstop_cargo_triggers = 0; st->cached_roadstop_cargo_triggers.Reset();
return; return;
} }
} }
@ -636,13 +633,13 @@ void DeallocateSpecFromRoadStop(BaseStation *st, uint8_t specindex)
void RoadStopUpdateCachedTriggers(BaseStation *st) void RoadStopUpdateCachedTriggers(BaseStation *st)
{ {
st->cached_roadstop_anim_triggers = {}; st->cached_roadstop_anim_triggers = {};
st->cached_roadstop_cargo_triggers = 0; st->cached_roadstop_cargo_triggers.Reset();
/* Combine animation trigger bitmask for all road stop specs /* Combine animation trigger bitmask for all road stop specs
* of this station. */ * of this station. */
for (const auto &sm : GetStationSpecList<RoadStopSpec>(st)) { for (const auto &sm : GetStationSpecList<RoadStopSpec>(st)) {
if (sm.spec == nullptr) continue; if (sm.spec == nullptr) continue;
st->cached_roadstop_anim_triggers.Set(sm.spec->animation.triggers); st->cached_roadstop_anim_triggers.Set(sm.spec->animation.triggers);
st->cached_roadstop_cargo_triggers |= sm.spec->cargo_triggers; st->cached_roadstop_cargo_triggers.Set(sm.spec->cargo_triggers);
} }
} }

View File

@ -134,7 +134,7 @@ struct RoadStopSpec : NewGRFSpecBase<RoadStopClassID> {
RoadStopCallbackMasks callback_mask{}; RoadStopCallbackMasks callback_mask{};
RoadStopSpecFlags flags{}; RoadStopSpecFlags flags{};
CargoTypes cargo_triggers = 0; ///< Bitmask of cargo types which cause trigger re-randomizing CargoTypes cargo_triggers{}; ///< Bitmask of cargo types which cause trigger re-randomizing
AnimationInfo<StationAnimationTriggers> animation; AnimationInfo<StationAnimationTriggers> animation;

View File

@ -415,7 +415,7 @@ uint32_t Station::GetNewGRFVariable(const ResolverObject &object, uint8_t variab
{ {
switch (variable) { switch (variable) {
case 0x48: { // Accepted cargo types case 0x48: { // Accepted cargo types
uint32_t value = GetAcceptanceMask(this); uint32_t value = GetAcceptanceMask(this).base();
return value; return value;
} }
@ -514,14 +514,14 @@ uint32_t Waypoint::GetNewGRFVariable(const ResolverObject &, uint8_t variable, [
uint cargo = 0; uint cargo = 0;
const Station *st = Station::From(this->station_scope.st); const Station *st = Station::From(this->station_scope.st);
switch (this->station_scope.cargo_type) { switch (this->station_scope.cargo_type.base()) {
case INVALID_CARGO: case INVALID_CARGO.base():
case CargoGRFFileProps::SG_DEFAULT_NA: case CargoGRFFileProps::SG_DEFAULT_NA.base():
case CargoGRFFileProps::SG_PURCHASE: case CargoGRFFileProps::SG_PURCHASE.base():
cargo = 0; cargo = 0;
break; break;
case CargoGRFFileProps::SG_DEFAULT: case CargoGRFFileProps::SG_DEFAULT.base():
for (const GoodsEntry &ge : st->goods) { for (const GoodsEntry &ge : st->goods) {
if (!ge.HasData()) continue; if (!ge.HasData()) continue;
cargo += ge.GetData().cargo.TotalCount(); cargo += ge.GetData().cargo.TotalCount();
@ -771,7 +771,7 @@ void DeallocateSpecFromStation(BaseStation *st, uint8_t specindex)
} else { } else {
st->speclist.clear(); st->speclist.clear();
st->cached_anim_triggers = {}; st->cached_anim_triggers = {};
st->cached_cargo_triggers = 0; st->cached_cargo_triggers.Reset();
return; return;
} }
} }
@ -948,17 +948,14 @@ void TriggerStationRandomisation(BaseStation *st, TileIndex trigger_tile, Statio
/* Check the cached cargo trigger bitmask to see if we need /* Check the cached cargo trigger bitmask to see if we need
* to bother with any further processing. * to bother with any further processing.
* Note: cached_cargo_triggers must be non-zero even for cargo-independent triggers. */ * Note: cached_cargo_triggers must be non-zero even for cargo-independent triggers. */
if (st->cached_cargo_triggers == 0) return; if (st->cached_cargo_triggers.None()) return;
if (IsValidCargoType(cargo_type) && !HasBit(st->cached_cargo_triggers, cargo_type)) return; if (IsValidCargoType(cargo_type) && !st->cached_cargo_triggers.Test(cargo_type)) return;
uint32_t whole_reseed = 0; uint32_t whole_reseed = 0;
ETileArea area = ETileArea(st, trigger_tile, tas[static_cast<size_t>(trigger)]); ETileArea area = ETileArea(st, trigger_tile, tas[static_cast<size_t>(trigger)]);
/* Bitmask of completely empty cargo types to be matched. */ /* Bitmask of completely empty cargo types to be matched. */
CargoTypes empty_mask{}; CargoTypes not_empty_mask = (trigger == StationRandomTrigger::CargoTaken) ? GetEmptyMask(Station::From(st)).Flip() : ALL_CARGOTYPES;
if (trigger == StationRandomTrigger::CargoTaken) {
empty_mask = GetEmptyMask(Station::From(st));
}
/* Store triggers now for var 5F */ /* Store triggers now for var 5F */
st->waiting_random_triggers.Set(trigger); st->waiting_random_triggers.Set(trigger);
@ -973,10 +970,10 @@ void TriggerStationRandomisation(BaseStation *st, TileIndex trigger_tile, Statio
/* Cargo taken "will only be triggered if all of those /* Cargo taken "will only be triggered if all of those
* cargo types have no more cargo waiting." */ * cargo types have no more cargo waiting." */
if (trigger == StationRandomTrigger::CargoTaken) { if (trigger == StationRandomTrigger::CargoTaken) {
if ((ss->cargo_triggers & ~empty_mask) != 0) continue; if (ss->cargo_triggers.Any(not_empty_mask)) continue;
} }
if (!IsValidCargoType(cargo_type) || HasBit(ss->cargo_triggers, cargo_type)) { if (!IsValidCargoType(cargo_type) || ss->cargo_triggers.Test(cargo_type)) {
StationResolverObject object(ss, st, tile, CBID_RANDOM_TRIGGER, 0); StationResolverObject object(ss, st, tile, CBID_RANDOM_TRIGGER, 0);
object.SetWaitingRandomTriggers(st->waiting_random_triggers); object.SetWaitingRandomTriggers(st->waiting_random_triggers);
@ -1016,14 +1013,14 @@ void TriggerStationRandomisation(BaseStation *st, TileIndex trigger_tile, Statio
void StationUpdateCachedTriggers(BaseStation *st) void StationUpdateCachedTriggers(BaseStation *st)
{ {
st->cached_anim_triggers = {}; st->cached_anim_triggers = {};
st->cached_cargo_triggers = 0; st->cached_cargo_triggers.Reset();
/* Combine animation trigger bitmask for all station specs /* Combine animation trigger bitmask for all station specs
* of this station. */ * of this station. */
for (const auto &sm : GetStationSpecList<StationSpec>(st)) { for (const auto &sm : GetStationSpecList<StationSpec>(st)) {
if (sm.spec == nullptr) continue; if (sm.spec == nullptr) continue;
st->cached_anim_triggers.Set(sm.spec->animation.triggers); st->cached_anim_triggers.Set(sm.spec->animation.triggers);
st->cached_cargo_triggers |= sm.spec->cargo_triggers; st->cached_cargo_triggers.Set(sm.spec->cargo_triggers);
} }
} }

View File

@ -122,7 +122,7 @@ using StationSpecFlags = EnumBitSet<StationSpecFlag, uint8_t>;
struct StationSpec : NewGRFSpecBase<StationClassID> { struct StationSpec : NewGRFSpecBase<StationClassID> {
StationSpec() : name(0), StationSpec() : name(0),
disallowed_platforms(0), disallowed_lengths(0), disallowed_platforms(0), disallowed_lengths(0),
cargo_threshold(0), cargo_triggers(0), cargo_threshold(0), cargo_triggers{},
callback_mask(0), flags(0) callback_mask(0), flags(0)
{} {}

View File

@ -862,7 +862,7 @@ static void ProcessNewGRFStringControlCode(char32_t scc, StringConsumer &consume
case SCC_NEWGRF_PRINT_WORD_CARGO_NAME: { case SCC_NEWGRF_PRINT_WORD_CARGO_NAME: {
CargoType cargo = GetCargoTranslation(stack.PopUnsignedWord(), stack.grffile); CargoType cargo = GetCargoTranslation(stack.PopUnsignedWord(), stack.grffile);
params.emplace_back(cargo < NUM_CARGO ? 1ULL << cargo : 0); params.emplace_back(cargo < NUM_CARGO ? CargoTypes{cargo}.base() : 0);
break; break;
} }
} }

View File

@ -635,7 +635,7 @@ static void AddAcceptedCargo_Object(TileIndex tile, CargoArray &acceptance, Carg
CargoType pass = GetCargoTypeByLabel(CT_PASSENGERS); CargoType pass = GetCargoTypeByLabel(CT_PASSENGERS);
if (IsValidCargoType(pass)) { if (IsValidCargoType(pass)) {
acceptance[pass] += std::max(1U, level); acceptance[pass] += std::max(1U, level);
SetBit(always_accepted, pass); always_accepted.Set(pass);
} }
/* Top town building generates 4, HQ can make up to 8. The /* Top town building generates 4, HQ can make up to 8. The
@ -645,7 +645,7 @@ static void AddAcceptedCargo_Object(TileIndex tile, CargoArray &acceptance, Carg
CargoType mail = GetCargoTypeByLabel(CT_MAIL); CargoType mail = GetCargoTypeByLabel(CT_MAIL);
if (IsValidCargoType(mail)) { if (IsValidCargoType(mail)) {
acceptance[mail] += std::max(1U, level / 2); acceptance[mail] += std::max(1U, level / 2);
SetBit(always_accepted, mail); always_accepted.Set(mail);
} }
} }

View File

@ -368,7 +368,7 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, VehicleOrderI
next = v->cur_implicit_order_index; next = v->cur_implicit_order_index;
if (next >= this->GetNumOrders()) { if (next >= this->GetNumOrders()) {
next = this->GetFirstOrder(); next = this->GetFirstOrder();
if (next == INVALID_VEH_ORDER_ID) return StationID::Invalid().base(); if (next == INVALID_VEH_ORDER_ID) return StationID::Invalid();
} else { } else {
/* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list. /* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list.
* As the given "next" is already valid and a station in the list, we * As the given "next" is already valid and a station in the list, we
@ -404,11 +404,11 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, VehicleOrderI
if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) && if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) &&
orders[next].GetDestination() == v->last_station_visited && orders[next].GetDestination() == v->last_station_visited &&
(orders[next].GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) { (orders[next].GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
return StationID::Invalid().base(); return StationID::Invalid();
} }
} while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited); } while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited);
return orders[next].GetDestination().ToStationID().base(); return orders[next].GetDestination().ToStationID();
} }
/** /**

View File

@ -358,9 +358,9 @@ void DoPaletteAnimations()
* @param threshold Background colour brightness threshold below which the background is considered dark and TC_WHITE is returned, range: 0 - 255, default 128. * @param threshold Background colour brightness threshold below which the background is considered dark and TC_WHITE is returned, range: 0 - 255, default 128.
* @return TC_BLACK or TC_WHITE depending on what gives a better contrast. * @return TC_BLACK or TC_WHITE depending on what gives a better contrast.
*/ */
TextColour GetContrastColour(uint8_t background, uint8_t threshold) TextColour GetContrastColour(PixelColour background, uint8_t threshold)
{ {
Colour c = _cur_palette.palette[background]; Colour c = _cur_palette.palette[background.p];
/* Compute brightness according to http://www.w3.org/TR/AERT#color-contrast. /* Compute brightness according to http://www.w3.org/TR/AERT#color-contrast.
* The following formula computes 1000 * brightness^2, with brightness being in range 0 to 255. */ * The following formula computes 1000 * brightness^2, with brightness being in range 0 to 255. */
uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114; uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114;
@ -374,7 +374,7 @@ TextColour GetContrastColour(uint8_t background, uint8_t threshold)
*/ */
struct ColourGradients struct ColourGradients
{ {
using ColourGradient = std::array<uint8_t, SHADE_END>; using ColourGradient = std::array<PixelColour, SHADE_END>;
static inline std::array<ColourGradient, COLOUR_END> gradient{}; static inline std::array<ColourGradient, COLOUR_END> gradient{};
}; };
@ -385,7 +385,7 @@ struct ColourGradients
* @param shade Shade level from 1 to 7. * @param shade Shade level from 1 to 7.
* @returns palette index of colour. * @returns palette index of colour.
*/ */
uint8_t GetColourGradient(Colours colour, ColourShade shade) PixelColour GetColourGradient(Colours colour, ColourShade shade)
{ {
return ColourGradients::gradient[colour % COLOUR_END][shade % SHADE_END]; return ColourGradients::gradient[colour % COLOUR_END][shade % SHADE_END];
} }
@ -396,7 +396,7 @@ uint8_t GetColourGradient(Colours colour, ColourShade shade)
* @param shade Shade level from 1 to 7. * @param shade Shade level from 1 to 7.
* @param palette_index Palette index to set. * @param palette_index Palette index to set.
*/ */
void SetColourGradient(Colours colour, ColourShade shade, uint8_t palette_index) void SetColourGradient(Colours colour, ColourShade shade, PixelColour palette_index)
{ {
assert(colour < COLOUR_END); assert(colour < COLOUR_END);
assert(shade < SHADE_END); assert(shade < SHADE_END);

View File

@ -67,7 +67,7 @@ inline bool IsValidColours(Colours colours)
return colours < COLOUR_END; return colours < COLOUR_END;
} }
TextColour GetContrastColour(uint8_t background, uint8_t threshold = 128); TextColour GetContrastColour(PixelColour background, uint8_t threshold = 128);
enum ColourShade : uint8_t { enum ColourShade : uint8_t {
SHADE_BEGIN = 0, SHADE_BEGIN = 0,
@ -83,45 +83,45 @@ enum ColourShade : uint8_t {
}; };
DECLARE_INCREMENT_DECREMENT_OPERATORS(ColourShade) DECLARE_INCREMENT_DECREMENT_OPERATORS(ColourShade)
uint8_t GetColourGradient(Colours colour, ColourShade shade); PixelColour GetColourGradient(Colours colour, ColourShade shade);
void SetColourGradient(Colours colour, ColourShade shade, uint8_t palette_colour); void SetColourGradient(Colours colour, ColourShade shade, PixelColour palette_colour);
/** /**
* Return the colour for a particular greyscale level. * Return the colour for a particular greyscale level.
* @param level Intensity, 0 = black, 15 = white * @param level Intensity, 0 = black, 15 = white
* @return colour * @return colour
*/ */
constexpr uint8_t GREY_SCALE(uint8_t level) { return level; } inline constexpr PixelColour GREY_SCALE(uint8_t level) { return PixelColour{level}; }
static const uint8_t PC_BLACK = GREY_SCALE(1); ///< Black palette colour. static constexpr PixelColour PC_BLACK {GREY_SCALE(1)}; ///< Black palette colour.
static const uint8_t PC_DARK_GREY = GREY_SCALE(6); ///< Dark grey palette colour. static constexpr PixelColour PC_DARK_GREY {GREY_SCALE(6)}; ///< Dark grey palette colour.
static const uint8_t PC_GREY = GREY_SCALE(10); ///< Grey palette colour. static constexpr PixelColour PC_GREY {GREY_SCALE(10)}; ///< Grey palette colour.
static const uint8_t PC_WHITE = GREY_SCALE(15); ///< White palette colour. static constexpr PixelColour PC_WHITE {GREY_SCALE(15)}; ///< White palette colour.
static const uint8_t PC_VERY_DARK_RED = 0xB2; ///< Almost-black red palette colour. static constexpr PixelColour PC_VERY_DARK_RED {0xB2}; ///< Almost-black red palette colour.
static const uint8_t PC_DARK_RED = 0xB4; ///< Dark red palette colour. static constexpr PixelColour PC_DARK_RED {0xB4}; ///< Dark red palette colour.
static const uint8_t PC_RED = 0xB8; ///< Red palette colour. static constexpr PixelColour PC_RED {0xB8}; ///< Red palette colour.
static const uint8_t PC_VERY_DARK_BROWN = 0x56; ///< Almost-black brown palette colour. static constexpr PixelColour PC_VERY_DARK_BROWN {0x56}; ///< Almost-black brown palette colour.
static const uint8_t PC_ORANGE = 0xC2; ///< Orange palette colour. static constexpr PixelColour PC_ORANGE {0xC2}; ///< Orange palette colour.
static const uint8_t PC_YELLOW = 0xBF; ///< Yellow palette colour. static constexpr PixelColour PC_YELLOW {0xBF}; ///< Yellow palette colour.
static const uint8_t PC_LIGHT_YELLOW = 0x44; ///< Light yellow palette colour. static constexpr PixelColour PC_LIGHT_YELLOW {0x44}; ///< Light yellow palette colour.
static const uint8_t PC_VERY_LIGHT_YELLOW = 0x45; ///< Almost-white yellow palette colour. static constexpr PixelColour PC_VERY_LIGHT_YELLOW {0x45}; ///< Almost-white yellow palette colour.
static const uint8_t PC_GREEN = 0xD0; ///< Green palette colour. static constexpr PixelColour PC_GREEN {0xD0}; ///< Green palette colour.
static const uint8_t PC_VERY_DARK_BLUE = 0x9A; ///< Almost-black blue palette colour. static constexpr PixelColour PC_VERY_DARK_BLUE {0x9A}; ///< Almost-black blue palette colour.
static const uint8_t PC_DARK_BLUE = 0x9D; ///< Dark blue palette colour. static constexpr PixelColour PC_DARK_BLUE {0x9D}; ///< Dark blue palette colour.
static const uint8_t PC_LIGHT_BLUE = 0x98; ///< Light blue palette colour. static constexpr PixelColour PC_LIGHT_BLUE {0x98}; ///< Light blue palette colour.
static const uint8_t PC_ROUGH_LAND = 0x52; ///< Dark green palette colour for rough land. static constexpr PixelColour PC_ROUGH_LAND {0x52}; ///< Dark green palette colour for rough land.
static const uint8_t PC_GRASS_LAND = 0x54; ///< Dark green palette colour for grass land. static constexpr PixelColour PC_GRASS_LAND {0x54}; ///< Dark green palette colour for grass land.
static const uint8_t PC_BARE_LAND = 0x37; ///< Brown palette colour for bare land. static constexpr PixelColour PC_BARE_LAND {0x37}; ///< Brown palette colour for bare land.
static const uint8_t PC_RAINFOREST = 0x5C; ///< Pale green palette colour for rainforest. static constexpr PixelColour PC_RAINFOREST {0x5C}; ///< Pale green palette colour for rainforest.
static const uint8_t PC_FIELDS = 0x25; ///< Light brown palette colour for fields. static constexpr PixelColour PC_FIELDS {0x25}; ///< Light brown palette colour for fields.
static const uint8_t PC_TREES = 0x57; ///< Green palette colour for trees. static constexpr PixelColour PC_TREES {0x57}; ///< Green palette colour for trees.
static const uint8_t PC_WATER = 0xC9; ///< Dark blue palette colour for water. static constexpr PixelColour PC_WATER {0xC9}; ///< Dark blue palette colour for water.
#endif /* PALETTE_FUNC_H */ #endif /* PALETTE_FUNC_H */

View File

@ -234,7 +234,7 @@ public:
/** /**
* Colour on mini-map * Colour on mini-map
*/ */
uint8_t map_colour; PixelColour map_colour;
/** /**
* Introduction date. * Introduction date.

View File

@ -145,7 +145,7 @@ public:
/** /**
* Colour on mini-map * Colour on mini-map
*/ */
uint8_t map_colour; PixelColour map_colour;
/** /**
* Introduction date. * Introduction date.

View File

@ -36,7 +36,7 @@ void DrawRoadVehDetails(const Vehicle *v, const Rect &r)
if (v->HasArticulatedPart()) { if (v->HasArticulatedPart()) {
CargoArray max_cargo{}; CargoArray max_cargo{};
std::array<StringID, NUM_CARGO> subtype_text{}; TypedIndexContainer<std::array<StringID, NUM_CARGO>, CargoType> subtype_text{};
for (const Vehicle *u = v; u != nullptr; u = u->Next()) { for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
max_cargo[u->cargo_type] += u->cargo_cap; max_cargo[u->cargo_type] += u->cargo_cap;

View File

@ -359,7 +359,7 @@ public:
SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, SL_MIN_VERSION, SLV_170), SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, SL_MIN_VERSION, SLV_170),
SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, 32, SLV_170, SLV_EXTEND_CARGOTYPES), SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, 32, SLV_170, SLV_EXTEND_CARGOTYPES),
SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION), SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION),
SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32), SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32),
}; };
static inline const SaveLoadCompatTable compat_description = _company_economy_compat; static inline const SaveLoadCompatTable compat_description = _company_economy_compat;

View File

@ -383,7 +383,7 @@ public:
{ {
Station *st = Station::From(bst); Station *st = Station::From(bst);
SlSetStructListLength(NUM_CARGO); SlSetStructListLength(std::size(st->goods));
for (GoodsEntry &ge : st->goods) { for (GoodsEntry &ge : st->goods) {
SlStationGoods::cargo_reserved_count = ge.HasData() ? ge.GetData().cargo.reserved_count : 0; SlStationGoods::cargo_reserved_count = ge.HasData() ? ge.GetData().cargo.reserved_count : 0;

View File

@ -32,7 +32,7 @@
{ {
if (!IsValidCargo(cargo_type)) return std::nullopt; if (!IsValidCargo(cargo_type)) return std::nullopt;
return ::StrMakeValid(::GetString(STR_JUST_CARGO_LIST, 1ULL << cargo_type), {}); return ::StrMakeValid(::GetString(STR_JUST_CARGO_LIST, CargoTypes{cargo_type}), {});
} }
/* static */ std::optional<std::string> ScriptCargo::GetCargoLabel(CargoType cargo_type) /* static */ std::optional<std::string> ScriptCargo::GetCargoLabel(CargoType cargo_type)

View File

@ -60,9 +60,9 @@ public:
*/ */
enum SpecialCargoType { enum SpecialCargoType {
/* Note: these values represent part of the in-game CargoTypes enum */ /* Note: these values represent part of the in-game CargoTypes enum */
CT_AUTO_REFIT = ::CARGO_AUTO_REFIT, ///< Automatically choose cargo type when doing auto-refitting. CT_AUTO_REFIT = ::CARGO_AUTO_REFIT.base(), ///< Automatically choose cargo type when doing auto-refitting.
CT_NO_REFIT = ::CARGO_NO_REFIT, ///< Do not refit cargo of a vehicle. CT_NO_REFIT = ::CARGO_NO_REFIT.base(), ///< Do not refit cargo of a vehicle.
CT_INVALID = ::INVALID_CARGO, ///< An invalid cargo type. CT_INVALID = ::INVALID_CARGO.base(), ///< An invalid cargo type.
}; };
/** /**

View File

@ -20,7 +20,7 @@
ScriptCargoList::ScriptCargoList() ScriptCargoList::ScriptCargoList()
{ {
for (const CargoSpec *cs : CargoSpec::Iterate()) { for (const CargoSpec *cs : CargoSpec::Iterate()) {
this->AddItem(cs->Index()); this->AddItem(cs->Index().base());
} }
} }
@ -31,7 +31,7 @@ ScriptCargoList_IndustryAccepting::ScriptCargoList_IndustryAccepting(IndustryID
const Industry *ind = ::Industry::Get(industry_id); const Industry *ind = ::Industry::Get(industry_id);
for (const auto &a : ind->accepted) { for (const auto &a : ind->accepted) {
if (::IsValidCargoType(a.cargo)) { if (::IsValidCargoType(a.cargo)) {
this->AddItem(a.cargo); this->AddItem(a.cargo.base());
} }
} }
} }
@ -43,7 +43,7 @@ ScriptCargoList_IndustryProducing::ScriptCargoList_IndustryProducing(IndustryID
const Industry *ind = ::Industry::Get(industry_id); const Industry *ind = ::Industry::Get(industry_id);
for (const auto &p : ind->produced) { for (const auto &p : ind->produced) {
if (::IsValidCargoType(p.cargo)) { if (::IsValidCargoType(p.cargo)) {
this->AddItem(p.cargo); this->AddItem(p.cargo.base());
} }
} }
} }
@ -53,7 +53,7 @@ ScriptCargoList_StationAccepting::ScriptCargoList_StationAccepting(StationID sta
if (!ScriptStation::IsValidStation(station_id)) return; if (!ScriptStation::IsValidStation(station_id)) return;
const Station *st = ::Station::Get(station_id); const Station *st = ::Station::Get(station_id);
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
if (st->goods[cargo].status.Test(GoodsEntry::State::Acceptance)) this->AddItem(cargo); if (st->goods[cargo].status.Test(GoodsEntry::State::Acceptance)) this->AddItem(cargo.base());
} }
} }

View File

@ -67,7 +67,7 @@
if (!IsValidEngine(engine_id)) return false; if (!IsValidEngine(engine_id)) return false;
if (!ScriptCargo::IsValidCargo(cargo_type)) return false; if (!ScriptCargo::IsValidCargo(cargo_type)) return false;
return HasBit(::GetUnionOfArticulatedRefitMasks(engine_id, true), cargo_type); return ::GetUnionOfArticulatedRefitMasks(engine_id, true).Test(cargo_type);
} }
/* static */ bool ScriptEngine::CanPullCargo(EngineID engine_id, CargoType cargo_type) /* static */ bool ScriptEngine::CanPullCargo(EngineID engine_id, CargoType cargo_type)

View File

@ -72,7 +72,7 @@
ScriptList *list = new ScriptList(); ScriptList *list = new ScriptList();
for (const CargoType &cargo : ins->produced_cargo) { for (const CargoType &cargo : ins->produced_cargo) {
if (::IsValidCargoType(cargo)) list->AddItem(cargo); if (::IsValidCargoType(cargo)) list->AddItem(cargo.base());
} }
return list; return list;
@ -86,7 +86,7 @@
ScriptList *list = new ScriptList(); ScriptList *list = new ScriptList();
for (const CargoType &cargo : ins->accepts_cargo) { for (const CargoType &cargo : ins->accepts_cargo) {
if (::IsValidCargoType(cargo)) list->AddItem(cargo); if (::IsValidCargoType(cargo)) list->AddItem(cargo.base());
} }
return list; return list;

View File

@ -99,7 +99,7 @@ uint BaseSettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int
int x = rtl ? right : left; int x = rtl ? right : left;
if (cur_row >= first_row) { if (cur_row >= first_row) {
int colour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL); PixelColour colour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
y += (cur_row - first_row) * SETTING_HEIGHT; // Compute correct y start position y += (cur_row - first_row) * SETTING_HEIGHT; // Compute correct y start position
/* Draw vertical for parent nesting levels */ /* Draw vertical for parent nesting levels */

View File

@ -1849,7 +1849,7 @@ void ShowGameOptions()
*/ */
void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_left, bool clickable_right) void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_left, bool clickable_right)
{ {
int colour = GetColourGradient(button_colour, SHADE_DARKER); PixelColour colour = GetColourGradient(button_colour, SHADE_DARKER);
Dimension dim = NWidgetScrollbar::GetHorizontalDimension(); Dimension dim = NWidgetScrollbar::GetHorizontalDimension();
Rect lr = {x, y, x + (int)dim.width - 1, y + (int)dim.height - 1}; Rect lr = {x, y, x + (int)dim.width - 1, y + (int)dim.height - 1};
@ -1881,7 +1881,7 @@ void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool c
*/ */
void DrawUpDownButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_up, bool clickable_down) void DrawUpDownButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_up, bool clickable_down)
{ {
int colour = GetColourGradient(button_colour, SHADE_DARKER); PixelColour colour = GetColourGradient(button_colour, SHADE_DARKER);
Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1}; Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1};
Rect ur = r.WithWidth(SETTING_BUTTON_WIDTH / 2, (_current_text_dir == TD_RTL)); Rect ur = r.WithWidth(SETTING_BUTTON_WIDTH / 2, (_current_text_dir == TD_RTL));
@ -1907,7 +1907,7 @@ void DrawUpDownButtons(int x, int y, Colours button_colour, uint8_t state, bool
*/ */
void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable) void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable)
{ {
int colour = GetColourGradient(button_colour, SHADE_DARKER); PixelColour colour = GetColourGradient(button_colour, SHADE_DARKER);
Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1}; Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1};

View File

@ -45,9 +45,9 @@ void DrawSliderWidget(Rect r, Colours wedge_colour, Colours handle_colour, TextC
int wx1 = r.left + sw / 2; int wx1 = r.left + sw / 2;
int wx2 = r.right - sw / 2; int wx2 = r.right - sw / 2;
if (_current_text_dir == TD_RTL) std::swap(wx1, wx2); if (_current_text_dir == TD_RTL) std::swap(wx1, wx2);
const uint shadow = GetColourGradient(wedge_colour, SHADE_DARK); const PixelColour shadow = GetColourGradient(wedge_colour, SHADE_DARK);
const uint fill = GetColourGradient(wedge_colour, SHADE_LIGHTER); const PixelColour fill = GetColourGradient(wedge_colour, SHADE_LIGHTER);
const uint light = GetColourGradient(wedge_colour, SHADE_LIGHTEST); const PixelColour light = GetColourGradient(wedge_colour, SHADE_LIGHTEST);
const std::array<Point, 3> wedge{ Point{wx1, r.bottom - ha}, Point{wx2, r.top + ha}, Point{wx2, r.bottom - ha} }; const std::array<Point, 3> wedge{ Point{wx1, r.bottom - ha}, Point{wx2, r.top + ha}, Point{wx2, r.bottom - ha} };
GfxFillPolygon(wedge, fill); GfxFillPolygon(wedge, fill);
GfxDrawLine(wedge[0].x, wedge[0].y, wedge[2].x, wedge[2].y, light, t); GfxDrawLine(wedge[0].x, wedge[0].y, wedge[2].x, wedge[2].y, light, t);

View File

@ -44,7 +44,7 @@ static int _smallmap_cargo_count; ///< Number of cargos in the link stats leg
/** Structure for holding relevant data for legends in small map */ /** Structure for holding relevant data for legends in small map */
struct LegendAndColour { struct LegendAndColour {
uint8_t colour; ///< Colour of the item on the map. PixelColour colour; ///< Colour of the item on the map.
StringID legend; ///< String corresponding to the coloured item. StringID legend; ///< String corresponding to the coloured item.
IndustryType type; ///< Type of industry. Only valid for industry entries. IndustryType type; ///< Type of industry. Only valid for industry entries.
uint8_t height; ///< Height in tiles. Only valid for height legend entries. uint8_t height; ///< Height in tiles. Only valid for height legend entries.
@ -63,16 +63,16 @@ static const int NUM_NO_COMPANY_ENTRIES = 4; ///< Number of entries in the owner
#define MK(a, b) {a, b, IT_INVALID, 0, CompanyID::Invalid(), true, false, false} #define MK(a, b) {a, b, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
/** Macro for a height legend entry with configurable colour. */ /** Macro for a height legend entry with configurable colour. */
#define MC(col_break) {0, STR_TINY_BLACK_HEIGHT, IT_INVALID, 0, CompanyID::Invalid(), true, false, col_break} #define MC(col_break) {{}, STR_TINY_BLACK_HEIGHT, IT_INVALID, 0, CompanyID::Invalid(), true, false, col_break}
/** Macro for non-company owned property entry of LegendAndColour */ /** Macro for non-company owned property entry of LegendAndColour */
#define MO(a, b) {a, b, IT_INVALID, 0, CompanyID::Invalid(), true, false, false} #define MO(a, b) {a, b, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
/** Macro used for forcing a rebuild of the owner legend the first time it is used. */ /** Macro used for forcing a rebuild of the owner legend the first time it is used. */
#define MOEND() {0, STR_NULL, IT_INVALID, 0, OWNER_NONE, true, true, false} #define MOEND() {{}, STR_NULL, IT_INVALID, 0, OWNER_NONE, true, true, false}
/** Macro for end of list marker in arrays of LegendAndColour */ /** Macro for end of list marker in arrays of LegendAndColour */
#define MKEND() {0, STR_NULL, IT_INVALID, 0, CompanyID::Invalid(), true, true, false} #define MKEND() {{}, STR_NULL, IT_INVALID, 0, CompanyID::Invalid(), true, true, false}
/** /**
* Macro for break marker in arrays of LegendAndColour. * Macro for break marker in arrays of LegendAndColour.
@ -149,7 +149,7 @@ static const LegendAndColour _legend_vegetation[] = {
static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = { static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER), MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER),
MO(0x00, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings. MO({}, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings.
MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS), MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS),
MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES), MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES),
/* The legend will be terminated the first time it is used. */ /* The legend will be terminated the first time it is used. */
@ -227,7 +227,7 @@ void BuildLinkStatsLegend()
_legend_linkstats[i].legend = cs->name; _legend_linkstats[i].legend = cs->name;
_legend_linkstats[i].colour = cs->legend_colour; _legend_linkstats[i].colour = cs->legend_colour;
_legend_linkstats[i].type = cs->Index(); _legend_linkstats[i].type = cs->Index().base(); /// IndustryType!?
_legend_linkstats[i].show_on_map = true; _legend_linkstats[i].show_on_map = true;
} }
@ -258,15 +258,15 @@ static const LegendAndColour * const _legend_table[] = {
#define MKCOLOUR(x) TO_LE32(x) #define MKCOLOUR(x) TO_LE32(x)
#define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x)) #define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x.p))
#define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x)) #define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x.p))
#define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x)) #define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x.p))
#define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y)) #define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y))
#define MKCOLOUR_0000 MKCOLOUR_XXXX(0x00) #define MKCOLOUR_0000 MKCOLOUR_XXXX(PixelColour{0x00})
#define MKCOLOUR_F00F MKCOLOUR_X00X(0xFF) #define MKCOLOUR_F00F MKCOLOUR_X00X(PixelColour{0xFF})
#define MKCOLOUR_FFFF MKCOLOUR_XXXX(0xFF) #define MKCOLOUR_FFFF MKCOLOUR_XXXX(PixelColour{0xFF})
#include "table/heightmap_colours.h" #include "table/heightmap_colours.h"
@ -279,9 +279,9 @@ struct SmallMapColourScheme {
/** Available colour schemes for height maps. */ /** Available colour schemes for height maps. */
static SmallMapColourScheme _heightmap_schemes[] = { static SmallMapColourScheme _heightmap_schemes[] = {
{{}, _green_map_heights, MKCOLOUR_XXXX(0x54)}, ///< Green colour scheme. {{}, _green_map_heights, MKCOLOUR_XXXX(PixelColour{0x54})}, ///< Green colour scheme.
{{}, _dark_green_map_heights, MKCOLOUR_XXXX(0x62)}, ///< Dark green colour scheme. {{}, _dark_green_map_heights, MKCOLOUR_XXXX(PixelColour{0x62})}, ///< Dark green colour scheme.
{{}, _violet_map_heights, MKCOLOUR_XXXX(0x81)}, ///< Violet colour scheme. {{}, _violet_map_heights, MKCOLOUR_XXXX(PixelColour{0x81})}, ///< Violet colour scheme.
}; };
/** /**
@ -329,7 +329,7 @@ void BuildLandLegend()
_legend_land_contours[i].col_break = j % rows == 0; _legend_land_contours[i].col_break = j % rows == 0;
_legend_land_contours[i].end = false; _legend_land_contours[i].end = false;
_legend_land_contours[i].height = j * delta; _legend_land_contours[i].height = j * delta;
_legend_land_contours[i].colour = static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[_legend_land_contours[i].height]); _legend_land_contours[i].colour = PixelColour{static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[_legend_land_contours[i].height])};
j++; j++;
} }
_legend_land_contours[i].end = true; _legend_land_contours[i].end = true;
@ -340,7 +340,7 @@ void BuildLandLegend()
*/ */
void BuildOwnerLegend() void BuildOwnerLegend()
{ {
_legend_land_owners[1].colour = static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour); _legend_land_owners[1].colour = PixelColour{static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour)};
int i = NUM_NO_COMPANY_ENTRIES; int i = NUM_NO_COMPANY_ENTRIES;
for (const Company *c : Company::Iterate()) { for (const Company *c : Company::Iterate()) {
@ -607,7 +607,7 @@ uint32_t GetSmallMapOwnerPixels(TileIndex tile, TileType t, IncludeHeightmap inc
} }
/** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleType. */ /** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleType. */
static const uint8_t _vehicle_type_colours[6] = { static const PixelColour _vehicle_type_colours[6] = {
PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED
}; };
@ -935,7 +935,7 @@ protected:
uint8_t *val8 = (uint8_t *)&val; uint8_t *val8 = (uint8_t *)&val;
int idx = std::max(0, -start_pos); int idx = std::max(0, -start_pos);
for (int pos = std::max(0, start_pos); pos < end_pos; pos++) { for (int pos = std::max(0, start_pos); pos < end_pos; pos++) {
blitter->SetPixel(dst, idx, 0, val8[idx]); blitter->SetPixel(dst, idx, 0, PixelColour{val8[idx]});
idx++; idx++;
} }
/* Switch to next tile in the column */ /* Switch to next tile in the column */
@ -973,7 +973,7 @@ protected:
} }
/* Calculate pointer to pixel and the colour */ /* Calculate pointer to pixel and the colour */
uint8_t colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE; PixelColour colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE;
/* And draw either one or two pixels depending on clipping */ /* And draw either one or two pixels depending on clipping */
blitter->SetPixel(dpi->dst_ptr, x, y, colour); blitter->SetPixel(dpi->dst_ptr, x, y, colour);
@ -1254,9 +1254,9 @@ protected:
*/ */
void SetOverlayCargoMask() void SetOverlayCargoMask()
{ {
CargoTypes cargo_mask = 0; CargoTypes cargo_mask{};
for (int i = 0; i != _smallmap_cargo_count; ++i) { for (int i = 0; i != _smallmap_cargo_count; ++i) {
if (_legend_linkstats[i].show_on_map) SetBit(cargo_mask, _legend_linkstats[i].type); if (_legend_linkstats[i].show_on_map) cargo_mask.Set(static_cast<CargoType>(_legend_linkstats[i].type));
} }
this->overlay->SetCargoMask(cargo_mask); this->overlay->SetCargoMask(cargo_mask);
} }
@ -1348,7 +1348,7 @@ protected:
if (type == _smallmap_industry_highlight) { if (type == _smallmap_industry_highlight) {
if (_smallmap_industry_highlight_state) return MKCOLOUR_XXXX(PC_WHITE); if (_smallmap_industry_highlight_state) return MKCOLOUR_XXXX(PC_WHITE);
} else { } else {
return GetIndustrySpec(type)->map_colour * 0x01010101; return GetIndustrySpec(type)->map_colour.p * 0x01010101;
} }
} }
/* Otherwise make it disappear */ /* Otherwise make it disappear */
@ -1453,7 +1453,7 @@ public:
SmallMapWindow(WindowDesc &desc, int window_number) : Window(desc) SmallMapWindow(WindowDesc &desc, int window_number) : Window(desc)
{ {
_smallmap_industry_highlight = IT_INVALID; _smallmap_industry_highlight = IT_INVALID;
this->overlay = std::make_unique<LinkGraphOverlay>(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); this->overlay = std::make_unique<LinkGraphOverlay>(this, WID_SM_MAP, CargoTypes{}, this->GetOverlayCompanyMask(), 1);
this->CreateNestedTree(); this->CreateNestedTree();
this->LowerWidget(WID_SM_CONTOUR + this->map_type); this->LowerWidget(WID_SM_CONTOUR + this->map_type);
@ -1644,7 +1644,7 @@ public:
i = 1; i = 1;
} }
uint8_t legend_colour = tbl->colour; PixelColour legend_colour = tbl->colour;
std::array<StringParameter, 2> params{}; std::array<StringParameter, 2> params{};
switch (this->map_type) { switch (this->map_type) {

View File

@ -100,7 +100,7 @@ Station::~Station()
if (a->targetairport == this->index) a->targetairport = StationID::Invalid(); if (a->targetairport == this->index) a->targetairport = StationID::Invalid();
} }
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
LinkGraph *lg = LinkGraph::GetIfValid(this->goods[cargo].link_graph); LinkGraph *lg = LinkGraph::GetIfValid(this->goods[cargo].link_graph);
if (lg == nullptr) continue; if (lg == nullptr) continue;

View File

@ -526,7 +526,7 @@ public:
uint8_t last_vehicle_type = 0; uint8_t last_vehicle_type = 0;
std::list<Vehicle *> loading_vehicles{}; std::list<Vehicle *> loading_vehicles{};
std::array<GoodsEntry, NUM_CARGO> goods; ///< Goods at this station TypedIndexContainer<std::array<GoodsEntry, NUM_CARGO>, CargoType> goods; ///< Goods at this station
CargoTypes always_accepted{}; ///< Bitmask of always accepted cargo types (by houses, HQs, industry tiles when industry doesn't accept cargo) CargoTypes always_accepted{}; ///< Bitmask of always accepted cargo types (by houses, HQs, industry tiles when industry doesn't accept cargo)
IndustryList industries_near{}; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry() IndustryList industries_near{}; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry()

View File

@ -499,10 +499,10 @@ void ClearAllStationCachedNames()
*/ */
CargoTypes GetAcceptanceMask(const Station *st) CargoTypes GetAcceptanceMask(const Station *st)
{ {
CargoTypes mask = 0; CargoTypes mask{};
for (auto it = std::begin(st->goods); it != std::end(st->goods); ++it) { for (auto it = std::begin(st->goods); it != std::end(st->goods); ++it) {
if (it->status.Test(GoodsEntry::State::Acceptance)) SetBit(mask, std::distance(std::begin(st->goods), it)); if (it->status.Test(GoodsEntry::State::Acceptance)) mask.Set(static_cast<CargoType>(std::distance(std::begin(st->goods), it)));
} }
return mask; return mask;
} }
@ -514,10 +514,10 @@ CargoTypes GetAcceptanceMask(const Station *st)
*/ */
CargoTypes GetEmptyMask(const Station *st) CargoTypes GetEmptyMask(const Station *st)
{ {
CargoTypes mask = 0; CargoTypes mask{};
for (auto it = std::begin(st->goods); it != std::end(st->goods); ++it) { for (auto it = std::begin(st->goods); it != std::end(st->goods); ++it) {
if (!it->HasData() || it->GetData().cargo.TotalCount() == 0) SetBit(mask, std::distance(std::begin(st->goods), it)); if (!it->HasData() || it->GetData().cargo.TotalCount() == 0) mask.Set(static_cast<CargoType>(std::distance(std::begin(st->goods), it)));
} }
return mask; return mask;
} }
@ -582,7 +582,7 @@ CargoArray GetProductionAroundTiles(TileIndex north_tile, int w, int h, int rad)
CargoArray GetAcceptanceAroundTiles(TileIndex center_tile, int w, int h, int rad, CargoTypes *always_accepted) CargoArray GetAcceptanceAroundTiles(TileIndex center_tile, int w, int h, int rad, CargoTypes *always_accepted)
{ {
CargoArray acceptance{}; CargoArray acceptance{};
if (always_accepted != nullptr) *always_accepted = 0; if (always_accepted != nullptr) always_accepted->Reset();
TileArea ta = TileArea(center_tile, w, h).Expand(rad); TileArea ta = TileArea(center_tile, w, h).Expand(rad);
@ -604,7 +604,7 @@ CargoArray GetAcceptanceAroundTiles(TileIndex center_tile, int w, int h, int rad
static CargoArray GetAcceptanceAroundStation(const Station *st, CargoTypes *always_accepted) static CargoArray GetAcceptanceAroundStation(const Station *st, CargoTypes *always_accepted)
{ {
CargoArray acceptance{}; CargoArray acceptance{};
if (always_accepted != nullptr) *always_accepted = 0; if (always_accepted != nullptr) always_accepted->Reset();
BitmapTileIterator it(st->catchment_tiles); BitmapTileIterator it(st->catchment_tiles);
for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) { for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
@ -631,7 +631,7 @@ void UpdateStationAcceptance(Station *st, bool show_msg)
} }
/* Adjust in case our station only accepts fewer kinds of goods */ /* Adjust in case our station only accepts fewer kinds of goods */
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
uint amt = acceptance[cargo]; uint amt = acceptance[cargo];
/* Make sure the station can accept the goods type. */ /* Make sure the station can accept the goods type. */
@ -655,12 +655,12 @@ void UpdateStationAcceptance(Station *st, bool show_msg)
/* show a message to report that the acceptance was changed? */ /* show a message to report that the acceptance was changed? */
if (show_msg && st->owner == _local_company && st->IsInUse()) { if (show_msg && st->owner == _local_company && st->IsInUse()) {
/* Combine old and new masks to get changes */ /* Combine old and new masks to get changes */
CargoTypes accepts = new_acc & ~old_acc; CargoTypes accepts = new_acc & CargoTypes{old_acc}.Flip();
CargoTypes rejects = ~new_acc & old_acc; CargoTypes rejects = CargoTypes{new_acc}.Flip() & old_acc;
/* Show news message if there are any changes */ /* Show news message if there are any changes */
if (accepts != 0) ShowRejectOrAcceptNews(st, accepts, false); if (accepts.Any()) ShowRejectOrAcceptNews(st, accepts, false);
if (rejects != 0) ShowRejectOrAcceptNews(st, rejects, true); if (rejects.Any()) ShowRejectOrAcceptNews(st, rejects, true);
} }
/* redraw the station view since acceptance changed */ /* redraw the station view since acceptance changed */
@ -3760,13 +3760,13 @@ static VehicleEnterTileStates VehicleEnter_Station(Vehicle *v, TileIndex tile, i
void TriggerWatchedCargoCallbacks(Station *st) void TriggerWatchedCargoCallbacks(Station *st)
{ {
/* Collect cargoes accepted since the last big tick. */ /* Collect cargoes accepted since the last big tick. */
CargoTypes cargoes = 0; CargoTypes cargoes{};
for (CargoType cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) { for (CargoType cargo_type{}; cargo_type < NUM_CARGO; ++cargo_type) {
if (st->goods[cargo_type].status.Test(GoodsEntry::State::AcceptedBigtick)) SetBit(cargoes, cargo_type); if (st->goods[cargo_type].status.Test(GoodsEntry::State::AcceptedBigtick)) cargoes.Set(cargo_type);
} }
/* Anything to do? */ /* Anything to do? */
if (cargoes == 0) return; if (cargoes.None()) return;
/* Loop over all houses in the catchment. */ /* Loop over all houses in the catchment. */
BitmapTileIterator it(st->catchment_tiles); BitmapTileIterator it(st->catchment_tiles);
@ -4027,7 +4027,7 @@ void RerouteCargo(Station *st, CargoType cargo, StationID avoid, StationID avoid
*/ */
void DeleteStaleLinks(Station *from) void DeleteStaleLinks(Station *from)
{ {
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
const bool auto_distributed = (_settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL); const bool auto_distributed = (_settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL);
GoodsEntry &ge = from->goods[cargo]; GoodsEntry &ge = from->goods[cargo];
LinkGraph *lg = LinkGraph::GetIfValid(ge.link_graph); LinkGraph *lg = LinkGraph::GetIfValid(ge.link_graph);
@ -5079,7 +5079,7 @@ StationIDStack FlowStatMap::DeleteFlows(StationID via)
FlowStat &s_flows = f_it->second; FlowStat &s_flows = f_it->second;
s_flows.ChangeShare(via, INT_MIN); s_flows.ChangeShare(via, INT_MIN);
if (s_flows.GetShares()->empty()) { if (s_flows.GetShares()->empty()) {
ret.Push(f_it->first.base()); ret.Push(f_it->first);
this->erase(f_it++); this->erase(f_it++);
} else { } else {
++f_it; ++f_it;

View File

@ -76,7 +76,7 @@ using RoadWaypointTypeFilter = GenericWaypointTypeFilter<true, MP_ROAD>;
int DrawStationCoverageAreaText(const Rect &r, StationCoverageType sct, int rad, bool supplies) int DrawStationCoverageAreaText(const Rect &r, StationCoverageType sct, int rad, bool supplies)
{ {
TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y); TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
CargoTypes cargo_mask = 0; CargoTypes cargo_mask{};
if (_thd.drawstyle == HT_RECT && tile < Map::Size()) { if (_thd.drawstyle == HT_RECT && tile < Map::Size()) {
CargoArray cargoes; CargoArray cargoes;
if (supplies) { if (supplies) {
@ -86,14 +86,14 @@ int DrawStationCoverageAreaText(const Rect &r, StationCoverageType sct, int rad,
} }
/* Convert cargo counts to a set of cargo bits, and draw the result. */ /* Convert cargo counts to a set of cargo bits, and draw the result. */
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
switch (sct) { switch (sct) {
case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(cargo, CargoClass::Passengers)) continue; break; case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(cargo, CargoClass::Passengers)) continue; break;
case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(cargo, CargoClass::Passengers)) continue; break; case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(cargo, CargoClass::Passengers)) continue; break;
case SCT_ALL: break; case SCT_ALL: break;
default: NOT_REACHED(); default: NOT_REACHED();
} }
if (cargoes[cargo] >= (supplies ? 1U : 8U)) SetBit(cargo_mask, cargo); if (cargoes[cargo] >= (supplies ? 1U : 8U)) cargo_mask.Set(cargo);
} }
} }
return DrawStringMultiLine(r, GetString(supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO, cargo_mask)); return DrawStringMultiLine(r, GetString(supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO, cargo_mask));
@ -225,7 +225,7 @@ static void StationsWndShowStationRating(int left, int right, int y, CargoType c
int padding = ScaleGUITrad(1); int padding = ScaleGUITrad(1);
int width = right - left; int width = right - left;
int colour = cs->rating_colour; PixelColour colour = cs->rating_colour;
TextColour tc = GetContrastColour(colour); TextColour tc = GetContrastColour(colour);
uint w = std::min(amount + 5, units_full) * width / units_full; uint w = std::min(amount + 5, units_full) * width / units_full;
@ -291,7 +291,7 @@ protected:
Scrollbar *vscroll = nullptr; Scrollbar *vscroll = nullptr;
uint rating_width = 0; uint rating_width = 0;
bool filter_expanded = false; bool filter_expanded = false;
std::array<uint16_t, NUM_CARGO> stations_per_cargo_type{}; ///< Number of stations with a rating for each cargo type. TypedIndexContainer<std::array<uint16_t, NUM_CARGO>, CargoType> stations_per_cargo_type{}; ///< Number of stations with a rating for each cargo type.
uint16_t stations_per_cargo_type_no_rating = 0; ///< Number of stations without a rating. uint16_t stations_per_cargo_type_no_rating = 0; ///< Number of stations without a rating.
/** /**
@ -314,13 +314,13 @@ protected:
if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) { if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) {
bool has_rating = false; bool has_rating = false;
/* Add to the station/cargo counts. */ /* Add to the station/cargo counts. */
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
if (st->goods[cargo].HasRating()) this->stations_per_cargo_type[cargo]++; if (st->goods[cargo].HasRating()) this->stations_per_cargo_type[cargo]++;
} }
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
if (st->goods[cargo].HasRating()) { if (st->goods[cargo].HasRating()) {
has_rating = true; has_rating = true;
if (HasBit(this->filter.cargoes, cargo)) { if (this->filter.cargoes.Test(cargo)) {
this->stations.push_back(st); this->stations.push_back(st);
break; break;
} }
@ -359,7 +359,7 @@ protected:
{ {
int diff = 0; int diff = 0;
for (CargoType cargo : SetCargoBitIterator(cargo_filter)) { for (CargoType cargo : cargo_filter) {
diff += (a->goods[cargo].HasData() ? a->goods[cargo].GetData().cargo.TotalCount() : 0) - (b->goods[cargo].HasData() ? b->goods[cargo].GetData().cargo.TotalCount() : 0); diff += (a->goods[cargo].HasData() ? a->goods[cargo].GetData().cargo.TotalCount() : 0) - (b->goods[cargo].HasData() ? b->goods[cargo].GetData().cargo.TotalCount() : 0);
} }
@ -371,7 +371,7 @@ protected:
{ {
int diff = 0; int diff = 0;
for (CargoType cargo : SetCargoBitIterator(cargo_filter)) { for (CargoType cargo : cargo_filter) {
diff += (a->goods[cargo].HasData() ? a->goods[cargo].GetData().cargo.AvailableCount() : 0) - (b->goods[cargo].HasData() ? b->goods[cargo].GetData().cargo.AvailableCount() : 0); diff += (a->goods[cargo].HasData() ? a->goods[cargo].GetData().cargo.AvailableCount() : 0) - (b->goods[cargo].HasData() ? b->goods[cargo].GetData().cargo.AvailableCount() : 0);
} }
@ -384,7 +384,7 @@ protected:
uint8_t maxr1 = 0; uint8_t maxr1 = 0;
uint8_t maxr2 = 0; uint8_t maxr2 = 0;
for (CargoType cargo : SetCargoBitIterator(cargo_filter)) { for (CargoType cargo : cargo_filter) {
if (a->goods[cargo].HasRating()) maxr1 = std::max(maxr1, a->goods[cargo].rating); if (a->goods[cargo].HasRating()) maxr1 = std::max(maxr1, a->goods[cargo].rating);
if (b->goods[cargo].HasRating()) maxr2 = std::max(maxr2, b->goods[cargo].rating); if (b->goods[cargo].HasRating()) maxr2 = std::max(maxr2, b->goods[cargo].rating);
} }
@ -398,7 +398,7 @@ protected:
uint8_t minr1 = 255; uint8_t minr1 = 255;
uint8_t minr2 = 255; uint8_t minr2 = 255;
for (CargoType cargo : SetCargoBitIterator(cargo_filter)) { for (CargoType cargo : cargo_filter) {
if (a->goods[cargo].HasRating()) minr1 = std::min(minr1, a->goods[cargo].rating); if (a->goods[cargo].HasRating()) minr1 = std::min(minr1, a->goods[cargo].rating);
if (b->goods[cargo].HasRating()) minr2 = std::min(minr2, b->goods[cargo].rating); if (b->goods[cargo].HasRating()) minr2 = std::min(minr2, b->goods[cargo].rating);
} }
@ -558,9 +558,9 @@ public:
} }
if (widget == WID_STL_CARGODROPDOWN) { if (widget == WID_STL_CARGODROPDOWN) {
if (this->filter.cargoes == 0) return GetString(this->filter.include_no_rating ? STR_STATION_LIST_CARGO_FILTER_ONLY_NO_RATING : STR_STATION_LIST_CARGO_FILTER_NO_CARGO_TYPES); if (this->filter.cargoes.None()) return GetString(this->filter.include_no_rating ? STR_STATION_LIST_CARGO_FILTER_ONLY_NO_RATING : STR_STATION_LIST_CARGO_FILTER_NO_CARGO_TYPES);
if (this->filter.cargoes == _cargo_mask) return GetString(this->filter.include_no_rating ? STR_STATION_LIST_CARGO_FILTER_ALL_AND_NO_RATING : STR_CARGO_TYPE_FILTER_ALL); if (this->filter.cargoes == _cargo_mask) return GetString(this->filter.include_no_rating ? STR_STATION_LIST_CARGO_FILTER_ALL_AND_NO_RATING : STR_CARGO_TYPE_FILTER_ALL);
if (CountBits(this->filter.cargoes) == 1 && !this->filter.include_no_rating) return GetString(CargoSpec::Get(FindFirstBit(this->filter.cargoes))->name); if (this->filter.cargoes.Count() == 1 && !this->filter.include_no_rating) return GetString(CargoSpec::Get(*this->filter.cargoes.begin())->name);
return GetString(STR_STATION_LIST_CARGO_FILTER_MULTIPLE); return GetString(STR_STATION_LIST_CARGO_FILTER_MULTIPLE);
} }
@ -573,7 +573,7 @@ public:
using DropDownListCargoItem = DropDownCheck<DropDownString<DropDownListIconItem, FS_SMALL, true>>; using DropDownListCargoItem = DropDownCheck<DropDownString<DropDownListIconItem, FS_SMALL, true>>;
DropDownList list; DropDownList list;
list.push_back(MakeDropDownListStringItem(STR_STATION_LIST_CARGO_FILTER_SELECT_ALL, CargoFilterCriteria::CF_SELECT_ALL)); list.push_back(MakeDropDownListStringItem(STR_STATION_LIST_CARGO_FILTER_SELECT_ALL, CargoFilterCriteria::CF_SELECT_ALL.base()));
list.push_back(MakeDropDownListDividerItem()); list.push_back(MakeDropDownListDividerItem());
bool any_hidden = false; bool any_hidden = false;
@ -582,7 +582,7 @@ public:
if (count == 0 && !expanded) { if (count == 0 && !expanded) {
any_hidden = true; any_hidden = true;
} else { } else {
list.push_back(std::make_unique<DropDownString<DropDownListCheckedItem, FS_SMALL, true>>(fmt::format("{}", count), 0, this->filter.include_no_rating, GetString(STR_STATION_LIST_CARGO_FILTER_NO_RATING), CargoFilterCriteria::CF_NO_RATING, false, count == 0)); list.push_back(std::make_unique<DropDownString<DropDownListCheckedItem, FS_SMALL, true>>(fmt::format("{}", count), 0, this->filter.include_no_rating, GetString(STR_STATION_LIST_CARGO_FILTER_NO_RATING), CargoFilterCriteria::CF_NO_RATING.base(), false, count == 0));
} }
Dimension d = GetLargestCargoIconSize(); Dimension d = GetLargestCargoIconSize();
@ -591,13 +591,13 @@ public:
if (count == 0 && !expanded) { if (count == 0 && !expanded) {
any_hidden = true; any_hidden = true;
} else { } else {
list.push_back(std::make_unique<DropDownListCargoItem>(HasBit(this->filter.cargoes, cs->Index()), fmt::format("{}", count), d, cs->GetCargoIcon(), PAL_NONE, GetString(cs->name), cs->Index(), false, count == 0)); list.push_back(std::make_unique<DropDownListCargoItem>(this->filter.cargoes.Test(cs->Index()), fmt::format("{}", count), d, cs->GetCargoIcon(), PAL_NONE, GetString(cs->name), cs->Index().base(), false, count == 0));
} }
} }
if (!expanded && any_hidden) { if (!expanded && any_hidden) {
if (list.size() > 2) list.push_back(MakeDropDownListDividerItem()); if (list.size() > 2) list.push_back(MakeDropDownListDividerItem());
list.push_back(MakeDropDownListStringItem(STR_STATION_LIST_CARGO_FILTER_EXPAND, CargoFilterCriteria::CF_EXPAND_LIST)); list.push_back(MakeDropDownListStringItem(STR_STATION_LIST_CARGO_FILTER_EXPAND, CargoFilterCriteria::CF_EXPAND_LIST.base()));
} }
return list; return list;
@ -684,11 +684,11 @@ public:
if (widget == WID_STL_CARGODROPDOWN) { if (widget == WID_STL_CARGODROPDOWN) {
FilterState oldstate = this->filter; FilterState oldstate = this->filter;
if (index >= 0 && index < NUM_CARGO) { if (IsInsideMM(index, 0, NUM_CARGO)) {
if (_ctrl_pressed) { if (_ctrl_pressed) {
ToggleBit(this->filter.cargoes, index); this->filter.cargoes.Flip(static_cast<CargoType>(index));
} else { } else {
this->filter.cargoes = 1ULL << index; this->filter.cargoes = static_cast<CargoType>(index);
this->filter.include_no_rating = false; this->filter.include_no_rating = false;
} }
} else if (index == CargoFilterCriteria::CF_NO_RATING) { } else if (index == CargoFilterCriteria::CF_NO_RATING) {
@ -696,7 +696,7 @@ public:
this->filter.include_no_rating = !this->filter.include_no_rating; this->filter.include_no_rating = !this->filter.include_no_rating;
} else { } else {
this->filter.include_no_rating = true; this->filter.include_no_rating = true;
this->filter.cargoes = 0; this->filter.cargoes.Reset();
} }
} else if (index == CargoFilterCriteria::CF_SELECT_ALL) { } else if (index == CargoFilterCriteria::CF_SELECT_ALL) {
this->filter.cargoes = _cargo_mask; this->filter.cargoes = _cargo_mask;
@ -1047,13 +1047,11 @@ private:
void IncrementSize(); void IncrementSize();
CargoDataEntry *parent; ///< the parent of this entry. CargoDataEntry *parent; ///< the parent of this entry.
const union {
StationID station; ///< ID of the station this entry is associated with. const StationID station = StationID::Invalid(); ///< ID of the station this entry is associated with.
struct { const CargoType cargo = INVALID_CARGO; ///< ID of the cargo this entry is associated with.
CargoType cargo; ///< ID of the cargo this entry is associated with. bool transfers = false; ///< If there are transfers for this cargo.
bool transfers; ///< If there are transfers for this cargo.
};
};
uint num_children; ///< the number of subentries belonging to this entry. uint num_children; ///< the number of subentries belonging to this entry.
uint count; ///< sum of counts of all children or amount of cargo for this entry. uint count; ///< sum of counts of all children or amount of cargo for this entry.
std::unique_ptr<CargoDataSet> children; ///< the children of this entry. std::unique_ptr<CargoDataSet> children; ///< the children of this entry.
@ -1673,7 +1671,7 @@ struct StationViewWindow : public Window {
*/ */
void BuildCargoList(CargoDataEntry *entry, const Station *st) void BuildCargoList(CargoDataEntry *entry, const Station *st)
{ {
for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
if (this->cached_destinations.Retrieve(cargo) == nullptr) { if (this->cached_destinations.Retrieve(cargo) == nullptr) {
this->RecalcDestinations(cargo); this->RecalcDestinations(cargo);
@ -2141,8 +2139,8 @@ struct StationViewWindow : public Window {
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
{ {
if (gui_scope) { if (gui_scope) {
if (data >= 0 && data < NUM_CARGO) { if (IsInsideMM(data, 0, NUM_CARGO)) {
this->cached_destinations.Remove((CargoType)data); this->cached_destinations.Remove(static_cast<CargoType>(data));
} else { } else {
this->ReInit(); this->ReInit();
} }

View File

@ -26,7 +26,7 @@ struct RoadStop;
struct StationSpec; struct StationSpec;
struct Waypoint; struct Waypoint;
using StationIDStack = SmallStack<StationID::BaseType, StationID::BaseType, StationID::Invalid().base(), 8, StationID::End().base()>; using StationIDStack = SmallStack<StationID, StationID::BaseType, StationID::Invalid().base(), 8, StationID::End().base()>;
/** Station types */ /** Station types */
enum class StationType : uint8_t { enum class StationType : uint8_t {

View File

@ -1342,10 +1342,10 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin
/* Tiny description of cargotypes. Layout: /* Tiny description of cargotypes. Layout:
* param 1: cargo type * param 1: cargo type
* param 2: cargo count */ * param 2: cargo count */
CargoType cargo = args.GetNextParameter<CargoType>(); CargoType cargo{args.GetNextParameter<CargoType::BaseType>()};
int64_t amount = args.GetNextParameter<int64_t>(); int64_t amount = args.GetNextParameter<int64_t>();
if (cargo >= CargoSpec::GetArraySize()) { if (cargo.base() >= CargoSpec::GetArraySize()) {
builder += "(invalid cargo type)"; builder += "(invalid cargo type)";
break; break;
} }
@ -1371,10 +1371,10 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin
/* Short description of cargotypes. Layout: /* Short description of cargotypes. Layout:
* param 1: cargo type * param 1: cargo type
* param 2: cargo count */ * param 2: cargo count */
CargoType cargo = args.GetNextParameter<CargoType>(); CargoType cargo{args.GetNextParameter<CargoType::BaseType>()};
int64_t amount = args.GetNextParameter<int64_t>(); int64_t amount = args.GetNextParameter<int64_t>();
if (cargo >= CargoSpec::GetArraySize()) { if (cargo.base() >= CargoSpec::GetArraySize()) {
builder += "(invalid cargo type)"; builder += "(invalid cargo type)";
break; break;
} }
@ -1408,9 +1408,9 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin
case SCC_CARGO_LONG: { // {CARGO_LONG} case SCC_CARGO_LONG: { // {CARGO_LONG}
/* First parameter is cargo type, second parameter is cargo count */ /* First parameter is cargo type, second parameter is cargo count */
CargoType cargo = args.GetNextParameter<CargoType>(); CargoType cargo{args.GetNextParameter<CargoType::BaseType>()};
int64_t amount = args.GetNextParameter<int64_t>(); int64_t amount = args.GetNextParameter<int64_t>();
if (cargo < CargoSpec::GetArraySize()) { if (cargo.base() < CargoSpec::GetArraySize()) {
auto tmp_args = MakeParameters(amount); auto tmp_args = MakeParameters(amount);
GetStringWithArgs(builder, CargoSpec::Get(cargo)->quantifier, tmp_args); GetStringWithArgs(builder, CargoSpec::Get(cargo)->quantifier, tmp_args);
} else if (!IsValidCargoType(cargo)) { } else if (!IsValidCargoType(cargo)) {
@ -1427,7 +1427,7 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin
std::string_view list_separator = GetListSeparator(); std::string_view list_separator = GetListSeparator();
for (const auto &cs : _sorted_cargo_specs) { for (const auto &cs : _sorted_cargo_specs) {
if (!HasBit(cmask, cs->Index())) continue; if (!cmask.Test(cs->Index())) continue;
if (first) { if (first) {
first = false; first = false;

View File

@ -296,8 +296,8 @@ bool FindSubsidyTownCargoRoute()
/* Choose a random cargo that is produced in the town. */ /* Choose a random cargo that is produced in the town. */
uint8_t cargo_number = RandomRange(cargo_count); uint8_t cargo_number = RandomRange(cargo_count);
CargoType cargo_type; CargoType cargo_type{};
for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) { for (; cargo_type < NUM_CARGO; ++cargo_type) {
if (town_cargo_produced[cargo_type] > 0) { if (town_cargo_produced[cargo_type] > 0) {
if (cargo_number == 0) break; if (cargo_number == 0) break;
cargo_number--; cargo_number--;

Some files were not shown because too many files have changed in this diff Show More