From 98430f99d1a5c62931e0421b0132960fca6f1fd7 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 26 Mar 2025 18:48:52 +0000 Subject: [PATCH 1/3] Codechange: Add parameterless Flip() method to BaseBitSet. This allows flipping all valid bits. --- src/core/base_bitset_type.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/core/base_bitset_type.hpp b/src/core/base_bitset_type.hpp index 9ce8528d31..d8254bcd21 100644 --- a/src/core/base_bitset_type.hpp +++ b/src/core/base_bitset_type.hpp @@ -108,6 +108,16 @@ public: return static_cast(*this); } + /** + * Flip all bits. + * @returns The bit set + */ + inline constexpr Timpl &Flip() + { + this->data ^= Tmask; + return static_cast(*this); + } + /** * Flip the value-th bit. * @param value Bit to flip. From 329a2da122b507c21606b477098681b8fefc7eb6 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 16 Mar 2025 13:12:09 +0000 Subject: [PATCH 2/3] Codechange: Add StrongBitSet helper to simplify making a bitset from a StrongType. --- src/core/CMakeLists.txt | 1 + src/core/strong_bitset_type.hpp | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/core/strong_bitset_type.hpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 224cfba0eb..07e23f5c45 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -29,6 +29,7 @@ add_files( string_consumer.hpp string_inplace.cpp string_inplace.hpp + strong_bitset_type.hpp strong_typedef_type.hpp utf8.cpp utf8.hpp diff --git a/src/core/strong_bitset_type.hpp b/src/core/strong_bitset_type.hpp new file mode 100644 index 0000000000..0cf3f5a474 --- /dev/null +++ b/src/core/strong_bitset_type.hpp @@ -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 . + */ + +/** @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 ::max()> +class StrongBitSet : public BaseBitSet, 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 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, Tvalue_type, Tstorage, Tmask>; +}; + +#endif /* STRONG_BITSET_TYPE_HPP */ From b9eac1ee7894a44f7cec21a8dfeaf10184c3da8b Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 26 Mar 2025 18:48:53 +0000 Subject: [PATCH 3/3] Codechange: Use StrongType and StrongBitSet for CargoType(s). --- src/articulated_vehicles.cpp | 32 +++++++------- src/autoreplace_cmd.cpp | 16 +++---- src/build_vehicle_gui.cpp | 26 +++++------ src/cargo_type.h | 35 +++++++-------- src/cargomonitor.h | 6 +-- src/cargotype.cpp | 14 +++--- src/cargotype.h | 18 ++++---- src/economy.cpp | 30 ++++++------- src/engine.cpp | 8 ++-- src/graph_gui.cpp | 36 ++++++++-------- src/group_gui.cpp | 4 +- src/industry.h | 4 +- src/industry_cmd.cpp | 4 +- src/industry_gui.cpp | 48 ++++++++++----------- src/linkgraph/linkgraph_gui.cpp | 10 ++--- src/linkgraph/refresh.cpp | 6 +-- src/main_gui.cpp | 4 +- src/newgrf.cpp | 45 +++++++++---------- src/newgrf.h | 2 +- src/newgrf/newgrf_act0_aircraft.cpp | 4 +- src/newgrf/newgrf_act0_cargo.cpp | 6 +-- src/newgrf/newgrf_act0_houses.cpp | 2 +- src/newgrf/newgrf_act0_roadvehs.cpp | 4 +- src/newgrf/newgrf_act0_ships.cpp | 4 +- src/newgrf/newgrf_act0_trains.cpp | 4 +- src/newgrf/newgrf_act3.cpp | 2 +- src/newgrf_animation_base.h | 4 +- src/newgrf_commons.h | 7 +-- src/newgrf_debug_gui.cpp | 2 +- src/newgrf_engine.cpp | 8 ++-- src/newgrf_generic.cpp | 4 +- src/newgrf_house.cpp | 6 +-- src/newgrf_house.h | 4 +- src/newgrf_industries.cpp | 4 +- src/newgrf_roadstop.cpp | 21 ++++----- src/newgrf_roadstop.h | 2 +- src/newgrf_station.cpp | 31 ++++++------- src/newgrf_station.h | 2 +- src/newgrf_text.cpp | 2 +- src/object_cmd.cpp | 4 +- src/roadveh_gui.cpp | 2 +- src/saveload/company_sl.cpp | 2 +- src/saveload/station_sl.cpp | 2 +- src/script/api/script_cargo.cpp | 2 +- src/script/api/script_cargo.hpp | 6 +-- src/script/api/script_cargolist.cpp | 10 ++--- src/script/api/script_engine.cpp | 2 +- src/script/api/script_industrytype.cpp | 4 +- src/smallmap_gui.cpp | 8 ++-- src/station.cpp | 2 +- src/station_base.h | 2 +- src/station_cmd.cpp | 32 +++++++------- src/station_gui.cpp | 60 +++++++++++++------------- src/strings.cpp | 14 +++--- src/subsidy.cpp | 4 +- src/table/engines.h | 12 +++--- src/table/newgrf_debug_data.h | 4 +- src/table/town_land.h | 2 +- src/tile_cmd.h | 2 +- src/town.h | 2 +- src/town_cmd.cpp | 2 +- src/town_gui.cpp | 10 ++--- src/vehicle.cpp | 6 +-- src/vehicle_cmd.cpp | 2 +- src/vehicle_gui.cpp | 51 +++++++++++----------- src/vehicle_gui_base.h | 2 +- src/viewport.cpp | 4 +- 67 files changed, 358 insertions(+), 368 deletions(-) diff --git a/src/articulated_vehicles.cpp b/src/articulated_vehicles.cpp index ffb2fc052b..15ca606bb3 100644 --- a/src/articulated_vehicles.cpp +++ b/src/articulated_vehicles.cpp @@ -117,12 +117,12 @@ static inline std::pair GetVehicleDefaultCapacity(EngineID static inline CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type) { const Engine *e = Engine::Get(engine); - if (!e->CanCarryCargo()) return 0; + if (!e->CanCarryCargo()) return {}; CargoTypes cargoes = e->info.refit_mask; if (include_initial_cargo_type) { - SetBit(cargoes, e->GetDefaultCargoType()); + cargoes.Set(e->GetDefaultCargoType()); } return cargoes; @@ -165,11 +165,11 @@ CargoArray GetCapacityOfArticulatedParts(EngineID engine) */ CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine) { - CargoTypes cargoes = 0; + CargoTypes cargoes{}; const Engine *e = Engine::Get(engine); if (auto [cargo, cap] = GetVehicleDefaultCapacity(engine); IsValidCargoType(cargo) && cap > 0) { - SetBit(cargoes, cargo); + cargoes.Set(cargo); } if (!e->IsGroundVehicle()) return cargoes; @@ -181,7 +181,7 @@ CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine) if (artic_engine == EngineID::Invalid()) break; 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); CargoTypes veh_cargoes = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type); *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->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; veh_cargoes = GetAvailableVehicleCargoTypes(artic_engine, include_initial_cargo_type); - *union_mask |= veh_cargoes; - if (veh_cargoes != 0) *intersection_mask &= veh_cargoes; + union_mask->Set(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 cargoes = 0; + CargoTypes cargoes{}; CargoType first_cargo = INVALID_CARGO; do { 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 (first_cargo != v->cargo_type) { if (cargo_type != nullptr) { @@ -299,24 +299,24 @@ void CheckConsistencyOfArticulatedVehicle(const Vehicle *v) GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection); 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_default_cargoes = 0; + CargoTypes real_default_cargoes{}; do { CargoTypes refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true); - real_refit_union |= refit_mask; - if (refit_mask != 0) real_refit_intersection &= refit_mask; + real_refit_union.Set(refit_mask); + if (refit_mask.Any()) real_refit_intersection = real_refit_intersection & refit_mask; 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; } while (v != nullptr); /* Check whether the vehicle carries more cargoes than expected */ 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) { carries_more = true; break; diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index df64561cf3..eff1572b1f 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -47,7 +47,7 @@ static bool EnginesHaveCargoInCommon(EngineID engine_a, EngineID engine_b) { CargoTypes available_cargoes_a = GetUnionOfArticulatedRefitMasks(engine_a, 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; CargoType cargo_type = o.GetRefitCargo(); - if (!HasBit(union_refit_mask_a, cargo_type)) continue; - if (!HasBit(union_refit_mask_b, cargo_type)) return false; + if (!union_refit_mask_a.Test(cargo_type)) continue; + if (!union_refit_mask_b.Test(cargo_type)) return false; } return true; @@ -213,7 +213,7 @@ static int GetIncompatibleRefitOrderIdForAutoreplace(const Vehicle *v, EngineID for (VehicleOrderID i = 0; i < orders->GetNumOrders(); i++) { const Order *o = orders->GetOrderAt(i); if (!o->IsRefit()) continue; - if (!HasBit(union_refit_mask, o->GetRefitCargo())) return i; + if (!union_refit_mask.Test(o->GetRefitCargo())) return i; } return -1; @@ -233,11 +233,11 @@ static CargoType GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, boo CargoTypes available_cargo_types, union_mask; 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; CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type); - if (!HasAtMostOneBit(cargo_mask)) { + if (!HasAtMostOneBit(cargo_mask.base())) { CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(engine_type); 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 @@ -257,12 +257,12 @@ static CargoType GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, boo for (v = v->First(); v != nullptr; v = v->Next()) { 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 */ - 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 } 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 diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index d77ea2126c..d37a527616 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -546,7 +546,7 @@ static bool CargoAndEngineFilter(const GUIEngineListItem *item, const CargoType return Engine::Get(item->engine_id)->GetPower() != 0; } else { 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) { uint weight = 0; - for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { + for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) { if (cap[cargo] != 0) { if (vtype == VEH_TRAIN) { weight += CargoSpec::Get(cargo)->WeightOfNUnitsInTrain(cap[cargo]); @@ -1261,10 +1261,10 @@ struct BuildVehicleWindow : Window { StringID GetCargoFilterLabel(CargoType cargo_type) const { - switch (cargo_type) { - case CargoFilterCriteria::CF_ANY: return STR_PURCHASE_INFO_ALL_TYPES; - case CargoFilterCriteria::CF_ENGINES: return STR_PURCHASE_INFO_ENGINES_ONLY; - case CargoFilterCriteria::CF_NONE: return STR_PURCHASE_INFO_NONE; + switch (cargo_type.base()) { + case CargoFilterCriteria::CF_ANY.base(): return STR_PURCHASE_INFO_ALL_TYPES; + case CargoFilterCriteria::CF_ENGINES.base(): return STR_PURCHASE_INFO_ENGINES_ONLY; + case CargoFilterCriteria::CF_NONE.base(): return STR_PURCHASE_INFO_NONE; default: return CargoSpec::Get(cargo_type)->name; } } @@ -1274,7 +1274,7 @@ struct BuildVehicleWindow : Window { { /* Set the last cargo filter criteria. */ 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.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY); @@ -1570,20 +1570,20 @@ struct BuildVehicleWindow : Window { DropDownList list; /* 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. */ if (this->vehicle_type == VEH_TRAIN) { /* 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. * 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 */ Dimension d = GetLargestCargoIconSize(); 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; @@ -1675,7 +1675,7 @@ struct BuildVehicleWindow : Window { break; 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; case WID_BV_CONFIGURE_BADGES: @@ -1884,7 +1884,7 @@ struct BuildVehicleWindow : Window { case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria if (this->cargo_filter_criteria != index) { - this->cargo_filter_criteria = index; + this->cargo_filter_criteria = static_cast(index); _engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter_criteria; /* deactivate filter if criteria is 'Show All', activate it otherwise */ this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY); diff --git a/src/cargo_type.h b/src/cargo_type.h index 7bc0552f98..c2be2b3a8b 100644 --- a/src/cargo_type.h +++ b/src/cargo_type.h @@ -12,15 +12,19 @@ #include "core/enum_type.hpp" #include "core/strong_typedef_type.hpp" +#include "core/strong_bitset_type.hpp" #include "core/convertible_through_base.hpp" /** Globally unique label of a cargo type. */ using CargoLabel = StrongType::Typedef; +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. */ -using CargoType = uint8_t; +using CargoType = StrongType::Typedef; /** * 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 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. */ -static const 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_AUTO_REFIT{0xFD}; ///< Automatically choose cargo type when doing auto refitting. +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. */ 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. */ namespace CargoFilterCriteria { - 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_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_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_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_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_EXPAND_LIST = NUM_CARGO + 6; ///< Expand list to show all items (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_EXPAND_LIST{NUM_CARGO + 6}; ///< Expand list to show all items (station list) }; /** Test whether cargo type is not INVALID_CARGO */ inline bool IsValidCargoType(CargoType cargo) { return cargo != INVALID_CARGO; } -typedef uint64_t CargoTypes; +using CargoTypes = StrongBitSet; -static const CargoTypes ALL_CARGOTYPES = (CargoTypes)UINT64_MAX; +static constexpr CargoTypes ALL_CARGOTYPES{UINT64_MAX}; /** Class for storing amounts of cargo */ -struct CargoArray : std::array { +struct CargoArray : TypedIndexContainer, CargoType> { /** * Get the sum of all cargo amounts. * @return The sum. diff --git a/src/cargomonitor.h b/src/cargomonitor.h index 8d015f024e..1ade8fd93f 100644 --- a/src/cargomonitor.h +++ b/src/cargomonitor.h @@ -63,7 +63,7 @@ inline CargoMonitorID EncodeCargoIndustryMonitor(CompanyID company, CargoType ct uint32_t ret = 0; SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, ind.base()); 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()); return ret; } @@ -82,7 +82,7 @@ inline CargoMonitorID EncodeCargoTownMonitor(CompanyID company, CargoType ctype, uint32_t ret = 0; 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()); return ret; } @@ -104,7 +104,7 @@ inline CompanyID DecodeMonitorCompany(CargoMonitorID num) */ inline CargoType DecodeMonitorCargoType(CargoMonitorID num) { - return GB(num, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH); + return static_cast(GB(num, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH)); } /** diff --git a/src/cargotype.cpp b/src/cargotype.cpp index f65e6f9186..d1de5f548a 100644 --- a/src/cargotype.cpp +++ b/src/cargotype.cpp @@ -21,7 +21,7 @@ #include "safeguards.h" -CargoSpec CargoSpec::array[NUM_CARGO]; +TypedIndexContainer, CargoType> CargoSpec::array{}; std::array, NUM_TPE> CargoSpec::town_production_cargoes{}; /** @@ -63,7 +63,7 @@ void SetupCargoForClimate(LandscapeType l) { assert(to_underlying(l) < std::size(_default_climate_cargo)); - _cargo_mask = 0; + _cargo_mask.Reset(); _default_cargo_labels.clear(); _climate_dependent_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); if (insert->IsValid()) { - SetBit(_cargo_mask, insert->Index()); + _cargo_mask.Set(insert->Index()); _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; } ++insert; @@ -186,7 +186,7 @@ SpriteID CargoSpec::GetCargoIcon() const return sprite; } -std::array _sorted_cargo_types; ///< Sort order of cargoes by cargo type. +TypedIndexContainer, CargoType> _sorted_cargo_types; ///< Sort order of cargoes by cargo type. std::vector _sorted_cargo_specs; ///< Cargo specifications sorted alphabetically by name. std::span _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. */ - _standard_cargo_mask = 0; + _standard_cargo_mask.Reset(); uint8_t nb_standard_cargo = 0; for (const auto &cargo : _sorted_cargo_specs) { assert(cargo->town_production_effect != INVALID_TPE); CargoSpec::town_production_cargoes[cargo->town_production_effect].push_back(cargo); if (cargo->classes.Test(CargoClass::Special)) break; 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. */ diff --git a/src/cargotype.h b/src/cargotype.h index 3ca15bfcae..ec192a2a88 100644 --- a/src/cargotype.h +++ b/src/cargotype.h @@ -107,7 +107,7 @@ struct CargoSpec { */ inline CargoType Index() const { - return this - CargoSpec::array; + return static_cast(this - CargoSpec::array.data()); } /** @@ -126,7 +126,7 @@ struct CargoSpec { */ 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 * @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]; } @@ -165,12 +165,12 @@ struct CargoSpec { }; 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(this->index)}); } Iterator & operator++() { this->index++; this->ValidateIndex(); return *this; } private: 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, NUM_TPE> town_production_cargoes; private: - static CargoSpec array[NUM_CARGO]; ///< Array holding all CargoSpecs + static TypedIndexContainer, CargoType> array; ///< Array holding all CargoSpecs static inline std::map label_map{}; ///< Translation map from CargoLabel to Cargo type. friend void SetupCargoForClimate(LandscapeType l); @@ -223,7 +223,7 @@ inline CargoType GetCargoTypeByLabel(CargoLabel label) Dimension GetLargestCargoIconSize(); void InitializeSortedCargoSpecs(); -extern std::array _sorted_cargo_types; +extern TypedIndexContainer, CargoType> _sorted_cargo_types; extern std::vector _sorted_cargo_specs; extern std::span _sorted_standard_cargo_specs; @@ -238,8 +238,6 @@ inline bool IsCargoInClass(CargoType cargo, CargoClasses cc) return CargoSpec::Get(cargo)->classes.Any(cc); } -using SetCargoBitIterator = SetBitIterator; - /** Comparator to sort CargoType by according to desired order. */ struct CargoTypeComparator { bool operator() (const CargoType &lhs, const CargoType &rhs) const { return _sorted_cargo_types[lhs] < _sorted_cargo_types[rhs]; } diff --git a/src/economy.cpp b/src/economy.cpp index 03ed9a9053..a09075eebe 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1103,7 +1103,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); /* 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 */ if (accepted_total > 0) { @@ -1400,7 +1400,7 @@ struct PrepareRefitAction bool operator()(const Vehicle *v) { 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; } }; @@ -1493,7 +1493,7 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station if (is_auto_refit) { /* Get a refittable cargo type with waiting cargo for next_station or StationID::Invalid(). */ 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)) { /* Try to find out if auto-refitting would succeed. In case the refit is allowed, * the returned refit capacity will be greater than zero. */ @@ -1652,10 +1652,10 @@ static void LoadUnloadVehicle(Vehicle *front) bool completely_emptied = true; bool anything_unloaded = false; bool anything_loaded = false; - CargoTypes full_load_amount = 0; - CargoTypes cargo_not_full = 0; - CargoTypes cargo_full = 0; - CargoTypes reservation_left = 0; + CargoTypes full_load_amount{}; + CargoTypes cargo_not_full{}; + CargoTypes cargo_full{}; + CargoTypes reservation_left{}; front->cur_speed = 0; @@ -1786,14 +1786,14 @@ static void LoadUnloadVehicle(Vehicle *front) if (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) { /* Remember if there are reservations left so that we don't stop * 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.*/ if (loaded == cap_left) { - SetBit(full_load_amount, v->cargo_type); + full_load_amount.Set(v->cargo_type); } else { - ClrBit(full_load_amount, v->cargo_type); + full_load_amount.Reset(v->cargo_type); } /* TODO: Regarding this, when we do gradual loading, we @@ -1826,9 +1826,9 @@ static void LoadUnloadVehicle(Vehicle *front) } if (v->cargo.StoredCount() >= v->cargo_cap) { - SetBit(cargo_full, v->cargo_type); + cargo_full.Set(v->cargo_type); } else { - SetBit(cargo_not_full, v->cargo_type); + cargo_not_full.Set(v->cargo_type); } } @@ -1858,7 +1858,7 @@ static void LoadUnloadVehicle(Vehicle *front) } /* 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. */ - 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->vehicle_flags.Set(VehicleFlag::StopLoading); } @@ -1872,10 +1872,10 @@ static void LoadUnloadVehicle(Vehicle *front) /* if the aircraft carries passengers and is NOT full, then * 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()) || - (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; } - } else if (cargo_not_full != 0) { + } else if (cargo_not_full.Any()) { finished_loading = false; } diff --git a/src/engine.cpp b/src/engine.cpp index a63b5a1954..60d0766af2 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -927,7 +927,7 @@ static CompanyID GetPreviewCompany(Engine *e) /* Check whether the company uses similar vehicles */ for (const Vehicle *v : Vehicle::Iterate()) { 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_company = c->index; @@ -1294,7 +1294,7 @@ bool IsEngineRefittable(EngineID engine) if (!e->CanCarryCargo()) return false; const EngineInfo *ei = &e->info; - if (ei->refit_mask == 0) return false; + if (ei->refit_mask.None()) return false; /* Are there suffixes? * 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? */ CargoType default_cargo = e->GetDefaultCargoType(); - CargoTypes default_cargo_mask = 0; - SetBit(default_cargo_mask, default_cargo); - return IsValidCargoType(default_cargo) && ei->refit_mask != default_cargo_mask; + return IsValidCargoType(default_cargo) && ei->refit_mask != default_cargo; } /** diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 70b1ce92bd..dca94386cb 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -1106,7 +1106,7 @@ struct BaseCargoGraphWindow : BaseGraphWindow { this->cargo_types = this->GetCargoTypes(number); 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(WID_GRAPH_FOOTER); wid->SetString(TimerGameEconomy::UsingWallclockUnits() ? footer_wallclock : footer_calendar); @@ -1126,10 +1126,10 @@ struct BaseCargoGraphWindow : BaseGraphWindow { if (row >= this->vscroll->GetCount()) return std::nullopt; 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; - return cs->Index(); + return cs->Index().base(); } return std::nullopt; @@ -1150,7 +1150,7 @@ struct BaseCargoGraphWindow : BaseGraphWindow { 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); Dimension d = GetStringBoundingBox(GetString(STR_GRAPH_CARGO_PAYMENT_CARGO, cs->name)); @@ -1181,12 +1181,12 @@ struct BaseCargoGraphWindow : BaseGraphWindow { Rect line = r.WithHeight(this->line_height); 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 (--max < 0) break; - bool lowered = !HasBit(this->excluded_data, cs->Index()); + bool lowered = !HasBit(this->excluded_data, cs->Index().base()); /* Redraw frame if lowered */ if (lowered) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered); @@ -1213,14 +1213,14 @@ struct BaseCargoGraphWindow : BaseGraphWindow { case WID_GRAPH_ENABLE_CARGOES: /* Remove all cargoes from the excluded lists. */ this->GetExcludedCargoTypes() = {}; - this->excluded_data = this->GetExcludedCargoTypes(); + this->excluded_data = this->GetExcludedCargoTypes().base(); this->SetDirty(); break; case WID_GRAPH_DISABLE_CARGOES: { /* Add all cargoes to the excluded lists. */ this->GetExcludedCargoTypes() = this->cargo_types; - this->excluded_data = this->GetExcludedCargoTypes(); + this->excluded_data = this->GetExcludedCargoTypes().base(); this->SetDirty(); break; } @@ -1230,11 +1230,11 @@ struct BaseCargoGraphWindow : BaseGraphWindow { if (row >= this->vscroll->GetCount()) return; 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; - ToggleBit(this->GetExcludedCargoTypes(), cs->Index()); - this->excluded_data = this->GetExcludedCargoTypes(); + this->GetExcludedCargoTypes().Flip(cs->Index()); + this->excluded_data = this->GetExcludedCargoTypes().base(); this->SetDirty(); break; } @@ -1306,13 +1306,13 @@ struct PaymentRatesGraphWindow : BaseCargoGraphWindow { */ void UpdatePaymentRates() { - this->excluded_data = this->GetExcludedCargoTypes(); + this->excluded_data = this->GetExcludedCargoTypes().base(); this->data.clear(); for (const CargoSpec *cs : _sorted_standard_cargo_specs) { DataSet &dataset = this->data.emplace_back(); 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++) { dataset.values[j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, cs->Index()); @@ -1619,7 +1619,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow { CargoTypes cargo_types{}; const Industry *i = Industry::Get(window_number); 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; } @@ -1645,12 +1645,12 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow { 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 */ return; } - this->excluded_data = this->GetExcludedCargoTypes(); + this->excluded_data = this->GetExcludedCargoTypes().base(); this->year = yr; this->month = mo; @@ -1663,7 +1663,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow { DataSet &produced = this->data.emplace_back(); produced.colour = cs->legend_colour; - produced.exclude_bit = cs->Index(); + produced.exclude_bit = cs->Index().base(); produced.range_bit = 0; for (uint j = 0; j < GRAPH_NUM_MONTHS; j++) { @@ -1672,7 +1672,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow { DataSet &transported = this->data.emplace_back(); transported.colour = cs->legend_colour; - transported.exclude_bit = cs->Index(); + transported.exclude_bit = cs->Index().base(); transported.range_bit = 1; transported.dash = 2; diff --git a/src/group_gui.cpp b/src/group_gui.cpp index e94844f02f..9ce8ff515a 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -708,7 +708,7 @@ public: return; 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; case WID_GL_ALL_VEHICLES: // All vehicles button @@ -999,7 +999,7 @@ public: break; case WID_GL_FILTER_BY_CARGO: // Select a cargo filter criteria - this->SetCargoFilter(index); + this->SetCargoFilter(static_cast(index)); break; case WID_GL_MANAGE_VEHICLES_DROPDOWN: diff --git a/src/industry.h b/src/industry.h index 50e669ce4d..0a84edd62d 100644 --- a/src/industry.h +++ b/src/industry.h @@ -74,14 +74,14 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> { }; struct ProducedCargo { - CargoType cargo = 0; ///< Cargo type + CargoType cargo = INVALID_CARGO; ///< Cargo type uint16_t waiting = 0; ///< Amount of cargo produced uint8_t rate = 0; ///< Production rate std::array history{}; ///< History of cargo produced and transported for this month and 24 previous months }; struct AcceptedCargo { - CargoType cargo = 0; ///< Cargo type + CargoType cargo = INVALID_CARGO; ///< Cargo type uint16_t waiting = 0; ///< Amount of cargo waiting to processed TimerGameEconomy::Date last_accepted{}; ///< Last day cargo was accepted by this industry }; diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 617bb91847..8c20f6b0b5 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -462,13 +462,13 @@ static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, Ca acceptance[cargo] += cargo_acceptance[i]; /* 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 */ if (ind->IsCargoAccepted(cargo)) continue; /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */ - SetBit(always_accepted, cargo); + always_accepted.Set(cargo); } } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 6119c486dd..b5a60d1854 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -1308,12 +1308,12 @@ static bool CargoFilter(const Industry * const *industry, const std::pairIsCargoAccepted(); break; @@ -1324,12 +1324,12 @@ static bool CargoFilter(const Industry * const *industry, const std::pairIsCargoProduced(); break; @@ -1415,9 +1415,9 @@ protected: StringID GetCargoFilterLabel(CargoType cargo_type) const { - switch (cargo_type) { - case CargoFilterCriteria::CF_ANY: return STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES; - case CargoFilterCriteria::CF_NONE: return STR_INDUSTRY_DIRECTORY_FILTER_NONE; + switch (cargo_type.base()) { + case CargoFilterCriteria::CF_ANY.base(): return STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES; + case CargoFilterCriteria::CF_NONE.base(): return STR_INDUSTRY_DIRECTORY_FILTER_NONE; default: return CargoSpec::Get(cargo_type)->name; } } @@ -1795,14 +1795,14 @@ public: DropDownList list; /* 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 */ - 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 */ Dimension d = GetLargestCargoIconSize(); 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; @@ -1821,11 +1821,11 @@ public: break; 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; 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; case WID_ID_INDUSTRY_LIST: { @@ -1854,13 +1854,13 @@ public: } case WID_ID_FILTER_BY_ACC_CARGO: { - this->SetAcceptedCargoFilter(index); + this->SetAcceptedCargoFilter(static_cast(index)); this->BuildSortIndustriesList(); break; } case WID_ID_FILTER_BY_PROD_CARGO: { - this->SetProducedCargoFilter(index); + this->SetProducedCargoFilter(static_cast(index)); this->BuildSortIndustriesList(); break; } @@ -2667,7 +2667,7 @@ struct IndustryCargoesWindow : public Window { const IndustrySpec *indsp = GetIndustrySpec(this->ind_cargo); return GetString(STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION, indsp->name); } else { - const CargoSpec *csp = CargoSpec::Get(this->ind_cargo - NUM_INDUSTRYTYPES); + const CargoSpec *csp = CargoSpec::Get(static_cast(this->ind_cargo - NUM_INDUSTRYTYPES)); return GetString(STR_INDUSTRY_CARGOES_CARGO_CAPTION, csp->name); } } @@ -2680,9 +2680,9 @@ struct IndustryCargoesWindow : public Window { */ static bool HasCommonValidCargo(const std::span cargoes1, const std::span cargoes2) { - for (const CargoType cargo_type1 : cargoes1) { + for (const CargoType &cargo_type1 : cargoes1) { if (!IsValidCargoType(cargo_type1)) continue; - for (const CargoType cargo_type2 : cargoes2) { + for (const CargoType &cargo_type2 : cargoes2) { if (cargo_type1 == cargo_type2) return true; } } @@ -2696,7 +2696,7 @@ struct IndustryCargoesWindow : public Window { */ static bool HousesCanSupply(const std::span cargoes) { - for (const CargoType cargo_type : cargoes) { + for (const CargoType &cargo_type : cargoes) { if (!IsValidCargoType(cargo_type)) continue; TownProductionEffect tpe = CargoSpec::Get(cargo_type)->town_production_effect; if (tpe == TPE_PASSENGERS || tpe == TPE_MAIL) return true; @@ -2713,7 +2713,7 @@ struct IndustryCargoesWindow : public Window { { HouseZones climate_mask = GetClimateMaskForLandscape(); - for (const CargoType cargo_type : cargoes) { + for (const CargoType &cargo_type : cargoes) { if (!IsValidCargoType(cargo_type)) continue; for (const auto &hs : HouseSpec::Specs()) { @@ -2894,7 +2894,7 @@ struct IndustryCargoesWindow : public Window { */ void ComputeCargoDisplay(CargoType cargo_type) { - this->ind_cargo = cargo_type + NUM_INDUSTRYTYPES; + this->ind_cargo = cargo_type.base() + NUM_INDUSTRYTYPES; _displayed_industries.reset(); this->fields.clear(); @@ -3107,7 +3107,7 @@ struct IndustryCargoesWindow : public Window { DropDownList lst; Dimension d = GetLargestCargoIconSize(); 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()) { int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? (int)(this->ind_cargo - NUM_INDUSTRYTYPES) : -1; @@ -3138,7 +3138,7 @@ struct IndustryCargoesWindow : public Window { switch (widget) { case WID_IC_CARGO_DROPDOWN: - this->ComputeCargoDisplay(index); + this->ComputeCargoDisplay(static_cast(index)); break; case WID_IC_IND_DROPDOWN: diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index 57ab1dfaf0..6e6a50cb91 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -86,7 +86,7 @@ void LinkGraphOverlay::RebuildCache() StationLinkMap &seen_links = this->cached_links[from]; uint supply = 0; - for (CargoType cargo : SetCargoBitIterator(this->cargo_mask)) { + for (CargoType cargo : this->cargo_mask) { if (!CargoSpec::Get(cargo)->IsValid()) continue; if (!LinkGraph::IsValidID(sta->goods[cargo].link_graph)) continue; 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) { - for (CargoType cargo : SetCargoBitIterator(this->cargo_mask)) { + for (CargoType cargo : this->cargo_mask) { if (!CargoSpec::Get(cargo)->IsValid()) continue; const GoodsEntry &ge = from->goods[cargo]; if (!LinkGraph::IsValidID(ge.link_graph) || @@ -566,7 +566,7 @@ void LinkGraphLegendWindow::SetOverlay(std::shared_ptr overlay } CargoTypes cargoes = this->overlay->GetCargoMask(); 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())); } } @@ -669,10 +669,10 @@ void LinkGraphLegendWindow::UpdateOverlayCompanies() */ void LinkGraphLegendWindow::UpdateOverlayCargoes() { - CargoTypes mask = 0; + CargoTypes mask{}; for (uint c = 0; c < num_cargo; c++) { 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); } diff --git a/src/linkgraph/refresh.cpp b/src/linkgraph/refresh.cpp index 25e5f47fb1..7076c37f7a 100644 --- a/src/linkgraph/refresh.cpp +++ b/src/linkgraph/refresh.cpp @@ -72,7 +72,7 @@ bool LinkRefresher::HandleRefit(CargoType refit_cargo) bool any_refit = false; for (Vehicle *v = this->vehicle; v != nullptr; v = v->Next()) { 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; continue; } @@ -188,7 +188,7 @@ void LinkRefresher::RefreshStats(VehicleOrderID cur, VehicleOrderID next) Station *st = Station::GetIfValid(orders[cur].GetDestination().ToStationID()); if (st != nullptr && next_station != StationID::Invalid() && next_station != st->index) { 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. */ uint cargo_quantity = this->capacities[cargo]; @@ -260,7 +260,7 @@ void LinkRefresher::RefreshLinks(VehicleOrderID cur, VehicleOrderID next, Refres } else if (!flags.Test(RefreshFlag::InAutorefit)) { flags.Set(RefreshFlag::InAutorefit); 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)) { this->RefreshLinks(cur, next, flags, num_hops); *this = backup; diff --git a/src/main_gui.cpp b/src/main_gui.cpp index f58f759867..92b43ebc45 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -221,14 +221,14 @@ struct MainWindow : Window NWidgetViewport *nvp = this->GetWidget(WID_M_VIEWPORT); nvp->InitializeViewport(this, TileXY(32, 32), ScaleZoomGUI(ZoomLevel::Viewport)); - this->viewport->overlay = std::make_shared(this, WID_M_VIEWPORT, 0, CompanyMask{}, 2); + this->viewport->overlay = std::make_shared(this, WID_M_VIEWPORT, CargoTypes{}, CompanyMask{}, 2); this->refresh_timeout.Reset(); } /** Refresh the link-graph overlay. */ void RefreshLinkGraph() { - if (this->viewport->overlay->GetCargoMask() == 0 || + if (this->viewport->overlay->GetCargoMask().None() || this->viewport->overlay->GetCompanyMask().None()) { return; } diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 6cb2919198..1904213b23 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -310,10 +310,10 @@ EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16_t internal */ CargoTypes TranslateRefitMask(uint32_t refit_mask) { - CargoTypes result = 0; + CargoTypes result{}; for (uint8_t bit : SetBitIterator(refit_mask)) { CargoType cargo = GetCargoTranslation(bit, _cur_gps.grffile, true); - if (IsValidCargoType(cargo)) SetBit(result, cargo); + if (IsValidCargoType(cargo)) result.Set(cargo); } return result; } @@ -641,9 +641,9 @@ static CargoLabel GetActiveCargoLabel(const std::variantcargo_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 */ { - CargoTypes mask = 0; - CargoTypes not_mask = 0; + CargoTypes mask{}; + CargoTypes not_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. @@ -754,16 +754,17 @@ static void CalculateRefitMasks() if (_gted[engine].cargo_allowed.Any()) { /* Build up the list of cargo types from the set cargo classes. */ 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_disallowed)) SetBit(not_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)) 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. */ - ei->refit_mask |= _gted[engine].ctt_include_mask; - ei->refit_mask &= ~_gted[engine].ctt_exclude_mask; + ei->refit_mask.Set(_gted[engine].ctt_include_mask); + ei->refit_mask.Reset(_gted[engine].ctt_exclude_mask); /* Custom refit mask callback. */ const GRFFile *file = _gted[e->index].defaultcargo_grf; @@ -776,8 +777,8 @@ static void CalculateRefitMasks() case CALLBACK_FAILED: case 0: break; // Do nothing. - case 1: SetBit(ei->refit_mask, cs->Index()); break; - case 2: ClrBit(ei->refit_mask, cs->Index()); break; + case 1: ei->refit_mask.Set(cs->Index()); break; + case 2: ei->refit_mask.Reset(cs->Index()); break; 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) */ - 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. * 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; } /* 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. */ - 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'. */ const GRFFile *file = _gted[engine].defaultcargo_grf; if (file == nullptr) file = e->GetGRF(); if (file != nullptr && file->grf_version >= 8 && !file->cargo_list.empty()) { /* Use first refittable cargo from cargo translation table */ 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]; if (local_slot < best_local_slot) { best_local_slot = local_slot; @@ -814,7 +815,7 @@ static void CalculateRefitMasks() if (!IsValidCargoType(ei->cargo_type)) { /* 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) { @@ -822,14 +823,14 @@ static void CalculateRefitMasks() * Fallback to the first available instead, if the cargo type has not been changed (as indicated by * cargo_label not being CT_INVALID). */ if (GetActiveCargoLabel(ei->cargo_label) != CT_INVALID) { - ei->cargo_type = static_cast(FindFirstBit(_standard_cargo_mask)); + ei->cargo_type = *_standard_cargo_mask.begin(); } } if (!IsValidCargoType(ei->cargo_type)) ei->climates = {}; /* Clear refit_mask for not refittable ships */ if (e->type == VEH_SHIP && !e->u.ship.old_refittable) { - ei->refit_mask = 0; + ei->refit_mask.Reset(); } } } diff --git a/src/newgrf.h b/src/newgrf.h index beb5a0ed4f..c7b5415521 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -134,7 +134,7 @@ struct GRFFile { std::vector labels{}; ///< List of labels std::vector cargo_list{}; ///< Cargo translation table (local ID -> label) - std::array cargo_map{}; ///< Inverse cargo translation table (CargoType -> local ID) + TypedIndexContainer, CargoType> cargo_map{}; ///< Inverse cargo translation table (CargoType -> local ID) std::vector badge_list{}; ///< Badge translation table (local index -> global index) std::unordered_map badge_map{}; diff --git a/src/newgrf/newgrf_act0_aircraft.cpp b/src/newgrf/newgrf_act0_aircraft.cpp index d246544784..553a8f5597 100644 --- a/src/newgrf/newgrf_act0_aircraft.cpp +++ b/src/newgrf/newgrf_act0_aircraft.cpp @@ -153,10 +153,10 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int pro _gted[e->index].UpdateRefittability(prop == 0x1D && count != 0); 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; - ctt = 0; + ctt.Reset(); while (count--) { CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); - if (IsValidCargoType(ctype)) SetBit(ctt, ctype); + if (IsValidCargoType(ctype)) ctt.Set(ctype); } break; } diff --git a/src/newgrf/newgrf_act0_cargo.cpp b/src/newgrf/newgrf_act0_cargo.cpp index c5794a2874..fd301c10c2 100644 --- a/src/newgrf/newgrf_act0_cargo.cpp +++ b/src/newgrf/newgrf_act0_cargo.cpp @@ -34,16 +34,16 @@ static ChangeInfoResult CargoReserveInfo(uint first, uint last, int prop, ByteRe } for (uint id = first; id < last; ++id) { - CargoSpec *cs = CargoSpec::Get(id); + CargoSpec *cs = CargoSpec::Get(static_cast(id)); switch (prop) { case 0x08: // Bit number of cargo cs->bitnum = buf.ReadByte(); if (cs->IsValid()) { cs->grffile = _cur_gps.grffile; - SetBit(_cargo_mask, id); + _cargo_mask.Set(cs->Index()); } else { - ClrBit(_cargo_mask, id); + _cargo_mask.Reset(cs->Index()); } BuildCargoLabelMap(); break; diff --git a/src/newgrf/newgrf_act0_houses.cpp b/src/newgrf/newgrf_act0_houses.cpp index c73ff6fd6e..4135038646 100644 --- a/src/newgrf/newgrf_act0_houses.cpp +++ b/src/newgrf/newgrf_act0_houses.cpp @@ -305,7 +305,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt uint8_t count = buf.ReadByte(); for (uint8_t j = 0; j < count; j++) { 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; } diff --git a/src/newgrf/newgrf_act0_roadvehs.cpp b/src/newgrf/newgrf_act0_roadvehs.cpp index e8cf67f6bb..4143946246 100644 --- a/src/newgrf/newgrf_act0_roadvehs.cpp +++ b/src/newgrf/newgrf_act0_roadvehs.cpp @@ -194,10 +194,10 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B _gted[e->index].UpdateRefittability(prop == 0x24 && count != 0); 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; - ctt = 0; + ctt.Reset(); while (count--) { CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); - if (IsValidCargoType(ctype)) SetBit(ctt, ctype); + if (IsValidCargoType(ctype)) ctt.Set(ctype); } break; } diff --git a/src/newgrf/newgrf_act0_ships.cpp b/src/newgrf/newgrf_act0_ships.cpp index 0e1bfe0b17..97106961e7 100644 --- a/src/newgrf/newgrf_act0_ships.cpp +++ b/src/newgrf/newgrf_act0_ships.cpp @@ -173,10 +173,10 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, B _gted[e->index].UpdateRefittability(prop == 0x1E && count != 0); 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; - ctt = 0; + ctt.Reset(); while (count--) { CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); - if (IsValidCargoType(ctype)) SetBit(ctt, ctype); + if (IsValidCargoType(ctype)) ctt.Set(ctype); } break; } diff --git a/src/newgrf/newgrf_act0_trains.cpp b/src/newgrf/newgrf_act0_trains.cpp index 445dbf294b..d1c5624550 100644 --- a/src/newgrf/newgrf_act0_trains.cpp +++ b/src/newgrf/newgrf_act0_trains.cpp @@ -292,10 +292,10 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead _gted[e->index].UpdateRefittability(prop == 0x2C && count != 0); 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; - ctt = 0; + ctt.Reset(); while (count--) { CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); - if (IsValidCargoType(ctype)) SetBit(ctt, ctype); + if (IsValidCargoType(ctype)) ctt.Set(ctype); } break; } diff --git a/src/newgrf/newgrf_act3.cpp b/src/newgrf/newgrf_act3.cpp index aa9b61ee42..abea261e79 100644 --- a/src/newgrf/newgrf_act3.cpp +++ b/src/newgrf/newgrf_act3.cpp @@ -379,7 +379,7 @@ static void CargoMapSpriteGroup(ByteReader &buf, uint8_t idcount) continue; } - CargoSpec *cs = CargoSpec::Get(cargo_type); + CargoSpec *cs = CargoSpec::Get(static_cast(cargo_type)); cs->grffile = _cur_gps.grffile; cs->group = _cur_gps.spritegroups[groupid]; } diff --git a/src/newgrf_animation_base.h b/src/newgrf_animation_base.h index c601179a70..c1dc3fde35 100644 --- a/src/newgrf_animation_base.h +++ b/src/newgrf_animation_base.h @@ -49,7 +49,7 @@ struct AnimationBase { * @param random_animation Whether to pass random bits to the "next frame" callback. * @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); @@ -128,7 +128,7 @@ struct AnimationBase { * @param trigger What triggered this update? To be passed as parameter to the NewGRF. * @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); if (callback == CALLBACK_FAILED) return; diff --git a/src/newgrf_commons.h b/src/newgrf_commons.h index 0719d9948d..0fcd876ef4 100644 --- a/src/newgrf_commons.h +++ b/src/newgrf_commons.h @@ -15,6 +15,7 @@ #include "sprite.h" #include "core/alloc_type.hpp" +#include "core/convertible_through_base.hpp" #include "command_type.h" #include "direction_type.h" #include "company_type.h" @@ -454,9 +455,9 @@ struct VariableGRFFileProps : GRFFilePropsBase { * Sprite groups indexed by CargoType. */ struct CargoGRFFileProps : VariableGRFFileProps { - 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_DEFAULT_NA = NUM_CARGO + 2; ///< Used only by stations and roads 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_DEFAULT_NA{NUM_CARGO + 2}; ///< Used only by stations and roads when no more-specific cargo matches. }; /** diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index f3780370bf..a31042ced4 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -426,7 +426,7 @@ struct NewGRFInspectWindow : Window { { switch (nip.type) { 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(value)) ? CargoSpec::Get(static_cast(value))->name : STR_QUANTITY_N_A); default: NOT_REACHED(); } } diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index e37ed01cf4..9341d4a6b3 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -435,7 +435,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec case 0x42: { // Consist cargo information if (!HasBit(v->grf_cache.cache_valid, NCVV_CONSIST_CARGO_INFORMATION)) { - std::array common_cargoes{}; + TypedIndexContainer, CargoType> common_cargoes{}; uint8_t cargo_classes = 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, * 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); } /* 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(GB(v->grf_cache.consist_cargo_information, 8, 8)); /* Note: * - 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 0x37: return v->acceleration; 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 0x3B: return GB(v->cargo_cap, 8, 8); case 0x3C: return ClampTo(v->cargo.StoredCount()); diff --git a/src/newgrf_generic.cpp b/src/newgrf_generic.cpp index d070119db1..1576845435 100644 --- a/src/newgrf_generic.cpp +++ b/src/newgrf_generic.cpp @@ -36,7 +36,7 @@ struct GenericScopeResolver : public ScopeResolver { * @param ai_callback Callback comes from the AI. */ 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) { } @@ -124,7 +124,7 @@ void AddGenericCallback(GrfSpecFeature feature, const GRFFile *file, const Sprit switch (variable) { 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 0x82: return this->default_selection; case 0x83: return this->src_industry; diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 565927aaa7..7ddde396a3 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -402,7 +402,7 @@ static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex start_ti } /* 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; } @@ -739,9 +739,9 @@ void TriggerHouseAnimation_WatchedCargoAccepted(TileIndex tile, CargoTypes trigg HouseID id = GetHouseType(tile); 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? */ - if (trigger_cargoes == 0) return; + if (trigger_cargoes.None()) return; /* Same random value for all tiles of a multi-tile house. */ uint16_t r = Random(); diff --git a/src/newgrf_house.h b/src/newgrf_house.h index 56fbdb1dd0..9735665b05 100644 --- a/src/newgrf_house.h +++ b/src/newgrf_house.h @@ -55,7 +55,7 @@ struct HouseResolverObject : public SpecializedResolverObject 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); diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index 4f532ff1b2..9bb4d721fd 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -371,7 +371,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(const ResolverObject &objec case 0x87: return this->industry->location.h;// xy dimensions 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 0x8B: return GB(this->industry->GetProduced(0).waiting, 8, 8); 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 0x90: 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; /* amount of cargo produced so far THIS month. */ case 0x94: return this->industry->GetProduced(0).history[THIS_MONTH].production; diff --git a/src/newgrf_roadstop.cpp b/src/newgrf_roadstop.cpp index 02db3fa33d..ccead6450b 100644 --- a/src/newgrf_roadstop.cpp +++ b/src/newgrf_roadstop.cpp @@ -232,7 +232,7 @@ RoadStopResolverObject::RoadStopResolverObject(const RoadStopSpec *roadstopspec, /* Pick the first cargo that we have waiting */ for (const auto &[cargo, spritegroup] : roadstopspec->grf_prop.spritegroups) { if (cargo < NUM_CARGO && station->goods[cargo].HasData() && station->goods[cargo].GetData().cargo.TotalCount() > 0) { - ctype = cargo; + ctype = static_cast(cargo); this->root_spritegroup = spritegroup; break; } @@ -422,18 +422,15 @@ void TriggerRoadStopRandomisation(BaseStation *st, TileIndex tile, StationRandom /* Check the cached cargo trigger bitmask to see if we need * to bother with any further processing. * Note: cached_roadstop_cargo_triggers must be non-zero even for cargo-independent triggers. */ - if (st->cached_roadstop_cargo_triggers == 0) return; - if (IsValidCargoType(cargo_type) && !HasBit(st->cached_roadstop_cargo_triggers, cargo_type)) return; + if (st->cached_roadstop_cargo_triggers.None()) return; + if (IsValidCargoType(cargo_type) && !st->cached_roadstop_cargo_triggers.Test(cargo_type)) return; st->waiting_random_triggers.Set(trigger); uint32_t whole_reseed = 0; /* Bitmask of completely empty cargo types to be matched. */ - CargoTypes empty_mask{}; - if (trigger == StationRandomTrigger::CargoTaken) { - empty_mask = GetEmptyMask(Station::From(st)); - } + CargoTypes not_empty_mask = (trigger == StationRandomTrigger::CargoTaken) ? GetEmptyMask(Station::From(st)).Flip() : ALL_CARGOTYPES; StationRandomTriggers used_random_triggers; 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 types have no more cargo waiting." */ 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)); object.SetWaitingRandomTriggers(st->waiting_random_triggers); @@ -621,7 +618,7 @@ void DeallocateSpecFromRoadStop(BaseStation *st, uint8_t specindex) } else { st->roadstop_speclist.clear(); st->cached_roadstop_anim_triggers = {}; - st->cached_roadstop_cargo_triggers = 0; + st->cached_roadstop_cargo_triggers.Reset(); return; } } @@ -636,13 +633,13 @@ void DeallocateSpecFromRoadStop(BaseStation *st, uint8_t specindex) void RoadStopUpdateCachedTriggers(BaseStation *st) { 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 * of this station. */ for (const auto &sm : GetStationSpecList(st)) { if (sm.spec == nullptr) continue; 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); } } diff --git a/src/newgrf_roadstop.h b/src/newgrf_roadstop.h index 690c9adadb..e953bdc3c1 100644 --- a/src/newgrf_roadstop.h +++ b/src/newgrf_roadstop.h @@ -134,7 +134,7 @@ struct RoadStopSpec : NewGRFSpecBase { RoadStopCallbackMasks callback_mask{}; 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 animation; diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index 4c16bb7155..1f0bf875f5 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -415,7 +415,7 @@ uint32_t Station::GetNewGRFVariable(const ResolverObject &object, uint8_t variab { switch (variable) { case 0x48: { // Accepted cargo types - uint32_t value = GetAcceptanceMask(this); + uint32_t value = GetAcceptanceMask(this).base(); return value; } @@ -514,14 +514,14 @@ uint32_t Waypoint::GetNewGRFVariable(const ResolverObject &, uint8_t variable, [ uint cargo = 0; const Station *st = Station::From(this->station_scope.st); - switch (this->station_scope.cargo_type) { - case INVALID_CARGO: - case CargoGRFFileProps::SG_DEFAULT_NA: - case CargoGRFFileProps::SG_PURCHASE: + switch (this->station_scope.cargo_type.base()) { + case INVALID_CARGO.base(): + case CargoGRFFileProps::SG_DEFAULT_NA.base(): + case CargoGRFFileProps::SG_PURCHASE.base(): cargo = 0; break; - case CargoGRFFileProps::SG_DEFAULT: + case CargoGRFFileProps::SG_DEFAULT.base(): for (const GoodsEntry &ge : st->goods) { if (!ge.HasData()) continue; cargo += ge.GetData().cargo.TotalCount(); @@ -771,7 +771,7 @@ void DeallocateSpecFromStation(BaseStation *st, uint8_t specindex) } else { st->speclist.clear(); st->cached_anim_triggers = {}; - st->cached_cargo_triggers = 0; + st->cached_cargo_triggers.Reset(); return; } } @@ -948,17 +948,14 @@ void TriggerStationRandomisation(BaseStation *st, TileIndex trigger_tile, Statio /* Check the cached cargo trigger bitmask to see if we need * to bother with any further processing. * Note: cached_cargo_triggers must be non-zero even for cargo-independent triggers. */ - if (st->cached_cargo_triggers == 0) return; - if (IsValidCargoType(cargo_type) && !HasBit(st->cached_cargo_triggers, cargo_type)) return; + if (st->cached_cargo_triggers.None()) return; + if (IsValidCargoType(cargo_type) && !st->cached_cargo_triggers.Test(cargo_type)) return; uint32_t whole_reseed = 0; ETileArea area = ETileArea(st, trigger_tile, tas[static_cast(trigger)]); /* Bitmask of completely empty cargo types to be matched. */ - CargoTypes empty_mask{}; - if (trigger == StationRandomTrigger::CargoTaken) { - empty_mask = GetEmptyMask(Station::From(st)); - } + CargoTypes not_empty_mask = (trigger == StationRandomTrigger::CargoTaken) ? GetEmptyMask(Station::From(st)).Flip() : ALL_CARGOTYPES; /* Store triggers now for var 5F */ 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 types have no more cargo waiting." */ 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); object.SetWaitingRandomTriggers(st->waiting_random_triggers); @@ -1016,14 +1013,14 @@ void TriggerStationRandomisation(BaseStation *st, TileIndex trigger_tile, Statio void StationUpdateCachedTriggers(BaseStation *st) { st->cached_anim_triggers = {}; - st->cached_cargo_triggers = 0; + st->cached_cargo_triggers.Reset(); /* Combine animation trigger bitmask for all station specs * of this station. */ for (const auto &sm : GetStationSpecList(st)) { if (sm.spec == nullptr) continue; 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); } } diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 1b74f90e80..ec05c181b1 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -122,7 +122,7 @@ using StationSpecFlags = EnumBitSet; struct StationSpec : NewGRFSpecBase { StationSpec() : name(0), disallowed_platforms(0), disallowed_lengths(0), - cargo_threshold(0), cargo_triggers(0), + cargo_threshold(0), cargo_triggers{}, callback_mask(0), flags(0) {} diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index 3480598032..dac957f154 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -862,7 +862,7 @@ static void ProcessNewGRFStringControlCode(char32_t scc, StringConsumer &consume case SCC_NEWGRF_PRINT_WORD_CARGO_NAME: { 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; } } diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 0d3c7554a0..a564611a65 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -635,7 +635,7 @@ static void AddAcceptedCargo_Object(TileIndex tile, CargoArray &acceptance, Carg CargoType pass = GetCargoTypeByLabel(CT_PASSENGERS); if (IsValidCargoType(pass)) { 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 @@ -645,7 +645,7 @@ static void AddAcceptedCargo_Object(TileIndex tile, CargoArray &acceptance, Carg CargoType mail = GetCargoTypeByLabel(CT_MAIL); if (IsValidCargoType(mail)) { acceptance[mail] += std::max(1U, level / 2); - SetBit(always_accepted, mail); + always_accepted.Set(mail); } } diff --git a/src/roadveh_gui.cpp b/src/roadveh_gui.cpp index b7fedf2495..4b76133c7a 100644 --- a/src/roadveh_gui.cpp +++ b/src/roadveh_gui.cpp @@ -36,7 +36,7 @@ void DrawRoadVehDetails(const Vehicle *v, const Rect &r) if (v->HasArticulatedPart()) { CargoArray max_cargo{}; - std::array subtype_text{}; + TypedIndexContainer, CargoType> subtype_text{}; for (const Vehicle *u = v; u != nullptr; u = u->Next()) { max_cargo[u->cargo_type] += u->cargo_cap; diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index 679b42bded..0fcce07447 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -359,7 +359,7 @@ public: 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, 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), }; static inline const SaveLoadCompatTable compat_description = _company_economy_compat; diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 901c939dde..9f53efcab3 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -383,7 +383,7 @@ public: { Station *st = Station::From(bst); - SlSetStructListLength(NUM_CARGO); + SlSetStructListLength(std::size(st->goods)); for (GoodsEntry &ge : st->goods) { SlStationGoods::cargo_reserved_count = ge.HasData() ? ge.GetData().cargo.reserved_count : 0; diff --git a/src/script/api/script_cargo.cpp b/src/script/api/script_cargo.cpp index d38ff9300a..d7725c2b7e 100644 --- a/src/script/api/script_cargo.cpp +++ b/src/script/api/script_cargo.cpp @@ -32,7 +32,7 @@ { 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 ScriptCargo::GetCargoLabel(CargoType cargo_type) diff --git a/src/script/api/script_cargo.hpp b/src/script/api/script_cargo.hpp index 13751e6070..940684e95a 100644 --- a/src/script/api/script_cargo.hpp +++ b/src/script/api/script_cargo.hpp @@ -60,9 +60,9 @@ public: */ enum SpecialCargoType { /* 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_NO_REFIT = ::CARGO_NO_REFIT, ///< Do not refit cargo of a vehicle. - CT_INVALID = ::INVALID_CARGO, ///< An invalid cargo type. + CT_AUTO_REFIT = ::CARGO_AUTO_REFIT.base(), ///< Automatically choose cargo type when doing auto-refitting. + CT_NO_REFIT = ::CARGO_NO_REFIT.base(), ///< Do not refit cargo of a vehicle. + CT_INVALID = ::INVALID_CARGO.base(), ///< An invalid cargo type. }; /** diff --git a/src/script/api/script_cargolist.cpp b/src/script/api/script_cargolist.cpp index 6744911cfb..d734e76f82 100644 --- a/src/script/api/script_cargolist.cpp +++ b/src/script/api/script_cargolist.cpp @@ -20,7 +20,7 @@ ScriptCargoList::ScriptCargoList() { 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); for (const auto &a : ind->accepted) { 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); for (const auto &p : ind->produced) { 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; const Station *st = ::Station::Get(station_id); - for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { - if (st->goods[cargo].status.Test(GoodsEntry::State::Acceptance)) this->AddItem(cargo); + for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) { + if (st->goods[cargo].status.Test(GoodsEntry::State::Acceptance)) this->AddItem(cargo.base()); } } diff --git a/src/script/api/script_engine.cpp b/src/script/api/script_engine.cpp index e7cf0a025a..322eb0fc12 100644 --- a/src/script/api/script_engine.cpp +++ b/src/script/api/script_engine.cpp @@ -67,7 +67,7 @@ if (!IsValidEngine(engine_id)) 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) diff --git a/src/script/api/script_industrytype.cpp b/src/script/api/script_industrytype.cpp index 5a6929deec..de82538334 100644 --- a/src/script/api/script_industrytype.cpp +++ b/src/script/api/script_industrytype.cpp @@ -72,7 +72,7 @@ ScriptList *list = new ScriptList(); for (const CargoType &cargo : ins->produced_cargo) { - if (::IsValidCargoType(cargo)) list->AddItem(cargo); + if (::IsValidCargoType(cargo)) list->AddItem(cargo.base()); } return list; @@ -86,7 +86,7 @@ ScriptList *list = new ScriptList(); for (const CargoType &cargo : ins->accepts_cargo) { - if (::IsValidCargoType(cargo)) list->AddItem(cargo); + if (::IsValidCargoType(cargo)) list->AddItem(cargo.base()); } return list; diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 827b654fe9..335fe7087f 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -227,7 +227,7 @@ void BuildLinkStatsLegend() _legend_linkstats[i].legend = cs->name; _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; } @@ -1254,9 +1254,9 @@ protected: */ void SetOverlayCargoMask() { - CargoTypes cargo_mask = 0; + CargoTypes cargo_mask{}; 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(_legend_linkstats[i].type)); } this->overlay->SetCargoMask(cargo_mask); } @@ -1453,7 +1453,7 @@ public: SmallMapWindow(WindowDesc &desc, int window_number) : Window(desc) { _smallmap_industry_highlight = IT_INVALID; - this->overlay = std::make_unique(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); + this->overlay = std::make_unique(this, WID_SM_MAP, CargoTypes{}, this->GetOverlayCompanyMask(), 1); this->CreateNestedTree(); this->LowerWidget(WID_SM_CONTOUR + this->map_type); diff --git a/src/station.cpp b/src/station.cpp index fa7b545fc3..acf66be9be 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -100,7 +100,7 @@ Station::~Station() 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); if (lg == nullptr) continue; diff --git a/src/station_base.h b/src/station_base.h index c503118f9e..0eaa8521ef 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -526,7 +526,7 @@ public: uint8_t last_vehicle_type = 0; std::list loading_vehicles{}; - std::array goods; ///< Goods at this station + TypedIndexContainer, 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) IndustryList industries_near{}; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry() diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index a28153602f..bc84504515 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -499,10 +499,10 @@ void ClearAllStationCachedNames() */ CargoTypes GetAcceptanceMask(const Station *st) { - CargoTypes mask = 0; + CargoTypes mask{}; 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(std::distance(std::begin(st->goods), it))); } return mask; } @@ -514,10 +514,10 @@ CargoTypes GetAcceptanceMask(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) { - 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(std::distance(std::begin(st->goods), it))); } 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 acceptance{}; - if (always_accepted != nullptr) *always_accepted = 0; + if (always_accepted != nullptr) always_accepted->Reset(); 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) { CargoArray acceptance{}; - if (always_accepted != nullptr) *always_accepted = 0; + if (always_accepted != nullptr) always_accepted->Reset(); BitmapTileIterator it(st->catchment_tiles); 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 */ - for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { + for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) { uint amt = acceptance[cargo]; /* 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? */ if (show_msg && st->owner == _local_company && st->IsInUse()) { /* Combine old and new masks to get changes */ - CargoTypes accepts = new_acc & ~old_acc; - CargoTypes rejects = ~new_acc & old_acc; + CargoTypes accepts = new_acc & CargoTypes{old_acc}.Flip(); + CargoTypes rejects = CargoTypes{new_acc}.Flip() & old_acc; /* Show news message if there are any changes */ - if (accepts != 0) ShowRejectOrAcceptNews(st, accepts, false); - if (rejects != 0) ShowRejectOrAcceptNews(st, rejects, true); + if (accepts.Any()) ShowRejectOrAcceptNews(st, accepts, false); + if (rejects.Any()) ShowRejectOrAcceptNews(st, rejects, true); } /* redraw the station view since acceptance changed */ @@ -3760,13 +3760,13 @@ static VehicleEnterTileStates VehicleEnter_Station(Vehicle *v, TileIndex tile, i void TriggerWatchedCargoCallbacks(Station *st) { /* Collect cargoes accepted since the last big tick. */ - CargoTypes cargoes = 0; - for (CargoType cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) { - if (st->goods[cargo_type].status.Test(GoodsEntry::State::AcceptedBigtick)) SetBit(cargoes, cargo_type); + CargoTypes cargoes{}; + for (CargoType cargo_type{}; cargo_type < NUM_CARGO; ++cargo_type) { + if (st->goods[cargo_type].status.Test(GoodsEntry::State::AcceptedBigtick)) cargoes.Set(cargo_type); } /* Anything to do? */ - if (cargoes == 0) return; + if (cargoes.None()) return; /* Loop over all houses in the catchment. */ BitmapTileIterator it(st->catchment_tiles); @@ -4027,7 +4027,7 @@ void RerouteCargo(Station *st, CargoType cargo, StationID avoid, StationID avoid */ 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); GoodsEntry &ge = from->goods[cargo]; LinkGraph *lg = LinkGraph::GetIfValid(ge.link_graph); diff --git a/src/station_gui.cpp b/src/station_gui.cpp index 4f0979ec86..83c463f55f 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -76,7 +76,7 @@ using RoadWaypointTypeFilter = GenericWaypointTypeFilter; int DrawStationCoverageAreaText(const Rect &r, StationCoverageType sct, int rad, bool supplies) { TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y); - CargoTypes cargo_mask = 0; + CargoTypes cargo_mask{}; if (_thd.drawstyle == HT_RECT && tile < Map::Size()) { CargoArray cargoes; 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. */ - for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { + for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) { switch (sct) { 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_ALL: break; 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)); @@ -291,7 +291,7 @@ protected: Scrollbar *vscroll = nullptr; uint rating_width = 0; bool filter_expanded = false; - std::array stations_per_cargo_type{}; ///< Number of stations with a rating for each cargo type. + TypedIndexContainer, 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. /** @@ -314,13 +314,13 @@ protected: if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) { bool has_rating = false; /* 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]++; } - for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) { + for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) { if (st->goods[cargo].HasRating()) { has_rating = true; - if (HasBit(this->filter.cargoes, cargo)) { + if (this->filter.cargoes.Test(cargo)) { this->stations.push_back(st); break; } @@ -359,7 +359,7 @@ protected: { 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); } @@ -371,7 +371,7 @@ protected: { 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); } @@ -384,7 +384,7 @@ protected: uint8_t maxr1 = 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 (b->goods[cargo].HasRating()) maxr2 = std::max(maxr2, b->goods[cargo].rating); } @@ -398,7 +398,7 @@ protected: uint8_t minr1 = 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 (b->goods[cargo].HasRating()) minr2 = std::min(minr2, b->goods[cargo].rating); } @@ -558,9 +558,9 @@ public: } 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 (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); } @@ -573,7 +573,7 @@ public: using DropDownListCargoItem = DropDownCheck>; 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()); bool any_hidden = false; @@ -582,7 +582,7 @@ public: if (count == 0 && !expanded) { any_hidden = true; } else { - list.push_back(std::make_unique>(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>(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(); @@ -591,13 +591,13 @@ public: if (count == 0 && !expanded) { any_hidden = true; } else { - list.push_back(std::make_unique(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(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 (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; @@ -684,11 +684,11 @@ public: if (widget == WID_STL_CARGODROPDOWN) { FilterState oldstate = this->filter; - if (index >= 0 && index < NUM_CARGO) { + if (IsInsideMM(index, 0, NUM_CARGO)) { if (_ctrl_pressed) { - ToggleBit(this->filter.cargoes, index); + this->filter.cargoes.Flip(static_cast(index)); } else { - this->filter.cargoes = 1ULL << index; + this->filter.cargoes = static_cast(index); this->filter.include_no_rating = false; } } else if (index == CargoFilterCriteria::CF_NO_RATING) { @@ -696,7 +696,7 @@ public: this->filter.include_no_rating = !this->filter.include_no_rating; } else { this->filter.include_no_rating = true; - this->filter.cargoes = 0; + this->filter.cargoes.Reset(); } } else if (index == CargoFilterCriteria::CF_SELECT_ALL) { this->filter.cargoes = _cargo_mask; @@ -1047,13 +1047,11 @@ private: void IncrementSize(); CargoDataEntry *parent; ///< the parent of this entry. - const union { - StationID station; ///< ID of the station this entry is associated with. - struct { - CargoType cargo; ///< ID of the cargo this entry is associated with. - bool transfers; ///< If there are transfers for this cargo. - }; - }; + + const StationID station = StationID::Invalid(); ///< ID of the station this entry is associated with. + const CargoType cargo = INVALID_CARGO; ///< ID of the cargo this entry is associated with. + bool transfers = false; ///< If there are transfers for this cargo. + 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. std::unique_ptr children; ///< the children of this entry. @@ -1673,7 +1671,7 @@ struct StationViewWindow : public Window { */ 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) { 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 { if (gui_scope) { - if (data >= 0 && data < NUM_CARGO) { - this->cached_destinations.Remove((CargoType)data); + if (IsInsideMM(data, 0, NUM_CARGO)) { + this->cached_destinations.Remove(static_cast(data)); } else { this->ReInit(); } diff --git a/src/strings.cpp b/src/strings.cpp index c327615485..e5e9495fe6 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1332,10 +1332,10 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin /* Tiny description of cargotypes. Layout: * param 1: cargo type * param 2: cargo count */ - CargoType cargo = args.GetNextParameter(); + CargoType cargo{args.GetNextParameter()}; int64_t amount = args.GetNextParameter(); - if (cargo >= CargoSpec::GetArraySize()) { + if (cargo.base() >= CargoSpec::GetArraySize()) { builder += "(invalid cargo type)"; break; } @@ -1361,10 +1361,10 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin /* Short description of cargotypes. Layout: * param 1: cargo type * param 2: cargo count */ - CargoType cargo = args.GetNextParameter(); + CargoType cargo{args.GetNextParameter()}; int64_t amount = args.GetNextParameter(); - if (cargo >= CargoSpec::GetArraySize()) { + if (cargo.base() >= CargoSpec::GetArraySize()) { builder += "(invalid cargo type)"; break; } @@ -1398,9 +1398,9 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin case SCC_CARGO_LONG: { // {CARGO_LONG} /* First parameter is cargo type, second parameter is cargo count */ - CargoType cargo = args.GetNextParameter(); + CargoType cargo{args.GetNextParameter()}; int64_t amount = args.GetNextParameter(); - if (cargo < CargoSpec::GetArraySize()) { + if (cargo.base() < CargoSpec::GetArraySize()) { auto tmp_args = MakeParameters(amount); GetStringWithArgs(builder, CargoSpec::Get(cargo)->quantifier, tmp_args); } else if (!IsValidCargoType(cargo)) { @@ -1417,7 +1417,7 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin std::string_view list_separator = GetListSeparator(); for (const auto &cs : _sorted_cargo_specs) { - if (!HasBit(cmask, cs->Index())) continue; + if (!cmask.Test(cs->Index())) continue; if (first) { first = false; diff --git a/src/subsidy.cpp b/src/subsidy.cpp index 33c4094ae6..b0a4f2586c 100644 --- a/src/subsidy.cpp +++ b/src/subsidy.cpp @@ -296,8 +296,8 @@ bool FindSubsidyTownCargoRoute() /* Choose a random cargo that is produced in the town. */ uint8_t cargo_number = RandomRange(cargo_count); - CargoType cargo_type; - for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) { + CargoType cargo_type{}; + for (; cargo_type < NUM_CARGO; ++cargo_type) { if (town_cargo_produced[cargo_type] > 0) { if (cargo_number == 0) break; cargo_number--; diff --git a/src/table/engines.h b/src/table/engines.h index b5e745c1b2..de9814af20 100644 --- a/src/table/engines.h +++ b/src/table/engines.h @@ -26,7 +26,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MT(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 5, f, INVALID_CARGO, e, 0, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } +#define MT(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 5, f, INVALID_CARGO, e, CargoTypes{}, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } /** * Writes the properties of a multiple-unit train into the EngineInfo struct. @@ -39,7 +39,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MM(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 5, f, INVALID_CARGO, e, 0, 8, EngineMiscFlags{EngineMiscFlag::RailIsMU}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } +#define MM(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 5, f, INVALID_CARGO, e, CargoTypes{}, 8, EngineMiscFlags{EngineMiscFlag::RailIsMU}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } /** * Writes the properties of a train carriage into the EngineInfo struct. @@ -52,7 +52,7 @@ * @see MT * @note the 5 between b and f is the load amount */ -#define MW(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 5, f, INVALID_CARGO, e, 0, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } +#define MW(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 5, f, INVALID_CARGO, e, CargoTypes{}, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } /** * Writes the properties of a road vehicle into the EngineInfo struct. @@ -65,7 +65,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MR(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 5, f, INVALID_CARGO, e, 0, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } +#define MR(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 5, f, INVALID_CARGO, e, CargoTypes{}, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } /** * Writes the properties of a ship into the EngineInfo struct. @@ -77,7 +77,7 @@ * @param f Bitmask of the climates * @note the 10 between b and f is the load amount */ -#define MS(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 10, f, INVALID_CARGO, e, 0, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } +#define MS(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 10, f, INVALID_CARGO, e, CargoTypes{}, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } /** * Writes the properties of an aeroplane into the EngineInfo struct. @@ -88,7 +88,7 @@ * @param e Bitmask of the climates * @note the 20 between b and e is the load amount */ -#define MA(a, b, c, d, e) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 20, e, INVALID_CARGO, CT_INVALID, 0, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } +#define MA(a, b, c, d, e) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, TimerGameCalendar::Year{c}, TimerGameCalendar::Year{d}, b, 20, e, INVALID_CARGO, CT_INVALID, CargoTypes{}, 8, EngineMiscFlags{}, VehicleCallbackMasks{}, 0, {}, STR_EMPTY, Ticks::CARGO_AGING_TICKS, EngineID::Invalid() } /* Climates * T = Temperate diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 44fd14b40a..c6a8b0efd8 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -270,8 +270,8 @@ static const NIFeature _nif_industrytile = { /*** NewGRF industries ***/ -#define NIP_PRODUCED_CARGO(prop, base_class, slot, type, name) { name, [] (const void *b) -> uint32_t { return static_cast(b)->GetProduced(slot).cargo; }, prop, type } -#define NIP_ACCEPTED_CARGO(prop, base_class, slot, type, name) { name, [] (const void *b) -> uint32_t { return static_cast(b)->GetAccepted(slot).cargo; }, prop, type } +#define NIP_PRODUCED_CARGO(prop, base_class, slot, type, name) { name, [] (const void *b) -> uint32_t { return static_cast(b)->GetProduced(slot).cargo.base(); }, prop, type } +#define NIP_ACCEPTED_CARGO(prop, base_class, slot, type, name) { name, [] (const void *b) -> uint32_t { return static_cast(b)->GetAccepted(slot).cargo.base(); }, prop, type } static const NIProperty _nip_industries[] = { NIP_PRODUCED_CARGO(0x25, Industry, 0, NIT_CARGO, "produced cargo 0"), diff --git a/src/table/town_land.h b/src/table/town_land.h index 12c9c0c1b5..582274d0fa 100644 --- a/src/table/town_land.h +++ b/src/table/town_land.h @@ -1814,7 +1814,7 @@ static_assert(lengthof(_town_draw_tile_data) == (NEW_HOUSE_OFFSET) * 4 * 4); {ca1, ca2, ca3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ {INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO}, \ bf, ba, true, SubstituteGRFFileProps(INVALID_HOUSE_ID), HouseCallbackMasks{}, {COLOUR_BEGIN, COLOUR_BEGIN, COLOUR_BEGIN, COLOUR_BEGIN}, \ - 16, HouseExtraFlags{}, HOUSE_NO_CLASS, AnimationInfo{}, 0, 0, 0, {}, {cg1, cg2, cg3}, } + 16, HouseExtraFlags{}, HOUSE_NO_CLASS, AnimationInfo{}, 0, 0, CargoTypes{}, {}, {cg1, cg2, cg3}, } /** House specifications from original data */ extern const HouseSpec _original_house_specs[] = { /** diff --git a/src/tile_cmd.h b/src/tile_cmd.h index ec3563887c..2feb794b6a 100644 --- a/src/tile_cmd.h +++ b/src/tile_cmd.h @@ -169,7 +169,7 @@ inline void AddAcceptedCargo(TileIndex tile, CargoArray &acceptance, CargoTypes { AddAcceptedCargoProc *proc = _tile_type_procs[GetTileType(tile)]->add_accepted_cargo_proc; if (proc == nullptr) return; - CargoTypes dummy = 0; // use dummy bitmask so there don't need to be several 'always_accepted != nullptr' checks + CargoTypes dummy{}; // use dummy bitmask so there don't need to be several 'always_accepted != nullptr' checks proc(tile, acceptance, always_accepted == nullptr ? dummy : *always_accepted); } diff --git a/src/town.h b/src/town.h index 7894d19f86..febe4a646d 100644 --- a/src/town.h +++ b/src/town.h @@ -74,7 +74,7 @@ struct Town : TownPool::PoolItem<&_town_pool> { uint8_t exclusive_counter = 0; ///< months till the exclusivity expires TypedIndexContainer, CompanyID> ratings{}; ///< ratings of each company for this town - std::array, NUM_CARGO> supplied{}; ///< Cargo statistics about supplied cargo. + TypedIndexContainer, NUM_CARGO>, CargoType> supplied{}; ///< Cargo statistics about supplied cargo. std::array, NUM_TAE> received{}; ///< Cargo statistics about received cargotypes. std::array goal{}; ///< Amount of cargo required for the town to grow. diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index e9e72f1aec..9ceeaca9ca 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -783,7 +783,7 @@ static void AddAcceptedCargoSetMask(CargoType cargo, uint amount, CargoArray &ac { if (!IsValidCargoType(cargo) || amount == 0) return; acceptance[cargo] += amount; - SetBit(always_accepted, cargo); + always_accepted.Set(cargo); } /** diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 89f4bf655e..406b99e550 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -400,7 +400,7 @@ public: for (auto tpe : {TPE_PASSENGERS, TPE_MAIL}) { for (const CargoSpec *cs : CargoSpec::town_production_cargoes[tpe]) { CargoType cargo_type = cs->Index(); - DrawString(tr, GetString(str_last_period, 1ULL << cargo_type, this->town->supplied[cargo_type].old_act, this->town->supplied[cargo_type].old_max)); + DrawString(tr, GetString(str_last_period, CargoTypes{cargo_type}, this->town->supplied[cargo_type].old_act, this->town->supplied[cargo_type].old_max)); tr.top += GetCharacterHeight(FS_NORMAL); } } @@ -1616,12 +1616,12 @@ static CargoTypes GetProducedCargoOfHouse(const HouseSpec *hs) uint amt = GB(callback, 0, 8); if (amt == 0) continue; - SetBit(produced, cargo); + produced.Set(cargo); } } else { /* Cargo is not controlled by NewGRF, town production effect is used instead. */ - for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_PASSENGERS]) SetBit(produced, cs->Index()); - for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_MAIL]) SetBit(produced, cs->Index()); + for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_PASSENGERS]) produced.Set(cs->Index()); + for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_MAIL]) produced.Set(cs->Index()); } return produced; } @@ -1707,7 +1707,7 @@ struct BuildHouseWindow : public PickerWindow { } CargoTypes produced = GetProducedCargoOfHouse(hs); - if (produced != 0) { + if (produced.Any()) { line << "\n"; line << GetString(STR_HOUSE_PICKER_CARGO_PRODUCED, produced); } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 4765b07c41..3fc8b19903 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -246,10 +246,10 @@ bool Vehicle::NeedsServicing() const CargoTypes available_cargo_types, union_mask; GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types); /* Is there anything to refit? */ - if (union_mask != 0) { + if (union_mask.Any()) { CargoType cargo_type; CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type); - if (!HasAtMostOneBit(cargo_mask)) { + if (!HasAtMostOneBit(cargo_mask.base())) { CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(new_engine); if ((cargo_mask & new_engine_default_cargoes) != cargo_mask) { /* We cannot refit to mixed cargoes in an automated way */ @@ -260,7 +260,7 @@ bool Vehicle::NeedsServicing() const /* Did the old vehicle carry anything? */ if (IsValidCargoType(cargo_type)) { /* We can't refit the vehicle to carry the cargo we want */ - if (!HasBit(available_cargo_types, cargo_type)) continue; + if (!available_cargo_types.Test(cargo_type)) continue; } } } diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 75baae2051..d73057a73f 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -389,7 +389,7 @@ static std::tuple RefitVehicle(Vehicle /* If the vehicle is not refittable, or does not allow automatic refitting, * count its capacity nevertheless if the cargo matches */ - bool refittable = HasBit(e->info.refit_mask, new_cargo_type) && (!auto_refit || e->info.misc_flags.Test(EngineMiscFlag::AutoRefit)); + bool refittable = e->info.refit_mask.Test(new_cargo_type) && (!auto_refit || e->info.misc_flags.Test(EngineMiscFlag::AutoRefit)); if (!refittable && v->cargo_type != new_cargo_type) { uint amount = e->DetermineCapacity(v, nullptr); if (amount > 0) cargo_capacities[v->cargo_type] += amount; diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 6727ed5796..95cc71cc4d 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -227,10 +227,10 @@ void BaseVehicleListWindow::BuildVehicleList() GenerateVehicleSortList(&this->vehicles, this->vli); - CargoTypes used = 0; + CargoTypes used{}; for (const Vehicle *v : this->vehicles) { for (const Vehicle *u = v; u != nullptr; u = u->Next()) { - if (u->cargo_cap > 0) SetBit(used, u->cargo_type); + if (u->cargo_cap > 0) used.Set(u->cargo_type); } } this->used_cargoes = used; @@ -483,10 +483,10 @@ void BaseVehicleListWindow::OnInit() StringID BaseVehicleListWindow::GetCargoFilterLabel(CargoType cargo_type) const { - switch (cargo_type) { - case CargoFilterCriteria::CF_ANY: return STR_CARGO_TYPE_FILTER_ALL; - case CargoFilterCriteria::CF_FREIGHT: return STR_CARGO_TYPE_FILTER_FREIGHT; - case CargoFilterCriteria::CF_NONE: return STR_CARGO_TYPE_FILTER_NONE; + switch (cargo_type.base()) { + case CargoFilterCriteria::CF_ANY.base(): return STR_CARGO_TYPE_FILTER_ALL; + case CargoFilterCriteria::CF_FREIGHT.base(): return STR_CARGO_TYPE_FILTER_FREIGHT; + case CargoFilterCriteria::CF_NONE.base(): return STR_CARGO_TYPE_FILTER_NONE; default: return CargoSpec::Get(cargo_type)->name; } } @@ -501,17 +501,17 @@ DropDownList BaseVehicleListWindow::BuildCargoDropDownList(bool full) const DropDownList list; /* 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 freight (i.e. vehicles with cargo capacity and with no passenger capacity). */ - list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_FREIGHT), CargoFilterCriteria::CF_FREIGHT)); + list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_FREIGHT), CargoFilterCriteria::CF_FREIGHT.base())); /* Add item for vehicles not carrying anything, e.g. train engines. */ - 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 */ Dimension d = GetLargestCargoIconSize(); for (const CargoSpec *cs : _sorted_cargo_specs) { - if (!full && !HasBit(this->used_cargoes, cs->Index())) continue; - list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index(), false, !HasBit(this->used_cargoes, cs->Index()))); + if (!full && !this->used_cargoes.Test(cs->Index())) continue; + list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index().base(), false, !this->used_cargoes.Test(cs->Index()))); } return list; @@ -619,7 +619,7 @@ uint8_t GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoType dest_ca for (Vehicle *v = v_for; v != nullptr; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr) { const Engine *e = v->GetEngine(); if (!e->CanCarryCargo() || !e->info.callback_mask.Test(VehicleCallbackMask::CargoSuffix)) continue; - if (!HasBit(e->info.refit_mask, dest_cargo_type) && v->cargo_type != dest_cargo_type) continue; + if (!e->info.refit_mask.Test(dest_cargo_type) && v->cargo_type != dest_cargo_type) continue; CargoType old_cargo_type = v->cargo_type; uint8_t old_cargo_subtype = v->cargo_subtype; @@ -791,7 +791,7 @@ struct RefitWindow : public Window { for (const auto &cs : _sorted_cargo_specs) { CargoType cargo_type = cs->Index(); /* Skip cargo type if it's not listed */ - if (!HasBit(cmask, cargo_type)) continue; + if (!cmask.Test(cargo_type)) continue; auto &list = this->refit_list[cargo_type]; bool first_vehicle = list.empty(); @@ -1359,25 +1359,24 @@ void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *pare uint ShowRefitOptionsList(int left, int right, int y, EngineID engine) { /* List of cargo types of this engine */ - CargoTypes cmask = GetUnionOfArticulatedRefitMasks(engine, false); - /* List of cargo types available in this climate */ - CargoTypes lmask = _cargo_mask; + CargoTypes present = GetUnionOfArticulatedRefitMasks(engine, false); /* Draw nothing if the engine is not refittable */ - if (HasAtMostOneBit(cmask)) return y; + if (HasAtMostOneBit(present.base())) return y; std::string str; - if (cmask == lmask) { + if (present == _cargo_mask) { /* Engine can be refitted to all types in this climate */ str = GetString(STR_PURCHASE_INFO_REFITTABLE_TO, STR_PURCHASE_INFO_ALL_TYPES, std::monostate{}); } else { /* Check if we are able to refit to more cargo types and unable to. If * so, invert the cargo types to list those that we can't refit to. */ - if (CountBits(cmask ^ lmask) < CountBits(cmask) && CountBits(cmask ^ lmask) <= 7) { - cmask ^= lmask; - str = GetString(STR_PURCHASE_INFO_REFITTABLE_TO, STR_PURCHASE_INFO_ALL_BUT, cmask); + CargoTypes excluded = CargoTypes{present}.Flip(_cargo_mask); + uint num_excluded = excluded.Count(); + if (num_excluded < present.Count() && num_excluded <= 7) { + str = GetString(STR_PURCHASE_INFO_REFITTABLE_TO, STR_PURCHASE_INFO_ALL_BUT, excluded); } else { - str = GetString(STR_PURCHASE_INFO_REFITTABLE_TO, STR_JUST_CARGO_LIST, cmask); + str = GetString(STR_PURCHASE_INFO_REFITTABLE_TO, STR_JUST_CARGO_LIST, present); } } @@ -1793,12 +1792,12 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int if (_settings_client.gui.show_cargo_in_vehicle_lists) { /* Get the cargoes the vehicle can carry */ - CargoTypes vehicle_cargoes = 0; + CargoTypes vehicle_cargoes{}; for (auto u = v; u != nullptr; u = u->Next()) { if (u->cargo_cap == 0) continue; - SetBit(vehicle_cargoes, u->cargo_type); + vehicle_cargoes.Set(u->cargo_type); } if (!v->name.empty()) { @@ -2110,7 +2109,7 @@ public: return; case WID_VL_FILTER_BY_CARGO: // Cargo filter dropdown - ShowDropDownList(this, this->BuildCargoDropDownList(false), this->cargo_filter_criteria, widget); + ShowDropDownList(this, this->BuildCargoDropDownList(false), this->cargo_filter_criteria.base(), widget); break; case WID_VL_LIST: { // Matrix to show vehicles @@ -2182,7 +2181,7 @@ public: break; case WID_VL_FILTER_BY_CARGO: - this->SetCargoFilter(index); + this->SetCargoFilter(static_cast(index)); break; case WID_VL_MANAGE_VEHICLES_DROPDOWN: diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index d1097c499c..38d26e24ac 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -116,7 +116,7 @@ struct BaseVehicleListWindow : public Window { void UpdateVehicleGroupBy(GroupBy group_by); void SortVehicleList(); void BuildVehicleList(); - void SetCargoFilter(uint8_t index); + void SetCargoFilter(CargoType index); void SetCargoFilterArray(); void FilterVehicleList(); StringID GetCargoFilterLabel(CargoType cargo_type) const; diff --git a/src/viewport.cpp b/src/viewport.cpp index 4699990cce..24771f93ed 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1825,7 +1825,7 @@ void ViewportDoDraw(const Viewport &vp, int left, int top, int right, int bottom dp.height = UnScaleByZoom(dp.height, zoom); AutoRestoreBackup cur_dpi(_cur_dpi, &dp); - if (vp.overlay != nullptr && vp.overlay->GetCargoMask() != 0 && vp.overlay->GetCompanyMask().Any()) { + if (vp.overlay != nullptr && vp.overlay->GetCargoMask().Any() && vp.overlay->GetCompanyMask().Any()) { /* translate to window coordinates */ dp.left = x; dp.top = y; @@ -2499,7 +2499,7 @@ void RebuildViewportOverlay(Window *w) { if (w->viewport->overlay != nullptr && w->viewport->overlay->GetCompanyMask().Any() && - w->viewport->overlay->GetCargoMask() != 0) { + w->viewport->overlay->GetCargoMask().Any()) { w->viewport->overlay->SetDirty(); w->SetDirty(); }