diff --git a/src/elrail.cpp b/src/elrail.cpp index 7ca580182f..3dc3d7faae 100644 --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -133,7 +133,7 @@ static TrackBits MaskWireBits(TileIndex t, TrackBits tracks) if (!IsPlainRailTile(t)) return tracks; - TrackdirBits neighbour_tdb = TRACKDIR_BIT_NONE; + TrackdirBits neighbour_tdb{}; for (DiagDirection d = DiagDirection::Begin; d < DiagDirection::End; d++) { /* If the neighbour tile is either not electrified or has no tracks that can be reached * from this tile, mark all trackdirs that can be reached from the neighbour tile @@ -155,7 +155,7 @@ static TrackBits MaskWireBits(TileIndex t, TrackBits tracks) if (tracks == TRACK_BIT_CROSS || !TracksOverlap(tracks)) { /* If the tracks form either a diagonal crossing or don't overlap, both * trackdirs have to be marked to mask the corresponding track bit. */ - mask = static_cast(~((neighbour_tdb & (neighbour_tdb >> 8)) & TRACK_BIT_ALL.base())); + mask = static_cast(~((neighbour_tdb.base() & (neighbour_tdb.base() >> 8)) & TRACK_BIT_ALL.base())); /* If that results in no masked tracks and it is not a diagonal crossing, * require only one marked trackdir to mask. */ if (tracks != TRACK_BIT_CROSS && mask == TRACK_BIT_ALL) mask = TrackdirBitsToTrackBits(neighbour_tdb).Flip(TRACK_BIT_ALL); @@ -164,10 +164,10 @@ static TrackBits MaskWireBits(TileIndex t, TrackBits tracks) mask = TrackdirBitsToTrackBits(neighbour_tdb).Flip(TRACK_BIT_ALL); /* If that results in an empty set, require both trackdirs for diagonal track. */ if (!tracks.Any(mask)) { - if ((neighbour_tdb & TRACKDIR_BIT_X_NE) == 0 || (neighbour_tdb & TRACKDIR_BIT_X_SW) == 0) mask.Set(Track::X); - if ((neighbour_tdb & TRACKDIR_BIT_Y_NW) == 0 || (neighbour_tdb & TRACKDIR_BIT_Y_SE) == 0) mask.Set(Track::Y); + if (!neighbour_tdb.Test(Trackdir::X_NE) || !neighbour_tdb.Test(Trackdir::X_SW)) mask.Set(Track::X); + if (!neighbour_tdb.Test(Trackdir::Y_NW) || !neighbour_tdb.Test(Trackdir::Y_SE)) mask.Set(Track::Y); /* If that still is not enough, require both trackdirs for any track. */ - if (!tracks.Any(mask)) mask = static_cast(~((neighbour_tdb & (neighbour_tdb >> 8)) & TRACK_BIT_ALL.base())); + if (!tracks.Any(mask)) mask = static_cast(~((neighbour_tdb.base() & (neighbour_tdb.base() >> 8)) & TRACK_BIT_ALL.base())); } } diff --git a/src/misc/dbg_helpers.cpp b/src/misc/dbg_helpers.cpp index 6c4e922810..d93d8fd436 100644 --- a/src/misc/dbg_helpers.cpp +++ b/src/misc/dbg_helpers.cpp @@ -27,7 +27,7 @@ static const std::string_view trackdir_names[] = { */ std::string ValueStr(Trackdir td) { - return fmt::format("{} ({})", to_underlying(td), ItemAt(td, trackdir_names, "UNK", INVALID_TRACKDIR, "INV")); + return fmt::format("{} ({})", to_underlying(td), ItemAt(td, trackdir_names, "UNK", Trackdir::Invalid, "INV")); } /** @@ -37,7 +37,7 @@ std::string ValueStr(Trackdir td) */ std::string ValueStr(TrackdirBits td_bits) { - return fmt::format("{} ({})", to_underlying(td_bits), ComposeName(td_bits, trackdir_names, "UNK", INVALID_TRACKDIR_BIT, "INV")); + return fmt::format("{} ({})", td_bits.base(), ComposeName(td_bits, trackdir_names, "UNK", INVALID_TRACKDIR_BIT, "INV")); } diff --git a/src/misc/dbg_helpers.h b/src/misc/dbg_helpers.h index 68159b00c8..18be3fbc9b 100644 --- a/src/misc/dbg_helpers.h +++ b/src/misc/dbg_helpers.h @@ -58,34 +58,21 @@ inline std::string_view ItemAt(E idx, std::span names, s /** * Helper template function that returns compound bitfield name that is * concatenation of names of each set bit in the given value - * or invalid_name when index == invalid_index * or unknown_name when index is out of bounds. * @param value The bitmask of values. * @param names Span of names to index. * @param unknown_name The default value when the index does not exist. - * @param invalid_index The invalid value to consider. - * @param invalid_name The value to output when the invalid value is given. * @return The composed name. */ -template -inline std::string ComposeName(E value, std::span names, std::string_view unknown_name, E invalid_index, std::string_view invalid_name) +template +inline std::string ComposeName(Tbitset value, std::span names, std::string_view unknown_name) { + if (value.None()) return ""; + std::string out; - if (value == invalid_index) { - out = invalid_name; - } else if (value == 0) { - out = ""; - } else { - for (size_t i = 0; i < std::size(names); i++) { - if ((value & (1 << i)) == 0) continue; - out += (!out.empty() ? "+" : ""); - out += names[i]; - value &= ~static_cast(1 << i); - } - if (value != 0) { - out += (!out.empty() ? "+" : ""); - out += unknown_name; - } + for (auto index : value) { + if (!out.empty()) out += "+"; + out += to_underlying(index) < std::size(names) ? names[to_underlying(index)] : unknown_name; } return out; } @@ -93,31 +80,20 @@ inline std::string ComposeName(E value, std::span names, /** * Helper template function that returns compound bitfield name that is * concatenation of names of each set bit in the given value + * or invalid_name when value == invalid_index * or unknown_name when index is out of bounds. * @param value The bitmask of values. * @param names Span of names to index. * @param unknown_name The default value when the index does not exist. + * @param invalid_value The invalid value to consider. + * @param invalid_name The value to output when the invalid value is given. * @return The composed name. */ -template -inline std::string ComposeName(E value, std::span names, std::string_view unknown_name) +template +inline std::string ComposeName(Tbitset value, std::span names, std::string_view unknown_name, Tbitset invalid_value, std::string_view invalid_name) { - std::string out; - if (value.base() == 0) { - out = ""; - } else { - for (size_t i = 0; i < std::size(names); ++i) { - if (!value.Test(static_cast(i))) continue; - out += (!out.empty() ? "+" : ""); - out += names[i]; - value.Reset(static_cast(i)); - } - if (value.base() != 0) { - out += (!out.empty() ? "+" : ""); - out += unknown_name; - } - } - return out; + if (value == invalid_value) return std::string{invalid_name}; + return ComposeName(value, names, unknown_name); } std::string ValueStr(Trackdir td); diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp index 3b397f1616..6a84303624 100644 --- a/src/pathfinder/follow_track.hpp +++ b/src/pathfinder/follow_track.hpp @@ -75,9 +75,9 @@ struct CFollowTrackT { this->veh_owner = o; /* don't worry, all is inlined so compiler should remove unnecessary initializations */ this->old_tile = INVALID_TILE; - this->old_td = INVALID_TRACKDIR; + this->old_td = Trackdir::Invalid; this->new_tile = INVALID_TILE; - this->new_td_bits = TRACKDIR_BIT_NONE; + this->new_td_bits.Reset(); this->exitdir = DiagDirection::Invalid; this->is_station = false; this->is_bridge = false; @@ -134,7 +134,7 @@ struct CFollowTrackT { if (this->IsTram() && this->GetSingleTramBit(this->old_tile) != DiagDirection::Invalid) return true; // Skip the check for single tram bits const RoadTramType sub_mode = (IsRoadTT() && this->veh != nullptr) ? (this->IsTram() ? RoadTramType::Tram : RoadTramType::Road) : RoadTramType::Invalid; const TrackdirBits old_tile_valid_dirs = GetTileTrackStatus(this->old_tile, TT(), sub_mode).trackdirs; - return (old_tile_valid_dirs & TrackdirToTrackdirBits(this->old_td)) != TRACKDIR_BIT_NONE; + return old_tile_valid_dirs.Any(TrackdirToTrackdirBits(this->old_td)); }()); this->exitdir = TrackdirToExitdir(this->old_td); @@ -143,7 +143,7 @@ struct CFollowTrackT { this->FollowTileExit(); if (!this->QueryNewTileTrackStatus()) return TryReverse(); this->new_td_bits &= DiagdirReachesTrackdirs(this->exitdir); - if (this->new_td_bits == TRACKDIR_BIT_NONE || !this->CanEnterNewTile()) { + if (this->new_td_bits.None() || !this->CanEnterNewTile()) { /* In case we can't enter the next tile, but are * a normal road vehicle, then we can actually * try to reverse as this is the end of the road. @@ -160,13 +160,13 @@ struct CFollowTrackT { /* CanEnterNewTile already set a reason. * Do NOT overwrite it (important for example for EC_RAIL_ROAD_TYPE). * Only set a reason if CanEnterNewTile was not called */ - if (this->new_td_bits == TRACKDIR_BIT_NONE) this->err = EC_NO_WAY; + if (this->new_td_bits.None()) this->err = EC_NO_WAY; return false; } if ((!IsRailTT() && !Allow90degTurns()) || (IsRailTT() && Rail90DegTurnDisallowed(GetTileRailType(this->old_tile), GetTileRailType(this->new_tile), !Allow90degTurns()))) { - this->new_td_bits &= ~TrackdirCrossesTrackdirs(this->old_td); - if (this->new_td_bits == TRACKDIR_BIT_NONE) { + this->new_td_bits.Reset(TrackdirCrossesTrackdirs(this->old_td)); + if (this->new_td_bits.None()) { this->err = EC_90DEG; return false; } @@ -183,7 +183,7 @@ struct CFollowTrackT { TileIndexDiff diff = TileOffsByDiagDir(this->exitdir); for (TileIndex tile = this->new_tile - diff * this->tiles_skipped; tile != this->new_tile; tile += diff) { if (HasStationReservation(tile)) { - this->new_td_bits = TRACKDIR_BIT_NONE; + this->new_td_bits.Reset(); this->err = EC_RESERVED; return false; } @@ -192,12 +192,12 @@ struct CFollowTrackT { TrackBits reserved = GetReservedTrackbits(this->new_tile); /* Mask already reserved trackdirs. */ - this->new_td_bits &= ~TrackBitsToTrackdirBits(reserved); + this->new_td_bits.Reset(TrackBitsToTrackdirBits(reserved)); /* Mask out all trackdirs that conflict with the reservation. */ for (Track t : TrackdirBitsToTrackBits(this->new_td_bits)) { - if (TracksOverlap(reserved | t)) this->new_td_bits &= ~TrackToTrackdirBits(t); + if (TracksOverlap(reserved | t)) this->new_td_bits.Reset(TrackToTrackdirBits(t)); } - if (this->new_td_bits == TRACKDIR_BIT_NONE) { + if (this->new_td_bits.None()) { this->err = EC_RESERVED; return false; } @@ -255,7 +255,7 @@ protected: } else { this->new_td_bits = GetTileTrackStatus(this->new_tile, TT(), RoadTramType::Invalid).trackdirs; } - return (this->new_td_bits != TRACKDIR_BIT_NONE); + return this->new_td_bits.Any(); } /** @@ -457,7 +457,7 @@ protected: /* set new trackdir bits to all reachable trackdirs */ QueryNewTileTrackStatus(); this->new_td_bits &= DiagdirReachesTrackdirs(this->exitdir); - if (this->new_td_bits != TRACKDIR_BIT_NONE) { + if (this->new_td_bits.Any()) { /* we have some trackdirs reachable after reversal */ return true; } diff --git a/src/pathfinder/pathfinder_func.h b/src/pathfinder/pathfinder_func.h index 28bbe08d46..55f1e59d58 100644 --- a/src/pathfinder/pathfinder_func.h +++ b/src/pathfinder/pathfinder_func.h @@ -63,18 +63,18 @@ inline TrackdirBits GetTrackdirBitsForRoad(TileIndex tile, RoadTramType rtt) { TrackdirBits bits = GetTileTrackStatus(tile, TRANSPORT_ROAD, rtt).trackdirs; - if (rtt == RoadTramType::Tram && bits == TRACKDIR_BIT_NONE) { + if (rtt == RoadTramType::Tram && bits.None()) { if (IsNormalRoadTile(tile)) { RoadBits rb = GetRoadBits(tile, RoadTramType::Tram); switch (rb.base()) { case RoadBits{RoadBit::NE}.base(): case RoadBits{RoadBit::SW}.base(): - bits = TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW; + bits = {Trackdir::X_NE, Trackdir::X_SW}; break; case RoadBits{RoadBit::NW}.base(): case RoadBits{RoadBit::SE}.base(): - bits = TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_Y_SE; + bits = {Trackdir::Y_NW, Trackdir::Y_SE}; break; default: break; diff --git a/src/pathfinder/water_regions.cpp b/src/pathfinder/water_regions.cpp index e30b9210d0..d7667a2006 100644 --- a/src/pathfinder/water_regions.cpp +++ b/src/pathfinder/water_regions.cpp @@ -153,7 +153,7 @@ public: tiles_to_check.pop_back(); const TrackdirBits valid_dirs = TrackBitsToTrackdirBits(GetWaterTracks(tile)); - if (valid_dirs == TRACKDIR_BIT_NONE) continue; + if (valid_dirs.None()) continue; WaterRegionPatchLabel &tile_patch = (*this->data.tile_patch_labels)[this->GetLocalIndex(tile)]; if (tile_patch != INVALID_WATER_REGION_PATCH) continue; @@ -162,7 +162,7 @@ public: highest_assigned_label = current_label; increase_label = true; - for (const Trackdir dir : SetTrackdirBitIterator(valid_dirs)) { + for (Trackdir dir : valid_dirs) { /* By using a TrackFollower we "play by the same rules" as the actual ship pathfinder */ CFollowTrackWater ft; if (ft.Follow(tile, dir)) { diff --git a/src/pathfinder/yapf/yapf.h b/src/pathfinder/yapf/yapf.h index e93c2ac840..9df200f0db 100644 --- a/src/pathfinder/yapf/yapf.h +++ b/src/pathfinder/yapf/yapf.h @@ -43,7 +43,7 @@ bool YapfShipCheckReverse(const Ship *v, Trackdir *trackdir); * @param trackdirs available trackdirs on the new tile (to choose from) * @param path_found [out] Whether a path has been found (true) or has been guessed (false) * @param path_cache Cache of a previously chosen path. - * @return the best trackdir for next turn or INVALID_TRACKDIR if the path could not be found + * @return the best trackdir for next turn or Trackdir::Invalid if the path could not be found */ Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found, RoadVehPathCache &path_cache); diff --git a/src/pathfinder/yapf/yapf_base.hpp b/src/pathfinder/yapf/yapf_base.hpp index c2db9be579..b79094e811 100644 --- a/src/pathfinder/yapf/yapf_base.hpp +++ b/src/pathfinder/yapf/yapf_base.hpp @@ -235,9 +235,8 @@ public: */ inline void AddMultipleNodes(Node *parent, const TrackFollower &tf) { - bool is_choice = (KillFirstBit(tf.new_td_bits) != TRACKDIR_BIT_NONE); - for (TrackdirBits rtds = tf.new_td_bits; rtds != TRACKDIR_BIT_NONE; rtds = KillFirstBit(rtds)) { - Trackdir td = (Trackdir)FindFirstBit(rtds); + bool is_choice = tf.new_td_bits.Count() > 1; + for (Trackdir td : tf.new_td_bits) { Node &n = Yapf().CreateNewNode(); n.Set(parent, tf.new_tile, td, is_choice); Yapf().AddNewNode(n, tf); diff --git a/src/pathfinder/yapf/yapf_common.hpp b/src/pathfinder/yapf/yapf_common.hpp index 21944d98c9..4523e12d9a 100644 --- a/src/pathfinder/yapf/yapf_common.hpp +++ b/src/pathfinder/yapf/yapf_common.hpp @@ -37,9 +37,8 @@ public: */ void SetOrigin(TileIndex tile, TrackdirBits trackdirs) { - bool is_choice = (KillFirstBit(trackdirs) != TRACKDIR_BIT_NONE); - for (TrackdirBits tdb = trackdirs; tdb != TRACKDIR_BIT_NONE; tdb = KillFirstBit(tdb)) { - Trackdir td = (Trackdir)FindFirstBit(tdb); + bool is_choice = trackdirs.Count() > 1; + for (Trackdir td : trackdirs) { Node &node = Yapf().CreateNewNode(); node.Set(nullptr, tile, td, is_choice); Yapf().AddStartupNode(node); @@ -72,14 +71,14 @@ public: * @param reverse_penalty The penalty for reversing. */ void SetOrigin(TileIndex forward_tile, Trackdir forward_td, TileIndex reverse_tile = INVALID_TILE, - Trackdir reverse_td = INVALID_TRACKDIR, int reverse_penalty = 0) + Trackdir reverse_td = Trackdir::Invalid, int reverse_penalty = 0) { - if (forward_tile != INVALID_TILE && forward_td != INVALID_TRACKDIR) { + if (forward_tile != INVALID_TILE && forward_td != Trackdir::Invalid) { Node &node = Yapf().CreateNewNode(); node.Set(nullptr, forward_tile, forward_td, false); Yapf().AddStartupNode(node); } - if (reverse_tile != INVALID_TILE && reverse_td != INVALID_TRACKDIR) { + if (reverse_tile != INVALID_TILE && reverse_td != Trackdir::Invalid) { Node &node = Yapf().CreateNewNode(); node.Set(nullptr, reverse_tile, reverse_td, false); node.cost = reverse_penalty; diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index b9e85a54ad..310f591b53 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -35,7 +35,7 @@ protected: TileType tile_type; RailType rail_type; - TILE() : tile(INVALID_TILE), td(INVALID_TRACKDIR), tile_type(TileType::Void), rail_type(INVALID_RAILTYPE) { } + TILE() : tile(INVALID_TILE), td(Trackdir::Invalid), tile_type(TileType::Void), rail_type(INVALID_RAILTYPE) { } TILE(TileIndex tile, Trackdir td) : tile(tile), td(td), tile_type(GetTileType(tile)), rail_type(GetTileRailType(tile)) { } }; @@ -106,7 +106,7 @@ public: assert(IsValidTrackdir(td2)); int cost = 0; if (TrackFollower::Allow90degTurns() - && HasTrackdir(TrackdirCrossesTrackdirs(td1), td2)) { + && TrackdirCrossesTrackdirs(td1).Test(td2)) { /* 90-deg curve penalty */ cost += Yapf().PfGetSettings().rail_curve90_penalty; } else if (td2 != NextTrackdir(td1)) { @@ -295,7 +295,7 @@ public: { assert(!n.flags_u.flags_s.target_seen); assert(follower->new_tile == n.key.tile); - assert((HasTrackdir(follower->new_td_bits, n.key.td))); + assert(follower->new_td_bits.Test(n.key.td)); /* Does the node have some parent node? */ bool has_parent = (n.parent != nullptr); @@ -437,14 +437,14 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th t = ft.new_tile; if (t == cur.tile || --max_tiles == 0) { /* We looped back on ourself or found another loop, bail out. */ - td = INVALID_TRACKDIR; + td = Trackdir::Invalid; break; } - if (KillFirstBit(ft.new_td_bits) != TRACKDIR_BIT_NONE) { + if (ft.new_td_bits.Count() > 1) { /* We encountered a junction; it's going to be too complex to * handle this perfectly, so just bail out. There is no simple * free path, so try the other possibilities. */ - td = INVALID_TRACKDIR; + td = Trackdir::Invalid; break; } td = RemoveFirstTrackdir(&ft.new_td_bits); @@ -455,7 +455,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th /* In the case this platform is (possibly) occupied we add penalty so the * other platforms of this waypoint are evaluated as well, i.e. we assume * that there is a red signal in the waypoint when it's occupied. */ - if (td == INVALID_TRACKDIR || + if (td == Trackdir::Invalid || !IsSafeWaitingPosition(v, t, td, true, _settings_game.pf.forbid_90_deg) || !IsWaitingPositionFree(v, t, td, _settings_game.pf.forbid_90_deg)) { extra_cost += Yapf().PfGetSettings().rail_lastred_penalty; @@ -521,14 +521,14 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th } /* Check if the next tile is not a choice. */ - if (KillFirstBit(follower_local.new_td_bits) != TRACKDIR_BIT_NONE) { + if (follower_local.new_td_bits.Count() > 1) { /* More than one segment will follow. Close this one. */ end_segment_reason.Set(EndSegmentReason::ChoiceFollows); break; } /* Gather the next tile/trackdir/tile_type/rail_type. */ - TILE next(follower_local.new_tile, (Trackdir)FindFirstBit(follower_local.new_td_bits)); + TILE next(follower_local.new_tile, follower_local.new_td_bits.GetNthSetBit(0).value()); if (TrackFollower::DoTrackMasking() && IsTileType(next.tile, TileType::Railway)) { if (HasSignalOnTrackdir(next.tile, next.td) && IsPbsSignal(GetSignalType(next.tile, TrackdirToTrack(next.td)))) { diff --git a/src/pathfinder/yapf/yapf_destrail.hpp b/src/pathfinder/yapf/yapf_destrail.hpp index 49d8840f42..89be57c401 100644 --- a/src/pathfinder/yapf/yapf_destrail.hpp +++ b/src/pathfinder/yapf/yapf_destrail.hpp @@ -179,7 +179,7 @@ public: return IsRailDepotTile(tile); } - return (tile == this->dest_tile) && HasTrackdir(this->dest_trackdirs, td); + return (tile == this->dest_tile) && this->dest_trackdirs.Test(td); } /** @copydoc CYapfBaseT::PfCalcEstimateFunc */ diff --git a/src/pathfinder/yapf/yapf_node.hpp b/src/pathfinder/yapf/yapf_node.hpp index 703c215d08..6482331c27 100644 --- a/src/pathfinder/yapf/yapf_node.hpp +++ b/src/pathfinder/yapf/yapf_node.hpp @@ -23,7 +23,7 @@ struct CYapfNodeKeyExitDir { { this->tile = tile; this->td = td; - this->exitdir = (this->td == INVALID_TRACKDIR) ? DiagDirection::Invalid : TrackdirToExitdir(this->td); + this->exitdir = (this->td == Trackdir::Invalid) ? DiagDirection::Invalid : TrackdirToExitdir(this->td); } inline int CalcHash() const @@ -47,7 +47,7 @@ struct CYapfNodeKeyExitDir { struct CYapfNodeKeyTrackDir : public CYapfNodeKeyExitDir { inline int CalcHash() const { - return this->td | (this->tile.base() << 4); + return to_underlying(this->td) | (this->tile.base() << 4); } inline bool operator==(const CYapfNodeKeyTrackDir &other) const diff --git a/src/pathfinder/yapf/yapf_node_rail.hpp b/src/pathfinder/yapf/yapf_node_rail.hpp index 8e3790618f..8ae03b63f2 100644 --- a/src/pathfinder/yapf/yapf_node_rail.hpp +++ b/src/pathfinder/yapf/yapf_node_rail.hpp @@ -32,7 +32,7 @@ struct CYapfRailSegmentKey { inline void Set(const CYapfNodeKeyTrackDir &node_key) { - this->value = (node_key.tile.base() << 4) | node_key.td; + this->value = (node_key.tile.base() << 4) | to_underlying(node_key.td); } inline int32_t CalcHash() const @@ -47,7 +47,7 @@ struct CYapfRailSegmentKey { inline Trackdir GetTrackdir() const { - return (Trackdir)(this->value & 0x0F); + return static_cast(this->value & 0x0F); } inline bool operator==(const CYapfRailSegmentKey &other) const @@ -68,10 +68,10 @@ struct CYapfRailSegment { CYapfRailSegmentKey key; TileIndex last_tile = INVALID_TILE; - Trackdir last_td = INVALID_TRACKDIR; + Trackdir last_td = Trackdir::Invalid; int cost = -1; TileIndex last_signal_tile = INVALID_TILE; - Trackdir last_signal_td = INVALID_TRACKDIR; + Trackdir last_signal_td = Trackdir::Invalid; EndSegmentReasons end_segment_reason{}; CYapfRailSegment *hash_next = nullptr; @@ -186,7 +186,7 @@ struct CYapfRailNode : CYapfNodeT { if (!follower.Follow(cur, cur_td)) break; cur = follower.new_tile; - assert(KillFirstBit(follower.new_td_bits) == TRACKDIR_BIT_NONE); + assert(follower.new_td_bits.Count() == 1); cur_td = FindFirstTrackdir(follower.new_td_bits); } diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp index c3a18ac38b..28d87b04d5 100644 --- a/src/pathfinder/yapf/yapf_rail.cpp +++ b/src/pathfinder/yapf/yapf_rail.cpp @@ -459,15 +459,15 @@ public: /* set origin and destination nodes */ PBSTileInfo origin = FollowTrainReservation(v); - Yapf().SetOrigin(origin.tile, origin.trackdir, INVALID_TILE, INVALID_TRACKDIR, 1); + Yapf().SetOrigin(origin.tile, origin.trackdir, INVALID_TILE, Trackdir::Invalid, 1); Yapf().SetTreatFirstRedTwoWaySignalAsEOL(true); Yapf().SetDestination(v); /* find the best path */ path_found = Yapf().FindPath(v); - /* if path not found - return INVALID_TRACKDIR */ - Trackdir next_trackdir = INVALID_TRACKDIR; + /* if path not found - return Trackdir::Invalid */ + Trackdir next_trackdir = Trackdir::Invalid; Node *node = Yapf().GetBestNode(); if (node != nullptr) { /* reserve till end of path */ @@ -485,7 +485,7 @@ public: /* If the best PF node has no parent, then there is no (valid) best next trackdir to return. * This occurs when the PF is called while the train is already at its destination. */ - if (prev == nullptr) return INVALID_TRACKDIR; + if (prev == nullptr) return Trackdir::Invalid; /* return trackdir from the best origin node (one of start nodes) */ Node &best_next_node = *prev; @@ -600,7 +600,7 @@ Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdi ? CYapfRailNo90::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest) : CYapfRail::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest); - return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : FindFirstTrack(tracks); + return (td_ret != Trackdir::Invalid) ? TrackdirToTrack(td_ret) : FindFirstTrack(tracks); } bool YapfTrainCheckReverse(const Train *v) diff --git a/src/pathfinder/yapf/yapf_river_builder.cpp b/src/pathfinder/yapf/yapf_river_builder.cpp index 8f98d5707e..f9c34cc7ba 100644 --- a/src/pathfinder/yapf/yapf_river_builder.cpp +++ b/src/pathfinder/yapf/yapf_river_builder.cpp @@ -60,7 +60,7 @@ public: this->end_tile = end_tile; Node &node = Yapf().CreateNewNode(); - node.Set(nullptr, start_tile, INVALID_TRACKDIR, false); + node.Set(nullptr, start_tile, Trackdir::Invalid, false); Yapf().AddStartupNode(node); } @@ -92,7 +92,7 @@ public: const TileIndex t = old_node.GetTile() + TileOffsByDiagDir(d); if (IsValidTile(t) && RiverFlowsDown(old_node.GetTile(), t)) { Node &node = Yapf().CreateNewNode(); - node.Set(&old_node, t, INVALID_TRACKDIR, true); + node.Set(&old_node, t, Trackdir::Invalid, true); Yapf().AddNewNode(node, RiverBuilderFollower{}); } } diff --git a/src/pathfinder/yapf/yapf_road.cpp b/src/pathfinder/yapf/yapf_road.cpp index e361252682..efba10af20 100644 --- a/src/pathfinder/yapf/yapf_road.cpp +++ b/src/pathfinder/yapf/yapf_road.cpp @@ -145,9 +145,9 @@ public: if (!follower_local.Follow(tile, trackdir)) break; /* if there are more trackdirs available & reachable, we are at the end of segment */ - if (KillFirstBit(follower_local.new_td_bits) != TRACKDIR_BIT_NONE) break; + if (follower_local.new_td_bits.Count() > 1) break; - Trackdir new_td = (Trackdir)FindFirstBit(follower_local.new_td_bits); + Trackdir new_td = follower_local.new_td_bits.GetNthSetBit(0).value(); /* stop if RV is on simple loop with no junctions */ if (follower_local.new_tile == n.key.tile && new_td == n.key.td) return false; @@ -284,7 +284,7 @@ public: (this->non_artic || IsDriveThroughStopTile(tile)); } - return tile == this->dest_tile && HasTrackdir(this->dest_trackdirs, td); + return tile == this->dest_tile && this->dest_trackdirs.Test(td); } /** @copydoc CYapfBaseT::PfCalcEstimateFunc */ @@ -365,8 +365,8 @@ public: /* find the best path */ path_found = Yapf().FindPath(v); - /* if path not found - return INVALID_TRACKDIR */ - Trackdir next_trackdir = INVALID_TRACKDIR; + /* if path not found - return Trackdir::Invalid */ + Trackdir next_trackdir = Trackdir::Invalid; Node *node = Yapf().GetBestNode(); if (node != nullptr) { uint steps = 0; @@ -459,7 +459,7 @@ Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDi { Trackdir td_ret = CYapfRoad::stChooseRoadTrack(v, tile, enterdir, path_found, path_cache); - return (td_ret != INVALID_TRACKDIR) ? td_ret : (Trackdir)FindFirstBit(trackdirs); + return (td_ret != Trackdir::Invalid) ? td_ret : trackdirs.GetNthSetBit(0).value(); } FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_distance) @@ -467,7 +467,7 @@ FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_dist TileIndex tile = v->tile; Trackdir trackdir = v->GetVehicleTrackdir(); - if (!HasTrackdir(GetTrackdirBitsForRoad(tile, GetRoadTramType(v->roadtype)), trackdir)) { + if (!GetTrackdirBitsForRoad(tile, GetRoadTramType(v->roadtype)).Test(trackdir)) { return FindDepotData(); } diff --git a/src/pathfinder/yapf/yapf_ship.cpp b/src/pathfinder/yapf/yapf_ship.cpp index 3e15f099d8..0f466cb591 100644 --- a/src/pathfinder/yapf/yapf_ship.cpp +++ b/src/pathfinder/yapf/yapf_ship.cpp @@ -86,7 +86,7 @@ public: if (this->dest_station != StationID::Invalid()) return IsDockingTile(tile) && IsShipDestinationTile(tile, this->dest_station); - return tile == this->dest_tile && ((this->dest_trackdirs & TrackdirToTrackdirBits(td)) != TRACKDIR_BIT_NONE); + return tile == this->dest_tile && this->dest_trackdirs.Any(TrackdirToTrackdirBits(td)); } /** @copydoc CYapfBaseT::PfCalcEstimateFunc */ @@ -159,9 +159,7 @@ public: */ static Trackdir GetRandomTrackdir(TrackdirBits trackdirs) { - const int strip_amount = RandomRange(CountBits(trackdirs)); - for (int s = 0; s < strip_amount; ++s) RemoveFirstTrackdir(&trackdirs); - return FindFirstTrackdir(trackdirs); + return trackdirs.GetNthSetBit(RandomRange(trackdirs.Count())).value_or(Trackdir::Invalid); } /** @@ -176,11 +174,11 @@ public: TrackFollower follower{v}; if (follower.Follow(tile, dir)) { TrackdirBits dirs = follower.new_td_bits; - const TrackdirBits dirs_without_90_degree = dirs & ~TrackdirCrossesTrackdirs(dir); - if (dirs_without_90_degree != TRACKDIR_BIT_NONE) dirs = dirs_without_90_degree; + const TrackdirBits dirs_without_90_degree = dirs.Reset(TrackdirCrossesTrackdirs(dir)); + if (dirs_without_90_degree.Any()) dirs = dirs_without_90_degree; return { follower.new_tile, GetRandomTrackdir(dirs) }; } - return { follower.new_tile, INVALID_TRACKDIR }; + return { follower.new_tile, Trackdir::Invalid }; } /** @@ -188,18 +186,18 @@ public: * @param v The ship to create the path for. * @param[in,out] path_cache Cache of the path for the ship. * @param path_length The length of the random path to create. - * @return The next track direction to take, or \c INVALID_TRACKDIR when there is no option. + * @return The next track direction to take, or \c Trackdir::Invalid when there is no option. */ static Trackdir CreateRandomPath(const Ship *v, ShipPathCache &path_cache, int path_length) { std::pair tile_dir = { v->tile, v->GetVehicleTrackdir()}; for (int i = 0; i < path_length; ++i) { tile_dir = GetRandomFollowUpTileTrackdir(v, tile_dir.first, tile_dir.second); - if (tile_dir.second == INVALID_TRACKDIR) break; + if (tile_dir.second == Trackdir::Invalid) break; path_cache.push_back(tile_dir.second); } - if (path_cache.empty()) return INVALID_TRACKDIR; + if (path_cache.empty()) return Trackdir::Invalid; /* Reverse the path so we can take from the end. */ std::reverse(std::begin(path_cache), std::end(path_cache)); @@ -266,11 +264,11 @@ public: } assert(node->GetTile() == v->tile); - /* Return INVALID_TRACKDIR to trigger a ship reversal if that is the best option. */ + /* Return Trackdir::Invalid to trigger a ship reversal if that is the best option. */ best_origin_dir = node->GetTrackdir(); - if ((TrackdirToTrackdirBits(best_origin_dir) & forward_dirs) == TRACKDIR_BIT_NONE) { + if (TrackdirToTrackdirBits(best_origin_dir).Any(forward_dirs)) { path_cache.clear(); - return INVALID_TRACKDIR; + return Trackdir::Invalid; } /* A empty path means we are already at the destination. The pathfinder shouldn't have been called at all. @@ -301,7 +299,7 @@ public: { bool path_found = false; ShipPathCache dummy_cache; - Trackdir best_origin_dir = INVALID_TRACKDIR; + Trackdir best_origin_dir = Trackdir::Invalid; if (trackdir == nullptr) { /* The normal case, typically called when ships leave a dock. */ @@ -314,8 +312,8 @@ public: /* This gets called when a ship suddenly can't move forward, e.g. due to terraforming. */ const DiagDirection entry = ReverseDiagDir(VehicleExitDir(v->direction, v->state)); const TrackdirBits reverse_dirs = DiagdirReachesTrackdirs(entry) & GetTileTrackStatus(v->tile, TRANSPORT_WATER, RoadTramType::Invalid, entry).trackdirs; - (void)ChooseShipTrack(v, v->tile, TRACKDIR_BIT_NONE, reverse_dirs, path_found, dummy_cache, best_origin_dir); - *trackdir = path_found && best_origin_dir != INVALID_TRACKDIR ? best_origin_dir : GetRandomTrackdir(reverse_dirs); + (void)ChooseShipTrack(v, v->tile, {}, reverse_dirs, path_found, dummy_cache, best_origin_dir); + *trackdir = path_found && best_origin_dir != Trackdir::Invalid ? best_origin_dir : GetRandomTrackdir(reverse_dirs); return true; } } @@ -342,7 +340,7 @@ public: assert(IsValidTrackdir(td1)); assert(IsValidTrackdir(td2)); - if (HasTrackdir(TrackdirCrossesTrackdirs(td1), td2)) { + if (TrackdirCrossesTrackdirs(td1).Test(td2)) { /* 90-deg curve penalty. */ return Yapf().PfGetSettings().ship_curve90_penalty; } else if (td2 != NextTrackdir(td1)) { @@ -362,11 +360,11 @@ public: { const bool odd_x = TileX(tile) & 1; const bool odd_y = TileY(tile) & 1; - if (td == TRACKDIR_X_NE) return odd_y; - if (td == TRACKDIR_X_SW) return !odd_y; - if (td == TRACKDIR_Y_NW) return odd_x; - if (td == TRACKDIR_Y_SE) return !odd_x; - return (odd_x ^ odd_y) ^ HasBit(TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_LOWER_E, td); + if (td == Trackdir::X_NE) return odd_y; + if (td == Trackdir::X_SW) return !odd_y; + if (td == Trackdir::Y_NW) return odd_x; + if (td == Trackdir::Y_SE) return !odd_x; + return (odd_x ^ odd_y) ^ TrackdirBits{Trackdir::Right_N, Trackdir::Left_S, Trackdir::Upper_W, Trackdir::Lower_E}.Test(td); } /** @copydoc CYapfBaseT::PfCalcCostFunc */ @@ -437,10 +435,10 @@ struct CYapfShip : CYapfT> { Track YapfShipChooseTrack(const Ship *v, TileIndex tile, bool &path_found, ShipPathCache &path_cache) { - Trackdir best_origin_dir = INVALID_TRACKDIR; + Trackdir best_origin_dir = Trackdir::Invalid; const TrackdirBits origin_dirs = TrackdirToTrackdirBits(v->GetVehicleTrackdir()); - const Trackdir td_ret = CYapfShip::ChooseShipTrack(v, tile, origin_dirs, TRACKDIR_BIT_NONE, path_found, path_cache, best_origin_dir); - return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : Track::Invalid; + const Trackdir td_ret = CYapfShip::ChooseShipTrack(v, tile, origin_dirs, {}, path_found, path_cache, best_origin_dir); + return (td_ret != Trackdir::Invalid) ? TrackdirToTrack(td_ret) : Track::Invalid; } bool YapfShipCheckReverse(const Ship *v, Trackdir *trackdir) diff --git a/src/pbs.cpp b/src/pbs.cpp index 00b043b2db..74aeb0c388 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -213,7 +213,7 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra TrackdirBits reserved = ft.new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.new_tile)); /* No reservation --> path end found */ - if (reserved == TRACKDIR_BIT_NONE) { + if (reserved.None()) { if (ft.is_station) { /* Check skipped station tiles as well, maybe our reservation ends inside the station. */ TileIndexDiff diff = TileOffsByDiagDir(ft.exitdir); @@ -410,10 +410,10 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo /* Check for reachable tracks. */ ft.new_td_bits &= DiagdirReachesTrackdirs(ft.exitdir); - if (Rail90DegTurnDisallowed(GetTileRailType(ft.old_tile), GetTileRailType(ft.new_tile), forbid_90deg)) ft.new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir); - if (ft.new_td_bits == TRACKDIR_BIT_NONE) return include_line_end; + if (Rail90DegTurnDisallowed(GetTileRailType(ft.old_tile), GetTileRailType(ft.new_tile), forbid_90deg)) ft.new_td_bits.Reset(TrackdirCrossesTrackdirs(trackdir)); + if (ft.new_td_bits.None()) return include_line_end; - if (ft.new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.new_td_bits) == TRACKDIR_BIT_NONE) { + if (ft.new_td_bits.Count() == 1) { Trackdir td = FindFirstTrackdir(ft.new_td_bits); /* PBS signal on next trackdir? Safe position. */ if (HasPbsSignalOnTrackdir(ft.new_tile, td)) return true; @@ -456,7 +456,7 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo /* Check for reachable tracks. */ ft.new_td_bits &= DiagdirReachesTrackdirs(ft.exitdir); - if (Rail90DegTurnDisallowed(GetTileRailType(ft.old_tile), GetTileRailType(ft.new_tile), forbid_90deg)) ft.new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir); + if (Rail90DegTurnDisallowed(GetTileRailType(ft.old_tile), GetTileRailType(ft.new_tile), forbid_90deg)) ft.new_td_bits.Reset(TrackdirCrossesTrackdirs(trackdir)); return !HasReservedTracks(ft.new_tile, TrackdirBitsToTrackBits(ft.new_td_bits)); } diff --git a/src/pbs.h b/src/pbs.h index 921267e27e..15e794b2c1 100644 --- a/src/pbs.h +++ b/src/pbs.h @@ -31,7 +31,7 @@ struct PBSTileInfo { /** * Create an empty PBSTileInfo. */ - PBSTileInfo() : tile(INVALID_TILE), trackdir(INVALID_TRACKDIR), okay(false) {} + PBSTileInfo() : tile(INVALID_TILE), trackdir(Trackdir::Invalid), okay(false) {} /** * Create a PBSTileInfo with given tile, track direction and safe waiting position information. diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 1244c91519..3faa4c087f 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -849,8 +849,8 @@ static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileInd (trdx >= 0 && dx < 0) || (trdy <= 0 && dy > 0) || (trdy >= 0 && dy < 0)) { - if (!HasBit(*trackdir, 3)) { // first direction is invalid, try the other - SetBit(*trackdir, 3); // reverse the direction + if (!HasBit(to_underlying(*trackdir), 3)) { // first direction is invalid, try the other + *trackdir = ReverseTrackdir(*trackdir); // reverse the direction trdx = -trdx; trdy = -trdy; } else { // other direction is invalid too, invalid drag @@ -1215,13 +1215,13 @@ static bool AdvanceSignalAutoFill(TileIndex &tile, Trackdir &trackdir, bool remo trackdirbits &= TrackdirReachesTrackdirs(trackdir); /* No track bits, must stop */ - if (trackdirbits == TRACKDIR_BIT_NONE) return false; + if (trackdirbits.None()) return false; /* Get the first track dir */ trackdir = RemoveFirstTrackdir(&trackdirbits); /* Any left? It's a junction so we stop */ - if (trackdirbits != TRACKDIR_BIT_NONE) return false; + if (trackdirbits.Any()) return false; switch (GetTileType(tile)) { case TileType::Railway: @@ -1319,7 +1319,7 @@ static CommandCost CmdSignalTrackHelper(DoCommandFlags flags, TileIndex tile, Ti int last_used_ctr = -signal_density; // to force signal at first tile int last_suitable_ctr = 0; TileIndex last_suitable_tile = INVALID_TILE; - Trackdir last_suitable_trackdir = INVALID_TRACKDIR; + Trackdir last_suitable_trackdir = Trackdir::Invalid; CommandCost last_error = CMD_ERROR; bool had_success = false; auto build_signal = [&](TileIndex tile, Trackdir trackdir, bool test_only) { @@ -2781,13 +2781,13 @@ static TrackStatus GetTileTrackStatus_Rail(TileIndex tile, TransportType mode, [ case TrackBits{Track::Left}.base(): tb = Track::Right; break; case TrackBits{Track::Right}.base(): tb = Track::Left; break; } - return {TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE}; + return {TrackBitsToTrackdirBits(tb), {}}; } if (mode != TRANSPORT_RAIL) return {}; TrackBits trackbits{}; - TrackdirBits red_signals = TRACKDIR_BIT_NONE; + TrackdirBits red_signals{}; switch (GetRailTileType(tile)) { default: NOT_REACHED(); @@ -2810,10 +2810,10 @@ static TrackStatus GetTileTrackStatus_Rail(TileIndex tile, TransportType mode, [ if (!IsOnewaySignal(tile, Track::Upper) || (a & SignalOnTrack(Track::Upper)) == 0) b |= ~a & SignalOnTrack(Track::Upper); if (!IsOnewaySignal(tile, Track::Lower) || (a & SignalOnTrack(Track::Lower)) == 0) b |= ~a & SignalOnTrack(Track::Lower); - if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E); - if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W); - if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E); - if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W); + if ((b & 0x8) == 0) red_signals.Set({Trackdir::Left_N, Trackdir::X_NE, Trackdir::Y_SE, Trackdir::Upper_E}); + if ((b & 0x4) == 0) red_signals.Set({Trackdir::Left_S, Trackdir::X_SW, Trackdir::Y_NW, Trackdir::Upper_W}); + if ((b & 0x2) == 0) red_signals.Set({Trackdir::Right_N, Trackdir::Lower_E}); + if ((b & 0x1) == 0) red_signals.Set({Trackdir::Right_S, Trackdir::Lower_W}); break; } diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 63f00897e1..0b67070bc6 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -2141,8 +2141,8 @@ static const TrackBits _road_trackbits[16] = { /** @copydoc GetTileTrackStatusProc */ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, RoadTramType sub_mode, DiagDirection side) { - TrackdirBits trackdirbits = TRACKDIR_BIT_NONE; - TrackdirBits red_signals = TRACKDIR_BIT_NONE; // crossing barred + TrackdirBits trackdirbits{}; + TrackdirBits red_signals{}; // crossing barred switch (mode) { case TRANSPORT_RAIL: if (IsLevelCrossing(tile)) trackdirbits = TrackBitsToTrackdirBits(GetCrossingRailTrack(tile)); @@ -2178,9 +2178,9 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, R if (IsLevelCrossingTile(t) && IsCrossingBarred(t)) red_signals &= mask; }; /* Check for blocked adjacent crossing to south, keep only southbound red signal trackdirs, allow northbound traffic */ - mask_red_signal_bits_if_crossing_barred(TileAddByDiagDir(tile, AxisToDiagDir(axis)), TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_SE); + mask_red_signal_bits_if_crossing_barred(TileAddByDiagDir(tile, AxisToDiagDir(axis)), {Trackdir::X_SW, Trackdir::Y_SE}); /* Check for blocked adjacent crossing to north, keep only northbound red signal trackdirs, allow southbound traffic */ - mask_red_signal_bits_if_crossing_barred(TileAddByDiagDir(tile, ReverseDiagDir(AxisToDiagDir(axis))), TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_NW); + mask_red_signal_bits_if_crossing_barred(TileAddByDiagDir(tile, ReverseDiagDir(AxisToDiagDir(axis))), {Trackdir::X_NE, Trackdir::Y_NW}); } break; } @@ -2286,7 +2286,7 @@ static void GetTileDesc_Road(TileIndex tile, TileDesc &td) * vehicle should be travelling in in order to enter the depot. */ static constexpr DiagDirectionIndexArray _roadveh_enter_depot_dir{ - TRACKDIR_X_SW, TRACKDIR_Y_NW, TRACKDIR_X_NE, TRACKDIR_Y_SE + Trackdir::X_SW, Trackdir::Y_NW, Trackdir::X_NE, Trackdir::Y_SE }; /** @copydoc VehicleEnterTileProc */ @@ -2298,7 +2298,7 @@ static VehicleEnterTileStates VehicleEnterTile_Road(Vehicle *v, TileIndex tile, RoadVehicle *rv = RoadVehicle::From(v); if (rv->frame == RVC_DEPOT_STOP_FRAME && - _roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == rv->state) { + _roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == static_cast(rv->state)) { rv->state = RVSB_IN_DEPOT; rv->vehstatus.Set(VehState::Hidden); rv->direction = ReverseDir(rv->direction); diff --git a/src/roadveh.h b/src/roadveh.h index 8b5216a890..1872213f50 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -47,9 +47,9 @@ enum RoadVehicleStates : uint8_t { /* Bit sets of the above specified bits */ RVSB_IN_ROAD_STOP = 1 << RVS_IN_ROAD_STOP, ///< The vehicle is in a road stop - RVSB_IN_ROAD_STOP_END = RVSB_IN_ROAD_STOP + TRACKDIR_END, + RVSB_IN_ROAD_STOP_END = RVSB_IN_ROAD_STOP + to_underlying(Trackdir::End), RVSB_IN_DT_ROAD_STOP = 1 << RVS_IN_DT_ROAD_STOP, ///< The vehicle is in a drive-through road stop - RVSB_IN_DT_ROAD_STOP_END = RVSB_IN_DT_ROAD_STOP + TRACKDIR_END, + RVSB_IN_DT_ROAD_STOP_END = RVSB_IN_DT_ROAD_STOP + to_underlying(Trackdir::End), RVSB_DRIVE_SIDE = 1 << RVS_DRIVE_SIDE, ///< The vehicle is at the opposite side of the road @@ -90,7 +90,7 @@ void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs /** Element of the RoadVehPathCache. */ struct RoadVehPathElement { - Trackdir trackdir = INVALID_TRACKDIR; ///< Trackdir for this element. + Trackdir trackdir = Trackdir::Invalid; ///< Trackdir for this element. TileIndex tile = INVALID_TILE; ///< Tile for this element. constexpr RoadVehPathElement() {} @@ -307,7 +307,7 @@ protected: // These functions should not be called outside acceleration code. /* Check if this vehicle is in the same direction as the road under. * We already know it has either GVF_GOINGUP_BIT or GVF_GOINGDOWN_BIT set. */ - if (rv->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir((Trackdir)rv->state)) { + if (rv->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir(static_cast(rv->state))) { /* If the first vehicle is reversing, this vehicle may be reversing too * (especially if this is the first, and maybe the only, vehicle).*/ return true; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 2d2cd99770..4d565425e1 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -74,7 +74,7 @@ bool IsValidImageIndex(uint8_t image_index) /** Track direction to use when reversing for each diagonal direction. */ static constexpr DiagDirectionIndexArray _road_reverse_table{ - TRACKDIR_RVREV_NE, TRACKDIR_RVREV_SE, TRACKDIR_RVREV_SW, TRACKDIR_RVREV_NW + Trackdir::RvRev_NE, Trackdir::RvRev_SE, Trackdir::RvRev_SW, Trackdir::RvRev_NW }; /** @@ -470,7 +470,7 @@ inline int RoadVehicle::GetCurrentMaxSpeed() const /* Limit speed to 50% while reversing, 75% in curves. */ for (const RoadVehicle *u = this; u != nullptr; u = u->Next()) { if (_settings_game.vehicle.roadveh_acceleration_model == AM_REALISTIC) { - if (this->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir((Trackdir)this->state)) { + if (this->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir(static_cast(this->state))) { max_speed = this->gcache.cached_max_track_speed / 2; break; } else if (!IsDiagonalDirection(u->direction)) { @@ -796,7 +796,7 @@ static bool CheckRoadBlockedForOvertaking(OvertakeData *od) TrackBits trackbits = TrackdirBitsToTrackBits(ts.trackdirs); /* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */ - if (!HasBit(ts.trackdirs, od->trackdir) || trackbits.Any({Track::Upper, Track::Lower, Track::Left, Track::Right}) || (ts.signals != TRACKDIR_BIT_NONE)) return true; + if (!ts.trackdirs.Test(od->trackdir) || trackbits.Any({Track::Upper, Track::Lower, Track::Left, Track::Right}) || ts.signals.Any()) return true; /* Are there more vehicles on the tile except the two vehicles involved in overtaking */ return HasVehicleOnTile(od->tile, [&](const Vehicle *v) { @@ -824,7 +824,7 @@ static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u) if (v->direction != u->direction || !IsDiagonalDirection(v->direction)) return; /* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */ - if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->state & RVSB_TRACKDIR_MASK))) return; + if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir(static_cast(v->state & RVSB_TRACKDIR_MASK))) return; /* Can't overtake a vehicle that is moving faster than us. If the vehicle in front is * accelerating, take the maximum speed for the comparison, else the current speed. @@ -868,18 +868,9 @@ static void RoadZPosAffectSpeed(RoadVehicle *v, int old_z) } } -static int PickRandomBit(uint bits) -{ - uint i; - uint num = RandomRange(CountBits(bits)); - - for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {} - return i; -} - /** * Returns direction to for a road vehicle to take or - * INVALID_TRACKDIR if the direction is currently blocked + * Trackdir::Invalid if the direction is currently blocked * @param v the Vehicle to do the pathfinding for * @param tile the where to start the pathfinding * @param enterdir the direction the vehicle enters the tile from @@ -891,36 +882,36 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype)); - /* Replaces the given trackdir with INVALID_TRACKDIR when there is red signal for that trackdir. */ + /* Replaces the given trackdir with Trackdir::Invalid when there is red signal for that trackdir. */ auto FilterRedSignal = [&ts](Trackdir trackdir) { - if (HasBit(ts.signals, trackdir)) return INVALID_TRACKDIR; + if (ts.signals.Test(trackdir)) return Trackdir::Invalid; return trackdir; }; if (IsTileType(tile, TileType::Road)) { if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir)) { /* Road depot owned by another company or with the wrong orientation */ - ts.trackdirs = TRACKDIR_BIT_NONE; + ts.trackdirs.Reset(); } } else if (IsTileType(tile, TileType::Station) && IsBayRoadStopTile(tile)) { /* Standard road stop (drive-through stops are treated as normal road) */ if (!IsTileOwner(tile, v->owner) || GetBayRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) { /* different station owner or wrong orientation or the vehicle has articulated parts */ - ts.trackdirs = TRACKDIR_BIT_NONE; + ts.trackdirs.Reset(); } else { /* Our station */ RoadStopType rstype = v->IsBus() ? RoadStopType::Bus : RoadStopType::Truck; if (GetRoadStopType(tile) != rstype) { /* Wrong station type */ - ts.trackdirs = TRACKDIR_BIT_NONE; + ts.trackdirs.Reset(); } else { /* Proper station type, check if there is free loading bay */ if (!_settings_game.pf.roadveh_queue && IsBayRoadStopTile(tile) && !RoadStop::GetByTile(tile, rstype)->HasFreeBay()) { /* Station is full and RV queuing is off */ - ts.trackdirs = TRACKDIR_BIT_NONE; + ts.trackdirs.Reset(); } } } @@ -932,7 +923,7 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection /* Remove tracks unreachable from the enter dir */ ts.trackdirs &= DiagdirReachesTrackdirs(enterdir); - if (ts.trackdirs == TRACKDIR_BIT_NONE) { + if (ts.trackdirs.None()) { /* If vehicle expected a path, it no longer exists, so invalidate it. */ if (!v->path.empty()) v->path.clear(); /* No reachable tracks, so we'll reverse */ @@ -959,16 +950,16 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection if (v->dest_tile == INVALID_TILE) { /* We've got no destination, pick a random track */ - return FilterRedSignal(static_cast(PickRandomBit(ts.trackdirs))); + return FilterRedSignal(ts.trackdirs.GetNthSetBit(RandomRange(ts.trackdirs.Count())).value()); } /* Only one track to choose between? */ - if (KillFirstBit(ts.trackdirs) == TRACKDIR_BIT_NONE) { + if (ts.trackdirs.Count() == 1) { if (!v->path.empty() && v->path.back().tile == tile) { /* Vehicle expected a choice here, invalidate its path. */ v->path.clear(); } - return FilterRedSignal(static_cast(FindFirstBit(ts.trackdirs))); + return FilterRedSignal(ts.trackdirs.GetNthSetBit(0).value()); } /* Attempt to follow cached path. */ @@ -979,7 +970,7 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection } else { Trackdir trackdir = v->path.back().trackdir; - if (HasBit(ts.trackdirs, trackdir)) { + if (ts.trackdirs.Test(trackdir)) { v->path.pop_back(); return FilterRedSignal(trackdir); } @@ -1013,7 +1004,7 @@ bool RoadVehLeaveDepot(RoadVehicle *v, bool first) v->direction = DiagDirToDir(dir); Trackdir tdir = DiagDirToDiagTrackdir(dir); - const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE) + tdir]; + const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE) + to_underlying(tdir)]; int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF); int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF); @@ -1037,7 +1028,7 @@ bool RoadVehLeaveDepot(RoadVehicle *v, bool first) } v->vehstatus.Reset(VehState::Hidden); - v->state = tdir; + v->state = to_underlying(tdir); v->frame = RVC_DEPOT_START_FRAME; v->x_pos = x; @@ -1070,10 +1061,10 @@ static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicl diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile)); } - if (diag_dir == DiagDirection::Invalid) return INVALID_TRACKDIR; + if (diag_dir == DiagDirection::Invalid) return Trackdir::Invalid; dir = DiagDirToDiagTrackdir(diag_dir); } else { - if (already_reversed && (prev->tile != tile || (prev_state < TRACKDIR_END && IsReversingRoadTrackdir(static_cast(prev_state))))) { + if (already_reversed && (prev->tile != tile || (static_cast(prev_state) < Trackdir::End && IsReversingRoadTrackdir(static_cast(prev_state))))) { /* * The vehicle has reversed, but did not go straight back. * It immediately turn onto another tile. This means that @@ -1093,18 +1084,18 @@ static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicl if (prev->tile != tile) { north = prev->tile < tile; } else { - north = (prev_state == TRACKDIR_RVREV_NW || prev_state == TRACKDIR_RVREV_NE); + north = static_cast(prev_state) == Trackdir::RvRev_NW || static_cast(prev_state) == Trackdir::RvRev_NE; } static const DiagDirectionIndexArray reversed_turn_lookup[2] = { - { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N, TRACKDIR_UPPER_E }, - { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S }}; + { Trackdir::Upper_W, Trackdir::Right_N, Trackdir::Left_N, Trackdir::Upper_E }, + { Trackdir::Right_S, Trackdir::Lower_W, Trackdir::Lower_E, Trackdir::Left_S }}; dir = reversed_turn_lookup[north ? 0 : 1][ReverseDiagDir(entry_dir)]; } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) { - dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK); - } else if (prev_state < TRACKDIR_END) { - dir = (Trackdir)prev_state; + dir = static_cast(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK); + } else if (static_cast(prev_state) < Trackdir::End) { + dir = static_cast(prev_state); } else { - return INVALID_TRACKDIR; + return Trackdir::Invalid; } } @@ -1119,10 +1110,10 @@ static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicl ROAD_X, ROAD_Y, }; - RoadBits required = required_roadbits[dir & 0x07]; + RoadBits required = required_roadbits[to_underlying(dir) & 0x07]; if (!required.Any(GetAnyRoadBits(tile, GetRoadTramType(v->roadtype), true))) { - dir = INVALID_TRACKDIR; + dir = Trackdir::Invalid; } return dir; @@ -1153,7 +1144,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev) /* If overtaking just aborts at a random moment, we can have a out-of-bound problem, * if the vehicle started a corner. To protect that, only allow an abort of * overtake if we are on straight roads */ - if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) { + if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir(static_cast(v->state))) { v->overtaking = 0; } } @@ -1215,7 +1206,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev) dir = FollowPreviousRoadVehicle(v, prev, tile, diagdir, false); } - if (dir == INVALID_TRACKDIR) { + if (dir == Trackdir::Invalid) { if (!v->IsFrontEngine()) FatalError("Disconnecting road vehicle."); v->cur_speed = 0; return false; @@ -1234,10 +1225,10 @@ again: RoadBit needed; switch (dir) { default: NOT_REACHED(); - case TRACKDIR_RVREV_NE: needed = RoadBit::SW; break; - case TRACKDIR_RVREV_SE: needed = RoadBit::NW; break; - case TRACKDIR_RVREV_SW: needed = RoadBit::NE; break; - case TRACKDIR_RVREV_NW: needed = RoadBit::SE; break; + case Trackdir::RvRev_NE: needed = RoadBit::SW; break; + case Trackdir::RvRev_SE: needed = RoadBit::NW; break; + case Trackdir::RvRev_SW: needed = RoadBit::NE; break; + case Trackdir::RvRev_NW: needed = RoadBit::SE; break; } if ((v->Previous() != nullptr && v->Previous()->tile == tile) || (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) && @@ -1281,7 +1272,7 @@ again: } /* Get position data for first frame on the new tile */ - const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(dir + (to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE)) ^ v->overtaking]; + const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(to_underlying(dir) + (to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE)) ^ v->overtaking]; int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x; int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y; @@ -1327,7 +1318,7 @@ again: RoadStop::IsDriveThroughRoadStopContinuation(v->tile, tile) && v->tile != tile) { /* So, keep 'our' state */ - dir = (Trackdir)v->state; + dir = static_cast(v->state); } else if (IsStationRoadStop(v->tile)) { /* We're not continuing our drive through road stop, so leave. */ RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v); @@ -1377,10 +1368,10 @@ again: turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM; switch (static_cast(rd.x & 0x3)) { default: NOT_REACHED(); - case DiagDirection::NW: dir = TRACKDIR_RVREV_SE; break; - case DiagDirection::NE: dir = TRACKDIR_RVREV_SW; break; - case DiagDirection::SE: dir = TRACKDIR_RVREV_NW; break; - case DiagDirection::SW: dir = TRACKDIR_RVREV_NE; break; + case DiagDirection::NW: dir = Trackdir::RvRev_SE; break; + case DiagDirection::NE: dir = Trackdir::RvRev_SW; break; + case DiagDirection::SE: dir = Trackdir::RvRev_NW; break; + case DiagDirection::SW: dir = Trackdir::RvRev_NE; break; } } else { if (v->IsFrontEngine()) { @@ -1391,12 +1382,12 @@ again: } } - if (dir == INVALID_TRACKDIR) { + if (dir == Trackdir::Invalid) { v->cur_speed = 0; return false; } - const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE) + dir]; + const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(to_underlying(_settings_game.vehicle.road_side) << RVS_DRIVE_SIDE) + to_underlying(dir)]; int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x; int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y; @@ -1418,7 +1409,7 @@ again: return false; } - v->state = dir; + v->state = to_underlying(dir); v->frame = turn_around_start_frame; if (new_dir != v->direction) { @@ -1750,7 +1741,7 @@ void RoadVehicle::OnNewEconomyDay() Trackdir RoadVehicle::GetVehicleTrackdir() const { - if (this->vehstatus.Test(VehState::Crashed)) return INVALID_TRACKDIR; + if (this->vehstatus.Test(VehState::Crashed)) return Trackdir::Invalid; if (this->IsInDepot()) { /* We'll assume the road vehicle is facing outwards */ @@ -1767,7 +1758,7 @@ Trackdir RoadVehicle::GetVehicleTrackdir() const /* If vehicle's state is a valid track direction (vehicle is not turning around) return it, * otherwise transform it into a valid track direction */ - return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state); + return static_cast(IsReversingRoadTrackdir(static_cast(this->state)) ? (this->state - 6) : this->state); } uint16_t RoadVehicle::GetMaxWeight() const diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 21daf3dede..1cd4d6506b 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -438,8 +438,8 @@ static void FixOwnerOfRailTrack(Tile t) /* try to find any connected rail */ for (DiagDirection dd = DiagDirection::Begin; dd < DiagDirection::End; dd++) { TileIndex tt{t + TileOffsByDiagDir(dd)}; - if (GetTileTrackStatus(t, TRANSPORT_RAIL, RoadTramType::Invalid, dd).trackdirs != TRACKDIR_BIT_NONE && - GetTileTrackStatus(tt, TRANSPORT_RAIL, RoadTramType::Invalid, ReverseDiagDir(dd)).trackdirs != TRACKDIR_BIT_NONE && + if (GetTileTrackStatus(t, TRANSPORT_RAIL, RoadTramType::Invalid, dd).trackdirs.Any() && + GetTileTrackStatus(tt, TRANSPORT_RAIL, RoadTramType::Invalid, ReverseDiagDir(dd)).trackdirs.Any() && Company::IsValidID(GetTileOwner(tt))) { SetTileOwner(t, GetTileOwner(tt)); return; @@ -2681,7 +2681,7 @@ bool AfterLoadGame() switch (v->type) { case VehicleType::Train: Train::From(v)->track = DiagDirToDiagTrack(vdir); break; - case VehicleType::Road: RoadVehicle::From(v)->state = DiagDirToDiagTrackdir(vdir); RoadVehicle::From(v)->frame = frame; break; + case VehicleType::Road: RoadVehicle::From(v)->state = to_underlying(DiagDirToDiagTrackdir(vdir)); RoadVehicle::From(v)->frame = frame; break; default: NOT_REACHED(); } } diff --git a/src/script/api/script_rail.cpp b/src/script/api/script_rail.cpp index 532f604d4a..e9b666ecf3 100644 --- a/src/script/api/script_rail.cpp +++ b/src/script/api/script_rail.cpp @@ -402,11 +402,11 @@ static const int NUM_TRACK_DIRECTIONS = 3; ///< The number of directions you can * 2 it added. */ static const ScriptRailSignalData _possible_trackdirs[5][NUM_TRACK_DIRECTIONS] = { - {{Track::Upper, TRACKDIR_UPPER_E, 0}, {Track::Y, TRACKDIR_Y_SE, 0}, {Track::Left, TRACKDIR_LEFT_S, 1}}, - {{Track::Right, TRACKDIR_RIGHT_S, 1}, {Track::X, TRACKDIR_X_SW, 1}, {Track::Upper, TRACKDIR_UPPER_W, 1}}, - {{Track::Invalid, INVALID_TRACKDIR, 0}, {Track::Invalid, INVALID_TRACKDIR, 0}, {Track::Invalid, INVALID_TRACKDIR, 0}}, - {{Track::Lower, TRACKDIR_LOWER_E, 0}, {Track::X, TRACKDIR_X_NE, 0}, {Track::Left, TRACKDIR_LEFT_N, 0}}, - {{Track::Right, TRACKDIR_RIGHT_N, 0}, {Track::Y, TRACKDIR_Y_NW, 1}, {Track::Lower, TRACKDIR_LOWER_W, 1}} + {{Track::Upper, Trackdir::Upper_E, 0}, {Track::Y, Trackdir::Y_SE, 0}, {Track::Left, Trackdir::Left_S, 1}}, + {{Track::Right, Trackdir::Right_S, 1}, {Track::X, Trackdir::X_SW, 1}, {Track::Upper, Trackdir::Upper_W, 1}}, + {{Track::Invalid, Trackdir::Invalid, 0}, {Track::Invalid, Trackdir::Invalid, 0}, {Track::Invalid, Trackdir::Invalid, 0}}, + {{Track::Lower, Trackdir::Lower_E, 0}, {Track::X, Trackdir::X_NE, 0}, {Track::Left, Trackdir::Left_N, 0}}, + {{Track::Right, Trackdir::Right_N, 0}, {Track::Y, Trackdir::Y_NW, 1}, {Track::Lower, Trackdir::Lower_W, 1}} }; /* static */ ScriptRail::SignalType ScriptRail::GetSignalType(TileIndex tile, TileIndex front) diff --git a/src/script/api/script_tile.cpp b/src/script/api/script_tile.cpp index b66a790caf..d348dea1a0 100644 --- a/src/script/api/script_tile.cpp +++ b/src/script/api/script_tile.cpp @@ -219,10 +219,10 @@ if (!::IsValidTile(tile)) return false; if (transport_type == TRANSPORT_ROAD) { - return ::GetTileTrackStatus(tile, (::TransportType)transport_type, ::RoadTramType::Road).trackdirs != TRACKDIR_BIT_NONE || - ::GetTileTrackStatus(tile, (::TransportType)transport_type, ::RoadTramType::Tram).trackdirs != TRACKDIR_BIT_NONE; + return ::GetTileTrackStatus(tile, (::TransportType)transport_type, ::RoadTramType::Road).trackdirs.Any() || + ::GetTileTrackStatus(tile, (::TransportType)transport_type, ::RoadTramType::Tram).trackdirs.Any(); } else { - return ::GetTileTrackStatus(tile, (::TransportType)transport_type, ::RoadTramType::Invalid).trackdirs != TRACKDIR_BIT_NONE; + return ::GetTileTrackStatus(tile, (::TransportType)transport_type, ::RoadTramType::Invalid).trackdirs.Any(); } } diff --git a/src/ship.h b/src/ship.h index b08b4a144e..b68f2d4d3a 100644 --- a/src/ship.h +++ b/src/ship.h @@ -18,7 +18,7 @@ WaterClass GetEffectiveWaterClass(TileIndex tile); /** Element of the ShipPathCache. */ struct ShipPathElement { - Trackdir trackdir = INVALID_TRACKDIR; ///< Trackdir for this element. + Trackdir trackdir = Trackdir::Invalid; ///< Trackdir for this element. constexpr ShipPathElement() {} constexpr ShipPathElement(Trackdir trackdir) : trackdir(trackdir) {} diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 72507cf47e..81fd2a15df 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -287,7 +287,7 @@ void Ship::OnNewEconomyDay() Trackdir Ship::GetVehicleTrackdir() const { - if (this->vehstatus.Test(VehState::Crashed)) return INVALID_TRACKDIR; + if (this->vehstatus.Test(VehState::Crashed)) return Trackdir::Invalid; if (this->IsInDepot()) { /* We'll assume the ship is facing outwards */ @@ -387,7 +387,7 @@ static bool CheckShipStayInDepot(Ship *v) return u->type == VehicleType::Ship && u->cur_speed != 0; })) return true; - assert(v->GetVehicleTrackdir() == TRACKDIR_X_NE || v->GetVehicleTrackdir() == TRACKDIR_Y_NW); + assert(v->GetVehicleTrackdir() == Trackdir::X_NE || v->GetVehicleTrackdir() == Trackdir::Y_NW); v->direction = DiagDirToDir(TrackdirToExitdir(v->GetVehicleTrackdir())); if (CheckReverseShip(v)) v->direction = ReverseDir(v->direction); @@ -716,9 +716,9 @@ static void ShipController(Ship *v) assert(diagdir != DiagDirection::Invalid); const TrackBits tracks = GetAvailShipTracks(gp.new_tile, diagdir); if (tracks.None()) { - Trackdir trackdir = INVALID_TRACKDIR; + Trackdir trackdir = Trackdir::Invalid; CheckReverseShip(v, &trackdir); - if (trackdir == INVALID_TRACKDIR) return ReverseShip(v); + if (trackdir == Trackdir::Invalid) return ReverseShip(v); return ReverseShipIntoTrackdir(v, trackdir); } diff --git a/src/signal.cpp b/src/signal.cpp index 9f6779eb87..e3c73dab20 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -39,12 +39,12 @@ static constexpr DiagDirectionIndexArray _enterdir_to_trackbits{ }; /** Accessible TrackdirBits from a given enter direction. */ -static constexpr DiagDirectionIndexArray _enterdir_to_trackdirbits{ - TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S, - TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_RIGHT_N, - TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N, - TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LEFT_S -}; +static constexpr DiagDirectionIndexArray _enterdir_to_trackdirbits{{{ + {Trackdir::X_SW, Trackdir::Upper_W, Trackdir::Right_S}, + {Trackdir::Y_NW, Trackdir::Lower_W, Trackdir::Right_N}, + {Trackdir::X_NE, Trackdir::Lower_E, Trackdir::Left_N}, + {Trackdir::Y_SE, Trackdir::Upper_E, Trackdir::Left_S}, +}}}; /** * Set containing 'items' items of 'tile and Tdir' @@ -320,7 +320,7 @@ static SigFlags ExploreSegment(Owner owner) Track track = TrackBitsToTrack(tracks_masked); // mask TRACK_BIT_X and Y too if (HasSignalOnTrack(tile, track)) { // now check whole track, not trackdir SignalType sig = GetSignalType(tile, track); - Trackdir trackdir = static_cast(FindFirstBit(TrackBitsToTrackdirBits(tracks) & _enterdir_to_trackdirbits[enterdir])); + Trackdir trackdir = (TrackBitsToTrackdirBits(tracks) & _enterdir_to_trackdirbits[enterdir]).GetNthSetBit(0).value(); Trackdir reversedir = ReverseTrackdir(trackdir); /* add (tile, reversetrackdir) to 'to-be-updated' set when there is * ANY conventional signal in REVERSE direction @@ -417,7 +417,7 @@ static SigFlags ExploreSegment(Owner owner) static void UpdateSignalsAroundSegment(SigFlags flags) { TileIndex tile = INVALID_TILE; // Stop GCC from complaining about a possibly uninitialized variable (issue #8280). - Trackdir trackdir = INVALID_TRACKDIR; + Trackdir trackdir = Trackdir::Invalid; while (_tbuset.Get(&tile, &trackdir)) { assert(HasSignalOnTrackdir(tile, trackdir)); diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index dfc7a3259a..7fdfc6d198 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3731,7 +3731,7 @@ static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode break; } - return {TrackBitsToTrackdirBits(trackbits), TRACKDIR_BIT_NONE}; + return {TrackBitsToTrackdirBits(trackbits), {}}; } @@ -3881,7 +3881,7 @@ static VehicleEnterTileStates VehicleEnterTile_Station(Vehicle *v, TileIndex til } } else if (v->type == VehicleType::Road) { RoadVehicle *rv = RoadVehicle::From(v); - if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) { + if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir(static_cast(rv->state)) && rv->frame == 0) { if (IsStationRoadStop(tile) && rv->IsFrontEngine()) { /* Attempt to allocate a parking bay in a road stop */ if (RoadStop::GetByTile(tile, GetRoadStopType(tile))->Enter(rv)) return {}; diff --git a/src/table/track_data.h b/src/table/track_data.h index f915dfe5e0..091088546e 100644 --- a/src/table/track_data.h +++ b/src/table/track_data.h @@ -11,28 +11,28 @@ * Maps a diagonal direction to the all trackdirs that are connected to any * track entering in this direction (including those making 90 degree turns). */ -extern const DiagDirectionIndexArray _exitdir_reaches_trackdirs{ - TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N, // DiagDirection::NE - TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_E, // DiagDirection::SE - TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S, // DiagDirection::SW - TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W // DiagDirection::NW -}; +extern const DiagDirectionIndexArray _exitdir_reaches_trackdirs{{{ + {Trackdir::X_NE, Trackdir::Lower_E, Trackdir::Left_N}, // DiagDirection::NE + {Trackdir::Y_SE, Trackdir::Left_S, Trackdir::Upper_E}, // DiagDirection::SE + {Trackdir::X_SW, Trackdir::Upper_W, Trackdir::Right_S}, // DiagDirection::SW + {Trackdir::Y_NW, Trackdir::Right_N, Trackdir::Lower_W}, // DiagDirection::NW +}}}; /** Next trackdir to use when moving to a new tile for each current trackdir. */ extern const TrackdirIndexArray _next_trackdir{ - TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_LOWER_E, TRACKDIR_UPPER_E, TRACKDIR_RIGHT_S, TRACKDIR_LEFT_S, INVALID_TRACKDIR, INVALID_TRACKDIR, - TRACKDIR_X_SW, TRACKDIR_Y_NW, TRACKDIR_LOWER_W, TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N + Trackdir::X_NE, Trackdir::Y_SE, Trackdir::Lower_E, Trackdir::Upper_E, Trackdir::Right_S, Trackdir::Left_S, Trackdir::Invalid, Trackdir::Invalid, + Trackdir::X_SW, Trackdir::Y_NW, Trackdir::Lower_W, Trackdir::Upper_W, Trackdir::Right_N, Trackdir::Left_N }; /** Maps a trackdir to all trackdirs that make 90 deg turns with it. */ -extern const TrackIndexArray _track_crosses_trackdirs{ - TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_Y_NW, // TRACK_X - TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW, // TRACK_Y - TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_LEFT_S, // TRACK_UPPER - TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_LEFT_S, // TRACK_LOWER - TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LOWER_E, // TRACK_LEFT - TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LOWER_E // TRACK_RIGHT -}; +extern const TrackIndexArray _track_crosses_trackdirs{{{ + {Trackdir::Y_SE, Trackdir::Y_NW}, // TRACK_X + {Trackdir::X_NE, Trackdir::X_SW}, // TRACK_Y + {Trackdir::Right_N, Trackdir::Right_S, Trackdir::Left_N, Trackdir::Left_S}, // TRACK_UPPER + {Trackdir::Right_N, Trackdir::Right_S, Trackdir::Left_N, Trackdir::Left_S}, // TRACK_LOWER + {Trackdir::Upper_W, Trackdir::Upper_E, Trackdir::Lower_W, Trackdir::Lower_E}, // TRACK_LEFT + {Trackdir::Upper_W, Trackdir::Upper_E, Trackdir::Lower_W, Trackdir::Lower_E}, // TRACK_RIGHT +}}}; /** Maps a track to all tracks that make 90 deg turns with it. */ extern const TrackIndexArray _track_crosses_tracks{ @@ -52,37 +52,37 @@ extern const TrackdirIndexArray _trackdir_to_exitdir{ /** Maps a track and an (4-way) dir to the trackdir that represents the track with the exit in the given direction. */ extern const TrackIndexArray> _track_exitdir_to_trackdir{{{ - {TRACKDIR_X_NE, INVALID_TRACKDIR, TRACKDIR_X_SW, INVALID_TRACKDIR}, - {INVALID_TRACKDIR, TRACKDIR_Y_SE, INVALID_TRACKDIR, TRACKDIR_Y_NW}, - {TRACKDIR_UPPER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_UPPER_W}, - {INVALID_TRACKDIR, TRACKDIR_LOWER_E, TRACKDIR_LOWER_W, INVALID_TRACKDIR}, - {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LEFT_S, TRACKDIR_LEFT_N}, - {TRACKDIR_RIGHT_N, TRACKDIR_RIGHT_S, INVALID_TRACKDIR, INVALID_TRACKDIR} + {Trackdir::X_NE, Trackdir::Invalid, Trackdir::X_SW, Trackdir::Invalid}, + {Trackdir::Invalid, Trackdir::Y_SE, Trackdir::Invalid, Trackdir::Y_NW}, + {Trackdir::Upper_E, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Upper_W}, + {Trackdir::Invalid, Trackdir::Lower_E, Trackdir::Lower_W, Trackdir::Invalid}, + {Trackdir::Invalid, Trackdir::Invalid, Trackdir::Left_S, Trackdir::Left_N}, + {Trackdir::Right_N, Trackdir::Right_S, Trackdir::Invalid, Trackdir::Invalid} }}}; /** Maps a track and an (4-way) dir to the trackdir that represents the track with the entry in the given direction. */ extern const TrackIndexArray> _track_enterdir_to_trackdir{{{ - {TRACKDIR_X_NE, INVALID_TRACKDIR, TRACKDIR_X_SW, INVALID_TRACKDIR}, - {INVALID_TRACKDIR, TRACKDIR_Y_SE, INVALID_TRACKDIR, TRACKDIR_Y_NW}, - {INVALID_TRACKDIR, TRACKDIR_UPPER_E, TRACKDIR_UPPER_W, INVALID_TRACKDIR}, - {TRACKDIR_LOWER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LOWER_W}, - {TRACKDIR_LEFT_N, TRACKDIR_LEFT_S, INVALID_TRACKDIR, INVALID_TRACKDIR}, - {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_RIGHT_S, TRACKDIR_RIGHT_N} + {Trackdir::X_NE, Trackdir::Invalid, Trackdir::X_SW, Trackdir::Invalid}, + {Trackdir::Invalid, Trackdir::Y_SE, Trackdir::Invalid, Trackdir::Y_NW}, + {Trackdir::Invalid, Trackdir::Upper_E, Trackdir::Upper_W, Trackdir::Invalid}, + {Trackdir::Lower_E, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Lower_W}, + {Trackdir::Left_N, Trackdir::Left_S, Trackdir::Invalid, Trackdir::Invalid}, + {Trackdir::Invalid, Trackdir::Invalid, Trackdir::Right_S, Trackdir::Right_N} }}}; /** Maps a track and a full (8-way) direction to the trackdir that represents the track running in the given direction. */ extern const TrackIndexArray> _track_direction_to_trackdir{{{ - {INVALID_TRACKDIR, TRACKDIR_X_NE, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_X_SW, INVALID_TRACKDIR, INVALID_TRACKDIR}, - {INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_Y_SE, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_Y_NW}, - {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_UPPER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_UPPER_W, INVALID_TRACKDIR}, - {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LOWER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LOWER_W, INVALID_TRACKDIR}, - {TRACKDIR_LEFT_N, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LEFT_S, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR}, - {TRACKDIR_RIGHT_N, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_RIGHT_S, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR} + {Trackdir::Invalid, Trackdir::X_NE, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Invalid, Trackdir::X_SW, Trackdir::Invalid, Trackdir::Invalid}, + {Trackdir::Invalid, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Y_SE, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Y_NW}, + {Trackdir::Invalid, Trackdir::Invalid, Trackdir::Upper_E, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Upper_W, Trackdir::Invalid}, + {Trackdir::Invalid, Trackdir::Invalid, Trackdir::Lower_E, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Lower_W, Trackdir::Invalid}, + {Trackdir::Left_N, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Left_S, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Invalid}, + {Trackdir::Right_N, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Right_S, Trackdir::Invalid, Trackdir::Invalid, Trackdir::Invalid} }}}; /** Maps a (4-way) direction to the diagonal trackdir that runs in that direction. */ extern const DiagDirectionIndexArray _dir_to_diag_trackdir{ - TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW, + Trackdir::X_NE, Trackdir::Y_SE, Trackdir::X_SW, Trackdir::Y_NW, }; /** Maps a single horizontal/vertical trackbit that is in a specific tile corner. */ @@ -91,35 +91,35 @@ extern const CornerIndexArray _corner_to_trackbits{ }; extern const TrackdirBits _uphill_trackdirs[] = { - TRACKDIR_BIT_NONE , ///< 0 SLOPE_FLAT - TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW, ///< 1 SLOPE_W -> inclined for diagonal track - TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_SE, ///< 2 SLOPE_S -> inclined for diagonal track - TRACKDIR_BIT_X_SW , ///< 3 SLOPE_SW - TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE, ///< 4 SLOPE_E -> inclined for diagonal track - TRACKDIR_BIT_NONE , ///< 5 SLOPE_EW - TRACKDIR_BIT_Y_SE , ///< 6 SLOPE_SE - TRACKDIR_BIT_NONE , ///< 7 SLOPE_WSE -> leveled - TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_NW, ///< 8 SLOPE_N -> inclined for diagonal track - TRACKDIR_BIT_Y_NW , ///< 9 SLOPE_NW - TRACKDIR_BIT_NONE , ///< 10 SLOPE_NS - TRACKDIR_BIT_NONE , ///< 11 SLOPE_NWS -> leveled - TRACKDIR_BIT_X_NE , ///< 12 SLOPE_NE - TRACKDIR_BIT_NONE , ///< 13 SLOPE_ENW -> leveled - TRACKDIR_BIT_NONE , ///< 14 SLOPE_SEN -> leveled - TRACKDIR_BIT_NONE , ///< 15 invalid - TRACKDIR_BIT_NONE , ///< 16 invalid - TRACKDIR_BIT_NONE , ///< 17 invalid - TRACKDIR_BIT_NONE , ///< 18 invalid - TRACKDIR_BIT_NONE , ///< 19 invalid - TRACKDIR_BIT_NONE , ///< 20 invalid - TRACKDIR_BIT_NONE , ///< 21 invalid - TRACKDIR_BIT_NONE , ///< 22 invalid - TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_SE, ///< 23 SLOPE_STEEP_S -> inclined for diagonal track - TRACKDIR_BIT_NONE , ///< 24 invalid - TRACKDIR_BIT_NONE , ///< 25 invalid - TRACKDIR_BIT_NONE , ///< 26 invalid - TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW, ///< 27 SLOPE_STEEP_W -> inclined for diagonal track - TRACKDIR_BIT_NONE , ///< 28 invalid - TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_NW, ///< 29 SLOPE_STEEP_N -> inclined for diagonal track - TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE, ///< 30 SLOPE_STEEP_E -> inclined for diagonal track + {}, // 0 SLOPE_FLAT + {Trackdir::X_SW, Trackdir::Y_NW}, // 1 SLOPE_W -> inclined for diagonal track + {Trackdir::X_SW, Trackdir::Y_SE}, // 2 SLOPE_S -> inclined for diagonal track + {Trackdir::X_SW}, // 3 SLOPE_SW + {Trackdir::X_NE, Trackdir::Y_SE}, // 4 SLOPE_E -> inclined for diagonal track + {}, // 5 SLOPE_EW + {Trackdir::Y_SE}, // 6 SLOPE_SE + {}, // 7 SLOPE_WSE -> leveled + {Trackdir::X_NE, Trackdir::Y_NW}, // 8 SLOPE_N -> inclined for diagonal track + {Trackdir::Y_NW}, // 9 SLOPE_NW + {}, // 10 SLOPE_NS + {}, // 11 SLOPE_NWS -> leveled + {Trackdir::X_NE}, // 12 SLOPE_NE + {}, // 13 SLOPE_ENW -> leveled + {}, // 14 SLOPE_SEN -> leveled + {}, // 15 invalid + {}, // 16 invalid + {}, // 17 invalid + {}, // 18 invalid + {}, // 19 invalid + {}, // 20 invalid + {}, // 21 invalid + {}, // 22 invalid + {Trackdir::X_SW, Trackdir::Y_SE}, // 23 SLOPE_STEEP_S -> inclined for diagonal track + {}, // 24 invalid + {}, // 25 invalid + {}, // 26 invalid + {Trackdir::X_SW, Trackdir::Y_NW}, // 27 SLOPE_STEEP_W -> inclined for diagonal track + {}, // 28 invalid + {Trackdir::X_NE, Trackdir::Y_NW}, // 29 SLOPE_STEEP_N -> inclined for diagonal track + {Trackdir::X_NE, Trackdir::Y_SE}, // 30 SLOPE_STEEP_E -> inclined for diagonal track }; diff --git a/src/track_func.h b/src/track_func.h index 8409c0cdc7..8c3f7757df 100644 --- a/src/track_func.h +++ b/src/track_func.h @@ -10,13 +10,10 @@ #ifndef TRACK_FUNC_H #define TRACK_FUNC_H -#include "core/bitmath_func.hpp" #include "track_type.h" #include "direction_func.h" #include "slope_func.h" -using SetTrackdirBitIterator = SetBitIterator; - /** * Checks if a Track is valid. * @@ -38,7 +35,7 @@ inline bool IsValidTrack(Track track) */ inline bool IsValidTrackdirForRoadVehicle(Trackdir trackdir) { - return trackdir < TRACKDIR_END; + return trackdir < Trackdir::End; } /** @@ -50,7 +47,7 @@ inline bool IsValidTrackdirForRoadVehicle(Trackdir trackdir) */ inline bool IsValidTrackdir(Trackdir trackdir) { - return trackdir != INVALID_TRACKDIR && ((1 << trackdir & TRACKDIR_BIT_MASK) != TRACKDIR_BIT_NONE); + return trackdir < Trackdir::End && TRACKDIR_BIT_MASK.Test(trackdir); } /** @@ -89,7 +86,7 @@ inline TrackBits CornerToTrackBits(Corner corner) inline TrackdirBits TrackdirToTrackdirBits(Trackdir trackdir) { assert(IsValidTrackdir(trackdir)); - return static_cast(1 << trackdir); + return trackdir; } /** @@ -121,8 +118,8 @@ inline Track RemoveFirstTrack(TrackBits *tracks) * * This function searches for the first bit in the TrackdirBits parameter, * remove this bit from the parameter and returns the fnound bit as - * Trackdir value. It returns INVALID_TRACKDIR if the trackdirs is - * TRACKDIR_BIT_NONE or INVALID_TRACKDIR_BIT. This is basically used in a + * Trackdir value. It returns Trackdir::Invalid if the trackdirs is + * empty or INVALID_TRACKDIR_BIT. This is basically used in a * while-loop to get all track-directions step by step until the value * reaches TRACKDIR_BIT_NONE. * @@ -132,13 +129,12 @@ inline Track RemoveFirstTrack(TrackBits *tracks) */ inline Trackdir RemoveFirstTrackdir(TrackdirBits *trackdirs) { - if (*trackdirs != TRACKDIR_BIT_NONE && *trackdirs != INVALID_TRACKDIR_BIT) { - assert((*trackdirs & ~TRACKDIR_BIT_MASK) == TRACKDIR_BIT_NONE); - Trackdir first = (Trackdir)FindFirstBit(*trackdirs); - ClrBit(*trackdirs, first); - return first; - } - return INVALID_TRACKDIR; + if (trackdirs->None() || *trackdirs == INVALID_TRACKDIR_BIT) return Trackdir::Invalid; + + assert(!trackdirs->Any({Trackdir::RvRev_NE, Trackdir::RvRev_SE, Trackdir::RvRev_SW, Trackdir::RvRev_NW})); + Trackdir first = trackdirs->GetNthSetBit(0).value(); + trackdirs->Reset(first); + return first; } /** @@ -174,21 +170,21 @@ inline Track TrackBitsToTrack(TrackBits tracks) } /** - * Returns first Trackdir from TrackdirBits or INVALID_TRACKDIR + * Returns first Trackdir from TrackdirBits or Trackdir::Invalid * * This function returns the first Trackdir in the given TrackdirBits value or - * INVALID_TRACKDIR if the value is TRACKDIR_BIT_NONE. The TrackdirBits must + * Trackdir::Invalid if the value is empty. The TrackdirBits must * not be INVALID_TRACKDIR_BIT. * * @param trackdirs The TrackdirBits value - * @return The first Trackdir from the TrackdirBits or INVALID_TRACKDIR on TRACKDIR_BIT_NONE. + * @return The first Trackdir from the TrackdirBits or Trackdir::Invalid on empty. * @pre trackdirs must not be INVALID_TRACKDIR_BIT * @see RemoveFirstTrackdir */ inline Trackdir FindFirstTrackdir(TrackdirBits trackdirs) { - assert((trackdirs & ~TRACKDIR_BIT_MASK) == TRACKDIR_BIT_NONE); - return (trackdirs != TRACKDIR_BIT_NONE) ? (Trackdir)FindFirstBit(trackdirs) : INVALID_TRACKDIR; + assert(!trackdirs.Any({Trackdir::RvRev_NE, Trackdir::RvRev_SE, Trackdir::RvRev_SW, Trackdir::RvRev_NW})); + return trackdirs.GetNthSetBit(0).value_or(Trackdir::Invalid); } /* @@ -219,12 +215,12 @@ inline Track TrackToOppositeTrack(Track t) * * @param trackdir The Trackdir value * @return The reverse trackdir - * @pre trackdir must not be INVALID_TRACKDIR + * @pre trackdir must not be Trackdir::Invalid */ inline Trackdir ReverseTrackdir(Trackdir trackdir) { assert(IsValidTrackdirForRoadVehicle(trackdir)); - return (Trackdir)(trackdir ^ 8); + return static_cast(to_underlying(trackdir) ^ 8); } /** @@ -239,7 +235,7 @@ inline Trackdir ReverseTrackdir(Trackdir trackdir) inline Track TrackdirToTrack(Trackdir trackdir) { assert(IsValidTrackdir(trackdir)); - return static_cast(trackdir & 0x7); + return static_cast(to_underlying(trackdir) & 0x7); } /** @@ -256,7 +252,7 @@ inline Track TrackdirToTrack(Trackdir trackdir) inline Trackdir TrackToTrackdir(Track track) { assert(IsValidTrack(track)); - return (Trackdir)track; + return static_cast(track); } /** @@ -271,7 +267,7 @@ inline Trackdir TrackToTrackdir(Track track) inline TrackdirBits TrackToTrackdirBits(Track track) { Trackdir td = TrackToTrackdir(track); - return static_cast(TrackdirToTrackdirBits(td) | TrackdirToTrackdirBits(ReverseTrackdir(td))); + return TrackdirToTrackdirBits(td) | TrackdirToTrackdirBits(ReverseTrackdir(td)); } /** @@ -284,7 +280,7 @@ inline TrackdirBits TrackToTrackdirBits(Track track) */ inline TrackBits TrackdirBitsToTrackBits(TrackdirBits bits) { - return static_cast((bits | (bits >> 8)) & TRACK_BIT_ALL.base()); + return static_cast((bits.base() | (bits.base() >> 8)) & TRACK_BIT_ALL.base()); } /** @@ -298,18 +294,6 @@ inline TrackdirBits TrackBitsToTrackdirBits(TrackBits bits) return static_cast(bits.base() * 0x101); } -/** - * Checks whether a TrackdirBits has a given Trackdir. - * @param trackdirs The trackdir bits. - * @param trackdir The trackdir to check. - * @return \c true iff \c trackdir is in \c trackdirs. - */ -inline bool HasTrackdir(TrackdirBits trackdirs, Trackdir trackdir) -{ - assert(IsValidTrackdir(trackdir)); - return HasBit(trackdirs, trackdir); -} - /** * Maps a trackdir to the trackdir that you will end up on if you go straight * ahead. @@ -368,15 +352,15 @@ inline DiagDirection TrackdirToExitdir(Trackdir trackdir) * with the exit in the given direction. * * For the diagonal tracks the resulting track direction are clear for a given - * DiagDirection. It either matches the direction or it returns INVALID_TRACKDIR, + * DiagDirection. It either matches the direction or it returns Trackdir::Invalid, * as a Track::X cannot be applied with DIAG_SE. * For the straight tracks the resulting track direction will be the - * direction which the DiagDirection is pointing. But this will be INVALID_TRACKDIR + * direction which the DiagDirection is pointing. But this will be Trackdir::Invalid * if the DiagDirection is pointing 'away' the track. * * @param track The track to apply an direction on * @param diagdir The DiagDirection to apply on - * @return The resulting track direction or INVALID_TRACKDIR if not possible. + * @return The resulting track direction or Trackdir::Invalid if not possible. */ inline Trackdir TrackExitdirToTrackdir(Track track, DiagDirection diagdir) { @@ -391,17 +375,17 @@ inline Trackdir TrackExitdirToTrackdir(Track track, DiagDirection diagdir) * with the entry in the given direction. * * For the diagonal tracks the return value is clear, its either the matching - * track direction or INVALID_TRACKDIR. + * track direction or Trackdir::Invalid. * For the straight tracks this returns the track direction which results if * you follow the DiagDirection and then turn by 45 deg left or right on the * next tile. The new direction on the new track will be the returning Trackdir * value. If the parameters makes no sense like the track Track::Upper and the * direction DiagDirection::NE (target track cannot be reached) this function returns - * INVALID_TRACKDIR. + * Trackdir::Invalid. * * @param track The target track * @param diagdir The direction to "come from" - * @return the resulting Trackdir or INVALID_TRACKDIR if not possible. + * @return the resulting Trackdir or Trackdir::Invalid if not possible. */ inline Trackdir TrackEnterdirToTrackdir(Track track, DiagDirection diagdir) { @@ -584,7 +568,7 @@ inline bool TrackOverlapsTracks(TrackBits tracks, Track track) inline bool IsReversingRoadTrackdir(Trackdir dir) { assert(IsValidTrackdirForRoadVehicle(dir)); - return (dir & 0x07) >= 6; + return (to_underlying(dir) & 0x07) >= 6; } /** @@ -595,7 +579,7 @@ inline bool IsReversingRoadTrackdir(Trackdir dir) inline bool IsStraightRoadTrackdir(Trackdir dir) { assert(IsValidTrackdirForRoadVehicle(dir)); - return (dir & 0x06) == 0; + return (to_underlying(dir) & 0x06) == 0; } /** @@ -612,7 +596,7 @@ inline bool IsUphillTrackdir(Slope slope, Trackdir dir) { assert(IsValidTrackdirForRoadVehicle(dir)); extern const TrackdirBits _uphill_trackdirs[]; - return HasBit(_uphill_trackdirs[RemoveHalftileSlope(slope)], dir); + return _uphill_trackdirs[RemoveHalftileSlope(slope)].Test(dir); } /** diff --git a/src/track_type.h b/src/track_type.h index 42a61bb348..514c49065c 100644 --- a/src/track_type.h +++ b/src/track_type.h @@ -60,63 +60,46 @@ static constexpr TrackBits TRACK_BIT_ALL = {Track::X, Track::Y, Track::Upper, Tr * reversing track dirs are not considered to be 'valid' except in a small * corner in the road vehicle controller. */ -enum Trackdir : uint8_t { - TRACKDIR_BEGIN = 0, ///< Used for iterations - TRACKDIR_X_NE = 0, ///< X-axis and direction to north-east - TRACKDIR_Y_SE = 1, ///< Y-axis and direction to south-east - TRACKDIR_UPPER_E = 2, ///< Upper track and direction to east - TRACKDIR_LOWER_E = 3, ///< Lower track and direction to east - TRACKDIR_LEFT_S = 4, ///< Left track and direction to south - TRACKDIR_RIGHT_S = 5, ///< Right track and direction to south - TRACKDIR_RVREV_NE = 6, ///< (Road vehicle) reverse direction north-east - TRACKDIR_RVREV_SE = 7, ///< (Road vehicle) reverse direction south-east - TRACKDIR_X_SW = 8, ///< X-axis and direction to south-west - TRACKDIR_Y_NW = 9, ///< Y-axis and direction to north-west - TRACKDIR_UPPER_W = 10, ///< Upper track and direction to west - TRACKDIR_LOWER_W = 11, ///< Lower track and direction to west - TRACKDIR_LEFT_N = 12, ///< Left track and direction to north - TRACKDIR_RIGHT_N = 13, ///< Right track and direction to north - TRACKDIR_RVREV_SW = 14, ///< (Road vehicle) reverse direction south-west - TRACKDIR_RVREV_NW = 15, ///< (Road vehicle) reverse direction north-west - TRACKDIR_END, ///< Used for iterations - INVALID_TRACKDIR = 0xFF, ///< Flag for an invalid trackdir -}; +enum class Trackdir : uint8_t { + X_NE = 0, ///< X-axis and direction to north-east + Y_SE = 1, ///< Y-axis and direction to south-east + Upper_E = 2, ///< Upper track and direction to east + Lower_E = 3, ///< Lower track and direction to east + Left_S = 4, ///< Left track and direction to south + Right_S = 5, ///< Right track and direction to south + RvRev_NE = 6, ///< (Road vehicle) reverse direction north-east + RvRev_SE = 7, ///< (Road vehicle) reverse direction south-east + X_SW = 8, ///< X-axis and direction to south-west + Y_NW = 9, ///< Y-axis and direction to north-west + Upper_W = 10, ///< Upper track and direction to west + Lower_W = 11, ///< Lower track and direction to west + Left_N = 12, ///< Left track and direction to north + Right_N = 13, ///< Right track and direction to north + RvRev_SW = 14, ///< (Road vehicle) reverse direction south-west + RvRev_NW = 15, ///< (Road vehicle) reverse direction north-west -/** Allow incrementing of Trackdir variables */ -DECLARE_INCREMENT_DECREMENT_OPERATORS(Trackdir) + End, ///< End marker + Invalid = 0xFF, ///< Flag for an invalid trackdir +}; /** * Array with \c Trackdir as index. * @tparam T the type contained within the array. */ template -using TrackdirIndexArray = EnumIndexArray; +using TrackdirIndexArray = EnumIndexArray; -/** - * Enumeration of bitmasks for the TrackDirs - * - * These are a combination of tracks and directions. Values are 0-5 in one - * direction (corresponding to the Track enum) and 8-13 in the other direction. - */ -enum TrackdirBits : uint16_t { - TRACKDIR_BIT_NONE = 0U, ///< No track build - TRACKDIR_BIT_X_NE = 1U << TRACKDIR_X_NE, ///< Track x-axis, direction north-east - TRACKDIR_BIT_Y_SE = 1U << TRACKDIR_Y_SE, ///< Track y-axis, direction south-east - TRACKDIR_BIT_UPPER_E = 1U << TRACKDIR_UPPER_E, ///< Track upper, direction east - TRACKDIR_BIT_LOWER_E = 1U << TRACKDIR_LOWER_E, ///< Track lower, direction east - TRACKDIR_BIT_LEFT_S = 1U << TRACKDIR_LEFT_S, ///< Track left, direction south - TRACKDIR_BIT_RIGHT_S = 1U << TRACKDIR_RIGHT_S, ///< Track right, direction south - /* Again, note the two missing values here. This enables trackdir -> track conversion by doing (trackdir & 0xFF) */ - TRACKDIR_BIT_X_SW = 1U << TRACKDIR_X_SW, ///< Track x-axis, direction south-west - TRACKDIR_BIT_Y_NW = 1U << TRACKDIR_Y_NW, ///< Track y-axis, direction north-west - TRACKDIR_BIT_UPPER_W = 1U << TRACKDIR_UPPER_W, ///< Track upper, direction west - TRACKDIR_BIT_LOWER_W = 1U << TRACKDIR_LOWER_W, ///< Track lower, direction west - TRACKDIR_BIT_LEFT_N = 1U << TRACKDIR_LEFT_N, ///< Track left, direction north - TRACKDIR_BIT_RIGHT_N = 1U << TRACKDIR_RIGHT_N, ///< Track right, direction north - TRACKDIR_BIT_MASK = 0x3F3F, ///< Bitmask for bit-operations - INVALID_TRACKDIR_BIT = 0xFFFF, ///< Flag for an invalid trackdirbit value +/** Bitset of \c Trackdir elements. */ +using TrackdirBits = EnumBitSet; + +/** Bitset of valid non-road vehicle trackdirs/ */ +static constexpr TrackdirBits TRACKDIR_BIT_MASK{ + Trackdir::X_NE, Trackdir::Y_SE, Trackdir::Upper_E, Trackdir::Lower_E, Trackdir::Left_S, Trackdir::Right_S, + Trackdir::X_SW, Trackdir::Y_NW, Trackdir::Upper_W, Trackdir::Lower_W, Trackdir::Left_N, Trackdir::Right_N, }; -DECLARE_ENUM_AS_BIT_SET(TrackdirBits) + +/** Marker for an invalid TrackdirBits value. */ +static constexpr TrackdirBits INVALID_TRACKDIR_BIT{UINT16_MAX}; /** Track status of a tile. */ struct TrackStatus { diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index c89ab65757..7bbd4fff51 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2333,7 +2333,7 @@ static void CheckNextTrainTile(Train *consist) if (!HasReservedTracks(ft.new_tile, TrackdirBitsToTrackBits(ft.new_td_bits))) { /* Next tile is not reserved. */ - if (KillFirstBit(ft.new_td_bits) == TRACKDIR_BIT_NONE) { + if (ft.new_td_bits.Count() == 1) { if (HasPbsSignalOnTrackdir(ft.new_tile, FindFirstTrackdir(ft.new_td_bits))) { /* If the next tile is a PBS signal, try to make a reservation. */ TrackBits tracks = TrackdirBitsToTrackBits(ft.new_td_bits); @@ -2499,7 +2499,7 @@ void FreeTrainTrackReservation(const Train *consist) tile = ft.new_tile; TrackdirBits bits = ft.new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(tile)); td = RemoveFirstTrackdir(&bits); - assert(bits == TRACKDIR_BIT_NONE); + assert(bits.None()); if (!IsValidTrackdir(td)) break; @@ -2573,19 +2573,19 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, TileIndex tile = origin.tile; Trackdir cur_td = origin.trackdir; while (ft.Follow(tile, cur_td)) { - if (KillFirstBit(ft.new_td_bits) == TRACKDIR_BIT_NONE) { + if (ft.new_td_bits.Count() == 1) { /* Possible signal tile. */ if (HasOnewaySignalBlockingTrackdir(ft.new_tile, FindFirstTrackdir(ft.new_td_bits))) break; } if (Rail90DegTurnDisallowed(GetTileRailType(ft.old_tile), GetTileRailType(ft.new_tile))) { - ft.new_td_bits &= ~TrackdirCrossesTrackdirs(ft.old_td); - if (ft.new_td_bits == TRACKDIR_BIT_NONE) break; + ft.new_td_bits.Reset(TrackdirCrossesTrackdirs(ft.old_td)); + if (ft.new_td_bits.None()) break; } /* Station, depot or waypoint are a possible target. */ bool target_seen = ft.is_station || (IsTileType(ft.new_tile, TileType::Railway) && !IsPlainRail(ft.new_tile)); - if (target_seen || KillFirstBit(ft.new_td_bits) != TRACKDIR_BIT_NONE) { + if (target_seen || ft.new_td_bits.Count() > 1) { /* Choice found or possible target encountered. * On finding a possible target, we need to stop and let the pathfinder handle the * remaining path. This is because we don't know if this target is in one of our @@ -2645,10 +2645,10 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, if (!ft.Follow(tile, cur_td)) break; if (Rail90DegTurnDisallowed(GetTileRailType(ft.old_tile), GetTileRailType(ft.new_tile))) { - ft.new_td_bits &= ~TrackdirCrossesTrackdirs(ft.old_td); - assert(ft.new_td_bits != TRACKDIR_BIT_NONE); + ft.new_td_bits.Reset(TrackdirCrossesTrackdirs(ft.old_td)); + assert(ft.new_td_bits.Any()); } - assert(KillFirstBit(ft.new_td_bits) == TRACKDIR_BIT_NONE); + assert(ft.new_td_bits.Count() == 1); tile = ft.new_tile; cur_td = FindFirstTrackdir(ft.new_td_bits); @@ -2808,7 +2808,7 @@ static Track ChooseTrainTrack(Train *consist, TileIndex tile, DiagDirection ente const Train *moving_front = consist->GetMovingFront(); - PBSTileInfo res_dest(tile, INVALID_TRACKDIR, false); + PBSTileInfo res_dest(tile, Trackdir::Invalid, false); DiagDirection dest_enterdir = enterdir; if (do_track_reservation) { res_dest = ExtendTrainReservation(consist, &tracks, &dest_enterdir); @@ -3999,7 +3999,7 @@ static bool TrainCheckIfLineEnds(Train *moving_front, bool reverse) } /* approaching red signal */ - if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(moving_front, true, reverse); + if (trackdirbits.Any(red_signals)) return TrainApproachingLineEnd(moving_front, true, reverse); /* approaching a rail/road crossing? then make it red */ if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile); @@ -4298,7 +4298,7 @@ void Train::OnNewEconomyDay() */ Trackdir Train::GetVehicleTrackdir() const { - if (this->vehstatus.Test(VehState::Crashed)) return INVALID_TRACKDIR; + if (this->vehstatus.Test(VehState::Crashed)) return Trackdir::Invalid; if (this->track == Track::Depot) { /* We'll assume the train is facing outwards */ diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index b8a5e2c25e..d041a9182c 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -1857,7 +1857,7 @@ static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType DiagDirection dir = GetTunnelBridgeDirection(tile); if (side != DiagDirection::Invalid && side != ReverseDiagDir(dir)) return {}; - return {TrackBitsToTrackdirBits(DiagDirToDiagTrack(dir)), TRACKDIR_BIT_NONE}; + return {TrackBitsToTrackdirBits(DiagDirToDiagTrack(dir)), {}}; } /** @copydoc ChangeTileOwnerProc */ @@ -2017,7 +2017,7 @@ static VehicleEnterTileStates VehicleEnterTile_TunnelBridge(Vehicle *v, TileInde /* We're at the tunnel exit ?? */ if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) { rv->tile = tile; - rv->state = DiagDirToDiagTrackdir(vdir); + rv->state = to_underlying(DiagDirToDiagTrackdir(vdir)); rv->frame = frame; rv->vehstatus.Reset(VehState::Hidden); return VehicleEnterTileState::EnteredWormhole; @@ -2073,7 +2073,7 @@ static VehicleEnterTileStates VehicleEnterTile_TunnelBridge(Vehicle *v, TileInde case VehicleType::Road: { RoadVehicle *rv = RoadVehicle::From(v); if (rv->state == RVSB_WORMHOLE) { - rv->state = DiagDirToDiagTrackdir(vdir); + rv->state = to_underlying(DiagDirToDiagTrackdir(vdir)); rv->frame = 0; return VehicleEnterTileState::EnteredWormhole; } diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 8d29d4d65c..07452f0ef9 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -599,7 +599,7 @@ public: * in depots), returns 0xFF. * @return the trackdir of the vehicle */ - virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; } + virtual Trackdir GetVehicleTrackdir() const { return Trackdir::Invalid; } /** * Gets the running cost of a vehicle that can be sent into string parameters for string processing. diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 5c9ac46466..7c7af9cc50 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -1403,7 +1403,7 @@ static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, /* NW border: remove tracks that connects NW tile edge */ ts.Reset({Track::Y, Track::Left, Track::Upper}); } - return {TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE}; + return {TrackBitsToTrackdirBits(ts), {}}; } /** @copydoc ClickTileProc */